End-to-End Stock Prediction (LSTM & Transformer) — live demo

A research notebook turned into a self-retraining web service. Dual-head Transformer (direction probability + return %) plus an XGBoost baseline, evaluated against a naive_always_up baseline via a pre-declared honesty gate. Trained on ~8,800 daily bars per ticker (35 years of OHLCV) for MSFT and the S&P 500, with daily prediction logging, weekly atomic-swap retraining, and mtime-based hot reload.

← Home LinkedIn Notebook View on GitHub
About this project

This started as a research notebook comparing LSTM and Transformer architectures on Microsoft stock — a typical "trained a model on stock prices, plotted some charts" Jupyter artifact (preserved verbatim in research/). I then refactored it into a production-shaped commercial demo: a dual-head Transformer (direction probability + return %) and an XGBoost baseline, a FastAPI backend with mtime hot-reload, this static HTML dashboard, daily prediction logging, and a weekly retraining loop that atomically swaps the production artifact via tmp + fsync + os.replace.

The notebook had a few classic research-mode shortcuts: a normalizer fit on the full dataset (data leakage), a denormalization bug at lines 1634–1636, and one ticker only. The production version fixes the leakage (train-only fit, applied to val/test/inference), sidesteps the denormalization bug by predicting return percentage instead of absolute price, and ships two tickers (MSFT + S&P 500) via config blocks. A pre-declared honesty gate in the bake-off says the production model must beat naive_always_up by ≥3 pp on direction accuracy to count as real signal — neither winner does, on either ticker, and the dashboard shows the failure verdict in red below.

Training bars per ticker: ~8,800 Holdout days: 252 Transformer params: 87k MSFT dir acc: 0.524 (naive 0.524) SPX dir acc: 0.571 (naive 0.571) SPX return MAE: 0.59% Honesty gate: FAIL on both

The point of this project is the productionization, not the predictive accuracy. The model honestly reports it cannot extract next-day directional signal from this feature set; the system around it (fetch → cache → train → bake-off → promote → serve → log → backfill → retrain) is real, atomic, idempotent, and would immediately surface any future feature engineering that did move the gate.

Tech stack: TensorFlow / Keras 3 · XGBoost · scikit-learn · FastAPI · pydantic v2 · yfinance · pandas · pyarrow · vanilla HTML/JS (no framework, no CDN). Full source, plans, and journey writeup in the GitHub repository — see README.md, PLAN.md, LEARNING_NOTES.md, and docs/journey.md.

Disclaimer: Predictions are informational only and are not financial advice. The honesty gate explicitly says the directional signal is not extractable from this feature set on a 1-day horizon — treat displayed predictions accordingly.

Tomorrow's prediction

Loading…

Holdout performance (last 252 trading days)

Honest evaluation on data the model never saw during training.

Recent predictions (last 30 days)

Logged daily by tools/log_prediction.py. realized_* columns backfill on the day after each prediction.