Event-Driven
Besides polling at a fixed interval, a strategy can wait for events and handle them as they arrive, which avoids useless requests and reacts faster to market changes.
EventLoop
EventLoop waits for events such as the completion of concurrent tasks started with exchange.Go() or HttpQuery_Go(), readable data on a WebSocket connection, or thread messages; when one occurs it returns the event information and the strategy then reads the corresponding data. Events are recorded only from the first call of EventLoop(), so call EventLoop(-1) once before starting concurrent tasks:
javascript
function main() {
EventLoop(-1) // start recording events so none are missed
var r1 = exchange.Go("GetTicker")
var r2 = exchange.Go("GetDepth")
var ev = EventLoop(1000) // wait up to 1 second for either task to finish
Log("event:", ev)
Log("ticker:", r1.wait(), "depth:", r2.wait())
}
ctx.subscribe / ctx.poll
JavaScript and Rust strategies can also use the docker's event subscription interface: ctx.subscribe() subscribes to market data or order updates for an account and symbol and returns a stream ID; ctx.poll() takes the next event (optionally with a timeout), and the strategy handles it according to its kind. Python strategies do not support it.
javascript
function main() {
ctx.subscribe(0, "BTC_USDT", {channel: "ticker"}) // the first argument is the account's index in exchanges
ctx.subscribe(0, "", {channel: "orders"}) // order updates
while (true) {
const ev = ctx.poll([], 1000) // [] means all subscriptions; wait up to 1 second
if (!ev) {
continue
}
if (ev.kind === 1) {
Log("ticker:", ev.symbol, ev.bid, ev.ask, ev.last)
} else if (ev.kind === 16) {
Log("order:", ev.id, ev.state, ev.filledQty)
}
}
}
channelcan be"ticker","bbo","depth","trade","kline"(intervalis the period in seconds) or"orders".- Event
kind: 1 ticker, 3 depth (the event only signals that the order book changed; read the levels withctx.book(ev.ex, ev.symbol, n)), 4 trade, 5 K-line, 16 order update. - If market data subscriptions are not consumed in time, only the latest data is kept or the oldest is dropped; order updates are never dropped, so the strategy must keep calling
ctx.poll().
In Rust the calls are ctx::subscribe() and ctx::poll(); events are raw structures whose prices and quantities are fixed-point integers:
rust
fn main() {
let s = ctx::subscribe(0, "BTC_USDT", ctx::SubOpts::ticker()).unwrap();
loop {
match ctx::poll(&[s], Some(1000)) {
ctx::Polled::Event(ev) => Log!("event kind:", ev.kind),
ctx::Polled::Stopped => break,
_ => {}
}
}
}