src.training.trainer

πŸ¦‰ AthenaAI is an AI-powered ensemble machine-learning trading bot for PocketOption, built on BinaryOptionsToolsV2 β†’ Get it on GitLab
πŸ’¬ Need help? Join the Chipa Discord Β· ⚑ Go no-code with ChipaEditor

Source: src/training/trainer.py. The standalone trainer: trains the full ensemble (online SGD/PA/NB + batch GBM/RF + optional GPU MLP) on a historical CSV and saves a brain file the live bot loads at startup. Run via train.py (see the CLI reference); the package re-exports Trainer, TrainerConfig, and detect_device from src/training/__init__.py.

@dataclass TrainerConfig

FieldTypeDefaultMeaning
dataset_pathstr"EURUSD_M1.csv"Input candle CSV (--data)
brain_pathstr"athena_brain.pkl"Output brain file β€” matches main.py’s PO_BRAIN_PATH default (--out)
timeframeint60Seconds per candle (--timeframe)
expiryint300Trade duration to label for, seconds (--expiry)
feature_windowint20Rolling feature window in candles (--window)
lookbackint200Max candle history per feature vector (--lookback)
max_candlesint500_000Keep only the N most recent candles (--max-candles)
test_splitfloat0.30Walk-forward holdout fraction (--test-split)
online_batchint5000partial_fit chunk size (no CLI flag)
payoutfloat0.92Payout fraction used only for the breakeven-WR display (no CLI flag)
use_nnboolTrueTrain the neural model (--no-nn sets False)
force_cpuboolFalseSkip GPU detection (--cpu)
nn_epochsint30MLP epochs (--epochs)
nn_hiddentuple(128, 64)MLP hidden layer sizes (--hidden)
nn_batch_sizeint2048MLP mini-batch size (--batch-size)
nn_lrfloat1e-3MLP learning rate (--lr)

class Trainer

__init__(self, cfg: TrainerConfig)

Creates a fresh EnsemblePredictor and FeatureEngine, and resolves the training device via detect_device(force_cpu=cfg.force_cpu).

run(self) -> dict

The full pipeline. Returns the walk-forward metrics dict (see _walk_forward). Steps:

  1. Banner β€” logs dataset/brain paths and the device line (⚑ Training device: … or πŸ–₯ …).
  2. Load candles β€” load_candles(cfg.dataset_path). Fewer than 50 candles β†’ raise SystemExit("Dataset too small (N candles)."). More than max_candles β†’ keep the most recent.
  3. Build samples β€” label horizon = max(1, expiry // timeframe) candles; build_samples(...) produces (X, y) where y=1 means the close rose over the horizon (CALL wins). Fewer than 200 samples β†’ SystemExit.
  4. Chronological split β€” no shuffle (walk-forward): first 1 βˆ’ test_split for training, the rest held out.
  5. Online models β€” feed training samples to the ensemble in online_batch-sized chunks, calling ensemble.partial_fit() after each chunk (this also fits the scaler).
  6. Batch models β€” ensemble.train_batch_models() (GBM + RF; RF already uses all CPU cores).
  7. Neural model β€” _train_nn(...) unless use_nn is False.
  8. Walk-forward evaluation β€” _walk_forward(test_X, test_y).
  9. Save β€” creates the output directory (os.makedirs(..., exist_ok=True)), then ensemble.save_brain(cfg.brain_path) and logs βœ… Training complete β€” brain saved to <path>.

Note the trainer does not write the _expiry.pkl companion file β€” expiry stats are learned live only.

_train_nn(self, train_X, train_y, test_X, test_y) (internal)

Imports TorchMLPClassifier and torch; if PyTorch is missing, logs PyTorch not installed β€” skipping neural model (pip install torch for GPU training). and returns β€” training continues without the MLP.

Otherwise: builds the MLP with cfg.nn_hidden / nn_epochs / nn_batch_size / nn_lr on the detected device, fits it on scaler-transformed training data, and measures holdout accuracy (0.5 if the holdout is empty). The holdout accuracy becomes the model’s vote weight (accuracy_ema) in the ensemble. It then removes any existing "MLP" entry from ensemble._batch_models, appends {"name": "MLP", "clf": mlp, "accuracy_ema": acc}, and sets _batch_fitted = True. Because EnsemblePredictor.load_brain() rebuilds _batch_models from the saved list, the MLP survives the round-trip into the live bot, where it votes with weight acc Γ— 0.75 like the other batch models.

_walk_forward(self, test_X, test_y) -> dict (internal)

If the holdout has fewer than 100 samples, warns and returns {"samples": 0}. Otherwise predicts each holdout sample (direction only β€” confidence ignored; unlike the bot’s _load_dataset, no online learning during the test), counts wins/losses, and logs:

πŸ§ͺ WALK-FORWARD TEST (30% holdout): 41230 trades
   Win: 21876 | Loss: 19354 | HONEST WR: 53.1%
   βœ… EDGE: +1.0% above breakeven (52.1%)

Breakeven = 1 / (1 + payout) Γ— 100 with payout = 0.92 β†’ β‰ˆ 52.1%. Returns {"samples", "wins", "losses", "win_rate", "breakeven"} (win_rate and breakeven in percent).

Usage example

from src.training import Trainer, TrainerConfig

cfg = TrainerConfig(dataset_path="EURUSD_M1.csv", brain_path="athena_brain.pkl",
                    expiry=300, use_nn=True)
metrics = Trainer(cfg).run()
print(metrics["win_rate"], metrics["breakeven"])

Or from the shell: python train.py --data EURUSD_M1.csv --expiry 300 β€” see the training guide.

Risk note

A walk-forward win rate above breakeven on historical data does not guarantee live profitability. Binary options trading can lose money.

See also

πŸ’¬ Unsure how this interacts with the rest of the configuration? Ask in the Chipa Discord β€” or prototype strategies no-code with ChipaEditor.