该策略基于商品通道指数(CCI)指标,采用动态适应性 entries 标准来判断趋势反转的时机,同时利用追踪止损来锁定利润。策略名称“望远适应 CCI 底部捕捉商品交易策略”包含了该策略的核心要点:利用 CCI 指标判断超卖区域来捕捉反转机会,并采用动态适应性 entries 水平来优化 entries 时机。
核心指标为 CCI 指标,用于判断超卖区域从而提示趋势反转的机会。另外,根据不同标的以及市场环境,CCI 超卖区域的幅度也会有所不同。因此,本策略采用“望远”的方式,判断过去一段时间 CCI 最低点的位置,动态设定 CCI 买入水平。如果过去 40 天内最低 CCI 点大于 -90,那么 -90 作为新的超卖区域水平;如果过去 50 天内 CCI 最低点大于 -70,那么以 -70 作为新的超卖区域水平,依此类推。这样的设计使得 entries 水平动态适应不同的市场环境,在跌势较强的市场中追求更小的风险 entries,而在区间整理的市场中 entries 水平会更宽松一些。
具体来说,默认买入信号的 CCI 水平为 -145。然后判断过去 40 天、50 天等不同天数内 CCI 最低点的位置,如果最低点高于默认水平的下一级别比如 -90,那么以 -90 作为新的 entries 水平。如果最低点再高于 -90,以 -70 作为新的 entries 水平,依此类推。这样entries 水平可以在 -145 / -90 / -70 / -50 / -4 / 0 / +25 / +50 / +70 之间动态切换。当 CCI 低于对应水平时产生买入信号。
此外,策略还采用追踪止损来锁定利润,止损水平随着价格运行不断上移。
相比固定的 entries 水平,这样的动态设计使得 entries 时机可以得到优化。在跌势较强的市场中追求更高的 entries 标准可以减小风险;而在震荡区间整理的市场中降低 entries 标准可以抓住更多机会。这样的设计增强了策略的适应性。
CCI 本身作为判断超买超卖的指标也较为清晰可靠,基于 CCI 判读趋势反转的思路行之有效。结合动态 entries 设计,本策略整体优势显著。
基于 CCI 判断趋势转折点的思路有一定的滞后性,当价格快速拉升或者暴跌时, Entries 时机可能会不准。此外,Entries 水平的动态适应机制也难以完美匹配当前市场环境,这导致 Entries 不一定是最优时机。最后,商品市场本身波动较大,即便设置了止损,但具体参数设置不当时也可能造成较大的亏损。
主要可以从 CCI 参数本身、Entries 水平设定以及止损参数几个方面进行优化。针对具体标的来精确定位更优参数可以提升策略的效果。
该策略综合运用 CCI 指标判断超买超卖的思路以及动态适应性 Entries 水平设计,对突破性趋势进行捕捉。相比固定参数,动态 Entries 水平明显增强了策略的适应性。基于 Entries 反转捕捉模式与追踪止损结合,可以抓住较强势头的机会并及时止损。该策略在参数设置精确的前提下,整体效果可行性强。后续可继续优化 CCI 参数设定以及 Entries 水平判定来进一步提高策略的稳定性与收益率。
/*backtest
start: 2023-11-20 00:00:00
end: 2023-12-20 00:00:00
period: 1h
basePeriod: 15m
exchanges: [{"eid":"Futures_Binance","currency":"BTC_USDT"}]
*/
//@version=5
strategy("Extended Adaptive CCI Entry Strategy for Commodities", shorttitle="Ext_Adaptive_CCI_Entry_Com", overlay=true)
// Inputs
cciLength = input(20, title="CCI Period")
defaultCCIEntryOversold = input(-145, title="Default CCI Entry Oversold Level")
adaptiveCCIEntryLevel90 = input(-90, title="Adaptive CCI Entry Level for 40 Days")
adaptiveCCIEntryLevel70_50Days = input(-70, title="Adaptive CCI Entry Level for 50 Days")
adaptiveCCIEntryLevel50 = input(-50, title="Adaptive CCI Entry Level for 60 Days")
adaptiveCCIEntryLevel4 = input(-4, title="Adaptive CCI Entry Level for 90 Days")
adaptiveCCIEntryLevel0 = input(0, title="Adaptive CCI Entry Level for 120 Days")
adaptiveCCIEntryLevel25 = input(25, title="Adaptive CCI Entry Level for 140 Days")
adaptiveCCIEntryLevel50_160Days = input(50, title="Adaptive CCI Entry Level for 160 Days")
adaptiveCCIEntryLevel70_180Days = input(70, title="Adaptive CCI Entry Level for 180 Days")
lookback40 = input(40, title="Lookback Period for -90 Level")
lookback50 = input(50, title="Lookback Period for -70 Level")
lookback60 = input(60, title="Lookback Period for -50 Level")
lookback90 = input(90, title="Lookback Period for -4 Level")
lookback120 = input(120, title="Lookback Period for 0 Level")
lookback140 = input(140, title="Lookback Period for +25 Level")
lookback160 = input(160, title="Lookback Period for +50 Level")
lookback180 = input(180, title="Lookback Period for +70 Level")
// Indicator Calculation
cci = ta.cci(close, cciLength)
// Determine adaptive entry level based on lookback periods
var float entryLevel = defaultCCIEntryOversold // Initialize with the default level
if ta.lowest(cci, lookback40) > adaptiveCCIEntryLevel90
entryLevel := adaptiveCCIEntryLevel90
if ta.lowest(cci, lookback50) > adaptiveCCIEntryLevel70_50Days
entryLevel := adaptiveCCIEntryLevel70_50Days
if ta.lowest(cci, lookback60) > adaptiveCCIEntryLevel50
entryLevel := adaptiveCCIEntryLevel50
if ta.lowest(cci, lookback90) > adaptiveCCIEntryLevel4
entryLevel := adaptiveCCIEntryLevel4
if ta.lowest(cci, lookback120) > adaptiveCCIEntryLevel0
entryLevel := adaptiveCCIEntryLevel0
if ta.lowest(cci, lookback140) > adaptiveCCIEntryLevel25
entryLevel := adaptiveCCIEntryLevel25
if ta.lowest(cci, lookback160) > adaptiveCCIEntryLevel50_160Days
entryLevel := adaptiveCCIEntryLevel50_160Days
if ta.lowest(cci, lookback180) > adaptiveCCIEntryLevel70_180Days
entryLevel := adaptiveCCIEntryLevel70_180Days
// Entry Condition
longCondition = cci < entryLevel
// Entry and Exit
if (longCondition)
strategy.entry("Long", strategy.long, qty=1)
alert("Long entry executed at " + str.tostring(close), alert.freq_once_per_bar)
trailOffset = input(10.0, title="Trailing Stop Offset in USD")
strategy.exit("Trailing Stop", "Long", trail_offset = trailOffset, trail_price = close)
if (close < entryLevel - trailOffset)
alert("Long position closed at " + str.tostring(close), alert.freq_once_per_bar)
// Plotting
plot(series=cci, color=color.purple, title="CCI")
hline(price=defaultCCIEntryOversold, color=color.red, title="Default CCI Entry Oversold Level")
hline(price=adaptiveCCIEntryLevel90, color=color.orange, title="CCI -90 Level (40 Days)")
hline(price=adaptiveCCIEntryLevel70_50Days, color=color.yellow, title="CCI -70 Level (50 Days)")
hline(price=adaptiveCCIEntryLevel50, color=color.green, title="CCI -50 Level (60 Days)")
hline(price=adaptiveCCIEntryLevel4, color=color.blue, title="CCI -4 Level (90 Days)")
hline(price=adaptiveCCIEntryLevel0, color=color.purple, title="CCI 0 Level (120 Days)")
hline(price=adaptiveCCIEntryLevel25, color=color.aqua, title="CCI +25 Level (140 Days)")
hline(price=adaptiveCCIEntryLevel50_160Days, color=color.black, title="CCI +50 Level (160 Days)")
hline(price=adaptiveCCIEntryLevel70_180Days, color=color.gray, title="CCI +70 Level (180 Days)")