Skip to main content

StrategyReport

Struct StrategyReport 

Source
#[non_exhaustive]
pub struct StrategyReport { pub name: String, pub symbol: String, pub timeframe: Timeframe, pub initial_capital: f64, pub currency: Option<String>, pub risk_free_rate: f64, pub properties: Vec<(String, String)>, pub trades: Vec<StrategyTrade>, pub equity: Vec<(DateTime<Utc>, f64)>, }
Expand description

The result of one strategy run, from any source: a backtest the host runs against the headless engine, a forward test, or the host’s own analytics. Build it with StrategyReport::new and set the remaining fields directly; StrategyReport::performance computes the metrics.

§Example

use chrono::{TimeZone, Utc};
use egui_charts::model::{StrategyExit, StrategyReport, OrderSide, StrategyTrade, Timeframe};

let hour = |h| Utc.with_ymd_and_hms(2024, 1, 2, h, 0, 0).unwrap();
let mut report = StrategyReport::new("SMA cross", "AAPL", Timeframe::Hour1, 10_000.0);
report.currency = Some("USD".into());
report.properties.push(("Fast length".into(), "10".into()));

// The host computes each trade's net profit: here (190 - 185) * 10 shares less 2 of fees.
let mut trade = StrategyTrade::new(OrderSide::Buy, 10.0, hour(1), 185.0);
trade.fees = 2.0;
trade.exit = Some(StrategyExit::new(hour(3), 190.0, 48.0));
report.trades.push(trade);
report.equity = vec![(hour(0), 10_000.0), (hour(1), 9_998.0), (hour(2), 10_030.0), (hour(3), 10_048.0)];

let performance = report.performance();
assert_eq!(performance.net_profit, 48.0);
assert_eq!(performance.win_rate, Some(1.0));
assert_eq!(performance.max_drawdown, Some(2.0));
// Three hours of equity are too short to annualise.
assert_eq!(performance.sharpe_ratio, None);
assert!(report.trades_csv().starts_with("number,side,quantity,"));

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.
§name: String

What the run is called, as the host names it.

§symbol: String

The instrument the trades are in.

§timeframe: Timeframe

The bar interval the run used.

§initial_capital: f64

Account value at the start, in currency. Positive and finite, or StrategyPerformance::net_profit_fraction is unavailable.

§currency: Option<String>

Currency of capital, profits, fees and equity, such as “USD”. Display only.

§risk_free_rate: f64

Annual risk-free rate as a fraction (0.02 for 2%), used by the Sharpe and Sortino ratios. Finite and above -1, or the ratios are unavailable.

§properties: Vec<(String, String)>

Settings of the run as the host wants them shown (parameters, commission, sizing), in order. Display only.

§trades: Vec<StrategyTrade>

Every trade, closed or open, in any order.

§equity: Vec<(DateTime<Utc>, f64)>

Account value marked to market at each bar close, oldest first, one point per bar, in strictly increasing time order.

Implementations§

Source§

impl StrategyReport

Source

pub fn signals(&self) -> Vec<Signal>

Labelled entry and exit markers for the host’s signals service. Invalid trades are skipped; open trades have only an entry. Directions describe the fill side, including short exits. Ids remain stable for this report’s original trade indices. When replacing a run, remove its old signals before publishing the replacement, including when it has no trades.

Source

pub fn new( name: impl Into<String>, symbol: impl Into<String>, timeframe: Timeframe, initial_capital: f64, ) -> Self

A report with no trades, no equity, no properties, no currency and a risk-free rate of 0.

Source

pub fn performance(&self) -> StrategyPerformance

Computes the metrics of the run. Sorts closed trades for streaks; call once per report, not once per frame.

Source

pub fn equity_curve(&self) -> Vec<(DateTime<Utc>, f64)>

Finite equity points in strictly increasing time order, using the same validation as Self::performance. Empty if the finite points are out of order.

Source

pub fn comparison(&self, bars: &[Bar]) -> StrategyComparison

Computes buy-and-hold and excursions from the complete source bars of this run’s symbol and interval, oldest first. The host supplies exactly the run’s bars, including every held bar; this method neither fetches data nor infers missing sessions. Bar times denote opens.

Non-finite or inverted OHLC bars are skipped and counted. Unordered or duplicate timestamps make the whole source unusable. Volume is unused. Buy-and-hold uses the first valid open and last valid close, with fractional units, no fees or reinvested dividends. A non-finite calculation is unavailable. Excursions require at least one held source bar; invalid held bars make that trade’s excursion unavailable rather than understating risk.

Source

pub fn trades_csv(&self) -> String

The valid trades as CSV, sorted by entry time (trades entered at the same time keep their order), one header line and one line per trade, each ending with \n.

Columns: number (from 1, in this order), side (long or short), quantity, entry_time, entry_price, exit_time, exit_price, profit, fees, label. Times are RFC 3339 in UTC (2024-01-02T00:00:00Z), numbers use the shortest form that reads back to the same value, and an open trade leaves the three exit columns empty. Text cells starting with =, +, -, @, tab or carriage return gain a leading apostrophe so spreadsheets treat them as text. Numeric cells, including negative numbers, are unchanged.

Source

pub fn summary_csv( &self, performance: &StrategyPerformance, comparison: &StrategyComparison, ) -> String

The summary metrics and the properties of the run as CSV, one header line and one line per metric or property, each ending with \n. performance and comparison are this report’s Self::performance and Self::comparison, the figures the report panel shows.

Columns: section (summary or properties), name (as the panel labels it), value, unit and currency. The unit is money (in currency, empty when the report has none), percent (100 is 100%), ratio, count or text. Percent values round to 15 significant decimal digits to suppress binary multiplication noise; if rounding would overflow f64, the unrounded finite value is kept. Numbers use the shortest form that reads back to the resulting value, with a dot as the decimal separator and no thousands separator. Every numeric zero is 0, and an unavailable value is an empty cell, so numeric columns stay numeric in a spreadsheet.

Text cells starting with =, +, -, @, tab or carriage return gain a leading apostrophe so spreadsheets treat them as text. This also applies to property names and currencies; numeric cells, including negative numbers, are unchanged by this protection.

Trait Implementations§

Source§

impl Clone for StrategyReport

Source§

fn clone(&self) -> StrategyReport

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

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

Performs copy-assignment from source. Read more
Source§

impl Debug for StrategyReport

Source§

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

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

impl<'de> Deserialize<'de> for StrategyReport

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 PartialEq for StrategyReport

Source§

fn eq(&self, other: &StrategyReport) -> bool

Equality operator ==. Read more
1.0.0 (const: unstable) · Source§

fn ne(&self, other: &Rhs) -> bool

Inequality operator !=. Read more
Source§

impl Serialize for StrategyReport

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
Source§

impl StructuralPartialEq for StrategyReport

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
§

impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
where ST: ?Sized, DT: ?Sized,

§

impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
where ST: ?Sized, DT: ?Sized,

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> DeserializeOwned for T
where T: for<'de> Deserialize<'de>,

Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

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> MaybeSend for T
where T: Send + Sync + ?Sized,

§

impl<T> Read<Exclusive, BecauseExclusive> for T
where T: ?Sized,

§

impl<T> SerializableAny for T
where T: 'static + Any + Clone + for<'a> Send + Sync,

§

impl<T, S> SimdFrom<T, S> for T
where S: Simd,

§

fn simd_from(_simd: S, value: T) -> T

§

impl<F, T, S> SimdInto<T, S> for F
where T: SimdFrom<F, S>, S: Simd,

§

fn simd_into(self, simd: S) -> T

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.