Files
mymt5opp/scripts/query_xauusd_spec.py
T
2026-06-26 20:50:07 +08:00

111 lines
4.5 KiB
Python

"""Query XAUUSD symbol spec from MT5 and dump it as an InstrumentConfig sketch.
Run with the venv python. Uses the MetaTrader5 package (Topology A) to read
the symbol specification (digits, point, tick value, contract size, volume
steps) — these come from the broker, not guesses (doc 05 §1). Also downloads
a short M5 history window for the first validation pass (doc 03 §8).
IPC-timeout workarounds (Stack Overflow #66492735):
- Use forward slashes in the terminal path (backslashes trigger -10005).
- Split initialize(path) and login() into two steps (one-shot initialize with
login/password/server is fragile).
- Allow reusing an already-running terminal instance (same path = same IPC).
"""
from __future__ import annotations
import sys
import time
from pathlib import Path
# Make the project importable when run as a script.
PROJECT = Path(__file__).resolve().parent.parent
sys.path.insert(0, str(PROJECT))
from shared.config import get_secret, load_env
load_env(PROJECT)
import MetaTrader5 as mt5 # type: ignore
import pandas as pd
# Forward slashes — backslashes in this path trigger IPC timeout (-10005).
TERMINAL = "C:/Program Files/MetaTrader 5 IC Markets Global/terminal64.exe"
SYMBOL = "XAUUSD"
def connect(retries: int = 3, sleep_s: float = 5.0) -> bool:
"""Connect in two steps: initialize() → login(login,password,server).
IMPORTANT: call initialize() with NO path argument. Passing a path makes
the package spawn a NEW headless terminal at that path, which then sits
waiting for an interactive login it can never complete (IPC timeout -10005).
Calling initialize() with no args CONNECTS to the already-running terminal
(the one with the UI you logged into manually).
"""
for attempt in range(1, retries + 1):
# Step 1: connect to the running terminal (no path → reuse existing).
if not mt5.initialize():
err = mt5.last_error()
print(f" initialize() attempt {attempt}/{retries} failed: {err}")
time.sleep(sleep_s)
continue
# Step 2: explicit login with the demo account (re-auth is safe).
login = int(get_secret("MT5_DEMO_LOGIN") or 0)
password = get_secret("MT5_DEMO_PASSWORD")
server = get_secret("MT5_DEMO_SERVER")
if not mt5.login(login, password=password, server=server):
err = mt5.last_error()
print(f" login() attempt {attempt}/{retries} failed: {err}")
mt5.shutdown()
time.sleep(sleep_s)
continue
print(f" connected: login={login} server={server}")
return True
return False
def main() -> int:
if not connect(retries=5, sleep_s=10.0):
print("could not connect to MT5 after retries")
print("hint: confirm the demo account logs in manually in the terminal first;")
print(" if it does, the IPC issue is path/instance related, not account.")
return 1
try:
info = mt5.symbol_info(SYMBOL)
if info is None:
print(f"symbol_info({SYMBOL}) returned None — is the symbol in Market Watch?")
return 2
print(f"=== {SYMBOL} specification (IC Markets) ===")
fields = [
"name", "digits", "point", "trade_tick_size", "trade_tick_value",
"trade_contract_size", "volume_min", "volume_step", "volume_max",
"spread", "trade_stops_level", "swap_mode", "swap_long", "swap_short",
"swap_rollover3days",
]
for f in fields:
print(f" {f:24s} = {getattr(info, f, '<n/a>')}")
# Triple-swap weekday: MT5 swap_rollover3days is 0=Mon..6=Sun.
print("\n=== short M5 history probe (last 5 bars) ===")
rates = mt5.copy_rates_from_pos(SYMBOL, mt5.TIMEFRAME_M5, 0, 5)
if rates is None or len(rates) == 0:
print(" no rates returned")
else:
df = pd.DataFrame(rates)
df["timestamp"] = pd.to_datetime(df["time"], unit="s")
print(df[["timestamp", "open", "high", "low", "close", "spread"]].to_string(index=False))
print("\n=== available history depth (count bars in last 2 years) ===")
from datetime import datetime, timedelta
end = datetime.now()
start = end - timedelta(days=730)
n = mt5.copy_rates_range(SYMBOL, mt5.TIMEFRAME_M5, start, end)
print(f" M5 bars {start.date()}{end.date()}: {0 if n is None else len(n)}")
return 0
finally:
mt5.shutdown()
if __name__ == "__main__":
raise SystemExit(main())