sbasu2512's picture
intertwine the services
57384dd
Raw
History Blame Contribute Delete
4.8 kB
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()