src.core.feature_engine
π¦ 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/core/feature_engine.py. FeatureEngine turns a list of Candle objects into a fixed-length np.ndarray of numeric features: 40 always-on core features (indices 0β39) plus 17 experimental features (indices 40β56) that the FeatureLab can mask off at runtime.
Class attributes
CORE_NAMES: list[str]β 40 names for indices 0β39 (see table below).EXPERIMENTAL_NAMES: list[str]β 17 names for indices 40β56.NUM_CORE = 40,NUM_EXPERIMENTAL = 17.
Other modules address features by index; the load-bearing ones are:
| Index | Name | Used by |
|---|---|---|
| 6 | volatility (return std) | ExpirySelector.select() |
| 10 | ma_cross (SMA5 β SMA20) | alignment gate, fallback predictor |
| 12 | macd_hist | alignment gate, fallback predictor |
| 13 | rsi | ExpirySelector.select() |
| 14 | rsi_zone | alignment gate and fallback predictor read index 14 as βRSIβ β note this is actually the Β±1/0 overbought/oversold zone flag, while raw RSI is index 13 |
| 17 | atr | ExpirySelector.select() |
| 24 | adx | ExpirySelector.select() |
__init__(self)
Creates feature_mask β an np.ones(57) array where 1.0 = active, 0.0 = masked β and experimental_enabled = True (master switch). The FeatureLab only ever masks indices β₯ NUM_CORE; core features stay at 1.0.
compute(self, candles: list[Candle], window: int = 20) -> Optional[np.ndarray]
| Parameter | Type | Default | Meaning |
|---|---|---|---|
candles | list[Candle] | β | Chronological candles, newest last |
window | int | 20 | Rolling window length for windowed statistics |
Returns a float64 array of length 57, or None when len(candles) < max(window, 26) (26 candles are needed for the EMA-26/MACD). Callers must handle None and should also run np.nan_to_num on the result β both the bot and the trainer do, since divisions can still produce extreme values (guards use +1e-10 denominators).
Core features (indices 0β39)
In order: current body and range; 1-bar and 5-bar momentum; latest/mean return and return std (volatility); distances to SMA5/SMA10/SMA20; SMA5βSMA20 cross; MACD line (EMA12βEMA26), MACD histogram (vs EMA-9 signal); RSI(14) and RSI zone (+1 if >70, β1 if <30, else 0); Bollinger width and position (20, 2Ο); ATR(14) and current-range/ATR; Stochastic %K/%D(14,3) and their difference; CCI(20); Williams %R(14); simplified ADX(14) (actually the DX value, not smoothed); relative volume and volume std (neutral 1.0, 0.0 when all volumes are 0); doji/hammer/engulfing pattern codes; 25th/75th return percentiles, skewness, excess kurtosis; Higuchi fractal dimension of the last window closes; signed up/down close streak (capped at Β±10); and four cyclical time features (sin/cos of UTC hour-of-day and day-of-week from the last candleβs timestamp).
Experimental features (indices 40β56)
Shooting star flag; bearish engulfing flag; distance to SMA50 and above/below SMA50 flag (zeros if < 50 candles); 14/28 MA momentum ratio; four Fibonacci-level distances (23.6/38.2/50/61.8% of the 50-bar high-low range; zeros if < 50 candles); distance to window support and resistance; high/low and open/close ratios; RSI divergence flag (Β±1/0; recomputes RSI over the last 14 bars β the most expensive feature); volume spike ratio; wick/body ratio; body vs average body.
If experimental_enabled is False, the 17 slots are filled with zeros so the vector length never changes. Finally the vector is multiplied elementwise by feature_mask (only when lengths match), so masked features become exactly 0.0.
Side effects: none β pure computation, no logging.
Static indicator helpers
All private but useful when extending: _ema(data, span) / _ema_array(data, span) (recursive EMA, seeded from the first element; _ema returns the plain mean when len(data) < span), _rsi(closes, period=14) (returns 50.0 with insufficient data, 100.0 when there are no losses), _atr(highs, lows, closes, period=14) (true-range mean; falls back to mean highβlow), _stochastic(...) (returns (50.0, 50.0) with insufficient data), _cci(...) (0.0 fallback), _williams_r(...) (β50.0 fallback), _adx(...) (25.0 fallback), _doji/_hammer/_engulfing (pattern codes in {β1, 0, 1}), _skewness/_kurtosis (0.0 when std < 1e-10), _higuchi_fd(series, kmax=5) (Higuchi fractal dimension approximation; returns 1.5 when the series is too short or degenerate).
Adding a feature β dimension-change warning
Appending a feature changes the vector length. EnsemblePredictor.partial_fit() detects the mismatch and resets all models from scratch (models.md), and _reload_from_journal() in src/bot.py skips stored trades whose saved vectors have the old length. Add new features to EXPERIMENTAL_NAMES and the experimental block together, and expect to retrain.
Usage example
from src.core.feature_engine import FeatureEngine
engine = FeatureEngine()
feats = engine.compute(candles, window=20) # candles: list[Candle], len >= 26
if feats is not None:
print(len(feats)) # 57
print(dict(zip(engine.CORE_NAMES, feats[:5])))See also
- Feature engine concept
- feature-lab.md β runtime masking
- dataset.md β batch feature generation for training
π¬ Unsure how this interacts with the rest of the configuration? Ask in the Chipa Discord β or prototype strategies no-code with ChipaEditor.