| { | |
| "features": { | |
| "ret_1": { | |
| "name": "Lag-1 Return (1-bar momentum)", | |
| "formula": "(close[t-1] - close[t-2]) / close[t-2]", | |
| "python": "df['close'].shift(1).pct_change()", | |
| "description": "Single bar percentage return, captures immediate price momentum for mean-reversion identification", | |
| "importance": 0.0493, | |
| "value_range": [-0.05, 0.05], | |
| "units": "fraction" | |
| }, | |
| "ret_3": { | |
| "name": "3-Bar Return", | |
| "formula": "(close[t-1] - close[t-4]) / close[t-4]", | |
| "python": "df['close'].shift(1) / df['close'].shift(4) - 1", | |
| "description": "Cumulative return over 3 bars, smooths single-bar noise and confirms trends", | |
| "importance": 0.0495, | |
| "value_range": [-0.10, 0.10], | |
| "units": "fraction" | |
| }, | |
| "ret_5": { | |
| "name": "5-Bar Return", | |
| "formula": "(close[t-1] - close[t-6]) / close[t-6]", | |
| "python": "df['close'].shift(1) / df['close'].shift(6) - 1", | |
| "description": "5-bar cumulative return identifies longer-term trends and market regime", | |
| "importance": 0.0496, | |
| "value_range": [-0.15, 0.15], | |
| "units": "fraction" | |
| }, | |
| "ret_accel": { | |
| "name": "Return Acceleration (2nd derivative of momentum)", | |
| "formula": "ret_1[t-1] - ret_1[t-2]", | |
| "python": "df['close'].shift(1).pct_change().diff()", | |
| "description": "Change in momentum, detects momentum reversals and trend shifts", | |
| "importance": 0.0499, | |
| "value_range": [-0.10, 0.10], | |
| "units": "fraction" | |
| }, | |
| "close_pos": { | |
| "name": "Close Position within 20-bar Range", | |
| "formula": "(close[t-1] - low_20) / (high_20 - low_20)", | |
| "python": "(df['close'].shift(1) - df['low'].shift(1).rolling(20).min()) / (df['high'].shift(1).rolling(20).max() - df['low'].shift(1).rolling(20).min())", | |
| "description": "Normalized price position: 0=at 20-bar low (oversold), 1=at 20-bar high (overbought), 0.5=neutral", | |
| "importance": 0.0482, | |
| "value_range": [0.0, 1.0], | |
| "units": "fraction" | |
| }, | |
| "vol_20": { | |
| "name": "20-Bar Volume Mean", | |
| "formula": "average(volume[t-21:t-1])", | |
| "python": "df['volume'].shift(1).rolling(20).mean()", | |
| "description": "Expected volume baseline normalized by market regime, used as denominator for volume signals", | |
| "importance": 0.0508, | |
| "value_range": [0, "variable"], | |
| "units": "contracts" | |
| }, | |
| "high_vol": { | |
| "name": "Volume Spike Detection", | |
| "formula": "volume[t-1] > vol_20 * 1.5", | |
| "python": "(df['volume'].shift(1) > df['volume'].shift(1).rolling(20).mean() * 1.5).astype(int)", | |
| "description": "Binary flag (0/1): volume above 1.5x average indicates institutional activity or volatility spike", | |
| "importance": 0.0474, | |
| "value_range": [0, 1], | |
| "units": "binary" | |
| }, | |
| "low_vol": { | |
| "name": "Volume Drought Detection", | |
| "formula": "volume[t-1] < vol_20 * 0.7", | |
| "python": "(df['volume'].shift(1) < df['volume'].shift(1).rolling(20).mean() * 0.7).astype(int)", | |
| "description": "Binary flag (0/1): volume below 0.7x average signals thin liquidity and potential gap risk", | |
| "importance": 0.0480, | |
| "value_range": [0, 1], | |
| "units": "binary" | |
| }, | |
| "rsi_oversold": { | |
| "name": "RSI < 30 (Oversold Condition)", | |
| "formula": "RSI = 100 - (100 / (1 + RS)), where RS = avg_gain / avg_loss (14-period)", | |
| "python": "rsi = 100 - (100 / (1 + gain / loss)); (rsi < 30).astype(int)", | |
| "description": "Binary flag (0/1): RSI below 30 indicates oversold condition, high probability bounce opportunity", | |
| "importance": 0.0507, | |
| "value_range": [0, 1], | |
| "units": "binary" | |
| }, | |
| "rsi_neutral": { | |
| "name": "RSI Neutral Zone (30 <= RSI <= 70)", | |
| "formula": "(30 <= RSI <= 70)", | |
| "python": "((rsi >= 30) & (rsi <= 70)).astype(int)", | |
| "description": "Binary flag (0/1): RSI in normal zone avoids extreme volatility conditions", | |
| "importance": 0.0514, | |
| "value_range": [0, 1], | |
| "units": "binary", | |
| "note": "Highest importance among all features!" | |
| }, | |
| "macd_positive": { | |
| "name": "MACD > 0 (Bullish Signal)", | |
| "formula": "MACD = EMA12 - EMA26 > 0", | |
| "python": "ema12 = df['close'].shift(1).ewm(span=12).mean(); ema26 = df['close'].shift(1).ewm(span=26).mean(); (ema12 - ema26 > 0).astype(int)", | |
| "description": "Binary flag (0/1): MACD positive indicates bullish trend, used for trend confirmation", | |
| "importance": 0.0477, | |
| "value_range": [0, 1], | |
| "units": "binary" | |
| }, | |
| "london_open": { | |
| "name": "London Session Open (8:00 UTC ±30 min)", | |
| "formula": "hour == 8 AND minute < 30", | |
| "python": "((df.index.hour == 8) & (df.index.minute < 30)).astype(int)", | |
| "description": "Binary flag (0/1): Marks London session open, highest daily volatility period with institutional flows", | |
| "importance": 0.0508, | |
| "value_range": [0, 1], | |
| "units": "binary" | |
| }, | |
| "london_close": { | |
| "name": "London Session Close (16:30 UTC ±30 min)", | |
| "formula": "hour == 16 AND minute >= 30", | |
| "python": "((df.index.hour == 16) & (df.index.minute >= 30)).astype(int)", | |
| "description": "Binary flag (0/1): Marks London session close, position unwinding and end-of-day volatility", | |
| "importance": 0.0470, | |
| "value_range": [0, 1], | |
| "units": "binary" | |
| }, | |
| "nyse_open": { | |
| "name": "NYSE Stock Market Open (13:30 UTC ±30 min)", | |
| "formula": "hour == 13 AND minute >= 30", | |
| "python": "((df.index.hour == 13) & (df.index.minute >= 30)).astype(int)", | |
| "description": "Binary flag (0/1): Marks US equity market open, crypto-equity correlation spike and derivative hedging flows", | |
| "importance": 0.0502, | |
| "value_range": [0, 1], | |
| "units": "binary" | |
| }, | |
| "hour": { | |
| "name": "Hour of Day (UTC)", | |
| "formula": "extract hour from timestamp", | |
| "python": "df.index.hour", | |
| "description": "Numeric (0-23): Captures intraday seasonality patterns in 24-hour crypto markets", | |
| "importance": 0.0491, | |
| "value_range": [0, 23], | |
| "units": "hour" | |
| }, | |
| "vwap_deviation": { | |
| "name": "VWAP Deviation (%)", | |
| "formula": "((close[t-1] - VWAP_20) / VWAP_20) * 100", | |
| "python": "((df['close'].shift(1) - df['vwap'].rolling(20).mean()) / df['vwap'].rolling(20).mean() * 100)", | |
| "description": "Percentage deviation from 20-bar VWAP, negative = oversold opportunity, price below fair value", | |
| "importance": 0.04, | |
| "value_range": [-5, 5], | |
| "units": "percent" | |
| }, | |
| "atr_stops": { | |
| "name": "Average True Range (14-period, 1.0x multiplier)", | |
| "formula": "ATR = SMA(TR, 14) where TR = max(H-L, |H-Cp|, |L-Cp|)", | |
| "python": "tr = max(high - low, abs(high - close.shift(1)), abs(low - close.shift(1))); atr = tr.rolling(14).mean() * 1.0", | |
| "description": "Dynamic stop-loss and take-profit sizing scaled by market volatility. Used as: SL = Entry - ATR, TP = Entry + ATR", | |
| "importance": 0.04, | |
| "value_range": [0, "variable"], | |
| "units": "price" | |
| } | |
| }, | |
| "notes": { | |
| "look_ahead_bias": "All features use .shift(1) ensuring only historical data (t-1 and earlier) is available at prediction time t", | |
| "normalization": "After computation, all features normalized to mean=0, std=1 using sklearn.preprocessing.StandardScaler", | |
| "missing_values": "Typically appear in first 50 rows due to rolling window requirements - drop before training", | |
| "feature_importance": "Values from Trial 244 XGBoost model, sum to ~1.0 (normalized)" | |
| } | |
| } | |