这是一个基于趋势跟踪的突破策略。它在出现突破时买入力度较强的股票,在出现突破时卖出力度较弱的股票,实现趋势跟踪。
该策略主要基于两个指标判断进入和退出信号,一个是 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')