Documentation, examples and further information of the ta4j project
This project is maintained by ta4j Organization
ta4j 0.23.1 adds two complementary projection tools: analog forecasting creates an empirical return distribution from similar historical states, and rolling conformal calibration adjusts an existing forecast’s tails using matured forecast errors. Both are causal Indicator<Forecast> implementations and return ForecastSupport.Unavailable rather than inventing a partial distribution.
AnalogReturnProjectionIndicator<S extends ReturnMomentState> answers: “What happened after historical states that looked like this one?” It projects cumulative log returns and reports ForecastSupport.empirical(selectedNeighborCount).
LogReturnIndicator returns = new LogReturnIndicator(series);
ReturnForecastStateIndicator<ReturnForecastState> states =
new EwmaReturnForecastStateIndicator(returns);
AnalogReturnProjectionIndicator<ReturnForecastState> analog =
new AnalogReturnProjectionIndicator<>(states);
The return-specific state contract is the joyful path: the projection infers the source return indicator, validates shared-series and log-return semantics, and uses the representation-bound [mean, volatility] schema.
AnalogReturnProjectionIndicator<ReturnForecastState> analog =
AnalogReturnProjectionIndicator.builder(states)
.horizon(5)
.lookbackBarCount(504)
.neighborCount(40)
.minimumNeighborCount(15)
.featureExtractor(ForecastFeatureExtractors
.driftVolatility(ReturnRepresentation.LOG))
.standardizeFeatures(true)
.quantiles(0.01, 0.05, 0.5, 0.95, 0.99)
.build();
Use builder(ForecastStateIndicator<S>, ReturnIndicator) only when a custom state source cannot expose its return stream through ReturnForecastStateIndicator<S>.
ForecastStateIndicator<RegimeReturnState> regimeStates = ...;
ReturnIndicator logReturns = ...;
AnalogReturnProjectionIndicator<RegimeReturnState> analog =
AnalogReturnProjectionIndicator.builder(regimeStates, logReturns)
.featureExtractor(ForecastFeatureExtractors
.meanVolatility(ReturnRepresentation.LOG))
.build();
RegimeReturnState implements ReturnMomentState; the explicit return stream supplies the matured forward labels while the state remains free to carry model-specific fields.
Built-in rich return estimators keep the shorter return-specific builder path. For example, rough-volatility similarity is an explicit schema choice rather than a hidden change to analog defaults:
RoughVolatilityForecastStateIndicator roughStates =
new RoughVolatilityForecastStateIndicator(returns);
AnalogReturnProjectionIndicator<RoughVolatilityForecastState> roughAnalog =
AnalogReturnProjectionIndicator.builder(roughStates)
.featureExtractor(ForecastFeatureExtractors.roughVolatility())
.build();
The ordered raw features are [mean, volatility, roughness_hurst, vol_of_vol]. Candidate-only standardization remains owned by the analog model. Prefer the default [mean, volatility] schema unless roughness and vol-of-vol are intentional, tested similarity dimensions.
Online change-point state composes through the same return-specific builder without repeating the return source:
OnlineChangePointForecastStateIndicator changePointStates =
new OnlineChangePointForecastStateIndicator(returns);
AnalogReturnProjectionIndicator<OnlineChangePointForecastState> regimeAnalog =
AnalogReturnProjectionIndicator.builder(changePointStates)
.featureExtractor(ForecastFeatureExtractors.changePoint(
changePointStates.getRecentChangeWindow()))
.build();
Its raw schema is [mean, volatility, recent_change_probability, most_likely_run_length]. The default five-bar window uses change-point/default; custom windows use change-point/recent-change/<window>, and extraction rejects a state/window mismatch. Candidate-only standardization is especially important because probability, observations, and log returns have different units. Prefer the smaller default schema unless walk-forward evidence supports treating regime uncertainty and age as similarity dimensions. Unstable post-reset states are excluded rather than converted into artificial neighbors.
| Setting | Default | Operator intent |
|---|---|---|
horizon(...) |
1 |
Match the forward-return label to the holding period. |
lookbackBarCount(...) |
252 |
Bound historical candidate decisions. |
neighborCount(...) |
30 |
Cap the empirical states represented by the forecast. |
minimumNeighborCount(...) |
5 |
Refuse forecasts that rely on too little comparable history. |
featureExtractor(...) |
log [mean, volatility] |
Choose a fixed schema whose representation and units match the model. |
standardizeFeatures(...) |
true |
Fit per-feature scale from eligible candidates only. |
quantiles(...) |
0.05, 0.25, 0.5, 0.75, 0.95 |
Request only probabilities consumed downstream. |
For decision i, candidate j is eligible only when j + horizon <= i. Its feature vector and complete forward return must be usable and outside both upstream indicators’ unstable windows. The lookback counts matured candidate decision rows regardless of horizon. Standardization is fit without the current state, so the query never influences training scale. Euclidean distances sort by distance and then source index. Normalized exp(-distance) weights drive the mean, population variance, and weighted empirical quantiles; scaled moment arithmetic avoids avoidable overflow for finite extreme returns.
Use analog projection when state similarity has an interpretable historical meaning and an empirical neighbor distribution is useful. Do not use it when the history has too few comparable regimes, the schema mixes representations, or standardizing the chosen raw features cannot make their distances meaningful.
RollingConformalForecastProjectionIndicator wraps a numeric forecast with at least one configured non-median quantile and widens its tails using recent absolute median errors. It preserves the base mean, median, standard deviation, horizon, decision index, and support. Calibration rows are not samples and never replace base provenance.
RollingConformalForecastProjectionIndicator calibrated =
new RollingConformalForecastProjectionIndicator(priceForecast, closePrice);
The realized value for a decision is closePrice.getValue(decision + horizon).
ReturnForecastProjectionIndicator calibrated =
RollingConformalForecastProjectionIndicator
.cumulativeLogReturnBuilder(analog, returns)
.targetCoverage(0.95)
.calibrationWindow(504)
.minimumCalibrationCount(60)
.build();
This path validates that both the base forecast and realized stream use ReturnRepresentation.LOG, sums returns from decision + 1 through decision + horizon, and preserves ReturnForecastProjectionIndicator so downstream composition remains representation-aware.
| Setting | Default | Operator intent |
|---|---|---|
targetCoverage(...) |
0.90 |
Select the finite-sample absolute-error rank. |
calibrationWindow(...) |
252 |
Inspect this many recent matured decision rows. |
minimumCalibrationCount(...) |
30 |
Set the lower bound on valid scores; the requested rank may require more. |
With n valid scores, the calibration radius is order statistic ceil((n + 1) * coverage). The wrapper stays unavailable until that rank is attainable, even when the configured minimum is smaller, and rejects a calibration window that can never attain it. Lower quantiles subtract that radius, upper quantiles add it, and the median remains unchanged. This is intentionally called rolling conformal calibration, not Adaptive Conformal Inference: no online coverage-rate update is claimed.
Use the wrapper when recent, matured residuals are relevant to operational tail width and preserving the base model is important. Do not use it as a cure for a biased or semantically mismatched base model, and do not interpret target coverage as a guarantee under arbitrary distribution shift.
Analog output stays unavailable until the current state and enough fully matured, post-warm-up candidates are usable. Rolling conformal output stays unavailable until its base forecast is stable and enough valid scores exist for both the configured minimum and requested finite-sample rank. Both can recover at later indexes.
Unavailable results include:
BarSeries;NumFactory;Always branch on forecast.isStable() when reading a raw summary. Point adapters such as projection.quantile(0.05) emit NaN.NaN for unavailable forecasts.
ta4jexamples.analysis.forecast.RollingConformalForecastExample loads the committed Coinbase BTC-USD daily resource, builds a five-day analog return forecast, and calibrates it with matured five-day cumulative log returns.
./mvnw -pl ta4j-examples -am install
./mvnw -pl ta4j-examples exec:java \
-Dexec.mainClass=ta4jexamples.analysis.forecast.RollingConformalForecastExample