multiticker / core /models.py
Jitendra12421's picture
Upload folder using huggingface_hub
8fe2df2 verified
Raw
History Blame Contribute Delete
3.68 kB
"""
Model construction and training.
build_pipeline_map() -> dict of {ticker: (feature_type, fresh_model_clone)}
train_models() -> dict of {ticker: (feature_type, fitted_model)}
"""
import pandas as pd
from sklearn.ensemble import (
RandomForestClassifier,
HistGradientBoostingClassifier,
VotingClassifier,
)
from sklearn.linear_model import LogisticRegression
from sklearn.preprocessing import StandardScaler
from sklearn.pipeline import Pipeline
from sklearn.feature_selection import SelectKBest, f_classif
from sklearn.base import clone
from core.config import TICKERS, DATA_DIR, PIPELINE_MAP
from core.features import extract_semantic_features, extract_sequential_features
# ── Base model templates ─────────────────────────────────────────────────────
_RF = RandomForestClassifier(
random_state=42, n_estimators=300, max_depth=8,
min_samples_leaf=5, n_jobs=-1,
)
_GBM = HistGradientBoostingClassifier(
random_state=42, max_iter=300, l2_regularization=1.0, max_depth=8,
)
_ENSEMBLE = VotingClassifier(
estimators=[("rf", _RF), ("gbm", _GBM)], voting="soft",
)
_LR_PIPELINE = Pipeline([
("scaler", StandardScaler()),
("lr", LogisticRegression(C=0.1, max_iter=1000)),
])
_KBEST15_LR = Pipeline([
("scaler", StandardScaler()),
("kbest", SelectKBest(f_classif, k=15)),
("lr", LogisticRegression(C=0.1, max_iter=1000)),
])
_MODEL_TEMPLATES = {
"ensemble": _ENSEMBLE,
"lr_pipeline": _LR_PIPELINE,
"kbest15_lr": _KBEST15_LR,
}
# ── Public API ───────────────────────────────────────────────────────────────
def build_pipeline_map():
"""
Return a dict of {ticker: (feature_type, fresh_model_clone)}.
Uses PIPELINE_MAP from config to look up the architecture per ticker.
"""
result = {}
for ticker in TICKERS:
feat_type, model_key = PIPELINE_MAP[ticker]
result[ticker] = (feat_type, clone(_MODEL_TEMPLATES[model_key]))
return result
def train_models(log_fn=None):
"""
Load parquet data, extract features, and train all ticker models.
Parameters
----------
log_fn : callable(str), optional
Logging function (e.g. logger.info). Falls back to print.
Returns
-------
dict { ticker: (feature_type, fitted_model) }
"""
if log_fn is None:
log_fn = print
pipeline_map = build_pipeline_map()
models = {}
for ticker in TICKERS:
fpath = DATA_DIR / f"{ticker}_minute.parquet"
if not fpath.exists():
log_fn(f"[{ticker}] Parquet file not found: {fpath}")
continue
df = pd.read_parquet(fpath)
df["date"] = pd.to_datetime(df["date"])
df.set_index("date", inplace=True)
df.sort_index(inplace=True)
# Keep at most 300 trading days
unique_days = df.index.normalize().unique()
if len(unique_days) > 300:
df = df[df.index.normalize().isin(unique_days[-300:])]
feat_type, clf = pipeline_map[ticker]
if feat_type == "semantic":
X, y, _ = extract_semantic_features(df)
else:
X, y, _ = extract_sequential_features(df)
if X is None or X.empty:
log_fn(f"[{ticker}] Feature extraction returned empty!")
continue
clf.fit(X, y)
models[ticker] = (feat_type, clf)
log_fn(f"[{ticker}] Model trained ({feat_type}) | {len(X)} samples")
return models