Skip to content

Commit

Permalink
feat: add Sharpe ratio to Portfolio and helpers
Browse files Browse the repository at this point in the history
  • Loading branch information
chilango74 committed Oct 4, 2021
1 parent 5023222 commit 2cbe4da
Show file tree
Hide file tree
Showing 13 changed files with 54 additions and 12 deletions.
4 changes: 3 additions & 1 deletion main.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import okama as ok

print(ok.search('aeroflot', namespace='MOEX', response_format='frame'))
x = ok.Portfolio(['SPY.US', 'BND.US'], weights=[0.5, 0.5], ccy='RUB')

print(x.get_sharpe_ratio(rf_return=0.07))
2 changes: 1 addition & 1 deletion okama/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
macro_namespaces,
symbols_in_namespace,
)
from okama.common.helpers import Float, Frame, Rebalance, Date
from okama.common.helpers.helpers import Float, Frame, Rebalance, Date
import okama.settings

__version__ = "1.0.2"
2 changes: 1 addition & 1 deletion okama/asset.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import pandas as pd
import numpy as np

from .common.helpers import Frame
from .common.helpers.helpers import Frame
from .settings import default_ticker
from .api.data_queries import QueryData
from .api.namespaces import get_assets_namespaces
Expand Down
2 changes: 1 addition & 1 deletion okama/asset_list.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import numpy as np
import pandas as pd

from .common.helpers import Frame, Float, Date, Index
from .common.helpers.helpers import Frame, Float, Date, Index
from .common.make_asset_list import ListMaker


Expand Down
Empty file.
4 changes: 2 additions & 2 deletions okama/common/helpers.py → okama/common/helpers/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
import numpy as np
import scipy.stats

from ..settings import _MONTHS_PER_YEAR
from okama.settings import _MONTHS_PER_YEAR


def check_rolling_window(
Expand Down Expand Up @@ -580,7 +580,7 @@ def tracking_difference(accumulated_return: pd.DataFrame) -> pd.DataFrame:
@staticmethod
def tracking_difference_annualized(tracking_diff: pd.DataFrame) -> pd.DataFrame:
"""
Annualizes the values of tracking difference time series.
Annualize the values of tracking difference time series.
Annual values are available for periods of more than 12 months.
Returns for less than 12 months can't be annualized.
"""
Expand Down
8 changes: 8 additions & 0 deletions okama/common/helpers/rates.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
"""Portfolio rates"""


def get_sharpe_ratio(pf_return: float, rf_return: float, std_deviation: float) -> float:
"""
Calculate Sharpe ratio.
"""
return (pf_return - rf_return) / std_deviation
2 changes: 1 addition & 1 deletion okama/frontier/multi_period.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
from scipy.optimize import minimize

from .. import AssetList
from ..common.helpers import Float, Frame, Rebalance
from ..common.helpers.helpers import Float, Frame, Rebalance
from ..settings import _MONTHS_PER_YEAR


Expand Down
4 changes: 2 additions & 2 deletions okama/frontier/single_period.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
from typing import Optional, Tuple, Dict, List, Union
from typing import Optional, Tuple, Dict, List

import pandas as pd
import numpy as np

from scipy.optimize import minimize

from .. import AssetList
from ..common.helpers import Float, Frame
from ..common.helpers.helpers import Float, Frame


class EfficientFrontier(AssetList):
Expand Down
2 changes: 1 addition & 1 deletion okama/macro.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

from .api.data_queries import QueryData
from .api.namespaces import get_macro_namespaces
from .common.helpers import Float, Frame, Date
from .common.helpers.helpers import Float, Frame, Date
from .settings import default_macro, PeriodLength, _MONTHS_PER_YEAR


Expand Down
2 changes: 1 addition & 1 deletion okama/plots.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
from matplotlib import pyplot as plt

from .asset_list import AssetList
from .common.helpers import Float
from .common.helpers.helpers import Float
from .frontier.single_period import EfficientFrontier
from .settings import default_ticker

Expand Down
30 changes: 29 additions & 1 deletion okama/portfolio.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@
import scipy.stats
from matplotlib import pyplot as plt

from .common.helpers import Frame, Rebalance, Float, Date
from .common.helpers.helpers import Frame, Rebalance, Float, Date
from .common.helpers import rates
from .common.make_asset_list import ListMaker
from .common.validators import validate_real
from .settings import _MONTHS_PER_YEAR
Expand Down Expand Up @@ -1867,6 +1868,33 @@ def kstest(self, distr: str = "norm") -> Dict[str, float]:
"""
return Frame.kstest_series(self.ror, distr=distr)

def get_sharpe_ratio(self, rf_return: float = 0) -> float:
"""
Calculate Sharpe ratio.
The Sharpe ratio is the average annual return in excess of the risk-free rate
per unit of risk (annualized standard deviation).
Parameters
----------
rf_return : float, default 0
Risk-free rate of return.
Returns
-------
float
Examples
--------
>>> pf = ok.Portfolio(['VOO.US', 'BND.US'], weights=[0.40, 0.60])
>>> pf.get_sharpe_ratio(rf_return=0.04)
0.7412193684695373
"""
return rates.get_sharpe_ratio(
pf_return=self.mean_return_annual,
rf_return=rf_return,
std_deviation=self.risk_annual)

def plot_percentiles_fit(
self, distr: str = "norm", figsize: Optional[tuple] = None
) -> None:
Expand Down
4 changes: 4 additions & 0 deletions tests/test_portfolio.py
Original file line number Diff line number Diff line change
Expand Up @@ -313,6 +313,10 @@ def test_jarque_bera(portfolio_rebalanced_month):
)


def test_get_sharpe_ratio(portfolio_no_inflation):
assert portfolio_no_inflation.get_sharpe_ratio(rf_return=0.05) == approx(0.631, rel=1e-2)


# This test should be a last one, as it changes the weights
def test_init_portfolio_failing():
with pytest.raises(
Expand Down

0 comments on commit 2cbe4da

Please sign in to comment.