Compare commits

..

2 Commits

Author SHA1 Message Date
978566e0a8 Improved TSC.get 2022-04-24 23:47:27 +05:30
c99ffe02d0 changes to getitem to fetch closest date 2022-04-24 18:43:06 +05:30
4 changed files with 61 additions and 22 deletions

View File

@ -19,7 +19,7 @@ Fincal aims to simplify things by allowing you to:
## To-do
### Core features
- [ ] Add __setitem__
- [x] Add __setitem__
- [ ] Create emtpy TimeSeries object
- [x] Read from CSV
- [ ] Write to CSV

View File

@ -6,7 +6,7 @@ import warnings
from collections import UserList
from dataclasses import dataclass
from numbers import Number
from typing import Callable, Iterable, List, Literal, Mapping, Sequence, Type
from typing import Any, Callable, Iterable, List, Literal, Mapping, Sequence, Type
from dateutil.relativedelta import relativedelta
@ -393,7 +393,7 @@ class TimeSeriesCore:
def _get_item_from_date(self, date: str | datetime.datetime):
"""Helper function to retrieve item using a date"""
return date, self.data[date]
return self.get(date, raise_error=True)
def _get_item_from_key(self, key: str | datetime.datetime):
"""Helper function to implement special keys"""
@ -447,9 +447,9 @@ class TimeSeriesCore:
raise TypeError("Only numerical values can be stored in TimeSeries")
if key in self.data:
self.data[key] = value
self.data[key] = float(value)
else:
self.data.update({key: value})
self.data.update({key: float(value)})
self.data = dict(sorted(self.data.items()))
@date_parser(1)
@ -765,32 +765,71 @@ class TimeSeriesCore:
raise NotImplementedError("This operation is not supported.")
@date_parser(1)
def get(self, date: str | datetime.datetime, default=None, closest=None):
def get(
self,
date: str | datetime.datetime,
default: Any = None,
closest: Literal["previous", "next"] = None,
limit: int = 1000,
raise_error: bool = False,
) -> tuple | Any:
"""Get a value for a particular key. Return a default value on KeyError
Parameters
----------
date:
Date for which the value needs to be fetched.
default: Optional, Default None
Default value to be returned in case the date is not found. Default None.
closest:
Look for previous or next value when date is not found.
If not specified, the value set in FincalOptions is used
limit:
Maximum number of days to look for the closest available date.
If exceeded without finding a date, default value will be returned.
raise_error : bool, optional
Whether to raise an error and ignore the default value.
Meant for use with __getitem__.
Returns
-------
tuple | Any
_description_
Raises
------
ValueError
If the argument for closest is not valid.
KeyError
if raise_error is true and date is not found
"""
if closest is None:
closest = FincalOptions.get_closest
if closest == "exact":
try:
item = self._get_item_from_date(date)
return item
except KeyError:
return default
time_delta_dict = {"exact": 0, "previous": -1, "next": 1}
if closest == "previous":
delta = datetime.timedelta(-1)
elif closest == "next":
delta = datetime.timedelta(1)
else:
if closest not in time_delta_dict:
raise ValueError(f"Invalid argument from closest {closest!r}")
delta = relativedelta(days=time_delta_dict[closest])
while True:
for _ in range(limit):
try:
item = self._get_item_from_date(date)
return item
return date, self.data[date]
except KeyError:
if not delta:
break
date += delta
if raise_error:
raise KeyError(date)
return default
@property
def iloc(self) -> Mapping:
"""Returns an item or a set of items based on index

View File

@ -8,7 +8,7 @@ from .exceptions import DateNotFoundError, DateOutOfRangeError
@dataclass
class FincalOptions:
date_format: str = "%Y-%m-%d"
closest: str = "before" # after
closest: str = "previous" # next
traded_days: int = 365
get_closest: str = "exact"

View File

@ -386,7 +386,7 @@ class TestTimeSeriesArithmatic:
def test_truediv(self):
ts = TimeSeriesCore(self.data, "M")
ser = Series([21, 21, 23, 24], "number")
ser = Series([22, 23, 24, 25], "number")
num_div_ts = ts / 10
assert num_div_ts["2021-01-01"][1] == 22