Overview
The Multi-Source Confirmation Indicator Backtest Framework is a professional-grade quantitative trading testing system designed for evaluating custom indicators and trading signals. This framework integrates multiple signal detection methods, an advanced confirmation filtering system, and professional risk management capabilities, enabling traders to comprehensively test their trading strategies. The core advantage of the system lies in its flexibility, allowing users to connect any custom indicator or built-in study and detect signals through various methods, including value changes, crossovers, and threshold triggers. Additionally, the framework offers advanced risk management features such as static take-profit/stop-loss, break-even functionality, and position sizing management, as well as independent exit logic and a clear visual feedback system.
Strategy Principles
The core principle of this strategy is to provide a comprehensive testing environment that allows traders to evaluate the effectiveness of various indicators. The code implements the following key functions:
Multiple Signal Detection Methods: The strategy implements five different signal detection methods through the detectLongSignal() and detectShortSignal() functions:
- Value Change: Triggers when the indicator value changes and is greater than 0
- Crossover Above: Triggers when the indicator value crosses above the threshold
- Crossover Below: Triggers when the indicator value crosses below the threshold
- Value Above Threshold: Triggers when the indicator value moves from below to above the threshold
- Value Below Threshold: Triggers when the indicator value moves from above to below the threshold
Confirmation System: Through the longConfirmation() and shortConfirmation() functions, the strategy implements a multi-source confirmation system that requires trade signals to meet additional conditions within a specified lookback period before execution. This feature significantly reduces false signals.
Entry and Exit Logic: The strategy uses the strategy.entry and strategy.exit functions to manage trade entries and exits. Entry conditions are determined by both signal detection and the confirmation system, while exits can be implemented through multiple means:
- Fixed take-profit/stop-loss
- Custom exit signals
- Break-even functionality
Break-Even Logic: When a trade reaches a specified profit level in ticks, the strategy automatically moves the stop-loss to the entry price, protecting acquired profits. This is achieved by detecting the difference between the current price and the entry price, and modifying the stop-loss level when the specified number of ticks in the breakEvenTrigger is reached.
Visualization and Monitoring: The strategy uses the plotshape function to mark all entry and exit signals on the chart, and creates a real-time status table using table.new to display current strategy settings and trade status.
Strategy Advantages
High Flexibility: The strategy allows connecting any indicator as a signal source, making it applicable to various trading styles and market conditions. Users can test different indicator combinations by simply changing the input sources.
Multi-Layer Filtering System: Through the confirmation filter, the strategy can require multiple conditions to be simultaneously satisfied before executing a trade, significantly reducing false signals. This multi-source confirmation approach simulates the practice of professional traders seeking consistency across multiple indicators before making trading decisions.
Comprehensive Risk Management: The strategy has built-in professional-grade risk management features, including:
- Preset take-profit/stop-loss levels
- Dynamic break-even functionality
- Custom exit signals
These features ensure that traders can simulate risk control measures from real trading environments during testing.
Real-Time Feedback and Monitoring: Through signal markers and status tables, traders can visually understand the operational status and performance of the strategy, facilitating debugging and optimization.
Compatibility: The strategy is compatible with Pine Script v6 and can run on any trading platform that supports this version, with backtesting capabilities that allow traders to evaluate historical performance.
Strategy Risks
Signal Detection Dependency: The effectiveness of the strategy is highly dependent on the chosen signal detection method and threshold settings. Inappropriate configurations may lead to excessive false signals or missed important trading opportunities. It is recommended that traders test various setting combinations under different market conditions to find the most suitable signal detection method for specific indicators.
Confirmation System Filtering Risk: While the multi-source confirmation system can reduce false signals, it may also lead to missed profitable trading opportunities. Overly strict confirmation requirements may cause the strategy to miss rapidly developing market trends. The solution is to balance the strictness of the confirmation system or design different confirmation criteria for various market states.
Limitations of Fixed Take-Profit/Stop-Loss: Using fixed take-profit/stop-loss points may not be suitable for all market conditions, especially in markets with significant volatility changes. It is recommended to link take-profit/stop-loss levels with market volatility indicators (such as ATR) to adapt to different market environments.
Backtesting vs. Live Trading Differences: All backtesting results carry the risk of differing from live trading, as backtests cannot fully simulate slippage, trading costs, and liquidity issues. Traders should verify strategy performance in a demo environment before live trading.
Code Complexity: The complexity of the strategy may increase the difficulty of debugging and maintenance. Detailed comments and modular design can help manage this complexity and ensure code maintainability.
Strategy Optimization Directions
Dynamic Risk Management: The current strategy uses fixed take-profit/stop-loss points and could be optimized to a dynamic risk management system based on market volatility. For example, linking take-profit/stop-loss levels with ATR (Average True Range), expanding the stop-loss range when volatility increases, and narrowing it when volatility decreases. This would better adapt to different market conditions.
Enhanced Confirmation System: The current confirmation system could be expanded to include more filtering conditions, such as time filtering (avoiding trading during specific market sessions), volatility filtering (avoiding trading in low volatility environments), or trend filtering (only trading in directions consistent with the main trend). This would further reduce false signals and improve the robustness of the strategy.
Partial Position Management: The strategy could add partial position management functionality, allowing for batch entries and exits rather than opening or closing the entire position at once. This approach can reduce the risk of single-point entry/exit and potentially improve overall strategy performance.
Machine Learning Optimization: Machine learning algorithms could be introduced to optimize signal parameters and risk settings, automatically adjusting strategy parameters based on historical data to adapt to different market environments.
Additional Performance Metrics: While the strategy already provides basic status monitoring, more performance metrics could be added, such as Sharpe ratio, maximum drawdown, profit/loss ratio, etc., to provide a more comprehensive strategy evaluation. These metrics could be displayed in the status table to help traders better assess strategy performance.
Summary
The Multi-Source Confirmation Indicator Backtest Framework is a comprehensive quantitative trading testing system that provides traders with a powerful tool to evaluate and optimize their trading strategies by integrating multiple signal detection methods, multi-layer confirmation systems, and professional risk management features. The main advantages of the framework lie in its flexibility and customizability, allowing traders to test almost any type of indicator combination and signal generation method.
Despite some inherent risks and limitations, such as signal detection dependency and the limitations of fixed risk parameters, these issues can be addressed through the suggested optimization directions, such as implementing dynamic risk management, enhancing the confirmation system, and introducing partial position management. Through these optimizations, the framework can further improve its effectiveness and adaptability, becoming a valuable tool in the trader's arsenal.
In conclusion, the Multi-Source Confirmation Indicator Backtest Framework represents a professional, systematic approach to testing and evaluating trading strategies that goes beyond simple signal generation to incorporate risk management and multi-layer confirmation, which are key components of successful trading systems. For traders seeking to build and test custom trading strategies, this framework provides a comprehensive solution.
Strategy source code
/*backtest
start: 2024-07-08 00:00:00
end: 2025-07-04 08:00:00
period: 1d
basePeriod: 1d
exchanges: [{"eid":"Futures_Binance","currency":"ETH_USDT"}]
*/
//@version=6
strategy("FULLY FUNCTIONAL INDICATOR TESTER", overlay=true, margin_long=100, margin_short=100)
// Entry/Exit Signal Inputs
longEntry = input.source(close, 'Long Entry Trigger', 'Source for long signal (connect your indicator here)')
shortEntry = input.source(close, 'Short Entry Trigger', 'Source for short signal (connect your indicator here)')
activateLongExit = input.bool(false, 'Activate Long Exit Signals')
longExit = input.source(high, 'Long Exit Trigger', 'Source for long exit signal')
activateShortExit = input.bool(false, 'Activate Short Exit Signals')
shortExit = input.source(low, 'Short Exit Trigger', 'Source for short exit signal')
// Signal Detection Method
signalMethod = input.string('Value Change', 'Signal Detection Method', options=['Value Change', 'Crossover Above', 'Crossover Below', 'Value Above Threshold', 'Value Below Threshold'])
signalThreshold = input.float(0, 'Signal Threshold', tooltip='Threshold value for signal detection methods')
// Take Profit and Stop Loss
fixedTp = input.int(0, 'Static TP (in ticks)', 0, tooltip='0 = disabled')
initialSL = input.int(0, 'Initial SL (in ticks)', 0, tooltip='0 = disabled')
// Break Even Settings
breakEvenTrigger = input.int(0, 'Break Even Trigger (in ticks)', 0, tooltip='Move SL to break even after this many ticks profit. 0 = disabled')
// Confluence Settings
useConfluence = input.bool(false, 'Use Confluence Filter', 'Activate confluence filter for entries')
longConfluence = input.source(high, 'Long Signal Confluence', 'Source for long confluence filter')
longConfluenceTrigger = input.source(low, 'Long Confluence Trigger', 'Value that must be below confluence source for long entry')
shortConfluence = input.source(high, 'Short Signal Confluence', 'Source for short confluence filter')
shortConfluenceTrigger = input.source(low, 'Short Confluence Trigger', 'Value that must be above confluence source for short entry')
confluenceLookback = input.int(0, 'Confluence Lookback Period', 0, 10, 1, 'Number of candles to look back for confluence')
// Variables to track entry prices for break-even
var float longEntryPrice = na
var float shortEntryPrice = na
// Signal Detection Functions
detectLongSignal() =>
switch signalMethod
'Value Change' => longEntry != longEntry[1] and longEntry > 0
'Crossover Above' => ta.crossover(longEntry, signalThreshold)
'Crossover Below' => ta.crossunder(longEntry, signalThreshold)
'Value Above Threshold' => longEntry > signalThreshold and longEntry[1] <= signalThreshold
'Value Below Threshold' => longEntry < signalThreshold and longEntry[1] >= signalThreshold
=> false
detectShortSignal() =>
switch signalMethod
'Value Change' => shortEntry != shortEntry[1] and shortEntry > 0
'Crossover Above' => ta.crossover(shortEntry, signalThreshold)
'Crossover Below' => ta.crossunder(shortEntry, signalThreshold)
'Value Above Threshold' => shortEntry > signalThreshold and shortEntry[1] <= signalThreshold
'Value Below Threshold' => shortEntry < signalThreshold and shortEntry[1] >= signalThreshold
=> false
detectLongExit() =>
switch signalMethod
'Value Change' => longExit != longExit[1] and longExit > 0
'Crossover Above' => ta.crossover(longExit, signalThreshold)
'Crossover Below' => ta.crossunder(longExit, signalThreshold)
'Value Above Threshold' => longExit > signalThreshold and longExit[1] <= signalThreshold
'Value Below Threshold' => longExit < signalThreshold and longExit[1] >= signalThreshold
=> false
detectShortExit() =>
switch signalMethod
'Value Change' => shortExit != shortExit[1] and shortExit > 0
'Crossover Above' => ta.crossover(shortExit, signalThreshold)
'Crossover Below' => ta.crossunder(shortExit, signalThreshold)
'Value Above Threshold' => shortExit > signalThreshold and shortExit[1] <= signalThreshold
'Value Below Threshold' => shortExit < signalThreshold and shortExit[1] >= signalThreshold
=> false
// Confluence confirmation functions
longConfirmation() =>
confirmation = false
if confluenceLookback == 0
confirmation := longConfluenceTrigger < longConfluence
else
for x = 0 to confluenceLookback
if longConfluenceTrigger[x] < longConfluence[x]
confirmation := true
break
confirmation
shortConfirmation() =>
confirmation = false
if confluenceLookback == 0
confirmation := shortConfluenceTrigger > shortConfluence
else
for x = 0 to confluenceLookback
if shortConfluenceTrigger[x] > shortConfluence[x]
confirmation := true
break
confirmation
// Entry conditions
longConfirmed = useConfluence ? longConfirmation() : true
shortConfirmed = useConfluence ? shortConfirmation() : true
longCondition = detectLongSignal() and longConfirmed
shortCondition = detectShortSignal() and shortConfirmed
// Entry logic
if (longCondition and strategy.opentrades == 0)
strategy.entry('Long', strategy.long)
longEntryPrice := close
// Set initial exit orders
if fixedTp > 0 or initialSL > 0
strategy.exit('Long Exit', 'Long',
profit = fixedTp > 0 ? fixedTp : na,
loss = initialSL > 0 ? initialSL : na,
comment_profit = 'TP Hit',
comment_loss = 'SL Hit')
if (shortCondition and strategy.opentrades == 0)
strategy.entry('Short', strategy.short)
shortEntryPrice := close
// Set initial exit orders
if fixedTp > 0 or initialSL > 0
strategy.exit('Short Exit', 'Short',
profit = fixedTp > 0 ? fixedTp : na,
loss = initialSL > 0 ? initialSL : na,
comment_profit = 'TP Hit',
comment_loss = 'SL Hit')
// Custom exit signal logic
if (activateLongExit and detectLongExit() and strategy.position_size > 0)
strategy.close('Long', 'Custom Long Exit')
if (activateShortExit and detectShortExit() and strategy.position_size < 0)
strategy.close('Short', 'Custom Short Exit')
// Break-even logic
if (breakEvenTrigger > 0)
// Long position break-even
if (strategy.position_size > 0 and not na(longEntryPrice))
ticksProfit = math.round((high - longEntryPrice) / syminfo.mintick)
if (ticksProfit >= breakEvenTrigger)
strategy.exit('Long Exit', 'Long', stop = longEntryPrice, comment_loss = 'Break Even')
// Short position break-even
if (strategy.position_size < 0 and not na(shortEntryPrice))
ticksProfit = math.round((shortEntryPrice - low) / syminfo.mintick)
if (ticksProfit >= breakEvenTrigger)
strategy.exit('Short Exit', 'Short', stop = shortEntryPrice, comment_loss = 'Break Even')
// Reset entry prices when no position
if (strategy.position_size == 0)
longEntryPrice := na
shortEntryPrice := na
// Plot signals for debugging
plotshape(longCondition, title='Long Signal', location=location.belowbar, color=color.green, style=shape.triangleup, size=size.small)
plotshape(shortCondition, title='Short Signal', location=location.abovebar, color=color.red, style=shape.triangledown, size=size.small)
plotshape(activateLongExit and detectLongExit() and strategy.position_size > 0, title='Long Exit', location=location.abovebar, color=color.orange, style=shape.xcross, size=size.small)
plotshape(activateShortExit and detectShortExit() and strategy.position_size < 0, title='Short Exit', location=location.belowbar, color=color.orange, style=shape.xcross, size=size.small)
// Display current settings in a table for easy reference
if barstate.islast
var table infoTable = table.new(position.top_right, 2, 8, bgcolor=color.white, border_width=1)
table.cell(infoTable, 0, 0, "Signal Method:", text_color=color.black, bgcolor=color.gray)
table.cell(infoTable, 1, 0, signalMethod, text_color=color.black)
table.cell(infoTable, 0, 1, "Threshold:", text_color=color.black, bgcolor=color.gray)
table.cell(infoTable, 1, 1, str.tostring(signalThreshold), text_color=color.black)
table.cell(infoTable, 0, 2, "TP (ticks):", text_color=color.black, bgcolor=color.gray)
table.cell(infoTable, 1, 2, str.tostring(fixedTp), text_color=color.black)
table.cell(infoTable, 0, 3, "SL (ticks):", text_color=color.black, bgcolor=color.gray)
table.cell(infoTable, 1, 3, str.tostring(initialSL), text_color=color.black)
table.cell(infoTable, 0, 4, "Break Even:", text_color=color.black, bgcolor=color.gray)
table.cell(infoTable, 1, 4, str.tostring(breakEvenTrigger), text_color=color.black)
table.cell(infoTable, 0, 5, "Confluence:", text_color=color.black, bgcolor=color.gray)
table.cell(infoTable, 1, 5, useConfluence ? "ON" : "OFF", text_color=color.black)
table.cell(infoTable, 0, 6, "Position:", text_color=color.black, bgcolor=color.gray)
table.cell(infoTable, 1, 6, strategy.position_size > 0 ? "LONG" : strategy.position_size < 0 ? "SHORT" : "FLAT", text_color=color.black)
table.cell(infoTable, 0, 7, "Status:", text_color=color.black, bgcolor=color.gray)
table.cell(infoTable, 1, 7, "FULLY FUNCTIONAL", text_color=color.green)
Strategy parameters
The original address: Multi-Source Confirmation Indicator Backtest Framework: Quantitative Trading Testing System with Integrated Risk Management and Signal Detection
Top comments (1)
Ah, another strategy that promises to ‘manage risk’ until the market decides to yeet itself into oblivion. Jokes aside, the integrated signal detection here looks slick—especially appreciate the nod to avoiding overfitting (because we’ve all accidentally backtested on magic numbers before). Two questions though: 1) How many coffee cups died testing this? 2) Does the risk module include a ‘panic button’ for when correlation suddenly ≠ causation? Seriously though, solid write-up. Now if only my portfolio would read it…