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.
| Need | Primary classes | Notes |
|---|---|---|
| Risk-adjusted return | SharpeRatioCriterion, SortinoRatioCriterion |
Support SamplingFrequency, including trade-level sampling, 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. |
SharpeRatioCriterion and SortinoRatioCriterion build a return sample from the equity curve. Choose these settings deliberately:
SamplingFrequency.BAR,SECOND,MINUTE,HOUR,DAY,WEEK, orMONTHcontrols time-based return intervals.SamplingFrequency.TRADEcreates one return per included position interval. Use it when each trade, not each bar or calendar bucket, should contribute one observation.Annualization.PERIODreturns the per-sample ratio;Annualization.ANNUALIZEDscales by observed periods per year.EquityCurveMode.MARK_TO_MARKETincludes unrealized movement on each bar;EquityCurveMode.REALIZEDupdates the curve only when positions close.OpenPositionHandling.MARK_TO_MARKETincludes the current open position;IGNOREevaluates only closed positions. Realized Sharpe calculations always ignore open positions.
AnalysisCriterion sharpe = new SharpeRatioCriterion(
0.05,
SamplingFrequency.DAY,
Annualization.ANNUALIZED,
ZoneOffset.UTC);
Num score = sharpe.calculate(series, tradingRecord);For a trade-level distribution, switch only the sampling frequency:
AnalysisCriterion tradeSharpe = new SharpeRatioCriterion(
0.05,
SamplingFrequency.TRADE,
Annualization.PERIOD,
ZoneOffset.UTC);
AnalysisCriterion tradeSortino = new SortinoRatioCriterion(
0.05,
SamplingFrequency.TRADE,
Annualization.PERIOD,
ZoneOffset.UTC);
Num perTradeSharpe = tradeSharpe.calculate(series, tradingRecord);
Num perTradeSortino = tradeSortino.calculate(series, tradingRecord);TRADE is for criteria that receive a TradingRecord, such as Sharpe and Sortino. It is intentionally not supported by SamplingFrequencyIndexes, because that helper can only group bar indices and cannot inspect positions.
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:
AnalysisWindow.barRange(startInclusive, endInclusive)AnalysisWindow.lookbackBars(barCount)AnalysisWindow.timeRange(startInclusive, endExclusive)AnalysisWindow.lookbackDuration(duration)
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.
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.
- Pick the business question first: absolute return, downside risk, trade duration, open exposure, or stop-model quality.
- Match equity-curve mode and open-position handling to the system being measured.
- Use
AnalysisWindowfor rolling dashboards, recent-regime checks, and moving-series records. - Use the same
NumFactorythrough the originatingBarSeries; criteria returnNumvalues from that factory.
- The new-feature scout flagged recent criteria and analysis classes that had no dedicated wiki entry point.
- Commit
9e0f63a9addedSharpeRatioCriterionplus sampling helpers such asSamplingFrequency,SamplingFrequencyIndexes,Sample, andSampleSummary. - Commit
8d319169addedSortinoRatioCriterion; commitb5f5d2d0addedCalmarRatioCriterionandOmegaRatioCriterion. - Commit
3e7299a3added the window-awareAnalysisCriterion#calculate(..., AnalysisWindow, AnalysisContext)API withAnalysisWindowandAnalysisContext. - Commit
89cd2271added risk-unit scoring aroundRMultipleCriterionandPositionRiskModel.