다중 시간대 MACD-RSI 교차 변동성 필터 양적 거래 전략

MACD RSI VWAP ATR SMA
생성 날짜: 2025-06-09 15:50:55 마지막으로 수정됨: 2025-06-09 15:50:55
복사: 0 클릭수: 326
avatar of ianzeng123 ianzeng123
2
집중하다
319
수행원

다중 시간대 MACD-RSI 교차 변동성 필터 양적 거래 전략 다중 시간대 MACD-RSI 교차 변동성 필터 양적 거래 전략

개요

이 전략은 다중 시간 프레임 분석을 기반으로 한 정량 거래 시스템으로, 주로 MACD 지표, RSI 지표, VWAP 평균선 및 ATR 변동률 필터 30분 및 1시간 시간 프레임에 대한 통합 신호를 사용하여 거래를 수행합니다. 이 전략은 다중 시간 프레임의 기술 지표 교차 신호를 통해 확인하여 다중 시간 프레임의 기술 지표 교차 신호를 확인하여 다중 시간 프레임의 기술 지표 교차 신호를 확인하여 거래 품질을 향상시키기 위해 변동률 조건 필터링과 결합합니다.

전략 원칙

이 전략의 핵심 원칙은 다중 조건 확인을 통해 낮은 품질의 신호를 필터링하는 것이며, 주로 다음과 같은 몇 가지 핵심 구성 요소를 포함합니다:

  1. 다중 시간 프레임 MACD 교차 신호

    • 30분 차트에서 MACD ((12,26,9) 를 사용하여 주요 입시 신호를 식별한다
    • 선택적으로 1시간 MACD 트렌드를 확인 조건으로 사용한다
  2. RSI가 과매매하고

    • 30분 RSI > 55
    • 30분 RSI <45
    • 1시간 RSI가 추가로 확정되었습니다.
  3. 이중 VWAP 가격 위치 확인

    • 30분과 1시간 VWAP 위에 있는 다중 요청 가격
    • 공백 요청 가격은 30분 및 1시간 VWAP 아래입니다.
  4. 변동율 필터

    • 30분 차트의 ATR(14) 를 20주기 평균선과 비교
    • 현재 변동률이 평균보다 크거나 같을 때만 입력하여 낮은 변동률 환경에서 가짜 신호를 피하십시오.
  5. 다단계 탈퇴

    • 고정 비율 스톱 (~1.5%) 및 스톱로스 (~0.5%)
    • 30분 MACD 역 교차 탈퇴
    • 1시간 MACD 트렌드 반전 퇴출

이러한 다단계 조건 필터링과 확인을 통해 전략은 명확한 방향의 중·단기 변동성을 포착하는 동시에 낮은 품질의 신호를 필터링하여 승률과 수익률을 높이는 것을 목표로합니다.

우위 분석

  1. 다중 시간 프레임 확인30분 및 1시간 시간 프레임의 신호를 결합하여 전략은 실제 트렌드를 더 잘 식별하고 가짜 신호의 영향을 줄일 수 있습니다. 특히 1시간 MACD 트렌드 확인 기능은 역대 트렌드 거래를 피하는 데 도움이됩니다.

  2. 변동율 적응성ATR 변동율 필터는 전략이 충분한 동력이있는 경우에만 시장에 진입하도록 보장하며, 낮은 변동률 영역 내에서 거래하는 것을 피합니다. 이것은 죽은 영역의 흔들림 위험을 효과적으로 감소시킵니다.

  3. 유연한 탈퇴이 전략은 고정된 스톱로스뿐만 아니라 지표 반전 기반의 동적 탈퇴 메커니즘을 포함합니다. 이는 가격이 스톱로스에 도달하지 않았지만 시장이 반전하기 시작했을 때 적시에 출전을 하여 수익을 보호 할 수 있습니다.

  4. 이중 가격 위치 확인: 가격의 두 시간 프레임 VWAP 위에 () 또는 아래 () 또는 아래 () 에 동시에 위치하도록 요구합니다. 이것은 가격의 움직임과 방향을 추가로 확인하고 가짜 돌파구를 줄입니다.

  5. 리스크 관리 내장이 전략은 스톱 로즈 메커니즘과 포지션 관리를 내장하고 있습니다. 이는 매 거래마다 5%의 계정 이자를 사용하도록 설정되어 있습니다. 이는 매 거래마다 위험을 통제하고 자본을 보호하는 데 도움이됩니다.

위험 분석

  1. 낮은 승률의 도전코드 코멘트에서 언급한 바와 같이, 전략은 승률이 낮은 문제로 직면할 수 있다. 이것은 다중 조건 필터링이 신호 품질을 향상시키지만 거래 빈도를 현저히 감소시키므로, 샘플 크기가 작고 통계적 의미가 제한된다.

  2. 매개변수 민감도이 전략은 MACD 길이, RSI 미지수, ATR 필터 파라미터 등과 같은 여러 가지 조정 가능한 파라미터를 사용합니다. 이러한 파라미터의 작은 변화는 전략의 성능에 중대한 영향을 미칠 수 있으며, 과도한 최적화의 위험이 있습니다.

  3. 고정 비율 스탠프 손실의 제한: 모든 시장 환경에 동일한 스톱 ((1.5%) 와 스톱 ((0.5%) 비율을 사용하며, 다양한 변동률 환경에 적응하지 못할 수 있다. 높은 변동률의 시장에서 스톱은 너무 긴밀할 수 있고, 낮은 변동률의 시장에서 스톱은 너무 멀리 있을 수 있다.

  4. 다중 시간 프레임의 뒤처짐: 더 긴 시간 프레임 ((예를 들어 1시간) 을 사용하는 신호를 확인으로 사용하면 지연이 발생할 수 있으며, 이는 출입 기회를 놓치고 출퇴근을 지연시킬 수 있다.

  5. 시장 환경에 적응할 수 없는 것전략에는 다양한 시장 환경 (트렌드/스컬러) 을 구분하는 메커니즘이 포함되어 있지 않으며, 특정 시장 조건에서 좋지 않은 성능을 보일 수 있습니다.

해결책:

  • ATR 또는 다른 변동성 지표에 따라 동적으로 조정하는 적응형 스톱 손실 메커니즘을 도입하는 것을 고려하십시오.
  • 시장 환경 인식 모듈을 추가하여 다른 조건에 따라 전략 매개 변수 또는 거래 논리를 조정
  • 과잉 최적화를 방지하기 위해 더 엄격한 재검토와 전향 테스트 검증을 실시하십시오.
  • 시간 필터 또는 트렌드 강도 필터와 같은 거래 필터 조건을 추가하여 신호 품질을 더 향상시키는 것을 고려하십시오.

최적화 방향

  1. 동적 스톱 스톱 손실 최적화고정된 비율의 스톱로드를 ATR 기반의 동적 값으로 바꾸어, 예를 들어 1.5×ATR을 스톱로, 3×ATR을 스톱로 사용한다. 이렇게 하면 전략이 다른 시장의 변동적인 환경에 더 잘 적응할 수 있고, 높은 변동의 시기에 더 느슨한 스톱로드를 제공하며, 낮은 변동의 시기에 스톱 목표를 강화할 수 있다.

  2. 시장 환경 분류: 시장 환경 식별 메커니즘을 도입하여 트렌드 시장과 충격 시장을 구분한다. ADX, 브린 대역폭 또는 가격과 장기 이동 평균의 관계를 사용하여 시장 상태를 식별하고 그에 따라 전략 파라미터를 조정하거나 거래 논리를 완전히 전환 할 수 있습니다.

  3. 진입 시점 최적화: 현재 전략 MACD 교차에서 발생하는 현재 K 라인 입장은 슬라이드 포인트 또는 실행 지연에 직면 할 수 있습니다. 교차 확인 후 다음 K 라인 오픈 시 입장을 고려하거나 특정 가격 영역에 대한 제한 가격을 설정하여 더 나은 실행 가격을 얻을 수 있습니다.

  4. 시간 필터거래 시간 필터를 추가하여 특정 비효율 거래 시기를 피하십시오. 예를 들어, 아시아 시간대 종료 또는 유럽-미국 교차 시간대와 같은 유동성이 낮거나 불규칙하게 변동 할 수있는 시간에 거래하는 것을 피할 수 있습니다.

  5. 지표 변수는 스스로 적응: MACD, RSI, ATR의 파라미터를 자체 적응 값으로 설계하고, 최근의 시장 변동성이나 주기적인 자동 조정에 기초한다. 예를 들어, 높은 변동성 시장에서는 짧은 MACD 파라미터를 사용할 수 있고, 낮은 변동성 시장에서는 더 긴 파라미터를 사용할 수 있다.

  6. 신호 강도 등급입력 신호에 대한 강도 점수 시스템을 구축하여 여러 가지 요소 (MACD 기둥 크기, RSI 편차, VWAP 거리 등) 에 따라 신호에 점수를 부여하고, 강도가 특정 경계를 초과하는 거래만 실행하거나, 신호 강도에 따라 위치 크기를 조정합니다.

  7. 기계 학습 강화: 어떤 신호가 더 수익성있는 거래를 만들 수 있는지 예측하기 위해 기계 학습 모델을 도입하고, 역사 데이터 훈련 모델에 따라 가장 가치있는 모드 조합을 식별합니다. 이것은 전략의 적응성과 승률을 향상시킬 수 있습니다.

이러한 최적화 방향은 전략의 안정성, 적응성 및 장기적 성능을 향상시키며 핵심 논리를 그대로 유지합니다. 이러한 개선으로 전략은 다양한 시장 환경과 조건의 변화에 더 잘 대응할 수 있습니다.

요약하다

다중 시간 프레임 MACD-RSI 교차 변동률 과잉량화 거래 전략은 여러 기술 지표와 여러 시간 프레임의 신호를 결합하여 고품질 거래 기회를 식별하기 위해 설계된 포괄적인 거래 시스템입니다. 이 전략의 핵심 장점은 다층의 신호 확인 메커니즘과 내장 된 위험 관리 기능으로 가격 변동을 포착하면서 위험을 제어 할 수 있습니다.

낮은 승률의 도전에도 불구하고, 전략은 평균 수익 거래의 수익을 높임으로써 긍정적인 기대치를 유지한다. 제안된 최적화 조치를, 특히 동적 스톱 스톱 손실, 시장 환경 분류 및 신호 강도 등, 실행함으로써 전략의 성능이 더 향상될 전망이다.

이 전략은 중장기 및 단기 거래자들에게 적합하며, 특히 기술 분석을 기반으로 한 체계화된 거래 방법을 찾고 위험 관리에 중점을 둔 거래자들에게 적합합니다. 전략의 다중 조건 확인 메커니즘은 거래 빈도를 줄이지만 거래의 질을 높여줍니다. 이것은 “더 적은 것이 더 많은” 거래 철학과 일치합니다.

실제 적용에서, 거래자는 먼저 모형 환경에서 전략을 테스트하고, 특히 다양한 최적화 조치의 효과를 테스트하고, 그 다음 현장 거래에 신중하게 적용하는 것이 좋습니다. 동시에, 시장 조건의 변화를 지속적으로 모니터링하고, 적절한 시기에 전략 매개 변수를 조정하는 것은 장기적으로 안정적인 성과를 유지하는 데 도움이 될 것입니다.

전략 소스 코드
/*backtest
start: 2025-01-01 00:00:00
end: 2025-06-08 00:00:00
period: 1h
basePeriod: 1h
exchanges: [{"eid":"Futures_Binance","currency":"ETH_USDT"}]
*/

// This Pine Script® code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © GentlemanOfTrading

//@version=6
strategy(title = "ETH Day Trader", overlay = true, margin_long = 100, margin_short  = 100, default_qty_type  = strategy.percent_of_equity, default_qty_value = 5)

// ==== 1) USER INPUTS ====
// MACD/RSI lengths
fastLen   = input.int(12,   title="MACD Fast EMA Length", minval=1)
slowLen   = input.int(26,   title="MACD Slow EMA Length", minval=1)
signalLen = input.int(9,    title="MACD Signal EMA Length", minval=1)
rsiLen    = input.int(14,   title="RSI Length", minval=1)

// RSI thresholds
rsiThreshLong30 = input.int(55, title="RSI30m > (Long)", minval=1, maxval=100)
rsiThreshShort30= input.int(45, title="RSI30m < (Short)", minval=1, maxval=100)
rsiThresh1h     = input.int(50, title="RSI1h Threshold", minval=1, maxval=100)

// ATR filter (30m)
atrLen     = input.int(14, title="ATR Length (30m)", minval=1)
atrMaLen   = input.int(20, title="ATR MA Length (30m)", minval=1)

// Take Profit / Stop Loss (percent)
tpPerc      = input.float(1.5,  title="Take Profit (%)", minval=0.1) / 100
slPerc      = input.float(0.5,  title="Stop Loss (%)",   minval=0.1) / 100

// Toggle whether to use 1h trend confirmation
use1hTrend  = input.bool(true, title="Use 1h MACD Trend Confirmation?")

// ==== 2) FETCH INDICATORS ON 30m ====
// We assume this script is applied on a chart ≤ 30m (e.g. 15m or 5m), 
// but if you apply it on a 30m chart it still works: security() with "30" just returns the same bar.

[macd30m, macdSig30m, _] = ta.macd(close, fastLen, slowLen, signalLen)
rsi30m                  = ta.rsi(close, rsiLen)
atr30m                  = ta.atr(atrLen)

// ==== 3) FETCH INDICATORS ON 1h & VWAPs via request.security() ====
// --- 1h MACD & RSI ---
[macd1h, macdSig1h, _] = request.security(syminfo.tickerid, "60", ta.macd(close, fastLen, slowLen, signalLen), lookahead=barmerge.lookahead_off)
rsi1h = request.security(syminfo.tickerid, "60", ta.rsi(close, rsiLen), lookahead=barmerge.lookahead_off)

// --- 30m VWAP & 1h VWAP (session VWAP) ---
vwap30m = request.security(syminfo.tickerid, "30", ta.vwap(close), lookahead=barmerge.lookahead_off)
vwap1h  = request.security(syminfo.tickerid, "60", ta.vwap(close), lookahead=barmerge.lookahead_off)

// ==== 4) BUILD VOLATILITY FILTER (30m ATR vs ATR MA) ====
atr30m_ma = ta.sma(atr30m, atrMaLen)
volatilityOK = atr30m >= atr30m_ma

// ==== 5) MULTI-TIMEFRAME CROSS CONDITIONS ====
// 30m MACD cross signals
longCross30m  = ta.crossover(macd30m, macdSig30m)
shortCross30m = ta.crossunder(macd30m, macdSig30m)

// 1h MACD trend confirmation
macdTrendUp1h   = macd1h > macdSig1h
macdTrendDown1h = macd1h < macdSig1h

// ==== 6) ENTRY & EXIT CONDITIONS ====
// LONG ENTRY: 
//   • 30m MACD crossover 
//   • 30m RSI > rsiThreshLong30 
//   • (optionally) 1h MACD line > 1h MACD signal 
//   • Price > 30m VWAP AND Price > 1h VWAP 
//   • 30m ATR ≥ 30m ATR MA (volatility filter)
longEntryCond = 
     longCross30m 
  and (rsi30m > rsiThreshLong30) 
  and (close > vwap30m) 
  and (close > vwap1h) 
  and volatilityOK 
  and (use1hTrend ? macdTrendUp1h : true)

// LONG EXIT: 
//   • fixed TP/SL 
//   OR • 30m MACD crossunder 
//   OR • 1h MACD falls below signal (trend flipped)
var float entryPriceLong = na
longExitCond = false

if (strategy.position_size > 0)
    // Price-based TP / SL checks
    entryPriceLong := nz(entryPriceLong[1], strategy.position_avg_price)
    longTPprice = entryPriceLong * (1 + tpPerc)
    longSLprice = entryPriceLong * (1 - slPerc)
    
    // check TP/SL first
    longExitTP = high >= longTPprice
    longExitSL = low  <= longSLprice
    
    // fallback: MACD crossunder on 30m OR 1h trend flips
    macdTrendFlip1h = macdTrendUp1h and (macd1h < macdSig1h)
    macdCross30m    = shortCross30m
    
    longExitCond := longExitTP or longExitSL or macdCross30m or macdTrendFlip1h
else
    entryPriceLong := na  // reset when no position

// SHORT ENTRY: 
//   • 30m MACD crossunder 
//   • 30m RSI < rsiThreshShort30 
//   • (optionally) 1h MACD line < 1h MACD signal 
//   • Price < 30m VWAP AND Price < 1h VWAP 
//   • 30m ATR ≥ 30m ATR MA (volatility filter)
shortEntryCond = 
     shortCross30m 
  and (rsi30m < rsiThreshShort30) 
  and (close < vwap30m) 
  and (close < vwap1h) 
  and volatilityOK 
  and (use1hTrend ? macdTrendDown1h : true)

// SHORT EXIT: 
//   • fixed TP/SL 
//   OR • 30m MACD crossover 
//   OR • 1h MACD flips up
var float entryPriceShort = na
shortExitCond = false

if (strategy.position_size < 0)
    entryPriceShort := nz(entryPriceShort[1], strategy.position_avg_price)
    shortTPprice = entryPriceShort * (1 - tpPerc)
    shortSLprice = entryPriceShort * (1 + slPerc)
    
    // check TP/SL first
    shortExitTP = low <= shortTPprice
    shortExitSL = high >= shortSLprice
    
    macdTrendFlipUp1h = macdTrendDown1h and (macd1h > macdSig1h)
    macdCrossUp30m    = longCross30m
    
    shortExitCond := shortExitTP or shortExitSL or macdCrossUp30m or macdTrendFlipUp1h
else
    entryPriceShort := na  // reset when no position

// ==== 7) EXECUTE STRATEGY ORDERS WITH LABELS & ALERTS ====
// — Long Entry —
if (longEntryCond and strategy.position_size == 0)
    strategy.entry("Long", strategy.long)
    label.new(bar_index, low, text="Buy (LT)", style=label.style_label_up, color=color.new(color.green, 0), textcolor=color.white, yloc=yloc.belowbar)
    alert("Buy (LT)", alert.freq_once_per_bar_close)

// — Long Exit —
if (strategy.position_size > 0 and longExitCond)
    strategy.close("Long")
    label.new(bar_index, high, text="Sell (LT)", style=label.style_label_down, color=color.new(color.red, 0), textcolor=color.white, yloc=yloc.abovebar)
    alert("Sell (LT)", alert.freq_once_per_bar_close)

// — Short Entry —
if (shortEntryCond and strategy.position_size == 0)
    strategy.entry("Short", strategy.short)
    label.new(bar_index, high, text="Sell (ST)", style=label.style_label_down, color=color.new(color.red, 0), textcolor=color.white, yloc=yloc.abovebar)
    alert("Sell (ST)", alert.freq_once_per_bar_close)

// — Short Exit —
if (strategy.position_size < 0 and shortExitCond)
    strategy.close("Short")
    label.new(bar_index, low, text="Buy (ST)", style=label.style_label_up, color=color.new(color.green, 0), textcolor=color.white, yloc=yloc.belowbar)
    alert("Buy (ST)", alert.freq_once_per_bar_close)


// ==== 8) OPTIONAL PLOTTING (for debugging) ====
// We’ve removed any `transp`/`opacity` arguments. Instead, we use `color.new(baseColor, α)` 
// for transparency, where α = 0 is fully opaque and α = 255 is fully transparent.

// 30m VWAP
plot(vwap30m, title = "VWAP 30m", color = color.new(color.teal, 80)) // ~31% transparentlinewidth= 1

// 1h VWAP
plot(vwap1h,  title = "VWAP 1h",  color = color.new(color.fuchsia, 80), linewidth= 1) // ~31% transparent

// 30m ATR vs ATR_MA
plot(atr30m, title = "ATR 30m", color = color.new(color.orange, 80))
plot(atr30m_ma, title = "ATR30m MA", color = color.new(color.yellow, 80))

// 30m MACD Histogram (bars)
plot(macd30m - macdSig30m, title = "MACD Histogram (30m)", style = plot.style_columns, color = (macd30m - macdSig30m >= 0 ? color.new(color.green, 80) : color.new(color.red, 80)))

// 1h MACD Histogram (area)
h1 = request.security(syminfo.tickerid, "60", macd1h - macdSig1h, lookahead=barmerge.lookahead_off)
plot(1, title = "MACD Hist (1h)", style = plot.style_area, color = (h1 >= 0 ? color.new(color.green, 80) : color.new(color.red, 80)))