src.trading.feature_lab
🦉 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/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)
| Parameter | Type | Default | Meaning |
|---|---|---|---|
feature_engine | FeatureEngine | — | The live engine whose feature_mask will be mutated |
review_interval | int | 50 | Run 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
| Parameter | Type | Meaning |
|---|---|---|
features | np.ndarray | The trade’s entry feature vector (truncated to 57 dims if longer) |
result | str | "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:
- Computes
win_avgandloss_avgper 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.) - Logs the top 5 most predictive features (with a
↑WIN/↑LOSSdirection marker) and the bottom 5 least predictive. - For each experimental index (≥ 40): importance <
1e-6→feature_mask[i] = 0.0(masked); otherwise reset to1.0(a previously masked feature can be reinstated). - 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
- Feature lab concept
- feature-engine.md — mask semantics
💬 Unsure how this interacts with the rest of the configuration? Ask in the Chipa Discord — or prototype strategies no-code with ChipaEditor.