Files
mymt5opp/scripts/diag_atr_check.py
gavindiaz 63a829cc46 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)
2026-06-27 00:28:07 +08:00

89 lines
4.0 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""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())