Ta4j Wiki

Documentation, examples and further information of the ta4j project

View the Wiki On GitHub

This project is maintained by ta4j Organization

Analysis Criteria and Risk Metrics

Use analysis criteria after a strategy run to compare returns, risk, duration, fees, and open exposure. Current ta4j criteria work with the same TradingRecord model used by both backtests and fill-driven live-style simulations.

Recent Criteria Surface

Need Primary classes Notes
Risk-adjusted return SharpeRatioCriterion, SortinoRatioCriterion Support SamplingFrequency, Annualization, risk-free rates, grouping zones, cash-return policy, equity-curve mode, and open-position handling.
Drawdown-adjusted return CalmarRatioCriterion, ReturnOverMaxDrawdownCriterion CalmarRatioCriterion annualizes return and divides by maximum drawdown.
Distribution-aware return OmegaRatioCriterion Compares upside excess returns against downside shortfalls around a configurable threshold.
Trade duration PositionDurationCriterion Summarizes closed-position durations with Statistics such as mean/min/max.
Stop-model quality RMultipleCriterion Computes profit divided by per-trade risk from a PositionRiskModel.
Open exposure OpenPositionCostBasisCriterion, OpenPositionUnrealizedProfitCriterion Useful when evaluating records that can still have an open position.
Recorded fees TotalFeesCriterion Reads fees recorded on fills/trades instead of re-estimating them from a cost model.

Sampling And Equity-Curve Controls

SharpeRatioCriterion and SortinoRatioCriterion build a return sample from the equity curve. Choose these settings deliberately:

AnalysisCriterion sharpe = new SharpeRatioCriterion(
        0.05,
        SamplingFrequency.DAY,
        Annualization.ANNUALIZED,
        ZoneOffset.UTC);

Num score = sharpe.calculate(series, tradingRecord);

Windowed Criterion Evaluation

Since the window-aware criterion API, any AnalysisCriterion can be evaluated over a bounded slice without hand-copying a TradingRecord.

AnalysisWindow window = AnalysisWindow.lookbackBars(120);
AnalysisContext context = AnalysisContext.defaults()
        .withMissingHistoryPolicy(AnalysisContext.MissingHistoryPolicy.CLAMP)
        .withOpenPositionHandling(OpenPositionHandling.MARK_TO_MARKET);

Num recentSharpe = sharpe.calculate(series, tradingRecord, window, context);

Available windows:

Use MissingHistoryPolicy.STRICT when a missing lookback should fail fast. Use CLAMP for moving-series dashboards where the oldest requested bars may already have been evicted.

Risk-Unit Evaluation

When a strategy is designed around stop placement, score it in risk units instead of raw profit:

AnalysisCriterion rMultiple = new RMultipleCriterion(new StopLossPositionRiskModel(5));
Num averageR = rMultiple.calculate(series, tradingRecord);

RMultipleCriterion skips positions where the supplied PositionRiskModel cannot produce a positive risk value. That keeps invalid stop geometry from silently improving the average.

Practical Workflow

  1. Pick the business question first: absolute return, downside risk, trade duration, open exposure, or stop-model quality.
  2. Match equity-curve mode and open-position handling to the system being measured.
  3. Use AnalysisWindow for rolling dashboards, recent-regime checks, and moving-series records.
  4. Use the same NumFactory through the originating BarSeries; criteria return Num values from that factory.

Rationale Notes (2026-04-27)