전략은 특정 창 길이의 폐쇄 가격의 간단한 이동 평균 (SMA) 및 표준 편차 (STD) 에서 파생되는 베가스 채널을 계산하는 것으로 시작됩니다. 이 채널은 시장 변동성을 측정하는 데 도움이되며 슈퍼 트렌드 지표를 조정하는 기초를 형성합니다. 다음으로 평균 진정한 범위 (ATR) 와 조정된 곱셈자는 슈퍼 트렌드의 상부 및 하부 임계치를 결정하는 데 사용됩니다. 시장 트렌드는 폐쇄 가격을 슈퍼 트렌드 임계와 비교하여 결정됩니다. 두 슈퍼 트렌드 지표가 동일한 시장 방향으로 정렬 될 때만 거래 신호가 생성됩니다.
전략은 트렌드 식별의 정확성을 향상시키는 것을 목표로하지만, 여전히 몇 가지 위험이 있습니다. 첫째, 전략은 극도로 높은 변동성 또는 불분명한 시장 방향의 기간 동안 잘못된 거래 신호를 생성 할 수 있습니다. 둘째, 과도하게 빈번한 거래는 전략의 전반적인 성능에 영향을 미치는 높은 거래 비용으로 이어질 수 있습니다. 이러한 위험을 완화하기 위해, 거래자는 ATR 기간, 베가스 채널 창 장, 슈퍼 트렌드 멀티플라이저를 특정 시장 조건에 맞게 조정하는 것과 같은 전략 매개 변수를 최적화하는 것을 고려할 수 있습니다. 또한 적절한 수익 및 스톱 로스 수준을 설정하는 것이 잠재적 인 손실을 제어하는 데 중요합니다.
요약하자면,
/*backtest start: 2024-05-01 00:00:00 end: 2024-05-31 23:59:59 period: 3h basePeriod: 15m exchanges: [{"eid":"Futures_Binance","currency":"BTC_USDT"}] */ // This Pine Script™ code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/ // © PresentTrading // The "Double Vegas SuperTrend Enhanced" strategy uses two SuperTrend indicators with different ATR and Vegas Channel settings // to identify market trends and generate trades. Trades are executed only when both SuperTrends align in the same direction. // The strategy includes configurable take-profit and stop-loss levels, and plots the SuperTrend levels on the chart. //@version=5 strategy("Double Vegas SuperTrend Enhanced - Strategy [presentTrading]", shorttitle="Double Vegas SuperTrend Enhanced - Strategy [presentTrading]", overlay=true, overlay = false, precision=3, commission_value= 0.1, commission_type=strategy.commission.percent, slippage= 1, currency=currency.USD, default_qty_type = strategy.percent_of_equity, default_qty_value = 10, initial_capital= 10000) // Input settings allow the user to customize the strategy's parameters. tradeDirectionChoice = input.string(title="Trade Direction", defval="Both", options=["Long", "Short", "Both"]) // Option to select the trading direction // Settings for the first Vegas SuperTrend atrPeriod1 = input(10, "ATR Period for SuperTrend 1") // Length of the ATR for volatility measurement vegasWindow1 = input(100, "Vegas Window Length 1") // Length of the moving average for the Vegas Channel superTrendMultiplier1 = input(5, "SuperTrend Multiplier Base 1") // Base multiplier for the SuperTrend calculation volatilityAdjustment1 = input.float(5, "Volatility Adjustment Factor 1") // Factor to adjust the SuperTrend sensitivity to the Vegas Channel width // Settings for the second Vegas SuperTrend atrPeriod2 = input(5, "ATR Period for SuperTrend 2") // Length of the ATR for volatility measurement vegasWindow2 = input(200, "Vegas Window Length 2") // Length of the moving average for the Vegas Channel superTrendMultiplier2 = input(7, "SuperTrend Multiplier Base 2") // Base multiplier for the SuperTrend calculation volatilityAdjustment2 = input.float(7, "Volatility Adjustment Factor 2") // Factor to adjust the SuperTrend sensitivity to the Vegas Channel width // Settings for Hold Days and TPSL Conditions useHoldDays = input.bool(true, title="Use Hold Days") holdDays = input.int(5, title="Hold Days", minval=1, maxval=60, step=1) TPSLCondition = input.string("None", "TPSL Condition", options=["TP", "SL", "Both", "None"]) takeProfitPerc = input(30.0, title="Take Profit (%)") stopLossPerc = input(20.0, title="Stop Loss (%)") // Calculate the first Vegas Channel using a simple moving average and standard deviation. vegasMovingAverage1 = ta.sma(close, vegasWindow1) vegasChannelStdDev1 = ta.stdev(close, vegasWindow1) vegasChannelUpper1 = vegasMovingAverage1 + vegasChannelStdDev1 vegasChannelLower1 = vegasMovingAverage1 - vegasChannelStdDev1 // Adjust the first SuperTrend multiplier based on the width of the Vegas Channel. channelVolatilityWidth1 = vegasChannelUpper1 - vegasChannelLower1 adjustedMultiplier1 = superTrendMultiplier1 + volatilityAdjustment1 * (channelVolatilityWidth1 / vegasMovingAverage1) // Calculate the first SuperTrend indicator values. averageTrueRange1 = ta.atr(atrPeriod1) superTrendUpper1 = hlc3 - (adjustedMultiplier1 * averageTrueRange1) superTrendLower1 = hlc3 + (adjustedMultiplier1 * averageTrueRange1) var float superTrendPrevUpper1 = na var float superTrendPrevLower1 = na var int marketTrend1 = 1 // Update SuperTrend values and determine the current trend direction for the first SuperTrend. superTrendPrevUpper1 := nz(superTrendPrevUpper1[1], superTrendUpper1) superTrendPrevLower1 := nz(superTrendPrevLower1[1], superTrendLower1) marketTrend1 := close > superTrendPrevLower1 ? 1 : close < superTrendPrevUpper1 ? -1 : nz(marketTrend1[1], 1) superTrendUpper1 := marketTrend1 == 1 ? math.max(superTrendUpper1, superTrendPrevUpper1) : superTrendUpper1 superTrendLower1 := marketTrend1 == -1 ? math.min(superTrendLower1, superTrendPrevLower1) : superTrendLower1 superTrendPrevUpper1 := superTrendUpper1 superTrendPrevLower1 := superTrendLower1 // Calculate the second Vegas Channel using a simple moving average and standard deviation. vegasMovingAverage2 = ta.sma(close, vegasWindow2) vegasChannelStdDev2 = ta.stdev(close, vegasWindow2) vegasChannelUpper2 = vegasMovingAverage2 + vegasChannelStdDev2 vegasChannelLower2 = vegasMovingAverage2 - vegasChannelStdDev2 // Adjust the second SuperTrend multiplier based on the width of the Vegas Channel. channelVolatilityWidth2 = vegasChannelUpper2 - vegasChannelLower2 adjustedMultiplier2 = superTrendMultiplier2 + volatilityAdjustment2 * (channelVolatilityWidth2 / vegasMovingAverage2) // Calculate the second SuperTrend indicator values. averageTrueRange2 = ta.atr(atrPeriod2) superTrendUpper2 = hlc3 - (adjustedMultiplier2 * averageTrueRange2) superTrendLower2 = hlc3 + (adjustedMultiplier2 * averageTrueRange2) var float superTrendPrevUpper2 = na var float superTrendPrevLower2 = na var int marketTrend2 = 1 // Update SuperTrend values and determine the current trend direction for the second SuperTrend. superTrendPrevUpper2 := nz(superTrendPrevUpper2[1], superTrendUpper2) superTrendPrevLower2 := nz(superTrendPrevLower2[1], superTrendLower2) marketTrend2 := close > superTrendPrevLower2 ? 1 : close < superTrendPrevUpper2 ? -1 : nz(marketTrend2[1], 1) superTrendUpper2 := marketTrend2 == 1 ? math.max(superTrendUpper2, superTrendPrevUpper2) : superTrendUpper2 superTrendLower2 := marketTrend2 == -1 ? math.min(superTrendLower2, superTrendPrevLower2) : superTrendLower2 superTrendPrevUpper2 := superTrendUpper2 superTrendPrevLower2 := superTrendLower2 // Enhanced Visualization // Plot the SuperTrend and Vegas Channel for visual analysis for both lengths. plot(marketTrend1 == 1 ? superTrendUpper1 : na, "SuperTrend Upper 1", color=color.green, linewidth=2) plot(marketTrend1 == -1 ? superTrendLower1 : na, "SuperTrend Lower 1", color=color.red, linewidth=2) plot(marketTrend2 == 1 ? superTrendUpper2 : na, "SuperTrend Upper 2", color=color.rgb(31, 119, 130), linewidth=2) plot(marketTrend2 == -1 ? superTrendLower2 : na, "SuperTrend Lower 2", color=color.rgb(120, 42, 26), linewidth=2) // Detect trend direction changes and plot entry/exit signals for both lengths. trendShiftToBullish1 = marketTrend1 == 1 and marketTrend1[1] == -1 trendShiftToBearish1 = marketTrend1 == -1 and marketTrend1[1] == 1 trendShiftToBullish2 = marketTrend2 == 1 and marketTrend2[1] == -1 trendShiftToBearish2 = marketTrend2 == -1 and marketTrend2[1] == 1 // Define conditions for entering long or short positions, and execute trades based on these conditions for both lengths. enterLongCondition1 = marketTrend1 == 1 enterShortCondition1 = marketTrend1 == -1 enterLongCondition2 = marketTrend2 == 1 enterShortCondition2 = marketTrend2 == -1 // Entry conditions: Both conditions must be met for a trade to be executed. enterLongCondition = enterLongCondition1 and enterLongCondition2 and not na(superTrendPrevUpper1[1]) and not na(superTrendPrevUpper2[1]) enterShortCondition = enterShortCondition1 and enterShortCondition2 and not na(superTrendPrevLower1[1]) and not na(superTrendPrevLower2[1]) // Variables to track entry times var float longEntryTime = na var float shortEntryTime = na // Variables to track whether we have recently exited a trade to prevent re-entry in the same trend var bool recentlyExitedLong = false var bool recentlyExitedShort = false // Check trade direction choice before executing trade entries. if (enterLongCondition and (tradeDirectionChoice == "Long" or tradeDirectionChoice == "Both")) if (strategy.position_size < 0) strategy.close("Short Position") strategy.entry("Long Position", strategy.long) longEntryTime := time recentlyExitedLong := false recentlyExitedShort := false if (enterShortCondition and (tradeDirectionChoice == "Short" or tradeDirectionChoice == "Both")) if (strategy.position_size > 0) strategy.close("Long Position") strategy.entry("Short Position", strategy.short) shortEntryTime := time recentlyExitedShort := false recentlyExitedLong := false // Exit conditions: Either condition being met will trigger an exit. exitLongCondition = marketTrend1 == -1 or marketTrend2 == -1 exitShortCondition = marketTrend1 == 1 or marketTrend2 == 1 // Close positions based on exit conditions or hold days. if (useHoldDays and not na(longEntryTime) and (time >= longEntryTime + holdDays * 86400000) and strategy.position_size > 0) strategy.close("Long Position") longEntryTime := na recentlyExitedLong := true if (useHoldDays and not na(shortEntryTime) and (time >= shortEntryTime + holdDays * 86400000) and strategy.position_size < 0) strategy.close("Short Position") shortEntryTime := na recentlyExitedShort := true if (not useHoldDays and exitLongCondition and strategy.position_size > 0) strategy.close("Long Position") longEntryTime := na recentlyExitedLong := true if (not useHoldDays and exitShortCondition and strategy.position_size < 0) strategy.close("Short Position") shortEntryTime := na recentlyExitedShort := true // Reset recently exited flags on trend change to allow re-entry on a new trend if (trendShiftToBullish1 or trendShiftToBullish2) recentlyExitedLong := false if (trendShiftToBearish1 or trendShiftToBearish2) recentlyExitedShort := false // Conditional Profit and Loss Management if (TPSLCondition == "TP" or TPSLCondition == "Both") // Apply take profit conditions strategy.exit("TakeProfit_Long", "Long Position", limit=close * (1 + takeProfitPerc / 100)) strategy.exit("TakeProfit_Short", "Short Position", limit=close * (1 - takeProfitPerc / 100)) if (TPSLCondition == "SL" or TPSLCondition == "Both") // Apply stop loss conditions strategy.exit("StopLoss_Long", "Long Position", stop=close * (1 - stopLossPerc / 100)) strategy.exit("StopLoss_Short", "Short Position", stop=close * (1 + stopLossPerc / 100)) // Ensure that new entry signals can override the hold days condition if (enterLongCondition and (tradeDirectionChoice == "Long" or tradeDirectionChoice == "Both")) if (strategy.position_size < 0) strategy.close("Short Position") strategy.entry("Long Position", strategy.long) longEntryTime := time recentlyExitedLong := false recentlyExitedShort := false if (enterShortCondition and (tradeDirectionChoice == "Short" or tradeDirectionChoice == "Both")) if (strategy.position_size > 0) strategy.close("Long Position") strategy.entry("Short Position", strategy.short) shortEntryTime := time recentlyExitedShort := false recentlyExitedLong := false