PulseForce 듀얼 이동평균 전략 분석

1. 개요

듀얼 이동평균(Dual Moving Average) 은 가장 고전적이고 기본적인 추세 추종 전략 중 하나입니다.
이 전략은 두 개의 단순 이동평균(단기 ma_fast, 장기 ma_slow) 사이의 교차 관계만을 사용합니다.

  • 단기 MA가 장기 MA를 아래에서 위로 돌파 → 골든 크로스 → 매수 신호 생성
  • 단기 MA가 장기 MA를 위에서 아래로 이탈 → 데드 크로스 → 매도 신호 생성

PulseForce에서 dual_moving_avg 전략은 미니멀하지만 고도로 표준화된 추세 추종 구현입니다.

  • 1분 봉 사용 (timeframe = "1m")
  • 신호 조건으로 듀얼 이동평균 + 거래량 > 0 만 사용
  • 청산 로직은 통합 리스크 프레임워크를 따름: “매도 신호 + 일일 SL/TP + 하드 SL/TP”
  • ma_fast / ma_slow / daily_* / force_* 등의 파라미터를 대상으로 HyperOpt 최적화 지원
  • 모든 전략 파라미터는 PulseForce 앱에서 시각적으로 설정 가능

ma_crossover가 더 많은 추세 필터와 변동성 조정을 포함한 “강화 버전”이라면,
dual_moving_avg는 구조가 매우 단순하고 해석이 쉬운 더 순수한 이동평균 교차 버전입니다.


2. 기원과 포지셔닝

듀얼 이동평균 교차 전략은 초기 기술적 분석까지 거슬러 올라갑니다.
컴퓨터와 시스템 트레이딩의 등장과 함께, 이 전략은 추세 추종 전략의 “Hello World”가 되었습니다.

  • 초기 CTA / 추세 추종 펀드
    이동평균 교차를 핵심 추세 신호로 폭넓게 사용
  • 현대 퀀트 시스템
    듀얼 이동평균은 여전히 추세 추종의 핵심 기반으로, 다요인 모델, CTA 시스템, 추세 필터 등에 내장됨
  • 교육 및 연구
    초보자 교육이든 학술적 논의든, 듀얼 MA는 거의 항상 추세 전략의 기본 예시로 사용됨

PulseForce 내에서 dual_moving_avg의 포지셔닝은 다음과 같습니다.

“구조적으로 매우 깔끔한 베이스라인(기준) 추세 전략.”
MA Crossover, Momentum, MACD Trend 등 더 복잡한 전략과의 수익률, 드로우다운, 거래 스타일 비교에 활용됩니다.


3. 이 전략은 어떤 문제를 해결하는가?

듀얼 이동평균 전략은 핵심적으로 다음 세 가지 질문을 다룹니다.

  1. 추세 방향 변화는 어떻게 단순하고 직접적으로 식별할 것인가?
    → 단기 MA와 장기 MA의 상대 위치 및 교차를 통해 강세/약세 추세 상태를 판단합니다.

  2. 단일 캔들이나 국소 패턴에 대한 과도한 의존은 어떻게 줄일 것인가?
    → 이동평균은 가격을 평활화하여 고빈도 노이즈 및 비정상 단일 캔들의 영향을 줄입니다.

  3. 조정 가능한(tunable) 추세 추종 전략은 어떻게 만들 것인가?
    → ma_fast / ma_slow 를 조정하면, 더 빠르게 반응하는 변형 또는 더 안정적인 변형을 쉽게 만들 수 있습니다.


4. 핵심 지표와 신호 로직

4.1 지표 계산

이 전략은 단순 이동평균(SMA) 을 사용합니다.

f = int(self._val(self.ma_fast))
s = int(self._val(self.ma_slow))

# Simple moving averages
df["ma_fast"] = ta.SMA(df, timeperiod=f)
df["ma_slow"] = ta.SMA(df, timeperiod=s)

필수 기본 데이터:

  • close / open / high / low: 정제를 위해 모두 전방 채움(ffill)
  • volume: 누락 데이터로 인한 신호 오류를 피하기 위해 0으로 채움

4.2 매수 로직: 골든 크로스

def populate_buy_trend(self, dataframe: DataFrame, metadata: Dict) -> DataFrame:
    df = dataframe.copy()
    cond = (
        (df["ma_fast"].shift(1) < df["ma_slow"].shift(1)) &  # Previous bar: short MA below long MA
        (df["ma_fast"] > df["ma_slow"]) &                    # Current bar: short MA crosses above long MA → Golden Cross
        (df["volume"] > 0)                                   # Must have volume
    )
    df.loc[:, "buy"] = 0
    df.loc[cond, "buy"] = 1
    return df

의미:

  • 단순히 > 여부를 보는 것이 아니라, “단기 MA가 장기 MA 아래에 있다가 위로 올라서는 상태 변화” 가 반드시 발생해야 합니다. → 반복 트리거를 방지합니다.
  • RSI, 돌파, 변동성 필터 등을 추가하지 않은 가장 순수한 골든 크로스 정의를 사용합니다. → 베이스라인 전략으로 이상적입니다.
  • volume > 0 는 거래 정지 종목이나 비정상 데이터를 걸러내기 위한 조건입니다.

4.3 매도 신호 레이어: 데드 크로스

전략은 정적 메서드 _has_sell_signal 로 데드 크로스 발생 여부를 판단합니다.

@staticmethod
def _has_sell_signal(prev: Optional[pd.Series], curr: Optional[pd.Series]) -> bool:
    try:
        if prev is None or curr is None:
            return False
        return (float(prev.get("ma_fast", np.nan)) > float(prev.get("ma_slow", np.nan))) and \
               (float(curr.get("ma_fast", np.nan)) < float(curr.get("ma_slow", np.nan)))
    except Exception:
        return False

조건:

  • 이전 봉: ma_fast > ma_slow (단기 추세가 장기 추세 위)
  • 현재 봉: ma_fast < ma_slow (단기 추세가 장기 MA 아래로 이탈)

두 조건이 모두 충족되면 데드 크로스(강세 → 약세 전환) 로 간주됩니다.
다만 즉시 청산하지는 않으며, 이 신호를 custom_exit 에 전달한 뒤 SL/TP 로직에 따라 청산 여부를 결정합니다.


5. 통합 청산 로직: 매도 신호 + SL/TP

custom_exit 에서 dual_moving_avg 는 PulseForce 표준 리스크 제어 프로세스를 완전히 구현합니다.

def custom_exit(
    self,
    pair: str,
    trade: Trade,
    current_time: datetime,
    current_rate: float,
    current_profit: float,
    **kwargs,
):
    # ① Hard thresholds first (Force SL/TP)
    if current_profit <= -self.force_stop_loss.value:
        return "hard_sl"
    if current_profit >= self.force_take_profit.value:
        return "hard_tp"

    # ② Fetch prev/curr rows and check for Death Cross
    df = self._get_analyzed_df(pair)
    if df is None or df.empty:
        return None
    prev, curr = self._get_prev_curr_rows(df, current_time)
    if not self._has_sell_signal(prev, curr):
        return None

    # ③ Only after the sell signal layer occurs, apply daily SL/TP to decide the actual exit
    th = self._pick_trend_thresholds()
    sl = th["sl"]
    tp = th["tp"]
    if current_profit <= -sl:
        return "sl_signal"
    if current_profit >= tp:
        return "tp_signal"
    return None

이는 세 가지 보호 레이어로 요약할 수 있습니다.

  1. Force SL/TP(하드 임계값)

    • 모든 신호를 무시하고, 미실현 손익이 하드 임계값에 도달하면 즉시 청산합니다.
    • 급락/급등(플래시 크래시, 스파이크 등)과 같은 극단적 시장 움직임으로부터 보호하기 위함입니다.
  2. 매도 신호 레이어(데드 크로스)

    • 데드 크로스가 없으면, 일일 SL/TP만으로는 청산하지 않습니다.
    • “추세가 유지되는 동안은 최대한 보유한다”는 아이디어를 반영합니다.
  3. 일일 SL/TP(추세 기반 청산)

    • 데드 크로스가 발생한 이후에만 daily_stop_loss / daily_take_profit 을 적용해 실제 청산 여부를 결정합니다.
    • 이는 순수 PnL 기반 청산보다 추세 추종 논리에 더 가깝습니다.

6. PulseForce 파라미터 및 HyperOpt 최적화

PulseForce 앱(Apple App Store 및 Google Play 제공)은 트레이딩 작업, 백테스트, 하이퍼파라미터 최적화를 위한 시각적 설정 UI를 제공하여 전략을 완전히 파라미터화할 수 있습니다.

Backtest 설정 UI:

HyperOpt 설정 UI:

다음 파라미터들은 종목별로 최적의 조합을 찾기 위해 최적화 가능합니다.

6.1 기본 파라미터

이 파라미터들은 추세 신호 자체의 형태를 결정합니다.

Param Key Name Description Optimizable Suggested initial search range (otp_init_min ~ otp_init_max)
ma_fast 빠른 MA 기간 단기 MA 기간; 값이 작을수록 더 빠르게 반응 ✅ 8 ~ 25
ma_slow 느린 MA 기간 장기 MA 기간; 값이 클수록 더 부드러움 ✅ 40 ~ 90

코드에서는 HyperOpt 공간에 다음과 같이 매핑됩니다.

ma_fast = IntParameter(3, 100, default=10, space="buy", optimize=True)
ma_slow = IntParameter(5, 200, default=30, space="buy", optimize=True)

PulseForce 내 HyperOpt를 사용하면 종목별로 가장 적합한 단기/장기 MA 기간을 자동으로 탐색할 수 있습니다.


6.2 자본 배분(Capital Allocation)

자본 배분 파라미터는 다른 전략들과 일관된 구조를 유지합니다.
전략이 사용할 최대 자금과, 추세 상태별 노출 규모를 제어합니다. 기본적으로는 최적화 대상이 아니지만 UI에서 조정할 수 있습니다.

Param Key Description
max_funds_allowed_using 이 전략에 할당 가능한 최대 자본
allowable_funds_neutral 중립(Neutral) 구간 자본 배분
allowable_funds_uptrend 상승 추세(Uptrend) 구간 자본 배분
allowable_funds_downtrend 하락 추세(Downtrend) 구간 자본 배분

6.3 손절(Stop Loss) 파라미터

손절 파라미터는 HyperOpt 최적화를 지원합니다.

Param Key Name Meaning Optimizable Suggested Range
force_stop_loss 강제 손절 비율 하드 손절 임계값 ✅ 0.005 ~ 0.30
daily_stop_loss 일일 손절 비율 데드 크로스(매도 신호) 이후에만 활성화되는 일일 손절 ✅ 0.01 ~ 0.3

6.4 익절(Take Profit) 파라미터

익절 파라미터 또한 완전히 최적화 가능합니다.

Param Key Name Meaning Optimizable Suggested Range
force_take_profit 강제 익절 비율 하드 익절 임계값 ✅ 0.005 ~ 0.30
daily_take_profit 일일 익절 비율 매도 신호 이후에만 활성화되는 일일 익절 ✅ 0.01 ~ 0.3

하드 TP와 일일 TP를 결합하면 다층형 이익 보호 메커니즘을 구성할 수 있습니다.


7. Dual MA를 언제 사용하면 좋은가?

7.1 가장 적합한 시나리오

  • 뚜렷한 추세 특성이 있는 자산:
    예) 미국 성장주, 추세형 ETF, 주요 지수, 변동성이 큰 암호화폐
  • 단순한 규칙 + 깔끔한 신호를 선호하는 사용자:
    여러 지표에 의존하지 않아 과최적화(overfitting) 위험이 낮음
  • 베이스라인 전략이 필요한 연구/비교 환경:
    MA Crossover, MACD, Momentum 등의 초과 수익 비교에 활용

7.2 덜 적합한 시나리오

  • 장기간 박스권에 머물며 잦은 휩쏘(whipsaw)가 발생하는 종목
  • 초단기 랜덤 움직임처럼 고주파 노이즈가 매우 강한 환경
  • 매우 정밀한 진입이 필요한 경우(듀얼 MA는 “추세 초입”보다는 “추세 중간 구간”을 더 잘 잡는 편)

8. 강점과 약점

강점

  • 구조가 매우 단순하고 투명하여 해석 가능성이 높음
  • 파라미터 수가 적음 → HyperOpt 최적화가 더 안정적이고 과최적화에 덜 취약
  • 다음 목적에 이상적:
    • 베이스라인(벤치마크) 전략
    • 교육/온보딩
    • 더 복잡한 전략과의 비교
  • PulseForce 리스크 프레임워크를 완전히 준수:
    • 하드 SL/TP 임계값
    • 일일 SL/TP
    • 통합 custom_exit 프로세스

약점

  • RSI, 거래량, 변동성 등을 고려하지 않음 → 횡보/변동 장에서 민감해져 거짓 신호가 늘 수 있음
  • 더 고급 추세 전략(예: AI 필터가 포함된 Momentum)과 비교하면 일부 종목에서 성능이 다소 열세일 수 있음
  • 명시적 일일 추세 필터가 없음 → 매우 노이즈가 큰 환경에서는 추가 필터와의 결합이 필요할 수 있음

9. 요약

dual_moving_avg는 PulseForce 내에서 가장 순수하고 표준적인 듀얼 이동평균 교차 구현입니다.

  • 단기/장기 MA의 골든 크로스 / 데드 크로스만으로 추세 신호 생성
  • 하드 임계값 + 일일 손절/익절을 결합한 통합 리스크 프레임워크 적용
  • ma_fast / ma_slow / daily_* / force_* 를 대상으로 HyperOpt 지원
  • UI 설정 + 백테스트 + 하이퍼최적화를 통해 사용자는 자신에게 맞는 듀얼 MA 스타일을 빠르게 구축 가능

특히 다음 용도로 적합합니다.

  • 첫 번째 추세 추종 전략
  • Momentum / MA Crossover / MACD Trend 등과 비교하기 위한 베이스라인
  • PulseForce 파이프라인(전략 → 파라미터 → 리스크 → 백테스트 → HyperOpt)을 학습하기 위한 예시 전략

더 많은 전략과 최신 기능을 확인하려면:
👉 PulseForce 공식 웹사이트: https://www.hiforce.ai