Skip to main content

DrawdownTracker

Struct DrawdownTracker 

Source
pub struct DrawdownTracker { /* private fields */ }
Expand description

Tracks peak equity and computes current drawdown percentage.

Implementations§

Source§

impl DrawdownTracker

Source

pub fn new(initial_equity: Decimal) -> Self

Creates a new DrawdownTracker with the given initial (and peak) equity.

Source

pub fn update(&mut self, equity: Decimal)

Updates the tracker with the latest equity value, updating the peak if higher.

Source

pub fn drawdown_duration(&self) -> usize

Returns the number of update() calls since the last new equity peak.

A value of 0 means the last update set a new peak. Higher values indicate how long the portfolio has been in drawdown (in update units).

Source

pub fn current_drawdown_pct(&self) -> Decimal

Returns current drawdown as a percentage: (peak - current) / peak * 100.

Returns 0 if peak_equity is zero.

Source

pub fn peak(&self) -> Decimal

Returns the highest equity seen since construction.

Source

pub fn current_equity(&self) -> Decimal

Returns the current equity value.

Source

pub fn is_below_threshold(&self, max_dd_pct: Decimal) -> bool

Returns true if the current drawdown percentage does not exceed max_dd_pct.

Source

pub fn reset_peak(&mut self)

Resets the peak to the current equity value.

Useful for daily or session-boundary resets where you want drawdown measured from the start of the new session rather than the all-time high.

Source

pub fn worst_drawdown_pct(&self) -> Decimal

Returns the worst (highest) drawdown percentage seen since construction or last reset.

Source

pub fn update_count(&self) -> usize

Returns the total number of equity updates since construction or last reset.

Source

pub fn win_rate(&self) -> Option<Decimal>

Returns the fraction of updates where equity was at or above peak (not in drawdown).

win_rate = (update_count - drawdown_update_count) / update_count

Returns None if no updates have been processed.

Source

pub fn underwater_pct(&self) -> Decimal

Returns how far below peak current equity is, as a percentage.

underwater_pct = (peak - current) / peak × 100

Returns Decimal::ZERO when at or above peak.

Source

pub fn reset(&mut self, initial: Decimal)

Fully resets the tracker as if it were freshly constructed with initial equity.

Source

pub fn volatility(&self) -> Option<f64>

Returns the sample standard deviation of per-update equity changes.

Uses Welford’s online algorithm internally. Returns None until at least two updates have been processed (can’t compute variance from one sample).

Source

pub fn recovery_factor(&self, net_profit_pct: Decimal) -> Option<Decimal>

Returns the recovery factor: net_profit_pct / worst_drawdown_pct.

A higher value indicates better risk-adjusted performance. Returns None when worst_drawdown_pct is zero (no drawdown has occurred).

Source

pub fn calmar_ratio(&self, annualized_return: Decimal) -> Option<Decimal>

Returns the Calmar ratio: annualized_return / worst_drawdown_pct.

Higher values indicate better risk-adjusted performance. Returns None when worst_drawdown_pct is zero (no drawdown has occurred).

Source

pub fn in_drawdown(&self) -> bool

Returns true if the current equity is strictly below the peak (i.e. in drawdown).

Source

pub fn update_with_returns(&mut self, equities: &[Decimal])

Applies a sequence of equity values in order, as if each were an individual update call.

Useful for batch processing historical equity curves without a manual loop.

Source

pub fn drawdown_count(&self) -> usize

Returns the number of consecutive updates where equity was below the peak.

Equivalent to DrawdownTracker::drawdown_duration. Provided as a semantic alias for call sites that prefer “count” over “duration”.

Source

pub fn sharpe_ratio( &self, annualized_return: Decimal, annualized_vol: Decimal, ) -> Option<Decimal>

Returns the Sharpe ratio: annualized_return / annualized_vol.

Returns None when annualized_vol is zero to avoid division by zero.

Source

pub fn recovery_to_peak_pct(&self) -> Decimal

Returns the percentage gain required from the current equity to recover to the peak.

Formula: (peak / current - 1) * 100. Returns Decimal::ZERO when already at peak or when current equity is zero (to avoid division by zero).

Source

pub fn time_underwater_pct(&self) -> Decimal

Fraction of equity updates spent below peak: drawdown_update_count / update_count.

Returns Decimal::ZERO when no updates have been processed.

Source

pub fn avg_drawdown_pct(&self) -> Option<Decimal>

Average drawdown percentage across all updates that had a non-zero drawdown.

Returns None when no drawdown updates have been recorded.

Source

pub fn max_loss_streak(&self) -> usize

Longest consecutive run of updates where equity was below peak.

Source

pub fn consecutive_gain_updates(&self) -> usize

Returns the current consecutive run of updates where equity increased from the prior update.

Resets to zero on any non-increasing update. Useful for detecting sustained rallies.

Source

pub fn equity_ratio(&self) -> Decimal

Returns current_equity / peak_equity, useful for position sizing formulas.

Returns Decimal::ONE when peak is zero (no drawdown state yet). A value below 1 indicates the portfolio is in drawdown; exactly 1 means at peak.

Source

pub fn new_peak_count(&self) -> usize

Returns how many times a new equity peak has been set since construction or last reset.

Source

pub fn pain_index(&self) -> Decimal

Returns the “pain index”: mean absolute drawdown across all updates.

pain_index = drawdown_pct_sum / update_count

Represents the average percentage loss a holder experienced over the equity curve. Returns Decimal::ZERO when no updates have been processed.

Source

pub fn above_high_water_mark(&self, equity: Decimal) -> bool

Returns true if equity is strictly greater than the current peak (new high-water mark).

Useful for triggering high-water-mark-based fee calculations or performance resets. Note: this does NOT update the tracker — call update(equity) to advance the peak.

Source

pub fn max_single_loss(&self) -> Option<f64>

Returns the largest single-step equity drop seen across all updates.

Returns the magnitude (positive number) of the worst per-update loss. Returns None if no loss has occurred or fewer than two updates have been processed.

Source

pub fn loss_rate(&self) -> Option<f64>

Returns the fraction of equity updates that decreased equity (loss rate).

A value of 0.0 means equity never decreased; 1.0 means it always decreased. Returns None if no updates have been processed.

Note: uses the drawdown update count as a proxy for loss updates — specifically the number of updates where equity was below peak, not strictly below the prior update.

Source

pub fn consecutive_loss_updates(&self) -> usize

Returns the current number of consecutive updates where equity decreased.

Resets to zero on any update where equity increases or stays the same. A current losing streak indicator complementing DrawdownTracker::consecutive_gain_updates.

Source

pub fn equity_change_mean(&self) -> Option<f64>

Returns the running mean of per-update equity changes.

Computed via Welford’s online algorithm. Returns None until at least one equity change has been recorded (requires 2+ updates).

Source

pub fn stress_test(&self, shock_pct: Decimal) -> Decimal

Returns the hypothetical drawdown percentage if equity dropped by shock_pct from current.

stress_drawdown = current_drawdown + shock_pct × (1 - current_drawdown/100)

This estimates the total drawdown from peak if the current equity fell an additional shock_pct percent. Returns the result as a percentage (0–100+).

Source

pub fn max_gain_streak(&self) -> usize

Returns the longest consecutive run of equity increases seen since construction or reset.

Source

pub fn total_gain_sum(&self) -> f64

Returns the cumulative sum of all positive per-update equity changes.

Returns 0.0 if no gains have been recorded.

Source

pub fn total_loss_sum(&self) -> f64

Returns the cumulative sum of absolute values of all negative per-update equity changes.

Returns 0.0 if no losses have been recorded.

Source

pub fn gain_to_loss_ratio(&self) -> Option<f64>

Returns total_gain_sum / total_loss_sum. Returns None if no losses recorded.

Source

pub fn expectancy(&self) -> Option<f64>

Trading expectancy: win_rate × avg_gain − loss_rate × avg_loss.

Returns None if fewer than 2 equity changes have been recorded.

Source

pub fn recovery_speed(&self) -> Option<f64>

Average number of updates required to recover from a drawdown to a new peak.

Returns None if no drawdown has ever been fully recovered.

Source

pub fn peak_hit_count(&self) -> usize

Number of times a new equity peak has been set.

This equals the number of update() calls where equity exceeded the prior peak.

Source

pub fn avg_recovery_drawdown_pct(&self) -> Option<Decimal>

Average drawdown percentage at the moment each recovery began.

Returns None if no drawdown has ever been fully recovered.

Source

pub fn max_gain_pct(&self) -> f64

Largest single-step equity gain expressed as a percentage of the prior equity.

Returns 0.0 if no gain has been recorded yet.

Source

pub fn avg_drawdown_duration(&self) -> Option<f64>

Average number of updates spent in each drawdown episode.

Returns None if no drawdown episode has been entered yet.

Source

pub fn breakeven_equity(&self) -> Decimal

The peak equity level the current equity must reach to exit drawdown.

Equals the all-time peak. If equity is already at peak, this is the current equity.

Source

pub fn loss_streak(&self) -> usize

Current consecutive count of updates where equity decreased.

Resets to 0 as soon as equity increases or stays flat.

Source

pub fn net_return_pct(&self) -> Option<f64>

Net return as a percentage: (current_equity - initial_equity) / initial_equity * 100.

Returns None if initial_equity is zero.

Source

pub fn consecutive_flat_count(&self) -> usize

Current count of consecutive updates where equity did not change.

Source

pub fn total_updates(&self) -> usize

Total number of update() calls processed since construction or last reset().

Source

pub fn pct_time_in_drawdown(&self) -> f64

Percentage of all updates spent below peak equity (in drawdown).

Returns 0.0 if no updates have been processed.

Source

pub fn equity_cagr(&self, periods_per_year: usize) -> Option<f64>

Compound Annual Growth Rate (CAGR) of equity.

CAGR = (current / initial) ^ (periods_per_year / update_count) - 1. Returns None if initial_equity is zero or non-positive, or fewer than 2 updates.

Source

pub fn is_recovering(&self) -> bool

Returns true when equity is below its peak but gained on the last update.

Source

pub fn drawdown_ratio(&self) -> Decimal

Current drawdown as a fraction of the worst recorded drawdown.

Returns Decimal::ZERO if no drawdown has been recorded yet.

Source

pub fn equity_multiple(&self) -> Decimal

Current equity as a multiple of initial equity (e.g., 1.5 = 50% gain).

Source

pub fn avg_gain_pct(&self) -> Option<f64>

Average per-update equity gain across all positive updates.

Uses win_rate and update_count to estimate the number of positive updates. Returns None if there have been no positive updates recorded.

Source

pub fn is_at_peak(&self) -> bool

Returns true if the current equity equals the peak (no drawdown).

Source

pub fn below_initial_equity(&self) -> bool

Returns true if the current equity is below the initial equity at construction.

Source

pub fn return_drawdown_ratio(&self) -> Option<f64>

Net return divided by max drawdown percentage (simplified Calmar-like ratio).

Returns None if max drawdown is zero or there are fewer than 2 updates.

Source

pub fn consecutive_flat_pct(&self) -> f64

Percentage of total updates where equity was unchanged (flat).

Returns 0.0 if no updates have been recorded.

Source

pub fn current_streak(&self) -> i64

Current consecutive streak length: positive = gains, negative = losses, 0 = flat.

Source

pub fn max_loss_pct_single(&self) -> Option<f64>

The single largest equity loss as a percentage of the equity at the time of the loss.

Returns None if no loss has been recorded (min_equity_delta >= 0).

Source

pub fn win_loss_ratio(&self) -> Option<f64>

Win rate divided by loss rate (win probability / loss probability).

Returns None if either rate is unavailable or loss rate is zero.

Source

pub fn best_drawdown_recovery(&self) -> Option<f64>

Max single gain percentage divided by worst drawdown percentage (reward/risk ratio).

Returns None if no drawdown or no gain has been recorded.

Source

pub fn recovery_count(&self) -> usize

Total number of completed drawdown recovery events.

Source

pub fn avg_gain_loss_ratio(&self) -> Option<f64>

Ratio of average gain to average loss per update.

Returns None if either average is unavailable or average loss is zero.

Source

pub fn time_to_recover_est(&self) -> Option<usize>

Estimated number of updates to recover from the current drawdown.

Based on average gain size and current distance from peak. Returns None if not in drawdown, no gain history, or average gain is zero.

Source

pub fn current_drawdown_absolute(&self) -> Decimal

Current distance of equity below the peak in absolute terms.

Source

pub fn median_drawdown_pct(drawdowns: &[Decimal]) -> Option<Decimal>

Median of a slice of drawdown percentages.

The input need not be sorted. Returns None if the slice is empty.

Source

pub fn sortino_ratio(returns: &[Decimal], target: Decimal) -> Option<f64>

Sortino ratio from a slice of period returns.

sortino = (mean_return - target) / downside_deviation

where downside deviation is the standard deviation of returns below target. Returns None if returns is empty or downside deviation is zero.

Source

pub fn returns_volatility( returns: &[Decimal], periods_per_year: u32, ) -> Option<f64>

Annualised volatility from a slice of period returns.

volatility = std_dev(returns) * sqrt(periods_per_year)

Returns None if returns has fewer than 2 elements.

Source

pub fn omega_ratio(returns: &[Decimal], threshold: Decimal) -> Option<f64>

Omega ratio: sum of returns above threshold / abs(sum of returns below threshold).

Values > 1 indicate more upside than downside relative to the threshold. Returns None if returns is empty or total downside is zero.

Source

pub fn information_ratio( returns: &[Decimal], benchmark: &[Decimal], ) -> Option<f64>

Information ratio: (mean(returns) - mean(benchmark)) / std_dev(returns - benchmark).

Measures risk-adjusted excess return over a benchmark. Returns None if fewer than 2 matched return pairs exist or tracking error is zero.

Source

pub fn annualized_volatility(&self, periods_per_year: u32) -> Option<f64>

Annualized volatility of equity changes: std_dev_of_changes * sqrt(periods_per_year).

Returns None if fewer than 2 updates have been recorded.

Source

pub fn pain_ratio(&self, annualized_return_pct: Decimal) -> Option<Decimal>

Pain ratio: annualized_return_pct / pain_index.

A higher ratio indicates better risk-adjusted performance relative to sustained drawdown. Returns None if the pain index is zero (no drawdowns).

Source

pub fn time_above_watermark_pct(&self) -> Decimal

Fraction of all updates where equity was at or above the peak (above water).

Complement of time_underwater_pct. Returns Decimal::ONE when no updates have been processed.

Source

pub fn equity_change_std_dev(&self) -> Option<f64>

Sample standard deviation of per-update equity changes.

Uses the Welford running variance accumulator. Returns None when fewer than 2 equity changes have been recorded.

Source

pub fn gain_streak_ratio(&self) -> Option<f64>

Ratio of the longest gain streak to total updates.

Higher values indicate equity spent a larger fraction of updates trending upward. Returns None when no updates have been processed.

Source§

impl DrawdownTracker

Source

pub fn gain_loss_asymmetry(&self) -> Option<f64>

Ratio of average equity gain per gain-update to average equity loss per loss-update.

Values > 1 mean average gains outsize average losses (positive asymmetry). Returns None if there are no recorded losses.

Source

pub fn streaks(&self) -> (usize, usize, usize, usize)

Returns (current_gain_streak, max_gain_streak, current_loss_streak, max_loss_streak).

A “gain streak” is a consecutive run of updates where equity increased. The tracker maintains gain_streak and max_drawdown_streak (loss streak).

Source

pub fn sharpe_proxy( &self, annualized_return: f64, periods_per_year: u32, ) -> Option<f64>

Quick Sharpe proxy: annualized_return / annualized_volatility(periods_per_year).

Uses the Welford-tracked equity change volatility maintained by the tracker. Returns None if volatility is unavailable or zero.

Source

pub fn max_consecutive_underwater(&self) -> usize

Longest single underwater streak in number of consecutive updates below peak.

Returns 0 if there have been no updates below peak.

Source

pub fn underwater_duration_avg(&self) -> Option<f64>

Average duration of underwater periods: drawdown_update_count / drawdown_count.

Returns None if there have been no drawdown periods.

Source

pub fn equity_efficiency(&self) -> f64

Equity efficiency: ratio of current equity to peak equity [0.0, 1.0].

A value of 1.0 means at the peak; values below 1.0 indicate drawdown depth.

Source

pub fn sortino_proxy( &self, annualized_return: f64, periods_per_year: u32, ) -> Option<f64>

Sortino-style proxy: annualized_return / downside_volatility.

Downside vol uses only negative equity changes in the Welford variance. Returns None if downside volatility is zero or unavailable.

Source

pub fn gain_loss_ratio(&self) -> Option<f64>

👎Deprecated since 2.1.0:

Use gain_to_loss_ratio instead

Ratio of cumulative gains to cumulative losses: total_gain_sum / total_loss_sum.

Alias for gain_to_loss_ratio.

Source

pub fn recovery_efficiency(&self) -> Option<f64>

Recovery efficiency: completed_recoveries / drawdown_count.

A ratio of 1.0 means every drawdown was fully recovered. Returns None if no drawdowns have occurred.

Source

pub fn drawdown_velocity(&self) -> Option<f64>

Rate of change of drawdown per update: current_drawdown_pct / updates_since_peak.

Returns None if at peak (no drawdown) or no updates have been counted.

Source

pub fn streak_win_rate(&self) -> Option<f64>

Fraction of streak length dominated by gains: max_gain_streak / (max_gain_streak + max_drawdown_streak).

Returns None if neither streak has been recorded.

Source

pub fn equity_change_std(&self) -> Option<f64>

👎Deprecated since 2.1.0:

Use equity_change_std_dev instead

Sample standard deviation of per-update equity changes (Welford online algorithm).

Alias for equity_change_std_dev.

Source

pub fn avg_loss_pct(&self) -> Option<f64>

Average loss per loss-update (absolute value). Returns None if no losses have been recorded.

Trait Implementations§

Source§

impl Clone for DrawdownTracker

Source§

fn clone(&self) -> DrawdownTracker

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 DrawdownTracker

Source§

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

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

impl<'de> Deserialize<'de> for DrawdownTracker

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 Display for DrawdownTracker

Source§

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

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

impl Serialize for DrawdownTracker

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> 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> 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> ToString for T
where T: Display + ?Sized,

Source§

fn to_string(&self) -> String

Converts the given value to a String. 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<T> DeserializeOwned for T
where T: for<'de> Deserialize<'de>,