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

81 lines
2.8 KiB
Python

"""Download XAUUSD M1 history to Parquet for tick-level simulation.
M1 bars are the finest granularity MT5 exposes via copy_rates_range. We use
each M1 bar's OHLC as 4 synthetic ticks (open→high→low→close for longs,
open→low→high→close for shorts) to drive BE/trailing precisely inside
each M5 bar.
Downloads the same 2-year window as the M5 file so the two align.
"""
from __future__ import annotations
import sys
import time
from datetime import datetime, timedelta
from pathlib import Path
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
SYMBOL = "XAUUSD"
TIMEFRAME = "M1"
START = (datetime.now() - timedelta(days=730)).strftime("%Y-%m-%d")
END = datetime.now().strftime("%Y-%m-%d")
OUT = PROJECT / "data" / f"{SYMBOL}_{TIMEFRAME}_{START}_{END}.parquet"
def connect(retries: int = 5, sleep_s: float = 5.0) -> bool:
for attempt in range(1, retries + 1):
if not mt5.initialize():
print(f" initialize() attempt {attempt}/{retries} failed: {mt5.last_error()}")
time.sleep(sleep_s)
continue
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):
print(f" login() attempt {attempt}/{retries} failed: {mt5.last_error()}")
mt5.shutdown()
time.sleep(sleep_s)
continue
print(f" connected: login={login} server={server}")
return True
return False
def main() -> int:
if not connect():
print("could not connect — is the terminal running and logged in?")
return 1
try:
tf = getattr(mt5, f"TIMEFRAME_{TIMEFRAME}")
print(f"downloading {SYMBOL} {TIMEFRAME} {START}{END} ...")
rates = mt5.copy_rates_range(
SYMBOL, tf, pd.Timestamp(START), pd.Timestamp(END)
)
if rates is None or len(rates) == 0:
print(f" no bars returned: {mt5.last_error()}")
return 2
df = pd.DataFrame(rates)
df["timestamp"] = pd.to_datetime(df["time"], unit="s", utc=False)
df = df[["timestamp", "open", "high", "low", "close", "spread"]]
df = df.sort_values("timestamp").reset_index(drop=True)
df = df.drop_duplicates(subset=["timestamp"]).reset_index(drop=True)
OUT.parent.mkdir(parents=True, exist_ok=True)
df.to_parquet(OUT, index=False)
print(f"saved {len(df):,} bars → {OUT.relative_to(PROJECT)}")
print(f"range: {df['timestamp'].iloc[0]}{df['timestamp'].iloc[-1]}")
return 0
finally:
mt5.shutdown()
if __name__ == "__main__":
raise SystemExit(main())