中心引力通道趋势跟踪策略


创建日期: 2023-09-19 21:30:23 最后修改: 2023-09-19 21:30:23
复制: 0 点击次数: 622
avatar of ChaoZhang ChaoZhang
1
关注
1362
关注者

概述

该策略融合了中心引力指标和SSL通道指标,实现价格趋势的判断和突破跟踪,属于趋势跟踪类策略。同时结合动态ATR止损来控制风险。

策略原理

  1. 计算中心引力指标,其中上轨和下轨分别为价格上涨和下跌的趋势界限。

  2. 计算SSL通道指标,通道内部为盘整区间,通道外部为趋势方向。

  3. 当价格突破上轨或通道时判断为上涨趋势并做多;当价格突破下轨或通道时判断为下跌趋势并做空。

  4. 在持仓时使用动态ATR止损来跟踪止损位,避免亏损扩大。

  5. 结合回测时间段来产生实际的交易信号。

该策略同时利用两个指标判断趋势方向,一个用来判断突破,一个用来确认趋势,二者结合可以提高判断准确性。动态止损可以根据市场波动幅度来调整止损位,是一个非常实用的风险控制手段。

优势分析

  1. 同时利用两个指标判断趋势,可以提高准确率。

  2. 中心引力指标对趋势变化敏感,SSL通道判断趋势方向 cleared。

  3. 动态ATR止损根据市场波动实时调整止损位,具有灵活性。

  4. 策略规则简单清晰,易于理解和实现。

  5. 参数优化空间大,可以针对不同市场进行调整。

  6. 回测功能完备,可以验证策略效果。

风险分析

  1. 中心引力指标和SSL通道都可能出现失效的情况,导致交易信号错误。可以加入其他指标进行确认。

  2. 动态止损可能过于激进,可以适当放宽止损幅度。

  3. 回测时间段选择不当可能导致策略效果不佳,需要针对不同市场阶段进行回测。

  4. 需要充分考虑交易成本的影响。

优化方向

  1. 测试不同参数组合,找到最佳参数对。

  2. 优化动态止损的ATR周期和倍数参数。

  3. 引入其他指标进行信号过滤,如MACD、KDJ等。

  4. 增加机器学习模型来辅助判断趋势方向。

  5. 优化资金管理,设定仓位控制。

  6. 针对具体品种进行参数调整和优化。

总结

该策略结合中心引力指标和SSL通道指标来判断趋势,使用动态ATR止损控制风险,是一个可实际操作的趋势跟踪策略。通过参数优化、引入其他指标以及机器学习等方式进行改进,可以进一步提升策略稳定性和实战效果。总体来说,该策略具有较强的实用性和拓展性,是量化交易的一个值得参考的策略思路。

策略源码
/*backtest
start: 2023-08-19 00:00:00
end: 2023-09-13 00:00:00
period: 1h
basePeriod: 15m
exchanges: [{"eid":"Futures_Binance","currency":"BTC_USDT"}]
*/

//@version=4
// Thanks to HPotter for the original code for Center of Gravity Backtest
strategy("CoG SSL BF 🚀", overlay=true, initial_capital=10000, default_qty_type=strategy.percent_of_equity, default_qty_value=100, commission_type=strategy.commission.percent, commission_value=0.075)

/////////////// Time Frame ///////////////
_0 = input(false,  "════════ Test Period ═══════")
testStartYear = input(2017, "Backtest Start Year") 
testStartMonth = input(1, "Backtest Start Month")
testStartDay = input(1, "Backtest Start Day")
testPeriodStart = timestamp(testStartYear,testStartMonth,testStartDay, 0, 0)

testStopYear = input(2019, "Backtest Stop Year")
testStopMonth = input(12, "Backtest Stop Month")
testStopDay = input(31, "Backtest Stop Day")
testPeriodStop = timestamp(testStopYear,testStopMonth,testStopDay, 0, 0)

testPeriod() => true

/////////////// SSL Channels /////////////// 
_1 = input(false,  "═════════ SSL ══════════")
len1=input(title="SMA Length 1", defval=12)
len2=input(title="SMA Length 2", defval=13)

smaHigh = sma(high, len1)
smaLow = sma(low, len2)

Hlv = 0
Hlv := close > smaHigh ? 1 : close < smaLow ? -1 : Hlv[1]
sslDown = Hlv < 0 ? smaHigh : smaLow
sslUp = Hlv < 0 ? smaLow : smaHigh

///////////// Center of Gravity /////////////
_2 = input(false,  "═════════ CoG ══════════")
Length = input(25, minval=1)
m = input(5, minval=0)
Percent = input(6, minval=0, title="COG %")

xLG = linreg(close, Length, m)
xLG1r = xLG + ((close * Percent) / 100)
xLG1s = xLG - ((close * Percent) / 100)

pos = 0.0
pos := iff(close > xLG1r, 1, iff(close < xLG1s, -1, nz(pos[1], 0))) 
possig = iff(pos == 1, 1, iff(pos == -1, -1, pos))

///////////// Rate Of Change ///////////// 
_3 = input(false,  "══════ Rate of Change ══════")
source = close
roclength = input(2, "ROC Length",  minval=1)
pcntChange = input(10, "ROC % Change", minval=1)
roc = 100 * (source - source[roclength]) / source[roclength]
emaroc = ema(roc, roclength / 2)
isMoving() => emaroc > (pcntChange / 2) or emaroc < (0 - (pcntChange / 2))

/////////////// Srategy ///////////////
long = possig == 1 or (sslUp > sslDown and isMoving())
short = possig == -1 or (sslUp < sslDown and isMoving())

last_long = 0.0
last_short = 0.0
last_long := long ? time : nz(last_long[1])
last_short := short ? time : nz(last_short[1])

long_signal = crossover(last_long, last_short)
short_signal = crossover(last_short, last_long)

last_open_long_signal = 0.0
last_open_short_signal = 0.0
last_open_long_signal := long_signal ? open : nz(last_open_long_signal[1])
last_open_short_signal := short_signal ? open : nz(last_open_short_signal[1])

last_long_signal = 0.0
last_short_signal = 0.0
last_long_signal := long_signal ? time : nz(last_long_signal[1])
last_short_signal := short_signal ? time : nz(last_short_signal[1])

in_long_signal = last_long_signal > last_short_signal
in_short_signal = last_short_signal > last_long_signal

last_high = 0.0
last_low = 0.0
last_high := not in_long_signal ? na : in_long_signal and (na(last_high[1]) or high > nz(last_high[1])) ? high : nz(last_high[1])
last_low := not in_short_signal ? na : in_short_signal and (na(last_low[1]) or low < nz(last_low[1])) ? low : nz(last_low[1])

since_longEntry = barssince(last_open_long_signal != last_open_long_signal[1]) 
since_shortEntry = barssince(last_open_short_signal != last_open_short_signal[1]) 

/////////////// Dynamic ATR Stop Losses ///////////////
_4 = input(false,  "════════ Stop Loss ═══════")
atrLkb = input(1, minval=1, title='ATR Stop Period')
atrMult = input(2, step=0.25, title='ATR Stop Multiplier') 
atr1 = atr(atrLkb)

longStop = 0.0
longStop :=  short_signal ? na : long_signal ? close - (atr1 * atrMult) : longStop[1]
shortStop = 0.0
shortStop := long_signal ? na : short_signal ? close + (atr1 * atrMult) : shortStop[1]

/////////////// Execution ///////////////
if testPeriod()
    strategy.entry("L",  strategy.long, when=long)
    strategy.entry("S", strategy.short, when=short)
    strategy.exit("L SL", "L", stop=longStop, when=since_longEntry > 0)
    strategy.exit("S SL", "S", stop=shortStop, when=since_shortEntry > 0)

/////////////// Plotting ///////////////
p1 = plot(sslDown, linewidth = 1, color=color.red, title="SSL down")
p2 = plot(sslUp, linewidth = 1, color=color.lime, title="SSL up")
fill(p1, p2,  color = not isMoving() ? color.white : sslDown < sslUp ? color.lime : color.red, transp=80)
plot(xLG1r, color=color.lime, title="LG1r")
plot(xLG1s, color=color.red, title="LG1s")
plot(strategy.position_size <= 0 ? na : longStop, title="Long Stop Loss", color=color.yellow, style=plot.style_circles, linewidth=1)
plot(strategy.position_size >= 0 ? na : shortStop, title="Short Stop Loss", color=color.orange, style=plot.style_circles, linewidth=1)
bgcolor(long ? color.green : short ? color.red : not isMoving() ? color.white : na, transp=80)
bgcolor(long_signal ? color.lime : short_signal ? color.red : na, transp=60)