Problem statement: The first cell of the Sell-gap part5 notebook not working
How to reproduce:
- Clone Sell-gap repo
from quantrocket.codeload import clone
clone("sell-gap")
- Run part1 ~ part 4 notebooks
- Open part5 notebook and run the first cell
from quantrocket.zipline import backtest
backtest(
"sell-gap",
start_date="2015-01-03",
end_date="2020-08-18",
capital_base=2e4,
filepath_or_buffer="sell_gap_backtest_results.csv",
progress="M")
Expected behavior: No errors
Actual behavior: See error message below
HTTPError: ('500 Server Error: INTERNAL SERVER ERROR for url: http://houston/zipline/backtests/sell-gap?capital_base=20000.0&start_date=2015-01-03&end_date=2020-08-18', {'status': 'error', 'msg': "Timestamp('2021-10-08 00:00:00+0000', tz='UTC')"})
Comments: I'm not sure where did this 2021-10-08
come from in the error message.
Full error logs:
quantrocket_zipline_1|# Copyright 2020 QuantRocket LLC - All Rights Reserved
quantrocket_zipline_1|#
quantrocket_zipline_1|# Licensed under the Apache License, Version 2.0 (the "License");
quantrocket_zipline_1|# you may not use this file except in compliance with the License.
quantrocket_zipline_1|# You may obtain a copy of the License at
quantrocket_zipline_1|#
quantrocket_zipline_1|# http://www.apache.org/licenses/LICENSE-2.0
quantrocket_zipline_1|#
quantrocket_zipline_1|# Unless required by applicable law or agreed to in writing, software
quantrocket_zipline_1|# distributed under the License is distributed on an "AS IS" BASIS,
quantrocket_zipline_1|# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
quantrocket_zipline_1|# See the License for the specific language governing permissions and
quantrocket_zipline_1|# limitations under the License.
quantrocket_zipline_1|
quantrocket_zipline_1|import zipline.api as algo
quantrocket_zipline_1|from zipline.pipeline import Pipeline
quantrocket_zipline_1|from zipline.pipeline.factors import AverageDollarVolume, SimpleMovingAverage, ExponentialWeightedMovingStdDev
quantrocket_zipline_1|from zipline.pipeline.data.equity_pricing import EquityPricing
quantrocket_zipline_1|from zipline.pipeline.data.master import SecuritiesMaster
quantrocket_zipline_1|from zipline.finance.execution import MarketOrder, LimitOrder
quantrocket_zipline_1|from zipline.finance.order import ORDER_STATUS
quantrocket_zipline_1|from zipline.finance import slippage, commission
quantrocket_zipline_1|from quantrocket.realtime import collect_market_data
quantrocket_zipline_1|from codeload.sell_gap.pipeline import make_pipeline
quantrocket_zipline_1|
quantrocket_zipline_1|def initialize(context):
quantrocket_zipline_1| """
quantrocket_zipline_1| Called once at the start of a backtest, and once per day at
quantrocket_zipline_1| the start of live trading.
quantrocket_zipline_1| """
quantrocket_zipline_1| # Attach the pipeline to the algo
quantrocket_zipline_1| algo.attach_pipeline(make_pipeline(), 'pipeline')
quantrocket_zipline_1|
quantrocket_zipline_1| # Set SPY as benchmark
quantrocket_zipline_1| algo.set_benchmark(algo.sid("FIBBG000BDTBL9"))
quantrocket_zipline_1|
quantrocket_zipline_1| # identify down gaps immediately after the opening
quantrocket_zipline_1| algo.schedule_function(
quantrocket_zipline_1| find_down_gaps,
quantrocket_zipline_1| algo.date_rules.every_day(),
quantrocket_zipline_1| algo.time_rules.market_open(minutes=1),
quantrocket_zipline_1| )
quantrocket_zipline_1|
quantrocket_zipline_1| # at 9:40, short stocks that gapped down
quantrocket_zipline_1| algo.schedule_function(
quantrocket_zipline_1| short_down_gaps,
quantrocket_zipline_1| algo.date_rules.every_day(),
quantrocket_zipline_1| algo.time_rules.market_open(minutes=10),
quantrocket_zipline_1| )
quantrocket_zipline_1|
quantrocket_zipline_1| # close positions 5 minutes before the close
quantrocket_zipline_1| algo.schedule_function(
quantrocket_zipline_1| close_positions,
quantrocket_zipline_1| algo.date_rules.every_day(),
quantrocket_zipline_1| algo.time_rules.market_close(minutes=5),
quantrocket_zipline_1| )
quantrocket_zipline_1|
quantrocket_zipline_1| # Set commissions and slippage
quantrocket_zipline_1| algo.set_commission(
quantrocket_zipline_1| commission.PerShare(cost=0.0))
quantrocket_zipline_1| algo.set_slippage(
quantrocket_zipline_1| slippage.FixedBasisPointsSlippage(
quantrocket_zipline_1| basis_points=3.0))
quantrocket_zipline_1|
quantrocket_zipline_1|def before_trading_start(context, data):
quantrocket_zipline_1| """
quantrocket_zipline_1| Called every day before market open. Gathers today's pipeline
quantrocket_zipline_1| output and initiates real-time data collection (in live trading).
quantrocket_zipline_1| """
quantrocket_zipline_1| context.candidates = algo.pipeline_output('pipeline')
quantrocket_zipline_1| context.assets_to_short = []
quantrocket_zipline_1| context.target_value_per_position = -50e3
quantrocket_zipline_1|
quantrocket_zipline_1| # Start real-time data collection if we are in live trading
quantrocket_zipline_1| if algo.get_environment("arena") == "trade":
quantrocket_zipline_1|
quantrocket_zipline_1| # start real-time tick data collection for our candidates...
quantrocket_zipline_1| sids = [asset.real_sid for asset in context.candidates.index]
quantrocket_zipline_1|
quantrocket_zipline_1| if sids:
quantrocket_zipline_1|
quantrocket_zipline_1| # collect the trade/volume data
quantrocket_zipline_1| collect_market_data(
quantrocket_zipline_1| "us-stk-tick",
quantrocket_zipline_1| sids=sids,
quantrocket_zipline_1| until="09:32:00 America/New_York")
quantrocket_zipline_1|
quantrocket_zipline_1| # ...and point Zipline to the derived aggregate db
quantrocket_zipline_1| algo.set_realtime_db(
quantrocket_zipline_1| "us-stk-tick-1min",
quantrocket_zipline_1| fields={
quantrocket_zipline_1| "close": "LastPriceClose",
quantrocket_zipline_1| "open": "LastPriceOpen",
quantrocket_zipline_1| "high": "LastPriceHigh",
quantrocket_zipline_1| "low": "LastPriceLow",
quantrocket_zipline_1| "volume": "VolumeClose"}) # for IBKR real-time data, use VolumeClose
quantrocket_zipline_1|
quantrocket_zipline_1|def find_down_gaps(context, data):
quantrocket_zipline_1| """
quantrocket_zipline_1| Identify stocks that gapped down below their moving average.
quantrocket_zipline_1| """
quantrocket_zipline_1|
quantrocket_zipline_1| if len(context.candidates) == 0:
quantrocket_zipline_1| return
quantrocket_zipline_1|
quantrocket_zipline_1| today_opens = data.current(context.candidates.index, 'open')
quantrocket_zipline_1| prior_lows = context.candidates["prior_low"]
quantrocket_zipline_1| stds = context.candidates["std"]
quantrocket_zipline_1|
quantrocket_zipline_1| # find stocks that opened sufficiently below the prior day's low...
quantrocket_zipline_1| gapped_down = today_opens < (prior_lows - stds)
quantrocket_zipline_1|
quantrocket_zipline_1| # ...and are now below their moving averages
quantrocket_zipline_1| are_below_mavg = (today_opens < context.candidates["mavg"])
quantrocket_zipline_1|
quantrocket_zipline_1| assets_to_short = context.candidates[
quantrocket_zipline_1| gapped_down
quantrocket_zipline_1| & are_below_mavg
quantrocket_zipline_1| ]
quantrocket_zipline_1|
quantrocket_zipline_1| # Limit to the top 10 by std
quantrocket_zipline_1| assets_to_short = assets_to_short.sort_values(
quantrocket_zipline_1| "std", ascending=False).iloc[:10].index
quantrocket_zipline_1|
quantrocket_zipline_1| context.assets_to_short = assets_to_short
quantrocket_zipline_1|
quantrocket_zipline_1|def short_down_gaps(context, data):
quantrocket_zipline_1| """
quantrocket_zipline_1| Short the stocks that gapped down.
quantrocket_zipline_1| """
quantrocket_zipline_1| for asset in context.assets_to_short:
quantrocket_zipline_1|
quantrocket_zipline_1| # Sell with market order
quantrocket_zipline_1| algo.order_value(
quantrocket_zipline_1| asset,
quantrocket_zipline_1| context.target_value_per_position,
quantrocket_zipline_1| style=MarketOrder(exchange="SMART") # for IBKR, specify exchange (e.g. exchange="SMART")
quantrocket_zipline_1| )
quantrocket_zipline_1|
quantrocket_zipline_1|def close_positions(context, data):
quantrocket_zipline_1| """
quantrocket_zipline_1| Closes all positions.
quantrocket_zipline_1| """
quantrocket_zipline_1| for asset, position in context.portfolio.positions.items():
quantrocket_zipline_1| algo.order(
quantrocket_zipline_1| asset,
quantrocket_zipline_1| -position.amount,
quantrocket_zipline_1| style=MarketOrder(exchange="SMART")
quantrocket_zipline_1| )
quantrocket_zipline_1|Traceback (most recent call last):
quantrocket_zipline_1| File "/opt/conda/lib/python3.6/site-packages/trading_calendars/utils/memoize.py", line 47, in __get__
quantrocket_zipline_1| return self._cache[instance]
quantrocket_zipline_1| File "/opt/conda/lib/python3.6/weakref.py", line 394, in __getitem__
quantrocket_zipline_1| return self.data[ref(key)]
quantrocket_zipline_1|KeyError: <weakref at 0x7fe099255b38; to 'BcolzMinuteBarReader' at 0x7fe09952eef0>
quantrocket_zipline_1|
quantrocket_zipline_1|During handling of the above exception, another exception occurred:
quantrocket_zipline_1|
quantrocket_zipline_1|Traceback (most recent call last):
quantrocket_zipline_1| File "pandas/_libs/index.pyx", line 449, in pandas._libs.index.DatetimeEngine.get_loc
quantrocket_zipline_1| File "pandas/_libs/hashtable_class_helper.pxi", line 811, in pandas._libs.hashtable.Int64HashTable.get_item
quantrocket_zipline_1| File "pandas/_libs/hashtable_class_helper.pxi", line 817, in pandas._libs.hashtable.Int64HashTable.get_item
quantrocket_zipline_1|KeyError: 1633651200000000000
quantrocket_zipline_1|
quantrocket_zipline_1|During handling of the above exception, another exception occurred:
quantrocket_zipline_1|
quantrocket_zipline_1|Traceback (most recent call last):
quantrocket_zipline_1| File "sym://qrocket_app_py", line 738, in post
quantrocket_houston_1|172.18.0.12 - - [11/Oct/2020:02:56:29 +0000] "POST /zipline/backtests/sell-gap?data_frequency=minute&capital_base=20000.0&bundle=usstock-1min&start_date=2015-01-03&end_date=2020-08-18&progress=M HTTP/1.1" 500 78 "-" "-"
quantrocket_zipline_1| File "sym://qrocket_qrzipline_backtest_py", line 110, in backtest_algo
quantrocket_zipline_1| File "/opt/conda/lib/python3.6/site-packages/zipline/data/data_portal.py", line 192, in __init__
quantrocket_zipline_1| for reader in [equity_minute_reader, future_minute_reader]
quantrocket_zipline_1| File "/opt/conda/lib/python3.6/site-packages/zipline/data/data_portal.py", line 193, in <listcomp>
quantrocket_zipline_1| if reader is not None
quantrocket_zipline_1| File "/opt/conda/lib/python3.6/site-packages/trading_calendars/utils/memoize.py", line 49, in __get__
quantrocket_zipline_1| self._cache[instance] = val = self._get(instance)
quantrocket_zipline_1| File "/opt/conda/lib/python3.6/site-packages/zipline/data/minute_bars.py", line 973, in last_available_dt
quantrocket_zipline_1| _, close = self.calendar.open_and_close_for_session(self._end_session)
quantrocket_zipline_1| File "/opt/conda/lib/python3.6/site-packages/trading_calendars/trading_calendar.py", line 768, in open_and_close_for_session
quantrocket_zipline_1| sched.at[session_label, 'market_open'].tz_localize(UTC),
quantrocket_zipline_1| File "/opt/conda/lib/python3.6/site-packages/pandas/core/indexing.py", line 1869, in __getitem__
quantrocket_zipline_1| return self.obj._get_value(*key, takeable=self._takeable)
quantrocket_zipline_1| File "/opt/conda/lib/python3.6/site-packages/pandas/core/frame.py", line 1985, in _get_value
quantrocket_zipline_1| return engine.get_value(series._values, index)
quantrocket_zipline_1| File "pandas/_libs/index.pyx", line 83, in pandas._libs.index.IndexEngine.get_value
quantrocket_zipline_1| File "pandas/_libs/index.pyx", line 91, in pandas._libs.index.IndexEngine.get_value
quantrocket_zipline_1| File "pandas/_libs/index.pyx", line 451, in pandas._libs.index.DatetimeEngine.get_loc
quantrocket_zipline_1|KeyError: Timestamp('2021-10-08 00:00:00+0000', tz='UTC')
quantrocket_zipline_1|
quantrocket_zipline_1|[pid: 174|app: 0|req: 54/54] 172.18.0.12 () {34 vars in 651 bytes} [Sun Oct 11 02:56:29 2020] POST /zipline/backtests/sell-gap?data_frequency=minute&capital_base=20000.0&bundle=usstock-1min&start_date=2015-01-03&end_date=2020-08-18&progress=M => generated 78 bytes in 119 msecs (HTTP/1.1 500) 2 headers in 90 bytes (1 switches on core 1)