Compare commits
2 Commits
65f2e8434c
...
978566e0a8
Author | SHA1 | Date | |
---|---|---|---|
978566e0a8 | |||
c99ffe02d0 |
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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"
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
Loading…
Reference in New Issue
Block a user