레거시 분석·매칭·운영 코드를 정리하고 src/deepcoin 기반으로 재구성한다. 1단계 GT는 2년 스윙·눌림목·돌파·다이버전스 타점을 차트에 표시하고, 2단계는 8개 매매 기법과 GT 정합 평가 스크립트를 추가한다. .env와 GT JSON 산출물은 추적에서 제외한다. Co-authored-by: Cursor <cursoragent@cursor.com>
55 lines
1.7 KiB
Python
55 lines
1.7 KiB
Python
"""기술적 지표 계산 (인과 신호용)."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import pandas as pd
|
|
|
|
|
|
def ema(series: pd.Series, span: int) -> pd.Series:
|
|
"""지수이동평균을 계산한다."""
|
|
return series.ewm(span=span, adjust=False).mean()
|
|
|
|
|
|
def sma(series: pd.Series, window: int) -> pd.Series:
|
|
"""단순이동평균을 계산한다."""
|
|
return series.rolling(window=window, min_periods=window).mean()
|
|
|
|
|
|
def bollinger_bands(
|
|
close: pd.Series,
|
|
window: int = 20,
|
|
num_std: float = 2.0,
|
|
) -> tuple[pd.Series, pd.Series, pd.Series]:
|
|
"""볼린저 밴드 (중심, 상단, 하단)를 계산한다."""
|
|
mid = sma(close, window)
|
|
std = close.rolling(window=window, min_periods=window).std()
|
|
upper = mid + num_std * std
|
|
lower = mid - num_std * std
|
|
return mid, upper, lower
|
|
|
|
|
|
def rsi(close: pd.Series, period: int = 14) -> pd.Series:
|
|
"""RSI(상대강도지수)를 계산한다."""
|
|
delta = close.diff()
|
|
gain = delta.clip(lower=0.0)
|
|
loss = -delta.clip(upper=0.0)
|
|
avg_gain = gain.ewm(alpha=1 / period, min_periods=period, adjust=False).mean()
|
|
avg_loss = loss.ewm(alpha=1 / period, min_periods=period, adjust=False).mean()
|
|
rs = avg_gain / avg_loss.replace(0, pd.NA)
|
|
return 100 - (100 / (1 + rs))
|
|
|
|
|
|
def macd(
|
|
close: pd.Series,
|
|
fast: int = 12,
|
|
slow: int = 26,
|
|
signal: int = 9,
|
|
) -> tuple[pd.Series, pd.Series, pd.Series]:
|
|
"""MACD, 시그널, 히스토그램을 계산한다."""
|
|
ema_fast = ema(close, fast)
|
|
ema_slow = ema(close, slow)
|
|
macd_line = ema_fast - ema_slow
|
|
signal_line = ema(macd_line, signal)
|
|
hist = macd_line - signal_line
|
|
return macd_line, signal_line, hist
|