Zero-latency Position Management

You will learn how to launch the position manager and configure gateways.

Conda

Install the roq-position-manager package

$ conda install -y -c https://roq-trading.com/conda/unstable roq-position-manager

Configure

Gateway

You must add the position manager as a user in your TOML config file

[users.position_manager]
password = "secret"
drop_copy = true

Important

This user must include the drop_copy = true option.

The gateway’s command-line must include the --enable_portfolio flag and should include the --download_trades_lookback and --download_trades_lookback_on_restart flags

$ roq-deribit \
    --name "deribit" \
    --config_file $HOME/deribit.toml \
    --client_listen_address unix://$HOME/deribit.sock \
    --flagfile $CONDA_PREFIX/share/roq-deribit/flags/test/flags.cfg \
    --download_trades_lookback_on_restart=24h \
    --download_trades_lookback=5m \
    --enable_portfolio=true

Note

The gateway will cache trades received from the exchange they can be correlated with positions received from the position manager. (This is the trick to how the gateway can support zero-latency position updates.)

This extra work has some cost and is the reason why the feature currently is opt-in.

Position Manager

symbols = [
  "^BTC-PERPETUAL$"
]
roq-position-manager \
  --name position-manager \
  --config_file $CONFIG_FILE \
  --database_uri http://localhost:8123 \
  --database_name roq \
  --database_username roq \
  --database_password roq \
  --enable_portfolio=true \
  $HOME/deribit.sock

Note

We assume that a ClickHouse service is running on the same host.

Note

The position manager could be passive (simply pushing fills into the database) or active (communicating positions back to the gateway). This is the reason behind the --enable_portfolio flag.

Database

Tables will automatically be created when launching the position manager

../../../_images/tables.png

We can inspect a single table like this

../../../_images/desc_trades.png

Example

Enter a market order

../../../_images/sell.png

Which was accepted by the exchange

../../../_images/sold.png

We can now see the trade being inserted into the database

../../../_images/trade.png

Using “roq-dump” to inspect the event-log, we can find the gateway events

The gateway receives a trade from from the exchange

1778148424225973185ns

trade_update={
  stream_id=3,
  account="A1",
  order_id=424588017088,
  exchange="deribit",
  symbol="BTC-PERPETUAL",
  side=SELL,
  position_effect=UNDEFINED,
  margin_mode=UNDEFINED,
  quantity_type=UNDEFINED,
  create_time_utc=1778148424213000000ns,
  update_time_utc=1778148424213000000ns,
  external_account="",
  external_order_id="97071497011",
  client_order_id="oAAIwP1q22IAAQAAAAAA",
  fills=[{exchange_time_utc=1778148424213000000ns,
  external_trade_id="BTC-PERPETUAL#133188392",
  quantity=1,
  price=80960,
  liquidity=TAKER,
  commission_amount=6.000000000000001e-08,
  commission_currency="BTC",
  base_amount=nan,
  quote_amount=nan,
  profit_loss_amount=809600}],
  routing_id="",
  update_type=SNAPSHOT,
  exchange_time_utc=0ns,
  exchange_sequence=0,
  sending_time_utc=0ns,
  user="trader",
  strategy_id=0
}

The gateway injects a portfolio update immediately after the trade update

1778148424225973185ns

portfolio_update={
  user="",
  strategy_id=0,
  account="A1",
  positions=[{exchange="deribit",
  symbol="BTC-PERPETUAL",
  position=2,
  profit_loss_amount=nan,
  profit_loss_currency=""}],
  update_type=SNAPSHOT,
  exchange_time_utc=0ns
}

Note

Same timestamp as the trade update.

The gateway receives a portfolio update from the position manager

1778148424480107609ns

portfolio_update={
  user="",
  strategy_id=0,
  account="A1",
  positions=[{exchange="deribit",
  symbol="BTC-PERPETUAL",
  position=2,
  profit_loss_amount=nan,
  profit_loss_currency=""}],
  update_type=INCREMENTAL,
  exchange_time_utc=1778148424213000000ns
}

Note

This event happens 254 milliseconds later, the cost of using a database. Roq can hide this latency as was just demonstrated.