Choosing metrics
By default every calculator runs. Pass the calculator classes you want; their dependencies are pulled in automatically — transitively — and the canonical run order is kept:
use RoundlyConsulting\TradingAnalytics\Analytics\Counts;
use RoundlyConsulting\TradingAnalytics\Analytics\Streaks;
$analytics = TradingAnalytics::calculate($trades, only: [Counts::class]);
$analytics = TradingAnalytics::for($trades)->only([Counts::class])->calculate(); // same, fluent
// $analytics->counts is populated; metrics you didn't request stay null
$analytics = TradingAnalytics::for($trades)->except([Streaks::class])->calculate();Passing a class that is not a registered calculator throws UnknownCalculatorException. To discover what only() / except() accept, call TradingAnalytics::metrics() (or metrics() on an engine instance):
$available = TradingAnalytics::metrics(); // list of calculator class-strings
// Counts, TradingVolume, TradingValue, Commissions,
// UnrealizedGrossProfitAndLoss, UnrealizedNetProfitAndLoss,
// RealizedGrossProfitAndLoss, RealizedNetProfitAndLoss, Wins, ProfitFactor,
// GrossCumulativeReturn, NetCumulativeReturn, TradingFrequency, TradesDuration,
// Streaks, Expectancy, RiskRewardRatio, WinRateByPeriod, MaxDrawdown,
// RiskAdjustedReturns — all in RoundlyConsulting\TradingAnalytics\Analytics\Dependencies
Every calculator runs on its own: every aggregate counts the trades it averages over itself. Only three calculators depend on another — ProfitFactor, Expectancy and RiskRewardRatio are built from the realized gross P&L, so they bring RealizedGrossProfitAndLoss with them:
| Calculator | only() also runs |
|---|---|
ProfitFactor | RealizedGrossProfitAndLoss |
Expectancy | RealizedGrossProfitAndLoss |
RiskRewardRatio | RealizedGrossProfitAndLoss |
except() still runs an excluded calculator that a remaining one depends on — except([RealizedGrossProfitAndLoss::class]) keeps it while the profit factor needs it. The figures match a full run either way:
use RoundlyConsulting\TradingAnalytics\Analytics\Expectancy;
use RoundlyConsulting\TradingAnalytics\Analytics\MaxDrawdown;
use RoundlyConsulting\TradingAnalytics\Analytics\RealizedGrossProfitAndLoss;
use RoundlyConsulting\TradingAnalytics\Analytics\RealizedNetProfitAndLoss;
$analytics = TradingAnalytics::for($trades)
->scale(2)
->only([
RealizedNetProfitAndLoss::class, // averages over the closed trades it counted itself
Expectancy::class, // pulls in RealizedGrossProfitAndLoss
MaxDrawdown::class,
])
->calculate();
array_keys($analytics->toArray());
// ['profit_and_loss', 'expectancy', 'max_drawdown']
$analytics->realizedProfitAndLoss->net->global->total->average; // '260.33' — same as a full run
$analytics->counts; // null — not requested
// except() keeps a dependency a remaining calculator still needs
$analytics = TradingAnalytics::for($trades)->except([RealizedGrossProfitAndLoss::class])->calculate();
$analytics->realizedProfitAndLoss->gross; // still calculated — the profit factor needs itShow your open-source love
This package is free and MIT-licensed. If it saves you time, a one-off donation or a Patreon membership keeps it maintained, tested and documented.
More ways to support, including cryptoBy donating, you agree to our donation terms.
Want this built into your product?
We integrate our packages into custom Laravel and AI builds. Tell us what you're working on and we'll reply within 48 hours.