本策略是一个结合了均线交叉信号与市场状态过滤的交易系统。它通过9周期与21周期简单移动平均线(SMA)的交叉来捕捉市场趋势,同时利用平均方向指数(ADX)和混沌指数(Choppiness Index, CI)来过滤市场环境,确保只在趋势明确且波动特征良好的市场中进行交易。这种方法有效地将传统的趋势跟踪策略与现代技术指标相结合,提供了一个更加稳健的交易框架。
策略的核心逻辑包含三个关键组成部分: 1. 趋势信号生成:使用9周期和21周期SMA的交叉来确定趋势方向,形成基础的交易信号。 2. 趋势强度确认:通过ADX指标(设定阈值为20)来验证趋势的强度,确保只在趋势明确的市场环境中交易。 3. 市场波动过滤:引入混沌指数(阈值设为50)来识别市场的波动特征,避免在剧烈震荡的市场中交易。
策略采用了优化的技术指标计算方法,包括自定义的求和函数、最高值和最低值计算,以及标准化的真实波幅(TR)计算,确保了信号的准确性和计算效率。
该策略通过将经典的均线交叉策略与现代技术指标相结合,构建了一个完整的交易系统。它不仅注重趋势的捕捉,还特别关注市场环境的适宜性,通过多重过滤机制提高了交易的稳定性。虽然存在一定的参数敏感性和滞后性问题,但通过提出的优化方向,策略仍有较大的改进空间。整体而言,这是一个逻辑完整、实用性强的交易策略。
/*backtest
start: 2024-02-22 00:00:00
end: 2024-12-06 00:00:00
period: 1d
basePeriod: 1d
exchanges: [{"eid":"Binance","currency":"ETH_USDT"}]
*/
//@version=6
strategy("MA9/MA21 Cross with ADX & CHOP Filter", overlay=true, initial_capital=10000, currency=currency.USD)
// ─── CUSTOM FUNCTIONS ──────────────────────────────────────────────────────
// Custom function to compute the sum over the last 'len' bars.
f_sum(src, len) =>
s = 0.0
for i = 0 to len - 1
s += src[i]
s
// Custom function to compute the highest value over the last 'len' bars.
f_highest(src, len) =>
h = src[0]
for i = 1 to len - 1
h := math.max(h, src[i])
h
// Custom function to compute the lowest value over the last 'len' bars.
f_lowest(src, len) =>
l = src[0]
for i = 1 to len - 1
l := math.min(l, src[i])
l
// ─── INPUTS ──────────────────────────────────────────────────────────────
ma9Period = input.int(9, title="MA 9 Period", minval=1)
ma21Period = input.int(21, title="MA 21 Period", minval=1)
adxLength = input.int(7, title="ADX Smoothing / DI Length", minval=1)
adxThresh = input.float(20.0, title="ADX Threshold", step=0.1)
chopLen = input.int(7, title="CHOP Length", minval=1)
chopOff = input.int(0, title="CHOP Offset", minval=0) // Not applied in calculation
chopThresh = input.float(50.0, title="CHOP Maximum (do not trade if above)", step=0.1)
// ─── CALCULATE INDICATORS ────────────────────────────────────────────────────
// Moving Averages
ma9 = ta.sma(close, ma9Period)
ma21 = ta.sma(close, ma21Period)
// --- True Range Calculation ---
// Manual implementation of true range (tr)
tr = math.max(math.max(high - low, math.abs(high - nz(close[1]))), math.abs(low - nz(close[1])))
// --- ADX Calculation (Manual Implementation) ---
// Calculate directional movements
upMove = high - nz(high[1])
downMove = nz(low[1]) - low
plusDM = (upMove > downMove and upMove > 0) ? upMove : 0.0
minusDM = (downMove > upMove and downMove > 0) ? downMove : 0.0
// Smooth the values using the built-in rma function
atr = ta.rma(tr, adxLength)
plusDI = 100 * ta.rma(plusDM, adxLength) / atr
minusDI = 100 * ta.rma(minusDM, adxLength) / atr
dx = 100 * math.abs(plusDI - minusDI) / (plusDI + minusDI)
adxValue = ta.rma(dx, adxLength)
// --- Choppiness Index Calculation ---
// Compute the sum of true range over chopLen periods
atrSum = f_sum(tr, chopLen)
// Compute highest high and lowest low over chopLen periods using custom functions
highestHigh = f_highest(high, chopLen)
lowestLow = f_lowest(low, chopLen)
priceRange = highestHigh - lowestLow
chop = priceRange != 0 ? 100 * math.log(atrSum / priceRange) / math.log(chopLen) : 0
// ─── STRATEGY CONDITIONS ─────────────────────────────────────────────────────
// MA Crossover Signals
longCond = ta.crossover(ma9, ma21)
shortCond = ta.crossunder(ma9, ma21)
// Filter: Only trade if ADX > threshold and CHOP ≤ threshold.
filterCond = (adxValue > adxThresh) and (chop <= chopThresh)
// Entries and Exits
if longCond and filterCond
strategy.entry("Long", strategy.long)
if shortCond and filterCond
strategy.entry("Short", strategy.short)
if shortCond
strategy.close("Long")
if longCond
strategy.close("Short")
// ─── PLOTTING ──────────────────────────────────────────────────────────────
plot(ma9, color=color.red, title="MA 9")
plot(ma21, color=color.blue, title="MA 21")
plot(adxValue, title="ADX", color=color.purple)
hline(adxThresh, title="ADX Threshold", color=color.purple, linestyle=hline.style_dotted)
plot(chop, title="CHOP", color=color.orange)
hline(chopThresh, title="CHOP Threshold", color=color.orange, linestyle=hline.style_dotted)