Compare commits

...

7 Commits

  1. 15
      .ipynb_checkpoints/README-checkpoint.md
  2. 129
      .ipynb_checkpoints/testing-checkpoint.ipynb
  3. 15
      .vscode/launch.json
  4. 128
      fincal/core.py
  5. 22
      fincal/fincal.py
  6. 326
      testing.ipynb

15
.ipynb_checkpoints/README-checkpoint.md

@ -0,0 +1,15 @@
# Fincal
This module simplified handling of time-series data
## The problem
Time series data often have missing data points. These missing points mess things up when you are trying to do a comparison between two sections of a time series.
To make things worse, most libraries don't allow comparison based on dates. Month to Month and year to year comparisons become difficult as they cannot be translated into number of days. However, these are commonly used metrics while looking at financial data.
## The Solution
Fincal aims to simplify things by allowing you to:
* Compare time-series data based on dates
* Easy way to work around missing dates by taking the closest data points
* Completing series with missing data points using forward fill and backward fill
## Examples

129
.ipynb_checkpoints/testing-checkpoint.ipynb

@ -0,0 +1,129 @@
{
"cells": [
{
"cell_type": "code",
"execution_count": 14,
"id": "3f7938c0-98e3-43b8-86e8-4f000cda7ce5",
"metadata": {},
"outputs": [],
"source": [
"import datetime\n",
"import pandas as pd\n",
"\n",
"from fincal.fincal import TimeSeries\n",
"from fincal.core import Series"
]
},
{
"cell_type": "code",
"execution_count": 16,
"id": "757eafc2-f804-4e7e-a3b8-2d09cd62e646",
"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": {},
"outputs": [],
"source": [
"dfd = dfd[dfd['amfi_code'] == 118825].reset_index(drop=True)"
]
},
{
"cell_type": "code",
"execution_count": 19,
"id": "4bc95ae0-8c33-4eab-acf9-e765d22979b8",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Warning: The input data contains duplicate dates which have been ignored.\n"
]
}
],
"source": [
"ts = TimeSeries([(i.date, i.nav) for i in dfd.itertuples()], frequency='D')"
]
},
{
"cell_type": "code",
"execution_count": 20,
"id": "f2c3218c-3984-43d6-8638-41a74a9d0b58",
"metadata": {},
"outputs": [
{
"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.53299999999999)], frequency='D')"
]
},
"execution_count": 20,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"ts"
]
},
{
"cell_type": "code",
"execution_count": 22,
"id": "dc469722-c816-4b57-8d91-7a3b865f86be",
"metadata": {},
"outputs": [
{
"ename": "TypeError",
"evalue": "getattr(): attribute name must be string",
"output_type": "error",
"traceback": [
"\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
"\u001b[1;31mTypeError\u001b[0m Traceback (most recent call last)",
"File \u001b[1;32m<timed eval>:1\u001b[0m, in \u001b[0;36m<module>\u001b[1;34m\u001b[0m\n",
"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",
"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": [
"%%time\n",
"ts.calculate_rolling_returns(from_date='2020-01-01', to_date='2021-01-01')"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.8.3"
}
},
"nbformat": 4,
"nbformat_minor": 5
}

15
.vscode/launch.json

@ -0,0 +1,15 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "Python: Current File",
"type": "python",
"request": "launch",
"program": "${file}",
"console": "integratedTerminal"
}
]
}

128
fincal/core.py

@ -1,8 +1,8 @@
import datetime
from collections import UserList
from collections import UserDict, UserList
from dataclasses import dataclass
from numbers import Number
from typing import Iterable, List, Literal, Mapping, Sequence, Tuple, Union
from typing import Iterable, List, Literal, Mapping, Sequence, Tuple, Type, Union
@dataclass
@ -108,23 +108,24 @@ def _parse_date(date: str, date_format: str = None):
try:
date = datetime.datetime.strptime(date, date_format)
except TypeError:
raise Exception("Date does not seem to be valid date-like string")
raise ValueError("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?")
raise ValueError("Date could not be parsed. Have you set the correct date format in FincalOptions.date_format?")
return date
class _IndexSlicer:
"""Class to create a slice using iloc in TimeSeriesCore"""
def __init__(self, parent_obj):
self.parent = parent_obj
def __getitem__(self, n):
all_keys = list(self.parent.time_series)
if isinstance(n, int):
keys = [all_keys[n]]
keys = [self.parent.dates[n]]
else:
keys = all_keys[n]
item = [(key, self.parent.time_series[key]) for key in keys]
keys = self.parent.dates[n]
item = [(key, self.parent.data[key]) for key in keys]
if len(item) == 1:
return item[0]
@ -132,34 +133,36 @@ class _IndexSlicer:
class Series(UserList):
def __init__(self, data):
"""Container for a series of objects, all objects must be of the same type"""
def __init__(
self,
data,
data_type: Union[Type[bool], Type[float], Type[str], Type[datetime.datetime]],
date_format: str = None,
):
self.dtype = data_type
if not isinstance(data, Sequence):
raise TypeError("Series only supports creation using Sequence types")
if isinstance(data[0], bool):
self.data = data
self.dtype = bool
elif isinstance(data[0], Number):
self.dtype = float
self.data = [float(i) for i in data]
elif isinstance(data[0], str):
try:
data = [datetime.datetime.strptime(i, FincalOptions.date_format) for i in data]
self.dtype = datetime.datetime
except ValueError:
raise TypeError(
"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.data = [_parse_date(i) for i in data]
else:
raise TypeError(f"Cannot create series object from {type(data).__name__} of {type(data[0]).__name__}")
raise TypeError("Series object can only be created using Sequence types")
for i in data:
if not isinstance(i, data_type):
raise Exception("All arguments must be of the same type")
if data_type == str:
data = [_parse_date(i, date_format) for i in data]
self.data = data
def __repr__(self):
return f"{self.__class__.__name__}({self.data})"
def __getitem__(self, i):
if isinstance(i, slice):
return self.__class__(self.data[i], self.dtype)
else:
return self.data[i]
def __gt__(self, other):
if self.dtype == bool:
raise TypeError("> not supported for boolean series")
@ -168,7 +171,7 @@ class Series(UserList):
other = _parse_date(other)
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], bool)
else:
raise Exception(f"Cannot compare type {self.dtype.__name__} to {type(other).__name__}")
@ -179,20 +182,20 @@ class Series(UserList):
raise TypeError("< not supported for boolean series")
if self.dtype == float and isinstance(other, Number) or isinstance(other, self.dtype):
lt = Series([i < other for i in self.data])
lt = Series([i < other for i in self.data], bool)
else:
raise Exception(f"Cannot compare type {self.dtype.__name__} to {type(other).__name__}")
return lt
def __eq__(self, other):
if self.dtype == float and isinstance(other, Number) or isinstance(other, self.dtype):
eq = Series([i == other for i in self.data])
eq = Series([i == other for i in self.data], bool)
else:
raise Exception(f"Cannot compare type {self.dtype.__name__} to {type(other).__name__}")
return eq
class TimeSeriesCore:
class TimeSeriesCore(UserDict):
"""Defines the core building blocks of a TimeSeries object"""
def __init__(
@ -219,8 +222,8 @@ class TimeSeriesCore:
data = _preprocess_timeseries(data, date_format=date_format)
self.time_series = dict(data)
if len(self.time_series) != len(data):
self.data = dict(data)
if len(self.data) != len(data):
print("Warning: The input data contains duplicate dates which have been ignored.")
self.frequency = getattr(AllFrequencies, frequency)
self.iter_num = -1
@ -231,17 +234,17 @@ class TimeSeriesCore:
@property
def dates(self):
if self._dates is None or len(self._dates) != len(self.time_series):
self._dates = list(self.time_series.keys())
if self._dates is None or len(self._dates) != len(self.data):
self._dates = list(self.data.keys())
return Series(self._dates)
return Series(self._dates, datetime.datetime)
@property
def values(self):
if self._values is None or len(self._values) != len(self.time_series):
self._values = list(self.time_series.values())
if self._values is None or len(self._values) != len(self.data):
self._values = list(self.data.values())
return Series(self._values)
return Series(self._values, float)
@property
def start_date(self):
@ -255,19 +258,19 @@ class TimeSeriesCore:
"""Returns a slice of the dataframe from beginning and end"""
printable = {}
iter_f = iter(self.time_series)
iter_f = iter(self.data)
first_n = [next(iter_f) for i in range(n // 2)]
iter_b = reversed(self.time_series)
iter_b = reversed(self.data)
last_n = [next(iter_b) for i in range(n // 2)]
last_n.sort()
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["start"] = [str((i, self.data[i])) for i in first_n]
printable["end"] = [str((i, self.data[i])) for i in last_n]
return printable
def __repr__(self):
if len(self.time_series) > 6:
if len(self.data) > 6:
printable = self._get_printable_slice(6)
printable_str = "{}([{}\n\t ...\n\t {}], frequency={})".format(
self.__class__.__name__,
@ -278,20 +281,20 @@ class TimeSeriesCore:
else:
printable_str = "{}([{}], frequency={})".format(
self.__class__.__name__,
",\n\t".join([str(i) for i in self.time_series.items()]),
",\n\t".join([str(i) for i in self.data.items()]),
repr(self.frequency.symbol),
)
return printable_str
def __str__(self):
if len(self.time_series) > 6:
if len(self.data) > 6:
printable = self._get_printable_slice(6)
printable_str = "[{}\n ...\n {}]".format(
",\n ".join(printable["start"]),
",\n ".join(printable["end"]),
)
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.data.items()]))
return printable_str
def __getitem__(self, key):
@ -302,14 +305,14 @@ class TimeSeriesCore:
raise Exception(f"Length of Series: {len(key)} did not match length of object: {len(self.dates)}")
else:
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]
return TimeSeriesCore(data_to_return, frequency=self.frequency.symbol)
data_to_return = [(key, self.data[key]) for key in dates_to_return]
return self.__class__(data_to_return, frequency=self.frequency.symbol)
if isinstance(key, int):
raise KeyError(f"{key}. For index based slicing, use .iloc[{key}]")
elif isinstance(key, (datetime.datetime, datetime.date)):
key = _parse_date(key)
item = (key, self.time_series[key])
item = (key, self.data[key])
elif isinstance(key, str):
if key == "dates":
return self.dates
@ -317,18 +320,15 @@ class TimeSeriesCore:
return self.values
dt_key = _parse_date(key)
item = (dt_key, self.time_series[dt_key])
item = (dt_key, self.data[dt_key])
elif isinstance(key, Sequence):
keys = [_parse_date(i) for i in key]
item = [(k, self.time_series[k]) for k in keys]
item = [(k, self.data[k]) for k in keys]
else:
raise TypeError(f"Invalid type {repr(type(key).__name__)} for slicing.")
return item
def __len__(self):
return len(self.time_series)
def __iter__(self):
self.n = 0
return self
@ -339,22 +339,22 @@ class TimeSeriesCore:
else:
key = self.dates[self.n]
self.n += 1
return key, self.time_series[key]
return key, self.data[key]
def head(self, n: int = 6):
"""Returns the first n items of the TimeSeries object"""
keys = list(self.time_series.keys())
keys = list(self.data.keys())
keys = keys[:n]
result = [(key, self.time_series[key]) for key in keys]
result = [(key, self.data[key]) for key in keys]
return result
def tail(self, n: int = 6):
"""Returns the last n items of the TimeSeries object"""
keys = list(self.time_series.keys())
keys = list(self.data.keys())
keys = keys[-n:]
result = [(key, self.time_series[key]) for key in keys]
result = [(key, self.data[key]) for key in keys]
return result
@property

22
fincal/fincal.py

@ -40,7 +40,7 @@ class TimeSeries(TimeSeriesCore):
def info(self):
"""Summary info about the TimeSeries object"""
total_dates = len(self.time_series.keys())
total_dates = len(self.data.keys())
res_string = "First date: {}\nLast date: {}\nNumber of rows: {}"
return res_string.format(self.start_date, self.end_date, total_dates)
@ -66,16 +66,16 @@ class TimeSeries(TimeSeriesCore):
new_ts = dict()
for cur_date in dates_to_fill:
try:
cur_val = self.time_series[cur_date]
cur_val = self.data[cur_date]
except KeyError:
pass
new_ts.update({cur_date: cur_val})
if inplace:
self.time_series = new_ts
self.data = new_ts
return None
return TimeSeries(new_ts, frequency=self.frequency.symbol)
return self.__class__(new_ts, frequency=self.frequency.symbol)
def bfill(self, inplace: bool = False, limit: int = None) -> Union[TimeSeries, None]:
"""Backward fill missing dates in the time series
@ -100,16 +100,16 @@ class TimeSeries(TimeSeriesCore):
bfill_ts = dict()
for cur_date in reversed(dates_to_fill):
try:
cur_val = self.time_series[cur_date]
cur_val = self.data[cur_date]
except KeyError:
pass
bfill_ts.update({cur_date: cur_val})
new_ts = {k: bfill_ts[k] for k in reversed(bfill_ts)}
if inplace:
self.time_series = new_ts
self.data = new_ts
return None
return TimeSeries(new_ts, frequency=self.frequency.symbol)
return self.__class__(new_ts, frequency=self.frequency.symbol)
def calculate_returns(
self,
@ -163,7 +163,7 @@ class TimeSeries(TimeSeriesCore):
as_on_delta, prior_delta = _preprocess_match_options(as_on_match, prior_match, closest)
while True:
current = self.time_series.get(as_on, None)
current = self.data.get(as_on, None)
if current is not None:
break
elif not as_on_delta:
@ -172,7 +172,7 @@ class TimeSeries(TimeSeriesCore):
prev_date = as_on - relativedelta(years=years)
while True:
previous = self.time_series.get(prev_date, None)
previous = self.data.get(prev_date, None)
if previous is not None:
break
elif not prior_delta:
@ -211,7 +211,7 @@ class TimeSeries(TimeSeriesCore):
dates = create_date_series(from_date, to_date, frequency.symbol)
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.data]
rolling_returns = []
for i in dates:
@ -225,7 +225,7 @@ class TimeSeries(TimeSeriesCore):
)
rolling_returns.append((i, returns))
rolling_returns.sort()
return rolling_returns
return self.__class__(rolling_returns, self.frequency.symbol)
if __name__ == "__main__":

326
testing.ipynb

@ -22,7 +22,6 @@
"outputs": [],
"source": [
"dfd = pd.read_csv('test_files/nav_history_daily - copy.csv')\n",
"\n",
"dfd = dfd[dfd['amfi_code'] == 118825].reset_index(drop=True)"
]
},
@ -48,7 +47,7 @@
"\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')"
"\t (datetime.datetime(2022, 2, 14, 0, 0), 82.53299999999999)], frequency='D')"
]
},
"execution_count": 3,
@ -58,7 +57,6 @@
],
"source": [
"ts = TimeSeries([(i.date, i.nav) for i in dfd.itertuples()], frequency='D')\n",
"\n",
"ts"
]
},
@ -71,8 +69,8 @@
{
"data": {
"text/plain": [
"[(datetime.datetime(2021, 1, 1, 0, 0), 66.652),\n",
" (datetime.datetime(2020, 1, 1, 0, 0), 57.804)]"
"[(datetime.datetime(2022, 1, 31, 0, 0), 85.18),\n",
" (datetime.datetime(2021, 5, 31, 0, 0), 74.85)]"
]
},
"execution_count": 4,
@ -81,79 +79,99 @@
}
],
"source": [
"ts[['2021-01-01', '2020-01-01']]"
"ts[['2022-01-31', '2021-05-31']]"
]
},
{
"cell_type": "code",
"execution_count": 5,
"id": "4d927a61-0f90-4b47-89b7-0e0d3ab1b442",
"execution_count": 16,
"id": "086d4377-d1b1-4e51-84c0-39dee28ef75e",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"Series([False, False, False, False, False, False, False, False, False, False])"
"TimeSeries([(datetime.datetime(2021, 2, 15, 0, 0), 73.483),\n",
"\t (datetime.datetime(2021, 2, 16, 0, 0), 73.237),\n",
"\t (datetime.datetime(2021, 2, 17, 0, 0), 72.98)\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": 5,
"execution_count": 16,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"s = ts.dates > '2020-01-01'\n",
"s[:10]"
"ts[ts.dates>'2021-02-14']"
]
},
{
"cell_type": "code",
"execution_count": 8,
"id": "311d1c07-d827-4d69-855f-883e1198c162",
"execution_count": 5,
"id": "6f1226a3-2327-435b-88e7-fd0fdcc8cc1c",
"metadata": {},
"outputs": [],
"outputs": [
{
"data": {
"text/plain": [
"TimeSeries([(datetime.datetime(2020, 1, 2, 0, 0), 58.285),\n",
"\t (datetime.datetime(2020, 1, 3, 0, 0), 58.056999999999995),\n",
"\t (datetime.datetime(2020, 1, 6, 0, 0), 56.938)\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": 5,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"import pandas as pd"
"s = ts.dates > '2020-01-01'\n",
"ts[s]"
]
},
{
"cell_type": "code",
"execution_count": 10,
"id": "bb625050-5d7b-45a9-9cde-ac6e599adea5",
"execution_count": 9,
"id": "e815edc9-3746-4192-814e-bd27b2771a0c",
"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"
"[(datetime.datetime(2013, 1, 2, 0, 0), 18.972),\n",
" (datetime.datetime(2013, 1, 3, 0, 0), 19.011),\n",
" (datetime.datetime(2013, 1, 4, 0, 0), 19.008),\n",
" (datetime.datetime(2013, 1, 7, 0, 0), 18.95),\n",
" (datetime.datetime(2013, 1, 8, 0, 0), 18.954),\n",
" (datetime.datetime(2013, 1, 9, 0, 0), 18.94),\n",
" (datetime.datetime(2013, 1, 10, 0, 0), 18.957),\n",
" (datetime.datetime(2013, 1, 11, 0, 0), 18.948),\n",
" (datetime.datetime(2013, 1, 14, 0, 0), 19.177),\n",
" (datetime.datetime(2013, 1, 15, 0, 0), 19.272000000000002)]"
]
},
"execution_count": 10,
"execution_count": 9,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"pd.Series(s)"
"ts.iloc[:10]"
]
},
{
"cell_type": "code",
"execution_count": 9,
"execution_count": 6,
"id": "dc469722-c816-4b57-8d91-7a3b865f86be",
"metadata": {
"scrolled": true,
"tags": []
},
"outputs": [
@ -161,233 +179,9 @@
"name": "stdout",
"output_type": "stream",
"text": [
"CPU times: total: 15.6 ms\n",
"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": [
@ -395,13 +189,21 @@
"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)"
"rr = ts.calculate_rolling_returns(from_date, to_date)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "e5d357b4-4fe5-4a0a-8107-0ab6828d7c41",
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
},
@ -415,7 +217,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.9.2"
"version": "3.8.3"
}
},
"nbformat": 4,

Loading…
Cancel
Save