phase 7-8 完成 + warmup 修复 + 产物结构化重组
主要内容: - 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)
This commit is contained in:
@@ -0,0 +1,88 @@
|
||||
"""Diagnostic: print the ATR value Python computes at the first signal bar
|
||||
(2025-01-02 01:50) and derive what MT5's ATR must have been (from the observed
|
||||
0.16 lots). If they differ, the gap is in the bar data, not in the ATR math.
|
||||
|
||||
Also dump the OHLC of the M5 bars around 2025-01-02 01:50 so we can compare
|
||||
against what MT5 sees.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
import sys
|
||||
from pathlib import Path
|
||||
PROJECT = Path(__file__).resolve().parent.parent
|
||||
sys.path.insert(0, str(PROJECT))
|
||||
|
||||
import optuna
|
||||
import pandas as pd
|
||||
|
||||
from shared.data.loaders import load_bars
|
||||
from shared.indicators.base import atr
|
||||
from shared.optimizer.selector import select_diverse_topn
|
||||
from strategies.gold_scalper_pro.instruments import XAUUSD_REAL
|
||||
from strategies.gold_scalper_pro.search_space import FROZEN_BASELINE, SEARCH_SPACE
|
||||
|
||||
|
||||
def main() -> int:
|
||||
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)
|
||||
f1 = finalists[0]
|
||||
merged = {**FROZEN_BASELINE, **f1.params}
|
||||
atr_period = int(merged["InpAtrPeriod"])
|
||||
sl_mult = float(merged["InpAtrSLMult"])
|
||||
risk_pct = float(merged["InpRiskPercent"])
|
||||
init_deposit = 1000.0
|
||||
|
||||
print(f"finalist #1 atr_period={atr_period} sl_mult={sl_mult} risk={risk_pct}%")
|
||||
|
||||
full_m5 = load_bars(PROJECT / "data" / "XAUUSD_M5_2024-06-26_2026-06-26.parquet")
|
||||
close = full_m5["close"].to_numpy(dtype=float)
|
||||
high = full_m5["high"].to_numpy(dtype=float)
|
||||
low = full_m5["low"].to_numpy(dtype=float)
|
||||
atr_arr = atr(high, low, close, atr_period)
|
||||
|
||||
# Find the 2025-01-02 01:50 bar (signal bar for first trade).
|
||||
target = pd.Timestamp("2025-01-02 01:50:00")
|
||||
ts = pd.to_datetime(full_m5["timestamp"].to_numpy())
|
||||
idx = int(ts.searchsorted(target, side="left"))
|
||||
print(f"\n first-signal bar @ {ts[idx]} (idx {idx})")
|
||||
print(f" OHLC = O={full_m5['open'].iloc[idx]:.2f} H={full_m5['high'].iloc[idx]:.2f} "
|
||||
f"L={full_m5['low'].iloc[idx]:.2f} C={full_m5['close'].iloc[idx]:.2f} "
|
||||
f"spread={full_m5['spread'].iloc[idx]}")
|
||||
print(f" ATR({atr_period}) at this bar = {atr_arr[idx]:.6f}")
|
||||
print(f" sl_dist = {sl_mult} × ATR = {sl_mult * atr_arr[idx]:.6f}")
|
||||
print(f" loss_per_lot = sl_dist / tick_size × tick_value = "
|
||||
f"{sl_mult * atr_arr[idx] / XAUUSD_REAL.tick_size * XAUUSD_REAL.tick_value:.4f}")
|
||||
risk_money = init_deposit * risk_pct / 100.0
|
||||
sl_dist = sl_mult * atr_arr[idx]
|
||||
loss_per_lot = sl_dist / XAUUSD_REAL.tick_size * XAUUSD_REAL.tick_value
|
||||
lots = risk_money / loss_per_lot
|
||||
print(f" risk_money = ${risk_money:.4f}")
|
||||
print(f" Python computed lots = {lots:.6f} → rounded to {XAUUSD_REAL.round_volume(lots):.4f}")
|
||||
|
||||
# What would MT5's ATR have to be to produce 0.16 lots?
|
||||
mt5_lots = 0.16
|
||||
mt5_loss_per_lot = risk_money / mt5_lots
|
||||
mt5_sl_dist = mt5_loss_per_lot * XAUUSD_REAL.tick_size / XAUUSD_REAL.tick_value
|
||||
mt5_atr = mt5_sl_dist / sl_mult
|
||||
print(f"\n MT5 first trade: {mt5_lots} lots → sl_dist={mt5_sl_dist:.6f} → ATR={mt5_atr:.6f}")
|
||||
print(f" ratio Python/MT5 ATR = {atr_arr[idx] / mt5_atr:.4f} ({(atr_arr[idx]/mt5_atr - 1)*100:+.1f}%)")
|
||||
|
||||
# Dump 30 bars around the signal to inspect the recent volatility.
|
||||
print(f"\n last {atr_period + 5} bars before signal (for ATR warmup):")
|
||||
print(f" {'ts':<22} {'open':>9} {'high':>9} {'low':>9} {'close':>9} {'TR':>9}")
|
||||
for j in range(max(0, idx - atr_period - 5), idx + 1):
|
||||
tr = max(
|
||||
high[j] - low[j],
|
||||
abs(high[j] - close[j-1]) if j > 0 else high[j] - low[j],
|
||||
abs(low[j] - close[j-1]) if j > 0 else high[j] - low[j],
|
||||
)
|
||||
print(f" {str(ts[j]):<22} {full_m5['open'].iloc[j]:>9.2f} {full_m5['high'].iloc[j]:>9.2f} "
|
||||
f"{full_m5['low'].iloc[j]:>9.2f} {full_m5['close'].iloc[j]:>9.2f} {tr:>9.4f}")
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
Reference in New Issue
Block a user