这是一个基于趋势跟踪的突破策略。它在出现突破时买入力度较强的股票,在出现突破时卖出力度较弱的股票,实现趋势跟踪。
该策略主要基于两个指标判断进入和退出信号,一个是 highest()函数判断的一定周期内的最高价,一个是 lowest()函数判断的一定周期内的最低价。
当收盘价高于过去一定周期(参数highPeriod)的最高价时,认为这是上涨趋势的突破,因此发出做多信号。当收盘价低于过去一定周期(参数lowPeriod)的最低价时,认为这是下跌趋势的突破,因此发出做空信号。
这个策略同时设定了移动止损和固定止损。移动止损基于ATR指标,通过计算一定周期内的ATR值,并乘以一个倍数(参数trailingAtrMultiplier)作为移动止损位。固定止损也类似,基于ATR指标计算得到。
在做多做空后的首根K线,固定止损生效;之后转为以移动止损为主。这种组合可以锁定部分利润,同时跟踪趋势。
该策略还设定了仓位计算规则。基于可承受的最大损失百分比、账户权益等计算出仓位。并考虑了交易品种数,适当降低单一品种的仓位。
总体来说,这是一个典型的趋势跟踪型策略,它在判断到突破发生时进入场内,通过止损方式锁定利润并跟踪趋势,在趋势反转时退出场外。
这是一个突破策略,它的主要优势在于:
趋势判断准确。用最高价和最低价判断趋势是否反转,准确性很高,不易发出错误信号。
仓位和止损科学合理。最大损失比例设定、账户权益关联等使得仓位合理,避免超量或无效交易。组合止损方式锁定利润且跟踪趋势运行。
简单实用,容易理解使用。只需要最基本的指标,策略逻辑简单清晰,易于掌握。
可扩展性好。指标参数、仓位规则等都提供了输入框,用户可以根据需要调整。
总的来说,这是一个实用性很强的突破策略。在判断上安全可靠,同时策略设计考虑到了风险控制和跟踪。非常适合中长线持有。
该策略的主要风险在于:
趋势反转风险。突破策略对趋势判断非常依赖,一旦判断错误,可能面临巨额亏损。
参数不当风险。最高价最低价周期参数选择不当可能错过趋势,仓位参数设定不当可能亏损过大。
止损过于激进风险。如果移动止损距离过小,可能会被市场噪音打出场外。
主要的解决方法是:
增加趋势过滤。例如加入其他指标判断,避免错误突破。
优化参数选择。对参数进行测试优选取值,确保其稳定性。
止损距离可适当放宽。让止损距离能包容一定回调。
该策略主要可从以下方向进行优化:
增加更多指标判断趋势。除最高最低价外,可加入移动均线等判断,使趋势判断更为准确。
优化参数设置。对最高最低价周期参数、止损倍数参数等进行测试,选择最优参数组合。
根据市场调整仓位算法。可让仓位与市场波动性挂钩,如VIX上涨时降低仓位。
增加量能指标过滤。只在量能放大的突破中进入,避免虚假突破。
考虑基差和相关性优选交易品种。选择基差波动小、相关性低的品种组合,可降低组合风险。
优化和调整止损机制。可测试移动止损和固定止损的比例组合,降低止损过于激进的风险。
该策略作为一个趋势跟踪型的突破策略,在判断准确性、仓位与风险控制、操作简便性等方面表现不错。它captured了趋势的早期,通过移动止损平衡了利润的锁定和趋势跟踪。
当然作为突破策略,它对趋势判断的依赖性非常高,容易受到噪音的干扰。此外参数设置不当也可能影响策略表现。这需要通过进一步优化来解决。
总的来说,这是一个非常实用的策略,它的基本结构就已经包含了一个量化策略所需要的最关键要素。如果能够不断优化和改进,完全可以成为稳定盈利的程序化策略。值得量化人学习和参考。
/*backtest
start: 2023-12-01 00:00:00
end: 2023-12-31 23:59:59
period: 1h
basePeriod: 15m
exchanges: [{"eid":"Futures_Binance","currency":"BTC_USDT"}]
*/
//@version=4
strategy(shorttitle="Trend Surfers - Breakout", title="Trend Surfers - Premium Breakout",
overlay=true)
// Risk for position and pyramid
maxriskval = input(2, "Max % risk", type = input.float,
tooltip="Risk % over total equity / Position", group = "Risk Management")
pairnumber = input(title = "How many pairs",type = input.integer, defval= 1,
tooltip="How many pairs are you trading with the strategy?", group = "Risk Management")
// Emtry Exit
highPeriod = input(title="Highest High Period", type=input.integer, defval=168
, tooltip="Highest High of X bars - This will trigger a Long Entry when close is above. (Thin Green Line)"
, group = "Entry Condition")
lowPeriod = input(title="Lowest Low Period", type=input.integer, defval=168,
tooltip="Lowest low of X bars - This will trigger a Short Entry when close is under. (Thin Red Line)"
, group = "Entry Condition")
// Stoploss
trailingAtrPeriod = input(title="Trailing ATR Pediod", type=input.integer, defval=10,
tooltip="Average True Range for the Trailing Stop. (Thick Green Line) "
, group = "Exit Condition")
trailingAtrMultiplier = input(title="Trailing ATR Multiplier", type=input.float, defval=8
, group = "Exit Condition")
fixAtrPeriod = input(title="Fix ATR Pediod", type=input.integer, defval=10,
tooltip="Average True Range for the Fix Stoloss. (Thick Yellow Line)"
, group = "Exit Condition")
fixAtrMultiplier = input(title="Fix ATR Multiplier", type=input.float, defval=2
, group = "Exit Condition")
// Pair info
pair = syminfo.basecurrency + syminfo.currency
// High Low Variable
highestHigh = highest(high, highPeriod)[1]
lowestLow = lowest(low, lowPeriod)[1]
trailingAtr = atr(trailingAtrPeriod) * trailingAtrMultiplier
// Trade Condition
longCondition = crossover(close, highestHigh)
shortCondition = crossunder(close, lowestLow)
// Risk Variable
fixAtr = atr(fixAtrPeriod) * fixAtrMultiplier
stopvaluelong = close[1] - fixAtr[1]
stopvalueshort = close[1] + fixAtr[1]
// Position size Long
maxpossize = strategy.equity / close
positionsizelong = ( ( ( (maxriskval/100) * strategy.equity) / (close - stopvaluelong)))
stopperclong = ((close - stopvaluelong) / close) * 100
leveragelong = max(1, ceil(positionsizelong / maxpossize)) * 2
posperclong = (((positionsizelong * close) / strategy.equity) *100 / leveragelong) / pairnumber
realposlong = (((posperclong / 100) * strategy.equity) * leveragelong) / close
// Position size Short
positionsizeshort = ( ( ( (maxriskval/100) * strategy.equity) / (stopvalueshort - close)))
stoppercshort = ((close - stopvalueshort) / close) * 100
leverageshort = max(1, ceil(positionsizeshort / maxpossize)) * 2
pospercshort = (((positionsizeshort * close) / strategy.equity) *100 / leverageshort) / pairnumber
realposshort = (((pospercshort / 100) * strategy.equity) * leverageshort) / close
// Alert Message
entry_long_message = '\nGo Long for ' + pair + 'NOW!' +
'\nPosition Size % =' + tostring(posperclong) +
'\nLeverage' + tostring(leveragelong) +
'\nStoploss Price =' + tostring(stopvaluelong) +
'\nClose any Short position that are open for ' + pair + '!' +
'\n\nVisit TrendSurfersSignals.com' +
'\nFor automated premium signals (FREE)'
entry_short_message ='\nGo Short for ' + pair + 'NOW!' +
'\nPosition Size % =' + tostring(pospercshort) +
'\nLeverage' + tostring(leverageshort) +
'\nStoploss Price =' + tostring(stopvalueshort) +
'\nClose any Long position that are open for ' + pair + '!' +
'\n\nVisit TrendSurfersSignals.com' +
'\nFor automated premium signals (FREE)'
exit_short_message = '\nExit Short for ' + pair + 'NOW!' +
'\n\nVisit TrendSurfersSignals.com' +
'\nFor automated premium signals (FREE)'
exit_long_message = '\nExit Long for ' + pair + 'NOW!' +
'\n\nVisit TrendSurfersSignals.com' +
'\nFor automated premium signals (FREE)'
// Order
if longCondition
strategy.entry("Long", strategy.long, stop=highestHigh, comment="Long", qty=realposlong
, alert_message = entry_long_message)
if shortCondition
strategy.entry("Short", strategy.short, stop=lowestLow, comment="Short", qty=realposshort
, alert_message = entry_short_message)
// Stoploss Trailing
longTrailing = close - trailingAtr
shortTrailing = close + trailingAtr
var longTrailingStop = 0.0
var shortTrailingStop = 999999.9
trailingStopLine = 0.0
trailingStopLine := na
fixedStopLine = 0.0
fixedStopLine := na
var inTrade = 0
if longCondition or shortCondition
if 0 == inTrade
if longCondition
inTrade := 1
else
inTrade := -1
if 1 == inTrade and (shortCondition or low <= max(fixedStopLine[1], longTrailingStop))
inTrade := 0
if -1 == inTrade and (longCondition or high >= min(fixedStopLine[1], shortTrailingStop))
inTrade := 0
longTrailingStop := if (1 == inTrade)
stopValue = longTrailing
max(stopValue, longTrailingStop[1])
else
0
shortTrailingStop := if (-1 == inTrade)
stopValue = shortTrailing
min(stopValue, shortTrailingStop[1])
else
999999
// Fix Stoploss
firstPrice = 0.0
firstFixAtr = 0.0
firstPrice := na
firstFixAtr := na
if 0 != inTrade
firstPrice := valuewhen(inTrade != inTrade[1] and 0 != inTrade, close, 0)
firstFixAtr := valuewhen(inTrade != inTrade[1] and 0 != inTrade, fixAtr, 0)
if 1 == inTrade
fixedStopLine := firstPrice - firstFixAtr
trailingStopLine := longTrailingStop
else
fixedStopLine := firstPrice + firstFixAtr
trailingStopLine := shortTrailingStop
if (strategy.position_size > 0)
strategy.exit(id="L Stop", stop=max(fixedStopLine, longTrailingStop)
, alert_message = exit_long_message)
if (strategy.position_size < 0)
strategy.exit(id="S Stop", stop=min(fixedStopLine, shortTrailingStop)
, alert_message = exit_long_message)
// Plot
plot(highestHigh, color=color.green, linewidth=1, transp=0, title='Highest High')
plot(lowestLow, color=color.red, linewidth=1, transp=0, title='Lowest Low')
plot(trailingStopLine, color=color.lime, linewidth=2, transp=0, offset=1, title='Trailing Stop')
plot(fixedStopLine, color=color.orange, linewidth=2, transp=0, offset=1, title='Fixed Stop')