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 ## To-do
### Core features ### Core features
- [ ] Add __setitem__ - [x] Add __setitem__
- [ ] Create emtpy TimeSeries object - [ ] Create emtpy TimeSeries object
- [x] Read from CSV - [x] Read from CSV
- [ ] Write to CSV - [ ] Write to CSV

View File

@ -6,7 +6,7 @@ import warnings
from collections import UserList from collections import UserList
from dataclasses import dataclass from dataclasses import dataclass
from numbers import Number 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 from dateutil.relativedelta import relativedelta
@ -393,7 +393,7 @@ class TimeSeriesCore:
def _get_item_from_date(self, date: str | datetime.datetime): def _get_item_from_date(self, date: str | datetime.datetime):
"""Helper function to retrieve item using a date""" """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): def _get_item_from_key(self, key: str | datetime.datetime):
"""Helper function to implement special keys""" """Helper function to implement special keys"""
@ -447,9 +447,9 @@ class TimeSeriesCore:
raise TypeError("Only numerical values can be stored in TimeSeries") raise TypeError("Only numerical values can be stored in TimeSeries")
if key in self.data: if key in self.data:
self.data[key] = value self.data[key] = float(value)
else: else:
self.data.update({key: value}) self.data.update({key: float(value)})
self.data = dict(sorted(self.data.items())) self.data = dict(sorted(self.data.items()))
@date_parser(1) @date_parser(1)
@ -765,32 +765,71 @@ class TimeSeriesCore:
raise NotImplementedError("This operation is not supported.") raise NotImplementedError("This operation is not supported.")
@date_parser(1) @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: if closest is None:
closest = FincalOptions.get_closest closest = FincalOptions.get_closest
if closest == "exact": time_delta_dict = {"exact": 0, "previous": -1, "next": 1}
try:
item = self._get_item_from_date(date)
return item
except KeyError:
return default
if closest == "previous": if closest not in time_delta_dict:
delta = datetime.timedelta(-1)
elif closest == "next":
delta = datetime.timedelta(1)
else:
raise ValueError(f"Invalid argument from closest {closest!r}") raise ValueError(f"Invalid argument from closest {closest!r}")
delta = relativedelta(days=time_delta_dict[closest])
while True: for _ in range(limit):
try: try:
item = self._get_item_from_date(date) return date, self.data[date]
return item
except KeyError: except KeyError:
if not delta:
break
date += delta date += delta
if raise_error:
raise KeyError(date)
return default
@property @property
def iloc(self) -> Mapping: def iloc(self) -> Mapping:
"""Returns an item or a set of items based on index """Returns an item or a set of items based on index

View File

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

View File

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