
Эта стратегия представляет собой торговую систему, которая сочетает в себе фильтрацию состояния рынка с помощью пересечения 9-циклического и 21-циклического простых движущихся средних (SMA), чтобы уловить рыночные тенденции, а также использовать средний индекс направления (ADX) и индекс хаоса (Choppiness Index, CI) для фильтрации рыночной среды, чтобы обеспечить торговлю только в рынках с ясными тенденциями и хорошей волатильностью. Этот метод эффективно сочетает традиционные стратегии отслеживания тенденций с современными техническими показателями, обеспечивая более устойчивую торговую структуру.
Основная логика стратегии состоит из трех ключевых компонентов:
Стратегия использует оптимизированный метод расчета технических показателей, включающий в себя пользовательские функции суммирования, расчет максимальных и минимальных значений, а также стандартизированный расчет реальной диапазона (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)