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})