듀얼 트랙 역방향 MACD 양적 거래 전략


생성 날짜: 2023-12-21 11:07:51 마지막으로 수정됨: 2023-12-21 11:07:51
복사: 3 클릭수: 642
avatar of ChaoZhang ChaoZhang
1
집중하다
1621
수행원

듀얼 트랙 역방향 MACD 양적 거래 전략

개요

이 전략은 쌍방향 역행 MACD 양적 거래 전략이다. 이 전략은 윌리엄 블라우가 그의 저서 ?? Momentum, Direction and Divergence ?? 에서 설명한 기술 지표를 모티브로 삼고, 이를 기반으로 확장하였다. 이 전략은 동시에 회귀 기능을 가지고 있으며, 경고, 필터, 추적 스톱 등과 같은 부가 기능을 추가할 수 있다.

전략 원칙

이 전략의 핵심 지표는 MACD이다. 그것은 빠른 이동 평균 EMA ® 와 느린 이동 평균 EMA (slowMALen) 를 계산하고, 그 다음 그들의 차수를 계산한다. xmacd의 EMA (signalLength) 를 계산한다. 또한 xmacd의 EMA (signalLength) 는 xMA_MACD를 얻는다.

또한, 이 전략은 트렌드 필터를 도입한다. 여러 신호를 발송할 때, 보이스 트렌드 필터를 구성하면 가격이 상승하고 있는지 검출할 수 있다. 유사하게, 하위 신호는 가격 하락의 경향을 검출할 수 있다. RSI 지표와 MFI 지표도 필터링 신호 구성을 위해 사용될 수 있다.

우위 분석

이 전략의 가장 큰 장점은 재검토 기능이 강하다는 것입니다. 다른 거래 품종을 선택하고, 재검토의 시간 범위를 설정하고, 특정 품종 데이터에 대해 전략적 최적화를 할 수 있습니다. 간단한 MACD 전략에 비해, 추세, 과매, 과매 판단을 증가시키고, 몇 가지雷同 신호를 필터링 할 수 있습니다. 쌍궤도 역 MACD는 전통적인 MACD와 달리, 전통적인 MACD가 놓칠 수있는 몇 가지 기회를 잡을 수 있습니다.

위험 분석

이 전략의 위험은 주로 역전 거래의 사고에서 비롯된다. 역전 신호는 몇 가지 기회를 얻을 수 있지만, 일부 전통적인 MACD 매수점을 포기하는 것을 의미하며, 이는 신중하게 평가되어야 한다. 또한, MACD 자체는 여러 개의 가짜 신호를 생성하는 데 취약하다.

위험을 줄이기 위해, 적절한 변수를 조정하여 이동 평균의 길이를 최적화 할 수 있습니다. 추세와 지표 필터를 결합하여 흔들리는 시장에서 신호를 발생하지 않도록합니다. 개별 거래의 손실을 제어하기 위해 중지 손실 거리를 적절히 높일 수 있습니다.

최적화 방향

이 전략은 다음과 같은 부분에서 최적화될 수 있습니다.

  1. 빠른 속도 변수를 조정하고, 이동 평균 길이를 최적화하고, 특정 품종 데이터를 테스트하여 최적의 변수 조합을 찾습니다.
  2. 트렌드 필터를 추가하거나 조정하여 피드백 결과에 따라 전략 수익률이 향상되는지 판단하십시오.
  3. 고정된 손실 또는 추적된 손실을 테스트하는 다른 손실 메커니즘을 테스트합니다.
  4. KD, 브린 밴드 등과 같은 다른 지표와 결합하여 더 많은 필터링 조건을 설정하여 신호 품질을 보장하십시오.

요약하다

이중 궤도 역 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)