Compare commits

...

5 Commits

Author SHA1 Message Date
Gourav Kumar 2f0f1e0e47 further testing 2 years ago
Gourav Kumar 44d5ea7b29 date parsing replaced with _parse_date function 2 years ago
Gourav Kumar cbace875c1 implemented _parse_date function to formalise date parsing 2 years ago
Gourav Kumar 053a93900a Rolling return was passing frequency object 2 years ago
Gourav Kumar 81856b2c1a changed IndexSlicer to _IndexSlicer 2 years ago
  1. 136
      fincal/core.py
  2. 29
      fincal/fincal.py
  3. 378
      testing.ipynb

136
fincal/core.py

@ -1,4 +1,5 @@
import datetime import datetime
from collections import UserList
from dataclasses import dataclass from dataclasses import dataclass
from numbers import Number from numbers import Number
from typing import Iterable, List, Literal, Mapping, Sequence, Tuple, Union from typing import Iterable, List, Literal, Mapping, Sequence, Tuple, Union
@ -6,8 +7,8 @@ from typing import Iterable, List, Literal, Mapping, Sequence, Tuple, Union
@dataclass @dataclass
class FincalOptions: class FincalOptions:
date_format: str = '%Y-%m-%d' date_format: str = "%Y-%m-%d"
closest: str = 'before' # after closest: str = "before" # after
@dataclass(frozen=True) @dataclass(frozen=True)
@ -20,12 +21,12 @@ class Frequency:
class AllFrequencies: class AllFrequencies:
D = Frequency('daily', 'days', 1, 1, 'D') D = Frequency("daily", "days", 1, 1, "D")
W = Frequency('weekly', 'days', 7, 7, 'W') W = Frequency("weekly", "days", 7, 7, "W")
M = Frequency('monthly', 'months', 1, 30, 'M') M = Frequency("monthly", "months", 1, 30, "M")
Q = Frequency('quarterly', 'months', 3, 91, 'Q') Q = Frequency("quarterly", "months", 3, 91, "Q")
H = Frequency('half-yearly', 'months', 6, 182, 'H') H = Frequency("half-yearly", "months", 6, 182, "H")
Y = Frequency('annual', 'years', 1, 365, 'Y') Y = Frequency("annual", "years", 1, 365, "Y")
def _preprocess_timeseries( def _preprocess_timeseries(
@ -33,9 +34,9 @@ def _preprocess_timeseries(
Sequence[Iterable[Union[str, datetime.datetime, float]]], Sequence[Iterable[Union[str, datetime.datetime, float]]],
Sequence[Mapping[str, Union[float, datetime.datetime]]], Sequence[Mapping[str, Union[float, datetime.datetime]]],
Sequence[Mapping[Union[str, datetime.datetime], float]], Sequence[Mapping[Union[str, datetime.datetime], float]],
Mapping[Union[str, datetime.datetime], float] Mapping[Union[str, datetime.datetime], float],
], ],
date_format: str date_format: str,
) -> List[Tuple[datetime.datetime, float]]: ) -> List[Tuple[datetime.datetime, float]]:
"""Converts any type of list to the correct type""" """Converts any type of list to the correct type"""
@ -75,12 +76,12 @@ def _preprocess_timeseries(
def _preprocess_match_options(as_on_match: str, prior_match: str, closest: str) -> datetime.timedelta: def _preprocess_match_options(as_on_match: str, prior_match: str, closest: str) -> datetime.timedelta:
"""Checks the arguments and returns appropriate timedelta objects""" """Checks the arguments and returns appropriate timedelta objects"""
deltas = {'exact': 0, 'previous': -1, 'next': 1} deltas = {"exact": 0, "previous": -1, "next": 1}
if closest not in deltas.keys(): if closest not in deltas.keys():
raise ValueError(f"Invalid closest argument: {closest}") raise ValueError(f"Invalid closest argument: {closest}")
as_on_match = closest if as_on_match == 'closest' else as_on_match as_on_match = closest if as_on_match == "closest" else as_on_match
prior_match = closest if prior_match == 'closest' else prior_match prior_match = closest if prior_match == "closest" else prior_match
if as_on_match in deltas.keys(): if as_on_match in deltas.keys():
as_on_delta = datetime.timedelta(days=deltas[as_on_match]) as_on_delta = datetime.timedelta(days=deltas[as_on_match])
@ -95,7 +96,25 @@ def _preprocess_match_options(as_on_match: str, prior_match: str, closest: str)
return as_on_delta, prior_delta return as_on_delta, prior_delta
class IndexSlicer: def _parse_date(date: str, date_format: str = None):
"""Parses date and handles errors"""
if isinstance(date, (datetime.datetime, datetime.date)):
return datetime.datetime.fromordinal(date.toordinal())
if date_format is None:
date_format = FincalOptions.date_format
try:
date = datetime.datetime.strptime(date, date_format)
except TypeError:
raise Exception("Date does not seem to be valid date-like string")
except ValueError:
raise Exception("Date could not be parsed. Have you set the correct date format in FincalOptions.date_format?")
return date
class _IndexSlicer:
def __init__(self, parent_obj): def __init__(self, parent_obj):
self.parent = parent_obj self.parent = parent_obj
@ -112,7 +131,7 @@ class IndexSlicer:
return item return item
class Series: class Series(UserList):
def __init__(self, data): def __init__(self, data):
if not isinstance(data, Sequence): if not isinstance(data, Sequence):
raise TypeError("Series only supports creation using Sequence types") raise TypeError("Series only supports creation using Sequence types")
@ -128,26 +147,26 @@ class Series:
data = [datetime.datetime.strptime(i, FincalOptions.date_format) for i in data] data = [datetime.datetime.strptime(i, FincalOptions.date_format) for i in data]
self.dtype = datetime.datetime self.dtype = datetime.datetime
except ValueError: except ValueError:
raise TypeError("Series does not support string data type") raise TypeError(
elif isinstance(data[0], datetime.datetime): "Series does not support string data type except dates.\n"
"Hint: Try setting the date format using FincalOptions.date_format"
)
elif isinstance(data[0], (datetime.datetime, datetime.date)):
self.dtype = datetime.datetime self.dtype = datetime.datetime
self.data = data self.data = [_parse_date(i) for i in data]
else: else:
raise TypeError(f"Cannot create series object from {type(data).__name__} of {type(data[0]).__name__}") raise TypeError(f"Cannot create series object from {type(data).__name__} of {type(data[0]).__name__}")
def __repr__(self): def __repr__(self):
return f"{self.__class__.__name__}({self.data})" return f"{self.__class__.__name__}({self.data})"
def __getitem__(self, n):
return self.data[n]
def __len__(self):
return len(self.data)
def __gt__(self, other): def __gt__(self, other):
if self.dtype == bool: if self.dtype == bool:
raise TypeError("> not supported for boolean series") raise TypeError("> not supported for boolean series")
if isinstance(other, (str, datetime.datetime, datetime.date)):
other = _parse_date(other)
if self.dtype == float and isinstance(other, Number) or isinstance(other, self.dtype): if self.dtype == float and isinstance(other, Number) or isinstance(other, self.dtype):
gt = Series([i > other for i in self.data]) gt = Series([i > other for i in self.data])
else: else:
@ -177,10 +196,7 @@ class TimeSeriesCore:
"""Defines the core building blocks of a TimeSeries object""" """Defines the core building blocks of a TimeSeries object"""
def __init__( def __init__(
self, self, data: List[Iterable], frequency: Literal["D", "W", "M", "Q", "H", "Y"], date_format: str = "%Y-%m-%d"
data: List[Iterable],
frequency: Literal['D', 'W', 'M', 'Q', 'H', 'Y'],
date_format: str = "%Y-%m-%d"
): ):
"""Instantiate a TimeSeries object """Instantiate a TimeSeries object
@ -240,42 +256,42 @@ class TimeSeriesCore:
printable = {} printable = {}
iter_f = iter(self.time_series) iter_f = iter(self.time_series)
first_n = [next(iter_f) for i in range(n//2)] first_n = [next(iter_f) for i in range(n // 2)]
iter_b = reversed(self.time_series) iter_b = reversed(self.time_series)
last_n = [next(iter_b) for i in range(n//2)] last_n = [next(iter_b) for i in range(n // 2)]
last_n.sort() last_n.sort()
printable['start'] = [str((i, self.time_series[i])) for i in first_n] printable["start"] = [str((i, self.time_series[i])) for i in first_n]
printable['end'] = [str((i, self.time_series[i])) for i in last_n] printable["end"] = [str((i, self.time_series[i])) for i in last_n]
return printable return printable
def __repr__(self): def __repr__(self):
if len(self.time_series) > 6: if len(self.time_series) > 6:
printable = self._get_printable_slice(6) printable = self._get_printable_slice(6)
printable_str = "{}([{}\n\t ...\n\t {}], frequency={})".format( printable_str = "{}([{}\n\t ...\n\t {}], frequency={})".format(
self.__class__.__name__, self.__class__.__name__,
',\n\t '.join(printable['start']), ",\n\t ".join(printable["start"]),
',\n\t '.join(printable['end']), ",\n\t ".join(printable["end"]),
repr(self.frequency.symbol) repr(self.frequency.symbol),
) )
else: else:
printable_str = "{}([{}], frequency={})".format( printable_str = "{}([{}], frequency={})".format(
self.__class__.__name__, self.__class__.__name__,
',\n\t'.join([str(i) for i in self.time_series.items()]), ",\n\t".join([str(i) for i in self.time_series.items()]),
repr(self.frequency.symbol) repr(self.frequency.symbol),
) )
return printable_str return printable_str
def __str__(self): def __str__(self):
if len(self.time_series) > 6: if len(self.time_series) > 6:
printable = self._get_printable_slice(6) printable = self._get_printable_slice(6)
printable_str = "[{}\n ...\n {}]".format( printable_str = "[{}\n ...\n {}]".format(
',\n '.join(printable['start']), ",\n ".join(printable["start"]),
',\n '.join(printable['end']), ",\n ".join(printable["end"]),
) )
else: else:
printable_str = "[{}]".format(',\n '.join([str(i) for i in self.time_series.items()])) printable_str = "[{}]".format(",\n ".join([str(i) for i in self.time_series.items()]))
return printable_str return printable_str
def __getitem__(self, key): def __getitem__(self, key):
@ -287,27 +303,25 @@ class TimeSeriesCore:
else: else:
dates_to_return = [self.dates[i] for i, j in enumerate(key) if j] dates_to_return = [self.dates[i] for i, j in enumerate(key) if j]
data_to_return = [(key, self.time_series[key]) for key in dates_to_return] data_to_return = [(key, self.time_series[key]) for key in dates_to_return]
return TimeSeriesCore(data_to_return) return TimeSeriesCore(data_to_return, frequency=self.frequency.symbol)
if isinstance(key, int): if isinstance(key, int):
raise KeyError(f"{key}. For index based slicing, use .iloc[{key}]") raise KeyError(f"{key}. For index based slicing, use .iloc[{key}]")
elif isinstance(key, datetime.datetime): elif isinstance(key, (datetime.datetime, datetime.date)):
key = _parse_date(key)
item = (key, self.time_series[key]) item = (key, self.time_series[key])
if isinstance(key, str): elif isinstance(key, str):
if key == 'dates': if key == "dates":
return self.dates return self.dates
elif key == 'values': elif key == "values":
return list(self.time_series.values()) return self.values
try:
dt_key = datetime.datetime.strptime(key, FincalOptions.date_format) dt_key = _parse_date(key)
item = (dt_key, self.time_series[dt_key]) item = (dt_key, self.time_series[dt_key])
except ValueError:
raise KeyError(f"{repr(key)}. If you passed a date as a string, "
"try setting the date format using Fincal.Options.date_format")
except KeyError:
raise KeyError(f"{repr(key)}. This date is not available.")
elif isinstance(key, Sequence): elif isinstance(key, Sequence):
item = [(k, self.time_series[k]) for k in key] keys = [_parse_date(i) for i in key]
item = [(k, self.time_series[k]) for k in keys]
else: else:
raise TypeError(f"Invalid type {repr(type(key).__name__)} for slicing.") raise TypeError(f"Invalid type {repr(type(key).__name__)} for slicing.")
return item return item
@ -347,4 +361,4 @@ class TimeSeriesCore:
def iloc(self): def iloc(self):
"""Returns an item or a set of items based on index""" """Returns an item or a set of items based on index"""
return IndexSlicer(self) return _IndexSlicer(self)

29
fincal/fincal.py

@ -5,7 +5,7 @@ from typing import List, Union
from dateutil.relativedelta import relativedelta from dateutil.relativedelta import relativedelta
from .core import AllFrequencies, TimeSeriesCore, _preprocess_match_options from .core import AllFrequencies, TimeSeriesCore, _parse_date, _preprocess_match_options
def create_date_series( def create_date_series(
@ -113,12 +113,13 @@ class TimeSeries(TimeSeriesCore):
def calculate_returns( def calculate_returns(
self, self,
as_on: datetime.datetime, as_on: Union[str, datetime.datetime],
as_on_match: str = "closest", as_on_match: str = "closest",
prior_match: str = "closest", prior_match: str = "closest",
closest: str = "previous", closest: str = "previous",
compounding: bool = True, compounding: bool = True,
years: int = 1, years: int = 1,
date_format: str = None
) -> float: ) -> float:
"""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
@ -158,6 +159,7 @@ class TimeSeries(TimeSeriesCore):
>>> calculate_returns(datetime.date(2020, 1, 1), years=1) >>> calculate_returns(datetime.date(2020, 1, 1), years=1)
""" """
as_on = _parse_date(as_on, date_format)
as_on_delta, prior_delta = _preprocess_match_options(as_on_match, prior_match, closest) as_on_delta, prior_delta = _preprocess_match_options(as_on_match, prior_match, closest)
while True: while True:
@ -184,23 +186,30 @@ class TimeSeries(TimeSeriesCore):
def calculate_rolling_returns( def calculate_rolling_returns(
self, self,
from_date: datetime.date, from_date: Union[datetime.date, str],
to_date: datetime.date, to_date: Union[datetime.date, str],
frequency: str = "D", frequency: str = None,
as_on_match: str = "closest", as_on_match: str = "closest",
prior_match: str = "closest", prior_match: str = "closest",
closest: str = "previous", closest: str = "previous",
compounding: bool = True, compounding: bool = True,
years: int = 1, years: int = 1,
date_format: str = None
) -> List[tuple]: ) -> List[tuple]:
"""Calculates the rolling return""" """Calculates the rolling return"""
try: from_date = _parse_date(from_date, date_format)
frequency = getattr(AllFrequencies, frequency) to_date = _parse_date(to_date, date_format)
except AttributeError:
raise ValueError(f"Invalid argument for frequency {frequency}")
dates = create_date_series(from_date, to_date, frequency) if frequency is None:
frequency = self.frequency
else:
try:
frequency = getattr(AllFrequencies, frequency)
except AttributeError:
raise ValueError(f"Invalid argument for frequency {frequency}")
dates = create_date_series(from_date, to_date, frequency.symbol)
if frequency == AllFrequencies.D: if frequency == AllFrequencies.D:
dates = [i for i in dates if i in self.time_series] dates = [i for i in dates if i in self.time_series]

378
testing.ipynb

@ -2,7 +2,7 @@
"cells": [ "cells": [
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 14, "execution_count": 1,
"id": "3f7938c0-98e3-43b8-86e8-4f000cda7ce5", "id": "3f7938c0-98e3-43b8-86e8-4f000cda7ce5",
"metadata": {}, "metadata": {},
"outputs": [], "outputs": [],
@ -16,28 +16,20 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 16, "execution_count": 2,
"id": "757eafc2-f804-4e7e-a3b8-2d09cd62e646", "id": "4b8ccd5f-dfff-4202-82c4-f66a30c122b6",
"metadata": {},
"outputs": [],
"source": [
"dfd = pd.read_csv('test_files/nav_history_daily - copy.csv')"
]
},
{
"cell_type": "code",
"execution_count": 17,
"id": "59b3d4a9-8ef4-4652-9e20-1bac69ab4ff9",
"metadata": {}, "metadata": {},
"outputs": [], "outputs": [],
"source": [ "source": [
"dfd = pd.read_csv('test_files/nav_history_daily - copy.csv')\n",
"\n",
"dfd = dfd[dfd['amfi_code'] == 118825].reset_index(drop=True)" "dfd = dfd[dfd['amfi_code'] == 118825].reset_index(drop=True)"
] ]
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 19, "execution_count": 3,
"id": "4bc95ae0-8c33-4eab-acf9-e765d22979b8", "id": "c52b0c2c-dd01-48dd-9ffa-3147ec9571ef",
"metadata": {}, "metadata": {},
"outputs": [ "outputs": [
{ {
@ -46,68 +38,370 @@
"text": [ "text": [
"Warning: The input data contains duplicate dates which have been ignored.\n" "Warning: The input data contains duplicate dates which have been ignored.\n"
] ]
},
{
"data": {
"text/plain": [
"TimeSeries([(datetime.datetime(2013, 1, 2, 0, 0), 18.972),\n",
"\t (datetime.datetime(2013, 1, 3, 0, 0), 19.011),\n",
"\t (datetime.datetime(2013, 1, 4, 0, 0), 19.008)\n",
"\t ...\n",
"\t (datetime.datetime(2022, 2, 10, 0, 0), 86.5),\n",
"\t (datetime.datetime(2022, 2, 11, 0, 0), 85.226),\n",
"\t (datetime.datetime(2022, 2, 14, 0, 0), 82.533)], frequency='D')"
]
},
"execution_count": 3,
"metadata": {},
"output_type": "execute_result"
} }
], ],
"source": [ "source": [
"ts = TimeSeries([(i.date, i.nav) for i in dfd.itertuples()], frequency='D')" "ts = TimeSeries([(i.date, i.nav) for i in dfd.itertuples()], frequency='D')\n",
"\n",
"ts"
] ]
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 20, "execution_count": 4,
"id": "f2c3218c-3984-43d6-8638-41a74a9d0b58", "id": "9e8ff6c6-3a36-435a-ba87-5b9844c18779",
"metadata": {}, "metadata": {},
"outputs": [ "outputs": [
{ {
"data": { "data": {
"text/plain": [ "text/plain": [
"TimeSeries([(datetime.datetime(2013, 1, 2, 0, 0), 18.972),\n", "[(datetime.datetime(2021, 1, 1, 0, 0), 66.652),\n",
"\t (datetime.datetime(2013, 1, 3, 0, 0), 19.011),\n", " (datetime.datetime(2020, 1, 1, 0, 0), 57.804)]"
"\t (datetime.datetime(2013, 1, 4, 0, 0), 19.008)\n",
"\t ...\n",
"\t (datetime.datetime(2022, 2, 10, 0, 0), 86.5),\n",
"\t (datetime.datetime(2022, 2, 11, 0, 0), 85.226),\n",
"\t (datetime.datetime(2022, 2, 14, 0, 0), 82.53299999999999)], frequency='D')"
] ]
}, },
"execution_count": 20, "execution_count": 4,
"metadata": {}, "metadata": {},
"output_type": "execute_result" "output_type": "execute_result"
} }
], ],
"source": [ "source": [
"ts" "ts[['2021-01-01', '2020-01-01']]"
] ]
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 22, "execution_count": 5,
"id": "dc469722-c816-4b57-8d91-7a3b865f86be", "id": "4d927a61-0f90-4b47-89b7-0e0d3ab1b442",
"metadata": {}, "metadata": {},
"outputs": [ "outputs": [
{ {
"ename": "TypeError", "data": {
"evalue": "getattr(): attribute name must be string", "text/plain": [
"output_type": "error", "Series([False, False, False, False, False, False, False, False, False, False])"
"traceback": [ ]
"\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", },
"\u001b[1;31mTypeError\u001b[0m Traceback (most recent call last)", "execution_count": 5,
"File \u001b[1;32m<timed eval>:1\u001b[0m, in \u001b[0;36m<module>\u001b[1;34m\u001b[0m\n", "metadata": {},
"File \u001b[1;32mD:\\Documents\\Projects\\fincal\\fincal\\fincal.py:203\u001b[0m, in \u001b[0;36mTimeSeries.calculate_rolling_returns\u001b[1;34m(self, from_date, to_date, frequency, as_on_match, prior_match, closest, compounding, years)\u001b[0m\n\u001b[0;32m 200\u001b[0m \u001b[38;5;28;01mexcept\u001b[39;00m \u001b[38;5;167;01mAttributeError\u001b[39;00m:\n\u001b[0;32m 201\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mValueError\u001b[39;00m(\u001b[38;5;124mf\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mInvalid argument for frequency \u001b[39m\u001b[38;5;132;01m{\u001b[39;00mfrequency\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m\"\u001b[39m)\n\u001b[1;32m--> 203\u001b[0m dates \u001b[38;5;241m=\u001b[39m \u001b[43mcreate_date_series\u001b[49m\u001b[43m(\u001b[49m\u001b[43mfrom_date\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mto_date\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mfrequency\u001b[49m\u001b[43m)\u001b[49m\n\u001b[0;32m 204\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m frequency \u001b[38;5;241m==\u001b[39m AllFrequencies\u001b[38;5;241m.\u001b[39mD:\n\u001b[0;32m 205\u001b[0m dates \u001b[38;5;241m=\u001b[39m [i \u001b[38;5;28;01mfor\u001b[39;00m i \u001b[38;5;129;01min\u001b[39;00m dates \u001b[38;5;28;01mif\u001b[39;00m i \u001b[38;5;129;01min\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mtime_series]\n", "output_type": "execute_result"
"File \u001b[1;32mD:\\Documents\\Projects\\fincal\\fincal\\fincal.py:16\u001b[0m, in \u001b[0;36mcreate_date_series\u001b[1;34m(start_date, end_date, frequency, eomonth)\u001b[0m\n\u001b[0;32m 11\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21mcreate_date_series\u001b[39m(\n\u001b[0;32m 12\u001b[0m start_date: datetime\u001b[38;5;241m.\u001b[39mdatetime, end_date: datetime\u001b[38;5;241m.\u001b[39mdatetime, frequency: \u001b[38;5;28mstr\u001b[39m, eomonth: \u001b[38;5;28mbool\u001b[39m \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;01mFalse\u001b[39;00m\n\u001b[0;32m 13\u001b[0m ) \u001b[38;5;241m-\u001b[39m\u001b[38;5;241m>\u001b[39m List[datetime\u001b[38;5;241m.\u001b[39mdatetime]:\n\u001b[0;32m 14\u001b[0m \u001b[38;5;124;03m\"\"\"Creates a date series using a frequency\"\"\"\u001b[39;00m\n\u001b[1;32m---> 16\u001b[0m frequency \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;43mgetattr\u001b[39;49m\u001b[43m(\u001b[49m\u001b[43mAllFrequencies\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mfrequency\u001b[49m\u001b[43m)\u001b[49m\n\u001b[0;32m 17\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m eomonth \u001b[38;5;129;01mand\u001b[39;00m frequency\u001b[38;5;241m.\u001b[39mdays \u001b[38;5;241m<\u001b[39m AllFrequencies\u001b[38;5;241m.\u001b[39mM\u001b[38;5;241m.\u001b[39mdays:\n\u001b[0;32m 18\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mValueError\u001b[39;00m(\u001b[38;5;124mf\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124meomonth cannot be set to True if frequency is higher than \u001b[39m\u001b[38;5;132;01m{\u001b[39;00mAllFrequencies\u001b[38;5;241m.\u001b[39mM\u001b[38;5;241m.\u001b[39mname\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m\"\u001b[39m)\n", }
"\u001b[1;31mTypeError\u001b[0m: getattr(): attribute name must be string" ],
"source": [
"s = ts.dates > '2020-01-01'\n",
"s[:10]"
]
},
{
"cell_type": "code",
"execution_count": 8,
"id": "311d1c07-d827-4d69-855f-883e1198c162",
"metadata": {},
"outputs": [],
"source": [
"import pandas as pd"
]
},
{
"cell_type": "code",
"execution_count": 10,
"id": "bb625050-5d7b-45a9-9cde-ac6e599adea5",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"0 False\n",
"1 False\n",
"2 False\n",
"3 False\n",
"4 False\n",
" ... \n",
"2196 True\n",
"2197 True\n",
"2198 True\n",
"2199 True\n",
"2200 True\n",
"Length: 2201, dtype: bool"
]
},
"execution_count": 10,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"pd.Series(s)"
]
},
{
"cell_type": "code",
"execution_count": 9,
"id": "dc469722-c816-4b57-8d91-7a3b865f86be",
"metadata": {
"scrolled": true,
"tags": []
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Wall time: 14 ms\n"
] ]
},
{
"data": {
"text/plain": [
"[(datetime.datetime(2020, 1, 1, 0, 0), 0.13778442642311628),\n",
" (datetime.datetime(2020, 1, 2, 0, 0), 0.15907011891977874),\n",
" (datetime.datetime(2020, 1, 3, 0, 0), 0.16528842679940592),\n",
" (datetime.datetime(2020, 1, 6, 0, 0), 0.13725881835976517),\n",
" (datetime.datetime(2020, 1, 7, 0, 0), 0.1361567661029075),\n",
" (datetime.datetime(2020, 1, 8, 0, 0), 0.12943599493029145),\n",
" (datetime.datetime(2020, 1, 9, 0, 0), 0.14162066246056781),\n",
" (datetime.datetime(2020, 1, 10, 0, 0), 0.14866092589666624),\n",
" (datetime.datetime(2020, 1, 13, 0, 0), 0.15898777321998292),\n",
" (datetime.datetime(2020, 1, 14, 0, 0), 0.16791720569210877),\n",
" (datetime.datetime(2020, 1, 15, 0, 0), 0.15701288705571237),\n",
" (datetime.datetime(2020, 1, 16, 0, 0), 0.15895332557726816),\n",
" (datetime.datetime(2020, 1, 17, 0, 0), 0.1597678687747972),\n",
" (datetime.datetime(2020, 1, 20, 0, 0), 0.1517952575115793),\n",
" (datetime.datetime(2020, 1, 21, 0, 0), 0.14416159380188165),\n",
" (datetime.datetime(2020, 1, 22, 0, 0), 0.1388367359038718),\n",
" (datetime.datetime(2020, 1, 23, 0, 0), 0.15628915183454306),\n",
" (datetime.datetime(2020, 1, 24, 0, 0), 0.16305428514615228),\n",
" (datetime.datetime(2020, 1, 27, 0, 0), 0.1622537810406386),\n",
" (datetime.datetime(2020, 1, 28, 0, 0), 0.16702450881101893),\n",
" (datetime.datetime(2020, 1, 29, 0, 0), 0.1718259672423219),\n",
" (datetime.datetime(2020, 1, 30, 0, 0), 0.15395125479716287),\n",
" (datetime.datetime(2020, 1, 31, 0, 0), 0.13100540412138484),\n",
" (datetime.datetime(2020, 2, 3, 0, 0), 0.10046175704475502),\n",
" (datetime.datetime(2020, 2, 4, 0, 0), 0.12408874488808119),\n",
" (datetime.datetime(2020, 2, 5, 0, 0), 0.13495745562947903),\n",
" (datetime.datetime(2020, 2, 6, 0, 0), 0.1316705790297339),\n",
" (datetime.datetime(2020, 2, 7, 0, 0), 0.1293798434480471),\n",
" (datetime.datetime(2020, 2, 10, 0, 0), 0.13417161807378752),\n",
" (datetime.datetime(2020, 2, 11, 0, 0), 0.14703664006986616),\n",
" (datetime.datetime(2020, 2, 12, 0, 0), 0.15665338645418325),\n",
" (datetime.datetime(2020, 2, 13, 0, 0), 0.16157913712294203),\n",
" (datetime.datetime(2020, 2, 14, 0, 0), 0.15528598971722363),\n",
" (datetime.datetime(2020, 2, 17, 0, 0), 0.15469223007063593),\n",
" (datetime.datetime(2020, 2, 18, 0, 0), 0.1616112297833383),\n",
" (datetime.datetime(2020, 2, 19, 0, 0), 0.1795321518161237),\n",
" (datetime.datetime(2020, 2, 20, 0, 0), 0.16892628011136668),\n",
" (datetime.datetime(2020, 2, 24, 0, 0), 0.14102204408817642),\n",
" (datetime.datetime(2020, 2, 25, 0, 0), 0.1287774793593952),\n",
" (datetime.datetime(2020, 2, 26, 0, 0), 0.11844857467280234),\n",
" (datetime.datetime(2020, 2, 27, 0, 0), 0.11330677290836633),\n",
" (datetime.datetime(2020, 2, 28, 0, 0), 0.07688934948979576),\n",
" (datetime.datetime(2020, 3, 2, 0, 0), 0.06323384067997617),\n",
" (datetime.datetime(2020, 3, 3, 0, 0), 0.08272385847005337),\n",
" (datetime.datetime(2020, 3, 4, 0, 0), 0.07610199644198445),\n",
" (datetime.datetime(2020, 3, 5, 0, 0), 0.06134216421544747),\n",
" (datetime.datetime(2020, 3, 6, 0, 0), 0.0307951704490399),\n",
" (datetime.datetime(2020, 3, 9, 0, 0), -0.014902463666744414),\n",
" (datetime.datetime(2020, 3, 11, 0, 0), -0.02972061472425558),\n",
" (datetime.datetime(2020, 3, 12, 0, 0), -0.1201765519331679),\n",
" (datetime.datetime(2020, 3, 13, 0, 0), -0.08575267799689612),\n",
" (datetime.datetime(2020, 3, 16, 0, 0), -0.15648316950777152),\n",
" (datetime.datetime(2020, 3, 17, 0, 0), -0.17358618226925038),\n",
" (datetime.datetime(2020, 3, 18, 0, 0), -0.21612661547106204),\n",
" (datetime.datetime(2020, 3, 19, 0, 0), -0.2452152219243373),\n",
" (datetime.datetime(2020, 3, 20, 0, 0), -0.20796112876097927),\n",
" (datetime.datetime(2020, 3, 23, 0, 0), -0.30970261339741667),\n",
" (datetime.datetime(2020, 3, 24, 0, 0), -0.2908531090417543),\n",
" (datetime.datetime(2020, 3, 25, 0, 0), -0.24436994526204125),\n",
" (datetime.datetime(2020, 3, 26, 0, 0), -0.22233453129679548),\n",
" (datetime.datetime(2020, 3, 27, 0, 0), -0.21821047890707101),\n",
" (datetime.datetime(2020, 3, 30, 0, 0), -0.2572613339750828),\n",
" (datetime.datetime(2020, 3, 31, 0, 0), -0.23261195549549218),\n",
" (datetime.datetime(2020, 4, 1, 0, 0), -0.2608607426811047),\n",
" (datetime.datetime(2020, 4, 3, 0, 0), -0.27431740614334477),\n",
" (datetime.datetime(2020, 4, 7, 0, 0), -0.2134398339479976),\n",
" (datetime.datetime(2020, 4, 8, 0, 0), -0.20755173891175982),\n",
" (datetime.datetime(2020, 4, 9, 0, 0), -0.18395973278558087),\n",
" (datetime.datetime(2020, 4, 13, 0, 0), -0.19529673178409412),\n",
" (datetime.datetime(2020, 4, 15, 0, 0), -0.20106882889523636),\n",
" (datetime.datetime(2020, 4, 16, 0, 0), -0.1970295580918935),\n",
" (datetime.datetime(2020, 4, 17, 0, 0), -0.1732330992098331),\n",
" (datetime.datetime(2020, 4, 20, 0, 0), -0.16734041380324138),\n",
" (datetime.datetime(2020, 4, 21, 0, 0), -0.19352467752012048),\n",
" (datetime.datetime(2020, 4, 23, 0, 0), -0.15569230769230757),\n",
" (datetime.datetime(2020, 4, 24, 0, 0), -0.17741518697626335),\n",
" (datetime.datetime(2020, 4, 27, 0, 0), -0.1667833069357988),\n",
" (datetime.datetime(2020, 4, 28, 0, 0), -0.1604110648642676),\n",
" (datetime.datetime(2020, 4, 29, 0, 0), -0.14832958856679812),\n",
" (datetime.datetime(2020, 4, 30, 0, 0), -0.1300687474725194),\n",
" (datetime.datetime(2020, 5, 4, 0, 0), -0.17366232326032705),\n",
" (datetime.datetime(2020, 5, 5, 0, 0), -0.1822936881988726),\n",
" (datetime.datetime(2020, 5, 6, 0, 0), -0.1722083628104405),\n",
" (datetime.datetime(2020, 5, 7, 0, 0), -0.17076925965564504),\n",
" (datetime.datetime(2020, 5, 8, 0, 0), -0.15704080857208003),\n",
" (datetime.datetime(2020, 5, 11, 0, 0), -0.1536333632218556),\n",
" (datetime.datetime(2020, 5, 12, 0, 0), -0.15922315279394084),\n",
" (datetime.datetime(2020, 5, 13, 0, 0), -0.12893477713422308),\n",
" (datetime.datetime(2020, 5, 14, 0, 0), -0.1515904189772027),\n",
" (datetime.datetime(2020, 5, 15, 0, 0), -0.1482976040353089),\n",
" (datetime.datetime(2020, 5, 18, 0, 0), -0.19486496766831485),\n",
" (datetime.datetime(2020, 5, 19, 0, 0), -0.19478889311525294),\n",
" (datetime.datetime(2020, 5, 20, 0, 0), -0.20504325418737346),\n",
" (datetime.datetime(2020, 5, 21, 0, 0), -0.1923849185691976),\n",
" (datetime.datetime(2020, 5, 22, 0, 0), -0.20265491640901256),\n",
" (datetime.datetime(2020, 5, 26, 0, 0), -0.21261575969288427),\n",
" (datetime.datetime(2020, 5, 27, 0, 0), -0.1977462346949832),\n",
" (datetime.datetime(2020, 5, 28, 0, 0), -0.18100478037341028),\n",
" (datetime.datetime(2020, 5, 29, 0, 0), -0.16737799894662286),\n",
" (datetime.datetime(2020, 6, 1, 0, 0), -0.1486066432934544),\n",
" (datetime.datetime(2020, 6, 2, 0, 0), -0.1406549318682908),\n",
" (datetime.datetime(2020, 6, 3, 0, 0), -0.1455950320312639),\n",
" (datetime.datetime(2020, 6, 4, 0, 0), -0.14420304132112982),\n",
" (datetime.datetime(2020, 6, 5, 0, 0), -0.13168311511525865),\n",
" (datetime.datetime(2020, 6, 8, 0, 0), -0.11935565702688988),\n",
" (datetime.datetime(2020, 6, 9, 0, 0), -0.13055374356744232),\n",
" (datetime.datetime(2020, 6, 10, 0, 0), -0.12668580404051355),\n",
" (datetime.datetime(2020, 6, 11, 0, 0), -0.14811351293025943),\n",
" (datetime.datetime(2020, 6, 12, 0, 0), -0.13644004989063818),\n",
" (datetime.datetime(2020, 6, 15, 0, 0), -0.14417647273124712),\n",
" (datetime.datetime(2020, 6, 16, 0, 0), -0.13541476920835016),\n",
" (datetime.datetime(2020, 6, 17, 0, 0), -0.12496542567903979),\n",
" (datetime.datetime(2020, 6, 18, 0, 0), -0.10886799410029502),\n",
" (datetime.datetime(2020, 6, 19, 0, 0), -0.09316449153637418),\n",
" (datetime.datetime(2020, 6, 22, 0, 0), -0.09261870319166465),\n",
" (datetime.datetime(2020, 6, 23, 0, 0), -0.07956272545824083),\n",
" (datetime.datetime(2020, 6, 24, 0, 0), -0.09426049373672252),\n",
" (datetime.datetime(2020, 6, 25, 0, 0), -0.10081348053457295),\n",
" (datetime.datetime(2020, 6, 26, 0, 0), -0.09618408922470667),\n",
" (datetime.datetime(2020, 6, 29, 0, 0), -0.10191913883401882),\n",
" (datetime.datetime(2020, 6, 30, 0, 0), -0.10248092640582795),\n",
" (datetime.datetime(2020, 7, 1, 0, 0), -0.09865244649419913),\n",
" (datetime.datetime(2020, 7, 2, 0, 0), -0.09126384692849943),\n",
" (datetime.datetime(2020, 7, 3, 0, 0), -0.08705088880518042),\n",
" (datetime.datetime(2020, 7, 6, 0, 0), -0.06379048033036305),\n",
" (datetime.datetime(2020, 7, 7, 0, 0), -0.05848366297181784),\n",
" (datetime.datetime(2020, 7, 8, 0, 0), -0.045594224361347635),\n",
" (datetime.datetime(2020, 7, 9, 0, 0), -0.039114513981358234),\n",
" (datetime.datetime(2020, 7, 10, 0, 0), -0.03792507846888182),\n",
" (datetime.datetime(2020, 7, 13, 0, 0), -0.04068015895018928),\n",
" (datetime.datetime(2020, 7, 14, 0, 0), -0.05505960632104223),\n",
" (datetime.datetime(2020, 7, 15, 0, 0), -0.058529292332681115),\n",
" (datetime.datetime(2020, 7, 16, 0, 0), -0.05489779859827626),\n",
" (datetime.datetime(2020, 7, 17, 0, 0), -0.04157081827144271),\n",
" (datetime.datetime(2020, 7, 20, 0, 0), -0.008800284000672676),\n",
" (datetime.datetime(2020, 7, 21, 0, 0), 0.002092636535191872),\n",
" (datetime.datetime(2020, 7, 22, 0, 0), 0.0022844730731781393),\n",
" (datetime.datetime(2020, 7, 23, 0, 0), 0.014283837303151303),\n",
" (datetime.datetime(2020, 7, 24, 0, 0), 0.017490781885222795),\n",
" (datetime.datetime(2020, 7, 27, 0, 0), 0.0014461451779510526),\n",
" (datetime.datetime(2020, 7, 28, 0, 0), 0.010423513944971319),\n",
" (datetime.datetime(2020, 7, 29, 0, 0), 0.014873903404892141),\n",
" (datetime.datetime(2020, 7, 30, 0, 0), 0.021221125275567854),\n",
" (datetime.datetime(2020, 7, 31, 0, 0), 0.017523096892418044),\n",
" (datetime.datetime(2020, 8, 3, 0, 0), 0.017039424171667816),\n",
" (datetime.datetime(2020, 8, 4, 0, 0), 0.03604716234731087),\n",
" (datetime.datetime(2020, 8, 5, 0, 0), 0.05061139977341078),\n",
" (datetime.datetime(2020, 8, 6, 0, 0), 0.05082975513519794),\n",
" (datetime.datetime(2020, 8, 7, 0, 0), 0.05958251310737306),\n",
" (datetime.datetime(2020, 8, 10, 0, 0), 0.048723986751670445),\n",
" (datetime.datetime(2020, 8, 11, 0, 0), 0.05220837401642653),\n",
" (datetime.datetime(2020, 8, 12, 0, 0), 0.05186376428694506),\n",
" (datetime.datetime(2020, 8, 13, 0, 0), 0.07394496484839053),\n",
" (datetime.datetime(2020, 8, 14, 0, 0), 0.05147838833490859),\n",
" (datetime.datetime(2020, 8, 17, 0, 0), 0.05283004347993381),\n",
" (datetime.datetime(2020, 8, 18, 0, 0), 0.06824040940397857),\n",
" (datetime.datetime(2020, 8, 19, 0, 0), 0.07100728132024359),\n",
" (datetime.datetime(2020, 10, 8, 0, 0), 0.09372370534689822),\n",
" (datetime.datetime(2020, 10, 9, 0, 0), 0.08128249892061357),\n",
" (datetime.datetime(2020, 10, 12, 0, 0), 0.08653955068906938),\n",
" (datetime.datetime(2020, 10, 13, 0, 0), 0.08506701906739678),\n",
" (datetime.datetime(2020, 10, 14, 0, 0), 0.08405050922620161),\n",
" (datetime.datetime(2020, 10, 15, 0, 0), 0.05063125897469378),\n",
" (datetime.datetime(2020, 10, 16, 0, 0), 0.060133007954397355),\n",
" (datetime.datetime(2020, 10, 19, 0, 0), 0.04674158943297102),\n",
" (datetime.datetime(2020, 10, 20, 0, 0), 0.04907684448660876),\n",
" (datetime.datetime(2020, 10, 21, 0, 0), 0.052287820185360934),\n",
" (datetime.datetime(2020, 10, 22, 0, 0), 0.05187688373367427),\n",
" (datetime.datetime(2020, 10, 23, 0, 0), 0.05667055904247564),\n",
" (datetime.datetime(2020, 10, 26, 0, 0), 0.04027605345797136),\n",
" (datetime.datetime(2020, 10, 27, 0, 0), 0.04849193018330533),\n",
" (datetime.datetime(2020, 10, 28, 0, 0), 0.03806689549404818),\n",
" (datetime.datetime(2020, 10, 29, 0, 0), 0.014816143497757839),\n",
" (datetime.datetime(2020, 10, 30, 0, 0), 0.00481137623180139),\n",
" (datetime.datetime(2020, 11, 2, 0, 0), -0.00014131778837667142),\n",
" (datetime.datetime(2020, 11, 3, 0, 0), 0.010563504681151636),\n",
" (datetime.datetime(2020, 11, 4, 0, 0), 0.01794663654972828),\n",
" (datetime.datetime(2020, 11, 5, 0, 0), 0.0394424147838115),\n",
" (datetime.datetime(2020, 11, 6, 0, 0), 0.043924408336276866),\n",
" (datetime.datetime(2020, 11, 9, 0, 0), 0.06426903481460511),\n",
" (datetime.datetime(2020, 11, 10, 0, 0), 0.07422870082083222),\n",
" (datetime.datetime(2020, 11, 11, 0, 0), 0.08174632645483015),\n",
" (datetime.datetime(2020, 11, 12, 0, 0), 0.07851042385019369),\n",
" (datetime.datetime(2020, 11, 13, 0, 0), 0.0942456954233204),\n",
" (datetime.datetime(2020, 11, 17, 0, 0), 0.09901112922662514),\n",
" (datetime.datetime(2020, 11, 18, 0, 0), 0.10079208973472964),\n",
" (datetime.datetime(2020, 11, 19, 0, 0), 0.08264929654539355),\n",
" (datetime.datetime(2020, 11, 20, 0, 0), 0.07989130434782621),\n",
" (datetime.datetime(2020, 11, 23, 0, 0), 0.0914305886506046),\n",
" (datetime.datetime(2020, 11, 24, 0, 0), 0.10378607360338887),\n",
" (datetime.datetime(2020, 11, 25, 0, 0), 0.07314267788989381),\n",
" (datetime.datetime(2020, 11, 26, 0, 0), 0.08476710029374734),\n",
" (datetime.datetime(2020, 11, 27, 0, 0), 0.07934822345629589),\n",
" (datetime.datetime(2020, 12, 1, 0, 0), 0.09014280738418656),\n",
" (datetime.datetime(2020, 12, 2, 0, 0), 0.09430073533264638),\n",
" (datetime.datetime(2020, 12, 3, 0, 0), 0.10218081653420374),\n",
" (datetime.datetime(2020, 12, 4, 0, 0), 0.10882414661443751),\n",
" (datetime.datetime(2020, 12, 7, 0, 0), 0.13058534603084881),\n",
" (datetime.datetime(2020, 12, 8, 0, 0), 0.13247583879573832),\n",
" (datetime.datetime(2020, 12, 9, 0, 0), 0.14204505331544381),\n",
" (datetime.datetime(2020, 12, 10, 0, 0), 0.14810928106435184),\n",
" (datetime.datetime(2020, 12, 11, 0, 0), 0.14509213323883752),\n",
" (datetime.datetime(2020, 12, 14, 0, 0), 0.12969764486762192),\n",
" (datetime.datetime(2020, 12, 15, 0, 0), 0.1272258873087433),\n",
" (datetime.datetime(2020, 12, 16, 0, 0), 0.1384985949417905),\n",
" (datetime.datetime(2020, 12, 17, 0, 0), 0.1336538294659746),\n",
" (datetime.datetime(2020, 12, 18, 0, 0), 0.13410538706550335),\n",
" (datetime.datetime(2020, 12, 21, 0, 0), 0.09376186695204902),\n",
" (datetime.datetime(2020, 12, 22, 0, 0), 0.1060517140194015),\n",
" (datetime.datetime(2020, 12, 23, 0, 0), 0.12163516362002835),\n",
" (datetime.datetime(2020, 12, 24, 0, 0), 0.1345174146595043),\n",
" (datetime.datetime(2020, 12, 28, 0, 0), 0.13883233842862563),\n",
" (datetime.datetime(2020, 12, 29, 0, 0), 0.14235188571822932),\n",
" (datetime.datetime(2020, 12, 30, 0, 0), 0.1433421220424269),\n",
" (datetime.datetime(2020, 12, 31, 0, 0), 0.1496252444998356),\n",
" (datetime.datetime(2021, 1, 1, 0, 0), 0.15306899176527566)]"
]
},
"execution_count": 9,
"metadata": {},
"output_type": "execute_result"
} }
], ],
"source": [ "source": [
"%%time\n", "%%time\n",
"ts.calculate_rolling_returns(from_date='2020-01-01', to_date='2021-01-01')" "from_date = datetime.date(2020, 1, 1)\n",
"to_date = datetime.date(2021, 1, 1)\n",
"# print(ts.calculate_returns(to_date, years=7))\n",
"ts.calculate_rolling_returns(from_date, to_date)"
] ]
} }
], ],
"metadata": { "metadata": {
"kernelspec": { "kernelspec": {
"display_name": "Python 3 (ipykernel)", "display_name": "Python 3",
"language": "python", "language": "python",
"name": "python3" "name": "python3"
}, },
@ -121,7 +415,7 @@
"name": "python", "name": "python",
"nbconvert_exporter": "python", "nbconvert_exporter": "python",
"pygments_lexer": "ipython3", "pygments_lexer": "ipython3",
"version": "3.8.3" "version": "3.9.2"
} }
}, },
"nbformat": 4, "nbformat": 4,

Loading…
Cancel
Save