TokSeq documentation/Models

Features and models

The feature families, the model classes that were tried, how ensembles are built, how probabilities are calibrated and how uncertainty is reported.

Feature families

Features are organized into named blocks so that a hypothesis declares which blocks it consumes and the search space over feature sets is explicit rather than accidental. Roughly twenty-five blocks span about a hundred and fifty columns.

Two disciplines apply to all of them. Every feature is past-only: a bar at time t sees nothing after t, and only closed bars are used. Every threshold inside a feature is a causal rolling quantile of the feature's own distribution, not a constant tuned once on the whole history.

Model classes tried

The search was not restricted to one family. What was executed, in rough order of complexity:

An unknown architecture name is a hard error. It is never silently downgraded to the baseline, which is a specific defect the platform found in its own history: results once attributed to a tree ensemble had in fact been produced by logistic regression because the dispatch branch did not exist. Those results were withdrawn and the audit that found it is documented.

Ensembles

Five aggregation methods were implemented and compared: mean, performance-weighted mean, majority vote, regime routing, and a trained stacking combiner over out-of-sample member probabilities plus the regime state.

The measured result is unambiguous and it is the reason the live system looks the way it does: only the trained stacking combiner works. Averaging, voting and regime routing are dead. Every member of the live registry is a stack.

Two further ensemble results are worth stating because they are counterintuitive:

A published-looking claim that a stacked combiner beats voting collapsed under a fair stratification: the effect measured on a biased stratum was five times its unbiased size, and the unbiased comparison was not significant.

Live aggregation

The aggregation across committee members in the live engine is deterministic. There is no learning in the live path, and a trainable orchestrator is admissible only as a pre-registered research stage.

Freshness is checked first – member signatures older than their bound are dropped. Surviving probabilities are mapped through a per-committee calibration map; a member without a map is used with halved confidence rather than trusted. Weights come from live reliability tracking with a maturity guard, so an immature member carries neutral weight, and a floor prevents any member from being weighted out entirely. The aggregate is a reliability-weighted median. A quorum requirement and a dispersion threshold both produce explicit abstention rather than a low-confidence number.

Calibration

Probability calibration uses isotonic regression, exported as monotone piecewise-linear maps, trained offline and applied statically. There is no Platt scaling anywhere in the code, and there is no refitting in the live path. A map that fails a monotonicity check at load time raises rather than loading.

Maps can be conditioned on regime. The multi-class regime transition model uses per-class isotonic calibration with renormalization. Training scripts hold out the final third of the out-of-sample period to measure calibration error on data the map never saw, then build the shipped map on the full out-of-sample period.

Calibration drift is monitored as a one-way degradation signal over a rolling window of about thirty thousand rows. It can trigger a freeze. It never triggers a refit.

The decision to calibrate at all was itself tested by removing the map: expected calibration error rose from 0.0187 to 0.0306, Brier score from 0.2495 to 0.2515 and log loss from 0.6922 to 0.7261, against 0.6931 for the constant one-half forecast. A separate attempt to refit the committee calibration produced an area under the curve of 0.5263 and was refused by its gate.

Uncertainty

Uncertainty is reported, not hidden in a point estimate:

Registered forecasters

Three models are registered in the live engine, all gradient boosting, each with a declared gate it had to clear:

ModelTaskRegistered performance
Volatility expansionBinary, will hourly realized volatility expandOut-of-sample AUC 0.744, calibration error 0.000, on 126 000 bars
Regime transitionMulti-class next regimeChange-AUC 0.695, per-class AUC 0.79 for stress, 0.77 for squeeze, 0.72 for thin liquidity
Realized volatility forecastQuantile regression on log volatilityPinball loss 11.5 per cent better than persistence, and required to beat a heterogeneous autoregressive benchmark as well

The 0.744 figure carries a mandatory caveat wherever it is quoted, including here. It is walk-forward out-of-sample on the training epoch of the artifact, not a measurement of live behaviour, and the target compares future realized volatility to a trailing estimate, so a substantial part of the absolute number is the trivial mean reversion of a noisy estimator. On a synthetic series with constant volatility the trivial score reaches about 0.83. The honest margin of the benchmark model over the trivial one on real five-minute bars is 0.02 to 0.04. Reading 0.744 as "expansion is called correctly three times in four" is wrong.

The gate for the regime model is deliberately change-AUC rather than macro-AUC, because regime is persistent and macro-AUC is inflated by that persistence into a number that looks impressive and means nothing.