Skip to content

Latest commit

 

History

History
235 lines (185 loc) · 8.56 KB

File metadata and controls

235 lines (185 loc) · 8.56 KB

QuantDinger Python 전략 개발 가이드

이 가이드는 QuantDinger 플랫폼에서 Python을 사용하여 거래 전략을 개발하는 방법을 자세히 설명합니다. QuantDinger는 데이터 액세스, 지표 계산 및 신호 생성을 지원하는 유연한 실행 환경을 제공합니다.

1. 개요

QuantDinger의 전략은 신호 제공자(Signal Provider) 모드를 기반으로 작동합니다. 시스템은 귀하의 Python 스크립트를 실행하며, 이 스크립트는 시장 데이터(DataFrame)를 처리하고 거래 신호를 출력합니다.

실행 흐름은 다음과 같습니다:

  1. 입력: 시스템은 OHLCV 데이터를 포함하는 df(Pandas DataFrame)를 스크립트 환경에 주입합니다.
  2. 처리: Python(pandas, numpy)을 사용하여 지표를 계산하고 buy/sell 로직을 정의합니다.
  3. 출력: 플롯 데이터와 신호를 포함하는 특정 output 딕셔너리를 구성합니다.

2. 환경 및 데이터

스크립트는 샌드박스 처리된 Python 환경에서 실행됩니다.

2.1 사전 가져오기된 라이브러리

다음 라이브러리는 기본적으로 사용할 수 있습니다(import필요 없음):

  • pd (pandas)
  • np (numpy)

2.2 입력 데이터 (df)

df라는 이름의 Pandas DataFrame 변수가 전역 범위에 자동으로 존재합니다. 여기에는 선택한 심볼 및 시간대의 과거 시장 데이터가 포함되어 있습니다.

열 (Columns):

  • time: 타임스탬프 (datetime 또는 int, 컨텍스트에 따라 다름)
  • open: 시가 (float)
  • high: 고가 (float)
  • low: 저가 (float)
  • close: 종가 (float)
  • volume: 거래량 (float)

예시:

# 종가 시리즈 가져오기
closes = df['close']

# 단순 이동 평균(SMA) 계산
sma_20 = df['close'].rolling(20).mean()

3. 전략 개발

표준 전략 스크립트는 세 부분으로 구성됩니다:

  1. 지표 계산: 기술적 지표를 계산합니다.
  2. 신호 생성: 매수 및 매도 신호 로직을 정의합니다.
  3. 출력 구성: 차트 표시 및 실행 엔진을 위한 결과를 포맷팅합니다.

3.1 지표 계산

표준 Pandas 연산을 사용하여 지표를 계산할 수 있습니다.

# 예시: MACD 계산
short_window = 12
long_window = 26
signal_window = 9

ema12 = df['close'].ewm(span=short_window, adjust=False).mean()
ema26 = df['close'].ewm(span=long_window, adjust=False).mean()
macd = ema12 - ema26
signal_line = macd.ewm(span=signal_window, adjust=False).mean()

3.2 신호 생성 (중요)

df 내에(또는 독립 변수로) buysell이라는 이름의 두 개의 불리언(Boolean) Series를 반드시 생성해야 합니다.

  • True는 신호 트리거를 나타냅니다.
  • False는 신호 없음을 나타냅니다.

중요: 엣지 트리거(Edge Triggering) 연속된 캔들에서 반복적으로 신호가 발생하는 것을 방지하기 위해(백엔드 설정에 따라 중복 주문으로 이어질 수 있음), 엣지 트리거 신호(조건이 참이 되는 순간에만 신호 발생)를 사용하는 것이 모범 사례입니다.

# 조건: 종가가 SMA 20 상향 돌파
condition_buy = (df['close'] > sma_20) & (df['close'].shift(1) <= sma_20.shift(1))

# 조건: 종가가 SMA 20 하향 돌파
condition_sell = (df['close'] < sma_20) & (df['close'].shift(1) >= sma_20.shift(1))

# df에 할당 (백테스팅에 필수)
df['buy'] = condition_buy.fillna(False)
df['sell'] = condition_sell.fillna(False)

신호 유형에 대한 참고:

  • QuantDinger는 전략 구성(롱 전용, 숏 전용 또는 양방향)에 따라 신호를 정규화합니다.
  • 스크립트는 단순히 "buy"(강세 의도) 또는 "sell"(약세 의도)을 출력하면 됩니다. 백엔드가 진입/청산 로직을 처리합니다.

3.3 시각적 마커

차트에 표시하기 위해 일반적으로 신호 아이콘을 캔들 위나 아래에 배치합니다.

# 매수 마커를 저가보다 0.5% 아래에 배치
buy_marks = [
    df['low'].iloc[i] * 0.995 if df['buy'].iloc[i] else None 
    for i in range(len(df))
]

# 매도 마커를 고가보다 0.5% 위에 배치
sell_marks = [
    df['high'].iloc[i] * 1.005 if df['sell'].iloc[i] else None 
    for i in range(len(df))
]

3.4 output 변수 (필수)

마지막 단계는 output 변수에 딕셔너리를 할당하는 것입니다. 이는 프론트엔드에 무엇을 그릴지, 백엔드에 신호가 어디에 있는지를 알려줍니다.

구조:

output = {
    "name": "내 전략 이름",
    "plots": [ ... ],   # 그릴 라인/지표 목록
    "signals": [ ... ]  # 신호 마커 목록
}

Plots Schema (플롯 구성):

  • name: 범례 이름 (예: "SMA 20")
  • data: 값 목록 (df 길이와 일치해야 함). .tolist()를 사용하여 변환.
  • color: 16진수 색상 문자열 (예: "#ff0000").
  • overlay: True는 메인 차트(가격) 위에 그리기, False는 보조 차트(RSI/MACD 등)에 그리기.

Signals Schema (신호 구성):

  • type: "buy" 또는 "sell"이어야 합니다.
  • text: 아이콘에 표시할 텍스트 (예: "B", "S").
  • data: 값 목록 (가격 위치). 신호 없는 곳은 None.
  • color: 아이콘 색상.

4. 전체 예제: 이중 이동 평균 교차 (Dual SMA)

다음은 SMA(10)이 SMA(30)을 상향 돌파할 때 매수하고, 하향 돌파할 때 매도하는 전체 복사 가능한 전략 예제입니다.

# 1. 지표 계산
# -----------------------
# 단기 및 장기 SMA 계산
sma_short = df['close'].rolling(10).mean()
sma_long = df['close'].rolling(30).mean()

# 2. 신호 로직
# -----------------------
# 매수: 단기 SMA가 장기 SMA 상향 돌파
raw_buy = (sma_short > sma_long) & (sma_short.shift(1) <= sma_long.shift(1))

# 매도: 단기 SMA가 장기 SMA 하향 돌파
raw_sell = (sma_short < sma_long) & (sma_short.shift(1) >= sma_long.shift(1))

# NaN 정리 및 불리언 타입 보장
buy = raw_buy.fillna(False)
sell = raw_sell.fillna(False)

# df 열에 할당 (백엔드 실행의 핵심)
df['buy'] = buy
df['sell'] = sell

# 3. 시각적 포맷팅
# -----------------------
# 마커 위치 계산
buy_marks = [
    df['low'].iloc[i] * 0.995 if buy.iloc[i] else None 
    for i in range(len(df))
]

sell_marks = [
    df['high'].iloc[i] * 1.005 if sell.iloc[i] else None 
    for i in range(len(df))
]

# 4. 최종 출력
# -----------------------
output = {
  'name': 'Dual SMA Strategy',
  'plots': [
    {
        'name': 'SMA 10',
        'data': sma_short.fillna(0).tolist(),
        'color': '#1890ff',
        'overlay': True
    },
    {
        'name': 'SMA 30',
        'data': sma_long.fillna(0).tolist(),
        'color': '#faad14',
        'overlay': True
    }
  ],
  'signals': [
    {
        'type': 'buy',
        'text': 'B',
        'data': buy_marks,
        'color': '#00E676'
    },
    {
        'type': 'sell',
        'text': 'S',
        'data': sell_marks,
        'color': '#FF5252'
    }
  ]
}

5. 모범 사례 및 문제 해결

5.1 NaN 처리

롤링 계산(rolling(14) 등)은 데이터 시작 부분에 NaN 값을 생성합니다.

  • 규칙: 신호를 생성하기 전에 항상 NaN을 처리하십시오.
  • 수정: 상황에 따라 .fillna(0) 또는 .fillna(False)를 사용하십시오.

5.2 미래 참조 편향 (Look-ahead Bias)

시스템은 캔들의 종가에서 발생한 신호를 기반으로 거래를 실행합니다.

  • 백테스트 엔진은 일반적으로 다음 캔들의 시가에서 주문을 실행합니다.
  • 신호 로직은 close(현재 완료된 캔들) 또는 shift(1)(이전 캔들)에 의존해야 합니다. shift(-1)은 절대 사용하지 마십시오.

5.3 성능

계산 로직에서 DataFrame 행을 반복(for i in range(len(df)): ...)하는 것을 피하십시오. 매우 느립니다.

  • 나쁨: 루프를 사용하여 SMA 계산.
  • 좋음: df['close'].rolling(...) 사용.
  • 예외: buy_marks/sell_marks 리스트 구성에는 일반적으로 리스트 컴프리헨션이 필요하며, 이는 시각적 출력에만 사용되므로 허용됩니다.

5.4 디버깅

일부 실행 모드에서는 print() 출력을 쉽게 볼 수 없으므로, 전략 로드에 실패하면 백엔드 로그(backend_api_python/logs/app.log)를 확인하십시오.

  • 일반적인 오류: KeyError (잘못된 열 이름).
  • 일반적인 오류: ValueError (배열 길이 불일치). plots의 데이터 길이가 df와 일치하는지 확인하십시오.