| """ |
| ML-3m-trader Main Entry Point |
| ================================ |
| Unified CLI for the full ML trading pipeline. |
| |
| Usage: |
| python main.py fetch Fetch 1-year of 3m data from MetaTrader 5 |
| python main.py train Build features, generate labels, train model |
| python main.py backtest Run walk-forward backtest on test set |
| python main.py evaluate Print performance metrics report |
| python main.py run Full pipeline: fetch -> train -> backtest -> evaluate |
| python main.py predict Predict on latest data using saved model |
| """ |
|
|
| import argparse |
| import os |
| import sys |
| import time |
|
|
| import numpy as np |
| import pandas as pd |
|
|
| import config as cfg |
|
|
|
|
| def cmd_fetch(args): |
| """Fetch data from MetaTrader 5.""" |
| from data_fetcher import fetch_mt5, save_csv |
|
|
| print("\n--- FETCH DATA ---") |
| df = fetch_mt5() |
| save_csv(df) |
| print(f"[DONE] {len(df):,} bars saved.\n") |
|
|
|
|
| def cmd_train(args): |
| """Feature engineering + labeling + model training.""" |
| from data_fetcher import load_csv |
| from features import build_features |
| from labeler import generate_labels |
| from model import train as train_model, save_model |
|
|
| print("\n--- TRAIN ---") |
| t0 = time.time() |
|
|
| |
| df = load_csv() |
|
|
| |
| df = build_features(df) |
|
|
| |
| labels = generate_labels(df) |
| df["label"] = labels |
|
|
| |
| os.makedirs(cfg.DATA_DIR, exist_ok=True) |
| feat_path = os.path.join(cfg.DATA_DIR, "featured_data.csv") |
| df.to_csv(feat_path, index=False) |
| print(f"[INFO] Featured data saved to {feat_path}") |
|
|
| |
| model = train_model(df, labels) |
| save_model(model) |
|
|
| elapsed = time.time() - t0 |
| print(f"\n[DONE] Training complete in {elapsed:.1f}s\n") |
|
|
|
|
| def cmd_backtest(args): |
| """Run backtest on the test set using saved model.""" |
| from data_fetcher import load_csv |
| from features import build_features |
| from labeler import generate_labels |
| from model import load_model, predict |
| from backtester import run_backtest |
| from metrics import ( |
| compute_metrics, format_report, save_report, save_trades_csv, |
| ) |
|
|
| print("\n--- BACKTEST ---") |
| t0 = time.time() |
|
|
| |
| df = load_csv() |
| df = build_features(df) |
| labels = generate_labels(df) |
|
|
| |
| split_idx = int(len(df) * cfg.TRAIN_SPLIT_RATIO) |
| df_test = df.iloc[split_idx:].reset_index(drop=True) |
|
|
| |
| model = load_model() |
| preds = predict(model, df_test) |
|
|
| |
| results = run_backtest(df_test, preds) |
|
|
| |
| m = compute_metrics(results["trades"], results["equity_curve"]) |
| report = format_report(m) |
| print(report) |
| save_report(report) |
| save_trades_csv(results["trades"]) |
|
|
| elapsed = time.time() - t0 |
| print(f"[DONE] Backtest complete in {elapsed:.1f}s\n") |
|
|
|
|
| def cmd_evaluate(args): |
| """Re-print the saved report.""" |
| report_path = os.path.join(cfg.RESULTS_DIR, "report.txt") |
| if not os.path.exists(report_path): |
| print("[ERROR] No report found. Run 'python main.py backtest' first.") |
| sys.exit(1) |
| with open(report_path, "r", encoding="utf-8") as f: |
| print(f.read()) |
|
|
|
|
| def cmd_predict(args): |
| """Predict on latest data using saved model.""" |
| from data_fetcher import load_csv |
| from features import build_features |
| from model import load_model, predict_proba |
|
|
| print("\n--- PREDICT ---") |
| df = load_csv() |
| df = build_features(df) |
|
|
| model = load_model() |
| proba = predict_proba(model, df) |
|
|
| |
| last_n = min(10, len(df)) |
| print(f"\nLast {last_n} predictions (probability per class):") |
| print(f"{'Bar Time':<22} {'DO_NOTHING':>10} {'BUY':>10} {'SELL':>10} {'HOLD':>10}") |
| print("-" * 65) |
| for i in range(len(df) - last_n, len(df)): |
| t = df["time"].iloc[i] |
| p = proba[i] |
| cls = np.argmax(p) |
| print(f"{str(t):<22} {p[0]:>10.4f} {p[1]:>10.4f} {p[2]:>10.4f} {p[3]:>10.4f} -> {cfg.LABEL_NAMES[cls]}") |
| print() |
|
|
|
|
| def cmd_run(args): |
| """Full pipeline: fetch -> train -> backtest -> evaluate.""" |
| cmd_fetch(args) |
| cmd_train(args) |
| cmd_backtest(args) |
|
|
|
|
| def main(): |
| parser = argparse.ArgumentParser( |
| prog="ML-3m-trader", |
| description=( |
| "Machine learning trading system for XAUUSDc on the 3-minute timeframe.\n" |
| "Uses LightGBM for multi-class signal prediction with a vectorized backtester." |
| ), |
| formatter_class=argparse.RawDescriptionHelpFormatter, |
| epilog=( |
| "Examples:\n" |
| " python main.py fetch Fetch 1-year of 3m bars from MT5\n" |
| " python main.py train Feature engineering + label + train\n" |
| " python main.py backtest Backtest on test set with metrics\n" |
| " python main.py evaluate Re-print saved report\n" |
| " python main.py predict Show latest predictions\n" |
| " python main.py run Full pipeline (fetch->train->backtest)\n" |
| ), |
| ) |
|
|
| subparsers = parser.add_subparsers(dest="command", help="Available commands") |
|
|
| subparsers.add_parser("fetch", help="Fetch 1-year of 3m data from MetaTrader 5") |
| subparsers.add_parser("train", help="Build features, generate labels, train model") |
| subparsers.add_parser("backtest", help="Run walk-forward backtest on test set") |
| subparsers.add_parser("evaluate", help="Print saved performance report") |
| subparsers.add_parser("predict", help="Show predictions on latest data") |
| subparsers.add_parser("run", help="Full pipeline: fetch -> train -> backtest -> evaluate") |
|
|
| args = parser.parse_args() |
|
|
| if args.command is None: |
| parser.print_help() |
| sys.exit(0) |
|
|
| dispatch = { |
| "fetch": cmd_fetch, |
| "train": cmd_train, |
| "backtest": cmd_backtest, |
| "evaluate": cmd_evaluate, |
| "predict": cmd_predict, |
| "run": cmd_run, |
| } |
|
|
| dispatch[args.command](args) |
|
|
|
|
| if __name__ == "__main__": |
| main() |
|
|