Source code for fynance.backtest.result
#!/usr/bin/env python3
# coding: utf-8
""" Backtest result value object.
:class:`BacktestResult` is the engine's output and the hand-off to metrics and
reporting. It holds numpy arrays and computes a standard performance summary.
"""
from __future__ import annotations
# Built-in packages
from dataclasses import dataclass
# Third-party packages
import numpy as np
from numpy.typing import NDArray
# Local packages
from fynance.core import PriceSeries
__all__ = ['BacktestResult']
[docs]
@dataclass
class BacktestResult:
""" Output of :func:`~fynance.backtest.engine.backtest`.
Attributes
----------
equity : numpy.ndarray
Equity curve.
returns : numpy.ndarray
Net strategy returns (after costs).
gross_returns : numpy.ndarray
Strategy returns before costs.
positions : numpy.ndarray
Position/weight book used.
costs : numpy.ndarray
Per-step transaction costs.
index : numpy.ndarray, optional
Temporal index carried from the input.
"""
equity: NDArray
returns: NDArray
gross_returns: NDArray
positions: NDArray
costs: NDArray
index: NDArray | None = None
[docs]
def to_numpy(self) -> NDArray:
""" Return the equity curve as a numpy array. """
return np.asarray(self.equity)
[docs]
def to_price_series(self) -> PriceSeries:
""" Return the equity curve as a :class:`PriceSeries`. """
return PriceSeries(self.equity, index=self.index, name="equity")
[docs]
def summary(self, period: int = 252) -> dict[str, float]:
""" Standard performance summary.
Delegates the risk-adjusted ratios and drawdown to
:func:`fynance.metrics.summary` (computed on the equity curve) and adds
the hit-rate and total transaction cost from the strategy's own data.
"""
from fynance.metrics import summary as _metric_summary
out = _metric_summary(self.equity, period=period)
r = self.returns[~np.isnan(self.returns)]
out["hit_rate"] = float((r > 0).mean()) if r.size else 0.0
out["total_cost"] = float(np.nansum(self.costs))
return out