Mt5pro-bot2/python/backtest/data.py

45 lines
2.1 KiB
Python

import numpy as np
import pandas as pd
def load_csv(path: str) -> pd.DataFrame:
"""CSV exporté de MT5 (Historique) ou générique: time/date, open, high, low, close."""
df = pd.read_csv(path, sep=None, engine="python")
df.columns = [c.strip().strip("<>").lower() for c in df.columns]
if "time" in df.columns and "date" in df.columns:
df["time"] = pd.to_datetime(df["date"].astype(str) + " " + df["time"].astype(str))
elif "date" in df.columns:
df["time"] = pd.to_datetime(df["date"])
else:
df["time"] = pd.to_datetime(df["time"])
df = df[["time", "open", "high", "low", "close"]].sort_values("time").drop_duplicates("time")
return df.reset_index(drop=True)
def from_mt5(symbol: str, tf: str, bars: int, cfg_account: dict) -> pd.DataFrame:
"""Télécharge l'historique depuis un terminal MT5 (Windows)."""
from core.connector import MT5
mt = MT5(cfg_account, 0, 0)
if not mt.connect():
raise SystemExit("Connexion MT5 impossible")
df = mt.rates(symbol, tf, bars)
mt.shutdown()
return df[["time", "open", "high", "low", "close"]].reset_index(drop=True)
def synthetic(bars: int = 12000, start_price: float = 2000.0, seed: int = 7, freq: str = "15min") -> pd.DataFrame:
"""Données FICTIVES (régimes tendance/range). Sert uniquement à tester le moteur."""
rng = np.random.default_rng(seed)
vol = np.zeros(bars); drift = np.zeros(bars)
v, d = 0.6, 0.0
for i in range(bars):
if i % 400 == 0:
d = rng.choice([-0.05, 0.0, 0.0, 0.05]) * start_price / 2000
v = rng.uniform(0.4, 1.2) * start_price / 2000
vol[i], drift[i] = v, d
ret = drift + vol * rng.standard_normal(bars)
close = start_price + np.cumsum(ret)
open_ = np.concatenate([[start_price], close[:-1]])
wick = np.abs(rng.standard_normal(bars)) * vol * 0.6
high = np.maximum(open_, close) + wick
low = np.minimum(open_, close) - np.abs(rng.standard_normal(bars)) * vol * 0.6
t = pd.date_range("2025-01-06", periods=bars * 2, freq=freq)
t = t[t.dayofweek < 5][:bars]
return pd.DataFrame({"time": t, "open": open_, "high": high, "low": low, "close": close})