Skip to content

Commit

Permalink
refactor: format code with black
Browse files Browse the repository at this point in the history
  • Loading branch information
chilango74 committed Apr 20, 2022
1 parent bfa528c commit 8e3587f
Show file tree
Hide file tree
Showing 26 changed files with 1,231 additions and 586 deletions.
2 changes: 1 addition & 1 deletion docs/requirements.txt
Expand Up @@ -6,4 +6,4 @@ nbsphinx-link>=1.3.0
pandoc>=1.1.0
recommonmark==0.7.1
ipython>=7.20.0
jinja2<3.1
jinja2<3.0.0
2 changes: 1 addition & 1 deletion okama/__init__.py
Expand Up @@ -39,4 +39,4 @@
from okama.common.helpers.helpers import Float, Frame, Rebalance, Date
import okama.settings

__version__ = version('okama')
__version__ = version("okama")
15 changes: 10 additions & 5 deletions okama/api/api_methods.py
Expand Up @@ -9,6 +9,7 @@ class API:
"""
Set of methods to get data from API.
"""

# TODO: introduce 'from' & 'to' for dates.

api_url = "http://api.okama.io:5000"
Expand Down Expand Up @@ -39,20 +40,24 @@ def connect(
period: str = "d",
) -> str:
session = requests.session()
retry_strategy = Retry(total=3,
backoff_factor=0.1,
status_forcelist=[429, 500, 502, 503, 504])
retry_strategy = Retry(
total=3, backoff_factor=0.1, status_forcelist=[429, 500, 502, 503, 504]
)
adapter = HTTPAdapter(max_retries=retry_strategy)
request_url = cls.api_url + endpoint + symbol
params = {"first_date": first_date, "last_date": last_date, "period": period}
session.mount("https://", adapter)
session.mount("http://", adapter)
try:
r = session.get(request_url, params=params, verify=False, timeout=cls.default_timeout)
r = session.get(
request_url, params=params, verify=False, timeout=cls.default_timeout
)
r.raise_for_status()
except requests.exceptions.HTTPError as errh:
if r.status_code == 404:
raise requests.exceptions.HTTPError(f"{symbol} is not found in the database.", 404) from errh
raise requests.exceptions.HTTPError(
f"{symbol} is not found in the database.", 404
) from errh
raise requests.exceptions.HTTPError(
f"HTTP error fetching data for {symbol}:",
r.status_code,
Expand Down
4 changes: 3 additions & 1 deletion okama/api/data_queries.py
Expand Up @@ -110,7 +110,9 @@ def get_adj_close(

@staticmethod
def get_dividends(
symbol: str, first_date: str = "1913-01-01", last_date: str = "2100-01-01",
symbol: str,
first_date: str = "1913-01-01",
last_date: str = "2100-01-01",
) -> pd.Series:
"""
Dividends time series daily data (dividend payment day should be considered).
Expand Down
8 changes: 5 additions & 3 deletions okama/api/namespaces.py
Expand Up @@ -14,13 +14,15 @@ def get_namespaces():


@lru_cache()
def symbols_in_namespace(namespace: str = settings.default_namespace, response_format: str = 'frame') -> pd.DataFrame:
def symbols_in_namespace(
namespace: str = settings.default_namespace, response_format: str = "frame"
) -> pd.DataFrame:
string_response = api_methods.API.get_symbols_in_namespace(namespace.upper())
list_of_symbols = json.loads(string_response)
if response_format.lower() == 'frame':
if response_format.lower() == "frame":
df = pd.DataFrame(list_of_symbols[1:], columns=list_of_symbols[0])
return df.astype("string", copy=False)
elif response_format.lower() == 'json':
elif response_format.lower() == "json":
return list_of_symbols
else:
raise ValueError('response_format must be "json" or "frame"')
Expand Down
20 changes: 11 additions & 9 deletions okama/api/search.py
Expand Up @@ -8,27 +8,29 @@


@lru_cache()
def search(search_string: str, namespace: Optional[str] = None, response_format: str = 'frame') -> json:
def search(
search_string: str, namespace: Optional[str] = None, response_format: str = "frame"
) -> json:
# search for string in a single namespace
if namespace:
df = namespaces.symbols_in_namespace(namespace.upper())
condition1 = df['name'].str.contains(search_string, case=False)
condition2 = df['ticker'].str.contains(search_string, case=False)
condition3 = df['isin'].str.contains(search_string, case=False)
condition1 = df["name"].str.contains(search_string, case=False)
condition2 = df["ticker"].str.contains(search_string, case=False)
condition3 = df["isin"].str.contains(search_string, case=False)
frame_response = df[condition1 | condition2 | condition3]
if response_format.lower() == 'frame':
if response_format.lower() == "frame":
return frame_response
elif response_format.lower() == 'json':
return frame_response.to_json(orient='records')
elif response_format.lower() == "json":
return frame_response.to_json(orient="records")
else:
raise ValueError('response_format must be "json" or "frame"')
# search for string in all namespaces
string_response = api_methods.API.search(search_string)
json_response = json.loads(string_response)
if response_format.lower() == 'frame':
if response_format.lower() == "frame":
df = pd.DataFrame(json_response[1:], columns=json_response[0])
return df
elif response_format.lower() == 'json':
elif response_format.lower() == "json":
return json_response
else:
raise ValueError('response_format must be "json" or "frame"')
4 changes: 2 additions & 2 deletions okama/asset.py
Expand Up @@ -105,7 +105,7 @@ def close_daily(self):
Series
Time series of close price historical data (daily).
"""
return data_queries.QueryData.get_close(self.symbol, period='D')
return data_queries.QueryData.get_close(self.symbol, period="D")

@property
def close_monthly(self):
Expand Down Expand Up @@ -142,7 +142,7 @@ def adj_close(self):
Series
Time series of adjusted close price historical data (daily).
"""
return data_queries.QueryData.get_adj_close(self.symbol, period='D')
return data_queries.QueryData.get_adj_close(self.symbol, period="D")

@property
def dividends(self) -> pd.Series:
Expand Down
102 changes: 73 additions & 29 deletions okama/asset_list.py
Expand Up @@ -218,7 +218,7 @@ def semideviation_annual(self) -> pd.Series:
SHV.US 0.000560
dtype: float64
"""
return helpers.Frame.get_semideviation(self.assets_ror) * 12 ** 0.5
return helpers.Frame.get_semideviation(self.assets_ror) * 12**0.5

def get_var_historic(self, time_frame: int = 12, level: int = 1) -> pd.Series:
"""
Expand Down Expand Up @@ -365,14 +365,16 @@ def recovery_periods(self) -> pd.Series:
max_recovery_periods = pd.Series(dtype=int)
for name in self.symbols:
namespace = name.split(".", 1)[-1]
if namespace == 'INFL':
if namespace == "INFL":
continue
s = growth[name]
s1 = s.where(s == 0).notnull().astype(int)
s1_1 = s.where(s == 0).isnull().astype(int).cumsum()
s2 = s1.groupby(s1_1).cumsum()
# Max recovery period date should not be in the border (it's not recovered)
max_period = s2.max() if s2.idxmax().to_timestamp() != self.last_date else np.NAN
max_period = (
s2.max() if s2.idxmax().to_timestamp() != self.last_date else np.NAN
)
ser = pd.Series(max_period, index=[name])
max_recovery_periods = pd.concat([max_recovery_periods, ser])
return max_recovery_periods
Expand Down Expand Up @@ -491,7 +493,9 @@ def get_rolling_cagr(self, window: int = 12, real: bool = False) -> pd.DataFrame
df = self._add_inflation()
if real:
df = self._make_real_return_time_series(df)
return helpers.Frame.get_rolling_fn(df, window=window, fn=helpers.Frame.get_cagr)
return helpers.Frame.get_rolling_fn(
df, window=window, fn=helpers.Frame.get_cagr
)

def get_cumulative_return(
self, period: Union[str, int, None] = None, real: bool = False
Expand Down Expand Up @@ -553,7 +557,9 @@ def get_cumulative_return(
"Real cumulative return is not defined (no inflation information is available)."
"Set inflation=True in AssetList to calculate it."
)
cumulative_inflation = helpers.Frame.get_cumulative_return(self.inflation_ts[dt:])
cumulative_inflation = helpers.Frame.get_cumulative_return(
self.inflation_ts[dt:]
)
cr = (1.0 + cr) / (1.0 + cumulative_inflation) - 1.0
cr.drop(self.inflation, inplace=True)
return cr
Expand Down Expand Up @@ -602,7 +608,10 @@ def get_rolling_cumulative_return(
if real:
df = self._make_real_return_time_series(df)
return helpers.Frame.get_rolling_fn(
df, window=window, fn=helpers.Frame.get_cumulative_return, window_below_year=True
df,
window=window,
fn=helpers.Frame.get_cumulative_return,
window_below_year=True,
)

@property
Expand Down Expand Up @@ -692,7 +701,9 @@ def describe(
ytd_return = self.get_cumulative_return(period="YTD")
row = ytd_return.to_dict()
row.update(period="YTD", property="Compound return")
description = pd.concat([description, pd.DataFrame(row, index=[0])], ignore_index=True)
description = pd.concat(
[description, pd.DataFrame(row, index=[0])], ignore_index=True
)
# CAGR for a list of periods
if self.pl.years >= 1:
for i in years:
Expand All @@ -702,32 +713,46 @@ def describe(
else:
row = {x: None for x in df.columns}
row.update(period=f"{i} years", property="CAGR")
description = pd.concat([description, pd.DataFrame(row, index=[0])], ignore_index=True)
description = pd.concat(
[description, pd.DataFrame(row, index=[0])], ignore_index=True
)
# CAGR for full period
row = self.get_cagr(period=None).to_dict()
row.update(period=self._pl_txt, property="CAGR")
description = pd.concat([description, pd.DataFrame(row, index=[0])], ignore_index=True)
description = pd.concat(
[description, pd.DataFrame(row, index=[0])], ignore_index=True
)
# Dividend Yield
row = self.assets_dividend_yield.iloc[-1].to_dict()
row.update(period="LTM", property="Dividend yield")
description = pd.concat([description, pd.DataFrame(row, index=[0])], ignore_index=True)
description = pd.concat(
[description, pd.DataFrame(row, index=[0])], ignore_index=True
)
# risk for full period
row = self.risk_annual.to_dict()
row.update(period=self._pl_txt, property="Risk")
description = pd.concat([description, pd.DataFrame(row, index=[0])], ignore_index=True)
description = pd.concat(
[description, pd.DataFrame(row, index=[0])], ignore_index=True
)
# CVAR
if self.pl.years >= 1:
row = self.get_cvar_historic().to_dict()
row.update(period=self._pl_txt, property="CVAR")
description = pd.concat([description,pd.DataFrame(row, index=[0])], ignore_index=True)
description = pd.concat(
[description, pd.DataFrame(row, index=[0])], ignore_index=True
)
# max drawdowns
row = self.drawdowns.min().to_dict()
row.update(period=self._pl_txt, property="Max drawdowns")
description = pd.concat([description, pd.DataFrame(row, index=[0])], ignore_index=True)
description = pd.concat(
[description, pd.DataFrame(row, index=[0])], ignore_index=True
)
# max drawdowns dates
row = self.drawdowns.idxmin().to_dict()
row.update(period=self._pl_txt, property="Max drawdowns dates")
description = pd.concat([description, pd.DataFrame(row, index=[0])], ignore_index=True)
description = pd.concat(
[description, pd.DataFrame(row, index=[0])], ignore_index=True
)
# inception dates
row = {}
for ti in self.symbols:
Expand All @@ -737,7 +762,9 @@ def describe(
row.update(period=None, property="Inception date")
if hasattr(self, "inflation"):
row.update({self.inflation: self.inflation_first_date.strftime("%Y-%m")})
description = pd.concat([description, pd.DataFrame(row, index=[0])], ignore_index=True)
description = pd.concat(
[description, pd.DataFrame(row, index=[0])], ignore_index=True
)
# last asset date
row = {}
for ti in self.symbols:
Expand All @@ -747,11 +774,15 @@ def describe(
row.update(period=None, property="Last asset date")
if hasattr(self, "inflation"):
row.update({self.inflation: self.inflation_last_date.strftime("%Y-%m")})
description = pd.concat([description, pd.DataFrame(row, index=[0])], ignore_index=True)
description = pd.concat(
[description, pd.DataFrame(row, index=[0])], ignore_index=True
)
# last data date
row = {x: self.last_date.strftime("%Y-%m") for x in df.columns}
row.update(period=None, property="Common last data date")
description = pd.concat([description, pd.DataFrame(row, index=[0])], ignore_index=True)
description = pd.concat(
[description, pd.DataFrame(row, index=[0])], ignore_index=True
)
# rename columns
if hasattr(self, "inflation"):
description.rename(columns={self.inflation: "inflation"}, inplace=True)
Expand Down Expand Up @@ -929,7 +960,9 @@ def get_dividend_mean_growth_rate(self, period=5) -> pd.Series:
growth_ts = self.dividends_annual.pct_change().iloc[
1:-1
] # Slice the last year for full dividends
growth_ts.replace([np.inf, -np.inf, np.nan], 0, inplace=True) # replace possible nan and inf
growth_ts.replace(
[np.inf, -np.inf, np.nan], 0, inplace=True
) # replace possible nan and inf
dt0 = self.last_date
dt = helpers.Date.subtract_years(dt0, period)
return ((growth_ts[dt:] + 1.0).prod()) ** (1 / period) - 1.0
Expand Down Expand Up @@ -1011,12 +1044,12 @@ def tracking_difference_annual(self) -> pd.DataFrame:
>>> al.tracking_difference_annual.plot(kind='bar')
"""
result = pd.DataFrame()
for x in self.assets_ror.resample('Y'):
for x in self.assets_ror.resample("Y"):
df = x[1]
wealth_index = helpers.Frame.get_wealth_indexes(df)
row = helpers.Index.tracking_difference(wealth_index).iloc[[-1]]
result = pd.concat([result, row], ignore_index=False)
result.index = result.index.asfreq('Y')
result.index = result.index.asfreq("Y")
return result

@property
Expand Down Expand Up @@ -1390,11 +1423,14 @@ def get_sharpe_ratio(self, rf_return: float = 0) -> pd.Series:
BND.US 0.390814
dtype: float64
"""
mean_return = self.mean_return.drop(self.inflation) if self.inflation else self.mean_return
mean_return = (
self.mean_return.drop(self.inflation)
if self.inflation
else self.mean_return
)
return ratios.get_sharpe_ratio(
pf_return=mean_return,
rf_return=rf_return,
std_deviation=self.risk_annual)
pf_return=mean_return, rf_return=rf_return, std_deviation=self.risk_annual
)

def get_sortino_ratio(self, t_return: float = 0) -> pd.Series:
"""
Expand All @@ -1421,9 +1457,17 @@ def get_sortino_ratio(self, t_return: float = 0) -> pd.Series:
BND.US 0.028969
dtype: float64
"""
mean_return = self.mean_return.drop(self.inflation) if self.inflation else self.mean_return
semideviation = helpers.Frame.get_below_target_semideviation(ror=self.assets_ror, t_return=t_return) * 12 ** 0.5
mean_return = (
self.mean_return.drop(self.inflation)
if self.inflation
else self.mean_return
)
semideviation = (
helpers.Frame.get_below_target_semideviation(
ror=self.assets_ror, t_return=t_return
)
* 12**0.5
)
return ratios.get_sortino_ratio(
pf_return=mean_return,
t_return=t_return,
semi_deviation=semideviation)
pf_return=mean_return, t_return=t_return, semi_deviation=semideviation
)

0 comments on commit 8e3587f

Please sign in to comment.