Ergotic Dual-rail Reverse MACD Quantitative Trading Strategy (Эрготическая двойная рельсовая обратная MACD количественная стратегия торговли)

Автор:Чао Чжан, Дата: 2021-12-21 11:07:51
Тэги:

img

Обзор

Эта стратегия является двухугольной обратной количественной торговой стратегией MACD. Она опирается на технические индикаторы, описанные Уильямом Блау в его книге Momentum, Direction and Divergence и расширяется на них. Стратегия также имеет возможности обратного тестирования и может включать дополнительные функции, такие как предупреждения, фильтры, отслеживание стоп-лосса и т. Д.

Принципы

Основным индикатором этой стратегии является MACD. Он вычисляет быструю скользящую среднюю EMA и медленно скользящую среднюю EMA ((slowMALen), затем вычисляет их разницу xmacd. Он также вычисляет EMA ((signalLength) xmacd, чтобы получить xMA_MACD. Длинный сигнал запускается, когда xmacd пересекает xMA_MACD, а короткий сигнал запускается на перекрестке ниже. Ключевым аспектом этой стратегии являются обратные торговые сигналы, т.е. отношение между xmacd и xMA_MACD противоположно отношению к обычному индикатору MACD, откуда также происходит название Reverse MACD.

Кроме того, стратегия включает в себя трендовые фильтры. Когда длинный сигнал стреляет, если настроен фильтр бычьего тренда, он будет проверять, растет ли цена. Аналогично, короткий сигнал проверяет тенденцию снижения цены.

Анализ преимуществ

Самым большим преимуществом этой стратегии являются мощные возможности обратного тестирования. Вы можете выбрать различные торговые инструменты, установить временные рамки обратного тестирования и оптимизировать параметры стратегии на основе данных конкретных инструментов. По сравнению с простой стратегией MACD, она включает в себя тренд и анализ перекупленности / перепродажи для фильтрации некоторых идентичных сигналов. Двухполосный обратный MACD отличается от традиционного MACD, что позволяет ему использовать некоторые возможности, которые традиционный MACD может упустить.

Анализ рисков

Основной риск этой стратегии исходит от обратной логики торговли. Хотя обратные сигналы могут поймать некоторые возможности, упущенные традиционными сигналами, это также означает потерю некоторых обычных пунктов входа MACD, что требует тщательной оценки. Кроме того, сам MACD склонен генерировать ложные бычьи сигналы. Стратегия может привести к чрезмерным сделкам и увеличению затрат во время неуравновешенных, безнаправленных рынков.

Для смягчения рисков параметры могут быть оптимизированы - настройка длины скользящей средней; объединение тенденций и фильтров индикаторов позволяет избежать сигналов на нестабильных рынках; увеличение расстояния стоп-лосса обеспечивает ограничение потерь на отдельных сделках.

Руководство по оптимизации

Стратегия может быть улучшена в нескольких аспектах:

  1. Настройка параметров скоростных и медленных рельсов, оптимизация длины скользящего среднего, обратное тестирование для поиска оптимальных наборов параметров для конкретных инструментов
  2. Добавить или настроить фильтры тренда, судить по результатам бэкстеста, улучшает ли он доходность
  3. Испытать различные механизмы остановки потерь, фиксированные или отстающие, чтобы определить лучший производитель
  4. Попробуйте комбинировать другие индикаторы, такие как KD, Bollinger Bands, чтобы установить дополнительные условия фильтрации и обеспечить качество сигнала

Резюме

Двухрельсовая обратная количественная стратегия 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)

Больше