Compare commits

..

No commits in common. "335a6fc2e9e2b5b2b7b6a15cadb1042ccba6f44a" and "1f2b75282b313564bc6043c784a48f3370267691" have entirely different histories.

View File

@ -1,6 +1,6 @@
import datetime import datetime
from dataclasses import dataclass from dataclasses import dataclass
from typing import Dict, Iterable, List, Literal, Tuple, Union from typing import List
from dateutil.relativedelta import relativedelta from dateutil.relativedelta import relativedelta
@ -11,12 +11,15 @@ class Options:
closest: str = 'before' # after closest: str = 'before' # after
@dataclass(frozen=True)
class Frequency: class Frequency:
name: str def __init__(self, name, interval_type, interval_value, interval_days_value):
freq_type: str self.name = name
value: int self.type = interval_type
days: int self.value = interval_value
self.days = interval_days_value
def __repr__(self):
return f"Frequency({self.name}, {self.type}, {self.value}, {self.days})"
class AllFrequencies: class AllFrequencies:
@ -40,65 +43,16 @@ def create_date_series(
dates = [] dates = []
for i in range(0, int(datediff)): for i in range(0, int(datediff)):
diff = {frequency.freq_type: frequency.value*i} diff = {frequency.type: frequency.value*i}
dates.append(start_date + relativedelta(**diff)) dates.append(start_date + relativedelta(**diff))
return dates return dates
def _preprocess_timeseries(
data: Union[
List[Iterable[Union[str, datetime.datetime, float]]],
List[Dict[str, Union[float, datetime.datetime]]],
List[Dict[Union[str, datetime.datetime], float]],
Dict[Union[str, datetime.datetime], float]
],
date_format: str
) -> List[Tuple[datetime.datetime, float]]:
"""Converts any type of list to the correct type"""
if isinstance(data, list):
if isinstance(data[0], dict):
if len(data[0].keys()) == 2:
current_data = [tuple(i.values()) for i in data]
elif len(data[0].keys()) == 1:
current_data = [tuple(*i.items()) for i in data]
else:
raise TypeError("Could not parse the data")
current_data = _preprocess_timeseries(current_data, date_format)
elif isinstance(data[0], Iterable):
if isinstance(data[0][0], str):
current_data = []
for i in data:
row = datetime.datetime.strptime(i[0], date_format), i[1]
current_data.append(row)
elif isinstance(data[0][0], datetime.datetime):
current_data = [(i, j) for i, j in data]
else:
raise TypeError("Could not parse the data")
else:
raise TypeError("Could not parse the data")
elif isinstance(data, dict):
current_data = [(k, v) for k, v in data.items()]
current_data = _preprocess_timeseries(current_data, date_format)
else:
raise TypeError("Could not parse the data")
current_data.sort()
return current_data
class TimeSeries: class TimeSeries:
"""Container for TimeSeries objects""" """Container for TimeSeries objects"""
def __init__( def __init__(self, data: List[tuple], date_format: str = "%Y-%m-%d", frequency="D"):
self,
data: List[Iterable],
date_format: str = "%Y-%m-%d",
frequency=Literal['D', 'W', 'M', 'Q', 'H', 'Y']
):
"""Instantiate a TimeSeries object """Instantiate a TimeSeries object
Parameters Parameters
@ -118,11 +72,11 @@ class TimeSeries:
Valid values are {D, W, M, Q, H, Y} Valid values are {D, W, M, Q, H, Y}
""" """
data = _preprocess_timeseries(data, date_format=date_format) time_series = [(datetime.datetime.strptime(i[0], date_format), i[1]) for i in data]
time_series.sort()
self.time_series = dict(data) self.time_series = dict(time_series)
self.dates = set(list(self.time_series)) self.dates = set(list(self.time_series))
if len(self.dates) != len(data): if len(self.dates) != len(time_series):
print("Warning: The input data contains duplicate dates which have been ignored.") print("Warning: The input data contains duplicate dates which have been ignored.")
self.start_date = list(self.time_series)[0] self.start_date = list(self.time_series)[0]
self.end_date = list(self.time_series)[-1] self.end_date = list(self.time_series)[-1]
@ -172,7 +126,7 @@ class TimeSeries:
cur_val = self.time_series[cur_date] cur_val = self.time_series[cur_date]
except KeyError: except KeyError:
pass pass
new_ts.update({cur_date: cur_val}) new_ts.update({cur_date: cur_val}) # type: ignore
if inplace: if inplace:
self.time_series = new_ts self.time_series = new_ts
@ -190,7 +144,7 @@ class TimeSeries:
cur_val = self.time_series[cur_date] cur_val = self.time_series[cur_date]
except KeyError: except KeyError:
pass pass
new_ts.update({cur_date: cur_val}) new_ts.update({cur_date: cur_val}) # type: ignore
if inplace: if inplace:
self.time_series = new_ts self.time_series = new_ts
@ -200,7 +154,7 @@ class TimeSeries:
def calculate_returns( def calculate_returns(
self, as_on: datetime.datetime, closest: str = "previous", compounding: bool = True, years: int = 1 self, as_on: datetime.datetime, closest: str = "previous", compounding: bool = True, years: int = 1
) -> float: ) -> int:
"""Method to calculate returns for a certain time-period as on a particular date """Method to calculate returns for a certain time-period as on a particular date
>>> calculate_returns(datetime.date(2020, 1, 1), years=1) >>> calculate_returns(datetime.date(2020, 1, 1), years=1)
""" """
@ -216,7 +170,7 @@ class TimeSeries:
elif closest == "next": elif closest == "next":
delta = 1 delta = 1
else: else:
raise ValueError(f"Invalid value for closest parameter: {closest}") raise ValueError(f"Invalid value for closes parameter: {closest}")
while True: while True:
try: try: