WLD DeepCoin 단계별 구조 재편 및 설정·문서 통합
로고스/루트 레거시를 제거하고 deepcoin 패키지·scripts 01~05 CLI·docs/reference로 데이터·GT·분석·매칭·운영 단계를 정리했다. config와 .env 기반 설정, trade_anaysis.html 동기화 포함. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
153
deepcoin/analysis/general_analysis_align.py
Normal file
153
deepcoin/analysis/general_analysis_align.py
Normal file
@@ -0,0 +1,153 @@
|
||||
"""
|
||||
general_analysis MTF 합성·정렬 점수.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Any
|
||||
|
||||
import pandas as pd
|
||||
|
||||
from config import (
|
||||
ALIGN_BB_POS_HIGH,
|
||||
ALIGN_BB_POS_LOW,
|
||||
ALIGN_RSI_CONFLICT_TIMING_HIGH,
|
||||
ALIGN_RSI_CONFLICT_TIMING_LOW,
|
||||
ALIGN_RSI_CONFLICT_TREND_HIGH,
|
||||
ALIGN_RSI_CONFLICT_TREND_LOW,
|
||||
ALIGN_RSI_OVERBOUGHT,
|
||||
ALIGN_RSI_OVERSOLD,
|
||||
)
|
||||
from deepcoin.analysis.general_analysis_config import TIMING_INTERVALS, TREND_INTERVALS
|
||||
from deepcoin.analysis.general_analysis_core import ga_col, interval_tf_prefix
|
||||
|
||||
|
||||
def general_analysis_mtf_scores(
|
||||
prefixed_row: dict[str, Any],
|
||||
) -> dict[str, float | int | str]:
|
||||
"""
|
||||
간격 접두사가 붙은 스냅샷 행에서 MTF 합성 점수 계산.
|
||||
|
||||
Args:
|
||||
prefixed_row: m3_ga_rsi 형태 flat dict.
|
||||
|
||||
Returns:
|
||||
ga_align_* 점수.
|
||||
"""
|
||||
rsi_oversold = 0
|
||||
rsi_overbought = 0
|
||||
trend_up = 0
|
||||
trend_down = 0
|
||||
n_timing = 0
|
||||
n_trend = 0
|
||||
conflict = 0
|
||||
|
||||
for interval in TIMING_INTERVALS:
|
||||
p = interval_tf_prefix(interval)
|
||||
rk = f"{p}_RSI"
|
||||
if rk in prefixed_row and prefixed_row[rk] is not None:
|
||||
n_timing += 1
|
||||
rsi = float(prefixed_row[rk])
|
||||
if rsi < ALIGN_RSI_OVERSOLD:
|
||||
rsi_oversold += 1
|
||||
if rsi > ALIGN_RSI_OVERBOUGHT:
|
||||
rsi_overbought += 1
|
||||
|
||||
for interval in TREND_INTERVALS:
|
||||
p = interval_tf_prefix(interval)
|
||||
sk = f"{p}_{ga_col('struct_trend')}"
|
||||
if sk in prefixed_row:
|
||||
n_trend += 1
|
||||
t = prefixed_row[sk]
|
||||
if t == "up":
|
||||
trend_up += 1
|
||||
elif t == "down":
|
||||
trend_down += 1
|
||||
|
||||
m3_rsi = prefixed_row.get("m3_RSI")
|
||||
d1_rsi = prefixed_row.get("d1_RSI")
|
||||
if m3_rsi is not None and d1_rsi is not None:
|
||||
if (
|
||||
float(m3_rsi) < ALIGN_RSI_CONFLICT_TIMING_LOW
|
||||
and float(d1_rsi) > ALIGN_RSI_CONFLICT_TREND_HIGH
|
||||
):
|
||||
conflict = 1
|
||||
if (
|
||||
float(m3_rsi) > ALIGN_RSI_CONFLICT_TIMING_HIGH
|
||||
and float(d1_rsi) < ALIGN_RSI_CONFLICT_TREND_LOW
|
||||
):
|
||||
conflict = 1
|
||||
|
||||
timing_buy_align = rsi_oversold / max(len(TIMING_INTERVALS), 1)
|
||||
timing_sell_align = rsi_overbought / max(len(TIMING_INTERVALS), 1)
|
||||
|
||||
return {
|
||||
"ga_align_rsi_oversold_tf": rsi_oversold,
|
||||
"ga_align_rsi_overbought_tf": rsi_overbought,
|
||||
"ga_align_trend_up_tf": trend_up,
|
||||
"ga_align_trend_down_tf": trend_down,
|
||||
"ga_align_timing_buy_score": round(timing_buy_align, 3),
|
||||
"ga_align_timing_sell_score": round(timing_sell_align, 3),
|
||||
"ga_align_trend_score": round(
|
||||
(trend_up - trend_down) / max(n_trend, 1), 3
|
||||
),
|
||||
"ga_align_mtf_conflict": conflict,
|
||||
}
|
||||
|
||||
|
||||
def general_analysis_mtf_vote_latest(
|
||||
frames_enriched: dict[int, pd.DataFrame],
|
||||
) -> dict[str, float | int | str]:
|
||||
"""
|
||||
각 TF 최신 완성봉 지표로 TF 가중 투표·필터 점수 산출.
|
||||
|
||||
Args:
|
||||
frames_enriched: interval → enrich된 DataFrame.
|
||||
|
||||
Returns:
|
||||
ga_vote_* 점수 (접두사 없음, ga_col로 감쌀 것).
|
||||
"""
|
||||
votes_buy = 0
|
||||
votes_sell = 0
|
||||
trend_ok = 0
|
||||
n = 0
|
||||
|
||||
for interval in TIMING_INTERVALS:
|
||||
df = frames_enriched.get(interval)
|
||||
if df is None or df.empty:
|
||||
continue
|
||||
row = df.iloc[-1]
|
||||
n += 1
|
||||
rsi = row.get("RSI")
|
||||
if rsi is not None and not pd.isna(rsi):
|
||||
if float(rsi) < ALIGN_RSI_OVERSOLD:
|
||||
votes_buy += 1
|
||||
if float(rsi) > ALIGN_RSI_OVERBOUGHT:
|
||||
votes_sell += 1
|
||||
bb_pos = row.get("bb_pos")
|
||||
if bb_pos is not None and float(bb_pos) < ALIGN_BB_POS_LOW:
|
||||
votes_buy += 1
|
||||
if bb_pos is not None and float(bb_pos) > ALIGN_BB_POS_HIGH:
|
||||
votes_sell += 1
|
||||
|
||||
for interval in TREND_INTERVALS:
|
||||
df = frames_enriched.get(interval)
|
||||
if df is None or df.empty:
|
||||
continue
|
||||
row = df.iloc[-1]
|
||||
st = row.get(ga_col("struct_trend"), "range")
|
||||
if st == "up":
|
||||
trend_ok += 1
|
||||
elif st == "down":
|
||||
trend_ok -= 1
|
||||
|
||||
return {
|
||||
"vote_timing_buy": votes_buy,
|
||||
"vote_timing_sell": votes_sell,
|
||||
"vote_trend_score": trend_ok,
|
||||
"vote_tf_used": n,
|
||||
}
|
||||
|
||||
|
||||
def general_analysis_vote_columns() -> list[str]:
|
||||
return ["vote_timing_buy", "vote_timing_sell", "vote_trend_score", "vote_tf_used"]
|
||||
Reference in New Issue
Block a user