Skip to content

Commit

Permalink
table (#326)
Browse files Browse the repository at this point in the history
  • Loading branch information
tschm authored Jan 15, 2024
1 parent 8841369 commit beaa763
Show file tree
Hide file tree
Showing 11 changed files with 104 additions and 27 deletions.
99 changes: 86 additions & 13 deletions cvx/simulator/portfolio.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import plotly.graph_objects as go
from plotly.subplots import make_subplots

from cvx.simulator.utils.metric import sharpe
from cvx.simulator.utils.rescale import returns2prices


Expand Down Expand Up @@ -246,6 +247,7 @@ def snapshot(
self,
benchmark: Any = None,
title: str = "Portfolio Summary",
table: pd.DataFrame = None,
aggregate: bool = False,
log_scale: bool = False,
label_strategy: str = "Strategy",
Expand All @@ -255,34 +257,49 @@ def snapshot(
The snapshot method creates a snapshot of the performance of a Portfolio object.
"""
fig = make_subplots(
rows=3,
rows=4,
cols=1,
shared_xaxes=True,
vertical_spacing=0.01,
row_heights=[0.6, 0.2, 0.2],
row_heights=[0.13, 0.47, 0.2, 0.2],
specs=[
[{"type": "table"}],
[{"type": "scatter"}],
[{"type": "scatter"}],
[{"type": "bar"}],
],
)

# NAV
# fig = make_subplots(
# rows=3, cols=1,
# shared_xaxes=True,
# vertical_spacing=0.03,
# specs=[[{"type": "table"}],
# [{"type": "scatter"}],
# [{"type": "scatter"}]]
# )

# display the NAV
fig.add_trace(
go.Scatter(x=self.nav.index, y=self.nav, name=label_strategy), row=1, col=1
go.Scatter(x=self.nav.index, y=self.nav, name=label_strategy), row=2, col=1
)

# change the title of the yaxis
fig.update_yaxes(title_text="Cumulative Return", row=1, col=1)
fig.update_yaxes(title_text="Cumulative Return", row=2, col=1)

# change yaxis to log scale
if log_scale:
fig.update_yaxes(type="log", row=1, col=1)
fig.update_yaxes(type="log", row=2, col=1)

# Drawdown data
fig.add_trace(
go.Scatter(
x=self.drawdown.index, y=-self.drawdown, name="Drawdown", fill="tozeroy"
),
row=2,
row=3,
col=1,
)
fig.update_yaxes(title_text="Drawdown", row=2, col=1)
fig.update_yaxes(title_text="Drawdown", row=3, col=1)

# Daily/Monthly Returns
if aggregate:
Expand All @@ -301,10 +318,10 @@ def snapshot(
marker_color=df["color"],
name="Monthly Returns",
),
row=3,
row=4,
col=1,
)
fig.update_yaxes(title_text="Monthly Returns", row=3, col=1)
fig.update_yaxes(title_text="Monthly Returns", row=4, col=1)

else:
returns = 100 * self.nav.pct_change().dropna()
Expand All @@ -319,21 +336,77 @@ def snapshot(
marker_color=df["color"],
name="Daily Returns",
),
row=3,
row=4,
col=1,
)
fig.update_yaxes(title_text="Daily Returns", row=3, col=1)
fig.update_yaxes(title_text="Daily Returns", row=4, col=1)

fig.update_traces(showlegend=True)
fig.update_layout(height=800, title_text=title)

if benchmark is not None:
fig.add_trace(
go.Scatter(x=benchmark.index, y=benchmark.values, name=label_benchmark),
row=1,
row=2,
col=1,
)

if table is None:
table = pd.DataFrame(
index=[label_strategy],
columns=["start", "end", "# assets", "Sharpe ratio"],
)
table.index.name = "Portfolio"

table["start"][label_strategy] = self.nav.index[0].strftime("%Y-%m-%d")
table["end"][label_strategy] = self.nav.index[-1].strftime("%Y-%m-%d")
# table["start"][label_benchmark] = benchmark.index[0].strftime("%Y-%m-%d")
# table["end"][label_benchmark] = benchmark.index[-1].strftime("%Y-%m-%d")
table["# assets"][label_strategy] = len(self.assets)
# table['# assets'][label_benchmark] =
table["Sharpe ratio"][label_strategy] = sharpe(
self.nav.pct_change().dropna()
)
# table["Sharpe ratio"][label_benchmark] = sharpe(benchmark.pct_change().dropna())

if benchmark is not None:
table_bench = pd.DataFrame(
index=[label_benchmark],
columns=["start", "end", "# assets", "Sharpe ratio"],
)
table_bench["start"][label_benchmark] = benchmark.index[0].strftime(
"%Y-%m-%d"
)
table_bench["end"][label_benchmark] = benchmark.index[-1].strftime(
"%Y-%m-%d"
)
table_bench["# assets"][label_benchmark] = ""
table_bench["Sharpe ratio"][label_benchmark] = sharpe(
benchmark.pct_change().dropna()
)

table = pd.concat([table, table_bench], axis=0)

table = table.reset_index()

# print(table)
# assert False

# if table is not None:
fig.add_trace(
go.Table(
header=dict(
values=list(table.columns), font=dict(size=10), align="left"
),
cells=dict(
values=[table[column].values for column in table.columns],
align="left",
),
),
row=1,
col=1,
)

return fig

@classmethod
Expand Down
8 changes: 8 additions & 0 deletions cvx/simulator/utils/metric.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
from math import sqrt


def sharpe(ts, n=252):
"""
compute the sharpe ratio of a time series
"""
return ts.mean() / ts.std() * sqrt(n)
5 changes: 0 additions & 5 deletions tests/test_applications/conftest.py
Original file line number Diff line number Diff line change
@@ -1,17 +1,12 @@
"""global fixtures"""
from __future__ import annotations

from math import sqrt
from pathlib import Path

import pandas as pd
import pytest


def sharpe(x, n=252):
return x.mean() * sqrt(n) / x.std()


@pytest.fixture(scope="session", name="resource_dir")
def resource_fixture():
"""resource fixture"""
Expand Down
2 changes: 1 addition & 1 deletion tests/test_applications/test_cta.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

from cvx.simulator.builder import Builder
from cvx.simulator.utils.interpolation import interpolate
from tests.test_applications.conftest import sharpe
from cvx.simulator.utils.metric import sharpe


@pytest.fixture()
Expand Down
2 changes: 1 addition & 1 deletion tests/test_applications/test_portfolios.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import pytest

from cvx.simulator.builder import Builder
from tests.test_applications.conftest import sharpe
from cvx.simulator.utils.metric import sharpe


@pytest.fixture()
Expand Down
2 changes: 1 addition & 1 deletion tests/test_applications/test_talk/test_experiment1.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
import pytest

from cvx.simulator.portfolio import Portfolio
from tests.test_applications.conftest import sharpe
from cvx.simulator.utils.metric import sharpe


# take two moving averages and apply sign-function
Expand Down
2 changes: 1 addition & 1 deletion tests/test_applications/test_talk/test_experiment2.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
import pytest

from cvx.simulator.portfolio import Portfolio
from tests.test_applications.conftest import sharpe
from cvx.simulator.utils.metric import sharpe


# take two moving averages and apply the sign-function, adjust by volatility
Expand Down
2 changes: 1 addition & 1 deletion tests/test_applications/test_talk/test_experiment3.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
from tinycta.signal import osc, returns_adjust

from cvx.simulator.portfolio import Portfolio
from tests.test_applications.conftest import sharpe
from cvx.simulator.utils.metric import sharpe


# take two moving averages and apply the sign-function, adjust by volatility
Expand Down
2 changes: 1 addition & 1 deletion tests/test_applications/test_talk/test_experiment4.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
from tinycta.signal import osc, returns_adjust

from cvx.simulator.portfolio import Portfolio
from tests.test_applications.conftest import sharpe
from cvx.simulator.utils.metric import sharpe


# take two moving averages and apply the sign-function, adjust by volatility
Expand Down
2 changes: 1 addition & 1 deletion tests/test_applications/test_talk/test_experiment5.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
from tinycta.signal import osc, returns_adjust, shrink2id

from cvx.simulator.builder import Builder
from tests.test_applications.conftest import sharpe
from cvx.simulator.utils.metric import sharpe

correlation = 200

Expand Down
5 changes: 3 additions & 2 deletions tests/test_portfolio.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import pytest

from cvx.simulator.portfolio import Portfolio
from tests.test_applications.conftest import sharpe
from cvx.simulator.utils.metric import sharpe


@pytest.fixture()
Expand Down Expand Up @@ -137,7 +137,8 @@ def test_monotonic():

def test_snapshot(portfolio):
xxx = pd.Series(index=portfolio.index, data=0.0)
portfolio.snapshot(benchmark=xxx)
fig = portfolio.snapshot(benchmark=xxx)
fig.show()


def test_snapshot_no_benchmark(portfolio):
Expand Down

0 comments on commit beaa763

Please sign in to comment.