src.trading.feature_lab

🦉 AthenaAI is an AI-powered ensemble machine-learning trading bot for PocketOption, built on BinaryOptionsToolsV2Get it on GitLab
💬 Need help? Join the Chipa Discord · ⚡ Go no-code with ChipaEditor

Source: src/trading/feature_lab.py. FeatureLab watches which feature values differ between winning and losing trades and, on a periodic review, zeroes out experimental features that show no signal by writing into the FeatureEngine.feature_mask it was constructed with. Core features (indices 0–39) are never masked.

class FeatureLab

__init__(self, feature_engine: FeatureEngine, review_interval: int = 50)

ParameterTypeDefaultMeaning
feature_engineFeatureEngineThe live engine whose feature_mask will be mutated
review_intervalint50Run a review every N recorded trades (the bot uses 50)

State: running _win_sums / _loss_sums (np.zeros(57)), _win_count / _loss_count, _trade_count, and all_names = CORE_NAMES + EXPERIMENTAL_NAMES.

record_trade(self, features: np.ndarray, result: str) -> None

ParameterTypeMeaning
featuresnp.ndarrayThe trade’s entry feature vector (truncated to 57 dims if longer)
resultstr"win" or "loss" — anything else is ignored for the sums but still increments the trade counter

Adds the vector to the appropriate running sum. Every review_interval calls, runs _review(). Fed by _result_checker() for live trades and by _reload_from_journal() for historical ones (only when the stored vector’s length matches the current engine’s 57 dims).

_review(self) (internal)

Skipped until there are at least 20 wins and 20 losses. Then:

  1. Computes win_avg and loss_avg per feature and importance = |win_avg − loss_avg|. (The source comment mentions dividing by std, but the code uses the raw absolute difference — the documented behavior here follows the code. Because features aren’t normalised first, large-scale features naturally dominate this ranking.)
  2. Logs the top 5 most predictive features (with a ↑WIN/↑LOSS direction marker) and the bottom 5 least predictive.
  3. For each experimental index (≥ 40): importance < 1e-6feature_mask[i] = 0.0 (masked); otherwise reset to 1.0 (a previously masked feature can be reinstated).
  4. Logs 🧪 Experimental features: N active, M masked.

Side effects: mutates feature_engine.feature_mask in place — every subsequent FeatureEngine.compute() returns 0.0 in masked slots — and writes a multi-line log block starting 🔬 Feature Lab Review (after N trades):.

The mask is not persisted; it is rebuilt from journal history on restart.

get_report(self) -> str

Short status like "features: 40+15/17exp" (core + active experimental / total experimental).

Usage example

from src.core.feature_engine import FeatureEngine
from src.trading.feature_lab import FeatureLab

engine = FeatureEngine()
lab = FeatureLab(engine, review_interval=50)
lab.record_trade(features, "win")   # repeat per resolved trade
print(lab.get_report())

See also

💬 Unsure how this interacts with the rest of the configuration? Ask in the Chipa Discord — or prototype strategies no-code with ChipaEditor.