I've written the following strategy:
%%writefile pv_strategy6.py
import zipline.api as algo
from zipline.finance import commission, slippage
from zipline.pipeline import Pipeline
from zipline.pipeline.data import USEquityPricing
from zipline.pipeline.factors import AverageDollarVolume
from zipline.pipeline.factors import CustomFactor
MONTH = 21
N_LONGS = 50
N_SHORTS = 50
class ParkinsonVolatility(CustomFactor):
inputs = [USEquityPricing.high, USEquityPricing.low]
window_length = MONTH
def compute(self, today, assets, out, highs, lows):
rs = (1.0 / (4.0 * np.log(2.0))) * (np.log(highs / lows)) ** 2.0
vol = np.sqrt(252 * np.nanmean(rs, axis=0))
out[:] = (vol - np.mean(vol)) / np.std(vol)
def make_pipeline():
pipe = Pipeline(
columns={
"parkinson": ParkinsonVolatility()
},
screen=AverageDollarVolume(window_length=30) > 10e6
)
return pipe
def initialize(context):
attach_pipeline(compute_factors(), "factor_pipeline")
schedule_function(
rebalance,
date_rules.week_start(),
time_rules.market_open(),
)
set_commission(
us_equities=commission.PerShare(
cost=0.005,
min_trade_cost=2.0
)
)
set_slippage(
us_equities=slippage.VolumeShareSlippage(
volume_limit=0.0025,
price_impact=0.01
)
)
def before_trading_start(context, data):
context.factor_data = pipeline_output("factor_pipeline")
record(factor_data=context.factor_data.ranking)
assets = context.factor_data.index
record(prices=data.current(assets, "price"))
def rebalance(context, data):
factor_data = context.factor_data
assets = factor_data.index
longs = assets[factor_data.longs]
shorts = assets[factor_data.shorts]
divest = context.portfolio.positions.keys() - longs.union(shorts)
# Print some portfolio details.
print(
f"{get_datetime().date()} | Longs {len(longs)} | Shorts | {len(shorts)} | {context.portfolio.portfolio_value}"
)
# Execute the trades with equal weight
exec_trades(data, assets=divest, target_percent=0)
exec_trades(data, assets=longs, target_percent=1 / N_LONGS) #if N_LONGS else 0)
exec_trades(data, assets=shorts, target_percent=-1 / N_SHORTS) #if N_SHORTS else 0)
def exec_trades(data, assets, target_percent):
# Loop through every asset...
for asset in assets:
# ...if the asset is tradeable and there are no open orders...
if data.can_trade(asset) and not get_open_orders(asset):
# ...execute the order against the target percent
order_target_percent(asset, target_percent)
This code executes in Jupyter without any errors. I then attempt to run the backtest as follows:
from quantrocket.zipline import backtest
backtest("pv_strategy6",
progress="M", # Use for long running test. 'D'= daily, 'W'=weeky, 'M'=monthly, 'Q'=quarterly,'A'=annually
start_date="2017-01-01", end_date="2018-01-01",
filepath_or_buffer="PV_results.csv") # are you nameing the file of the backtest here?
And I'm receiving the following error:
HTTPError Traceback (most recent call last)
Input In [85], in <cell line: 7>()
1 # Strategy files should be placed in /codeload/zipline/, that is, inside a zipline subdirectory in the
2 # JupyterLab file browser. The filename without the .py extension is the code you will use to refer to the strategy in
3 # backtesting and trading. For example, if you name the file dma.py, the strategy's code is dma. Use this code to
4 # run a backtest.
6 from quantrocket.zipline import backtest
----> 7 backtest("pv_strategy6",
8 progress="M", # Use for long running test. 'D'= daily, 'W'=weeky, 'M'=monthly, 'Q'=quarterly,'A'=annually
9 start_date="2017-01-01", end_date="2018-01-01",
10 filepath_or_buffer="PV_results.csv") # are you nameing the file of the backtest here?
File /opt/conda/lib/python3.9/site-packages/quantrocket/zipline.py:817, in backtest(strategy, data_frequency, capital_base, bundle, start_date, end_date, progress, params, filepath_or_buffer)
813 _params["progress"] = progress
815 response = houston.post("/zipline/backtests/{0}".format(strategy), params=_params, timeout=606096)
--> 817 houston.raise_for_status_with_json(response)
819 filepath_or_buffer = filepath_or_buffer or sys.stdout
820 write_response_to_filepath_or_buffer(filepath_or_buffer, response)
File /opt/conda/lib/python3.9/site-packages/quantrocket/houston.py:225, in Houston.raise_for_status_with_json(response)
223 e.json_response = {}
224 e.args = e.args + ("please check the logs for more details",)
--> 225 raise e
File /opt/conda/lib/python3.9/site-packages/quantrocket/houston.py:217, in Houston.raise_for_status_with_json(response)
212 """
213 Raises 400/500 error codes, attaching a json response to the
214 exception, if possible.
215 """
216 try:
--> 217 response.raise_for_status()
218 except requests.exceptions.HTTPError as e:
219 try:
File /opt/conda/lib/python3.9/site-packages/requests/models.py:1021, in Response.raise_for_status(self)
1016 http_error_msg = (
1017 f"{self.status_code} Server Error: {reason} for url: {self.url}"
1018 )
1020 if http_error_msg:
-> 1021 raise HTTPError(http_error_msg, response=self)
HTTPError: ('400 Client Error: BAD REQUEST for url: http://houston/zipline/backtests/pv_strategy6?start_date=2017-01-01&end_date=2018-01-01&progress=M', {'status': 'error', 'msg': "name 'attach_pipeline' is not defined (see detailed logs for full traceback)"})
Any assistance / insights would be appreciated.
Thanks.