The Lab

Overview

The Risk Instance keeps order and position states, maintains the credit pool hierarchy, and performs all risk checks. 

The output of the message parser consists of order actions. The risk instance determines the legality of those order actions. To accomplish this, Reflector acts as-if the following steps are taken:

  1. Identity - New order requests must have new IDs. Modify requests must refer to existing and live IDs.
  2. Sanity - Any checks that require validating against prior state. NOTE: The message parser actually performs most of the sanity checks because they can be done a priori.
  3. Order State - A speculative order state is constructed.
  4. Order Diff - A diff between the speculative order state and the previous order state is calculated.
  5. Position Diff - The order state diff is transformed into a position diff.
  6. Position States - For each associated risk pool, a speculative position is created with the old position and the position diff.
  7. Risk Checks - For each associated risk pool, the speculative position is checked against the parameters for that pool.
  8. Success - If risk checks pass, speculative order and position states are made permanent, and order allowed through.
  9. Failure - If risk checks fail, order and position states are rolled back, and order action is denied.


Risk Pool Hierarchy

Definitions:

  • A Group is a collection of live orders and unsettled fills that logically belong together, a pool of risk.
  • Within a Group, the actualized outlays of the fills combined with the potential outlays of live orders form a Position.
  • Additionally, every Group has a set of risk parameters, known as Limits, to which its Position is subject.


There are two types of Groups:

Aggregate groups contain other groups.

User groups contain credentials. Credentials are uniquely identified by the ordered triple (Venue, CompID, SubID). Users may be associated with multiple credentials per venue and over multiple venues.


In the following diagram, the BROKER and FUND nodes are aggregates. The access, command/control, and semantics surrounding them are external to the runtime, and are handled elsewhere. The only constraints that Reflector enforces on Aggregates are that they can only contain other groups and their Position is the sum of the Positions of the groups contained by them.

User groups, represented by TRADER in this diagram, contain only credentials and represent the most granular division of risk available in Reflector. Individual credential entries do not keep their own positions.


RiskPoolHierarchy

Position Model

Inside a risk pool, position is stored as an array of arrays.

  • The outside array is indexed by currency.
  • The inside array is an ordered 4-truple of non-negative values: { Buying, Selling, Bought, Sold }.

Expressed more formally:

A position p is an aggregation of outlays of both open and filled portions of orders made by a set of traders.
A formula f is a mapping from positions to non-negative real numbers. f must be convex.
A limit l is an ordered pair of (f, v) where f is a formula and v is a non-negative real number.
A Position p is said to be in violation of limit l under formula f if and only if f(p) > v.

Volatility

Volatility is essentially an additional and independent multiplier that is applied per-currency to allow Risk managers to treat certain currencies as particularly more or less risky than others.

Valid volatility values range from 0.01 to 100.00, inclusive.
All volatility values default to 1.00, and the USD (Reserve Currency) volatility is currently fixed at a baseline of 1.00
Each risk pool can define its own set of volatility values.

Limits

Limits may be categorized as follows:

  1. Fat Finger Checks - These limits are entirely unrelated to the overall position. They either enforce properties of a single order/execution (single limit), or measure some side-channel effect (submission rate).
  2. Tranched Limits - These limits encompass only some defined subset of the overall position, providing fine-grained control:
    1. Pending limit
    2. Currency-exposure limits
    3. DSL
  3. Credit Limits - The following limits accumulate over the entire position, emits an ordering (required for de-escalation mode) and maps to a well known notion of risk. Every pool of risk must choose one of them as its primary measure of risk:
    1. Downside limit
    2. Upside limit
    3. Exposure
    4. Displacement
  4. Daily Credit Limits - Just like credit limits, but divided by settlement date.
  5. Counterparty Credit Limits - Just like credit limits, but divided by settlement counterparty.

Fat-Finger Checks

Submission Rate

The submission rate counter measures the number of risk carrying messages in a rolling window. The restraint placed on it is intended to act as a runaway-algo check.

Risk carrying messages include the following outbound messages:

  • NewOrderSingle (taker),
  • NewOrderList (taker),
  • NewOrderMultiLeg (taker),
  • QuoteResponse (taker, only when accepting),
  • OrderCancelReplace (taker, only when increasing quantity),
  • ExecutionReport (maker, only when accepting)
  • ExecutionAcknowledgement (maker, only when accepting)

Rejected risk-carrying orders still increment the count.
Messages that cancel orders are not considered risk-carrying.

Live Order Count Limit

A live order count is maintained and constrained to a live order count limit.

Single Order Limit

The absolute values of both buy and sell outlays are multiplied by their respective conversion rates to USD, then averaged.

Tranched Limits

Pending Limit

This is similar to the Single Order Limit, except this is a summation over all unfilled portions of all orders:


PendingValue = \frac{1}{2} \sum_{c \in currency} ( buying_c + selling_c ) * ExchangeRate_c * Volatility_c

Per-Currency Exposure Limits

A vector of exposure limits, each applying to a single currency, expressed in that currency. This limit can be expressed in either its native currency or in USD (the Reserve Currency), based on a global setting that is loaded at startup:

NativeCcyExposureValue_c = max ( buying_c + bought_c - sold_c, selling_c + sold_c - bought_c ) \\ ReserveCurrencyExposureValue_c = NativeCcyExposureValue_c * ExchangeRate_c * Volatility_c


Two levels of enforcement are offered: nothing or everything.

By default,  per-currency exposure limits are not enforced; meaning the trader is allowed to accumulate any position in any currency, provided that they do not violate other limits.

When enabled, then currency limits become mandatory: traders will not be able to trade in a given currency without a limit.

Currency Basket Exposure Limits

A currency basket is an ordered 3-tuple of (name, limit value, currency set).
Each risk can define up to 16 currency baskets.
The set of currency sets defined under one risk pool must be pairwise distinct (e.g.: no currency can appear in more than one basket under the same risk pool).

BasketValue_n = \sum_{c \in Basket_n} max ( buying_c + bought_c - sold_c, selling_c + sold_c - bought_c ) * ExchangeRate_c * Volatility_c


By default, this option is disabled, and the trader is allowed to accumulate any position in any currency basket, provided that they do not violate other limits.
If enabled, then currency basket limits become mandatory: traders will not be able to trade in currencies that do not belong to a basket.

Daily Settlement Limit

If ZEBRA_DSL is defined, then daily positions are kept. DSL uses whichever position tracking type is chosen for NOP.

Credit Limits

Net Open Position

Reflector uses the following terms to quantify NOP: Downside, Upside, Exposure, Displacement.

Downside Limit

An upper bound on how much the trader can lose.
This limit first assumes that the upside of every pending trade is gone but the downside remains.
Then, it assumes that all the credited currencies are gone while the debited currencies remain.


DownsideValue = \sum_{c \in currency} max ( 0, selling_c + sold_c - bought_c ) * ExchangeRate_c * Volatility_c


Upside Limit

An upper bound on how much the trader can make.
This limit first assumes that the downside of every pending trade is gone but the upside remains.
Then, it assumes that all the debited currencies are gone while the credited currencies remain.


UpsideValue = \sum_{c \in currency} max ( 0, buying_c + bought_c - sold_c ) * ExchangeRate_c * Volatility_c

Exposure Limit

This formula nominates one currency (usually USD) as a risk-free asset, then considers positions in all other currencies as risk carrying, pursuant to their absolute value, then scaled by the exchange rate & volatility.


ExposureValue = \sum_{\substack{c \in currency \\ c \neq USD}} max ( buying_c + bought_c - sold_c, selling_c + sold_c - bought_c ) * ExchangeRate_c * Volatility_c

Displacement Limit

This formula is very similar to the Exposure Limit formula.
In the exposure formula, the upside and downside are reconciled per currency, then summed up. In this formula, they are summed up independently, then reconciled.

DisplacementValue = max ( DownsideValue, UpsideValue )

Risk Modes

Reflector has four different risk modes as itemised below (ordered in increasing constriction):

  • NORMAL - All risk limits are maintained. No additional restrictions.
  • DEESCALATION - Trader only able to submit submit orders which may reduce position, or cancels.
  • LOCKED - Trader only able to submit cancels.
  • UNPLUGGED - TCP sessions terminated.


Order Risk Model

Reflector implements an "Order Risk model", not an "Order model". The difference is that only the attributes of an order that has risk implications are modeled.

For taker orders, this means that open orders and fills are separate entities. A given open taker order has exactly 3 possible states: nonexistent, live, and dead. The order is live from the outbound NewOrderSingle until an inbound ExecReport confirms its death. The fills that the open order accumulates have 3 possible states too: nonexistent, filled, and rolled back.

For makers, the inbound order itself is assumed to carry no risk. It is the outbound ExecReport that is being examined for risk. We model that as a fill that can potentially be rolled back; because most maker venues do not ack on accept, and rejects are rather rare.

Daily Settlement Limit

DSL is supported by Reflector, however it shoudl be noted that DSL is primarily a passive post-trade metric - as discussed in the following subsections.

Precision versus Correctness

DSL demands precision on a metric that is inherently ambiguous before an order executes: settlement date. There are three potential sources of truth with regard to settlement date on a spot order:

  • Trader - irrelevant in this context.
  • Venue  - silent on a NewOrderSingle, because it is the recipient.
  • Reflector - must determine settlement dates using Copp-Clark. But, what happens when the venue confirms a fill with a settlement date different to Reflector's?

Implications:

  • Reflector could conform the settlement date to the venue's value, but this essentially means that we have no daily limit.
  • Reflector could stick with its original determination, but would then be vulnerable to rollovers.


There is essentially no way to perfectly deduce settlement date pre-trade.


False Precision & Perverse Incentives

Even if the precision described in the previous section can be captured correctly, the effort to do so may be in vain.

A trader wishing to load up on risk while evading DSL can simply make sure to spread his orders between different settlement days. Even a trader who is fully compliant in spirit will be incentivized to take on riskier bets with longer settlement terms in the event that his near term position is approaching its DSL limit.

In other words, DSL encourages in practice precisely the kind of behavior it purports to curtail in principle.


Ordering

DSL is weakly ordered. Given two DSL positions, it is not possible in all cases to determine if one position is "more risky", "less risky", or "equally risky" as the other in terms of DSL. This matters a lot when a trader is put in any sort of "deleveraging mode", where only risk decreasing trades are allowed. Since we cannot determine which DSL is "worse" than another, we actually must also run something else to arbitrate, and when the arbitrating metric allows through a trade in deleveraging mode, it must be allowed to bypass DSL even if its limits are bust. DSL is therefore a rule that attempts to preempt extreme situations that actually must be discarded in precisely some of these extreme situations it is charged upon preventing.


The current implementation of DSL deleveraging mode requires that an order not increase worst-case risk assessment in any settlement date it deals in.


Performance

Implementing DSL requires us to multiply the memory required to store a position by 2N, where N is the average number of unsettled date buckets per pool of risk. This effect multiplies with other storage-multiplying features, such as counterparty position and multi-location. Worse yet, we cannot precompute all the dates; which means that we need additional synchronization during runtime to make sure that the web server read the correct memory locations. These factors have a direct impact for a real-time application.



  • No labels