Spaces:
Runtime error
Runtime error
File size: 2,505 Bytes
b717bee | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 | """Full V5 Feature Engineering — mirrors cleaned notebook Part A (pandas version)"""
import pandas as pd
import numpy as np
from ta.momentum import RSIIndicator # type: ignore
from ta.trend import MACD # type: ignore
def add_v5_features(df: pd.DataFrame) -> tuple[pd.DataFrame, list]:
df = df.copy()
if not isinstance(df.index, pd.DatetimeIndex):
df = df.set_index('timestamp').sort_index()
c, h, l, v, o = df['close'], df['high'], df['low'], df['volume'], df['open']
# === Core V5 blocks from notebook ===
for lag in [1, 2, 4, 6, 12, 24, 48, 168]:
df[f'return_{lag}h'] = c.pct_change(lag)
df['candle_body_ratio'] = (c - o) / (h - l + 1e-10)
df['range_pct'] = (h - l) / (c + 1e-10)
df['close_location_value'] = (c - l) / (h - l + 1e-10)
for w in [4, 12, 24, 48, 168]:
df[f'sma_{w}h'] = c.rolling(w).mean()
df[f'vol_{w}h'] = c.rolling(w).std()
df[f'vol_avg_{w}h'] = v.rolling(w).mean()
df[f'price_vs_sma_{w}h'] = c / df[f'sma_{w}h'] - 1
for period in [6, 14, 24]:
df[f'rsi_{period}h'] = RSIIndicator(c, window=period).rsi()
macd = MACD(c, window_slow=26, window_fast=12, window_sign=9)
df['macd_h'] = macd.macd()
df['macd_signal_h'] = macd.macd_signal()
df['macd_hist_h'] = macd.macd_diff()
df['vol_ratio_24h'] = v / (v.rolling(24).mean() + 1e-10)
df['vol_ratio_168h'] = v / (v.rolling(168).mean() + 1e-10)
# On-chain momentum
for col in ['tx_count', 'active_senders', 'active_receivers', 'total_eth_transferred', 'total_gas_used']:
if col in df.columns:
df[f'{col}_change_24h'] = df[col] / (df[col].shift(24) + 1e-10) - 1
df[f'{col}_ma24h'] = df[col].rolling(24).mean()
# Cyclical
df['hour_sin'] = np.sin(2 * np.pi * df.index.hour / 24) # type: ignore
df['hour_cos'] = np.cos(2 * np.pi * df.index.hour / 24) # type: ignore
df['dow_sin'] = np.sin(2 * np.pi * df.index.dayofweek / 7) # type: ignore
df['dow_cos'] = np.cos(2 * np.pi * df.index.dayofweek / 7) # type: ignore
# 30d regime features (used by filter & routing)
df['ret_30d'] = c.pct_change(30*24) # ≈30d on 1h bars
df['vol_30d'] = df['return'].rolling(30*24).std()
df = df.dropna()
feature_cols = [col for col in df.columns if col not in
{'open','high','low','close','volume','timestamp'}]
print(f"✅ Built {len(feature_cols)} V5 features (matches notebook Part A)")
return df, feature_cols |