ADX 동적 트렌드 전략 (ADX Dynamic Trend Strategy) 은 ADX 지표를 활용하여 시장 트렌드의 강도와 방향을 결정하는 양적 거래 전략이다. 시장에서 트렌드가 존재하는지 판단하기 위해 평균 방향 지표 (ADX) 를 계산하고 트렌드의 방향을 결정하기 위해 긍정적 방향 지표 (DI+) 및 부정적인 방향 지표 (DI-) 를 계산하여 구매 및 판매 신호를 생성한다.
이 전략은 ADX 지표를 먼저 사용하여 시장에서 추세가 존재하는지 여부를 결정합니다. ADX가 사용자 정의 키 레벨 (23 기본값) 이상일 때 시장 추세가 상대적으로 강하다는 것을 신호합니다. 현재 ADX 값이 n 일 전에 ADX 값보다 높을 때 (n는 사용자 정의 룩백 기간, 기본값 3 일), ADX가 상승하고 시장에서 추세가 형성되고 있음을 신호합니다.
이 전략은 시장 트렌드의 방향을 결정하기 위해 DI+와 DI-를 사용합니다. DI+가 DI-보다 높을 때 시장의 상승 추세를 나타냅니다. DI+가 DI-보다 낮을 때 시장의 하락 추세를 나타냅니다.
마지막으로 전략은 ADX와 DI 분석을 결합하여 특정 구매 및 판매 신호를 생성합니다.
이 전략은 또한 이동 평균 필터링과 사용자 정의 가능한 백테스팅 시간 범위와 같은 기능을 제공합니다.
ADX 동적 트렌드 전략은 다음과 같은 장점을 가지고 있습니다.
이 전략은 또한 몇 가지 위험을 안고 있습니다.
위험을 줄이기 위해 다음을 고려할 수 있습니다.
이 전략은 다음과 같은 측면에서 향상될 수 있습니다.
ADX 동적 트렌드 전략은 트렌드 존재를 결정하고 트렌드 방향을 결정하기 위해 ADX를 사용합니다. 트렌드가 존재할 때 거래 신호를 생성하고 트렌드가 사라질 때 포지션을 평평하게합니다. 논리는 명확합니다. 트렌드를 자동으로 감지하고 추적함으로써 트렌드가 아닌 시장에서 비효율적인 거래를 어느 정도 피할 수 있습니다. 적절한 향상으로이 전략은 중장기 양적 거래에 강력한 도구가 될 수 있습니다.
/*backtest start: 2024-01-07 00:00:00 end: 2024-01-14 00:00:00 period: 10m basePeriod: 1m exchanges: [{"eid":"Futures_Binance","currency":"BTC_USDT"}] */ //@version=4 // This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/ // © millerrh with inspiration from @9e52f12edd034d28bdd5544e7ff92e //The intent behind this study is to look at ADX when it has an increasing slope and is above a user-defined key level (23 default). //This is to identify when it is trending. //It then looks at the DMI levels. If D+ is above D- and the ADX is sloping upwards and above the key level, it triggers a buy condition. Opposite for short. //Can use a user-defined moving average to filter long/short if desried. // NOTE: THIS IS MEANT TO BE USED IN CONJUNCTION WITH MY "ATX TRIGGER" INDICATOR FOR VISUALIZATION. MAKE SURE SETTINGS ARE THE SAME FOR BOTH. strategy("ADX | DMI Trend", overlay=true, initial_capital=10000, currency='USD', default_qty_type=strategy.percent_of_equity, default_qty_value=100, commission_type=strategy.commission.percent, commission_value=0.04) // === BACKTEST RANGE === From_Year = input(defval = 2019, title = "From Year") From_Month = input(defval = 1, title = "From Month", minval = 1, maxval = 12) From_Day = input(defval = 1, title = "From Day", minval = 1, maxval = 31) To_Year = input(defval = 9999, title = "To Year") To_Month = input(defval = 1, title = "To Month", minval = 1, maxval = 12) To_Day = input(defval = 1, title = "To Day", minval = 1, maxval = 31) Start = timestamp(From_Year, From_Month, From_Day, 00, 00) // backtest start window Finish = timestamp(To_Year, To_Month, To_Day, 23, 59) // backtest finish window // == INPUTS == // ADX Info adxlen = input(14, title="ADX Smoothing") dilen = input(14, title="DI Period") keyLevel = input(23, title="Keylevel for ADX") adxLookback = input(3, title="Lookback Period for Slope") // == FILTERING == // Inputs useMaFilter = input(title = "Use MA for Filtering?", type = input.bool, defval = true) maType = input(defval="EMA", options=["EMA", "SMA"], title = "MA Type For Filtering") maLength = input(defval = 200, title = "MA Period for Filtering", minval = 1) // Declare function to be able to swap out EMA/SMA ma(maType, src, length) => maType == "EMA" ? ema(src, length) : sma(src, length) //Ternary Operator (if maType equals EMA, then do ema calc, else do sma calc) maFilter = ma(maType, close, maLength) plot(maFilter, title = "Trend Filter MA", color = color.green, linewidth = 3, style = plot.style_line, transp = 50) // Check to see if the useMaFilter check box is checked, this then inputs this conditional "maFilterCheck" variable into the strategy entry maFilterCheck = if useMaFilter == true maFilter else close // == USE BUILT-IN DMI FUNCTION TO DETERMINE ADX AND BULL/BEAR STRENGTH [diplus, diminus, adx] = dmi(dilen, adxlen) buySignal = (adx[0]-adx[adxLookback] > 0) and adx > keyLevel and diplus > diminus and close >= maFilterCheck // buySignalValue = valuewhen(buySignal, close, 0) shortSignal = (adx[0]-adx[adxLookback] > 0) and adx > keyLevel and diplus < diminus and close <= maFilterCheck // shortSignalValue = valuewhen(shortSignal, close, 0) sellCoverSignal = adx[0]-adx[adxLookback] < 0 // == ENTRY & EXIT CRITERIA // Triggers to be TRUE for it to fire of the BUY Signal : (opposite for the SELL signal). // (1): Price is over the 200 EMA line. (EMA level configurable by the user) // (2): "D+" is OVER the "D-" line // (3): RSI 7 is under 30 (for SELL, RSI 7 is over 70) // 1* = The ultimate is to have a combination line of 3 EMA values, EMA 14, EMA 50 and EMA 200 - And if price is over this "combo" line, then it's a strong signal // == STRATEGY ENTRIES/EXITS == strategy.entry("Long", strategy.long, when = buySignal) strategy.close("Long", when = sellCoverSignal) strategy.entry("Short", strategy.short, when = shortSignal) strategy.close("Short", when = sellCoverSignal) // == ALERTS == // alertcondition(buySignal, title='ADX Trigger Buy', message='ADX Trigger Buy') // alertcondition(sellSignal, title='ADX Trigger Sell', message='ADX Trigger Sell')