first commit with basic time series operations
This commit is contained in:
commit
c9ead1a561
126
fincal/fincal.py
Normal file
126
fincal/fincal.py
Normal file
@ -0,0 +1,126 @@
|
||||
import datetime
|
||||
import pandas as pd
|
||||
from typing import Union, Dict, List, Iterable, Any
|
||||
|
||||
|
||||
class TimeSeries:
|
||||
def __init__(
|
||||
self,
|
||||
data=List[tuple],
|
||||
date_format: str = '%Y-%m-%d',
|
||||
frequency='infer' # D, W, M, Q, H, Y
|
||||
):
|
||||
self.time_series = [(datetime.datetime.strptime(i[0], date_format), i[1]) for i in data]
|
||||
self.dates = {i[0] for i in self.time_series}
|
||||
|
||||
# def infer_frequency(self):
|
||||
# sample_dates = [i[0] for i in self.time_series[:10]]
|
||||
# for i in sample_dates
|
||||
def __repr__(self):
|
||||
if len(self.time_series) > 6:
|
||||
printable_data_1 = self.time_series[:3]
|
||||
printable_data_2 = self.time_series[-3:]
|
||||
printable_str = "TimeSeries([{}\n\t...\n\t{}])".format(
|
||||
',\n\t'.join([str(i) for i in printable_data_1]),
|
||||
',\n\t'.join([str(i) for i in printable_data_2])
|
||||
)
|
||||
else:
|
||||
printable_data = self.time_series
|
||||
printable_str = "TimeSeries([{}])".format(',\n\t'.join([str(i) for i in printable_data]))
|
||||
return printable_str
|
||||
|
||||
def __str__(self):
|
||||
if len(self.time_series) > 6:
|
||||
printable_data_1 = self.time_series[:3]
|
||||
printable_data_2 = self.time_series[-3:]
|
||||
printable_str = "[{}\n ...\n {}]".format(
|
||||
',\n '.join([str(i) for i in printable_data_1]),
|
||||
',\n '.join([str(i) for i in printable_data_2])
|
||||
)
|
||||
else:
|
||||
printable_data = self.time_series
|
||||
printable_str = "[{}]".format(',\n '.join([str(i) for i in printable_data]))
|
||||
return printable_str
|
||||
|
||||
def ffill(self):
|
||||
new_ts = []
|
||||
for dt, val in self.time_series:
|
||||
if dt == self.time_series[0][0]:
|
||||
new_ts.append((dt, val))
|
||||
else:
|
||||
diff = (dt - prev_date).days
|
||||
if diff != 1:
|
||||
for k in range(1, diff):
|
||||
new_ts.append((prev_date + datetime.timedelta(days=k), prev_val))
|
||||
new_ts.append((dt, val))
|
||||
prev_date = dt
|
||||
prev_val = val
|
||||
self.ffilled_time_series = new_ts
|
||||
return self.ffilled_time_series
|
||||
|
||||
def bfill(self):
|
||||
new_ts = []
|
||||
for dt, val in self.time_series[::-1]:
|
||||
if dt == self.time_series[-1][0]:
|
||||
new_ts.append((dt, val))
|
||||
else:
|
||||
diff = (prev_date - dt).days
|
||||
if diff != 1:
|
||||
for k in range(1, diff):
|
||||
new_ts.append((prev_date - datetime.timedelta(days=k), prev_val))
|
||||
new_ts.append((dt, val))
|
||||
prev_date = dt
|
||||
prev_val = val
|
||||
self.ffilled_time_series = new_ts[::-1]
|
||||
return self.ffilled_time_series
|
||||
|
||||
def calculate_returns(
|
||||
self,
|
||||
as_on: datetime.date,
|
||||
closest: str = 'previous',
|
||||
compounding: bool = True,
|
||||
years: int = 1
|
||||
) -> int:
|
||||
"""Method to calculate returns for a certain time-period as on a particular date
|
||||
>>> calculate_returns(datetime.date(2020, 1, 1), years=1)
|
||||
"""
|
||||
|
||||
current = [(dt, val) for dt, val in self.time_series if dt == as_on][0]
|
||||
if not current:
|
||||
raise ValueError("As on date not found")
|
||||
|
||||
prev_date = as_on.replace(year=as_on.year-years)
|
||||
if closest == 'previous':
|
||||
previous = [(dt, val) for dt, val in self.time_series if dt <= prev_date][-1]
|
||||
elif closest == 'next':
|
||||
previous = [(dt, val) for dt, val in self.time_series if dt >= prev_date][0]
|
||||
# print(current, previous)
|
||||
|
||||
returns = current[1]/previous[1]
|
||||
if compounding:
|
||||
returns = returns ** (1/years)
|
||||
return returns - 1
|
||||
|
||||
def calculate_rolling_returns(
|
||||
self,
|
||||
from_date: datetime.date,
|
||||
to_date: datetime.date,
|
||||
frequency: str = 'd',
|
||||
closest: str = 'previous',
|
||||
compounding: bool = True,
|
||||
years: int = 1
|
||||
) -> List[tuple]:
|
||||
"""Calculates the rolling return"""
|
||||
|
||||
datediff = (to_date - from_date).days
|
||||
dates = []
|
||||
for i in range(datediff):
|
||||
if from_date + datetime.timedelta(days=i) in self.dates:
|
||||
dates.append(from_date + datetime.timedelta(days=i))
|
||||
|
||||
rolling_returns = []
|
||||
for i in dates:
|
||||
returns = self.calculate_returns(as_on=i, compounding=compounding, years=years, closest=closest)
|
||||
rolling_returns.append((i, returns))
|
||||
self.rolling_returns = rolling_returns
|
||||
return self.rolling_returns
|
Loading…
Reference in New Issue
Block a user