Forex CSV Backtesting in Python
A practical workflow for using XAUUSD and forex historical CSV data in Python without building a misleading backtest. The goal is not just loading candles. The goal is checking data quality, modeling cost, separating training and validation, then comparing results with MT5.
The Minimum Serious Python Workflow
Detect missing bars, duplicate timestamps, bad OHLC rows, spread outliers and symbol suffix differences.
Use candle range, ATR, spread, momentum, session, wick ratios and trend filters without future leakage.
Include spread, slippage, commission and realistic entry timing before judging any strategy.
Split history into development and unseen validation segments to reduce overfitting.
Copy-Paste Starter Backtest
This simple example tests a previous-candle breakout idea on CSV data. It is a template for structure, not a profitable strategy claim.
import pandas as pd
df = pd.read_csv("XAUUSDm_PERIOD_M30_OHLC.csv")
df["Timestamp"] = pd.to_datetime(df["Timestamp"])
df = df.sort_values("Timestamp").set_index("Timestamp")
df["prev_high"] = df["High"].shift(1)
df["prev_low"] = df["Low"].shift(1)
df["range"] = df["High"] - df["Low"]
df["signal"] = 0
df.loc[df["Close"] > df["prev_high"], "signal"] = 1
df.loc[df["Close"] < df["prev_low"], "signal"] = -1
spread_cost = df["Spread"].fillna(0) * 0.01
next_move = df["Close"].shift(-1) - df["Close"]
df["gross_pnl"] = df["signal"] * next_move
df["net_pnl"] = df["gross_pnl"] - spread_cost.abs()
sample = df.dropna()
train = sample.iloc[: int(len(sample) * 0.7)]
test = sample.iloc[int(len(sample) * 0.7):]
print("Train net:", train["net_pnl"].sum())
print("Test net:", test["net_pnl"].sum())
print("Signals:", int((sample["signal"] != 0).sum()))
Backtesting Mistakes That Kill Forex Systems
- Using current candle high/low to enter before that candle has closed.
- Optimizing parameters on the full dataset and then calling it validation.
- Ignoring spread on XAUUSD, GBPJPY, indices and high-volatility symbols.
- Testing with broker A data and expecting broker B execution to match perfectly.
- Training an ML classifier on future-derived labels that would not exist live.
- Judging by win rate only instead of profit factor, expectancy, max drawdown and trade count.
When to Move From Python to MT5
Python is excellent for research, scanning, feature discovery and data diagnostics. MT5 is where broker execution, order placement, stop-level rules, tick feed differences, spreads and terminal behavior become real. A serious workflow uses both: Python to discover and validate ideas, then MQL5 to implement the EA and compare Strategy Tester trades against the Python signal log.
Choose the next useful step
Most visitors arrive with one question: build, test, price, or trust. These shortcuts keep the path practical.