From 77117326122087169365d2f9d8714fd8a581ac2c Mon Sep 17 00:00:00 2001 From: Kernc Date: Tue, 15 Jan 2019 11:12:07 +0100 Subject: [PATCH] DOC: Make MultipleTimeFrames tutorial simpler ... ... by moving behind-the-scenes explanation into `backtesting.lib.resample_apply()` docstring. --- backtesting/lib.py | 30 +++++++++++++++++++ doc/examples/Multiple Time Frames.ipynb | 40 +++---------------------- doc/examples/Multiple Time Frames.py | 40 +++---------------------- 3 files changed, 38 insertions(+), 72 deletions(-) diff --git a/backtesting/lib.py b/backtesting/lib.py index c95b200..32999cd 100644 --- a/backtesting/lib.py +++ b/backtesting/lib.py @@ -168,6 +168,36 @@ def resample_apply(rule: str, def init(self): self.sma = resample_apply( 'D', SMA, self.data.Close, 10, plot=False) + + This short snippet is roughly equivalent to: + + class System(Strategy): + def init(self): + # Strategy exposes `self.data` as raw NumPy arrays. + # Let's convert closing prices back to pandas Series. + close = pd.Series(self.data.Close, + index=self.data.index, + name='Close') + + # Resample to daily resolution. Aggregate groups + # using their last value (i.e. closing price at the end + # of the day). Notice `label='right'`. If it were set to + # 'left' (default), the strategy would exhibit + # look-ahead bias. + daily = close.resample('D', label='right').agg('last') + + # We apply SMA(10) to daily close prices, + # then reindex it back to original hourly index, + # forward-filling the missing values in each day. + # We make a separate function that returns the final + # indicator array. + def SMA(series, n): + from backtesting.test import SMA + return SMA(series, n).reindex(close.index).ffill() + + # The result equivalent to the short example above: + self.sma = self.I(SMA, daily, 10, plot=False) + """ if not isinstance(series, pd.Series): series = pd.Series(series, diff --git a/doc/examples/Multiple Time Frames.ipynb b/doc/examples/Multiple Time Frames.ipynb index 13fefb2..7efd0a8 100644 --- a/doc/examples/Multiple Time Frames.ipynb +++ b/doc/examples/Multiple Time Frames.ipynb @@ -394,40 +394,8 @@ " # Compute daily RSI(30)\n", " self.daily_rsi = self.I(RSI, self.data.Close, self.d_rsi)\n", " \n", - " # To construct weekly RSI, we have to resample\n", - " # the daily values.\n", - " \n", - " # Strategy exposes `self.data` as raw NumPy arrays.\n", - " # Let's make closing prices back a pandas Series.\n", - " \n", - " close = pd.Series(self.data.Close,\n", - " index=self.data.index,\n", - " name='Close')\n", - " \n", - " # Resample to weekly resolution, ending weeks on\n", - " # fridays. Aggregate groups using their last value\n", - " # (i.e. week's closing price).\n", - " # Notice `label='right'`. If it were set to 'left' (default),\n", - " # the strategy would exhibit look-ahead bias.\n", - " \n", - " weekly_close = close.resample('W-FRI', label='right').agg('last')\n", - " \n", - " # We apply RSI(30) to weekly close\n", - " # prices, then reindex it back to original daily\n", - " # index, forward-filling the missing values in each\n", - " # week.\n", - " # We make a separate function that returns the final\n", - " # indicator array.\n", - " \n", - " def W_RSI(series, n):\n", - " return RSI(series, n).reindex(close.index).ffill()\n", - " \n", - " self.weekly_rsi = self.I(W_RSI, weekly_close, self.w_rsi)\n", - " \n", - " \n", - " # ... And, now that you know what goes on behind the scenes,\n", - " # we could achieve the whole *exact* same thing with simpler:\n", - " \n", + " # To construct weekly RSI, we can use `resample_apply()`\n", + " # helper function from the library\n", " self.weekly_rsi = resample_apply(\n", " 'W-FRI', RSI, self.data.Close, self.w_rsi)\n", " \n", @@ -646,8 +614,8 @@ "source": [ "Better. While the strategy doesn't perform as well as simple buy & hold, it does so with significantly lower exposure (time in market).\n", "\n", - "In conclusion, to test strategies on multiple time frames, you need to pass in data in the lowest time frame, then resample it to higher time frames, apply the indicators, then resample back to lower time frame, filling in the in-betweens.\n", - "Or simply use [`backtesting.lib.resample_apply()`](https://kernc.github.io/backtesting.py/doc/backtesting/lib.html#backtesting.lib.resample_apply) function." + "In conclusion, to test strategies on multiple time frames, you need to pass in data in the lowest time frame, then resample it to higher time frames, apply the indicators, then resample back to the lower time frame, filling in the in-betweens.\n", + "Which is what the function [`backtesting.lib.resample_apply()`](https://kernc.github.io/backtesting.py/doc/backtesting/lib.html#backtesting.lib.resample_apply) does for you." ] } ], diff --git a/doc/examples/Multiple Time Frames.py b/doc/examples/Multiple Time Frames.py index bca59ce..841ac01 100644 --- a/doc/examples/Multiple Time Frames.py +++ b/doc/examples/Multiple Time Frames.py @@ -85,40 +85,8 @@ class System(Strategy): # Compute daily RSI(30) self.daily_rsi = self.I(RSI, self.data.Close, self.d_rsi) - # To construct weekly RSI, we have to resample - # the daily values. - - # Strategy exposes `self.data` as raw NumPy arrays. - # Let's make closing prices back a pandas Series. - - close = pd.Series(self.data.Close, - index=self.data.index, - name='Close') - - # Resample to weekly resolution, ending weeks on - # fridays. Aggregate groups using their last value - # (i.e. week's closing price). - # Notice `label='right'`. If it were set to 'left' (default), - # the strategy would exhibit look-ahead bias. - - weekly_close = close.resample('W-FRI', label='right').agg('last') - - # We apply RSI(30) to weekly close - # prices, then reindex it back to original daily - # index, forward-filling the missing values in each - # week. - # We make a separate function that returns the final - # indicator array. - - def W_RSI(series, n): - return RSI(series, n).reindex(close.index).ffill() - - self.weekly_rsi = self.I(W_RSI, weekly_close, self.w_rsi) - - - # ... And, now that you know what goes on behind the scenes, - # we could achieve the whole *exact* same thing with simpler: - + # To construct weekly RSI, we can use `resample_apply()` + # helper function from the library self.weekly_rsi = resample_apply( 'W-FRI', RSI, self.data.Close, self.w_rsi) @@ -168,5 +136,5 @@ backtest.plot() # Better. While the strategy doesn't perform as well as simple buy & hold, it does so with significantly lower exposure (time in market). # -# In conclusion, to test strategies on multiple time frames, you need to pass in data in the lowest time frame, then resample it to higher time frames, apply the indicators, then resample back to lower time frame, filling in the in-betweens. -# Or simply use [`backtesting.lib.resample_apply()`](https://kernc.github.io/backtesting.py/doc/backtesting/lib.html#backtesting.lib.resample_apply) function. +# In conclusion, to test strategies on multiple time frames, you need to pass in data in the lowest time frame, then resample it to higher time frames, apply the indicators, then resample back to the lower time frame, filling in the in-betweens. +# Which is what the function [`backtesting.lib.resample_apply()`](https://kernc.github.io/backtesting.py/doc/backtesting/lib.html#backtesting.lib.resample_apply) does for you.