Files

89 lines
4.0 KiB
Python
Raw Permalink Normal View History

"""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())