多周期动态波动率跟踪策略是一个结合了快速/慢速指数移动平均线(EMA)交叉与相对强弱指数(RSI)过滤器的短线交易系统。该策略专注于在主导短期趋势内寻找回调机会进行交易,通过多重确认机制减少噪音交易。其核心特点包括基于平均真实波幅(ATR)的风险控制、自适应跟踪止损、基于交易量的止损调整以及三级部分获利目标。此外,策略还采用了更高时间框架的RSI检查作为提前预警退出机制,避免在不利趋势中过度停留。
该策略运行原理基于多层信号堆栈架构: 1. 趋势识别:通过快速EMA与慢速EMA的交叉判断微观趋势方向。当快速EMA在慢速EMA上方时,识别为看涨趋势;反之则为看跌趋势。 2. 动量健康度过滤:防止追逐过度延伸的行情。只有在RSI低于超买水平时才允许做多;只有在RSI高于超卖水平时才允许做空。 3. K线确认机制:要求信号条件连续多根K线成立,有效过滤市场噪音。 4. 入场触发:当完成确认窗口的K线出现时发出市场订单。 5. 初始止损:基于ATR的波动率调整,并根据相对交易量进行动态调整。 6. 跟踪止损逻辑:结合枢轴点和ATR基础止损的最优化方案,实现利润锁定。 7. 高时间框架RSI监控:提供市场背景退出信号,避免逆势交易。 8. 分级获利目标:设置三个基于ATR的目标位置,实现逐步减仓。 9. 交易限制器:每个趋势阶段限制最大交易次数,防止过度交易。
策略的关键创新点在于将多重技术指标与市场行为指标(如交易量、波动率)有机结合,形成了一个自适应性强的交易系统,能够在不同市场条件下自动调整参数。
多周期动态波动率跟踪策略是一个将经典技术分析工具与现代量化风险管理方法相结合的短线交易系统。它通过多层信号堆栈架构,结合EMA趋势识别、RSI动量过滤、连续K线确认机制、ATR波动率调整和多周期分析,构建了一个全面的交易决策框架。该策略最显著的特点是其自适应性——能够根据市场波动率、交易量和趋势成熟度自动调整交易参数和风险控制措施。
尽管存在一些固有风险,如参数敏感性、高频交易成本和延迟风险等,但通过合理的资金管理和持续优化,这些风险可以得到有效控制。未来的优化方向主要集中在机器学习参数优化、市场状态分类、多指标共识机制和动态风险管理等方面。
对于希望在短线市场中捕捉趋势内回调机会的交易者,该策略提供了一个结构化的框架,平衡了交易机会捕捉与风险控制的需求。然而,与所有交易策略一样,实际应用时应先在模拟账户上充分测试,并根据个人风险承受能力和资金规模适当调整参数。
/*backtest
start: 2024-09-15 00:00:00
end: 2025-06-09 08:00:00
period: 1d
basePeriod: 1d
exchanges: [{"eid":"Futures_Binance","currency":"BTC_USDT"}]
*/
//@version=5
//@strategy_alert_message {{strategy.order.comment}}
// © AlgoSystems
strategy("Scalping Trend Power for MT5 - Updated", overlay=true, calc_on_every_tick=false)
//-------------------------------------------------------------------
// Function: confirm a condition for N consecutive bars
//-------------------------------------------------------------------
f_confirm(cond, bars) =>
_ok = true
for i = 0 to bars - 1
_ok := _ok and cond[i]
_ok
//-------------------------------------------------------------------
// Inputs: strategy parameters & PineConnector
//-------------------------------------------------------------------
lotSize = input.float(0.1, title="Lot Size")
lotMultiplier = input.float(1.0, title="Lot Multiplier", minval=0.1, step=0.1)
contractType = input.string("FX", title="Contract Type", options=["FX", "CFD", "Futures"])
// (kept for potential future use)
riskPercentage = input.float(1.0, title="Risk per Trade (%)")
riskRewardRatio = input.float(1.2, title="Risk/Reward Ratio", step=0.1)
trailingStopMultiplier = input.float(1.2, title="Trailing-Stop Multiplier", step=0.1)
emaShortLength = input.int(9, title="EMA Short Length")
emaLongLength = input.int(21, title="EMA Long Length")
rsiLength = input.int(14, title="RSI Length")
atrLength = input.int(14, title="ATR Length")
rsiOverbought = input.int(70, title="RSI Overbought Level")
rsiOversold = input.int(30, title="RSI Oversold Level")
higherTF = input.timeframe("30", title="Higher Time-Frame for Exit")
higherRsiOverbought = input.int(70, title="Higher-TF RSI Overbought", minval=50)
higherRsiOversold = input.int(30, title="Higher-TF RSI Oversold", minval=10)
pivotLookback = input.int(5, title="Pivot Look-Back Period", minval=2, step=1)
volumeLookback = input.int(20, title="Volume Look-Back Period", minval=5, step=1)
volumeMultiplier = input.float(1.0, title="Volume Multiplier", minval=0.1, step=0.1)
enablePartialExit = input.bool(true, title="Enable Partial Exit")
tp1ProfitMult = input.float(1.0, title="TP1 Profit Multiplier", step=0.1)
tp2ProfitMult = input.float(1.5, title="TP2 Profit Multiplier", step=0.1)
tp3ProfitMult = input.float(2.0, title="TP3 Profit Multiplier", step=0.1)
tp1ExitPercentage = input.float(33, title="TP1 Exit (%)", minval=1, maxval=100, step=1)
tp2ExitPercentage = input.float(33, title="TP2 Exit (%)", minval=1, maxval=100, step=1)
tp3ExitPercentage = input.float(34, title="TP3 Exit (%)", minval=1, maxval=100, step=1)
confirmBars = input.int(2, title="Confirmation Bars", minval=1, step=1)
baseLongTrades = 5
tradeDecreaseFactor = input.int(0, title="Trade Decrease Factor", minval=0)
maxLongTradesPerTrend = math.max(1, baseLongTrades - tradeDecreaseFactor)
activatePineConnector = input.bool(false, title="Activate PineConnector")
pineConnectorLicense = input.string("", title="PineConnector License Code")
//-------------------------------------------------------------------
// Indicator calculations
//-------------------------------------------------------------------
emaShort = ta.ema(close, emaShortLength)
emaLong = ta.ema(close, emaLongLength)
rsiValue = ta.rsi(close, rsiLength)
atrValue = ta.atr(atrLength)
// ATR-based TP & SL
dynamicTP = atrValue * riskRewardRatio
dynamicSL = atrValue * trailingStopMultiplier
rawLongSignal = emaShort > emaLong and rsiValue < rsiOverbought
rawShortSignal = emaShort < emaLong and rsiValue > rsiOversold
longSignal = f_confirm(rawLongSignal, confirmBars)
shortSignal = f_confirm(rawShortSignal, confirmBars)
//-------------------------------------------------------------------
// Dynamic ticker symbol (remove exchange prefix if any)
//-------------------------------------------------------------------
var string dynSymbol = na
if bar_index == 0
parts = str.split(syminfo.tickerid, ":")
dynSymbol := array.size(parts) > 1 ? array.get(parts, 1) : syminfo.tickerid
//-------------------------------------------------------------------
// PineConnector messages (no "lots=" or "contract=" – updated syntax)
// The value after risk= is interpreted as LOTS if EA’s VolumeType = "Lots".
//-------------------------------------------------------------------
prefix = activatePineConnector and (pineConnectorLicense != "") ? pineConnectorLicense + "," : ""
calculatedLot = lotSize * lotMultiplier // actual order volume
// ENTRY messages
riskValue = str.tostring(calculatedLot) // risk= interpreted as lots
txtBuy = prefix + "buy," + dynSymbol + ",risk=" + riskValue
txtSell = prefix + "sell," + dynSymbol + ",risk=" + riskValue
// CLOSE FULL messages
txtCloseLong = prefix + "closelong," + dynSymbol
txtCloseShort = prefix + "closeshort," + dynSymbol
// Helper to compute risk= for partial exits
f_partialRisk(pct) => str.tostring(calculatedLot * pct / 100)
// PARTIAL EXIT messages
msgTP1Long = prefix + "closelongvol," + dynSymbol + ",risk=" + f_partialRisk(tp1ExitPercentage)
msgTP2Long = prefix + "closelongvol," + dynSymbol + ",risk=" + f_partialRisk(tp2ExitPercentage)
msgTP3Long = prefix + "closelongvol," + dynSymbol + ",risk=" + f_partialRisk(tp3ExitPercentage)
msgTP1Short = prefix + "closeshortvol," + dynSymbol + ",risk=" + f_partialRisk(tp1ExitPercentage)
msgTP2Short = prefix + "closeshortvol," + dynSymbol + ",risk=" + f_partialRisk(tp2ExitPercentage)
msgTP3Short = prefix + "closeshortvol," + dynSymbol + ",risk=" + f_partialRisk(tp3ExitPercentage)
//-------------------------------------------------------------------
// Higher-time-frame RSI request
//-------------------------------------------------------------------
higherRsi = request.security(syminfo.tickerid, higherTF, ta.rsi(close, rsiLength))
//-------------------------------------------------------------------
// State variables
//-------------------------------------------------------------------
var bool inLongTrade = false
var bool inShortTrade = false
var int longTradeCount = 0
var float trailingStopLevel = na
var bool tp1_exited = false
var bool tp2_exited = false
var bool tp3_exited = false
//-------------------------------------------------------------------
// Entry/Exit logic
//-------------------------------------------------------------------
if barstate.isconfirmed
avgVol = ta.sma(volume, volumeLookback)
volRatio = avgVol != 0 ? volume / avgVol : 1.0
adjSL = dynamicSL / (volRatio * volumeMultiplier)
pivotH = ta.pivothigh(high, pivotLookback, pivotLookback)
pivotL = ta.pivotlow(low, pivotLookback, pivotLookback)
// LONG entry
if longSignal and not inLongTrade and not inShortTrade and longTradeCount < maxLongTradesPerTrend
strategy.entry("Long", strategy.long, qty=calculatedLot, comment="Long Entry")
if activatePineConnector
alert(txtBuy, alert.freq_once_per_bar)
inLongTrade := true
inShortTrade := false
longTradeCount += 1
trailingStopLevel := low - adjSL
tp1_exited := false
tp2_exited := false
tp3_exited := false
// SHORT entry
if shortSignal and not inShortTrade and not inLongTrade
strategy.entry("Short", strategy.short, qty=calculatedLot, comment="Short Entry")
if activatePineConnector
alert(txtSell, alert.freq_once_per_bar)
inShortTrade := true
inLongTrade := false
trailingStopLevel := high + adjSL
tp1_exited := false
tp2_exited := false
tp3_exited := false
// Trailing-stop update
if inLongTrade
baseStop = close - adjSL
trailingStopLevel := (not na(pivotL) and pivotL > trailingStopLevel) ? pivotL : math.max(trailingStopLevel, baseStop)
if inShortTrade
baseStop = close + adjSL
trailingStopLevel := (not na(pivotH) and pivotH < trailingStopLevel) ? pivotH : math.min(trailingStopLevel, baseStop)
// Dynamic TPs & partial exits
if enablePartialExit and strategy.position_size != 0
avgPrice = strategy.position_avg_price
direction = strategy.position_size > 0 ? 1 : -1
tp1 = avgPrice + direction * dynamicTP * tp1ProfitMult
tp2 = avgPrice + direction * dynamicTP * tp2ProfitMult
tp3 = avgPrice + direction * dynamicTP * tp3ProfitMult
// TP1
if not tp1_exited and f_confirm(direction > 0 ? close >= tp1 : close <= tp1, confirmBars)
strategy.exit("TP1", from_entry=direction>0 ? "Long" : "Short", qty_percent=tp1ExitPercentage, limit=tp1, comment=direction>0 ? msgTP1Long : msgTP1Short)
if activatePineConnector
alert(direction>0 ? msgTP1Long : msgTP1Short, alert.freq_once_per_bar)
tp1_exited := true
// TP2
if not tp2_exited and f_confirm(direction > 0 ? close >= tp2 : close <= tp2, confirmBars)
strategy.exit("TP2", from_entry=direction>0 ? "Long" : "Short", qty_percent=tp2ExitPercentage, limit=tp2, comment=direction>0 ? msgTP2Long : msgTP2Short)
if activatePineConnector
alert(direction>0 ? msgTP2Long : msgTP2Short, alert.freq_once_per_bar)
tp2_exited := true
// TP3
if not tp3_exited and f_confirm(direction > 0 ? close >= tp3 : close <= tp3, confirmBars)
strategy.exit("TP3", from_entry=direction>0 ? "Long" : "Short", qty_percent=tp3ExitPercentage, limit=tp3, comment=direction>0 ? msgTP3Long : msgTP3Short)
if activatePineConnector
alert(direction>0 ? msgTP3Long : msgTP3Short, alert.freq_once_per_bar)
tp3_exited := true
// FULL exit (trailing stop or opposite signals)
exitCondLong = inLongTrade and (close < trailingStopLevel or rsiValue > rsiOverbought or higherRsi > higherRsiOverbought)
exitCondShort = inShortTrade and (close > trailingStopLevel or rsiValue < rsiOversold or higherRsi < higherRsiOversold)
if exitCondLong and f_confirm(exitCondLong, confirmBars)
strategy.exit("ExitLong", from_entry="Long", stop=trailingStopLevel, comment=txtCloseLong)
if activatePineConnector
alert(txtCloseLong, alert.freq_once_per_bar)
inLongTrade := false
if exitCondShort and f_confirm(exitCondShort, confirmBars)
strategy.exit("ExitShort", from_entry="Short", stop=trailingStopLevel, comment=txtCloseShort)
if activatePineConnector
alert(txtCloseShort, alert.freq_once_per_bar)
inShortTrade := false
// Reset counter when the bullish trend ends
if not rawLongSignal
longTradeCount := 0
//-------------------------------------------------------------------
// Plot & styling
//-------------------------------------------------------------------
plot(emaShort, color=color.blue, linewidth=1, title="EMA Short")
plot(emaLong , color=color.red , linewidth=1, title="EMA Long")
barcolor(inLongTrade ? color.new(color.green,0) : inShortTrade ? color.new(color.red,0) : na)
bgcolor(rawLongSignal ? color.new(color.green,90) : rawShortSignal ? color.new(color.red,90) : na)
// Signal arrows disabled (user request):
// plotshape(longSignal , title="Long signal", style=shape.triangleup, location=location.belowbar, color=color.green, size=size.tiny)
// plotshape(shortSignal, title="Short signal", style=shape.triangledown, location=location.abovebar, color=color.red, size=size.tiny)
//-------------------------------------------------------------------
// HOW TO USE with PineConnector (quick checklist):
// 1. Attach this script to the chart.
// 2. Click the “Alert” bell → Create Alert.
// 3. Condition: “Scalping Trend Power … (Any alert() call)” (or “Order fills only”).
// 4. Webhook URL: https://webhook.pineconnector.com
// 5. Leave the Message box empty – the script fills it.
// 6. On MT5, run the PineConnector EA on the same symbol (dynSymbol) and keep VolumeType = Lots.
// 7. Enter your License ID in the input and tick “Activate PineConnector”.
//-------------------------------------------------------------------