Event Callbacks in Blueshift
Blueshift is an event-driven engine. The core engine implements the event loop. The user strategy implements a set of callback functions ( i.e. event handlers) that are called by the event loop at defined events. The whole strategy logic is structured by responding to events as and when they occur. Blueshift strategies can respond to three types of events during its run.
- Lifetime Events
These are events generated by the Blueshift event loop based on the lifetime epochs of the strategy. They are summarised under the Main Callback Functions below.
- Trade and Data Events
These are events that are triggered once an order is (potentially partially) filled or on arrival of new data points. They work differently in backtest or real-time trading. See Trade and Data Callbacks below.
- Time-based Events
These are events scheduled by the user (using one of the scheduling functions). These are summarised under the Scheduled Callback Functions section.
Main Callback Functions
Lifetime event handlers are based on the epoch of the strategy run. This includes the following:
Initialize
- initialize(context)
This is the first entry point function.
initialize
is called when at the beginning of an algorithm run, only once. For backtest, the call time is at midnight of the start date of the backtest run. For live trading, this is called at the start of the execution as soon as possible.- Parameters:
context (context object.) – The algorithm context.
User program should utilise this function to set up the algorithm initialization (parameters, trading universe, function scheduling, risk limits etc).
Warning
A valid strategy script/ module must have this function defined.
Before Trading Start
- before_trading_start(context, data)
This function is called at the beginning of every trading session (day). For backtest, this is called 30 minutes before the regular market open hour everyday. For live trading, this is called 30 minutes before the market opens each day, or just after (around a minute) of the
initialize
call at the start on the execution start day (in case it is already trading hours or less than 30 minutes remaining from the opening hour).
User program should utilise this function to set up daily initialization ( e.g. profit and loss, model re-evaluation etc.)
Warning
User strategy should not depend on the exact time of invocation of this handler function. The only thing that is guaranteed is that it will be called only once per session and will be called before any handle data or scheduled functions.
Handle Data
- handle_data(context, data)
This function is called at every clock beat, i.e. every iteration of the
event loop
(usually at every minute bar).
User program should utilise this function to run their core algo logic if the algorithm needs to respond to every trading bar (every minute). For algorithms (or functions) that need to respond at a lower scheduled frequency, it is more efficient to use the scheduling API function to handle such cases.
Note
If the clock frequency is one minute (which is the case at present
on Blueshift), this function is equivalent to a scheduled function
with time_rule
as every_nth_minute(1)
.
After Trading Hours
- after_trading_hours(context, data)
This function is called at the end of every session (every day) around 5 minutes after the last trading minute (market close).
User program should utilise this function to do their end-of-day activities (e.g. update profit and loss, reconcile, set up for next day).
Warning
User strategy should not depend on the exact time of invocation of this handler function. The only thing that is guaranteed is that it will be called only once per session and will be called after the end of the regular market hours.
Analyze
- analyze(context, performance)
This function is called only once, at the end of an algorithm run, as soon as possible.
- Parameters:
context (context object.) – The algorithm context.
performance (pandas.DataFrame) – The algorithm performance.
Note
The performance
object is a DataFrame with algo performance
captured at daily intervals. The dataframe timestamps are the
timestamps for after_trading_hours
calls. The columns include
some of the algo account fields as well the profit and loss (pnls) metrics.
See also
on_error for exit with a fatal error. on_cancel for exit after a cancellation of algo run. on_exit for exit in any cases.
User program can implement this method to add custom analysis of backtest results or after a live run completion. The analyze callback will be called only when the strategy exits normally (reaches end of the algo run without any fatal error).
Trade and Data Callbacks
Attention
only available for live trading, for brokers supporting streaming for data and trade updates.
These callback APIs on Blueshift allows the user strategy to respond to the markets events as it happens (in real-time for live mode).
On Data
- on_data(context, data)
This event handler is invoked at arrival of new data points. This function is called at every clock tick, i.e. every iteration of the
event loop
(usually at every minute bar) in backtest mode. In realtime mode, this is invoked only if the broker supports real-time data streaming and a new data point has been made available. In the case of the latter, only instruments that the algo has subscribed to can trigger a call to this function.
Important
The on_data event handler is called only when triggered by the underlying broker. For that to happen, the broker must support streaming data (market data websockets or socketIO API), as well as the strategy must have subscribed to at least one instrument for streaming data. There is no explicit API to subscribe to streaming data, but curret or history will automatically trigger data subscriptions for the queried assets. If you are using this handler, make sure you have triggered a call to one of these methods to enable subscription. Without it, the handler will never be called.
Warning
The callback function must be short and quick to avoid creating a backlog. Adding long running funtions may lead to the algo crashing. Also, a temporary network disconnection will cause this event handler to stop triggering (till the connection is restored). To make sure your strategy logic is robust, you can also put the same logic inside handle_data to make sure the strategy logic is triggered at least once every minute, even if there is a disconnection. Of course, this depends on the specific need of a given strategy.
See also
See available callback types blueshift.protocol.AlgoCallBack
.
On Trade
- on_trade(context, data)
This event handler is invoked when an order placed by the strategy is filled. This function is called when the simulator fills an order in backtest mode or paper trading mode. In realtime mode, this is invoked only if the broker supports real-time order update streaming and an order has been filled.
See also
See available callback types blueshift.protocol.AlgoCallBack
.
Warning
The callback function must be short and quick to avoid creating a backlog. Adding long running funtions, may lead to the algo crashing.
On Stoploss
- on_stoploss(context, asset)
This event handler is invoked when a (previously set) stoploss target is hit. The parameter asset is the asset object for which the position hit the target. If the stoploss is strategy-level, asset will be None.
Note
If a specific callback is supplied while setting up the stoploss, This function will not be called, instead the one supplied will be invoked.
On Takeprofit
- on_takeprofit(context, asset)
This event handler is invoked when a (previously set) takeprofit target is hit. The parameter asset is the asset object for which the position hit the target. If the takeprofit is strategy-level, asset will be None.
Note
If a specific callback is supplied while setting up the takeproft, This function will not be called, instead the one supplied will be invoked.
Scheduled Callback Functions
The scheduled event callbacks provide a way to schedule a callback
function (with signature func(context, data)
) based on a date and time
based rule. There is no limit on how many callbacks can be scheduled in
such a manner. But only one callback can be scheduled at each call of the
schedule_function
.
Schedule Soon
- TradingAlgorithm.schedule_soon(callback)
Add a callback to be called as soon as possible. The callback must have the standard call signature of
f(context, data)
. The handler will be called for live modes as soon as possible, if in trading hours, else will be called in the next trading bar for the day. For backtest, it will always be next trading bar (exactly same behaviour asschedule_once
).- Parameters:
callback (callable) – Callback function to run.
Note
This schedules the callback to run one time only. For repetitive callbacks, use
schedule_function
belowThe callback can use this function to schedule itself recursively, if needed.
Schedule Once
- TradingAlgorithm.schedule_once(callback)
Add a callback to be called once at the next event processing cycle. The callback must have the standard call signature of
f(context, data)
. The handler will be called in the next trading bar - for both backtest and live modes.- Parameters:
callback (callable) – Callback function to run.
Note
This schedules the callback to run one time only. For repetitive callbacks, use
schedule_function
belowThe callback can use this function to schedule itself recursively, if needed.
Schedule Later
- TradingAlgorithm.schedule_later(callback, delay)
Add a callback to be called once after a specified delay (in minutes). The callback must have the signature
f(context, data)
. The callback will be triggered during the market hour only.- Parameters:
callback (callable) – Callback function to run.
delay (number) – Delay in minutes (can be fractional).
Note
This schedules the callback to run one time only. For repetitive callbacks, use
schedule_function
belowThe callback can use this function to schedule itself recursively, if needed.
You can use a fractional number to run a function at higher frequency resolution than minute. For example specifying delay=0.1 will run the callback after 6 seconds. This is only applicable for live runs. For backtests, it will fall back to one minute minimum. The minimum delay that can be specified is 1 second.
Warning
There is no guarantee the function will be called at the exact delay, but if it is called, it will be called at least after the specified delay amount. Also, scheduling are not carried forward over the end-of-day.
Schedule Function
- TradingAlgorithm.schedule_function(callback, date_rule=None, time_rule=None)
Schedule a callable to be executed repeatedly by a set of date and time based rules. Schedule function can only be triggered during trading hours. The callable in the schedule function will be run before handle_data for that trading bar. The callback must accept two arguments - context and data.
- Parameters:
callback (function) – A function with signature
f(context, data)
.date_rule (see
blueshift.api.date_rules
) – Defines schedules in terms of dates.time_rule (see
blueshift.api.time_rules
) – Defines schedules in terms of time.
Warning
This method can only be used within the initialize function. Attempting to set a scheduled callback anywhere else will raise error and crash the algo.
The offset should be meaningful and always non-negative. For e.g. although the hours offset can be maximum 23, using such an offset is not meaningful for shorter trading hours (unless it is a 24x7 market).
In live trading, there is no guarantee that the scheduled function will be called at exactly at the scheduled date and time. It may be delayed if the algorithm is busy with some other function. The function is guaranteed to be called no sooner than the scheduled date and time, and as soon as possible after that.
Date Rules
- class blueshift.api.date_rules
Date rules define the date part of the rules for a scheduled function call. The supported functions are as below (further subjected to time rule). The
days_offset
parameter below (if applicable) must beint
(positive), and it must not be greater than 3 forweek_start
/week_end
and must not be greater than 15 formonth_start
andmonth_end
. The weekday parameter can be either an integer between 0 (Monday) to 6 (Sunday), or a string representing the day of week (e.g. “Fri”, or “Friday”).every_day()
: called every day.week_start(days_offset=0)
: days_offet days after the first trading day of the week.week_end(days_offset=0)
: days_offet days before the last trading day of the week.week_day(weekday=0)
: Run on given weekday - can be either an integer or weekday name or list of the same.month_start(days_offset=0)
: days_offet days after the first trading day of the month.month_end(days_offset=0)
: days_offet days before the last trading day of the month.on(dts)
: called every day in the list dts (must be list of pandas Timestamps or DatetimeIndex).
Time Rules
- class blueshift.api.time_rules
time rules defines the time part of the rules for a scheduled function call. The supported functions are as below (further subjected to date rule).
The
hours
parameter below (if applicable) must beint
, (positive) and it must not be greater than 23. Theminutes
parameter below (if applicable) must beint
(positive) and must not be greater than 59.market_open(minutes=0, hours=0)
: called afterhours
andminutes
offset from market open.on_open(minutes=0, hours=0)
: Alias for market_open.market_close(minutes=0, hours=0)
: called afterhours
andminutes
offset before market close.on_close(minutes=0, hours=0)
: Alias for market_close.every_nth_minute(minutes=1)
: called every n-th minute during the trading hours.every_nth_hour(cls, hours=1)
: called every n-th hour during the trading hours.every_hour()
: called every hours during the trading day.at(dt)
: Called at the given time dt (must be a datetime.time object).
Scheduling Examples
Repetitive Logic with Scheduling
The below code shows examples of setting up a monthly callback function, to be called on the first business day of each month, 30 minutes before the market close.
from blueshift.api import schedule_function, date_rules, time_rules
from blueshift.api import get_datetime
def initialize(context):
schedule_function(myfunc,
date_rule=date_rules.month_start(),
time_rule=time_rules.market_open(minutes=30))
def myfunc(context, data):
print(f'scheduled function called at {get_datetime()}')
Responsive Strategy with Scheduling
The below code shows examples of placing a limit order and then updating the order to optimize time to fill and fill price. The algo terminates once the order is executed.
from blueshift.api import schedule_later, schedule_once, symbol, terminate
from blueshift.api import terminate, order, update_order, get_order
def initialize(context):
context.asset = symbol('AAPL')
context.order_id = None
schedule_once(myfunc) # call as soon as ready
def myfunc(context, data):
if context.order_id is None:
context.order_id = order(context.asset, 1)
if not context.order_id:
raise ValueError(f'something went wrong.')
schedule_later(myfunc, 1) # call again after one minute
return
o = get_order(context.order_id)
if o.is_open():
px = data.current(context.asset, 'close')
update_order(context.order_id, price=px)
schedule_later(myfunc, 1) # call again after one minute
else:
# we are done
terminate(f'order executed, terminate now.')
If you are using schedule_once
or schedule_later
recursively, carefully
follow your logic and make sure the recursion ends where it needs to.
User Order Confirmation Callback
Attention
only available for live trading, when running in oneclick execution mode.
On Oneclick
- blueshift.api.on_oneclick(notifications)
This callback function is invoked when notifications (raised when a order notification is generated in oneclick mode) are either confirmed by the user or expired or some error occured. The input parameter notifications is a dictionary with notification ID (returnd from the ordering functions in oneclick mode) as key and the final state of that notification as value. This is a global handler, i.e. it is called only in the parent algo context, and not any sub-contexts.
See also
See available status types blueshift.protocol.OneClickState
.
See execution mode blueshift.api.ExecutionMode
.
Algo Error and Cancel Callbacks
User strategy can define an error or cancel handler if desired. Only one
of them will be triggered - depending on if the algo exits by a user
cancel or with an error. If the algo finishes the run normally, none of
these will be invoked (and the analyze
callback will be called instead).
These callbacks are for any reporting purposes and
should not be used to place orders or trigger square-offs/ order
cancellations. To handle square-off/ cancellation behaviour on exit, see
set_exit_policy
under risk management.
On Cancel
This callback function is invoked once if the strategy exits following a
user cancel. The only argument to this function is the context
object.
On Error
- blueshift.api.on_error(context, error)
This callback function is invoked once if the strategy exits with an error.
The first argument is the context
object. The second argument can be
either a string (in which case it is the error message), or an exception
object.
On Exit
- blueshift.api.on_exit(context)
This callback function is invoked once on strategy exit. This will always be invoked (after any one of analyze, on_error or on_cancel as the case maybe) before the final strategy exit.