QuantileModel

Defined in fynance.models.quantile

class QuantileModel(taus=(0.1, 0.5, 0.9), layers=[16, 8], activation=torch.nn.ReLU, drop=None, bias=True, activation_kwargs={}, lr=1e-3, epochs=200, optimizer=torch.optim.Adam, seed=0)[source]

Bases: object

Multi-quantile regression SignalModel.

Trains a feed-forward trunk with one output column per tau on PinballLoss. Unlike ObjectiveModel (trained on positions * returns), fit(X, y) reads y as an ordinary supervised target (e.g. the next-bar return), not a returns series to be combined with positions.

Parameters:
tausfloat or sequence of float, optional

Target quantile(s) in (0, 1). Default (0.1, 0.5, 0.9).

layerslist of int, optional

Hidden layer sizes of the trunk. Default [16, 8] (a small nonlinear trunk — matching the ObjectiveModel / RegimeMoE convention of a usable-out-of-the-box default).

activationtype[torch.nn.Module] or None, optional

Activation class applied after each hidden layer (never after the linear output head — see _quantile_trunk). Default torch.nn.ReLU; pass None for a purely linear trunk.

dropfloat, optional

Dropout probability after each hidden layer. Default None (no dropout).

biasbool, optional

Whether the trunk’s linear layers use a bias term. Default True.

activation_kwargsdict, optional

Extra keyword arguments for activation. Default {}.

lrfloat, optional

Learning rate for the optimizer. Default 1e-3.

epochsint, optional

Full-batch training steps. Default 200.

optimizertype[torch.optim.Optimizer], optional

Optimizer class. Default torch.optim.Adam.

seedint, optional

Seed for reproducible net initialization. Default 0.

Attributes:
nettorch.nn.Module or None

The trunk, built lazily on the first fit call (None before that).

See also

fynance.models.loss.PinballLoss
fynance.models.objective.ObjectiveModel
fynance.models.regime_model.RegimeMoE

Examples

>>> import numpy as np
>>> rng = np.random.default_rng(0)
>>> x = rng.uniform(-2, 2, size=300).astype(np.float32)
>>> sigma = 0.1 + 0.3 * np.abs(x)
>>> y = (x + sigma * rng.standard_normal(300)).astype(np.float32)
>>> X = x.reshape(-1, 1)
>>> model = QuantileModel(
...     taus=(0.1, 0.5, 0.9), layers=[16, 8], epochs=200, lr=1e-2, seed=0,
... ).fit(X, y)
>>> point = model.predict(X)
>>> point.shape
(300,)
>>> q = model.predict_quantiles(X)
>>> q.shape
(300, 3)
>>> bool(np.all(np.diff(q, axis=1) >= 0))   # non-crossing, enforced at predict time
True
fit(X, y)[source]

Train the trunk to minimize the multi-quantile pinball loss.

Parameters:
Xarray-like, shape (T, F)

Feature matrix.

yarray-like, shape (T,) (or any shape reshaping to it)

Supervised target aligned with X (e.g. the realized next-bar return) — not a returns series to combine with positions.

Returns:
QuantileModel

self.

Raises:
ValueError

If X is not 2-D, or X and y have different lengths.

predict(X)[source]

Point forecast: the tau=0.5 (or nearest) quantile column.

Parameters:
Xarray-like, shape (T, F)

Feature matrix.

Returns:
numpy.ndarray

Shape (T,), the median (or nearest-to-0.5 tau) column of predict_quantiles.

predict_quantiles(X)[source]

Return the full quantile band, shape (T, n_taus).

Columns follow self.taus (sorted ascending). Non-crossing is enforced here (not during training) by sorting the raw, independently trained columns along the quantile axis.

Parameters:
Xarray-like, shape (T, F)

Feature matrix.

Returns:
numpy.ndarray

Quantile predictions, shape (T, n_taus), non-decreasing along axis 1.

Raises:
RuntimeError

If called before fit.