Events
At its core, the Botmain Automation Platform is a Complex Event Processing system (CEP). User strategies can process events at the instrument and portfolio levels, as well as events from other strategies themselves.
Instrument-level Events
To handle instrument-level events, users can implement an InstrumentProcessor
class extending
and add handlers for desired events:
import { Bar , Inject, InstrumentProcessorBase , Market , TradingInterface, Timeframe } from '@botmain/common';
import { MovingAverage } from '@botmain/indicators';
import { MarketOrder } from '@botmain/execution';
export class InstrumentProcessor extends InstrumentProcessorBase {
onBarClose(bar: Bar ) {
//called on every bar close for every instrument in the strategy
}
onBarUpdate(bar: Bar ) {
//called on every tick resulting in a bar update for every instrument in the strategy
}
onTrade(trade: Trade ) {
//called when a trade is received for the current instrument
console.log(`Trade received for ${this.market.symbol} for ${trade.amount}`);
}
}
Some events are specific to certain type of data subscriptions. For example, tick-related events like onTick() only fire on strategies that have subscribed to a tick stream. The full list of instrument-level events and their required subscriptions are given in the table below:
Event name | Available for subscription | Event description |
---|---|---|
onInit() | All | Event is called on the start of strategy to perform instrument level initialization. |
onExit(ExitState exitState) | All | Event is called after strategy execution to perform instrument level post processing. |
onDayOpen() | All | Event is called every day when instrument exchange is opening. Not applicable to markets that never close, such as crypto |
onMarketSessionResume() | All | Event is called when market session for an exchange is resuming. Not applicable to crypto |
onDayClose() | All | Event is called every day when instrument exchange is closing. Not applicable to crypto |
onMarketSessionPause() | All | Event is called when market session for an exchange is pausing. Not applicable to crypto |
onBarClose() | Intraday | Event is called when bar on instrument exchange is closing. |
onBarUpdate(Bar updatedBar) | Daily | Event is called when bar on instrument exchange is updated. |
onTick() | Tick | Event is called when quote for the instrument is received. |
onTrade(Trade trade) | Tick | Event is called when trade for the instrument is received. |
onBestBid(BestBidOffer bid) | Tick | Event is called when bid for the instrument is received. |
onBestAsk(BestBidOffer ask) | Tick | Event is called when ask for the instrument is received. |
onFirstTrade() | Intraday, Tick | Event is called when first trade for the instrument occurred. If only Intraday subscription is used, event is called when first bar is received. |
onBarOpen() | Intraday | Event is called when bar for the instrument opens. If strategy works on tick data it is fired when first trade of a bar interval is received for an instrument. When working on intraday data the event is fired when first intraday bar of an interval is received. |
Portfolio-level Events
To handle portfolio-level events, users can implement a PortfolioProcessor
class extending
and add handlers for desired events:
import { Bar , Inject, PortfolioProcessorBase , Market , TradingInterface, Timeframe } from '@botmain/common';
import { MovingAverage } from '@botmain/indicators';
import { MarketOrder } from '@botmain/execution';
export class PortfolioProcessor extends PortfolioProcessorBase {
onBarClose(bar: Bar ) {
//called on every bar close for every instrument in the strategy
}
onBarUpdate(bar: Bar ) {
//called on every tick resulting in a bar update for every instrument in the strategy
}
onTrade(trade: Trade ) {
//called when a trade is received for the current instrument
console.log(`Trade received for ${this.market.symbol} for ${trade.amount}`);
}
}
The full list of portfolio-level events and their required subscriptions are given in the table below:
Event name | Available for subscription | Event description |
---|---|---|
onInit() | All | Event is called on the start of strategy to perform portfolio level initialization. |
onAfterInit() | All | Event is called after onInit() event to perform additional portfolio level initialization. All instrument-level onInit events are fired by this time. |
onWarmupEnd() | All | This event is called when historical data warm-up ends. This event fires in real-time mode only. |
onDayOpen(Context context) | All | Event is called every day when instrument exchange is opening. Not applicable to markets that never close, such as crypto |
onAfterDayOpen(Context context) | All | Event is called after onDayOpen(Context context) event to perform additional portfolio level processing. All instrument-level onDayOpen events are fired by this time. Not applicable to crypto |
onDayClose(Context context) | All | Event is called every day when instrument exchange is closing. Not applicable to crypto |
onAfterDayClose(Context context) | All | Event is called after onDayClose(Context context) event to perform additional portfolio level processing. All instrument-level onDayClose events are fired by this time. Not applicable to crypto |
onMarketSessionPause(Context context) | All | Event is called when market session for an exchange is pausing. Not applicable to crypto |
onAfterMarketSessionPause(Context context) | All | Event is called after onMarketSessionPause(Context context) event to perform additional portfolio level processing. All instrument-level onMarketSessionPause events are fired by this time. Not applicable to crypto |
onMarketSessionResume(Context context) | All | Event is called when market session for an exchange is resuming. Not applicable to crypto |
onAfterMarketSessionResume(Context context) | All | Event is called after onMarketSessionResume(Context context) event to perform additional portfolio level processing. All instrument-level onMarketSessionResume events are fired by this time. Not applicable to crypto |
onBarClose(Context context) | Intraday | Event is called when bar on at least one exchange is closing. Not applicable to crypto |
onAfterBarClose(Context context) | Intraday | Event is called after onBarClose(Context context) event to perform additional portfolio level processing. All instrument-level onBarClose events are fired by this time. |
onExit(ExitState exitState) | All | This event is called after strategy execution to perform portfolio level post processing. |
Inter-strategy Events
Multiple strategies running simultaneously can send and respond to events between each other using the
service.
Consider the following example:
import { EventEmitter , Inject, InstrumentProcessorBase } from '@botmain/common';
import { MovingAverage } from '@botmain/indicators';
import { MarketOrder } from '@botmain/execution';
export class InstrumentProcessor extends InstrumentProcessorBase {
static displayName = 'Trend Trader';
@Inject() events: EventEmitter ;
@Inject() sma: SimpleMovingAverage ;
onBarClose(bar: Bar ) {
if(bar.close > sma.current) {
this.orderProcessor.sendOrder(new MarketOrder (...));
}
}
onOrderStatus(event: OrderStatusEvent) {
if(event instanceof OrderFilledEvent) {
this.events.emit('trendTrader.orderFilled', event.order);
}
}
}
In the above code, the strategy sends a MarketOrder when the bar close price crosses the simple moving average. When the order is filled, the strategy emits an event with custom name. Now consider a second strategy running simultaneously that can handle this custom event:
import { EventEmitter , Inject, InstrumentProcessorBase } from '@botmain/common';
import { Order } from '@botmain/execution';
export class InstrumentProcessor extends InstrumentProcessorBase {
static displayName = 'Arbitrage Hedge Strategy';
@Inject() events: EventEmitter ;
@Inject() orderProcessor: OrderProcessor ;
onInit() {
this.events.on('trendTrader.orderFilled', (order: Order ) => {
console.log('Order filled in Trend Trader strategy', order);
});
}
}