-
Notifications
You must be signed in to change notification settings - Fork 40
Algo Order System
Algorithmic orders are defined by an ID/Name pair, a set of meta functions describing the order, and a set of event handlers to be triggered during the orders lifetime/execution. A defineAlgoOrder
helper is provided to construct the final AO definition object:
const AO = defineAlgoOrder({
id: 'some.ao.identifier',
name: 'Descriptive AO Label',
// meta functions describing the order/execution environment
meta: {
validateParams, // validates processed parameters
processParams, // prepares raw parameters for execution
declareEvents, // declares/hooks up custom internal event handlers
declareChannels, // declares needed data channels, to be managed by the AO host
getUIDef, // returns the Bitfinex Order Form definition schema
genOrderLabel, // constructs a label for generated atomic orders
genPreview, // generates preview orders for rendering in the bfx UI
initState, // creates the initial AO state object
serialize, // serializes state for DB persistence
unserialize, // unserializes loaded DB states for execution
},
events: {
self: {
// internal events, bound in declareEvents()
},
life: {
start, // triggered on execution start, should handle initialisation
stop, // triggered on execution stop, should handle teardown
},
orders: {
order_snapshot, // triggered upon receival of an account order snapshot
order_new, // triggered when a new order is opened
order_update, // triggered when an order is updated
order_close, // triggered when an order is closed
order_fill, // triggered on any order fill (order new/update/close)
order_cancel, // triggered when an order is closed via cancellation
},
data: {
managedCandles, // triggered by receipt of a managed candle dataset
managedBook, // triggered by receipt of a managed order book
notification, // triggered by receipt of a notification
candles, // triggered by receipt of candles
ticker, // triggered by receipt of a ticker
trades, // triggered by receipt of trades
book, // triggered by receipt of an order book snapshot/update
}
}
})
All event handlers receive the same arguments: (instance = {}, ...args)
. The instance contains two objects, { state = {}, h = {} }
with state
being the current AO state, and h
being a helper object.
The provided helpers are:
-
debug(str, ...args)
- for logging information to the console, tagged by AO GID -
emitSelf(eventName, ...args)
- triggers an event on the 'self' section -
emitSelfAsync(eventName, ...args)
- same asemitSelf
but operates on next tick -
emit(eventName, ...args)
- raw event emitter, i.e.emit('life:start')
-
emitAsync(eventName, ...args)
- same asemit
but operates on next tick -
notifyUI(level, message)
- generates and sends a notification which appears on the Bitfinex UI -
cancelOrderWithDelay(state, delay, order)
- takes current algo state, delay in ms -
cancelAllOrdersWithDelay(state, delay)
- cancels all active atomic orders on the AO state, delay in ms -
submitOrderWithDelay(state, delay, order)
- takes current algo state, submits a new order, delay in ms -
declareEvent(instance, host, eventName, path)
- declares an internal AO event, see section below -
declareChannel(instance, host, channel, filter)
- declares a required data channel, see section below -
updateState(instance, update)
- update the current state for an AO instance
To declare custom events to be triggered by the emitSelf
or emitSelfAsync
helpers, use the declareEvent
helper inside of the declareEvents
meta method in order to register the event names on AO startup. For an example, see the Iceberg
event definition handler:
module.exports = (instance = {}, host) => {
const { h = {} } = instance
const { declareEvent } = h
// All declared events are expected to be handled on the 'self' section, but can have any path/label
// Map self:submit_order to the 'submit_order' handler
declareEvent(instance, host, 'self:submit_order', 'submit_order')
// Map self:interval_tick to the 'interval_tick' handler
declareEvent(instance, host, 'self:interval_tick', 'interval_tick')
}
Later, these events are triggered within other Iceberg
event handlers, such as submit_orders
within the life:start
handler:
module.exports = async (instance = {}) => {
const { h = {} } = instance
const { emitSelf } = h
// ...
await emitSelf('submit_orders')
}
To subscribe to Bitfinex websocket API data channels, use the declareChannel
helper within the declareChannels()
meta method. Channel subscribe/unsubscribe calls will be handled automatically by the AO host during execution, with the relevant data being passed to the data
section event handlers upon receival. For an example, see the TWAP
channel declaration:
module.exports = async (instance = {}, host) => {
const { h = {}, state = {} } = instance
const { args = {} } = state
const { symbol, priceTarget } = args
const { declareChannel } = h
if (hasTradeTarget(args)) {
await declareChannel(instance, host, 'trades', { symbol })
} else if (hasOBTarget(args)) {
await declareChannel(instance, host, 'book', {
symbol,
prec: 'R0',
len: '25'
})
} else {
throw new Error(`invalid price target ${priceTarget}`)
}
}