Compare commits
2 Commits
fa2ab84c92
...
b5aa5d22d4
Author | SHA1 | Date | |
---|---|---|---|
b5aa5d22d4 | |||
03ccbe0cb1 |
@ -31,4 +31,8 @@ Fincal aims to simplify things by allowing you to:
|
||||
- [ ] Sharpe ratio
|
||||
- [ ] Jensen's Alpha
|
||||
- [ ] Beta
|
||||
- [x] Max drawdown
|
||||
- [x] Max drawdown
|
||||
|
||||
### Pending implementation
|
||||
- [ ] Use limit parameter in ffill and bfill
|
||||
- [ ] Implementation of ffill and bfill may be incorrect inside expand, check and correct
|
@ -130,7 +130,7 @@ class TimeSeries(TimeSeriesCore):
|
||||
res_string: str = "First date: {}\nLast date: {}\nNumber of rows: {}"
|
||||
return res_string.format(self.start_date, self.end_date, total_dates)
|
||||
|
||||
def ffill(self, inplace: bool = False, limit: int = None) -> Union[TimeSeries, None]:
|
||||
def ffill(self, inplace: bool = False, limit: int = None, skip_weekends: bool = False) -> Union[TimeSeries, None]:
|
||||
"""Forward fill missing dates in the time series
|
||||
|
||||
Parameters
|
||||
@ -141,18 +141,23 @@ class TimeSeries(TimeSeriesCore):
|
||||
limit : int, optional
|
||||
Maximum number of periods to forward fill
|
||||
|
||||
skip_weekends: bool, optional, default false
|
||||
Skip weekends while forward filling daily data
|
||||
|
||||
Returns
|
||||
-------
|
||||
Returns a TimeSeries object if inplace is False, otherwise None
|
||||
"""
|
||||
|
||||
eomonth: bool = True if self.frequency.days >= AllFrequencies.M.days else False
|
||||
dates_to_fill = create_date_series(self.start_date, self.end_date, self.frequency.symbol, eomonth)
|
||||
dates_to_fill = create_date_series(
|
||||
self.start_date, self.end_date, self.frequency.symbol, eomonth, skip_weekends=skip_weekends
|
||||
)
|
||||
|
||||
new_ts = dict()
|
||||
for cur_date in dates_to_fill:
|
||||
try:
|
||||
cur_val = self.data[cur_date]
|
||||
cur_val = self.get(cur_date, closest="previous")
|
||||
except KeyError:
|
||||
pass
|
||||
new_ts.update({cur_date: cur_val})
|
||||
@ -163,7 +168,7 @@ class TimeSeries(TimeSeriesCore):
|
||||
|
||||
return self.__class__(new_ts, frequency=self.frequency.symbol)
|
||||
|
||||
def bfill(self, inplace: bool = False, limit: int = None) -> Union[TimeSeries, None]:
|
||||
def bfill(self, inplace: bool = False, limit: int = None, skip_weekends: bool = False) -> Union[TimeSeries, None]:
|
||||
"""Backward fill missing dates in the time series
|
||||
|
||||
Parameters
|
||||
@ -174,13 +179,18 @@ class TimeSeries(TimeSeriesCore):
|
||||
limit : int, optional
|
||||
Maximum number of periods to back fill
|
||||
|
||||
skip_weekends: bool, optional, default false
|
||||
Skip weekends while forward filling daily data
|
||||
|
||||
Returns
|
||||
-------
|
||||
Returns a TimeSeries object if inplace is False, otherwise None
|
||||
"""
|
||||
|
||||
eomonth: bool = True if self.frequency.days >= AllFrequencies.M.days else False
|
||||
dates_to_fill = create_date_series(self.start_date, self.end_date, self.frequency.symbol, eomonth)
|
||||
dates_to_fill = create_date_series(
|
||||
self.start_date, self.end_date, self.frequency.symbol, eomonth, skip_weekends=skip_weekends
|
||||
)
|
||||
dates_to_fill.append(self.end_date)
|
||||
|
||||
bfill_ts = dict()
|
||||
@ -574,9 +584,9 @@ class TimeSeries(TimeSeriesCore):
|
||||
output_ts: TimeSeries = TimeSeries(new_ts, frequency=to_frequency.symbol)
|
||||
|
||||
if method == "ffill":
|
||||
output_ts.ffill(inplace=True)
|
||||
output_ts.ffill(inplace=True, skip_weekends=skip_weekends)
|
||||
elif method == "bfill":
|
||||
output_ts.bfill(inplace=True)
|
||||
output_ts.bfill(inplace=True, skip_weekends=skip_weekends)
|
||||
else:
|
||||
raise NotImplementedError(f"Method {method} not implemented")
|
||||
|
||||
|
@ -298,6 +298,60 @@ class TestReturns:
|
||||
with pytest.raises(DateNotFoundError):
|
||||
ts.calculate_returns("2020-11-25", return_period_unit="days", return_period_value=90, closest_max_days=10)
|
||||
|
||||
def test_rolling_returns(self):
|
||||
# Yet to be written
|
||||
return True
|
||||
|
||||
|
||||
class TestExpand:
|
||||
def test_weekly_to_daily(self):
|
||||
ts_data = create_test_data(AllFrequencies.W, 10)
|
||||
ts = TimeSeries(ts_data, "W")
|
||||
expanded_ts = ts.expand("D", "ffill")
|
||||
assert len(expanded_ts) == 64
|
||||
assert expanded_ts.frequency.name == "daily"
|
||||
assert expanded_ts.iloc[0][1] == expanded_ts.iloc[1][1]
|
||||
|
||||
def test_weekly_to_daily_no_weekends(self):
|
||||
ts_data = create_test_data(AllFrequencies.W, 10)
|
||||
ts = TimeSeries(ts_data, "W")
|
||||
expanded_ts = ts.expand("D", "ffill", skip_weekends=True)
|
||||
assert len(expanded_ts) == 45
|
||||
assert expanded_ts.frequency.name == "daily"
|
||||
assert expanded_ts.iloc[0][1] == expanded_ts.iloc[1][1]
|
||||
|
||||
def test_monthly_to_daily(self):
|
||||
ts_data = create_test_data(AllFrequencies.M, 6)
|
||||
ts = TimeSeries(ts_data, "M")
|
||||
expanded_ts = ts.expand("D", "ffill")
|
||||
assert len(expanded_ts) == 152
|
||||
assert expanded_ts.frequency.name == "daily"
|
||||
assert expanded_ts.iloc[0][1] == expanded_ts.iloc[1][1]
|
||||
|
||||
def test_monthly_to_daily_no_weekends(self):
|
||||
ts_data = create_test_data(AllFrequencies.M, 6)
|
||||
ts = TimeSeries(ts_data, "M")
|
||||
expanded_ts = ts.expand("D", "ffill", skip_weekends=True)
|
||||
assert len(expanded_ts) == 109
|
||||
assert expanded_ts.frequency.name == "daily"
|
||||
assert expanded_ts.iloc[0][1] == expanded_ts.iloc[1][1]
|
||||
|
||||
def test_monthly_to_weekly(self):
|
||||
ts_data = create_test_data(AllFrequencies.M, 6)
|
||||
ts = TimeSeries(ts_data, "M")
|
||||
expanded_ts = ts.expand("W", "ffill")
|
||||
assert len(expanded_ts) == 22
|
||||
assert expanded_ts.frequency.name == "weekly"
|
||||
assert expanded_ts.iloc[0][1] == expanded_ts.iloc[1][1]
|
||||
|
||||
def test_yearly_to_monthly(self):
|
||||
ts_data = create_test_data(AllFrequencies.Y, 5)
|
||||
ts = TimeSeries(ts_data, "Y")
|
||||
expanded_ts = ts.expand("M", "ffill")
|
||||
assert len(expanded_ts) == 49
|
||||
assert expanded_ts.frequency.name == "monthly"
|
||||
assert expanded_ts.iloc[0][1] == expanded_ts.iloc[1][1]
|
||||
|
||||
|
||||
class TestReturnsAgain:
|
||||
data = [
|
||||
|
Loading…
Reference in New Issue
Block a user