Skip to main content

BacktestResult

Struct BacktestResult 

Source
#[non_exhaustive]
pub struct BacktestResult {
Show 14 fields pub symbol: String, pub strategy_name: String, pub config: BacktestConfig, pub start_timestamp: i64, pub end_timestamp: i64, pub initial_capital: f64, pub final_equity: f64, pub metrics: PerformanceMetrics, pub trades: Vec<Trade>, pub equity_curve: Vec<EquityPoint>, pub signals: Vec<SignalRecord>, pub open_position: Option<Position>, pub benchmark: Option<BenchmarkMetrics>, pub diagnostics: Vec<String>,
}
Expand description

Complete backtest result

Fields (Non-exhaustive)§

This struct is marked as non-exhaustive
Non-exhaustive structs could have additional fields added in future. Therefore, non-exhaustive structs cannot be constructed in external crates using the traditional Struct { .. } syntax; cannot be matched against without a wildcard ..; and struct update syntax will not work.
§symbol: String

Symbol that was backtested

§strategy_name: String

Strategy name

§config: BacktestConfig

Configuration used

§start_timestamp: i64

Start timestamp

§end_timestamp: i64

End timestamp

§initial_capital: f64

Initial capital

§final_equity: f64

Final equity

§metrics: PerformanceMetrics

Performance metrics

§trades: Vec<Trade>

Complete trade log

§equity_curve: Vec<EquityPoint>

Equity curve (portfolio value at each bar)

§signals: Vec<SignalRecord>

All signals generated (including non-executed)

§open_position: Option<Position>

Current open position (if any at end)

§benchmark: Option<BenchmarkMetrics>

Benchmark comparison metrics (set when a benchmark is provided)

§diagnostics: Vec<String>

Diagnostic messages (e.g. why zero trades were produced).

Empty when the backtest ran without issues. Populated with actionable hints when the engine detects likely misconfiguration.

Implementations§

Source§

impl BacktestResult

Source

pub fn summary(&self) -> String

Get a formatted summary string

Source

pub fn is_profitable(&self) -> bool

Check if the backtest was profitable

Source

pub fn total_pnl(&self) -> f64

Get total P&L

Source

pub fn num_bars(&self) -> usize

Get the number of bars in the backtest

Source

pub fn rolling_sharpe(&self, window: usize) -> Vec<f64>

Rolling Sharpe ratio over a sliding window of equity-curve bars.

For each window of window consecutive bar-to-bar returns, computes the Sharpe ratio using the same risk_free_rate and bars_per_year as the overall backtest. The first element corresponds to bars 0..window of the equity curve.

Returns an empty vector when window == 0 or when the equity curve contains fewer than window + 1 bars (i.e. fewer than window return periods).

§Statistical reliability

Sharpe and Sortino are computed from window return observations using sample variance (n − 1 degrees of freedom). Very small windows produce extreme and unreliable values — at least 30 bars is a practical lower bound; 60–252 is typical for daily backtests.

Source

pub fn drawdown_series(&self) -> Vec<f64>

Running drawdown fraction at each bar of the equity curve (0.0–1.0).

Each value is the fractional decline from the running all-time-high equity up to that bar: 0.0 means the equity is at a new peak; 0.2 means it is 20% below the highest value seen so far.

This is not a sliding-window computation. Values are read directly from the precomputed EquityPoint::drawdown_pct field, which tracks the running-peak drawdown since the backtest began. To compute the maximum drawdown within a rolling N-bar window (regime-change detection), iterate over BacktestResult::equity_curve manually.

The returned vector has the same length as BacktestResult::equity_curve.

Source

pub fn rolling_win_rate(&self, window: usize) -> Vec<f64>

Rolling win rate over a sliding window of consecutive closed trades.

For each window of window trades (ordered by exit timestamp as stored in the trade log), returns the fraction of winning trades in that window. The first element corresponds to trades 0..window.

This is a trade-count window, not a time window. To compute win rate over a fixed calendar period, use by_year, by_month, or filter BacktestResult::trades directly by timestamp.

Returns an empty vector when window == 0 or when fewer than window trades were closed.

Source

pub fn by_year(&self) -> HashMap<i32, PerformanceMetrics>

Performance metrics broken down by calendar year.

Each trade is attributed to the year in which it closed (exit_timestamp). The equity curve is sliced to the bars that fall within that calendar year, and the equity at the first bar of the year serves as initial_capital for the period metrics.

Years with no closed trades are omitted from the result.

§Caveats
  • Open positions: a position that is open throughout the year contributes to the equity-curve drawdown and Sharpe of that year but does not appear in total_trades or win_rate, because those are derived from closed trades only. Strategies with long holding periods will show systematically low trade counts per year.
  • Partial years: the first and last year of a backtest typically cover fewer than 12 months. annualized_return_pct, calmar_ratio, and serenity_ratio are set to 0.0 for slices shorter than half a year (< bars_per_year / 2 bars) to prevent geometric-compounding distortion.
  • total_signals / executed_signals: these fields are 0 in period breakdowns because signal records are not partitioned per period. Use BacktestResult::signals directly if needed.
Source

pub fn by_month(&self) -> HashMap<(i32, u32), PerformanceMetrics>

Performance metrics broken down by calendar month.

Each trade is attributed to the (year, month) in which it closed. Uses the same equity-slicing approach as by_year; the same caveats about open positions, partial periods, and signal counts apply here as well.

Source

pub fn by_day_of_week(&self) -> HashMap<Weekday, PerformanceMetrics>

Performance metrics broken down by day of week.

Each trade is attributed to the weekday on which it closed (exit_timestamp). Only weekdays present in the trade log appear in the result. Trades and equity-curve points with timestamps that cannot be converted to a valid date are silently skipped.

§Sharpe / Sortino annualisation

The equity curve is filtered to bars that fall on each specific weekday, so consecutive equity points in each slice are roughly one week apart (for a daily-bar backtest). bars_per_year is inferred from the calendar span of each slice so that annualisation matches the actual sampling frequency — you do not need to adjust the config. The inferred value is approximately 52 for daily bars, 12 for weekly bars, and so on.

§Other caveats

The same open-position and signal-count caveats from by_year apply here.

Source

pub fn trades_by_tag(&self, tag: &str) -> Vec<&Trade>

Return all trades that carry the given tag.

Tags are attached to a [Signal] at strategy time with .tag("name") and propagated to Trade::tags when the position closes.

Tag comparison is exact and case-sensitive: "Breakout" and "breakout" are distinct tags. Normalise tag strings at the call site if case-insensitive matching is required.

Returns an empty Vec when no trades match or no trades have been tagged at all.

Source

pub fn metrics_by_tag(&self, tag: &str) -> PerformanceMetrics

Compute PerformanceMetrics for the subset of trades that carry tag.

A synthetic equity curve is built by replaying the tagged trades in sequence starting from initial_capital, which gives an accurate drawdown and return series for that trade subset.

§Capital base

All return metrics (total_return_pct, annualized_return_pct, sharpe_ratio, calmar_ratio) are computed relative to initial_capital — the full portfolio starting value — not the capital actually deployed into tagged trades. A tag that fired 2 small trades on a $10,000 portfolio will show a lower total_return_pct than a tag that deployed the same profit using more capital.

For capital-independent comparisons across tags prefer: profit_factor, win_rate, avg_win_pct, avg_loss_pct.

§Sharpe / Sortino annualisation

bars_per_year is inferred from the calendar span of the synthetic equity curve (same technique as by_day_of_week) so that a sparsely-firing tag is not penalised by an inflated annualisation factor.

Returns PerformanceMetrics::empty when no tagged trades exist.

Source

pub fn all_tags(&self) -> Vec<&str>

Return a sorted, deduplicated list of all tags used across all trades.

Useful for discovering which tags are present in a result before calling trades_by_tag or metrics_by_tag.

Trait Implementations§

Source§

impl Clone for BacktestResult

Source§

fn clone(&self) -> BacktestResult

Returns a duplicate of the value. Read more
1.0.0 · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for BacktestResult

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl<'de> Deserialize<'de> for BacktestResult

Source§

fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>
where __D: Deserializer<'de>,

Deserialize this value from the given Serde deserializer. Read more
Source§

impl Serialize for BacktestResult

Source§

fn serialize<__S>(&self, __serializer: __S) -> Result<__S::Ok, __S::Error>
where __S: Serializer,

Serialize this value into the given Serde serializer. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> DynClone for T
where T: Clone,

Source§

fn __clone_box(&self, _: Private) -> *mut ()

Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self>

Converts self into a Left variant of Either<Self, Self> if into_left is true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
where F: FnOnce(&Self) -> bool,

Converts self into a Left variant of Either<Self, Self> if into_left(&self) returns true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

impl<T> Key for T
where T: Clone,

Source§

fn align() -> usize

The alignment necessary for the key. Must return a power of two.
Source§

fn size(&self) -> usize

The size of the key in bytes.
Source§

unsafe fn init(&self, ptr: *mut u8)

Initialize the key in the given memory location. Read more
Source§

unsafe fn get<'a>(ptr: *const u8) -> &'a T

Get a reference to the key from the given memory location. Read more
Source§

unsafe fn drop_in_place(ptr: *mut u8)

Drop the key in place. Read more
Source§

impl<T> Pointable for T

Source§

const ALIGN: usize

The alignment of pointer.
Source§

type Init = T

The type for initializers.
Source§

unsafe fn init(init: <T as Pointable>::Init) -> usize

Initializes a with the given initializer. Read more
Source§

unsafe fn deref<'a>(ptr: usize) -> &'a T

Dereferences the given pointer. Read more
Source§

unsafe fn deref_mut<'a>(ptr: usize) -> &'a mut T

Mutably dereferences the given pointer. Read more
Source§

unsafe fn drop(ptr: usize)

Drops the object pointed to by the given pointer. Read more
Source§

impl<T> PolicyExt for T
where T: ?Sized,

Source§

fn and<P, B, E>(self, other: P) -> And<T, P>
where T: Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns Action::Follow only if self and other return Action::Follow. Read more
Source§

fn or<P, B, E>(self, other: P) -> Or<T, P>
where T: Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns Action::Follow if either self or other returns Action::Follow. Read more
Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

Source§

fn vzip(self) -> V

Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

impl<T> DeserializeOwned for T
where T: for<'de> Deserialize<'de>,

Source§

impl<T> PlanCallbackArgs for T

Source§

impl<T> PlanCallbackOut for T