Skip to content

Algo Order System

Cris Mihalache edited this page Oct 2, 2018 · 1 revision

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
    }
  }
})

AO Event Handlers & Helpers

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 as emitSelf but operates on next tick
  • emit(eventName, ...args) - raw event emitter, i.e. emit('life:start')
  • emitAsync(eventName, ...args) - same as emit 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

Custom AO Event Handlers

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')
}

Subscribing to Data Channels

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}`)
  }
}
Clone this wiki locally