Skip to content

Commit 54d3f23

Browse files
committed
chore: check if an asset has historical data period too short (ListMaker)
1 parent d80ac74 commit 54d3f23

File tree

6 files changed

+34
-53
lines changed

6 files changed

+34
-53
lines changed

main.py

Lines changed: 3 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,41 +1,6 @@
11
import okama as ok
22

3-
tk = ['VCIT.US',
4-
'VTIP.US',
5-
'TIP.US',
6-
'SCHP.US',
7-
'FXRU.MOEX',
8-
'HACK.US',
9-
'JETS.US',
10-
'XAR.US',
11-
'QQQ.US',
12-
'VBR.US',
13-
'VBK.US',
14-
'PGJ.US',
15-
'VOO.US',
16-
'IHAK.US',
17-
'VNQ.US',
18-
'SLV.US',
19-
'GLDM.US']
3+
tk = ['FXGD.MOEX', 'FXRD.MOEX']
4+
al = ok.AssetList(assets=tk, ccy='USD', inflation=True, last_date='2021-10')
205

21-
wt = [0.14,
22-
0.13,
23-
0.03,
24-
0.29,
25-
0.05,
26-
0.03,
27-
0.01,
28-
0.01,
29-
0.01,
30-
0.04,
31-
0.03,
32-
0.01,
33-
0.02,
34-
0.02,
35-
0.03,
36-
0.03,
37-
0.12]
38-
39-
pf = ok.Portfolio(assets=tk, weights=wt, ccy='USD', inflation=True)
40-
41-
print(pf.dividend_yield)
6+
print(al.wealth_indexes)

okama/asset.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
import numpy as np
55

66
from .common.helpers.helpers import Frame
7-
from .settings import default_ticker
7+
from .settings import default_ticker, PeriodLength, _MONTHS_PER_YEAR
88
from .api.data_queries import QueryData
99
from .api.namespaces import get_assets_namespaces
1010

@@ -31,6 +31,10 @@ def __init__(self, symbol: str = default_ticker):
3131
self.period_length: float = round(
3232
(self.last_date - self.first_date) / np.timedelta64(365, "D"), ndigits=1
3333
)
34+
self.pl = PeriodLength(
35+
self.ror.shape[0] // _MONTHS_PER_YEAR,
36+
self.ror.shape[0] % _MONTHS_PER_YEAR,
37+
)
3438

3539
def __repr__(self):
3640
dic = {

okama/common/helpers/helpers.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -554,6 +554,10 @@ def subtract_years(dt: pd.Timestamp, years: int) -> pd.Timestamp:
554554
raise TypeError("The period should be integer")
555555
return new_dt
556556

557+
@staticmethod
558+
def get_difference_in_months(last_day: pd.Timestamp, first_day: pd.Timestamp):
559+
return last_day.to_period('M') - first_day.to_period('M')
560+
557561

558562
class Index:
559563
@staticmethod

okama/common/make_asset_list.py

Lines changed: 18 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
import matplotlib.pyplot as plt
77

88
from .validators import validate_integer
9-
from ..common.helpers.helpers import Frame, Float
9+
from ..common.helpers.helpers import Frame, Float, Date
1010
from ..macro import Inflation
1111
from ..asset import Asset
1212
from ..settings import default_ticker, PeriodLength, _MONTHS_PER_YEAR
@@ -61,7 +61,7 @@ def __init__(
6161
self.assets_first_dates,
6262
self.assets_last_dates,
6363
self.assets_ror,
64-
) = self._make_list(ls=self._list_of_asset_like_objects).values()
64+
) = self._make_list(ls=self._list_of_asset_like_objects, first_date=first_date, last_date=last_date).values()
6565
if first_date:
6666
self.first_date = max(self.first_date, pd.to_datetime(first_date))
6767
self.assets_ror = self.assets_ror[self.first_date:]
@@ -101,7 +101,7 @@ def __repr__(self):
101101
def __len__(self):
102102
return len(self.symbols)
103103

104-
def _make_list(self, ls: list) -> dict:
104+
def _make_list(self, ls: list, first_date, last_date) -> dict:
105105
"""
106106
Make an asset list from a list of symbols.
107107
"""
@@ -117,21 +117,26 @@ def _make_list(self, ls: list) -> dict:
117117
df = pd.DataFrame()
118118
for i, x in enumerate(ls):
119119
asset = x if hasattr(x, 'symbol') and hasattr(x, 'ror') else Asset(x)
120-
asset_obj_dict.update({asset.symbol: asset})
120+
if asset.pl.years == 0 and asset.pl.months <= 2:
121+
raise ValueError(f'{asset.symbol} period length is {asset.pl.months}. It should be at least 3 months.')
122+
asset_first_date = max(asset.first_date, pd.to_datetime(first_date)) if first_date else asset.first_date
123+
asset_last_date = min(asset.last_date, pd.to_datetime(last_date)) if last_date else asset.last_date
124+
if Date.get_difference_in_months(asset_last_date, asset_first_date).n < 2:
125+
raise ValueError(f'{asset.symbol} historical data period length is too short. '
126+
f'It must be at least 3 months.')
127+
asset_obj_dict[asset.symbol] = asset
121128
if i == 0: # required to use pd.concat below (df should not be empty).
122129
df = self._make_ror(asset, currency_name)
123130
else:
124131
new = self._make_ror(asset, currency_name)
125132
df = pd.concat([df, new], axis=1, join="inner", copy="false")
126-
currencies.update({asset.symbol: asset.currency})
127-
names.update({asset.symbol: asset.name})
128-
first_dates.update({asset.symbol: asset.first_date})
129-
last_dates.update({asset.symbol: asset.last_date})
130-
# Add currency to the date range dict
131-
first_dates.update({currency_name: currency_first_date})
132-
last_dates.update({currency_name: currency_last_date})
133-
currencies.update({"asset list": currency_name})
134-
133+
currencies[asset.symbol] = asset.currency
134+
names[asset.symbol] = asset.name
135+
first_dates[asset.symbol] = asset.first_date
136+
last_dates[asset.symbol] = asset.last_date
137+
first_dates[currency_name] = currency_first_date
138+
last_dates[currency_name] = currency_last_date
139+
currencies["asset list"] = currency_name
135140
first_dates_sorted: list = sorted(first_dates.items(), key=lambda y: y[1])
136141
last_dates_sorted: list = sorted(last_dates.items(), key=lambda y: y[1])
137142
if isinstance(df, pd.Series):

tests/conftest.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,6 @@ def _init_asset_list(
7878
inflation=True,
7979
)
8080

81-
8281
# Portfolio
8382
@pytest.fixture(scope="package")
8483
def init_portfolio_values():

tests/test_asset_list.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,10 @@
1515
def test_asset_list_init_failing():
1616
with pytest.raises(ValueError, match=r"Assets must be a list."):
1717
ok.AssetList(assets=("RUB.FX", "MCFTR.INDX"))
18+
with pytest.raises(ValueError, match=r"FXRD.MOEX historical data period length is too short. "
19+
r"It must be at least 3 months."):
20+
ok.AssetList(assets=['FXRD.MOEX'], last_date="2021-10", inflation=True)
21+
1822

1923

2024
@mark.asset_list

0 commit comments

Comments
 (0)