로고스/루트 레거시를 제거하고 deepcoin 패키지·scripts 01~05 CLI·docs/reference로 데이터·GT·분석·매칭·운영 단계를 정리했다. config와 .env 기반 설정, trade_anaysis.html 동기화 포함. Co-authored-by: Cursor <cursoragent@cursor.com>
115 lines
3.4 KiB
Python
115 lines
3.4 KiB
Python
"""
|
|
general_analysis 캔들·차트 변환 (Heikin-Ashi, 복수봉 패턴).
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import numpy as np
|
|
import pandas as pd
|
|
|
|
from deepcoin.analysis.general_analysis_core import ga_col
|
|
|
|
|
|
def general_analysis_apply_candles(df: pd.DataFrame) -> pd.DataFrame:
|
|
"""
|
|
단일·복수 봉 캔들 패턴 및 Heikin-Ashi 컬럼 추가.
|
|
|
|
Args:
|
|
df: OHLCV.
|
|
|
|
Returns:
|
|
ga_* 캔들 컬럼이 추가된 DataFrame.
|
|
"""
|
|
out = df.copy()
|
|
o = out["Open"].astype(float)
|
|
h = out["High"].astype(float)
|
|
l = out["Low"].astype(float)
|
|
c = out["Close"].astype(float)
|
|
|
|
rng = (h - l).replace(0, np.nan)
|
|
body = (c - o).abs()
|
|
out[ga_col("body_ratio")] = (body / rng).fillna(0).clip(0, 1)
|
|
upper_wick = h - np.maximum(o, c)
|
|
lower_wick = np.minimum(o, c) - l
|
|
out[ga_col("upper_wick_ratio")] = (upper_wick / rng).fillna(0).clip(0, 1)
|
|
out[ga_col("lower_wick_ratio")] = (lower_wick / rng).fillna(0).clip(0, 1)
|
|
out[ga_col("bullish")] = (c > o).astype(int)
|
|
out[ga_col("bearish")] = (c < o).astype(int)
|
|
out[ga_col("hammer")] = (
|
|
(out[ga_col("lower_wick_ratio")] > 0.45) & (out[ga_col("body_ratio")] < 0.35)
|
|
).astype(int)
|
|
out[ga_col("shooting_star")] = (
|
|
(out[ga_col("upper_wick_ratio")] > 0.45) & (out[ga_col("body_ratio")] < 0.35)
|
|
).astype(int)
|
|
out[ga_col("doji")] = (out[ga_col("body_ratio")] < 0.1).astype(int)
|
|
|
|
prev_o, prev_c = o.shift(1), c.shift(1)
|
|
out[ga_col("bullish_engulfing")] = (
|
|
(c > o) & (prev_c < prev_o) & (c >= prev_o) & (o <= prev_c)
|
|
).astype(int)
|
|
out[ga_col("bearish_engulfing")] = (
|
|
(c < o) & (prev_c > prev_o) & (c <= prev_o) & (o >= prev_c)
|
|
).astype(int)
|
|
|
|
o2, c2 = o.shift(2), c.shift(2)
|
|
mid1 = (o.shift(1) + c.shift(1)) / 2
|
|
out[ga_col("morning_star")] = (
|
|
(c2 < o2)
|
|
& (abs(c.shift(1) - o.shift(1)) < rng.shift(1) * 0.15)
|
|
& (c > o)
|
|
& (c > mid1)
|
|
).astype(int)
|
|
out[ga_col("evening_star")] = (
|
|
(c2 > o2)
|
|
& (abs(c.shift(1) - o.shift(1)) < rng.shift(1) * 0.15)
|
|
& (c < o)
|
|
& (c < mid1)
|
|
).astype(int)
|
|
|
|
out[ga_col("three_white_soldiers")] = (
|
|
(c > o)
|
|
& (c.shift(1) > o.shift(1))
|
|
& (c.shift(2) > o.shift(2))
|
|
& (c > c.shift(1))
|
|
& (c.shift(1) > c.shift(2))
|
|
).astype(int)
|
|
out[ga_col("three_black_crows")] = (
|
|
(c < o)
|
|
& (c.shift(1) < o.shift(1))
|
|
& (c.shift(2) < o.shift(2))
|
|
& (c < c.shift(1))
|
|
& (c.shift(1) < c.shift(2))
|
|
).astype(int)
|
|
|
|
# Heikin-Ashi
|
|
ha_close = (o + h + l + c) / 4
|
|
ha_open = ha_close.copy()
|
|
ha_open.iloc[0] = (o.iloc[0] + c.iloc[0]) / 2
|
|
for i in range(1, len(out)):
|
|
ha_open.iloc[i] = (ha_open.iloc[i - 1] + ha_close.iloc[i - 1]) / 2
|
|
out[ga_col("ha_close")] = ha_close
|
|
out[ga_col("ha_open")] = ha_open
|
|
out[ga_col("ha_bull")] = (ha_close > ha_open).astype(int)
|
|
out[ga_col("ha_trend_up")] = (
|
|
(ha_close > ha_close.shift(1)) & (ha_close.shift(1) > ha_close.shift(2))
|
|
).astype(int)
|
|
|
|
return out
|
|
|
|
|
|
def general_analysis_candle_columns() -> list[str]:
|
|
return [
|
|
"body_ratio",
|
|
"hammer",
|
|
"shooting_star",
|
|
"doji",
|
|
"bullish_engulfing",
|
|
"bearish_engulfing",
|
|
"morning_star",
|
|
"evening_star",
|
|
"three_white_soldiers",
|
|
"three_black_crows",
|
|
"ha_bull",
|
|
"ha_trend_up",
|
|
]
|