hybrid DD tier와 Option C 2차(+1000%) 검증을 추가하고 실거래 사이징을 정합한다.
인과 GT leg 엔진·drawdown tier·train 캘리브레이션, Phase 2 Go/No-Go 및 시뮬 리포트를 반영한다. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -11,6 +11,7 @@ from pathlib import Path
|
||||
from typing import Any
|
||||
|
||||
from config import (
|
||||
CHART_LOOKBACK_DAYS,
|
||||
COIN_NAME,
|
||||
LIVE_COOLDOWN_MIN,
|
||||
LIVE_DAILY_KRW_MAX,
|
||||
@@ -18,11 +19,14 @@ from config import (
|
||||
LIVE_MAX_TRADES_PER_DAY,
|
||||
LIVE_ORDER_KRW,
|
||||
LIVE_TRADING_ENABLED,
|
||||
MATCH_PRIMARY_INTERVAL,
|
||||
SYMBOL,
|
||||
TRADING_FEE_RATE,
|
||||
)
|
||||
from deepcoin.data.mtf_bb import load_frames_from_db
|
||||
from deepcoin.ground_truth.ground_truth import load_ground_truth
|
||||
from deepcoin.matching.live_eval import evaluate_live_rules
|
||||
from deepcoin.matching.live_sizing import LivePositionState, live_sizing_enabled
|
||||
from deepcoin.matching.load_rules import load_monitor_rules
|
||||
from deepcoin.matching.position_sizing import (
|
||||
compute_buy_amount_krw,
|
||||
@@ -52,6 +56,8 @@ class LiveTrader(Monitor):
|
||||
self._gt_trades: list[dict] = []
|
||||
self._large_legs: set[int] = set()
|
||||
self._approved_rules: set[str] = set()
|
||||
self._position_state = LivePositionState.load()
|
||||
self._ohlc_df = None
|
||||
self._load_sizing_context()
|
||||
|
||||
def _load_sizing_context(self) -> None:
|
||||
@@ -104,10 +110,20 @@ class LiveTrader(Monitor):
|
||||
return False, f"규칙 쿨다운({LIVE_COOLDOWN_MIN}분)"
|
||||
return True, ""
|
||||
|
||||
def _load_ohlc_df(self) -> None:
|
||||
"""drawdown tier용 3m OHLC 캐시."""
|
||||
try:
|
||||
frames = load_frames_from_db(self, SYMBOL, lookback_days=CHART_LOOKBACK_DAYS)
|
||||
self._ohlc_df = frames.get(MATCH_PRIMARY_INTERVAL)
|
||||
except Exception:
|
||||
self._ohlc_df = None
|
||||
|
||||
def _resolve_buy_amount_krw(self, hit: dict[str, Any]) -> float:
|
||||
"""
|
||||
총자산·현금·EV/WF·leg 티어로 매수 원화 산출.
|
||||
|
||||
GT_SIGNAL_CAUSAL=1 이면 시뮬 sim_tier_enhanced와 동일 인과 tier·weight.
|
||||
|
||||
Args:
|
||||
hit: evaluate_live_rules 항목.
|
||||
|
||||
@@ -127,6 +143,18 @@ class LiveTrader(Monitor):
|
||||
qty = float(sym.get("balance") or 0)
|
||||
except Exception:
|
||||
return 0.0
|
||||
if live_sizing_enabled():
|
||||
if self._ohlc_df is None:
|
||||
self._load_ohlc_df()
|
||||
return self._position_state.plan_buy_amount_krw(
|
||||
hit["dt"],
|
||||
price,
|
||||
cash,
|
||||
qty,
|
||||
self._ohlc_df,
|
||||
enhanced=False,
|
||||
fee_rate=TRADING_FEE_RATE,
|
||||
)
|
||||
scale = live_buy_asset_pct_scale(
|
||||
rid,
|
||||
hit["dt"],
|
||||
@@ -200,18 +228,31 @@ class LiveTrader(Monitor):
|
||||
if qty <= 0:
|
||||
record["message"] = "보유 없음"
|
||||
else:
|
||||
gross = qty * price
|
||||
record["amount_krw"] = round(gross, 0)
|
||||
ok = self.sellCoinMarket(SYMBOL, int(price), qty)
|
||||
record["ok"] = bool(ok)
|
||||
record["message"] = f"sell qty={qty}" if ok else "sell failed"
|
||||
if record["ok"] and live_sizing_enabled():
|
||||
fee = gross * TRADING_FEE_RATE
|
||||
self._position_state.record_sell(
|
||||
gross, fee, full_close=True
|
||||
)
|
||||
self._position_state.save()
|
||||
else:
|
||||
record["message"] = f"unknown side {side}"
|
||||
except Exception as exc:
|
||||
record["message"] = str(exc)
|
||||
|
||||
if record["ok"]:
|
||||
self._day_spent_krw += amount_krw
|
||||
spent = float(record.get("amount_krw") or amount_krw)
|
||||
self._day_spent_krw += spent
|
||||
self._day_trades += 1
|
||||
self._rule_last_unix[hit["rule_id"]] = time.time()
|
||||
if live_sizing_enabled() and side == "buy":
|
||||
fee = spent * TRADING_FEE_RATE
|
||||
self._position_state.record_buy(hit["dt"], price, spent, fee)
|
||||
self._position_state.save()
|
||||
return record
|
||||
|
||||
def run_once(self) -> None:
|
||||
|
||||
Reference in New Issue
Block a user