diff --git a/README.md b/README.md index 46d4cce..dedbc63 100644 --- a/README.md +++ b/README.md @@ -26,7 +26,7 @@ Fincal aims to simplify things by allowing you to: - [ ] Convert to dict - [ ] Convert to list of dicts ### Fincal features -- [ ] Sync two TimeSeries +- [x] Sync two TimeSeries - [x] Average rolling return - [ ] Sharpe ratio - [ ] Jensen's Alpha @@ -35,4 +35,5 @@ Fincal aims to simplify things by allowing you to: ### Pending implementation - [ ] Use limit parameter in ffill and bfill -- [ ] Implementation of ffill and bfill may be incorrect inside expand, check and correct \ No newline at end of file +- [x] Implementation of ffill and bfill may be incorrect inside expand, check and correct +- [ ] Implement interpolation in expand \ No newline at end of file diff --git a/fincal/core.py b/fincal/core.py index f22bb77..474f2b4 100644 --- a/fincal/core.py +++ b/fincal/core.py @@ -213,7 +213,7 @@ class TimeSeriesCore(UserDict): def __init__( self, - data: List[Iterable] | Mapping, + ts_data: List[Iterable] | Mapping, frequency: Literal["D", "W", "M", "Q", "H", "Y"], date_format: str = "%Y-%m-%d", ): @@ -221,7 +221,7 @@ class TimeSeriesCore(UserDict): Parameters ---------- - data : List[Iterable] | Mapping + ts_data : List[Iterable] | Mapping Time Series data in the form of list of tuples or dictionary. The first element of each tuple should be a date and second element should be a value. In case of dictionary, the key should be the date. @@ -235,10 +235,10 @@ class TimeSeriesCore(UserDict): Required only if the first argument of tuples is a string. Otherwise ignored. """ - data = _preprocess_timeseries(data, date_format=date_format) + ts_data = _preprocess_timeseries(ts_data, date_format=date_format) - super().__init__(dict(data)) - if len(self.data) != len(data): + super().__init__(dict(ts_data)) + if len(self.data) != len(ts_data): print("Warning: The input data contains duplicate dates which have been ignored.") self.frequency: Frequency = getattr(AllFrequencies, frequency) self.iter_num: int = -1 @@ -364,9 +364,6 @@ class TimeSeriesCore(UserDict): raise TypeError(f"Invalid type {repr(type(key).__name__)} for slicing.") - # def __setitem__(self, key, value): - # pass - def __iter__(self): self.n = 0 return self diff --git a/fincal/fincal.py b/fincal/fincal.py index 4946cba..3f5450a 100644 --- a/fincal/fincal.py +++ b/fincal/fincal.py @@ -617,14 +617,20 @@ class TimeSeries(TimeSeriesCore): if not isinstance(other, TimeSeries): raise TypeError("Only objects of type TimeSeries can be passed for sync") - if self.frequency.days > other.frequency.days: - other = other.expand(to_frequency=self.frequency.symbol, method=fill_method) if self.frequency.days < other.frequency.days: + other = other.expand(to_frequency=self.frequency.symbol, method=fill_method) + if self.frequency.days > other.frequency.days: self = self.expand(to_frequency=other.frequency.symbol, method=fill_method) - for dt, val in self.data.items(): - if dt not in other: - pass # Need to create setitem first before implementing this + new_other = {} + for dt in self.dates: + closest = "previous" if fill_method == "ffill" else "next" + if dt in other: + new_other[dt] = other[dt][1] + else: + new_other[dt] = other.get(dt, closest=closest)[1] + + return self.__class__(new_other, frequency=other.frequency.symbol) def _preprocess_csv(file_path: str | pathlib.Path, delimiter: str = ",", encoding: str = "utf-8") -> List[list]: