Multiple Strategies in a Single Algo ====================================== Sometimes we may want to run multiple strategies with different logic and order/ positions management within a single algo. This maybe useful when we are running an ensemble of strategies (with a capital allocation rule) in a single algorithm. There are other cases too. Blueshift API support such use cases by allowing to dynamically add or remove ``sub-strategies`` in a single algo. Sub-Strategies --------------- An algo run on Blueshift with the main context as defined by the `context` variable available through the :ref:`main callback
` functions. This is the main :ref:`context ` of the algo run. However, by using the sub-strategies API, we can add a ``sub-strategy`` to the algo (and remove it when required). Each such sub-strategy runs within its own context - also known as ``sub-context``. Since each such sub-contexts are maintained independently, a sub-strategy can maintain its independent orders and positions tracking. We can generally use the API functions as is in either in the context of the main strategy or any sub-strategies. Blueshift will automatically apply the correct context. This allows the main and the sub-strategies to work independetly from each other, without being aware of each others presence. Defining a sub-strategy ----------------------- A sub-strategy can be defined by sub-classing the Strategy class and then overriding the event handlers as required. .. py:module:: blueshift.core.algorithm.strategy .. autoclass:: Strategy() :noindex: Sub-strategy methods and attributes ++++++++++++++++++++++++++++++++++++ .. autoattribute:: Strategy.name .. automethod:: Strategy.initialize .. automethod:: Strategy.before_trading_start .. automethod:: Strategy.handle_data .. automethod:: Strategy.on_data .. automethod:: Strategy.on_trade .. automethod:: Strategy.after_trading_hours .. automethod:: Strategy.analyze .. automethod:: Strategy.on_error .. automethod:: Strategy.on_cancel The callbacks are similar in functionality as the :ref:`main event callbacks`. These will be automatically called (on appropriate events) once a sub-strategy is added in the algo run. Once a sub-strategy is removed, its callbacks will not be invoked anymore. Adding a sub-strategy ---------------------- .. py:module:: blueshift.core.algorithm.algorithm :noindex: .. automethod:: TradingAlgorithm.add_strategy This API method must be called from the main strategy, as a sub-strategy can be added from the main context only. Cancelling a sub-strategy -------------------------- .. automethod:: TradingAlgorithm.cancel_strategy This API method must be called from the main strategy, or from the sub-strategy itself that is being cancelled. Sub-strategy order and position tracking ----------------------------------------- Each sub-strategies, and the main strategy, will maintain their independent version of orders and positions tracking. That means order APIs (:ref:`trading APIs`), including order placement, order management, algo order and stoploss/ take-profit APIs will maintain and track their own contexts. Simulation APIs (:ref:`simulation APIs`) will also affect behaviour of only the respective contexts. For example, calling ``get_open_orders`` from a sub-context will return only the open orders placed from the corresponding sub-strategy. However, a few sets of APIs are global, in the sense that they will affect all contexts - the main context as well as any sub-contexts created. This inclues the :ref:`squareoff` API, the pipeline APIs (:ref:`pipeline`) and some :ref:`risk management APIs`). This means, for example, if we call square-off from any context, all positions in all active contexts will be squared-off by default. See more in the documentation of the respective APIs. Below code snippet shows how to add and cancel of sub-strategies in an algo run. Sub-strategies are added in the main context, but can be removed from itself or from the main context. .. code-block:: python from blueshift.api import order, symbol, schedule_once, cancel_strategy from blueshift.api import add_strategy, exit_when_done, get_context from blueshift.protocol import Strategy class Strategy1(Strategy): def initialize(self, context): # this context refers to the sub-context for this sub-strategy schedule_once(self.strategy) def strategy(self, context, data): order(symbol('MSFT'), 1) for oid in context.orders: # prints only MSFT order print(context.orders[oid].to_dict()) # cancelling sub-strategy from itself cancel_strategy(self.name) class Strategy2(Strategy): def initialize(self, context): # this context refers to the sub-context for this sub-strategy schedule_once(self.strategy) def strategy(self, context, data): order(symbol('AAPL'), 1) for oid in context.orders: # prints only AAPL order print(context.orders[oid].to_dict()) def initialize(context): # this context refers to the main context # add the sub-strategies add_strategy(Strategy1('strategy1', 15000)) add_strategy(Strategy2('strategy2', 25000)) schedule_once(strategy) def strategy(context, data): order(symbol('AMZN'), 1) for oid in context.orders: # prints only AMZN order print(context.orders[oid].to_dict()) schedule_once(wrap_up) def wrap_up(context, data): # cancelling sub-strategy from main context cancel_strategy('strategy2') # exit after all orders, (AAPL, MSFT and AMZN) are done exit_when_done() def analyze(context, perf): # print the performance for AMZN from the main context print(context.blotter.performance) # print the performance for AAPL from the sub-context "strategy1" ctx_1 = get_context('strategy1') print(ctx1.blotter.performance) The sub-strategy APIs provide a powerful way to create ensemble strategies, run multiple algos more efficiently and otherwise write clean modular algos and trading logic.