Spaces:
Running
Running
| import pandas as pd | |
| import numpy as np | |
| from pathlib import Path | |
| def compute_zscore(series: pd.Series, period=252): | |
| mean = series.rolling(period).mean() | |
| std = series.rolling(period).std() | |
| return (series - mean) / (std + 1e-9) | |
| def compute_percentile(series: pd.Series, period=252): | |
| return series.rolling(period).apply( | |
| lambda x: (x <= x.iloc[-1]).mean(), | |
| raw=False, | |
| ) | |
| def build_vix_store_features(vix_df: pd.Series): | |
| df = vix_df.sort_index().copy() | |
| df["vix_return_1d"] = df["close"].pct_change(1) | |
| df["vix_return_5d"] = df["close"].pct_change(5) | |
| df["vix_return_20d"] = df["close"].pct_change(20) | |
| df["vix_ma20"] = df["close"].rolling(20).mean() | |
| df["vix_volatility"] = df["vix_return_1d"].rolling(20).std() | |
| df["vix_zscore"] = compute_zscore(df["close"]) | |
| df["vix_percentile"] = compute_percentile(df["close"]) | |
| df["high_vol_regime"] = (df["vix_zscore"] > 1).astype("int8") | |
| df["low_vol_regime"] = (df["vix_zscore"] < -1).astype("int8") | |
| df["extreme_fear"] = (df["vix_zscore"] > 2).astype("int8") | |
| df["extreme_calm"] = (df["vix_zscore"] < -2).astype("int8") | |
| return df | |
| def clean_nifty(df): | |
| """ | |
| Clean NIFTY OHLCV data before feature engineering. | |
| Expected columns: | |
| timestamp, open, high, low, close, volume | |
| """ | |
| original_len = len(df) | |
| # Ensure timestamp is datetime | |
| df["timestamp"] = pd.to_datetime(df["timestamp"]) | |
| # Sort chronologically | |
| df = df.sort_values("timestamp").reset_index(drop=True) | |
| # ββ Layer 1: Drop zero/negative prices βββββββββββββββββββ | |
| price_cols = ["open", "high", "low", "close"] | |
| zero_mask = (df[price_cols] <= 0).any(axis=1) | |
| print(f"Dropped {zero_mask.sum()} rows with zero/negative prices") | |
| df = df.loc[~zero_mask] | |
| # ββ Layer 2: Validate OHLC relationships ββββββββββββββββ | |
| invalid_ohlc = ( | |
| (df["high"] < df["low"]) | |
| | (df["high"] < df["open"]) | |
| | (df["high"] < df["close"]) | |
| | (df["low"] > df["open"]) | |
| | (df["low"] > df["close"]) | |
| ) | |
| print(f"Dropped {invalid_ohlc.sum()} rows with invalid OHLC relationships") | |
| df = df.loc[~invalid_ohlc] | |
| # ββ Layer 3: Remove duplicate timestamps ββββββββββββββββ | |
| # duplicate_mask = df.duplicated(subset=["timestamp"], keep="last") | |
| # print(f"Dropped {duplicate_mask.sum()} duplicate timestamps") | |
| # df = df.loc[~duplicate_mask] | |
| # ββ Layer 4: Remove rows with missing OHLC values βββββββ | |
| nan_mask = df[["open", "high", "low", "close"]].isna().any(axis=1) | |
| print(f"Dropped {nan_mask.sum()} rows with missing OHLC values") | |
| df = df.loc[~nan_mask] | |
| df = df.reset_index(drop=True) | |
| print( | |
| f"\nTotal rows: {original_len:,} β {len(df):,} " | |
| f"({original_len - len(df):,} removed)" | |
| ) | |
| return df | |
| def sanity_check(df): | |
| print(f"Rows: {len(df):,}") | |
| print(f"Symbols: {df['symbol'].nunique()}") | |
| print(f"Date range: {df.index.min()} β {df.index.max()}") | |
| print(f"Null counts:\n{df[['open','high','low','close','volume']].isnull().sum()}") | |
| print(f"Min close: {df['close'].min()}") | |
| print(f"Any zero close: {(df['close'] <= 0).any()}") | |
| def identify_bad_df(df): | |
| bad = (df["close"] <= 0) | (df["close"].shift(1) <= 0) | |
| print(df.loc[bad, ["volume", "open", "high", "low", "close"]]) | |
| # input path for OHLCV | |
| INPUT_PATH = Path( | |
| "H:/Developer/stock_model/Dataset/Processed_dataset/feature_stores/vix_store.parquet" | |
| ) | |
| # output path | |
| OUTPUT_PATH = Path( | |
| "H:/Developer/stock_model/Dataset/Processed_dataset/feature_stores/vix_feature_store.parquet" | |
| ) | |
| def start_save_feature_store(): | |
| ohlcv_df = pd.read_parquet(INPUT_PATH) | |
| clean_df = clean_nifty(ohlcv_df) | |
| identify_bad_df(clean_df) | |
| nifty_feature_store = build_vix_store_features(clean_df) | |
| nifty_feature_store = pd.concat([nifty_feature_store], ignore_index=True) | |
| # save the new store | |
| # Ensure destination tracking directory paths exist natively | |
| OUTPUT_PATH.parent.mkdir(parents=True, exist_ok=True) | |
| # Export out to structural Parquet architecture | |
| nifty_feature_store.to_parquet(OUTPUT_PATH, index=False) | |
| print(f"\nβ Success! Nifty Feature Store created at: {OUTPUT_PATH}") | |
| print(f"Total rows recorded: {len(nifty_feature_store)}") | |
| print( | |
| f"Timeline Range: {nifty_feature_store['timestamp'].min().strftime('%Y-%m-%d')} to {nifty_feature_store['timestamp'].max().strftime('%Y-%m-%d')}" | |
| ) | |
| if __name__ == "__main__": | |
| start_save_feature_store() | |