이 전략은 듀얼 레일 리버스 MACD 양적 거래 전략이다. 윌리엄 블라우가 그의 책?? 모멘텀, 디렉션 앤 디버전스?? 에서 기술한 기술 지표에 기반을 두고 확장된다. 이 전략은 또한 백테스팅 기능을 가지고 있으며 알림, 필터, 트레일링 스톱 로스 등 추가 기능을 포함할 수 있다.
이 전략의 핵심 지표는 MACD입니다. 빠른 이동 평균 EMA®와 느린 이동 평균 EMA ((slowMALen) 을 계산하고, 그 다음 차이 xmacd를 계산합니다. 또한 xmacd의 EMA ((신호 길이) 를 계산하여 xMA_MACD를 얻습니다. xmacd가 xMA_MACD 위에 넘어가면 긴 신호가 트리거되며, 아래의 크로스에서 짧은 신호가 트리거됩니다. 이 전략의 핵심 측면은 역 거래 신호입니다. 즉, xmacd와 xMA_MACD 사이의 관계는 기존 MACD 지표와 반대입니다.
또한, 전략은 트렌드 필터를 포함합니다. 긴 신호가 발사되면, 상승 트렌드 필터가 구성되면 가격이 증가하는지 확인할 수 있습니다. 마찬가지로, 짧은 신호는 하락 가격 추세를 검사합니다. RSI 및 MFI 지표도 신호를 필터링하는 데 사용할 수 있습니다. 한계 이상의 손실을 방지하기 위해 스톱 로스 메커니즘이 포함되어 있습니다.
이 전략의 가장 큰 장점은 강력한 백테스팅 기능이다. 당신은 다른 거래 도구를 선택하고, 백테스트 시간 프레임을 설정하고, 특정 도구 데이터를 기반으로 전략 매개 변수를 최적화할 수 있다. 간단한 MACD 전략과 비교하면, 트렌드와 과잉 구매/ 과잉 판매 분석을 통합하여 몇 가지 동일한 신호를 필터링한다. 듀얼 레일 역 MACD는 전통적인 MACD와 다르며, 전통적인 MACD가 놓칠 수 있는 몇 가지 기회를 활용할 수 있다.
이 전략의 주요 위험은 역상거래 논리에서 비롯된다. 역상거래 신호는 전통적인 신호에 의해 놓친 몇 가지 기회를 포착 할 수 있지만, 또한 일부 전통적인 MACD 입구 지점을 잃는 것을 의미하며, 신중한 평가를 필요로 한다. 또한, MACD 자체는 잘못된 상승 신호를 생성하는 경향이 있다. 전략은 불안하고 방향 없는 시장에서 과도한 거래와 비용이 증가할 수 있다.
위험을 완화하기 위해 매개 변수를 최적화 할 수 있습니다. 이동 평균 길이를 조정; 트렌드와 지표 필터를 결합하여 불안정한 시장에서 신호를 피합니다.
이 전략은 몇 가지 측면에서 개선될 수 있습니다.
듀얼 레일 역 MACD 양적 전략은 확장 및 개선으로 고전적인 MACD 지표에 기반을 둔다. 유연한 매개 변수 구성, 풍부한 필터 선택 및 강력한 백테스팅 기능으로 다른 거래 도구에 맞게 조정할 수 있다. 따라서 추가 탐구에 가치가 있는 흥미롭고 유망한 양적 거래 전략이다.
/*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 = 3 //////////////////////////////////////////////////////////// // Copyright by HPotter v1.0 09/12/2016 // This is one of the techniques described by William Blau in his book // "Momentum, Direction and Divergence" (1995). If you like to learn more, // we advise you to read this book. His book focuses on three key aspects // of trading: momentum, direction and divergence. Blau, who was an electrical // engineer before becoming a trader, thoroughly examines the relationship // between price and momentum in step-by-step examples. From this grounding, // he then looks at the deficiencies in other oscillators and introduces some // innovative techniques, including a fresh twist on Stochastics. On directional // issues, he analyzes the intricacies of ADX and offers a unique approach to help // define trending and non-trending periods. // Blau`s indicator is like usual MACD, but it plots opposite of meaningof // stndard MACD indicator. // // You can change long to short in the Input Settings // Please, use it only for learning or paper trading. Do not for real trading. // // // 2018-09 forked by Khalid Salomão // - Backtesting // - Added filters: RSI, MFI, Price trend // - Trailing Stop Loss // - Other minor adjustments // //////////////////////////////////////////////////////////// strategy(title="Ergotic MACD Backtester [forked from HPotter]", shorttitle="Ergotic MACD Backtester", overlay=true, pyramiding=0, default_qty_type=strategy.cash, default_qty_value=25000, initial_capital=50000, commission_type=strategy.commission.percent, commission_value=0.15, slippage=3) // === BACKTESTING: INPUT BACKTEST RANGE === source = input(close) strategyType = input(defval="Long Only", options=["Long & Short", "Long Only", "Short Only"]) FromMonth = input(defval = 7, title = "From Month", minval = 1, maxval = 12) FromDay = input(defval = 1, title = "From Day", minval = 1, maxval = 31) FromYear = input(defval = 2018, title = "From Year", minval = 2017) ToMonth = input(defval = 12, title = "To Month", minval = 1, maxval = 12) ToDay = input(defval = 1, title = "To Day", minval = 1, maxval = 31) ToYear = input(defval = 2030, title = "To Year", minval = 2017) start = timestamp(FromYear, FromMonth, FromDay, 00, 00) finish = timestamp(ToYear, ToMonth, ToDay, 23, 59) window() => true // window of time verification // === STRATEGY === r = input(144, minval=1, title="R (32,55,89,100,144,200)") // default 32 slowMALen = input(6, minval=1) // default 32 signalLength = input(6, minval=1) reverse = input(false, title="Trade reverse (long/short switch)") //hline(0, color=blue, linestyle=line) fastMA = ema(source, r) slowMA = ema(source, slowMALen) xmacd = fastMA - slowMA xMA_MACD = ema(xmacd, signalLength) pos = 0 pos := iff(xmacd < xMA_MACD, 1, iff(xmacd > xMA_MACD, -1, nz(pos[1], 0))) possig = 0 possig := iff(reverse and pos == 1, -1, iff(reverse and pos == -1, 1, pos)) // === FILTER: price trend ==== trending_price_long = input(true, title="Long only if price has increased" ) trending_price_short = input(false, title="Short only if price has decreased" ) trending_price_length = input( 2, minval=1 ) trending_price_with_ema = input( false ) trending_price_ema = input( 3, minval=1 ) price_trend = trending_price_with_ema ? ema(source, trending_price_ema) : source priceLongTrend() => (trending_price_long ? rising(price_trend, trending_price_length) : true) priceShortTrend() => (trending_price_short ? falling(price_trend, trending_price_length) : true) // === FILTER: RSI === rsi_length = input( 14, minval=1 ) rsi_overSold = input( 14, minval=0, title="RSI Sell Cutoff (Sell only if >= #)" ) rsi_overBought = input( 82, minval=0, title="RSI Buy Cutoff (Buy only if <= #)" ) vrsi = rsi(source, rsi_length) rsiOverbought() => vrsi > rsi_overBought rsiOversold() => vrsi < rsi_overSold trending_rsi_long = input(false, title="Long only if RSI has increased" ) trending_rsi_length = input( 2 ) rsiLongTrend() => trending_rsi_long ? rising(vrsi, trending_rsi_length) : true // === FILTER: MFI === mfi_length = input(14, minval=1) mfi_lower = input(14, minval=0, maxval=50) mfi_upper = input(82, minval=50, maxval=100) upper_s = sum(volume * (change(source) <= 0 ? 0 : source), mfi_length) lower_s = sum(volume * (change(source) >= 0 ? 0 : source), mfi_length) mf = rsi(upper_s, lower_s) mfiOverbought() => (mf > mfi_upper) mfiOversold() => (mf < mfi_lower) trending_mfi_long = input(false, title="Long only if MFI has increased" ) trending_mfi_length = input( 2 ) mfiLongTrend() => trending_mfi_long ? rising(mf, trending_mfi_length) : true // === SIGNAL CALCULATION === long = window() and possig == 1 and rsiLongTrend() and mfiLongTrend() and not rsiOverbought() and not mfiOverbought() and priceLongTrend() short = window() and possig == -1 and not rsiOversold() and not mfiOversold() and priceShortTrend() // === trailing stop tslSource=input(hlc3,title="TSL source") //suseCurrentRes = input(true, title="Use current chart resolution for stop trigger?") tslResolution = input(title="Use different timeframe for stop trigger? Uncheck box above.", defval="5") tslTrigger = input(3.0) / 100 tslStop = input(0.6) / 100 currentPrice = request.security(syminfo.tickerid, tslResolution, tslSource, barmerge.gaps_off, barmerge.lookahead_off) isLongOpen = false isLongOpen := nz(isLongOpen[1], false) entryPrice=0.0 entryPrice:= nz(entryPrice[1], 0.0) trailPrice=0.0 trailPrice:=nz(trailPrice[1], 0.0) // update TSL high mark if (isLongOpen ) if (not trailPrice and currentPrice >= entryPrice * (1 + tslTrigger)) trailPrice := currentPrice else if (trailPrice and currentPrice > trailPrice) trailPrice := currentPrice if (trailPrice and currentPrice <= trailPrice * (1 - tslStop)) // FIRE TSL SIGNAL short:=true // <=== long := false // if short clean up if (short) isLongOpen := false entryPrice := 0.0 trailPrice := 0.0 if (long) isLongOpen := true if (not entryPrice) entryPrice := currentPrice // === BACKTESTING: ENTRIES === if long if (strategyType == "Short Only") strategy.close("Short") else strategy.entry("Long", strategy.long, comment="Long") if short if (strategyType == "Long Only") strategy.close("Long") else strategy.entry("Short", strategy.short, comment="Short") //barcolor(possig == -1 ? red: possig == 1 ? green : blue ) //plot(xmacd, color=green, title="Ergotic MACD") //plot(xMA_MACD, color=red, title="SigLin") plotshape(trailPrice ? trailPrice : na, style=shape.circle, location=location.absolute, color=blue, size=size.tiny) plotshape(long, style=shape.triangleup, location=location.belowbar, color=green, size=size.tiny) plotshape(short, style=shape.triangledown, location=location.abovebar, color=red, size=size.tiny) // === Strategy Alert === alertcondition(long, title='BUY - Ergotic MACD Long Entry', message='Go Long!') alertcondition(short, title='SELL - Ergotic MACD Long Entry', message='Go Short!') // === BACKTESTING: EXIT strategy === sl_inp = input(7, title='Stop Loss %', type=float)/100 tp_inp = input(1.8, title='Take Profit %', type=float)/100 stop_level = strategy.position_avg_price * (1 - sl_inp) take_level = strategy.position_avg_price * (1 + tp_inp) strategy.exit("Stop Loss/Profit", "Long", stop=stop_level, limit=take_level)