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
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
main entry-point functions.
For more details, check out the API callback functions.
As you can see, most of the functions above has two pre-defined variables
that are passed on as arguments. They are
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
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 print(context.universe)
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): print(context.account) print(context.portfolio)
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
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
- risk control related functions like
For a complete list of API function refer to the API doc.
Trading real time with live mode¶
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
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
must have a signature as
callback(context, data). Note, there is no
enforced limit on the number of handlers per event (
You can use these
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 pass def initialize(context): # some initialization... # schedule the function above to be called on every data update on_data(hande_stoploss)
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
callbackis optional - if not supplied, all handlers for that particular event (
data) will be removed. See the API doc for details.
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. ↩