From 7f72596461dbb3338031dd53497153632e149660 Mon Sep 17 00:00:00 2001 From: Thomas Schmelzer Date: Sat, 9 Nov 2024 14:36:54 +0800 Subject: [PATCH] sharpe for constant series (#428) * sharpe for constant series * fmt * address log warnings (#429) --- cvx/simulator/portfolio.py | 4 ++-- cvx/simulator/utils/metric.py | 13 ++++++++----- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/cvx/simulator/portfolio.py b/cvx/simulator/portfolio.py index 21a351d5..99dbfbe8 100644 --- a/cvx/simulator/portfolio.py +++ b/cvx/simulator/portfolio.py @@ -355,7 +355,7 @@ def snapshot( table.loc[label_strategy, "end"] = self.nav.index[-1].strftime("%Y-%m-%d") table.loc[label_strategy, "# assets"] = len(self.assets) - s = sharpe(self.nav.pct_change().dropna()) + s = sharpe(self.nav.ffill().pct_change(fill_method=None).dropna()) table.loc[label_strategy, "Sharpe ratio"] = f"{s:.2f}" if benchmark is not None: @@ -372,7 +372,7 @@ def snapshot( table_bench.loc[label_benchmark, "# assets"] = "" table_bench.loc[ label_benchmark, "Sharpe ratio" - ] = f"{sharpe(benchmark.pct_change().dropna()):.2f}" + ] = f"{sharpe(benchmark.ffill().pct_change(fill_method=None).dropna()):.2f}" table = pd.concat([table, table_bench], axis=0) diff --git a/cvx/simulator/utils/metric.py b/cvx/simulator/utils/metric.py index 75f9a01a..7a52bacb 100644 --- a/cvx/simulator/utils/metric.py +++ b/cvx/simulator/utils/metric.py @@ -1,5 +1,4 @@ -from math import sqrt - +import numpy as np import pandas as pd @@ -8,12 +7,16 @@ def _periods(ts): compute the number of periods in a time series """ series = pd.Series(data=ts.index) - return 365 * 24 * 60 * 60 / (series.diff().mean().total_seconds()) + return 365 * 24 * 60 * 60 / (series.diff().dropna().mean().total_seconds()) def sharpe(ts, n=None): """ compute the sharpe ratio of a time series """ - n = n or _periods(ts) - return ts.mean() / ts.std() * sqrt(n) + std = ts.std() + if std > 0: + n = n or _periods(ts) + return (ts.mean() / std) * np.sqrt(n) + else: + return np.inf