63a829cc46
主要内容: - Phase 8 PROMOTE: finalist #1 (trial #324) registry 条目,自动生成 - Optuna objective warmup bug 修复 (shared/optimizer/objective.py) - studies/ 目录按用途重组为 optuna/ + finalists/ + features/ 三层 - reports/ 加入 Optuna 中文 dashboard (5 主图 + 18 slice + 15 contour) - 新增 PROJECT_GUIDE.md 项目说明文档 - 新增 build_registry_entry.py / build_optuna_dashboard.py / build_feature_datasets.py - .gitignore: 允许提交 studies/*.db (Optuna DB) 和 reports/*.html (MT5 + dashboard)
83 lines
3.4 KiB
Python
83 lines
3.4 KiB
Python
"""Trace engine execution on 2025-01-02 to find why first trade fires at 15:50
|
|
instead of 01:55 (signal trigger bar 01:50 has buy_signal=True).
|
|
|
|
Patches ScalperEngine._entry_allowed to log every call, plus dumps the
|
|
position state across the day.
|
|
"""
|
|
import sys
|
|
from pathlib import Path
|
|
PROJECT = Path(__file__).resolve().parent.parent
|
|
sys.path.insert(0, str(PROJECT))
|
|
|
|
import pandas as pd
|
|
|
|
from shared.core.engine import SizingInputs
|
|
from shared.data.loaders import load_bars
|
|
from strategies.gold_scalper_pro.instruments import XAUUSD_REAL
|
|
from strategies.gold_scalper_pro.scalper_engine import (
|
|
ScalperEngine,
|
|
ScalperConfig,
|
|
engine_kwargs_from_params,
|
|
)
|
|
from strategies.gold_scalper_pro.search_space import FROZEN_BASELINE, SEARCH_SPACE
|
|
from strategies.gold_scalper_pro.signals import build_signals
|
|
import optuna
|
|
from shared.optimizer.selector import select_diverse_topn
|
|
|
|
|
|
db = PROJECT / "studies" / "optuna" / "gold_scalper_pro_is2025.db"
|
|
study = optuna.load_study(
|
|
study_name="gold_scalper_pro_is2025",
|
|
storage=f"sqlite:///{db}",
|
|
)
|
|
finalists = select_diverse_topn(study, n=3, ranges=SEARCH_SPACE)
|
|
params = {**FROZEN_BASELINE, **finalists[0].params}
|
|
|
|
m5 = load_bars(PROJECT / "data" / "XAUUSD_M5_2024-06-26_2026-06-26.parquet")
|
|
m1 = load_bars(PROJECT / "data" / "XAUUSD_M1_2024-06-26_2026-06-26.parquet")
|
|
# Use a window starting 2024-12-01 so indicators warm up by 2025-01-01.
|
|
START = pd.Timestamp("2024-12-01 00:00:00")
|
|
END = pd.Timestamp("2025-01-03 00:00:00")
|
|
bars = m5[(m5["timestamp"] >= START) & (m5["timestamp"] < END)].reset_index(drop=True)
|
|
m1_bars = m1[(m1["timestamp"] >= START) & (m1["timestamp"] < END)].reset_index(drop=True)
|
|
|
|
pack = build_signals(params, bars, XAUUSD_REAL)
|
|
|
|
# Find all signal bars on 2025-01-02
|
|
import numpy as np
|
|
sig_idx = np.where(pack.signals_long | pack.signals_short)[0]
|
|
print(f"signal bars on 2024-12-01..2025-01-02: {len(sig_idx)}")
|
|
for i in sig_idx[-10:]:
|
|
t = bars["timestamp"].iloc[i]
|
|
sig_dir = "LONG" if pack.signals_long[i] else "SHORT"
|
|
sl = pack.sl_prices[i] if not np.isnan(pack.sl_prices[i]) else float("nan")
|
|
tp = pack.tp_prices[i] if not np.isnan(pack.tp_prices[i]) else float("nan")
|
|
print(f" bar {i} ts={t} sig={sig_dir} close={bars['close'].iloc[i]:.2f} "
|
|
f"sl_price={sl:.2f} tp_price={tp:.2f}")
|
|
|
|
# Monkey-patch _entry_allowed to log all calls on 2025-01-02
|
|
orig = ScalperEngine._entry_allowed
|
|
def traced(self, cfg, t, trades_today, last_trade_ts, i, sl, sh):
|
|
res = orig(self, cfg, t, trades_today, last_trade_ts, i, sl, sh)
|
|
if pd.Timestamp("2025-01-02 00:00:00") <= t <= pd.Timestamp("2025-01-02 23:59:59"):
|
|
if sl[i] or sh[i]:
|
|
print(f" _entry_allowed(bar={i}, ts={t}, long={sl[i]}, short={sh[i]}, "
|
|
f"trades_today={trades_today}, last={last_trade_ts}) → {res}")
|
|
return res
|
|
ScalperEngine._entry_allowed = traced
|
|
|
|
print("\n--- Running engine on 2024-12-01..2025-01-02 window ---")
|
|
engine = ScalperEngine()
|
|
result = engine.run(
|
|
bars, pack.signals_long, pack.signals_short,
|
|
pack.sl_prices, pack.tp_prices,
|
|
XAUUSD_REAL, SizingInputs(), 1000.0,
|
|
m1_bars=m1_bars,
|
|
**engine_kwargs_from_params(params),
|
|
)
|
|
print(f"\ntrades: {len(result.trades)}")
|
|
for tr in result.trades[:5]:
|
|
d = "LONG" if tr.direction.name == "LONG" else "SHRT"
|
|
print(f" {tr.entry_time} {d} entry={tr.entry_price:.2f} lots={tr.lots:.4f} "
|
|
f"pnl={tr.pnl:.4f} reason={tr.exit_reason}")
|