This page documents Reflector's REST API.
The web server services requests on different threads than those that listen on TCP frames. As a result, some (minimal) amount of synchronization is required. All requests marked as GET either does not synchronize or at most grabs a read lock. Everything else (POST, PUT, DEL) requires scheduling and waiting. The goal is always to minimize the amount of work and synchronization required when servicing TCP frames.
All attempts to change configuration will be acknowledged with a reply with an HTTP status. It will have a ConfigFeedback categorization if actually serviced by the main thread. It may contain more details in the event of a rejection.
| HTTP Status | Source | Config Feedback | Description |
|---|---|---|---|
| 200 OK | main thread | SUCCESS | config change accepted and logged |
| 200 OK | both | IDEMPOTENT | config change accepted without change |
| 400 BAD REQUEST | web server | - | request malformed |
| 404 NOT FOUND | web server | - | entity not found |
| 405 METHOD NOT ALLOWED | web server | - | http method/action not allowed |
| 409 CONFLICT | main thread | REJECT | general reject (unused) |
| 409 CONFLICT | main thread | COLLISION | collision with existing name/value |
| 409 CONFLICT | main thread | NOT_FOUND | name/value not found |
| 409 CONFLICT | main thread | UNKNOWN_ACCOUNT | account lookup failed |
| 409 CONFLICT | main thread | TABLE_FULL | memory pool full |
| 409 CONFLICT | main thread | HASH_COLLISION | hash value collision |
| 409 CONFLICT | main thread | MALFORMED_NAME | malformed name/identifier |
| 409 CONFLICT | main thread | MALFORMED_PASS | malformed password |
| 409 CONFLICT | main thread | MALFORMED_DATE | malformed date |
| 409 CONFLICT | main thread | TYPE_MISMATCH | general category mismatch |
| 409 CONFLICT | main thread | SEQ_MISMATCH | sequence number mismatch |
| 409 CONFLICT | main thread | OUT_OF_RANGE | value/quantity out of range |
There are two types of commands here: state queries and shutdown.
[root]/system/ruokimok".[root]/system/envi[root]/system/stat[root]/system/update_dms_slack?[dms_slack_seconds][root]/system/shutdown[root]/system/abortSIGKILL. Not recommended for normal use.Exchange Codes identify either an exchange or a bank. When banks or exchanges provide multiple venues, they are typically combined in one because of convenience. This is reinforced by the fact that Reflector's FIX parser is mostly venue-agnostic. An exception is LMAX, whose FIX.4.4 feed is drastically different from its FIX.4.2 feed.
[root]/invariants/exchange_codes[ "FIX_360T", "FIX_ADS", "FIX_ANZ", "FIX_BAML", "FIX_Barclays", "FIX_BGC", "FIX_Bloomberg" , "FIX_BNPParibas", "FIX_CIBC", "FIX_Citadel", "FIX_Citi", "FIX_Commerz", "FIX_CreditSuisse" , "FIX_Currenex", "FIX_Deltix", "FIX_Deutsche", "FIX_DMALINK", "FIX_EBS", "FIX_Edgewater" , "FIX_Fastmatch", "FIX_FirstDerivative", "FIX_FlexTrade", "FIX_FXall", "FIX_FXCM" , "FIX_FXSpotStream", "FIX_GainGTX", "FIX_GFX", "FIX_GoldmanSachs", "FIX_GSA", "FIX_HenningCarey" , "FIX_Hotspot", "FIX_HSBC", "FIX_IG", "FIX_Integral", "FIX_ITG", "FIX_JPMorgan", "FIX_KCG" , "FIX_LMAX42", "FIX_LMAX44", "FIX_LumeFX", "FIX_MakoFX", "FIX_MorganStanley", "FIX_Nomura" , "FIX_ParFX", "FIX_Pragma", "FIX_PrimeXM", "FIX_RBC", "FIX_RBS", "FIX_Reuters", "FIX_Saxo" , "FIX_SEB", "FIX_SmartTrade", "FIX_SocGen", "FIX_SolidFX", "FIX_SpotEX", "FIX_StandardChartered" , "FIX_StateStreet", "FIX_SunTrading", "FIX_UBS", "FIX_Virtu", "FIX_Xenfin", "FIX_XTX" ] |
[root]/invariants/currencies[ "USD", "EUR", "JPY", "GBP", "AUD", "CAD", "CHF", "CNY" , "CNH", "SEK", "MXN", "NZD", "SGD", "HKD", "NOK", "KRW" , "TRY", "INR", "RUB", "BRL", "ZAR", "DKK", "PLN", "TWD" , "THB", "MYR", "HUF", "CZK", "ILS", "SAR", "CLP", "IDR" , "COP", "PHP", "RON", "PEN", "XAG", "XAU", "XPD", "XPT" , "AED", "BHD", "HRK", "ISK", "KWD", "OMR", "RSD", "EGP" ] |
All rates are stored as density per unit of USD, including the USD. Absolutely no concession will be made to the ``traditional" ordering of the currency pairs, apart from the fact that the rate update mechanism will parse it correctly when appropriately labeled. Rates are a global property, no one can have their own rate.
[root]/rates/allUSD.http method/path : PUT : [root]/rates/update
arguments : JSON dictionary of currency to rate. 2 possible forms: "CCY/USD", & "USD/CCY".
arg constraints : Rates must be between 10-4 and 104, and must be within a factor of 2 from the previous rate.
arg example : Disregarding rounding errors, the following argument sets are equivalent:
{ "EUR/USD": 1.03, "JPY/USD": 0.0086, "AUD/USD": 0.75 }
{ "USD/EUR": 0.97, "USD/JPY": 116.27, "USD/AUD": 1.33 }
Traders can only connect from whitelisted Trader IPs. Trader IP entries consist of 3 fields: origip, natip, and an optional string label. Whenever a TCP connection is refused, whether on account of Trader IP or Venue IP/Port, the Trader IP is added to a list of blocked Trader IPs
[root]/trader_ips/all[root]/trader_ips/bad[root]/trader_ips/[[search_term]][root]/trader_ips/new{ "orig_addr":"1.2.3.4", "nat_addr":"5.6.7.8", "label" : "invisible hand" }"nat_addr" is omitted, it is assumed that it is equivalent to "orig_addr".[root]/trader_ip/[trader_ip]/relabel{ "label" : "quantitative easer" }[root]/trader_ip/[trader_ip]/del"1.2.3.4"[root]/trader_ip/[trader_ip]/get"1.2.3.4"Traders can only connect to whitelisted Venue IP/Port pairs. A venue entry consists of: originalip/port, nattedip/port, exchange_code, and a boolean on whether it is a monitored endpoint. Whenever a TCP connection is refused, whether on account of Trader IP or Venue IP/Port, the Venue IP/Port is added to a list of blocked Venue IP/Ports.
[root]/venue_ips/all[root]/venue_ips/bad[root]/venue_ips/checked[root]/venue_ips/unchecked[root]/venue_ips/[exchange_code][root]/venue_ips/new{ "orig_addr":"1.2.3.4", "nat_addr":"5.6.7.8"
, "orig_port":3000, "nat_port":4000
, "exchange_code" : "FIX_Currenex", "checked" : true
} |
or"orig_[root]/venue_ip/[venue_ip]/[venue_port]/del"1.2.3.4"3000[root]/venue_ip/[venue_ip]/[venue_port]/get"1.2.3.4"3000Some venues dictate trader ip. This is handled by the `special routes' table. Given an original trader ip and translated venue ip/port, a special route entry provides a custom translated trader ip. The special route system is on an escape hatch for the address translation and not a part of the whitelist system, so both endpoints (trader & venue) still need to be separately whitelisted.
[root]/special_routes/all[root]/special_routes/new{ "orig_trader_addr" : "1.2.3.4"
, "nat_trader_addr" : "5.6.7.8"
, "nat_venue_addr" : "10.20.30.40"
, "nat_venue_port" : 1234
} |
"orig_trader_addr", "nat_venue_addr", and "nat_venue_port" constitutes the key"nat_trader_addr" constitutes the value[root]/special_route/[orig_trader_addr]/[nat_venue_addr]/[nat_venue_port]/del"1.2.3.4""5.6.7.8"1234A credential uniquely determined by the ordered quadruple : (TraderAddr, TraderPort, VenueAddr, VenuePort). Upon logon confirmation from the venue, a session will either be bound to a credential (if found and permitted to connect) or terminated.
[root]/sessions/all[root]/sessions/terminated[root]/sessions/[ip]"1.2.3.4"[root]/sessions/[search_term]A credential uniquely determined by the ordered triple : (ExchangeCode, CompID, SubID). Credentials participate in a many-to-many relationship with user groups. Credential type must be one of: {TAKER, MAKER, PASS_TKR, PASS_MKR, COPY, DATA}.
Credential double-login is an optional feature (empty string disables feature) where the trader is given an alternate password to be used aga upon validation, is overwritten into the real password required by the venue. The two passwords are required to have the same length.
Account overloading is another optional feature where orders and executions could be routed to different users based on certain fields sent over the wire, usually Account[1].
[root]/credentials/all[root]/credentials/[exchange_code]}[root]/credentials/[session_type_code]TAKER, MAKER, DATA.[root]/credentials/ENABLED[root]/credentials/DISABLED[root]/credentials/active[root]/credentials/overloaded[root]/credentials/[group_name][root]/credentials/new{ "venue" : "FIX_Currenex"
, "comp_id" : "LV-426"
, "sub_id" : "Nostromo"
, "user" : "Ash"
, "type" : "TAKER"
, "enabled" : true
, "zebra_pass" : "crew"
, "venue_pass" : "food"
} |
[root]/credential/enable{ "venue" : "FIX_Currenex", "comp_id" : "LV-426", "sub_id" : "Nostromo" }[root]/credential/disable{ "venue" : "FIX_Currenex", "comp_id" : "LV-426", "sub_id" : "Nostromo" }[root]/credential/change_pass{ "venue" : "FIX_Currenex"
, "comp_id" : "LV-426"
, "sub_id" : "Nostromo"
, "zebra_pass" : "spaceship"
, "venue_pass" : "xenomorph"
} |
A group represent a pool of risk. Within a group, the actualized outlays of the fills combined with the unactualized outlays of live orders form a Position". Additionally, every group has a set of risk parameters, known asLimits", to which the position is subject.
The set of groups organize themselves into trees, giving rise to 2 kinds of nodes: aggregate group & user group. An aggregate group can only contain other groups, and its position reflects the sum of the positions of its children. An user group does not contain other groups, but contains credentials, and its position reflects the sum of the positions of the credentials.
Every group has a integer visibility value, which dictates how far up the chain can the node be visible for.
Positions are stored as an array (indexed by currency) of ordered triples of (Buying, Selling, Filled).
Next, we have trading modes: (NORMAL, DEESCALATION, LOCKED, UNPLUGGED).\ The modes are controlled by 3 flags: (ESCALATION, TRADEABLE, ENABLED).\ When all flags are set, NORMAL mode entails.
There are many types of limits. The first is the primary limit, which must be one of (DownSide, UpSide, Exposure, Displacement), and is used to determine whether an order action increases risk. There are fat-finger checks, such as the submission rate limit, the single limit, and the pending limit. And finally, we have single currency trading permissions and exposure limits.
[root]/groups/all[root]/groups/all_names[root]/groups/all_limits[root]/groups/all_positions[root]/groups/selected?[groups][root]/groups/new{ "type" : "USER"
, "name" : "Ash"
, "visibility" : 127
, "parent_name" : "Weyland-Yutani"
, "throttle" : 5
, "single" : 10000000
, "pending" : 10000000
, "limit_type" : "DOWNSIDE"
, "position" : 30000000
, "flags" :
{ "ENABLED" : true
, "TRADEABLE" : true
, "ESCALATION" : true
, "THROTTLE": true
, "SINGLE" : true
, "POSITION" : true
, "PENDING" : true
, "DMS" : false
}
} |
[root]/group/[group]/get[root]/group/[group]/get_limit[root]/group/[group]/get_position[root]/group/[group]/get_component[root]/group/[group]/get_daily_component[root]/group/[group]/get_nested[root]/group/[group]/get_nested_names[root]/group/[group]/rename{ "new_name" : "Bishop" }[root]/group/[group]/retag{ "new_tag" : "android" }[root]/group/[group]/move{ "parent_name" : "Union-Aerospace", "visibility" : 1 }[root]/group/[group]/heartbeatupdate_limit| with these flags set to true:ENABLED, TRADEABLE, ESCALATION, DMS`.[root]/group/[group]/update_limit{ "throttle" : 5
, "single" : 10000000
, "pending" : 10000000
, "limit_type" : "EXPOSURE"
, "credit" : 30000000
, "leverage" : 1
, "flags" :
{ "ENABLED" : false
, "TRADEABLE" : false
, "ESCALATION" : false
, "THROTTLE": false
, "SINGLE" : false
, "POSITION" : false
, "PENDING" : false
, "DMS" : false
}
} |
[root]/group/[group]/update_currency_limit{ "currency_control": true
, "ccy_limit_denomination": "NATIVE"
, "USD": 10000000
, "EUR": 10000000
, "GBP": 10000000
, "JPY": 1000000000
} |
[root]/group/[group]/update_currency_volatility{ "USD": 1
, "EUR": 5
, "GBP": 2
, "JPY": 0.5
} |
[root]/group/[group]/update_currency_propertiesupdate_currency_limit & update_currency_volatility into one single atomic call.{ "limits":
{ "currency_control": true
, "ccy_limit_denomination": "RESERVE"
, "USD": 10000000
, "EUR": 10000000
, "GBP": 10000000
, "JPY": 10000000
}
, "volatilities":
{ "USD": 1
, "EUR": 5
, "GBP": 2
, "JPY": 0.5
}
} |
[root]/group/[group]/update_currency_basket{ "currency_basket_control": true
, "ccy_baskets":
[ { "name": "G10", "range": "[ USD EUR JPY GBP CHF AUD NZD CAD SEK NOK ]", "limit": 1000000000 }
, { "name": "Emergent.Markets", "range": "[ BRL RUB INR CNY CNH ]", "limit": 1000000000 }
]
} |
The order/position adjustment mechanism is not meant to be called directly. The only thing that should interface with it should be the database synchronization procedure.
[root]/ledger/get[root]/ledger/bind{ "db_target" : "postgres0.mf" }[root]/ledger/roll{ "name" : "Hudson", "counter" : 1, "date" : "2017-01-15" }[root]/ledger/diff{ "name" : "Hudson"
, "counter" : 1
, "date" : "2017-01-15"
, "venue": "FIX_Currenex"
, "comp_id" : "LV-426"
, "sub_id" : "Nostromo"
, "account": ""
, "USD" : 45000000
, "JPY" : -600000000
, "AUD" : -3000000
, "EUR" : 8000000
, "GBP" : -12000000
, "observed_execs" : [ ]
} |
[root]/ledger/externaldiff, but tracked separately and with a more relaxed consistency requirement.[root]/ledger/dates