def zipline_initialize(context: TradingAlgorithm): """Zipline backtest initialization method override. Initializes context namespace variables used during the portfolio optimization, and sets zipline configuration options for the simulation. Arguments: context {TradingAlgorithm} -- Context variable for the algorithm """ # Zipline context namespace variables context.first_run = True # First run flag context.synthetics = dict( ) # Dictionary to store synthetic ETF objects context.port = MinimumVariance() # Initializing portfolio # Enforcing long trades only # NOTE: This is commented out because of rounding bugs; i.e. when # certain positions were reduced to 0, some of the rounding caused # some positions to go to -1 shares. This is neglegible, and as # the current optimization enforces no shorts, this # condition is relaxed here. # set_long_only() # Setting the per-trade commission from config set_commission(PerDollar(cost=config.trade_commission)) # Initializing utilities module context.util = Utilities() # Initializing bookkeeping module context.books = Bookkeeping()
def zipline_handle_data(context: TradingAlgorithm, data: BarData): """Zipline `handle_data` method override. Handles all trading operations for the algorithm. Additionally, this method also handles synthetic ETF initialization, portfolio balancing, and logging. In summary, this method initializes all synthetic ETFs on the first iteration, balances, and opens positions in the necessary assets. After that, it checks the current date of the simulation against the triggers for portfolio balancing and ETF restructuring provided in the configuration file to initialize a rebalancing or restructuring operation, respectively. Arguments: context {TradingAlgorithm} -- Zipline context namespace variable. data {BarData} -- Instance zipline data bundle. """ # Reset log (to handle Zipline's forward-propagation behavior of the # `record(...)` function) context.books.cleanLog() # First run operations if (context.first_run): # Validate sector universe config.sector_universe = Backtest.validateSectorUniverse( candidate_sector_universe=config.sector_universe, zipline_data=data) # Building synthetic sector ETFs Backtest.buildSyntheticETFs(context=context, zipline_data=data) # Computing initial portfolio, updating positions Backtest.rebalancePortfolio(context=context, zipline_data=data, update_positions=True, log_commission=False) # Updating initial flags for rebalancing/restructuring trigger context.util.setInitialFlags() # Logging ETF prices context.books.etfDataLog(etf_prices=Backtest.getETFPrices( context, data), etf_weights=context.port_w) # Skip rest of logic for first iteration, update iteration flag context.first_run = False return # Portfolio Rebalancing if context.util.isRebalanceTriggered(): Backtest.rebalancePortfolio(context=context, zipline_data=data, update_positions=True, log_commission=True) # Synthetic ETF restructuring if context.util.isRestructureTriggered(): Backtest.restructureETF(context=context, zipline_data=data, update_positions=True, log_commission=True) # Log ETF prices context.books.etfDataLog(etf_prices=Backtest.getETFPrices( context, data), etf_weights=context.port_w)