{ "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)" } }