이중 이동 평균 양적 거래 전략


생성 날짜: 2024-02-01 15:13:13 마지막으로 수정됨: 2024-02-01 15:13:13
복사: 0 클릭수: 611
avatar of ChaoZhang ChaoZhang
1
집중하다
1617
수행원

이중 이동 평균 양적 거래 전략

개요

이 전략은 빠른 이동 평균과 느린 이동 평균을 계산하고, 대립선 지표와 결합하여 거래 판단을 수행합니다. 이 전략은 트렌드 추적 유형 전략에 속합니다. 빠른 이동 평균 상에서 느린 이동 평균을 통과 할 때 더 많이; 빠른 이동 평균 아래에서 느린 이동 평균을 통과 할 때 공허합니다.

전략 원칙

  1. 빠른 이동 평균과 느린 이동 평균을 계산한다. 이동 평균 파라미터를 사용자 정의할 수 있다.
  2. 두 개의 이동 평균을 비교하여 시장의 경향 방향을 판단한다. 빠른 이동 평균 위에 느린 이동 평균을 가로지르면 다목 시장으로 판단한다. 빠른 이동 평균 아래에 느린 이동 평균을 가로지르면 공허 시장으로 판단한다.
  3. 클로즈 가격과 이동 평균의 관계를 결합하여 추가 확인이 됩니다. 구매 신호는 빠른 라인에서 느린 라인을 통과하고 클로즈 가격이 빠른 라인보다 높을 때만 생성됩니다. 판매 신호는 빠른 라인 아래의 느린 라인을 통과하고 클로즈 가격이 빠른 라인보다 낮을 때만 생성됩니다.
  4. 패러블 라인 지표 사용 필터 가짜 돌파. 구매 신호는 빠른 라인에서 느린 라인을 통과하고, 빠른 라인보다 종결 가격이 높고, 패러블 라인보다 주가가 높을 때만 최종적으로 생성됩니다. 그 반대의 경우도 마찬가지입니다.
  5. 최대 감수 손실에 따라 스톱 라인을 설정하십시오. ATR 지표와 결합하여 특정 스톱 가격을 계산하십시오.

전략적 이점

  1. 이동 평균을 사용하여 시장의 추세 방향을 판단하여 명확하지 않은 방향으로 시장을 정리하는 자주 거래하는 것을 피하십시오.
  2. 이중 필터링 조건은 일반적인 가짜 돌파 문제를 효과적으로 방지합니다.
  3. 단편적 손실을 효율적으로 제어하기 위한 HAL 전략

전략적 위험

  1. 지표 전략은 잘못된 신호를 유발할 수 있습니다.
  2. 화폐 위험도 고려하지 않았습니다.
  3. “아마도 초기에 놓친 다른 방향의 행보”

이 문제를 해결하기 위해 다음의 몇 가지 측면에서 최적화할 수 있습니다.

  1. 이동 평균 변수를 최적화하여 특정 품종에 더 적합하게 만듭니다.
  2. 다른 지표 또는 모델과 결합하여 신호 필터링이 가능합니다.
  3. 실시간 헤지 또는 자동 전환 브로커 계정의 통화 위험을 고려하십시오.

최적화 방향

  1. 이동 평균 변수를 최적화하여 트렌드를 더 잘 잡을 수 있습니다.
  2. 모델 포트폴리지를 늘리고 신호의 정확도를 높여라
  3. 다중 시간 주기의 검증, 함정을 피하십시오.
  4. 손실을 막는 전략을 최적화하고 전략의 안정성을 향상시킵니다.

요약하다

이 전략은 전형적인 쌍 이동 평균과 지표 조합 트렌드 추적 전략에 속한다. 두 이동 평균의 방향을 비교하여 시장의 흐름을 판단하고, 여러 가지 필터 지표와 결합하여 가짜 신호를 피하여 거래 신호를 생성한다. 동시에, 전략은 단기 손실을 제어하기 위해 손실을 방지하는 기능을 갖추고 있다. 전략의 논리는 간단하고 이해하기 쉽고, 필요에 따라 유연하게 최적화 할 수 있다. 단점은 거친 트렌드 판단 도구로서 신호의 정확성이 향상되고, 기계 학습 고급 모델 등을 도입하여 최적화 할 수 있다.

전략 소스 코드
/*backtest
start: 2024-01-01 00:00:00
end: 2024-01-31 00:00:00
period: 4h
basePeriod: 15m
exchanges: [{"eid":"Futures_Binance","currency":"BTC_USDT"}]
*/

// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © sosacur01

//@version=5
strategy(title="2 MA | Trend Following", overlay=true, pyramiding=1, commission_type=strategy.commission.percent, commission_value=0.2, initial_capital=10000)

//==========================================


//BACKTEST RANGE
useDateFilter = input.bool(true, title="Filter Date Range of Backtest",
     group="Backtest Time Period")
backtestStartDate = input(timestamp("1 jan 2000"), 
     title="Start Date", group="Backtest Time Period",
     tooltip="This start date is in the time zone of the exchange " + 
     "where the chart's instrument trades. It doesn't use the time " + 
     "zone of the chart or of your computer.")
backtestEndDate = input(timestamp("1 Jul 2100"),
     title="End Date", group="Backtest Time Period",
     tooltip="This end date is in the time zone of the exchange " + 
     "where the chart's instrument trades. It doesn't use the time " + 
     "zone of the chart or of your computer.")
inTradeWindow = true
if not inTradeWindow and inTradeWindow[1]
    strategy.cancel_all()
    strategy.close_all(comment="Date Range Exit")

//--------------------------------------

//LONG/SHORT POSITION ON/OFF INPUT
LongPositions   = input.bool(title='On/Off Long Postion', defval=true, group="Long & Short Position")
ShortPositions  = input.bool(title='On/Off Short Postion', defval=true, group="Long & Short Position")

//---------------------------------------

//SLOW MA INPUTS
averageType1   = input.string(defval="SMA", group="Slow MA Inputs", title="Slow MA Type", options=["SMA", "EMA", "WMA", "HMA", "RMA", "SWMA", "ALMA", "VWMA", "VWAP"])
averageLength1 = input.int(defval=160, group="Slow MA Inputs", title="Slow MA Length", minval=50)
averageSource1 = input(close, title="Slow MA Source", group="Slow MA Inputs")
           

//SLOW MA TYPE
MovAvgType1(averageType1, averageSource1, averageLength1) =>
	switch str.upper(averageType1)
        "SMA"  => ta.sma(averageSource1, averageLength1)
        "EMA"  => ta.ema(averageSource1, averageLength1)
        "WMA"  => ta.wma(averageSource1, averageLength1)
        "HMA"  => ta.hma(averageSource1, averageLength1)
        "RMA"  => ta.rma(averageSource1, averageLength1)
        "SWMA" => ta.swma(averageSource1)
        "ALMA" => ta.alma(averageSource1, averageLength1, 0.85, 6)
        "VWMA" => ta.vwma(averageSource1, averageLength1)
        "VWAP" => ta.vwap(averageSource1)
        => runtime.error("Moving average type '" + averageType1 + 
             "' not found!"), na


//----------------------------------

//FAST MA INPUTS
averageType2   = input.string(defval="SMA", group="Fast MA Inputs", title="Fast MA Type", options=["SMA","EMA","WMA","HMA","RMA","SWMA","ALMA","VWMA","VWAP"])
averageLength2 = input.int(defval=40, group="Fast MA Inputs", title="Fast MA Length", maxval=40)
averageSource2 = input(close, title="Fast MA Source", group="Fast MA Inputs")

//FAST MA TYPE
MovAvgType2(averageType2, averageSource2, averageLength2) =>
	switch str.upper(averageType2)
        "SMA"  => ta.sma(averageSource2, averageLength2)
        "EMA"  => ta.ema(averageSource2, averageLength2)
        "WMA"  => ta.wma(averageSource2, averageLength2)
        "HMA"  => ta.hma(averageSource2, averageLength2)
        "RMA"  => ta.rma(averageSource2, averageLength2)
        "SWMA" => ta.swma(averageSource2)
        "ALMA" => ta.alma(averageSource2, averageLength2, 0.85, 6)
        "VWMA" => ta.vwma(averageSource2, averageLength2)
        "VWAP" => ta.vwap(averageSource2)
        => runtime.error("Moving average type '" + averageType2 + 
             "' not found!"), na

//---------------------------------------------------

//MA VALUES
FASTMA = MovAvgType2(averageType2, averageSource2, averageLength2)
SLOWMA = MovAvgType1(averageType1, averageSource1, averageLength1)

//BUY/SELL TRIGGERS
bullish_trend = FASTMA > SLOWMA and close > FASTMA
bearish_trend = FASTMA < SLOWMA and close < FASTMA

//MAs PLOT
plot1 = plot(SLOWMA,color=color.gray, linewidth=1, title="Slow-MA")
plot2 = plot(FASTMA,color=color.yellow, linewidth=1, title="Fast-MA")
fill(plot1, plot2, color=SLOWMA>FASTMA ? color.new(color.red, 70) : color.new(color.green, 70), title="EMA Clouds")

//-----------------------------------------------------

//PARABOLIC SAR USER INPUT
usepsarFilter = input.bool(title='Use Parabolic Sar?', defval=true, group = "Parabolic SAR Inputs")
psar_display  = input.bool(title="Display Parabolic Sar?", defval=false, group="Parabolic SAR Inputs")
start         = input.float(title="Start", defval=0.02, group="Parabolic SAR Inputs", step=0.001)
increment     = input.float(title="Increment", defval=0.02, group="Parabolic SAR Inputs", step=0.001)
maximum       = input.float(title="Maximum", defval=0.2, group="Parabolic SAR Inputs", step=0.001)

//SAR VALUES
psar        = request.security(syminfo.tickerid, "D", ta.sar(start, increment, maximum))

//BULLISH & BEARISH PSAR CONDITIONS
bullish_psar = (usepsarFilter ? low > psar : bullish_trend )
bearsish_psar = (usepsarFilter ? high < psar : bearish_trend)

//SAR PLOT
psar_plot    = if low > psar
    color.rgb(198, 234, 199, 13)
else
    color.rgb(219, 134, 134, 48)
    
plot(psar_display ? psar : na, color=psar_plot, title="Par SAR")

//-------------------------------------

//ENTRIES AND EXITS
long_entry  = if inTradeWindow and bullish_trend  and bullish_psar and LongPositions
    true
long_exit   = if inTradeWindow and bearish_trend   
    true

short_entry = if inTradeWindow  and bearish_trend and bearsish_psar and ShortPositions
    true
short_exit  = if inTradeWindow  and bullish_trend 
    true

//--------------------------------------

//RISK MANAGEMENT - SL, MONEY AT RISK, POSITION SIZING
atrPeriod                = input.int(14, "ATR Length", group="Risk Management Inputs")
sl_atr_multiplier        = input.float(title="Long Position - Stop Loss - ATR Multiplier", defval=2, group="Risk Management Inputs", step=0.5)
sl_atr_multiplier_short  = input.float(title="Short Position - Stop Loss - ATR Multiplier", defval=2, group="Risk Management Inputs", step=0.5)
i_pctStop                = input.float(2, title="% of Equity at Risk", step=.5, group="Risk Management Inputs")/100

//ATR VALUE
_atr = ta.atr(atrPeriod)

//CALCULATE LAST ENTRY PRICE
lastEntryPrice = strategy.opentrades.entry_price(strategy.opentrades - 1)

//STOP LOSS - LONG POSITIONS 
var float sl = na

//CALCULTE SL WITH ATR AT ENTRY PRICE - LONG POSITION
if (strategy.position_size[1] != strategy.position_size)
    sl := lastEntryPrice - (_atr * sl_atr_multiplier)

//IN TRADE - LONG POSITIONS
inTrade = strategy.position_size > 0

//PLOT SL - LONG POSITIONS
plot(inTrade ? sl : na, color=color.blue, style=plot.style_circles, title="Long Position - Stop Loss")

//CALCULATE ORDER SIZE - LONG POSITIONS
positionSize = (strategy.equity * i_pctStop) / (_atr * sl_atr_multiplier)

//============================================================================================

//STOP LOSS - SHORT POSITIONS 
var float sl_short = na

//CALCULTE SL WITH ATR AT ENTRY PRICE - SHORT POSITIONS 
if (strategy.position_size[1] != strategy.position_size)
    sl_short := lastEntryPrice + (_atr * sl_atr_multiplier_short)

//IN TRADE SHORT POSITIONS
inTrade_short = strategy.position_size < 0

//PLOT SL - SHORT POSITIONS
plot(inTrade_short ? sl_short : na, color=color.red, style=plot.style_circles, title="Short Position - Stop Loss")

//CALCULATE ORDER - SHORT POSITIONS
positionSize_short = (strategy.equity * i_pctStop) / (_atr * sl_atr_multiplier_short) 


//===============================================

//LONG STRATEGY
strategy.entry("Long", strategy.long, comment="Long", when = long_entry, qty=positionSize)
if (strategy.position_size > 0)
    strategy.close("Long", when = (long_exit), comment="Close Long")
    strategy.exit("Long", stop = sl, comment="Exit Long")

//SHORT STRATEGY
strategy.entry("Short", strategy.short, comment="Short", when = short_entry, qty=positionSize_short)
if (strategy.position_size < 0) 
    strategy.close("Short", when = (short_exit), comment="Close Short")
    strategy.exit("Short", stop = sl_short, comment="Exit Short")

//ONE DIRECTION TRADING COMMAND (BELLOW ONLY ACTIVATE TO CORRECT BUGS)