"""Advanced metrics.
Use :term:`Quantstats` library to calculate various metrics about the strategy performance.
This will generate metrics like:
- Sharpe
- Sortino
- Max drawdown
**Note**: These metrics are based on equity curve and returns - they do go down to the individual trade level.
Any consecutive wins and losses are measured in days, not in the trade or candle count.
"""
import enum
import warnings
import pandas as pd
from quantstats import stats
[docs]class AdvancedMetricsMode(enum.Enum):
"""What we will make quantstats to spit out."""
#: Less stats
basic = "basic"
#: More stats
full = "full"
[docs]def calculate_advanced_metrics(
returns: pd.Series,
mode: AdvancedMetricsMode=AdvancedMetricsMode.basic,
periods_per_year=365,
) -> pd.DataFrame:
"""Calculate advanced strategy performance statistics using Quantstats.
Calculates multiple metrics used to benchmark strategies for :term:`risk-adjusted returns`
in one go.
See :term:`Quantstats` for more information.
Example:
.. code-block:: python
from tradeexecutor.visual.equity_curve import calculate_equity_curve, calculate_returns
from tradeexecutor.analysis.advanced_metrics import calculate_advanced_metrics
equity = calculate_equity_curve(state)
returns = calculate_returns(equity)
metrics = calculate_advanced_metrics(returns)
# Each metric as a series. Index 0 is our performance,
# index 1 is the benchmark.
sharpe = metrics.loc["Sharpe"][0]
assert sharpe == pytest.approx(-1.73)
See also :py:func:`visualise_advanced_metrics`.
:param returns:
Returns series of the strategy.
See :py:`tradeeexecutor.visual.equity_curve.calculate_returns`.
:param mode:
Full or basic stats
:param periods_per_year:
How often the trade decision cycle was run.
This affects "trading periods per year" needed, to calculate
metrics like Sharpe.
The defaults to the daily trading cycle, trading 24/7.
:return:
DataFrame of metrics generated by quantstats.
You can directly display this in your notebook,
or extract individual metrics.
"""
# DeprecationWarning: Importing display from IPython.core.display is deprecated since IPython 7.14, please import from IPython display
with warnings.catch_warnings():
from quantstats.reports import metrics
result = metrics(returns, display=False, periods_per_year=periods_per_year, mode=mode.value)
# Hack - see analyse_combination()
result.loc["Annualised return (raw)"] = [stats.cagr(returns, 0., compounded=True)]
return result
[docs]def visualise_advanced_metrics(returns: pd.Series, mode: AdvancedMetricsMode=AdvancedMetricsMode.basic) -> pd.DataFrame:
"""Calculate advanced strategy performance statistics using Quantstats.
Calculates multiple metrics used to benchmark strategies for :term:`risk-adjusted returns`
in one go.
See :term:`Quantstats` for more information.
Example:
.. code-block:: python
from tradeexecutor.visual.equity_curve import calculate_equity_curve, calculate_returns
from tradeexecutor.analysis.advanced_metrics import visualise_advanced_metrics
equity = calculate_equity_curve(state)
returns = calculate_returns(equity)
df = visualise_advanced_metrics(returns)
display(df)
See also :py:func:`calculate_advanced_metrics`.
:param returns:
Returns series of the strategy.
See :py:`tradeeexecutor.visual.equity_curve.calculate_returns`.
:param mode:
Full or basic stats
:return:
A DataFrame ready to display
"""
# DeprecationWarning: Importing display from IPython.core.display is deprecated since IPython 7.14, please import from IPython display
with warnings.catch_warnings():
from quantstats.reports import metrics
# Internal sets the flag for percent output
df = metrics(returns, periods_per_year=365, mode=mode.value, internal=True, display=False)
return df