C.G.

From Time Series to Product

A time series does not become a product just because you trained a model. It becomes one when the data is clean, the validation does not cheat, the service answers on time and someone can tell when it stops working. This guide walks the whole path, using TradeScope AI as the case study.

What a time series is and why intuition fails

A time series is a sequence of observations ordered in time. Unlike a traditional table, order matters: each row depends on the previous ones and the future cannot be used to explain the past. A financial series usually combines trend, seasonality, cycles, noise and regime changes, and the signal-to-noise ratio is low.

Intuition fails for two reasons. First, a model can look excellent on history and fail on the next window. Second, mean error hides the moments that matter most: sharp changes. That is why design starts with the decision the forecast must support, not with the architecture.

Define the problem before choosing a model

Before writing code, answer what is being predicted, over which horizon and what a mistake costs. Forecasting tomorrow's price for an alert is not the same as estimating next week's demand to buy inventory. The horizon changes the features, the metric and even the retraining cadence.

Define a baseline too. Last-value persistence is a cheap and honest reference: if the model does not beat it consistently, there is no product. In TradeScope AI the goal was a stable forecast for a decision, not a benchmark win in isolation.

Data: the part that decides the result

Most of the work happens before training. Fix a frequency, align the series, review gaps and outliers, and document how they are filled. A value imputed with the future is a leak; one imputed with the historical mean can be acceptable if that mean only uses the past.

Normalization is fitted only on the training slice and reused for validation and test. It is easy to forget and one of the most common ways to contaminate an experiment. The same applies to exogenous variables: if a variable is not available at prediction time, it cannot enter the model.

Temporal validation: how not to fool yourself

Shuffling rows before splitting the dataset is the classic mistake. In a time series it means training on the future and evaluating on the past. The alternative is walk-forward validation: train on one block, predict the next, advance the window and repeat. You can also use expanding windows or hold out a final block that is never touched until the definitive evaluation.

Besides MAE and RMSE, look at directional accuracy and the error distribution per window. A model with a slightly worse mean error but much better stability is often better for a real decision. If the system generates trades, include costs and execution delay in the evaluation; a theoretical hit that arrives late is not a hit.

Model families and when to use each

FamilyStrengthsLimitsWhen to use it
Naive baselineTrivial and explainableCaptures no structureAlways, as a reference
ARIMA / SARIMAXInterpretable, fast, intervalsLinear relationship, hard with many seriesStable univariate series
ProphetSeasonality and holidays, easy to fitLess precise at high frequencyBusiness data with clear seasonality
LSTMLocal dependencies and long sequencesTraining cost, low transparencyNon-linear patterns with enough data
TransformerLong-range relationshipsMore data and computeDistant events and multivariate series
EnsembleReduces variance and biasMore infrastructure and maintenanceProduction with stability requirements

Start simple and move up only when evidence justifies it. A well-validated ARIMA can be enough for a clean series; an ensemble makes sense when several families capture different patterns and the maintenance cost is justified.

The LSTM + Transformer ensemble

The LSTM captures local, short-term dependencies; the Transformer models long-range relationships between distant events. Combining both reduces the bias of a single family and stabilizes predictions. The combination is not a blind average: each branch gets a weight depending on the window and the regime, and the system records its contribution so the result can be explained.

Training runs in PyTorch with sliding windows, a fixed seed and a strict temporal split between train and test. I do not shuffle rows or mix the dataset. I also keep the model and the preprocessor together: serving a different normalization than the one used in training is a silent source of bugs.

From notebook to service

A model that only lives in Jupyter is not a product. The backend is built with FastAPI and exposes predictions over WebSocket; the dashboard updates without reloading and shows the history next to the forecast. I chose WebSocket because the panel needs several updates per minute and opening new connections was more expensive. For a daily forecast, a REST API would be enough.

The model loads once at startup, stays in memory and is served through an explicit input/output contract. If it fails, the service returns the last valid forecast and logs the error instead of breaking the interface. That last mile —contract, latency and recovery— is part of the product, not an infrastructure detail.

Infrastructure and operations

Everything runs in Docker containers on a self-managed Linux VPS. Deployment includes environment variables for secrets, volumes for data and a Cloudflare tunnel to expose the service without opening ports. Operations are part of the product: contextual logs, healthchecks, automatic restarts and an alert when the data stream stops.

Without that vigilance, the dashboard looks fine until someone notices a chart with data from three days ago. An empty panel is obvious; one with stale data is misleading.

Reproducibility and metrics that matter

A result you cannot repeat is not a result. I fix the seed, pin library versions, store the experiment configuration next to the model and record which dataset was used. That lets me compare two runs without relying on memory. I also record MAE, RMSE and directional accuracy per window, and compare the distribution, not just the average.

Service performance counts: I measure endpoint response time and the share of forecasts served from cache. If the model takes longer than the decision window, accuracy is irrelevant.

Monitoring and drift

A model does not degrade only because of a bug; it degrades because the world changes. I track input distribution, recent error and the rate of out-of-range predictions. When one of those signals leaves its band for several windows, it triggers a review.

I do not retrain automatically on every alert. First I distinguish a real change from broken data; then I decide whether to retrain, recalibrate or just fix ingestion. That distinction prevents models that chase noise.

Finally, I keep a simple dashboard with four signals: recent error, input drift, prediction range and service latency. If any of them is outside its band, the model is not necessarily wrong, but it deserves a look. The goal is not a perfect score but a forecast the team can trust enough to act on.

Checklist for taking a model to production

  • Baseline defined and beaten with the same validation.
  • Strict temporal split with no shuffling.
  • Preprocessor fitted on train only and saved with the model.
  • Documented input/output contract.
  • Fallback when the model or data fails.
  • Healthcheck and stalled-data alert.
  • Contextual logs and model version.
  • Latency measured against the decision window.
  • Reproducible seed, versions and configuration.
  • Retraining plan and rollback criteria.

Common mistakes

  • Shuffling the series before splitting it: future leaks into the past.
  • Optimizing only mean error: the model becomes conservative during regime changes.
  • Measuring the model in the notebook but not the service latency.
  • Shipping without a stalled-data alert.
  • Comparing models with different validations.
  • Ignoring decision cost and execution delay.

Frequently asked questions

Do I need deep learning for a time series?

No. Start with a baseline and a well-validated statistical model. Deep learning helps when there is enough data, non-linear relationships and several related series; otherwise it adds complexity without a guaranteed gain.

How much data do I need?

It depends on the signal and the horizon, not just the number of rows. Little data favors simple models; many noisy series are not fixed with more parameters. Walk-forward validation will tell you whether the model generalizes.

How do I avoid leaking future information?

Split by time, never at random. Fit normalization and any transformation only on the past. Check that every exogenous variable is available at prediction time.

When should I retrain?

When error or data distribution changes persistently. Combine a schedule with drift triggers; retraining daily without evidence only adds operational risk.

Further reading

The code and architecture are in TradeScope AI. If you are building something similar, the order that worked for me was: data, validation, baseline, model and only then interface. The infrastructure side is in Docker for Developers, and if you want to discuss the approach you can write to me from the contact page.

← Back