This page covers:
- what a
ReferenceModelmust implement - how the built-in model classes behave
- what
evaluate(data, inline_metrics=True)adds - how class-based models relate to the simpler function wrappers used in manifests
Public Surface
The current public reference-architecture exports are:
ReferenceModelWeightLinkedBinaryPseudoLabelBinaryFeatureLinkedBinaryEntropyVaRRegressorCNN1DBinaryDLinearRegressorDirectionSizingModelLSTMBinaryGaussianHMMBinaryLightGBMBinaryLogRegBinaryRandomBinaryRBFSVMBinaryResidualRegressorRidgeRegressorRuleBasedStrategyXGBoostRegressorTabPFNBinary
Each model module also exposes a function-style wrapper with the same behavioral surface used by foundational manifests. The TabPFN symbols are importable without the optional dependency; constructing or training TabPFNBinary requires vaquum-limen[tabpfn]. The separate TabPFN campaign records a real pinned-checkpoint CPU run, its environment and numerical assertions. It does not claim CUDA execution or deterministic reconstruction.
The function exports are weight_link_binary, pseudo_label_binary, feature_link_binary, entropy_var_regressor, cnn1d_binary, direction_sizing, dlinear_regressor, gaussian_hmm_binary, lightgbm_binary, logreg_binary, lstm_binary, random_binary, rbf_svm_binary, residual_regressor, ridge_regressor, rule_based, tabpfn_binary, and xgboost_regressor.
Caller-owned fitting
The Python project fits and retains its own scaler/estimator pipeline. Its selection score, fitted-state identity and Sensor output meaning remain the caller's decisions:
def fit(train, round_params): return make_pipeline(StandardScaler(), Ridge(alpha=round_params["alpha"])).fit( train.select("momentum"), train["next_return"].to_numpy() )ReferenceModel
ReferenceModel is the base contract. Every subclass must implement:
@abstractmethoddef train(self, data: dict[str, Any], **params: Any) -> 'ReferenceModel': ...@abstractmethoddef predict(self, data: dict[str, Any]) -> dict[str, Any]: ...@abstractmethoddef evaluate(self, data: dict[str, Any], inline_metrics: bool=True) -> dict[str, Any]: ...Data expectations
Manifest preparation can provide:
x_train,y_trainx_val,y_valx_test,y_testprice_data_for_backtest_feature_names_alignment_scaler
Models consume the subset of keys they need from the standard Limen shape.
Sklearn input boundary
Manifest preparation retains Polars frames and series. Uncalibrated and
threshold-only LogRegBinary and RidgeRegressor convert features and labels to
NumPy arrays at sklearn fit and prediction calls, preserving row and column order.
Conversion does not replace prepared entries or recording feature names.
When a probability-calibration callable is configured, LogReg training and calibration fitting/prediction retain their original input containers. Native array inputs remain arrays. Sklearn's calibration fold gathers can change floating-point prediction arithmetic when frames are converted first; isotonic calibration can turn that difference into a different selected threshold. Frame and array calibration decisions are therefore not promised identical.
Custom calibration callbacks and fitted predictors receive original feature inputs; threshold callbacks retain original validation labels. Calibration keeps its existing dataframe-protocol dependency and backend warnings, including feature-name warnings when a frame-trained model later receives arrays in Sensor. Backend errors and warnings continue to propagate. This boundary applies to the same model calls in serial and worker execution; it adds no execution mode or preparation reuse. The ordinary per-permutation path remains the default, and factorized snapshot admission follows its explicit reuse contract.
The Built-In Model Classes
| Class | Task shape | Deterministic | Notes |
|---|---|---|---|
LogRegBinary |
binary classification | no | sklearn logistic regression wrapper; manifest wrapper exposes constructor params; solver refits are not bit-reproducible across BLAS builds and thread counts, so Trainer validates with relative tolerance |
LightGBMBinary |
binary classification | yes | LightGBM classifier exposing the full LGBMClassifier surface; accepts binary, cross_entropy, or None as its objective and rejects other objectives before training; early stopping on the validation split; reproducibility pinned via deterministic/force_row_wise/random_state defaults |
RandomBinary |
binary baseline | no | intentionally stochastic |
RidgeRegressor |
regression | no | sklearn Ridge wrapper; conservative flag because stochastic solvers are supported |
XGBoostRegressor |
regression | yes | requires xgboost; training is bit-reproducible for a fixed random_state on a fixed environment (verified byte-identical predictions across processes and thread counts), so Trainer validates with its near-exact deterministic tolerance |
DLinearRegressor |
regression | yes | canonical DLinear semantics; closed-form SVD ridge fit, no seed; requires scipy |
TabPFNBinary |
binary classification | no | optional, requires tabpfn |
RuleBasedStrategy |
rule-based long/flat | yes | no training step; boolean predicate logic |
RBFSVMBinary |
binary classification | no | RBF SVC probabilities with optional validation calibration and threshold selection |
GaussianHMMBinary |
binary classification | no | fitted return-state dynamics over raw chronological return windows |
LSTMBinary |
binary sequence classification | no | optional CPU PyTorch learner over completed return windows |
CNN1DBinary |
binary sequence classification | no | optional one-dimensional CPU convolution over completed return windows |
EntropyVaRRegressor |
forward-return quantile | no | signed quantile forecast with pinball loss and violation rate; no attached trading metrics |
ResidualRegressor |
residual regression | no | Ridge baseline plus XGBoost correction of observed training error |
FeatureLinkedBinary |
linked binary classification | no | chronological upstream predictions become a downstream feature |
PseudoLabelBinary |
binary classification | no | generated training labels for an explicitly pinned pool of real observations |
WeightLinkedBinary |
linked binary classification | no | chronological upstream errors determine downstream sample weights |
DirectionSizingModel |
signed exposure | component-dependent | paired completed trade outcomes fit direction and magnitude components |
The deterministic flag matters because Trainer uses it to choose its validation tolerance.
RidgeRegressor
RidgeRegressor delegates fitting and prediction to sklearn.linear_model.Ridge.
It uses x_train and y_train for fitting; validation and test targets do not
participate in training. Each train() call constructs a fresh estimator.
The fitted sklearn model remains available as model.model.
The function wrapper exposes alpha, fit_intercept, copy_X, max_iter,
tol, solver, positive, and random_state. Defaults follow sklearn except
that the function wrapper seeds stochastic solvers with random_state=42.
tol retains sklearn's meaning: it is not a Cholesky pivot cutoff, and it has
no effect for cholesky or svd. Backend errors and warnings are not replaced
with alternate results. See the sklearn Ridge reference
for solver-specific behavior.
predict({'x_test': features}) returns continuous _preds. evaluate() uses
Limen's existing continuous metrics; with inline_metrics=True, it also uses
preds > 0 and y_test > 0 for directional confusion metrics and the standard
long/flat backtest when prices are supplied. Costs and execution remain owned
by the manifest/backtest layer. The function wrapper returns _model for
normal Trainer reconstruction. Scaling belongs to the manifest, not the model.
Direction And Sizing
DirectionSizingModel owns two fitted components and emits one signed exposure in [-1, 1]. Its native wrapper is direction_sizing; default components are sklearn LogisticRegression for direction and Ridge for magnitude. It requires private simulated-trade outcomes and prediction_mode='target_exposure'.
# region declarationschema_version: '1.0'metadata: name: book_direction_sizing mode: developmentsfd: manifest: type: ml data_source: method: limen.data.HistoricalData.get_any_file params: file_path_or_url: inputs/spot_15m_20250101_20250531.parquet split_dates: train_start: '2025-01-01' train_end: '2025-01-15' val_start: '2025-01-15' val_end: '2025-01-18' test_start: '2025-01-18' test_end: '2025-01-22' indicators: - func: limen.indicators.roc params: period: 1 group: momentum target: name: outcome class: limen.targets.TradeOutcomeTarget backtest: prediction_mode: target_exposure product: kind: linear_perpetual instrument: BTCUSDT base_currency: BTC quote_currency: USDT quantity_step: 1e-09 min_notional: 0 source_interval_seconds: 900 fee_bps: 1 slip_bps: 0 max_holding_seconds: 1800 scaler: class: limen.scalers.RobustScaler reference_architecture: limen.sfd.reference_architecture.direction_sizing params: direction_params: - max_iter: 1000 C: 0.5 sizing_params: - alpha: 1.0 conditional_size: - false - true folds: - 3 min_train_samples: - 2 seed: - 42uel: output_path: compiled-family_direction_sizing n_permutations: 2 search_strategy: type: grid output_format: csv checkpoint_interval: 1 recording: predictions: true alignment: true trade_ledger: true fold_details: true# endregion declarationThis is the Compiled project's actual direction/sizing definition. The CLI reads its literal bundled input path and executes both conditional_size candidates. The declared source interval is 900 seconds and the holding limit is 1,800 seconds. Inputs require recorded OHLC and UTC datetime with that regular interval, or explicit causal interval metadata. Funding is optional and independently tunable.
When both candidates complete, direction is the strictly better positive side. Equal returns and neither side profitable map to flat. Magnitude is the better return divided by positive return_scale (default 0.01), clipped to max_size (default 1). One unavailable side excludes that row from paired fitting/metrics. Predictions still cover every feature-valid inference row.
direction_params and sizing_params have separate search namespaces. direction_features and sizing_features select prepared feature names independently. Factories accept seed and component kwargs and return estimators with fit(x, y)/predict(x). They require importable module-qualified identities and a deterministic declaration. Native manifests accept callables; YAML component factory paths use the existing native resolver. Unknown kwargs, invalid subsets, nonfinite predictions and insufficient classes/samples fail explicitly.
Set conditional_size=True to add direction to the sizing inputs. Training then uses chronological out-of-fold direction predictions. Each fold refits automatic feature shims and its scaler/PCA on its earlier prefix, then fits direction only on feature-valid outcomes completed before the fold begins. Automatic-shim warmup cannot change the original chronological fold boundaries; unavailable rows are excluded by source identity. The final outer fitted state remains the inference state. The initial fold has no causal predictions and cannot train sizing. Outer validation/test never calibrate this stack. folds (default 5) and min_train_samples (default 20) are tunable. Final direction uses all eligible training outcomes.
direction_accuracy and size_mae use completed paired test outcomes; inline execution metrics retain the entire inference population. Changed sizing signals target post-cost current equity. Unchanged sizing signals hold quantity, as defined by the shared execution rules.
JSONL binds the architecture, factory source hashes, component params, seed, feature/label sources, outcome mapping and economics to the round and manifest. Trainer reconstructs both components and rejects changed identities before tolerant metric checks. Sensor preserves the exact signed scalar, actual availability and read-only frozen contract. Binary Cohort rejects these members, including a single member. Use Sensor directly; downstream replay/paper/live parity remains a separate integration request.
Probability Support for Cohort
For Cohort, “probability” always means P(1): the probability that the positive class is 1.
Ordinary homogeneous Cohorts select aggregation through architecture capability hints. Mixed and fold-containing selections instead require the fitted model's native binary-output declaration. A returned probability and an ordinary Cohort's selected aggregation mode therefore have separate contracts. Cohort compatibility defines binding and output validation.
| Architecture | Returns probabilities P(1) | Cohort mode | Notes |
|---|---|---|---|
LogRegBinary |
yes | probability | predict() returns _probs = predict_proba(x_test)[:, 1], which is directly the class-1 probability P(1). |
LightGBMBinary |
yes | probability | predict() returns _probs from the classifier or fitted calibrator. |
RandomBinary |
yes | probability | predict() returns _probs, but they are fixed surrogate scores (0.9 for predicted 1, 0.1 for predicted 0), not model-derived calibrated probabilities. Still usable as P(1)-shaped output if Cohort accepts implementation-defined probability-like outputs. |
TabPFNBinary |
yes | probability | predict() returns _probs as positive-class probability. When a CalibrationConfig is configured, probabilities are optionally recalibrated and the threshold optimized before _preds are produced. This is compatible with P(1). |
RidgeRegressor |
no | fallback | Continuous _preds only; no class probabilities. Ordinary unqualified regressor Cohorts vote up at prediction > 0; qualified folds keep their separate contract. |
XGBoostRegressor |
no | fallback | Ordinary regressor members vote up at prediction > 0; forecast magnitude is not preserved by native voting. |
DLinearRegressor |
no | fallback | predict() returns only _preds. Same regressor caveat as XGBoostRegressor. |
RuleBasedStrategy |
no | fallback | predict() returns positions as _preds; _probs is intentionally absent. |
RBFSVMBinary |
yes | probability | Positive-class SVC or retained calibrated probability. |
GaussianHMMBinary |
yes | probability | Probability of positive next return under fitted state dynamics. |
LSTMBinary |
yes | probability | Sigmoid probability from the fitted sequence classifier. |
CNN1DBinary |
yes | probability | Sigmoid probability from the fitted convolutional classifier. |
ResidualRegressor |
no | fallback | Ordinary regressor voting uses the sign of the corrected forecast. |
EntropyVaRRegressor |
no | fallback | Ordinary regressor voting uses the sign of the quantile forecast and discards its magnitude. |
FeatureLinkedBinary |
yes | fallback | Ordinary architecture hints use voting; admitted mixed binary membership uses its explicit probability declaration. |
PseudoLabelBinary |
yes | fallback | Ordinary architecture hints use voting; admitted mixed binary membership uses its explicit probability declaration. |
WeightLinkedBinary |
yes | fallback | Ordinary architecture hints use voting; admitted mixed binary membership uses its explicit probability declaration. |
DirectionSizingModel |
no | refused | Native Cohort rejects signed-exposure members. Use the Sensor's signed output or explicitly compatible Python composition. |
predict() Versus evaluate()
predict() is the small inference surface. For the built-in binary models it always returns:
_preds_probs
When a CalibrationConfig is configured on the manifest and injected into the architecture, predict() additionally returns:
optimal_threshold— the threshold chosen by the optimizer (or0.5when only probability calibration is configured)val_score— the metric score at that threshold;Nonewhen no threshold function is set
evaluate() passes these keys through into the results dict alongside the standard binary metrics.
evaluate() is the richer offline evaluation surface.
inline_metrics=False
With inline_metrics=False, evaluate() omits inline confusion and backtest metrics. The returned dictionary still includes the five task metrics and private or schema-stability fields required by the architecture.
For LogRegBinary, the task metrics are:
accuracyaucprecisionrecallfpr
LogRegBinary also returns _preds, optimal_threshold, and val_score; the last two are None when no calibration or threshold step produced them. Other architectures may retain their own private prediction payloads.
inline_metrics=True
With inline_metrics=True, evaluate() adds:
confusion_*metricsconfusion_*_mean_return_pctandbacktest_*metrics whenprice_data_for_backtestis present
When price_data_for_backtest is absent, default inline evaluation still returns task metrics and confusion counts; price-derived confusion-return and backtest metrics are skipped.
For LogRegBinary, inline evaluation can add keys such as:
backtest_edge_bps_p50backtest_pnl_bps_p50backtest_cvar_95_pnl_bpsconfusion_tpconfusion_fpconfusion_precision
That is why the reference-architecture layer is the bridge between raw model output and the experiment-level analytics surfaces.
Class-based usage in the project
schema_version: '1.0'metadata: name: book_ridge_regressor mode: developmentsfd: manifest: type: ml data_source: method: limen.data.HistoricalData.get_any_file params: file_path_or_url: inputs/spot_15m_20250101_20250531.parquet split_dates: train_start: '2025-01-01' train_end: '2025-01-15' val_start: '2025-01-15' val_end: '2025-01-18' test_start: '2025-01-18' test_end: '2025-01-22' indicators: - func: limen.indicators.window_return params: period: 1 target: name: next_return class: limen.targets.NextReturnTarget transform_params: periods: 1 scale: 100.0 backtest: fee_bps: 7.0 slip_bps: 3.0 notional_rate: 0.5 scaler: class: limen.scalers.RobustScaler reference_architecture: limen.sfd.reference_architecture.ridge_regressor features: - func: limen.features.lag_range params: col: ret_1 start: 0 end: 5 params: alpha: - 1.0 solver: - svduel: output_path: compiled-family_ridge_regressor n_permutations: 1 search_strategy: type: grid output_format: csv checkpoint_interval: 1 recording: predictions: true alignment: true trade_ledger: true fold_details: trueThis complete YAML defines the recorded Ridge family case. The CLI fits its declared training population and retains the predictions used to recompute RMSE independently. The selection scenario separately proves CLI reconstruction; training a family case does not by itself prove its reconstruction.
Function Wrappers Versus Classes
Foundational manifests call a function wrapper through with_reference_architecture. The current Ridge wrapper signature is:
def ridge_regressor(data: dict[str, object], alpha: float=1.0, fit_intercept: bool=True, copy_X: bool=True, max_iter: int | None=None, tol: float=0.0001, solver: str='auto', positive: bool=False, random_state: int | None=42) -> dict[str, object]: ...That wrapper:
- instantiates the matching class
- trains it
- evaluates it with
inline_metrics=True
The class is the canonical reusable architecture surface. The function wrapper is the manifest-facing adapter.
Trainer Relationship
Trainer reconstructs the compiled manifest, reruns prepare_data() and run_model(), and uses the returned _model after metric validation.
The class-based layer matters even when daily work touches foundational SFDs:
- foundational SFDs package the experiment
- reference architecture owns the model contract
Trainerreplays selected rounds into validated class-based models
Deterministic models use near-exact metric tolerance; stochastic models use a wider relative tolerance and can still raise ReconstructionError when a replay diverges too far.
DLinearRegressor
DLinearRegressor is Limen's canonical DLinear surface (Zeng et al. 2023, Are Transformers Effective for Time Series Forecasting?). It owns the DLinear semantics that downstream parity checks compare against, so every semantic choice is explicit:
- Decomposition — each lookback window is split by a centered moving average with replicate edge padding (the official DLinear
moving_avgbehavior;kernel_sizemust be a positive odd integer, canonical default25) into a trend component and a remainder component. - Heads — each component gets its own linear head and the head outputs are summed, which is exactly the DLinear function class.
- Fit — the ridge-regularized DLinear MSE objective is minimized in closed form by SVD (
alphais the ridge strength;alpha=0gives the min-norm least-squares solution). There is no optimizer loop and no seed:deterministic = True, and re-running the same config reproduces the experiment log exactly on a fixed environment. Cross-BLAS-build float differences remain possible, as with any LAPACK-backed path. - Lookback — the window is read from feature columns named
ret_1_lag_{i}, ordered by lag descending so each row is the window in time order (oldest bar first). Window length is a manifest concern (lag_rangewithend=lookback_end); all other feature columns are ignored. - Target shape — scalar per bar:
NextReturnTarget(periods=horizon, scale=100.0), the percentage return over the nexthorizonbars. - Direction mapping —
evaluate()mirrorsXGBoostRegressor:preds > 0becomes the long/flat signal for the inline confusion and backtest metrics.
The Compiled project's recorded family case checks its prediction/target alignment and recomputes RMSE. Separate component tests cover reconstruction. Those assertions establish the declared case; they do not establish predictive edge or transfer a historical performance number to a new window.
RuleBasedStrategy
RuleBasedStrategy is the reference architecture for rule-based SFDs. It differs from the ML models in two important ways:
train()is a no-op — rule-based strategies have no learnable parametersevaluate()runs across all three splits (train/val/test) and returns cross-split stability metrics in addition to per-split backtest metrics
It expects a data_dict produced by a manifest configured with with_strategy():
| Prepared key | Rule-based input |
|---|---|
train, val, test |
Prepared frames containing predicate columns. |
strategy.conditions |
Resolved condition definitions. |
strategy.entry |
The root condition ID to evaluate. |
The strategy walks the boolean logic tree defined in strategy['conditions'], resolves each leaf condition by reading its pre-computed boolean column from the split DataFrame, and folds compound conditions via AND/OR/NOT. Positions are 0 (flat) or 1 (long) per bar.
rule_based() also returns its trained native model as _model. The model captures the selected strategy and leaf-column order and accepts a finite binary x_test matrix in that order for Sensor/fold inference; the existing named test/strategy route remains available. It declares inference_output = ('binary', False). See selected rule reconstruction for the raw-history and causality contract.
Metrics produced
evaluate() returns a flat dict with three tiers:
- Tier 1 — position stats:
num_trades_{split},position_rate_{split} - Tier 2 — per-split backtest: all
backtest_snapshotoutput columns plus rule-onlypnl_per_trade_bpsandnum_executed_trades, each suffixed with_{split}(e.g.pnl_bps_p50_train,drawdown_bps_p5_test,pnl_per_trade_bps_test) - Tier 3 — cross-split diagnostics:
drawdown_std_bps,is_stable
is_stable is False until a replacement stability rule is defined against the new decoder-level ledger.
pnl_per_trade_bps is intentionally outside the generic 20-column snapshot. RuleBasedStrategy derives it from contiguous executed-position segments returned by the shared long-flat strategy, reports their count as num_executed_trades, compounds net per-bar returns after costs and notional sizing within each segment, then takes the arithmetic mean. No executed trades yields a zero count and NaN mean.
NOTE: Tier 2 and Tier 3 metrics require open and close columns in the split DataFrames to run the backtest. When those columns are absent, per-split backtest results are empty and drawdown_std_bps is returned as None with is_stable falling back to False.
_preds is present; _probs is intentionally absent (not applicable to rule-based strategies).
TabPFN controls
Built with PriorLabs-TabPFN. The optional model project retains the package and checkpoint licenses with their additional attribution provisions.
tabpfn_binary exposes the nondeprecated constructor controls of
TabPFN 6.4.1.
The existing n_ensemble_configurations name maps to upstream n_estimators;
n_preprocessing_jobs replaces upstream's deprecated n_jobs. Existing positional
arguments retain their order; additional controls are keyword-only.
| Control | Wrapper default | Meaning |
|---|---|---|
n_ensemble_configurations |
4 |
Ensemble forward passes |
device |
'cpu' |
Upstream device specification |
categorical_features_indices |
None |
Categorical feature column indices |
softmax_temperature |
0.9 |
Probability temperature |
balance_probabilities |
False |
Adjust probabilities for class frequency |
average_before_softmax |
False |
Aggregate ensemble logits before softmax |
model_path |
'tabpfn-v2-classifier-v2_default.ckpt' |
Checkpoint path or upstream Python model specifications |
ignore_pretraining_limits |
True |
Permit inputs outside upstream pretraining limits |
inference_precision |
'auto' |
Automatic precision, autocast or an upstream Python dtype |
fit_mode |
'fit_preprocessors' |
Upstream fitting/cache mode |
memory_saving_mode |
'auto' |
Upstream memory-saving policy |
random_state |
0 |
Seed, NumPy random generator/state or None |
n_preprocessing_jobs |
1 |
Preprocessing parallelism |
inference_config |
None |
Expert inference configuration |
differentiable_input |
False |
Upstream differentiable-input mode |
eval_metric |
None |
Upstream evaluation metric |
tuning_config |
None |
Upstream classifier tuning configuration |
Limen's prediction_calibration_config remains separate from upstream tuning.
Prediction/calibration logic and the default CPU/v2 checkpoint are preserved.
Controls pass through without coercion; upstream validates compatible combinations.
Python can supply supported upstream objects directly. YAML retains its existing
serializable-value boundary; represent a list or configuration as one candidate
inside the parameter's outer search list.
The foundational SFD searches ensemble counts [4, 8], temperatures
[0.7, 0.9, 1.1], and both probability-balancing/logit-averaging settings.
Other controls have singleton defaults, including device: ['cpu'].
Existing target and indicator domains remain. Select a bounded run explicitly:
the complete Cartesian product is large and these starting domains do not imply
better market performance. The real-model procedure
verifies the supported surface and selected nondefault controls on recorded bars.
Optional Dependencies
xgboost_regressorrequiresxgboostdlinear_regressorrequiresscipy(thestatsextra), loaded lazily inside the modeltabpfn_binaryrequirestabpfnlstm_binaryandcnn1d_binaryrequiretorchthrough theneuralextragaussian_hmm_binaryrequireshmmlearnthrough thehmmextraresidual_regressorrequires theboostingextra for its XGBoost correction
Optional dependencies are checked when the relevant model executes, not when the package is imported.
Primary-preserving meta allocation
The compiled manifest's with_allocation(method, params) adds a research allocator around its original primary. The native method is limen.sfd.reference_architecture.meta_allocation.meta_allocation; a second allocation declaration rejects. Factory callables follow direction_sizing's source-bound estimator pattern. See Backtest for fitting, cost and exposure semantics.
Prepared data exposes _allocation_batches['val'] and ['test']. The fitted model accepts model.predict({'allocation_batch': batch}) without targets or outcomes. AllocationBatch binds full partition bounds, original ordered source IDs and availability, target-free primary inputs, named numeric meta features and decision-time stop/readiness values. Reordered, changed or truncated batches reject. This is not an incremental future-window inference protocol.
GaussianHMMBinary
Install vaquum-limen[hmm]. The matching gaussian_hmm_binary function fits
hmmlearn's homogeneous univariate GaussianHMM on chronological training
ret_1_lag_0 values. Inputs require contiguous ret_1_lag_0..N columns;
other feature columns are ignored. Use raw fractional returns, without a
per-lag scaler. The adapter converts training and inference to percentage
returns consistently, so Gaussian priors and covariance controls use those units.
Each prediction uses one completed lookback window, oldest first, restarting from the fitted initial-state distribution. Only the terminal posterior is retained: multiply it by the transition matrix and Gaussian positive-tail probabilities to obtain P(next return > 0). Decisions use probability > 0.5. This window-local filtering is causal and has identical row/batch behavior; it deliberately differs from maintaining an online full-history state. State IDs have no directional meaning. Labels do not fit the unsupervised model.
The function exposes 14 native controls for states, covariance, priors,
initial seed, EM iteration/tolerance/verbosity and log/scaling implementation.
n_iter caps EM; termination at the cap does not establish tolerance convergence.
The fitted backend retains its diagnostics. Supervised calibration is not part
of this variant. The Bitcoin HMM study
studies richer Bayesian/nonhomogeneous alternatives, rather than establishing
performance for this narrower EM implementation.
A recorded hourly-return CPU probe with two states, 24 lags, 30 EM iterations and one thread measured median complete-cycle costs of 0.103/0.087s for HMM/LogReg at 384 bars, 0.095/0.082s at 2048 and 0.264/0.098s at 8192. Three alternating repeats included fresh preparation, fit and test prediction. The larger HMM runs hit the iteration cap. These are configuration-specific cost observations on macOS/Python 3.12.12, NumPy 2.2.6, sklearn 1.7.2, Polars 1.42.1 and hmmlearn 0.3.3, with no efficacy or profitability claim.
RBF SVM binary classifier
RBFSVMBinary / rbf_svm_binary fits sklearn SVC with kernel='rbf' and
probability=True. It requires both numeric training classes 0 and 1, returns
binary predictions and class-1 probabilities, and supports the standard optional
validation calibration and threshold selection. Calibration is fitted once on
validation data and retained for later target-free inference; refitting clears it.
The public controls keep sklearn meanings: C=1.0, gamma='scale',
shrinking=True, tol=0.001, cache_size=200 MiB, class_weight=None,
verbose=False, max_iter=-1 and random_state=42. Gamma also accepts 'auto'
or a nonnegative float. C is positive; max_iter=-1 removes the iteration limit.
Backend validation and convergence warnings remain visible. Limen predicts 1
above a class-1 probability of 0.5 unless validation calibration/thresholding is
configured. SVC's native margin-based class prediction can differ; this adapter
uses the probability decision rule so recorded probabilities reconstruct its decisions.
The official SVC contract describes at-least-quadratic fit scaling and extra probability-fit cost. A local one-thread recorded hourly Bitcoin probe with 23 features measured median cycle time 5.995s versus LogReg 0.219s at 5931 training rows (three repetitions; includes preparation, fit and prediction). This configuration-specific cost is not a performance or trading-benefit claim. The research record contains the smaller windows and configuration.
The matching foundational SFD reuses LogReg preparation with SVM control domains
and bounded native data requests. The shipped rbf_svm_binary template supplies
every public control and a small dated experiment. The canonical compiled example
is docs/examples/compiled-research/family_rbf_svm_binary.yaml.
LSTMBinary
Install vaquum-limen[neural]. lstm_binary fits a PyTorch LSTM and a scalar
linear head using binary cross-entropy with logits and Adam on CPU. Each input
is a completed contiguous ret_1_lag_0..N window ordered oldest first. Other
feature columns are ignored. One shared mean/std is fitted to training windows
only, retained, and used unchanged in target-free inference. Hidden state resets
for each window. Bidirectional mode combines both final-layer final states;
all observations in either direction are already available at the decision.
Inference uses eval mode, sigmoid probabilities and probability >0.5 decisions. Initialization and training restore the caller's CPU RNG state. Exposed controls cover the native LSTM structure, Adam configuration, epochs, minibatch size and seed. Supervised validation calibration and GPU execution are outside this variant. The Bitcoin LSTM direction study establishes application relevance, without demonstrating efficacy for this specific return-window configuration. The bundled Apple Silicon research lock requires macOS 14 or later for its pinned PyTorch wheel. The native LSTM contract defines the sequence and final-state semantics.
ResidualRegressor
Install vaquum-limen[boosting]. residual_regressor fits Ridge to observed
training returns, then fits XGBoost to the aligned training errors
y - ridge.predict(x). Inference needs features only and returns
ridge.predict(x) + correction_scale * xgboost.predict(x). Both components
retain their fitted state. This is a bounded regression pair.
ridge_params and xgboost_params preserve native constructor controls as
nested dictionaries. Defaults use Ridge alpha 1/SVD and 32 CPU XGBoost trees,
depth 2, learning rate 0.1 and seed 42. The correction uses
reg:squarederror; its early stopping is disabled unless explicitly supplied.
Enabled early stopping requires nonempty observed validation data and uses
validation residuals from the training-fitted Ridge. Test labels never enter
either fit. correction_scale must be finite. Zero retains the primary forecast.
Evaluation reports final continuous metrics and ordinary linkage_* log
columns: kind, ordered component identities, training row count and SHA-256
fingerprints of features, observed targets and residual targets. Fingerprints
cover a compact JSON header [shape, columns-or-null] followed by C-order
little-endian float64 bytes. Round parameters preserve nested controls; Trainer
rebuilds the same pair and provenance through the existing recorded round.
The matching compiled example is compiled-research/family_residual_regressor.yaml.
An error correction may overfit and worsen held-out error. The recorded acceptance cases establish actual residual fitting and additive reconstruction, without a predictive or trading-benefit claim.
CNN1DBinary
Install vaquum-limen[neural]. cnn1d_binary applies CPU PyTorch Conv1d blocks
to the time axis of completed raw ret_1_lag_0..N windows, oldest first. Each
block uses the selected ReLU, tanh or GELU activation, followed by global
mean/max pooling, dropout and a scalar logit head. Kernel size, stride and
dilation describe time; no padding or future observations are added.
The model shares the LSTM's train-only scalar normalization, binary
cross-entropy/Adam fitting, scoped CPU RNG and target-free sigmoid inference.
Decisions use probability >0.5. Its 16 controls cover convolution structure,
pooling, dropout, optimizer and bounded training. The matching SFD/template
exposes every control and a 16-combination search domain. The compiled recorded
example is compiled-research/family_cnn1d_binary.yaml.
The Bitcoin CNN study uses richer market, sentiment and blockchain inputs; this raw-return variant does not replicate its accuracy. The native Conv1d contract defines temporal kernel, stride and dilation semantics. Recorded-data tests verify gradients and an independent NumPy convolution/pooling/probability oracle.
EntropyVaRRegressor
entropy_var_regressor fits a lower conditional return quantile using sklearn
QuantileRegressor. For each completed raw ret_1_lag_0..N window it computes
binary Shannon entropy of the negative/nonnegative return fractions. Zero terms
contribute zero. Unrelated feature columns are ignored. Fit uses observed training
returns only; inference retains the coefficients and requires no target labels.
Output is a signed return quantile in the target's units. The foundational SFD uses 24 completed hourly returns and the following 24-hour simple percentage return; the compiled example uses 96 quarter-hour returns and a 96-bar horizon. It reports pinball loss and strict violation rate (observed return below forecast), plus descriptive continuous metrics. It produces no direction, probability or trading metrics. Fitted scaler/PCA and execution policies are rejected; raw signs must retain their meaning. Manager owns downstream decisions and execution.
Controls expose quantile (strictly between 0 and 0.5), alpha, fit_intercept, solver and solver_options, plus SFD lookback/horizon. Defaults are quantile0.05, alpha0, intercept enabled and HiGHS. Solver validation and warnings stay visible. The Bitcoin entropy-VaR study motivates the sign-entropy predictor. This rolling-window, simple-return, frozen-fit variant does not replicate its calendar-day log-return and rolling coefficient protocol. Overlapping horizons imply dependent observations; violation rate alone establishes neither calibrated tails nor GARCH superiority.
FeatureLinkedBinary
This bounded link requires fitted NextBarUpTarget labels. Other targets and
unverified label horizons are rejected; prepare data through the matching manifest.
feature_link_binary appends an upstream logistic probability as the final
downstream feature, after the completed raw ret_1_lag_0..N inputs. Training
uses chronological out-of-sample probabilities from expanding prefixes; initial
rows without such a prediction are excluded. A separately retained upstream
fit on all observed training rows supplies the same feature at inference.
The downstream classifier then returns target-free probabilities and decisions.
Nested upstream_params/downstream_params retain native logistic controls
(default max_iter 200, seed 42). n_splits and the explicit
observation_interval_seconds define the chronology. The matching SFD's
recorded_rows extension carries real split timestamps through the existing
data-dictionary extension. Raw windows must be contiguous, finite and equally
spaced. External scaling/PCA and calibration are rejected. No validation/test
labels enter either fit.
Features from a completed bar are available at open plus one interval; its next-close label at plus two. Each fit prefix excludes labels unavailable by its first prediction decision and requires both observed classes. The final full-training upstream never generates downstream training features. These features are explicitly out of sample, without globally fitted preprocessing.
Ordinary linkage_* log columns retain ordered augmented feature names,
component identity, observed/covered row counts, actual row/availability and
fold cutoffs, and fingerprints of raw/augmented inputs, observed labels,
covered indices and out-of-sample probabilities. SHA-256 fingerprints cover a
compact JSON [shape, dtype] header and C-order little-endian float64 or int64
bytes. Existing round parameters and Trainer reconstruct the same composition
and provenance. The compiled example is compiled-research/family_feature_link_binary.yaml.
A full-training upstream may have a different output distribution than the chronological prefixes. Recorded assertions establish feature meaning, fit boundaries and reconstruction; they do not establish predictive or trading benefit.
PseudoLabelBinary
This bounded link requires fitted NextBarUpTarget labels. Other targets and
unverified label horizons are rejected; prepare data through the matching manifest.
pseudo_label_binary fits an upstream logistic classifier only on observed
training labels. It predicts a supplied pool of real recorded observations,
selects confidence max(p, 1-p) >= confidence_threshold, and fits the downstream
classifier on observed rows plus those selected generated labels (p > 0.5).
Target-free inference uses only the downstream classifier. Validation and test
outcomes remain observed and never enter either fit.
The pool requires a local Parquet path, exact SHA-256, timezone-aware start/end bounds and an explicit downstream training cutoff. Its completed raw return windows must follow the declared observation interval, fall after the observed upstream fitting boundary, and be disjoint from observed training/evaluation rows. Features use only source bars available by the cutoff, before evaluation decisions. Initial history must cover every requested pool window. External fitted preprocessing, calibration and protected holdout research are rejected. Missing/changed files and an empty confidence selection fail explicitly.
The matching SFD/YAML supplies 24 hourly return lags, the recorded hourly pool
identity and eight combinations of confidence and logistic regularization.
Provision inputs/spot_1h_20240101_20241231.parquet with that declared digest,
or explicitly replace its path/hash and dates with your own recorded source.
Nested upstream/downstream controls retain native logistic semantics. The
compiled recorded example uses the provided 15-minute source and a tighter
native upstream solver tolerance for its smaller raw return magnitudes.
Ordinary linkage_* log columns preserve observed/generated counts, source
path/hash, feature/label/row fingerprints, upstream configuration and fit cutoff,
downstream cutoff, and recoverable selected-row JSON. Each generated row records
its timestamp, availability, label, probability, confidence and origin: pseudo.
SHA-256 covers the exact selected JSON; matrix fingerprints use compact JSON
[shape, dtype] plus C-order little-endian float64/int64 bytes. Trainer validates
the same pool identity and reconstructs identical provenance. Relative pool paths
resolve from the working directory; use an absolute path for replay elsewhere. Generated labels
remain distinct from observed labels. Model confidence does not establish label
correctness or predictive/trading benefit.
WeightLinkedBinary
This bounded link requires fitted NextBarUpTarget labels. Other targets and
unverified label horizons are rejected; prepare data through the matching manifest.
weight_link_binary fits an ordinary logistic classifier on each expanding
training prefix. Observed next-close direction and the prefix model's
chronological out-of-sample probability define difficulty abs(y-p). The
downstream classifier fits covered rows with actual native sample_weight
values weight_floor + (1-weight_floor) * difficulty**weight_power. Initial
rows without out-of-sample predictions are excluded. Inference uses the fitted
downstream classifier with target-free probabilities and binary decisions.
Inputs are completed contiguous raw ret_1_lag_0..N windows. Other feature
columns are ignored; external scaling/PCA and calibration are rejected. Nested
upstream_params/downstream_params retain native logistic controls, with
default max_iter 200 and seed 42. Split count, positive weight floor/power and
observation_interval_seconds control the link. The floor is at most one.
The matching SFD's recorded_rows extension carries each split's real
timestamps through the existing data-dictionary extension. Timestamps must be
ordered and equally spaced at the declared interval. A completed bar's
features are available at its open timestamp plus one interval; the next-close
label is observed at plus two. Each prefix excludes labels unavailable by the
first prediction decision time and must contain both observed classes. No
validation/test rows or labels enter either fit.
Ordinary linkage_* log columns retain ordered feature names, component
identity, training/covered row counts, fold fit/prediction cutoffs and SHA-256
fingerprints of features, observed labels, timestamps, covered indices,
out-of-sample probabilities and consumed weights. Each fingerprint covers a
compact JSON [shape, dtype] header followed by C-order little-endian bytes
(float64 values or int64 timestamps/indices). Existing round parameters and
Trainer reconstruct the same training payload and provenance. The compiled
example is compiled-research/family_weight_link_binary.yaml.
Recorded-data assertions inspect actual native fit inputs and independently rebuild prefix probabilities, weights and final metrics. Weighting may worsen held-out results; this capability carries no predictive or trading-benefit claim.
Read Next
- Continue to Built-In SFDs to see how the shipped foundational SFDs package these model surfaces.
- Continue to Trainer for the reconstruction workflow that replays and validates selected rounds.
- Continue to Standard Metrics Library for the low-level metric helpers used inside these model classes.
For signed sizing, elapsed exits, recorded execution clocks and funding configuration, see Backtest.