I noticed many quants here have ideas of strategies but they struggle to integrate them in a clean modular implementation. Here is a modular framework designed to allow separate implementation of the different functions inside a trading algo. It comes with the implementation of a basic crossover moving average strategy to illustrate how it works.
Quick explanation of the framework. The central piece of the framework is the portfolio manager that is responsible of the portfolio. It manages alpha generators that are seeking the alpha and ask the portfolio manager for allocation. The portfolio manager gets all the requests of the alpha generator and computes a target portfolio being helped by a risk manager and a transaction cost simulator. It then transmits the target to the execution handler which is responsible of the order strategy to reach the target. All these modules are independant and can easily be modified and used again in other strategies.
|Returns||1 Month||3 Month||6 Month||12 Month|
|Alpha||1 Month||3 Month||6 Month||12 Month|
|Beta||1 Month||3 Month||6 Month||12 Month|
|Sharpe||1 Month||3 Month||6 Month||12 Month|
|Sortino||1 Month||3 Month||6 Month||12 Month|
|Volatility||1 Month||3 Month||6 Month||12 Month|
|Max Drawdown||1 Month||3 Month||6 Month||12 Month|
# L-Predator Analytics (wwww.lpredatoranalytics.com) framework to design # systematic strategies on Quantopian. # # The framework contains modules for alpha generation, risk management, # transaction cost, portfolio management and allocation and execution. It # allows to work on part of the trading process and uses the benefits for # all strategies. # # The framework comes with a crossing moving average strategy. # external libraries import math # abstract class to implement # Alpha generator module is supposed to find edge on the market and ask the # portfolio manager for allocation. Once the portfolio manager gives allocation # to the alpha generator, ag keeps track of positions associated with it and if # nothing change at the next portfolio reallocation the allocation it asks is # the one associated to the positions associated to it. class AlphaGenerator: def __init__(self): # allocation wanted self.alloc = dict() # positions associated to the strategy self.pos = dict() def compute_allocation(self, context, data): raise NotImplementedError() # Execution Handler module takes care of the strategy to reach allocation # once the portfolio manager gives a target allocation. class ExecutionHandler(object): # decides which order to make def compute_orders(self, context, data, target_portfolio): raise NotImplementedError() # Portfolio manager module manages the portfolio on the chosen frequency. It # has alpha generators under control that get edge and ask for allocation. It # then compute a target allocation being helped by a risk manager and a # transaction cost model. class PortfolioManager: def __init__(self): # target_portfolio self.target_portfolio = dict() # list of strategies self.list_alpha =  # computes the target portfolio def compute_target(self, context, data): raise NotImplementedError() # Risk manager module help the portfolio manager to measure the risks held by # the portfolio. It can held models of volatility or correlation and market # models class RiskManager: pass # Transaction cost module can help the execution handler and the portfolio # manager to make better decisions regarding the allocation and the strategy # to put orders class TransactionCost: pass # Implementation of concrete class to illustrate the framework with a crossover # moving average strategy. Each implementation of these module can be # independantly used in other strategies or replaced by customed ones. # AlphaGeneratorMa goes long if short term moving average is above long term # moving average and short else class AlphaGeneratorMa(AlphaGenerator): def __init__(self, sid_stock, len_short_ma=20, len_long_ma=50): AlphaGenerator.__init__(self) # length used to compute short term ma self.len_short_ma = len_short_ma # length used to compute long term ma self.len_long_ma = len_long_ma # stock on which ma strategy is applied self.sid_stock = sid_stock def compute_allocation(self, context, data): # compute simple moving average short_ma = data[self.sid_stock].mavg(self.len_short_ma) long_ma = data[self.sid_stock].mavg(self.len_long_ma) # go long with full exposure if short ma > long ma, short # else if (short_ma > long_ma): self.alloc[self.sid_stock] = 1 else: self.alloc[self.sid_stock] = -1 # ExecutionHandlerMarket makes market orders only to reach allocation class ExecutionHandlerMarket(ExecutionHandler): def compute_orders(self, context, data, target_portfolio): for stock in context.securities: order_target_percent(stock, target_portfolio[stock]) # PortfolioManagerEquiWeight gives equal dollar allocation to each alpha # generator in the portfolio class PortfolioManagerEquiWeight(PortfolioManager): def __init__(self): PortfolioManager.__init__(self) def compute_target(self, context, data): # get number of alpha generators nb_alpha = len(self.list_alpha) # clear target allocation for stock in context.securities: self.target_portfolio[stock] = 0 # for each alpha add allocation to the target for alpha in self.list_alpha: for stock in alpha.alloc: alloc_alpha = alpha.alloc[stock] / nb_alpha self.target_portfolio[stock] = self.target_portfolio[stock] + \ alloc_alpha # update the number of shares the alpha is responsible for port_value = context.portfolio.portfolio_value price = data[stock].price alpha.pos[stock] = math.floor(alloc_alpha * port_value / price) # initialize set up the algorithm def initialize(context): # set up of the universe context.securities = symbols('SPY') # first time initialization of all components of the algorithm try: context.first_time except: context.first_time = False # creation of a portfolio manager context.p_manager = PortfolioManagerEquiWeight() # creation of execution handler context.exec_handler = ExecutionHandlerMarket() # creation of alpha generator alpha_ma_spy = AlphaGeneratorMa(sid_stock=sid(8554)) # alpha generator is added to the portfolio manager context.p_manager.list_alpha.append(alpha_ma_spy) # rebalance frequency # the portfolio will compute new allocation each day one minute before # close so that all orders can be executed at close schedule_function(func=rebalance_portfolio, time_rule=time_rules.market_close(minutes=1)) # transaction cost # Quantopian default model # handle data is called every minute def handle_data(context, data): pass # rebalance_portfolio is called at each reallocation. It computes the new # target portfolio and organizes the order strategy to reach it def rebalance_portfolio(context, data): # compute new allocation each alpha would like for alpha in context.p_manager.list_alpha: alpha.compute_allocation(context, data) # compute new target portfolio context.p_manager.compute_target(context, data) # compute order strategy target = context.p_manager.target_portfolio context.exec_handler.compute_orders(context, data, target)