Skip to content

Developing Strategies on Blueshift®

Systematic strategy life cycle

A typical systematic strategy usually runs in the following manner. First at the onset, the strategy does some initialization. This includes things like defining the trading asset universe, setting up periodic function calls, and defining strategy parameters. Then onwards, during the market hours, as every new bar of price arrives, the strategy responds to it. This typically involves computing signals, computing the target portfolio based on these signals and current state of the algorithm, and potentially placing or cancelling orders. At the end of market hours, it does some end-of-day activities. Once the market hours are over, it goes in to a sleep mode. The next day, it wakes up again before the market opens. At this point it may carry out some functions to set itself up for the day. Once the market opens it gets into the usual routine of taking in the arriving data and responding to it.

Special functions on Blueshift®

On Blueshift®, each of the points in the trading cycle above directly maps to a particular functions. These functions are called the main entry-point functions. They are as below:

  • initialize(context): This is the first function that is called once (and only once) at the very start of the strategy run.

  • before_trading_start(context, data): This is the function that is called at a preset time before the market opens, every day. Your strategy should not depend on the exact time of this function call.

  • handle_data(context, data): This is the function called at every minute during the market hours.

  • analyze(context, performance): This is a function called at the end of a strategy run.

We must define the initialize function in our strategy for it to be a valid strategy. Other functions are useful but optional.

In the live version, we have a few extra functions

  • after_market_hours(context, data): called once everyday, after the market closes. Your strategy should not depend on the exact time of this function call.

  • on_trade(context, data): called at every trade-related update from the brokers (e.g. a order fill, cancellation etc).

  • on_data(context, data): called at every data update from the brokers.

The last two functions are only available if the broker for the live run supports live streaming. These two functions are useful to trade at real-time speed on Blueshift. For more, see below.

These are special functions understood by the platform (by their names) and are called by the platform at the periodicity mentioned above. At the heart of it, Blueshift® core engine is an elaborate event loop that manages the complex things about systematic trading (like scheduling, data management, order management, risk management, logging etc.). The user strategy code defines these functions above, and the platform call them at appropriate time inside this event loop. This is how a strategy gets executed on the platform. Hence they are collectively called main entry-point functions.

For more details, check out the API callback functions.

Special variables

As you can see, most of the functions above has two pre-defined variables that are passed on as arguments. They are context and data - these are special variables and are maintained by the platform itself. The user program can query them to get information about the current state of the strategy or fetch data on securities of interest.

The context variable

It is a special variable that servers two purposes.

First, it acts as a container for storing user defined variables that are needed across different functions. All the entry point functions have defined arguments, and hence it is not possible to pass an user defined argument directly. Instead, we can define our variables as an attribute to this special variable context. This makes them automatically accessible from other entry-point functions through the context variable. We have already seen examples of it when we stored our trading universe as a list of assets in the context variable.

def initialize(context):
    context.universe = [symbol("AAPL"), symbol("MSFT")]

def handle_data(context, data):
    # here we can access the universe as we have context as an argument

Second, the context variable is also used by the platform to track the current state of the strategy. Hence user program can query this variable anytime to get the information about its current state:

def handle_data(context, data):
It provides a host of metrics and state descriptions (like account cash, leverage, exposure, portfolio positions etc.) that the algorithm may be interested in to calculate its trading intentions.

For more details and a complete list of available attributes, check out the API doc.

The data variable

This is another special variable maintained by the platform that enables a user algorithm to query price and other data it has access to. For more on this see the API doc.

The API functions

Apart from the main entry-point functions, Blueshift® also provides a bunch of API functions, that can be imported from the api module. Examples:

from blueshift.api import symbol

For asset related API functions, see the section on asset. For ordering and trading related API functions, see the section on placing and cancelling orders. For scheduling related API functions, see the section on it. Other commonly used API functions are:

  • get_datetime(): Fetch the current date and time as Pandas Timestamp object.
  • risk control related functions like set_max_order_size, set_max_order_count, set_max_position_size etc.

For a complete list of API function refer to the API doc.

Trading real time with live mode

In the live mode, blueshift supports real time trading1. In addition to the regular events, we have two sets of event handlers than respond to real time updates. They have the following signatures:

on_trade(callback) # function `callback` is called for every trade updates
on_data(callback) # function `callback` is called for every data updates

Required broker support for real-time trading.

The broker must support streaming order updates for on_trade and streaming data updates for on_data API functions. Any or both or none can be avaialble for a broker depending on their API support. See footnote below for current status.

These functions take an argument, a function (callback above) that is called for every update received in real time. The function callback must have a signature as callback(context, data). Note, there is no enforced limit on the number of handlers per event (trade or data). You can use these on_data or on_trade functions to register multiple event handlers per event. However, adding the same function twice will call it only once - make sure the callback function names are different for multiple handlers for the same event. For example:

from blueshift.api import on_data, on_trade

# a user defined function that checks stoploss hit on every data update
def handle_stoploss(context, data):
    # do useful work here

def initialize(context):
    # some initialization...
    # schedule the function above to be called on every data update
For more examples, check out the demo strategies.

There is another set of API functions that turns off these event handlers.

off_trade(callback) # remove the callback for trade updates
off_data(callback) # remove the callback for data updates
Here the argument callback is optional - if not supplied, all handlers for that particular event (trade or data) will be removed. See the API doc for details.

  1. Only for brokers that support real time updates on trades and data through a streaming API. At present, the following brokers support this features: 1) Both trade and data streaming -FXCM (live and paper), Alpaca (live and paper) 2) Only data update - Mastertrust (live), 3) only trade updates - None.