refactor: GT·시뮬·운영 3축 정리 및 hybrid 실거래 정합
Phase C/dry-run·미사용 모듈·재생성 HTML을 제거하고, 운영 체결을 sim_causal_hybrid와 동일한 hybrid 로직으로 통합한다. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -217,72 +217,6 @@ def nearest_gt_leg_id(
|
||||
return best_buy if best_buy is not None else best_any
|
||||
|
||||
|
||||
_APPROVED_RULES_CACHE: set[str] | None = None
|
||||
|
||||
|
||||
def load_ev_wf_approved_rule_ids(
|
||||
matched_path: Path | None = None,
|
||||
outcomes_path: Path | None = None,
|
||||
) -> set[str]:
|
||||
"""
|
||||
holdout EV·PF, walk-forward, 수수료 스트레스를 모두 통과한 rule_id.
|
||||
|
||||
Args:
|
||||
matched_path: matched_rules.json.
|
||||
outcomes_path: fire_outcomes.csv.
|
||||
|
||||
Returns:
|
||||
통과 rule_id set. 산출 불가 시 monitor_rules 전체 fallback.
|
||||
"""
|
||||
global _APPROVED_RULES_CACHE
|
||||
if _APPROVED_RULES_CACHE is not None:
|
||||
return set(_APPROVED_RULES_CACHE)
|
||||
|
||||
from config import SIM_FEE_STRESS_MULT
|
||||
|
||||
from deepcoin.matching.select_rules import _rule_metrics, _split_train_valid_holdout
|
||||
from deepcoin.matching.simulation import (
|
||||
evaluate_go_no_go,
|
||||
simulate_live_order_cap,
|
||||
walk_forward_by_month,
|
||||
walk_forward_summary,
|
||||
)
|
||||
|
||||
mp = matched_path or MATCHING_MATCHED_RULES
|
||||
op = outcomes_path or MATCHING_FIRE_OUTCOMES
|
||||
matched = load_matched_rules(mp)
|
||||
rules = matched.get("monitor_rules") or []
|
||||
if not rules or not op.is_file():
|
||||
return {r["rule_id"] for r in rules}
|
||||
|
||||
import pandas as pd
|
||||
|
||||
from config import MATCH_FEE_RATE
|
||||
|
||||
outcomes = pd.read_csv(op)
|
||||
outcomes["split"] = _split_train_valid_holdout(outcomes)
|
||||
wf_sum = walk_forward_summary(walk_forward_by_month(outcomes))
|
||||
fee_stress: dict[str, Any] = {}
|
||||
for rid in outcomes["rule_id"].unique():
|
||||
sub = outcomes[outcomes["rule_id"] == rid]
|
||||
from deepcoin.matching.simulation import _fee_adjust_ret
|
||||
|
||||
adj = _fee_adjust_ret(sub["forward_ret_pct"], SIM_FEE_STRESS_MULT)
|
||||
fee_stress[rid] = _rule_metrics(sub.assign(forward_ret_pct=adj))
|
||||
monitor_ids = {r["rule_id"] for r in rules}
|
||||
live_cap = simulate_live_order_cap(
|
||||
outcomes, rule_ids=monitor_ids, holdout_only=True
|
||||
)
|
||||
go = evaluate_go_no_go(matched, wf_sum, fee_stress, live_cap)
|
||||
passed = {c["rule_id"] for c in go.get("checks", []) if c.get("pass")}
|
||||
if passed:
|
||||
_APPROVED_RULES_CACHE = passed
|
||||
return passed
|
||||
fallback = monitor_ids
|
||||
_APPROVED_RULES_CACHE = fallback
|
||||
return fallback
|
||||
|
||||
|
||||
def load_gt_allocation_analysis(
|
||||
gt_trades: list[dict[str, Any]] | None = None,
|
||||
) -> dict[str, Any]:
|
||||
@@ -328,8 +262,6 @@ def gt_tier_scale_for_trade(
|
||||
"""
|
||||
GT leg tier 배분 스케일 (분석 권장값 또는 config).
|
||||
|
||||
시뮬은 live_buy_asset_pct_scale 대신 GT와 동일 tier 정책을 사용합니다.
|
||||
|
||||
Args:
|
||||
trade: {dt, leg_id?, action, ...}.
|
||||
gt_trades: GT trades (leg 매칭).
|
||||
@@ -349,37 +281,6 @@ def gt_tier_scale_for_trade(
|
||||
return gt_tier_scale_from_analysis(int(lid), large_legs, analysis)
|
||||
|
||||
|
||||
def live_buy_asset_pct_scale(
|
||||
rule_id: str,
|
||||
dt: str,
|
||||
gt_trades: list[dict[str, Any]],
|
||||
*,
|
||||
approved_rules: set[str],
|
||||
large_legs: set[int],
|
||||
) -> float:
|
||||
"""
|
||||
실거래 전용 매수 tier (EV/WF·leg 상위). 시뮬은 gt_tier_scale_for_trade 사용.
|
||||
|
||||
Args:
|
||||
rule_id: 규칙 ID.
|
||||
dt: 체결 시각.
|
||||
gt_trades: GT trades.
|
||||
approved_rules: 통과 rule_id.
|
||||
large_legs: 상위 leg.
|
||||
|
||||
Returns:
|
||||
LIVE_BUY_PCT_LARGE 또는 LIVE_BUY_PCT_SMALL(또는 0에 가까운 소형).
|
||||
"""
|
||||
from config import LIVE_BUY_PCT_LARGE, LIVE_BUY_PCT_SMALL
|
||||
|
||||
if rule_id not in approved_rules:
|
||||
return float(LIVE_BUY_PCT_SMALL)
|
||||
lid = nearest_gt_leg_id(dt, gt_trades)
|
||||
if lid is not None and lid in large_legs:
|
||||
return float(LIVE_BUY_PCT_LARGE)
|
||||
return float(LIVE_BUY_PCT_SMALL)
|
||||
|
||||
|
||||
def enrich_sim_trades_with_gt_weights(
|
||||
trades: list[dict[str, Any]],
|
||||
gt_trades: list[dict[str, Any]],
|
||||
@@ -504,65 +405,6 @@ def attach_gt_model_amounts(
|
||||
return enriched
|
||||
|
||||
|
||||
def plan_open_position_buy(
|
||||
open_buys: list[dict[str, Any]],
|
||||
candidate: dict[str, Any],
|
||||
cash: float,
|
||||
qty: float,
|
||||
gt_trades: list[dict[str, Any]] | None = None,
|
||||
*,
|
||||
large_legs: set[int],
|
||||
analysis: dict[str, Any] | None = None,
|
||||
fee_rate: float = TRADING_FEE_RATE,
|
||||
) -> float:
|
||||
"""
|
||||
미청산 포지션 내 다음 매수 원화 (GT tier·보유 현금 한도, 1회 상한 없음).
|
||||
|
||||
Args:
|
||||
open_buys: 현재 포지션에서 이미 체결된 매수 dict.
|
||||
candidate: 이번 매수 후보 {dt, price, rule_id, leg_id?, ...}.
|
||||
cash: 보유 현금.
|
||||
qty: 보유 수량.
|
||||
gt_trades: GT leg 매칭용.
|
||||
large_legs: 상위 leg.
|
||||
analysis: GT 배분 분석.
|
||||
fee_rate: 수수료율.
|
||||
|
||||
Returns:
|
||||
매수 계획 원화.
|
||||
"""
|
||||
from deepcoin.ground_truth.gt_model import leg_entry_weights
|
||||
|
||||
if gt_trades is None:
|
||||
gt_trades, _, _ = load_sizing_context_from_gt()
|
||||
if analysis is None:
|
||||
analysis = load_gt_allocation_analysis(gt_trades)
|
||||
|
||||
prices = [float(t["price"]) for t in open_buys] + [float(candidate["price"])]
|
||||
weights = leg_entry_weights(prices)
|
||||
idx = len(open_buys)
|
||||
w = weights[idx]
|
||||
w_sum = sum(weights[idx:])
|
||||
cand = dict(candidate)
|
||||
if "leg_id" not in cand:
|
||||
cand["leg_id"] = nearest_gt_leg_id(str(candidate["dt"]), gt_trades)
|
||||
scale = gt_tier_scale_for_trade(
|
||||
cand,
|
||||
gt_trades,
|
||||
large_legs,
|
||||
analysis=analysis,
|
||||
)
|
||||
return compute_buy_amount_krw(
|
||||
cash,
|
||||
qty,
|
||||
float(candidate["price"]),
|
||||
w,
|
||||
w_sum,
|
||||
asset_pct_scale=scale,
|
||||
fee_rate=fee_rate,
|
||||
)
|
||||
|
||||
|
||||
def attach_dynamic_buy_amounts(
|
||||
trades: list[dict[str, Any]],
|
||||
*,
|
||||
|
||||
Reference in New Issue
Block a user