This document is a Jupyter notebook available on LSEG's Developer Portal.
all endpoints refer to the LSEG Data Platform, namely https://api.refinitiv.com/tradefeedr/
.
Conceptually, each API call has two components:
API end-point: This can be thought of as a function doing a specific job. For example, consider the API endpoint v1/fx/algo/parent-orders
. Parsing the endpoint name, one can conclude that it is API version 1 (v1), in the fx space, algo sub-space (meaning algo execution), and the actual function name is parent-orders
.
JSON string: This contains a set of parameters for the API end-point function. The exact structure of the query string depends on the endpoint, but the following parameters are typically present:
{'groupby':['Symbol']}
implies that results have to be grouped by Symbol.var = ['TradeQuantityUSD']
means that we would like to select TradeQuantityUSD. Aggregation can be implicit (sum for TradeQuantityUSD) or explicit (user can specify something like {"function": "avg", "var": "TradeQuantityUSD", "name": "MyAvgTradeQuantity"}
).{"function": "within", "var": "Date", "pars": ["2014-01-01", "2021-11-30"]}
filters the data to be within a certain range.All API endpoints return a JSON dictionary which can be translated into Python pandas (examples below).
Tradefeedr API can be split into the following groups:
Each group contains a number of "functions" to perform specific tasks. In what follows, those functions are described for each group.
import pandas as pd
import json
import numpy as np
import matplotlib.pyplot as plt
import plotly.express as px
import lseg.data as ld
ld.open_session()
<lseg.data.session.Definition object at 0x13c0670e590 {name='ppe'}>
Algo is defined as a combination of one or several Parent instructions and child orders. Parent instructions are conveyed from algo user to algo provider and include initial instruction (e.g., buy 100m EURUSD using Algo1 with Limit Price 1.20) and subsequent instructions (e.g., amend LimitPrice, amend OrderQuantity, amend Algo Urgency, etc.). Child orders are executed by algo provider as part of execution. The absolute minimum for meaningful analysis is to have Parent instruction and child fills. Depending on the algo provider, other child events such as order placements and rejects can be analyzed as well.
v1/fx/algo/parent-order-stats
returns a table with algo trading performance statistics, e.g., ArrivalMidPerfBPS. Each row contains algo trading performance aggregated by the specified groupby fields.
The purpose of the endpoint is to provide standard algo performance metrics aggregated across user-defined categories like currency pair or LP. For example, a user can rank the trading performance of their algo vendors using a performance metric (list of those provided below) within a specific time frame or for certain currency pairs.
The API endpoint requires a Query String. A Query String is a JSON object representing query logic in SQL-like fashion that contains the following fields:
The user can specify risk_price_benchmark as an additional field in the Query. The four possible values are described below:
# Send request to endpoint
request = ld.delivery.endpoint_request.Definition(
method=ld.delivery.endpoint_request.RequestMethod.POST,
url="tradefeedr/v1/fx/algo/parent-order-stats",
header_parameters={"Content-Type": "application/json"},
body_parameters={
"options": {
"groupby": [
"LP",
],
"select": [
# "TradeQuantityUSD",
#'ArrivalMidPerfBPS',
#'TWAPMidPerfBPS'
],
"filter": [
{"function": "within", "var": "Date", "pars": ["2014-01-01", "2025-12-31"]},
{"function": "in", "var": "Symbol", "par": ["EURUSD"]},
{"function": "within", "var": "ArrivalTime", "transform": "time", "pars": ["09:00:00", "20:00:00"]},
],
"risk_price_benchmark": "TradefeedrModel",
"notation": "performance"}})
response = request.get_data()
response_json = json.loads(response.data.raw)
result_df = pd.DataFrame(response_json["result"])
display(result_df)
LP | NumRuns | TradeQuantityUSD | OrderQuantityUSD | Duration | AssumedRisk | TradeIntensity | SpreadPaidBPSChildOrders | ArrivalMidPerfBPS | ArrivalMidPerfBPSStdDev | ... | ArrivalMidPerfTradeNetBPS | ArrivalMidPerfRemainNetBPS | TWAPMidPerfNetBPS | TWAPMidPerfNetBPSStdDev | RiskTransferPricePerfNetBPS | RiskTransferPricePerfNetBPSStdDev | ExecutionScore | ReversalScore | RiskTransferPricePerfIR | RiskTransferPricePerfNetIR | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | LP1 | 181 | 7.430435e+09 | 1.369676e+10 | 2083.317730 | 5.739559 | 117.066196 | 0.290844 | 0.807439 | 6.583353 | ... | 0.662582 | 1.379088 | -0.332539 | 2.270122 | 3.274181 | 6.559950 | 35.757815 | 41.233440 | 0.499117 | 0.499117 |
1 | LP2 | 184 | 7.291722e+09 | 1.398124e+10 | 1642.787354 | 5.285815 | 99.528063 | 0.281504 | 0.742939 | 5.751016 | ... | 0.430575 | 1.338693 | -0.064316 | 2.550290 | 3.250307 | 5.836353 | 38.374341 | 38.533477 | 0.556907 | 0.556907 |
2 | LP3 | 174 | 7.079398e+09 | 1.348800e+10 | 1247.272126 | 4.880645 | 98.924659 | 0.253023 | 0.023590 | 5.516902 | ... | -0.070885 | -0.046889 | -0.199247 | 1.936761 | 2.655498 | 5.658777 | 38.230079 | 43.021386 | 0.469271 | 0.469271 |
3 | TOTAL | 539 | 2.180156e+10 | 4.116600e+10 | 1664.497851 | 5.308894 | 105.309496 | 0.275439 | 0.531335 | 5.986756 | ... | 0.346814 | 0.902535 | -0.199547 | 2.271982 | 3.065297 | 6.044681 | 37.435729 | 40.910995 | 0.507107 | 0.507107 |
4 rows × 29 columns
v1/fx/algo/parent-orders
returns a table of algo execution information, one algo run per table row. Each row contains a number of fields controlled by the select parameter. The fields are either (1) descriptive such as ParentOrderID, Symbol, LP or (2) calculated such as ArrivalMidPerfBPS.
The endpoint can be used to build algo trading blotter. For example, a user can query the most recent trades and their associated performance metrics. API endpoint can also be used to compare the distributions of algo trading performance across different algo providers, business units, currencies etc (algo wheel).
The API endpoint requires a JSON query representing query logic in SQL-like fashion and containing the following fields:
request = ld.delivery.endpoint_request.Definition(
method=ld.delivery.endpoint_request.RequestMethod.POST,
url="tradefeedr/v1/fx/algo/parent-orders",
header_parameters={"Content-Type": "application/json"},
body_parameters={
"options": {
"select": [
"Date",
"ParentOrderID",
"Symbol",
"TradeCurrency",
"Side",
"LegSymbols",
"Trader",
"Account",
"SubAccount",
"AlgoName",
"LP",
"TimeZoneArrive",
"HourArrive",
"TimeZoneEnd"],
"filter": [
{"function": "within", "var": "Date", "pars": ["2014-01-01", "2024-01-01"]}]}},
)
response = request.get_data()
response_json = json.loads(response.data.raw)
parent_order_df = pd.DataFrame(response_json["result"])
display(parent_order_df)
Date | ParentOrderID | Symbol | TradeCurrency | Side | LegSymbols | Trader | Account | SubAccount | AlgoName | LP | TimeZoneArrive | HourArrive | TimeZoneEnd | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 2022-03-01 | 20220301-A00 | EURUSD | EUR | S | [EURUSD] | Algo | Algo | DefaultSubAccount | MidTracker | LP3 | London | 9 | London |
1 | 2022-03-01 | 20220301-A01 | EURUSD | EUR | B | [EURUSD] | Algo | Algo | DefaultSubAccount | PassiveMidTracker | LP3 | London | 12 | London |
2 | 2022-03-01 | 20220301-A02 | EURUSD | EUR | S | [EURUSD] | Algo | Algo | DefaultSubAccount | Iceberg | LP1 | London | 15 | London |
3 | 2022-03-01 | 20220301-A03 | USDJPY | USD | S | [USDJPY] | Algo | Algo | DefaultSubAccount | MidTracker | LP1 | NewYork | 19 | NewYork |
4 | 2022-03-01 | 20220301-A04 | EURUSD | EUR | B | [EURUSD] | Algo | Algo | DefaultSubAccount | AggressivePOL | LP1 | NewYork | 19 | NewYork |
... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
1640 | 2022-08-03 | m20220803-A00 | AUDCHF | AUD | S | [AUDCHF, AUDUSD, USDCHF] | Algo | Algo | DefaultSubAccount | PassiveMidTracker | LP3 | London | 11 | London |
1641 | 2022-08-04 | m20220804-A00 | AUDCAD | AUD | S | [AUDUSD, USDCAD] | Algo | Algo | DefaultSubAccount | MidTracker | LP2 | London | 9 | London |
1642 | 2022-08-05 | m20220805-A00 | AUDCHF | AUD | S | [AUDCHF, AUDUSD, USDCHF] | Algo | Algo | DefaultSubAccount | PassiveMidTracker | LP1 | London | 8 | London |
1643 | 2022-08-08 | m20220808-A00 | AUDCAD | AUD | S | [AUDUSD, USDCAD] | Algo | Algo | DefaultSubAccount | Iceberg | LP2 | London | 16 | NewYork |
1644 | 2022-08-09 | m20220809-A00 | AUDCAD | AUD | B | [AUDUSD, USDCAD] | Algo | Algo | DefaultSubAccount | PassiveMidTracker | LP2 | London | 11 | London |
1645 rows × 14 columns
v1/fx/algo/execution-stats
allows the user to query across the entire algo execution history (from parent level information to child orders/events). The query returns a table with the metrics (fields) selected by the user as columns. The rows are defined by groupby statements.
request = ld.delivery.endpoint_request.Definition(
method=ld.delivery.endpoint_request.RequestMethod.POST,
url="tradefeedr/v1/fx/algo/execution-stats",
header_parameters={"Content-Type": "application/json"},
body_parameters={
"options": {
"groupby": ["ExecVenue"],
"select": [
"TradeQuantityUSD", # sum
"SpreadPnLPM", # TradeQuantityUSD-weighted average
"DecayPM1s", # TradeQuantityUSD-weighted average
"Symbol", # cannot aggregate - returns None
"ExecVenue", # cannot aggregate - returns None
"Mid0", # cannot aggregate - returns None
"Price", # cannot aggregate - returns None
{"function": "sum", "var": "TradeQuantityUSD", "name": "TotalVolume"}, # explicit aggregation function
{"function": "avg", "var": "Price", "name": "AvgPrice"}, # explicit aggregation function
],
"filter": [
{"function": "within", "var": "Date", "pars": ["2014-01-01", "2025-11-30"]},
{"function": "within", "var": "TradeTime", "transform": "time", "pars": ["12:00:00", "14:00:00"]},
{"function": "in", "var": "Symbol", "pars": ["EURUSD", "USDJPY"]},
{"function": "eq", "var": "ParentChild", "par": "Child"},
],
}})
response = request.get_data()
response_json = json.loads(response.data.raw)
result_df = pd.DataFrame(response_json["result"])
display(result_df)
ExecVenue | TradeQuantityUSD | SpreadPnLPM | DecayPM1s | Symbol | Mid0 | Price | TotalVolume | AvgPrice | |
---|---|---|---|---|---|---|---|---|---|
0 | ExecV1 | 2.353820e+09 | 25.887285 | -1.967305 | None | None | None | 2.353820e+09 | 46.472571 |
1 | ExecV2 | 2.598710e+09 | 25.193271 | -2.187609 | None | None | None | 2.598710e+09 | 42.051753 |
display(px.bar(result_df.sort_values('TradeQuantityUSD'), x='ExecVenue', y='TradeQuantityUSD'))
v1/fx/algo/markouts
returns the markout curves information.
Different Markout Types are supported:
Mark-out Curves represent market dynamics before and after each trading event (fill, reject, or order placement). This market dynamics is typically aggregated across different categories such as Symbol LP, ExecVenue, and ParentOrderID but it is possible to extract markout curves for each trading event as well.
request = ld.delivery.endpoint_request.Definition(
method=ld.delivery.endpoint_request.RequestMethod.POST,
url="tradefeedr/v1/fx/algo/markouts",
header_parameters={"Content-Type": "application/json"},
body_parameters={
"options": {
"groupby": ["ExecVenue"],
"child_filter": [
{"function": "like", "var": "ParentChild", "par": "Child"}
],
"parent_filter":[
# {"function": "like", "var": "ParentOrderID", "par": "20180921-A00"},
{"function": "within", "var": "Date", "par": ['2017-01-01', '2025-01-01']}
]
}})
response = request.get_data()
response_json = json.loads(response.data.raw)
result_df = pd.DataFrame(response_json["result"])
display(result_df)
ExecVenue | TradeQuantityUSD | NumEvents | MarkoutType | -10s | -5s | -4s | -3s | -2s | -1s | ... | 15s | 20s | 30s | 45s | 1m | 2m | 3m | 4m | 5m | 10m | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | ExecV1 | 3.869159e+10 | 17993 | Markouts | 26.762634 | 27.186115 | 26.743079 | 26.697213 | 27.210438 | 27.050383 | ... | 26.495736 | 25.987476 | 24.767503 | 24.567175 | 24.349499 | 25.022601 | 25.569643 | 19.743626 | 18.900277 | 2.609239 |
1 | ExecV2 | 3.991564e+10 | 18147 | Markouts | 26.951506 | 26.547751 | 26.491076 | 26.737794 | 26.728522 | 26.790061 | ... | 24.821655 | 24.013963 | 22.659762 | 20.688178 | 20.413556 | 17.706123 | 17.958341 | 16.991607 | 13.979329 | -7.674540 |
2 | ExecV1 | 3.869159e+10 | 17993 | MarkoutsAtZero | -0.049681 | -0.473162 | -0.030126 | 0.015740 | -0.497485 | -0.337430 | ... | 0.217217 | 0.725477 | 1.945450 | 2.145778 | 2.363454 | 1.690352 | 1.143310 | 6.969327 | 7.812676 | 24.103714 |
3 | ExecV2 | 3.991564e+10 | 18147 | MarkoutsAtZero | -0.069881 | 0.333874 | 0.390549 | 0.143830 | 0.153102 | 0.091564 | ... | 2.059970 | 2.867661 | 4.221863 | 6.193446 | 6.468069 | 9.175502 | 8.923283 | 9.890017 | 12.902296 | 34.556165 |
4 | ExecV1 | 3.869159e+10 | 17993 | MarkoutsAtZeroAverage | 0.668962 | 0.351727 | 0.512756 | 0.472502 | -0.137857 | -0.094899 | ... | 1.036159 | 1.038150 | 2.248744 | 3.702136 | 4.887439 | 6.898983 | 4.667555 | 9.483972 | 11.970677 | 28.626283 |
5 | ExecV2 | 3.991564e+10 | 18147 | MarkoutsAtZeroAverage | -0.436319 | -0.032240 | 0.154454 | 0.267418 | 0.121488 | 0.070139 | ... | 1.640600 | 2.296883 | 3.761149 | 6.434496 | 6.671627 | 9.215595 | 8.905094 | 11.472097 | 16.226729 | 37.706587 |
6 | ExecV1 | 3.869159e+10 | 17993 | Volatilities | 0.675291 | 0.493714 | 0.448863 | 0.394852 | 0.330476 | 0.247679 | ... | 0.788448 | 0.905525 | 1.092144 | 1.341136 | 1.564768 | 2.170245 | 2.661621 | 3.019756 | 3.314036 | 4.664317 |
7 | ExecV2 | 3.991564e+10 | 18147 | Volatilities | 0.673840 | 0.499962 | 0.437518 | 0.391004 | 0.327820 | 0.242905 | ... | 0.785911 | 0.905963 | 1.096352 | 1.351102 | 1.548342 | 2.155697 | 2.656413 | 3.020933 | 3.318031 | 4.699018 |
8 rows × 34 columns
v1/fx/algo/event-history
allows the user to query all trading events for a given ParentOrderID. It should be used when the user requires detailed analysis and understanding of a specific ParentOrderID execution profile. The endpoint allows selection of multiple metrics (fields) such as spread paid and market impact at different time horizons (corresponding to each child order event available in the Tradefeedr database).
The API endpoint requires a JSON object representing query logic similar to SQL and containing the following fields:
parent_order_df.ParentOrderID.iloc[-1]
'm20220809-A00'
data_frame_parent = result_df
target_parent_order = list(data_frame_parent.iloc[-1])[0]
request = ld.delivery.endpoint_request.Definition(
method=ld.delivery.endpoint_request.RequestMethod.POST,
url="tradefeedr/v1/fx/algo/event-history",
header_parameters={"Content-Type": "application/json"},
body_parameters={
"options": {
"select": [
"ParentChild",
"ParentOrderID",
"TradeID",
"Symbol",
"Side",
"TradeCcy",
"TradeQuantityUSD",
"OrderQuantity",
"Price",
"OrderType",
"ExecVenue",
"Mid0",
"Mid1s",
"DecayPM1s",
"SpreadPnLPM",
"ArrivalTime",
"TradeTime"
],
"filter": [
{"function": "eq", "var": "ParentOrderID", "par": parent_order_df.ParentOrderID.iloc[-1]},
]
}})
response = request.get_data()
response_json = json.loads(response.data.raw)
result_df = pd.DataFrame(response_json["result"])
display(result_df)
ParentChild | ParentOrderID | TradeID | Symbol | Side | TradeCcy | TradeQuantityUSD | OrderQuantity | Price | OrderType | ExecVenue | Mid0 | Mid1s | DecayPM1s | SpreadPnLPM | ArrivalTime | TradeTime | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | Parent | m20220809-A00 | m20220809-A00-00 | AUDCAD | B | AUD | 0.00 | 75000000.0 | 0.89736 | Market | Parent | 0.897354 | 0.897354 | 0.000000 | NaN | 1660044656000 | 1660044656000 |
1 | Parent | m20220809-A00 | m20220809-A00-06 | AUDCAD | B | AUD | 0.00 | 75000000.0 | 0.89682 | Market | Parent | 0.896813 | 0.896817 | 5.356192 | NaN | 1660045477000 | 1660045477000 |
2 | Child | m20220809-A00 | m20220809-A00-01 | AUDUSD | B | AUD | 914946.90 | 1311000.0 | 0.69791 | Market | ExecV2 | 0.697900 | 0.697905 | 7.164350 | 14.328700 | 1660044884000 | 1660044884000 |
3 | Child | m20220809-A00 | m20220809-A00-02 | AUDUSD | B | AUD | 939407.05 | 1346000.0 | 0.69793 | Market | ExecV1 | 0.697925 | 0.697925 | 0.000000 | 7.164094 | 1660044937000 | 1660044937000 |
4 | Child | m20220809-A00 | m20220809-A00-03 | AUDUSD | B | AUD | 4248871.20 | 6090000.0 | 0.69769 | Market | ExecV2 | 0.697680 | 0.697680 | 0.000000 | 14.333219 | 1660045064000 | 1660045064000 |
5 | Child | m20220809-A00 | m20220809-A00-04 | AUDUSD | B | AUD | 1225454.79 | 1757000.0 | 0.69747 | Market | ExecV2 | 0.697470 | 0.697425 | -64.518904 | 0.000000 | 1660045214000 | 1660045214000 |
6 | Child | m20220809-A00 | m20220809-A00-05 | AUDUSD | B | AUD | 7459608.42 | 10698000.0 | 0.69729 | Market | ExecV2 | 0.697290 | 0.697295 | 7.170618 | 0.000000 | 1660045452000 | 1660045452000 |
7 | Child | m20220809-A00 | m20220809-A00-01 | USDCAD | B | USD | 914684.70 | 914684.7 | 1.28597 | Market | ExecV2 | 1.285965 | 1.285965 | 0.000000 | 3.888131 | 1660044884000 | 1660044884000 |
8 | Child | m20220809-A00 | m20220809-A00-02 | USDCAD | B | USD | 939104.20 | 939104.2 | 1.28583 | Market | ExecV1 | 1.285820 | 1.285820 | 0.000000 | 7.777138 | 1660044937000 | 1660044937000 |
9 | Child | m20220809-A00 | m20220809-A00-03 | USDCAD | B | USD | 4248993.00 | 4248993.0 | 1.28612 | Market | ExecV2 | 1.286110 | 1.286110 | 0.000000 | 7.775385 | 1660045064000 | 1660045064000 |
10 | Child | m20220809-A00 | m20220809-A00-04 | USDCAD | B | USD | 1225858.90 | 1225858.9 | 1.28619 | Market | ExecV2 | 1.286185 | 1.286240 | 42.762122 | 3.887466 | 1660045214000 | 1660045214000 |
11 | Child | m20220809-A00 | m20220809-A00-05 | USDCAD | B | USD | 7463994.60 | 7463994.6 | 1.28619 | Market | ExecV2 | 1.286185 | 1.286185 | 0.000000 | 3.887466 | 1660045452000 | 1660045452000 |
v1/fx/algo/market-data
give back the market data during algo exec.:
parent_order_df.ParentOrderID.iloc[-1]
'm20220809-A00'
request = ld.delivery.endpoint_request.Definition(
method=ld.delivery.endpoint_request.RequestMethod.POST,
url="tradefeedr/v1/fx/algo/market-data",
header_parameters={"Content-Type": "application/json"},
body_parameters={
"options": {
"filter": [
{"function": "eq", "var": "ParentOrderID", "par": parent_order_df.ParentOrderID.iloc[-1]},
]
}})
response = request.get_data()
response_json = json.loads(response.data.raw)
result_df = pd.DataFrame(response_json["result"])
display(result_df)
Time | Mid | Symbol | |
---|---|---|---|
0 | 1660044056000 | 0.897008 | AUDCAD |
1 | 1660044057000 | 0.897027 | AUDCAD |
2 | 1660044058000 | 0.897033 | AUDCAD |
3 | 1660044059000 | 0.897049 | AUDCAD |
4 | 1660044060000 | 0.897039 | AUDCAD |
... | ... | ... | ... |
4470 | 1660046070000 | 1.286435 | USDCAD |
4471 | 1660046071000 | 1.286440 | USDCAD |
4472 | 1660046073000 | 1.286480 | USDCAD |
4473 | 1660046074000 | 1.286470 | USDCAD |
4474 | 1660046075000 | 1.286465 | USDCAD |
4475 rows × 3 columns
v1/fx/algo/pnl-history
for each individual algo returns back market data during specific algo execution. The algo parent order ID has to be provided by user:
parent_order_df.ParentOrderID.iloc[-1]
'm20220809-A00'
request = ld.delivery.endpoint_request.Definition(
method=ld.delivery.endpoint_request.RequestMethod.POST,
url="tradefeedr/v1/fx/algo/pnl-history",
header_parameters={"Content-Type": "application/json"},
body_parameters={
"options": {
"filter": [
{"function": "eq", "var": "ParentOrderID", "par": parent_order_df.ParentOrderID.iloc[-1]},
]
}})
response = request.get_data()
response_json = json.loads(response.data.raw)
result_df = pd.DataFrame(response_json["result"])
display(result_df)
Time | Mid | LimitPrice | IsActive | SlippageToArrivalMidPM | SlippageToArrivalMidPMUser | SlippageToArrivalMidPMBank | TradeQuantityRemainUSD | |
---|---|---|---|---|---|---|---|---|
0 | 1660044656000 | 0.897354 | None | Active | 0.000000 | 0.0 | 0.000000 | 52327500.00 |
1 | 1660044657000 | 0.897353 | None | Active | -0.608734 | 0.0 | -0.608734 | NaN |
2 | 1660044658000 | 0.897339 | None | Active | -16.159011 | 0.0 | -16.159011 | NaN |
3 | 1660044659000 | 0.897350 | None | Active | -4.496303 | 0.0 | -4.496303 | NaN |
4 | 1660044660000 | 0.897346 | None | Active | -8.383872 | 0.0 | -8.383872 | NaN |
... | ... | ... | ... | ... | ... | ... | ... | ... |
680 | 1660045473000 | 0.896819 | None | Active | -20.654098 | 0.0 | -20.654098 | NaN |
681 | 1660045474000 | 0.896838 | None | Active | -20.654098 | 0.0 | -20.654098 | NaN |
682 | 1660045475000 | 0.896816 | None | Active | -20.654098 | 0.0 | -20.654098 | NaN |
683 | 1660045476000 | 0.896813 | None | Active | -20.654098 | 0.0 | -20.654098 | NaN |
684 | 1660045477000 | 0.896813 | None | Active | -20.654098 | 0.0 | -20.654098 | 37539211.64 |
685 rows × 8 columns
The set of Tradefeder RFS API allow the user to perform any task from calculating top level trading performance summary table to investigating the quality of invividual child fills.
v1/fx/rfs/summary-stats
allows api user to generate an RFS execution summary report.
The summary report includes standard flow quality metrics such as trading volume, spread paid, rejection costs, market impact (flow toxicity) across user defined categories. The query returns a table with the metrics (fields) groupby the user defined columns.
request = ld.delivery.endpoint_request.Definition(
method=ld.delivery.endpoint_request.RequestMethod.POST,
url="tradefeedr/v1/fx/rfs/summary-stats",
header_parameters={"Content-Type": "application/json"},
body_parameters={
"options": {
"groupby":[
"Symbol",
{"function": "gt", "var": "SpreadPnLPM", "pars": 100, 'name':"IsThisAnOutlier"},
],
#"select": []
"filter":[
{"function": "within", "var": "Date", "pars": ["2017-01-01", "2025-12-31"]},
{"function": "not_in", "var": "Symbol", "pars": ["EURUSD", "USDJPY", "GBPUSD"]},
#{"function": "gt", "var": "SpreadPnLPM", "pars": 100},
],
"time_offset": '1m'
}})
response = request.get_data()
response_json = json.loads(response.data.raw)
result_df = pd.DataFrame(response_json["result"])
display(result_df)
Symbol | IsThisAnOutlier | NumberOfFills | NumberOfRejects | FillVolume | RejectVolume | AvgTradeSizeUSD | SpreadPaid | RejectCost | ToxicityOfFills | RejectToFill | EffectiveSpread | VolumeShare | RejectCostUSD | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | AUDUSD | False | 667 | 31 | 338.407103 | 18.150338 | 5.073570e+05 | 21.252509 | 101.155141 | 26.261269 | 0.053635 | 26.677927 | 58.095048 | 1836.000000 |
1 | AUDUSD | True | 9 | 1 | 9.245359 | 0.535108 | 1.027262e+06 | 120.330637 | -1752.917168 | 134.608070 | 0.057878 | 18.874334 | 1.587170 | -938.000000 |
2 | NZDUSD | False | 118 | 10 | 65.595443 | 5.951270 | 5.558936e+05 | 33.660875 | 188.531187 | 72.245872 | 0.090727 | 50.765722 | 11.260905 | 1122.000000 |
3 | NZDUSD | True | 18 | 6 | 10.558029 | 5.215464 | 5.865572e+05 | 126.396692 | 415.495151 | 124.312970 | 0.493981 | 331.643324 | 1.812519 | 2167.000000 |
4 | USDCAD | False | 124 | 9 | 95.000000 | 5.300000 | 7.661290e+05 | 23.452220 | 24.267258 | 19.737939 | 0.055789 | 24.806077 | 16.308847 | 128.616468 |
5 | USDCHF | False | 59 | 0 | 39.500000 | 0.000000 | 6.694915e+05 | 23.373633 | 0.000000 | -0.255867 | 0.000000 | 23.373633 | 6.781047 | 0.000000 |
6 | USDHUF | True | 1 | 0 | 1.000000 | 0.000000 | 1.000000e+06 | 271.336436 | 0.000000 | -60.876765 | 0.000000 | 271.336436 | 0.171672 | 0.000000 |
7 | USDNOK | False | 9 | 0 | 6.000000 | 0.000000 | 6.666667e+05 | 42.260768 | 0.000000 | -56.070565 | 0.000000 | 42.260768 | 1.030032 | 0.000000 |
8 | USDNOK | True | 5 | 0 | 6.500000 | 0.000000 | 1.300000e+06 | 136.928774 | 0.000000 | -49.598856 | 0.000000 | 136.928774 | 1.115868 | 0.000000 |
9 | USDSEK | True | 2 | 0 | 1.100000 | 0.000000 | 5.500000e+05 | 211.062027 | 0.000000 | -27.160797 | 0.000000 | 211.062027 | 0.188839 | 0.000000 |
10 | USDSGD | False | 1 | 0 | 1.000000 | 0.000000 | 1.000000e+06 | 53.157747 | 0.000000 | 74.420846 | 0.000000 | 53.157747 | 0.171672 | 0.000000 |
11 | USDTRY | False | 1 | 0 | 0.700000 | 0.000000 | 7.000000e+05 | 98.487045 | 0.000000 | 116.519884 | 0.000000 | 98.487045 | 0.120170 | 0.000000 |
12 | USDTRY | True | 5 | 0 | 3.400000 | 0.000000 | 6.800000e+05 | 252.432494 | 0.000000 | 25.175635 | 0.000000 | 252.432494 | 0.583685 | 0.000000 |
13 | USDZAR | False | 1 | 0 | 1.000000 | 0.000000 | 1.000000e+06 | 11.582520 | 0.000000 | -270.258792 | 0.000000 | 11.582520 | 0.171672 | 0.000000 |
14 | USDZAR | True | 5 | 0 | 3.500000 | 0.000000 | 7.000000e+05 | 473.287330 | 0.000000 | 386.957610 | 0.000000 | 473.287330 | 0.600852 | 0.000000 |
v1/fx/rfs/execution-stats
allows the user to query across the entire execution history. The query returns a table (in Json file format as all APIs) with the metrics (fields) selected by the user as columns. The rows are defined by groupby statements.
The endpoint is designed to study general execution quality of the trades and their associated market impact. For example, in the notebook we show how a user can use this endpoint to create a venue analysis. It includes the summarised spread paid and market impact generated by different liquidity providers split by the different platforms/ECNs the user trades on.
request = ld.delivery.endpoint_request.Definition(
method=ld.delivery.endpoint_request.RequestMethod.POST,
url="tradefeedr/v1/fx/rfs/execution-stats",
header_parameters={"Content-Type": "application/json"},
body_parameters={
"options": {
"groupby":[
"Account", "Trader", 'Symbol'
],
'select': [
'TradeQuantityUSD',
{"function": "avg", "var": "TradeQuantityUSD", "name": 'averageSize'}, ### avgTradeQuantityUSD, sumTradeQuantity, medianTradeQuantity, medianLatency
{"function": "avg", "var": "DecayPM1s", "name": 'decay1s'},
{"function": "avg", "var": "DecayPM1m", "name": 'decay1m'},
"DecayPM1m", # implicitly doing weighted average
{"function": "min", "var": "Date", "name": 'minDate'},
{"function": "max", "var": "Date", "name": 'MYmaxDate'},
],
"filter":[
{"function": "within", "var": "Date", "pars": ["2017-01-01", "2017-12-31"]},
# {"function": "not_in", "var": "Symbol", "pars": ["EURUSD", "USDJPY", "GBPUSD"]},
],
}})
response = request.get_data()
response_json = json.loads(response.data.raw)
result_df = pd.DataFrame(response_json["result"])
display(result_df)
Account | Trader | Symbol | TradeQuantityUSD | averageSize | Decay1s | Decay1m | DecayPM1m | minDate | MYmaxDate | |
---|---|---|---|---|---|---|---|---|---|---|
0 | Account | Trader | AUDUSD | 3.663379e+08 | 5.174264e+05 | 7.326905 | 13.870029 | 30.107449 | 2017-02-02 | 2017-04-28 |
1 | Account | Trader | EURUSD | 1.187240e+09 | 7.754673e+05 | 3.779399 | 1.402014 | -4.293149 | 2017-02-01 | 2017-04-28 |
2 | Account | Trader | GBPUSD | 8.437707e+08 | 1.070775e+06 | 11.591372 | 23.219642 | 8.424090 | 2017-02-01 | 2017-04-28 |
3 | Account | Trader | NZDUSD | 8.732021e+07 | 5.744750e+05 | 23.090909 | 76.036456 | 106.968368 | 2017-02-01 | 2017-04-26 |
4 | Account | Trader | USDCAD | 1.003000e+08 | 7.541353e+05 | 15.890089 | 14.135086 | 19.977275 | 2017-02-03 | 2017-04-25 |
5 | Account | Trader | USDCHF | 3.950000e+07 | 6.694915e+05 | 5.178279 | 4.855262 | -0.255867 | 2017-02-08 | 2017-04-28 |
6 | Account | Trader | USDHUF | 1.000000e+06 | 1.000000e+06 | 0.000000 | -60.876765 | -60.876765 | 2017-04-28 | 2017-04-28 |
7 | Account | Trader | USDJPY | 7.015000e+08 | 7.454835e+05 | 11.527693 | 22.888867 | 21.912819 | 2017-02-01 | 2017-04-28 |
8 | Account | Trader | USDNOK | 1.250000e+07 | 8.928571e+05 | 4.390815 | -36.202224 | -52.705276 | 2017-03-20 | 2017-04-04 |
9 | Account | Trader | USDSEK | 1.100000e+06 | 5.500000e+05 | -3.960950 | -27.160797 | -27.160797 | 2017-03-17 | 2017-03-17 |
10 | Account | Trader | USDSGD | 1.000000e+06 | 1.000000e+06 | 17.719249 | 74.420846 | 74.420846 | 2017-03-07 | 2017-03-07 |
11 | Account | Trader | USDTRY | 4.100000e+06 | 6.833333e+05 | 22.756416 | 37.254846 | 40.770994 | 2017-02-14 | 2017-04-04 |
12 | Account | Trader | USDZAR | 4.500000e+06 | 7.500000e+05 | 5.354706 | 302.703720 | 240.909521 | 2017-02-24 | 2017-04-03 |
v1/fx/rfs/execution-history
allows the user to query all trades for a given Date.
It should be used when the user requires detailed analysis and understanding of a specific trading Date. The endpoint allows for the selection of multiple metrics (fields) such as markouts at various time points, Price, OrderStatus, spreadPnL and TradeQuantityUSD.
request = ld.delivery.endpoint_request.Definition(
method=ld.delivery.endpoint_request.RequestMethod.POST,
url="tradefeedr/v1/fx/rfs/execution-history",
header_parameters={"Content-Type": "application/json"},
body_parameters={
"options": {
#"select": ['Date', 'TradeQuantityUSD', 'LP'],
"filter": [
{"function": "eq", "var": "Date", "par": "2017-02-02"},
{"function": "eq", "var": "Symbol", "par": "EURUSD"},
],
}})
response = request.get_data()
response_json = json.loads(response.data.raw)
result_df = pd.DataFrame(response_json["result"])
display(result_df)
Date | TradeTime | TradeID | Symbol | Side | Price | TradeQuantity | LP | Account | SpreadPnL | Mid0 | Decay30s | TradeQuantityUSD | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 2017-02-02 | 1486047524757 | 133 | EURUSD | S | 1.08184 | 1000000.0 | LP5 | Account | 5.0 | 1.081845 | 100.0 | 1081845.0 |
1 | 2017-02-02 | 1486047524763 | 134 | EURUSD | S | 1.08183 | 3000000.0 | LP4 | Account | 45.0 | 1.081845 | 300.0 | 3245535.0 |
2 | 2017-02-02 | 1486047524853 | 135 | EURUSD | S | 1.08183 | 1000000.0 | LP2 | Account | 15.0 | 1.081845 | 100.0 | 1081845.0 |
3 | 2017-02-02 | 1486047524874 | 136 | EURUSD | S | 1.08184 | 1000000.0 | LP3 | Account | 5.0 | 1.081845 | 100.0 | 1081845.0 |
4 | 2017-02-02 | 1486047524956 | 137 | EURUSD | S | 1.08183 | 1000000.0 | LP6 | Account | 15.0 | 1.081845 | 100.0 | 1081845.0 |
5 | 2017-02-02 | 1486047525761 | 138 | EURUSD | S | 1.08183 | 1000000.0 | LP5 | Account | 15.0 | 1.081845 | 110.0 | 1081845.0 |
6 | 2017-02-02 | 1486047525870 | 139 | EURUSD | S | 1.08183 | 1000000.0 | LP3 | Account | 15.0 | 1.081845 | 125.0 | 1081845.0 |
7 | 2017-02-02 | 1486047578969 | 140 | EURUSD | S | NaN | 0.0 | LP3 | Account | -5.0 | 1.081825 | 0.0 | 1081825.0 |
8 | 2017-02-02 | 1486047657536 | 141 | EURUSD | S | 1.08183 | 1000000.0 | LP5 | Account | -35.0 | 1.081795 | 105.0 | 1081795.0 |
9 | 2017-02-02 | 1486047657552 | 142 | EURUSD | S | 1.08183 | 3000000.0 | LP4 | Account | 0.0 | 1.081830 | 345.0 | 3245490.0 |
10 | 2017-02-02 | 1486047657613 | 143 | EURUSD | S | 1.08183 | 1000000.0 | LP3 | Account | 0.0 | 1.081830 | 115.0 | 1081830.0 |
11 | 2017-02-02 | 1486047658083 | 144 | EURUSD | S | 1.08183 | 1000000.0 | LP2 | Account | 10.0 | 1.081840 | 120.0 | 1081840.0 |
12 | 2017-02-02 | 1486047658539 | 145 | EURUSD | S | 1.08184 | 1000000.0 | LP5 | Account | 0.0 | 1.081840 | 120.0 | 1081840.0 |
13 | 2017-02-02 | 1486047658608 | 146 | EURUSD | S | 1.08184 | 1000000.0 | LP3 | Account | 0.0 | 1.081840 | 120.0 | 1081840.0 |
14 | 2017-02-02 | 1486047658842 | 147 | EURUSD | S | 1.08184 | 4000000.0 | LP5 | Account | 0.0 | 1.081840 | 560.0 | 4327360.0 |
15 | 2017-02-02 | 1486047659544 | 148 | EURUSD | S | 1.08184 | 1100000.0 | LP5 | Account | 0.0 | 1.081840 | 132.0 | 1190024.0 |
16 | 2017-02-02 | 1486047659612 | 149 | EURUSD | S | 1.08184 | 1000000.0 | LP3 | Account | 0.0 | 1.081840 | 120.0 | 1081840.0 |
v1/fx/rfs/markouts
returns the markout curves.
Different types of markout curves are supported:
Mark-out Curves represent market dynamics before and after each trading event (fill, reject or order placement). This market dynamics is typically aggregated across different categories such as Symbol LP, and ExecVenue but it is possible to extract markout curves for each trading event as well.
request = ld.delivery.endpoint_request.Definition(
method=ld.delivery.endpoint_request.RequestMethod.POST,
url="tradefeedr/v1/fx/rfs/markouts",
header_parameters={"Content-Type": "application/json"},
body_parameters={
"options": {
"groupby": ['LP'],
#"select": ['TradeQuantityUSD', '-5s','-1s','0', '5s', '10s', '30s', '1m', '3m', '5m' ],
"filter": [
{"function": "like", "var": "ParentChild", "par": "Child"},
{"function": "gt", "var": "TradeQuantityUSD", "par": 1000000},
{"function": "eq", "var": "MarkoutType", "par": "Markouts"},
#{"function": "eq", "var": "Symbol", "par": "EURUSD"}
]}})
response = request.get_data()
response_json = json.loads(response.data.raw)
result_df = pd.DataFrame(response_json["result"])
display(result_df)
LP | TradeQuantityUSD | NumEvents | MarkoutType | -10s | -5s | -4s | -3s | -2s | -1s | ... | 15s | 20s | 30s | 45s | 1m | 2m | 3m | 4m | 5m | 10m | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | LP1 | 161030761.0 | 109 | Markouts | 109.913261 | 89.143445 | 89.938868 | 95.347051 | 89.352477 | 91.268227 | ... | 31.932227 | 27.937677 | 37.289571 | 53.075025 | 69.293095 | 102.026381 | 103.907967 | 116.571265 | 141.174070 | 173.487555 |
1 | LP2 | 81622587.0 | 72 | Markouts | 64.142784 | 48.656875 | 45.459230 | 40.276842 | 39.027187 | 39.137451 | ... | -6.444295 | -1.727463 | 0.318539 | 13.825830 | 21.942456 | 17.201121 | 11.773702 | 23.394260 | 78.795591 | 66.219415 |
2 | LP3 | 252378324.0 | 186 | Markouts | 11.639546 | 18.569470 | 16.551568 | 27.360235 | 21.520125 | 28.041842 | ... | 58.312883 | 43.233037 | 32.305920 | 46.366084 | 51.405218 | 62.368166 | 65.133765 | 91.872618 | 128.936484 | 80.782375 |
3 | LP4 | 181730409.0 | 102 | Markouts | 48.144209 | 33.550643 | 31.695989 | 27.052841 | 34.561956 | 39.062464 | ... | -18.105345 | -22.438158 | -27.450553 | -20.707481 | -9.331918 | -12.459374 | -28.473071 | -16.197177 | 0.001805 | -15.434912 |
4 | LP5 | 667755667.5 | 389 | Markouts | 45.978447 | 29.972139 | 27.187107 | 25.002938 | 25.513220 | 21.111561 | ... | 10.190266 | 9.274288 | 15.714869 | 17.950103 | 31.627192 | 45.463582 | 28.313924 | 40.045833 | 62.871901 | 43.237034 |
5 | LP6 | 311890855.0 | 253 | Markouts | 59.642118 | 40.949541 | 36.748578 | 36.278301 | 32.858453 | 31.307094 | ... | -3.839960 | 1.555755 | 0.953731 | -0.487631 | 16.002405 | 27.249569 | 32.811096 | 28.132891 | 56.186645 | 66.141752 |
6 rows × 34 columns
Normally most of the trading data available through these APIs is done via the RFQ process. RFQ is defined as a transaction which happens in several steps:
RFQ data is typically submitted to Tradefeedr by RFQ platforms so each transaction contains both winning LP quotes and losing LP quotes.
v1/fx/rfq-outrights/execution-history
allows the user to query all trading events for outrights RFQ. It should be used when the user requires detailed analysis and understanding of the execution. The endpoint allows selection of multiple metrics (fields) such as BestBid, BestAsk, NumLPs etc.
request = ld.delivery.endpoint_request.Definition(
method=ld.delivery.endpoint_request.RequestMethod.POST,
url="tradefeedr/v1/fx/rfq-outrights/execution-history",
header_parameters={"Content-Type": "application/json"},
body_parameters={
"options": {
"select":["Date","Account","TradeTime","Symbol","TradeCcy","Side","TradeQuantity","ProductType"],
"filter":[
{"function":"within","var":"Date","pars":['2010-04-02', '2027-06-30']}
]
}})
response = request.get_data()
response_json = json.loads(response.data.raw)
result_df = pd.DataFrame(response_json["result"])
display(result_df)
Date | Account | TradeTime | Symbol | TradeCcy | Side | TradeQuantity | ProductType | |
---|---|---|---|---|---|---|---|---|
0 | None | None | None |
v1/fx/rfq-outrights/execution-stats
allows the user to query across the entire execution history. The query returns a table with the metrics (fields) selected by the user as columns. The rows are defined by groupby statements. The user can review the outrights RFQs on a trade by trade level or an aggregated one by using the groupby query. The user can review the SecondBestPrice,BestBid,BestAsk in the panel of LPs and compare it to the Price that particular LP is quoting. This endpoint also displays the NumLPs that where in the stack at the time the outright RFQ was requested.
request = ld.delivery.endpoint_request.Definition(
method=ld.delivery.endpoint_request.RequestMethod.POST,
url="tradefeedr/v1/fx/rfq-outrights/execution-stats",
header_parameters={"Content-Type": "application/json"},
body_parameters={
"options": {
"select":["Date","Account","TradeTime","Symbol","TradeCcy","Side","TradeQuantity","ProductType"],
"filter":[
{"function":"within","var":"Date","pars":['2010-04-02', '2024-06-30']}
]
}})
response = request.get_data()
response_json = json.loads(response.data.raw)
result_df = pd.DataFrame(response_json["result"])
display(result_df)
Date | Account | TradeTime | Symbol | TradeCcy | Side | TradeQuantity | ProductType | |
---|---|---|---|---|---|---|---|---|
0 | 2022-10-03 | Account | 1664794445631 | AUDUSD | AUD | S | 198343000.0 | SPOT |
1 | 2022-10-03 | Account | 1664799130327 | AUDUSD | AUD | S | 151804000.0 | SPOT |
2 | 2022-10-03 | Account | 1664807452543 | AUDUSD | AUD | B | 15415000.0 | SPOT |
3 | 2022-10-03 | Account | 1664809297210 | AUDUSD | AUD | S | 173990000.0 | SPOT |
4 | 2022-10-03 | Account | 1664811949636 | AUDUSD | AUD | S | 17737000.0 | SPOT |
... | ... | ... | ... | ... | ... | ... | ... | ... |
3910 | 2023-01-24 | Account | 1674583252185 | USDJPY | USD | S | 19438000.0 | SPOT |
3911 | 2023-01-24 | Account | 1674585826952 | USDJPY | USD | B | 101010000.0 | SPOT |
3912 | 2023-01-24 | Account | 1674586797540 | USDJPY | USD | B | 155752000.0 | SPOT |
3913 | 2023-01-24 | Account | 1674586865600 | USDJPY | USD | B | 47364000.0 | SPOT |
3914 | 2023-01-24 | Account | 1674592030648 | USDJPY | USD | S | 48956000.0 | SPOT |
3915 rows × 8 columns
v1/fx/rfq-outrights/participation-report
returns a table summarizing the outrights RFQ participation rate by LP. This endpoint is used to study the hit ratios of the requested outrights RFQs, and the user can rank each LP against various performance ratios such as ActualWinRatio.
The metrics are as follows:
request = ld.delivery.endpoint_request.Definition(
method=ld.delivery.endpoint_request.RequestMethod.POST,
url="tradefeedr/v1/fx/rfq-outrights/participation-report",
header_parameters={"Content-Type": "application/json"},
body_parameters={
"options": {
"filter":[
{"function":"within","var":"date","pars":["2018-01-01","2022-12-30"]},
{"function":"in","var":"sym","pars":["EURUSD"]}
]}})
response = request.get_data()
response_json = json.loads(response.data.raw)
result_df = pd.DataFrame(response_json["result"])
display(result_df)
LP | NumberOfParticipations | NumberOfWins | ExpectedWins | ActualWinRatio | ExpectedWinRatio | VolumeParticipated | VolumeWon | ExpectedWinVolume | ActualVolumeWinRatio | ExpectedVolumeWinRatio | AverageRFQPanelSize | WinPerformanceScore | VolumePerformanceScore | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | LP_1 | 599 | 179 | 101.380952 | 29.883139 | 16.925034 | 4.991347e+10 | 1.561940e+10 | 8.490226e+09 | 31.292966 | 17.009891 | 6.245409 | 12.958105 | 14.283076 |
1 | LP_2 | 609 | 148 | 102.869048 | 24.302135 | 16.891469 | 5.012216e+10 | 1.100159e+10 | 8.456891e+09 | 21.949550 | 16.872558 | 6.251232 | 7.410665 | 5.076992 |
2 | LP_3 | 588 | 119 | 98.426191 | 20.238095 | 16.739148 | 4.844845e+10 | 9.944746e+09 | 8.119334e+09 | 20.526449 | 16.758708 | 6.301020 | 3.498947 | 3.767741 |
3 | LP_4 | 590 | 103 | 98.614286 | 17.457627 | 16.714286 | 4.795064e+10 | 9.242818e+09 | 8.034357e+09 | 19.275696 | 16.755477 | 6.305085 | 0.743341 | 2.520219 |
4 | LP_5 | 573 | 90 | 95.159524 | 15.706806 | 16.607247 | 4.828430e+10 | 7.488212e+09 | 8.117719e+09 | 15.508588 | 16.812338 | 6.342059 | -0.900440 | -1.303751 |
5 | LP_6 | 583 | 75 | 97.833333 | 12.864494 | 16.781018 | 4.969480e+10 | 6.263767e+09 | 8.453481e+09 | 12.604471 | 17.010794 | 6.293310 | -3.916524 | -4.406323 |
6 | LP_7 | 562 | 47 | 92.897619 | 8.362989 | 16.529826 | 4.604225e+10 | 3.784143e+09 | 7.603521e+09 | 8.218849 | 16.514224 | 6.364769 | -8.166836 | -8.295375 |
7 | LP_8 | 576 | 22 | 95.819048 | 3.819444 | 16.635251 | 4.828025e+10 | 2.020493e+09 | 8.089645e+09 | 4.184928 | 16.755599 | 6.328125 | -12.815807 | -12.570672 |
v1/fx/rfq-outrights/opportunity-report
generates an opportunity report which displays the OutCome of the outrights RFQ if it was WON or Lost.
From this piece of information the user can review pricing to see why the LP LOST or WON the RFQ. The user for example, can compare the price they were quoted for the outrights RFQ the AllInRate against the PriceShown (price that won the RFQ). To see how far the price was off the winning quote (MissedByPIPS column). They can also review the volume of the LOST trades that where traded away with another LP.
This can be used for broker reviews
request = ld.delivery.endpoint_request.Definition(
method=ld.delivery.endpoint_request.RequestMethod.POST,
url="tradefeedr/v1/fx/rfq-outrights/participation-report",
header_parameters={"Content-Type": "application/json"},
body_parameters={
"options": {
"filter":[
{"function":"within","var":"date","pars":["2014-01-01","2022-11-30"]},
{"function":"in","var":"LP","pars":["LP_1"]},
],
}})
response = request.get_data()
response_json = json.loads(response.data.raw)
result_df = pd.DataFrame(response_json["result"])
display(result_df)
LP | NumberOfParticipations | NumberOfWins | ExpectedWins | ActualWinRatio | ExpectedWinRatio | VolumeParticipated | VolumeWon | ExpectedWinVolume | ActualVolumeWinRatio | ExpectedVolumeWinRatio | AverageRFQPanelSize | WinPerformanceScore | VolumePerformanceScore | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | LP_1 | 1590 | 458 | 268.232143 | 28.805031 | 16.869946 | 1.267963e+11 | 3.646889e+10 | 2.133657e+10 | 28.761786 | 16.827434 | 6.266667 | 11.935085 | 11.934351 |
v1/fx/rfq-outrights/markouts
calculated spot markouts:
request = ld.delivery.endpoint_request.Definition(
method=ld.delivery.endpoint_request.RequestMethod.POST,
url="tradefeedr/v1/fx/rfq-outrights/markouts",
header_parameters={"Content-Type": "application/json"},
body_parameters={
"options": {
"groupby": ['LP'],
#"select": ['TradeQuantityUSD', '-5s','-1s','0', '5s', '10s', '30s', '1m', '3m', '5m' ],
"filter": [
{"function": "like", "var": "ParentChild", "par": "Child"},
{"function": "gt", "var": "TradeQuantityUSD", "par": 1000000},
{"function": "eq", "var": "MarkoutType", "par": "Markouts"},
#{"function": "eq", "var": "Symbol", "par": "EURUSD"}
]}})
response = request.get_data()
response_json = json.loads(response.data.raw)
result_df = pd.DataFrame(response_json["result"])
display(result_df)
LP | TradeQuantityUSD | NumEvents | MarkoutType | -10s | -5s | -1s | -500ms | -250ms | 0 | 250ms | 500ms | 1s | 5s | 10s | 30s | 1m | 5m | 10m | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | LP_1 | 6.795184e+10 | 830 | Markouts | 593.186789 | 590.003976 | 589.603810 | 589.643168 | 591.477387 | 594.208431 | 594.040650 | 593.918327 | 594.472041 | 594.589662 | 593.579704 | 576.905651 | 573.960616 | 584.717739 | 570.788533 |
1 | LP_2 | 6.055871e+10 | 762 | Markouts | 595.230444 | 596.331696 | 593.099695 | 595.999219 | 593.651541 | 598.027609 | 597.562737 | 597.598852 | 595.778845 | 591.094368 | 591.587332 | 596.551413 | 601.474633 | 605.164200 | 604.887628 |
2 | LP_3 | 5.077992e+10 | 643 | Markouts | 587.418613 | 587.817713 | 581.713291 | 581.837155 | 581.304711 | 580.235890 | 579.869606 | 579.767614 | 579.888765 | 584.230108 | 581.053980 | 584.546433 | 573.642363 | 590.330978 | 559.320602 |
3 | LP_4 | 4.808943e+10 | 550 | Markouts | 603.598182 | 603.386761 | 610.608212 | 611.748943 | 610.227001 | 605.487733 | 605.259727 | 604.916748 | 604.762841 | 607.890135 | 609.128761 | 620.610582 | 618.467280 | 614.472077 | 620.538398 |
4 | LP_5 | 3.660549e+10 | 446 | Markouts | 578.127776 | 578.640099 | 575.657885 | 578.233227 | 580.444731 | 582.448699 | 582.802673 | 584.311922 | 582.800084 | 584.762764 | 585.928090 | 591.314067 | 568.128846 | 529.480543 | 515.734088 |
5 | LP_6 | 2.664889e+10 | 344 | Markouts | 553.438796 | 559.604854 | 565.129746 | 568.497119 | 567.597147 | 565.165497 | 566.322792 | 566.165012 | 566.091338 | 569.667760 | 573.146305 | 576.820835 | 602.091171 | 589.800526 | 561.342388 |
6 | LP_7 | 1.672842e+10 | 210 | Markouts | 597.884673 | 595.888606 | 586.738065 | 593.387286 | 593.294213 | 589.933237 | 590.903861 | 592.485290 | 583.007531 | 578.892808 | 572.049758 | 574.152782 | 596.059845 | 640.919256 | 611.092583 |
7 | LP_8 | 1.096962e+10 | 130 | Markouts | 608.926452 | 599.984537 | 605.400173 | 604.658613 | 606.295698 | 602.683533 | 603.408878 | 603.119425 | 606.877821 | 604.445919 | 618.193724 | 606.405895 | 616.128002 | 672.661017 | 618.851817 |
v1/fx/rfq-swaps/execution-history
allows the user to query all trading events for outrights RFQ . It should be used when the user requires detailed analysis and understanding of the execution. The endpoint allows selection of multiple metrics (fields) such as BestBid, BestAsk, NumLPs etc.
request = ld.delivery.endpoint_request.Definition(
method=ld.delivery.endpoint_request.RequestMethod.POST,
url="tradefeedr/v1/fx/rfq-swaps/execution-history",
header_parameters={"Content-Type": "application/json"},
body_parameters={
"options": {
"select": ["Date","Account","TradeTime","Symbol","TradeCcy","Side","TradeQuantity","ProductType"],
"filter":[
{"function":"within","var":"Date","pars":['2010-04-02', '2024-06-30']}
]}})
response = request.get_data()
response_json = json.loads(response.data.raw)
result_df = pd.DataFrame(response_json["result"])
display(result_df)
Date | Account | TradeTime | Symbol | TradeCcy | Side | ProductType | |
---|---|---|---|---|---|---|---|
0 | 2023-01-02 | Account | 1672645732416 | AUDUSD | AUD | SB | SWAP |
1 | 2023-01-02 | Account | 1672646939624 | AUDUSD | AUD | BS | SWAP |
2 | 2023-01-02 | Account | 1672649530215 | AUDUSD | AUD | BS | SWAP |
3 | 2023-01-02 | Account | 1672654045778 | AUDUSD | AUD | SB | SWAP |
4 | 2023-01-02 | Account | 1672655016124 | AUDUSD | AUD | BS | SWAP |
... | ... | ... | ... | ... | ... | ... | ... |
75 | 2023-01-24 | Account | 1674574109492 | USDJPY | USD | SB | SWAP |
76 | 2023-01-24 | Account | 1674574402146 | USDJPY | USD | BS | SWAP |
77 | 2023-01-24 | Account | 1674589500545 | USDJPY | USD | BS | SWAP |
78 | 2023-01-24 | Account | 1674595600030 | USDJPY | USD | BS | SWAP |
79 | 2023-01-24 | Account | 1674599708650 | USDJPY | USD | SB | SWAP |
80 rows × 7 columns
v1/fx/rfq-outrights/execution-stats
allows the user to query across the entire execution history. The query returns a table with the metrics (fields) selected by the user as columns. The rows are defined by groupby statements. The user can review the outrights RFQs on a trade by trade level or an aggregated one by using the groupby query. The user can review the SecondBestPrice,BestBid,BestAsk in the panel of LPs and compare it to the Price that particular LP is quoting. This endpoint also displays the NumLPs that where in the stack at the time the outright RFQ was requested.
request = ld.delivery.endpoint_request.Definition(
method=ld.delivery.endpoint_request.RequestMethod.POST,
url="tradefeedr/v1/fx/rfq-outrights/execution-stats",
header_parameters={"Content-Type": "application/json"},
body_parameters={
"options": {
"groupby":[
"LP",
],
"select":[
{'var':"TradeQuantity", 'function':"sum"},
],
"filter":[{"function":"within","var":"date","pars":["2022-01-01","2024-11-30"]}]
}})
response = request.get_data()
response_json = json.loads(response.data.raw)
result_df = pd.DataFrame(response_json["result"])
display(result_df)
LP | TradeQuantity | |
---|---|---|
0 | LP_1 | 7.024957e+10 |
1 | LP_2 | 6.320382e+10 |
2 | LP_3 | 5.276552e+10 |
3 | LP_4 | 4.818891e+10 |
4 | LP_5 | 3.764970e+10 |
5 | LP_6 | 2.766302e+10 |
6 | LP_7 | 1.714921e+10 |
7 | LP_8 | 1.083411e+10 |
v1/fx/rfq-swaps/participation-report
returns a table summarizing the outrights RFQ participation rate by LP. This endpoint is used to study the hit ratios of the requested outrights RFQs, and the user can rank each LP against various performance ratios such as ActualWinRatio.
The metrics are as follows:
request = ld.delivery.endpoint_request.Definition(
method=ld.delivery.endpoint_request.RequestMethod.POST,
url="tradefeedr/v1/fx/rfq-swaps/participation-report",
header_parameters={"Content-Type": "application/json"},
body_parameters={
"options": {
"filter":[
{"function":"within","var":"date","pars":["2022-01-01", "2023-12-30"]},
{"function":"in","var":"sym","pars":["EURUSD"]}
]}})
response = request.get_data()
response_json = json.loads(response.data.raw)
result_df = pd.DataFrame(response_json["result"])
display(result_df)
LP | NumberOfParticipations | NumberOfWins | ExpectedWins | ActualWinRatio | ExpectedWinRatio | VolumeParticipated | VolumeWon | ExpectedWinVolume | ActualVolumeWinRatio | ExpectedVolumeWinRatio | AverageRFQPanelSize | WinPerformanceScore | VolumePerformanceScore | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | LP_8 | 17 | 4 | 2.982143 | 23.529412 | 17.542017 | 2.272287e+09 | 5.046232e+08 | 4.022288e+08 | 22.207726 | 17.701497 | 6.000000 | 5.987395 | 4.506228 |
1 | LP_1 | 14 | 3 | 2.265476 | 21.428571 | 16.181973 | 1.742043e+09 | 2.865584e+08 | 2.829924e+08 | 16.449562 | 16.244861 | 6.357143 | 5.246599 | 0.204702 |
2 | LP_2 | 15 | 3 | 2.622619 | 20.000000 | 17.484127 | 2.228001e+09 | 4.106794e+08 | 3.952985e+08 | 18.432640 | 17.742296 | 6.000000 | 2.515873 | 0.690344 |
3 | LP_3 | 13 | 3 | 2.158333 | 23.076923 | 16.602564 | 1.418802e+09 | 3.283962e+08 | 2.387114e+08 | 23.146013 | 16.824854 | 6.307692 | 6.474359 | 6.321160 |
4 | LP_5 | 15 | 3 | 2.696429 | 20.000000 | 17.976191 | 2.019358e+09 | 3.284386e+08 | 3.484131e+08 | 16.264504 | 17.253656 | 5.866667 | 2.023810 | -0.989152 |
5 | LP_4 | 14 | 2 | 2.291667 | 14.285714 | 16.369048 | 1.807973e+09 | 3.997088e+08 | 3.052461e+08 | 22.108116 | 16.883333 | 6.357143 | -2.083333 | 5.224783 |
6 | LP_7 | 16 | 2 | 2.741667 | 12.500000 | 17.135417 | 2.044155e+09 | 3.427811e+08 | 3.532352e+08 | 16.768836 | 17.280251 | 6.125000 | -4.635417 | -0.511414 |
7 | LP_6 | 14 | 0 | 2.241667 | 0.000000 | 16.011905 | 1.712825e+09 | 0.000000e+00 | 2.750601e+08 | 0.000000 | 16.058857 | 6.428571 | -16.011905 | -16.058857 |
v1/fx/rfq-swaps/opportunity-report
generates an opportunity report which displays the outcome of the outrights RFQ if it was WON or Lost.
From this piece of information, the user can review pricing to see why the LP LOST or WON the RFQ. The user, for example, can compare the price they were quoted for the outrights RFQ (the AllInRate) against the PriceShown (price that won the RFQ) to see how far the price was off the winning quote (MissedByPIPS column). They can also review the volume of the LOST trades that were traded away with another LP.
This can be used for broker reviews.
request = ld.delivery.endpoint_request.Definition(
method=ld.delivery.endpoint_request.RequestMethod.POST,
url="tradefeedr/v1/fx/rfq-swaps/opportunity-report",
header_parameters={"Content-Type": "application/json"},
body_parameters={
"options": {
"filter":[
{"function":"within","var":"date","pars":["2022-01-01","2023-11-30"]},
{"function":"in","var":"LP","pars":["LP_1"]},
],
}})
response = request.get_data()
response_json = json.loads(response.data.raw)
result_df = pd.DataFrame(response_json["result"])
display(result_df)
LP | OutCome | Symbol | Side | NearTradeQuantity | FarTradeQuantity | TradeCcy | TradeTime | FarPrice | NearPrice | NearForwardPoints | FarForwardPoints | NearPriceShown | FarPriceShown | NearFPShown | FarFPShown | ProductType | ShownFP | WinningFP | MissedFP | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | LP_1 | WON | AUDUSD | SB | 5.218147e+07 | 5.218147e+07 | AUD | 1672645732416 | 0.68070 | 0.68018 | -1.0 | 2.0 | 0.680180 | 0.680700 | -1.0 | 2.0 | SWAP | 3.0 | 3.0 | 0.0 |
1 | LP_1 | LOST | AUDUSD | BS | 9.213931e+07 | 9.213931e+07 | AUD | 1672649530215 | 0.67986 | 0.68073 | 1.0 | 0.0 | 0.680882 | 0.679783 | 1.0 | 0.0 | SWAP | 1.0 | 1.0 | 0.0 |
2 | LP_1 | LOST | AUDUSD | SB | 9.011011e+07 | 9.011011e+07 | AUD | 1672654045778 | 0.68049 | 0.67970 | -1.0 | 2.0 | 0.679584 | 0.680521 | -1.0 | 2.0 | SWAP | 3.0 | 3.0 | 0.0 |
3 | LP_1 | LOST | AUDUSD | SB | 1.178356e+08 | 1.178356e+08 | AUD | 1672664292792 | 0.68147 | 0.68050 | -1.0 | 2.0 | 0.680402 | 0.681625 | -1.0 | 2.0 | SWAP | 3.0 | 3.0 | 0.0 |
4 | LP_1 | LOST | AUDUSD | SB | 2.150120e+07 | 2.150120e+07 | AUD | 1672668604163 | 0.68103 | 0.68071 | -1.0 | 2.0 | 0.680602 | 0.681109 | -1.0 | 2.0 | SWAP | 3.0 | 3.0 | 0.0 |
... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
56 | LP_1 | WON | USDJPY | SB | 1.140482e+08 | 1.140482e+08 | USD | 1674574109492 | 130.51296 | 130.40804 | -1.0 | -2.0 | 130.408040 | 130.512960 | -1.0 | -2.0 | SWAP | -1.0 | -1.0 | 0.0 |
57 | LP_1 | LOST | USDJPY | BS | 1.244412e+08 | 1.244412e+08 | USD | 1674574402146 | 130.35195 | 130.47305 | 1.0 | -4.0 | 130.502762 | 130.325658 | 1.0 | -4.0 | SWAP | 5.0 | 5.0 | 0.0 |
58 | LP_1 | LOST | USDJPY | BS | 1.518552e+08 | 1.518552e+08 | USD | 1674589500545 | 129.98731 | 130.13269 | 1.0 | -4.0 | 130.134600 | 129.984783 | 1.0 | -4.0 | SWAP | 5.0 | 5.0 | 0.0 |
59 | LP_1 | LOST | USDJPY | BS | 1.967409e+07 | 1.967409e+07 | USD | 1674595600030 | 130.12675 | 130.16025 | 1.0 | -4.0 | 130.173786 | 130.117968 | 1.0 | -4.0 | SWAP | 5.0 | 5.0 | 0.0 |
60 | LP_1 | LOST | USDJPY | SB | 1.186889e+08 | 1.186889e+08 | USD | 1674599708650 | 130.23289 | 130.12811 | -1.0 | -2.0 | 130.086936 | 130.266149 | -1.0 | -2.0 | SWAP | -1.0 | -1.0 | 0.0 |
61 rows × 20 columns
v1/fx/rfq-swaps/markouts
calculated spots markouts around swap trades
request = ld.delivery.endpoint_request.Definition(
method=ld.delivery.endpoint_request.RequestMethod.POST,
url="tradefeedr/v1/fx/rfq-swaps/markouts",
header_parameters={"Content-Type": "application/json"},
body_parameters={
"options": {
"groupby": ['LP'],
# "select": ['TradeQuantityUSD', '-5s','-1s','0', '5s', '10s', '30s', '1m', '3m', '5m' ],
"filter": [
{"function": "like", "var": "ParentChild", "par": "Child"},
{"function": "gt", "var": "NearTradeQuantityUSD", "par": 1000000},
{"function": "eq", "var": "MarkoutType", "par": "Markouts"},
{"function": "eq", "var": "Symbol", "par": "EURUSD"}
]}})
response = request.get_data()
response_json = json.loads(response.data.raw)
result_df = pd.DataFrame(response_json["result"])
display(result_df)
LP | TradeQuantityUSD | NumEvents | MarkoutType | -10s | -5s | -1s | -500ms | -250ms | 0 | 250ms | 500ms | 1s | 5s | 10s | 30s | 1m | 5m | 10m | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | LP_1 | 2.865584e+08 | 3 | Markouts | -6.385663 | -4.080822 | -1.265512 | -1.265512 | -1.265512 | -0.0 | -0.000000 | -0.000000 | -5.630619 | -14.464805 | -43.116290 | -112.099465 | -76.811434 | -52.714759 | -20.213749 |
1 | LP_2 | 4.106794e+08 | 3 | Markouts | -191.867501 | -44.156726 | -28.350698 | 18.225449 | 14.175349 | -0.0 | -0.000000 | -2.025050 | -2.025050 | 39.750706 | 42.525209 | -24.277214 | -38.201549 | 80.688221 | -333.946071 |
2 | LP_3 | 3.283962e+08 | 3 | Markouts | -28.748900 | 7.187225 | -5.390419 | -1.796806 | -1.796806 | -0.0 | -0.000000 | 3.593612 | -14.374450 | -20.430195 | -12.011904 | 93.302559 | 130.634487 | -118.406269 | 239.940843 |
3 | LP_4 | 3.997088e+08 | 2 | Markouts | -0.481443 | -0.481443 | -9.489488 | -9.489488 | -9.489488 | 0.0 | 0.000000 | -12.492170 | -12.492170 | -24.984340 | -12.492170 | 2.521239 | 144.679856 | 87.983647 | -33.624969 |
4 | LP_5 | 3.284386e+08 | 3 | Markouts | -14.248870 | -1.301517 | -4.182143 | -1.468073 | -1.468073 | 0.0 | -2.035553 | -2.714071 | -2.035553 | -0.678518 | -2.035553 | 16.050055 | 57.384111 | 54.035714 | 13.490306 |
5 | LP_7 | 3.427811e+08 | 2 | Markouts | 15.153974 | 15.153974 | 6.298715 | 6.298715 | 6.298715 | 0.0 | 0.000000 | 0.000000 | 0.000000 | 18.105727 | 14.758765 | 6.786569 | 8.064842 | 146.216731 | -32.771845 |
6 | LP_8 | 5.046232e+08 | 4 | Markouts | 64.632585 | 57.909984 | 49.154616 | 28.182710 | 7.452258 | 0.0 | -11.488866 | -11.150315 | -15.103242 | -6.156645 | -56.381038 | -72.883450 | -120.038463 | 146.060927 | 12.037569 |
request = ld.delivery.endpoint_request.Definition(
method=ld.delivery.endpoint_request.RequestMethod.POST,
url="tradefeedr/v1/fx/rfq-swaps/execution-stats",
header_parameters={"Content-Type": "application/json"},
body_parameters={
"options": {
"groupby":[
"LP",
],
"select":[
{'var':"NearTradeQuantity", 'function':"sum"},
{'var':"FarTradeQuantity", 'function':"sum"},
],
"filter":[{"function":"within","var":"date","pars":["2022-01-01","2025-11-30"]}]
}})
response = request.get_data()
response_json = json.loads(response.data.raw)
result_df = pd.DataFrame(response_json["result"])
display(result_df)
LP | NearTradeQuantity | FarTradeQuantity | |
---|---|---|---|
0 | LP_1 | 1.401326e+09 | 1.401326e+09 |
1 | LP_2 | 1.406658e+09 | 1.406658e+09 |
2 | LP_3 | 1.138606e+09 | 1.138606e+09 |
3 | LP_4 | 1.405399e+09 | 1.405399e+09 |
4 | LP_5 | 6.414252e+08 | 6.414252e+08 |
5 | LP_6 | 2.412019e+08 | 2.412019e+08 |
6 | LP_7 | 5.236638e+08 | 5.236638e+08 |
7 | LP_8 | 7.882481e+08 | 7.882481e+08 |
v1/fx/stats/risk-transfer-cost
attempts to create an approximation of the fair price of immediate execution. This endpoint is used when the user wants to estimate the "fair" spread they would pay if they were to execute the full amount immediately.
There are different approaches to estimate the risk transfer costs. These approaches range from model-driven to purely empirical (measure realized transaction costs and assume those are the best forecast for the future).
Tradefeedr is not a trading company, does not have live market feeds, and hence lacks the data to estimate this risk transfer reliably and consistently with the market. Therefore, Tradefeedr relies on the combined information provided by its member banks and distills this information into a factor model to project fair risk transfer cost for each market environment.
request = ld.delivery.endpoint_request.Definition(
method=ld.delivery.endpoint_request.RequestMethod.POST,
url="tradefeedr/v1/fx/stats/risk-transfer-cost",
header_parameters={"Content-Type": "application/json"},
body_parameters={
"options": {
"select":[
"Date",
"Symbol",
"ArrivalTime",
"OrderQuantity",
"VolatilityRollingPct",
#"VolatilityIntegratedPct",
#"VolatilityRollingEMAPct",
"RiskTransferCostBPS"
],
"filter":[
{"var":"Symbol", "pars":["USDZAR", "EURGBP", "EURUSD"]},
{"var":"ArrivalTime", "pars": ["2022.01.20D11:38:48.725717000", "2022.01.19D07:52:08.725717000", "2022.01.18D04:05:28.725717000"]},
{"var":"OrderQuantity", "pars": [100, 200, 300]},
],
}})
response = request.get_data()
response_json = json.loads(response.data.raw)
result_df = pd.DataFrame(response_json["result"])
display(result_df)
Date | Symbol | ArrivalTime | OrderQuantity | VolatilityRollingPct | RiskTransferCostBPS | |
---|---|---|---|---|---|---|
0 | 2022-01-20 | USDZAR | 1642678728725 | 100.0 | 0.119888 | 28.750017 |
1 | 2022-01-19 | EURGBP | 1642578728725 | 200.0 | 0.043202 | 5.201235 |
2 | 2022-01-18 | EURUSD | 1642478728725 | 300.0 | 0.049048 | 3.488076 |
v1/fx/stats/intraday-volatility
attempts to create an approximation of fair price of immediate execution.
request = ld.delivery.endpoint_request.Definition(
method=ld.delivery.endpoint_request.RequestMethod.POST,
url="tradefeedr/v1/fx/stats/intraday-volatility",
header_parameters={"Content-Type": "application/json"},
body_parameters={
"options": {
"filter":[
{"var":"Symbol", "pars":["EURUSD"]},
{"var":"Date", "pars": ["2024-08-01"]},
],
}})
response = request.get_data()
response_json = json.loads(response.data.raw)
result_df = pd.DataFrame(response_json["result"])
display(result_df)
Time | Volatility | Symbol | |
---|---|---|---|
0 | 1722470400000 | 1.801016 | EURUSD |
1 | 1722470460000 | 1.809290 | EURUSD |
2 | 1722470520000 | 1.817674 | EURUSD |
3 | 1722470580000 | 1.826166 | EURUSD |
4 | 1722470640000 | 1.834764 | EURUSD |
... | ... | ... | ... |
1435 | 1722556500000 | 1.761356 | EURUSD |
1436 | 1722556560000 | 1.769053 | EURUSD |
1437 | 1722556620000 | 1.776870 | EURUSD |
1438 | 1722556680000 | 1.784803 | EURUSD |
1439 | 1722556740000 | 1.792853 | EURUSD |
1440 rows × 3 columns
Both the Pre- and Post-Trade APIs rely on basically the same Tradefeedr proprietary algo forecasting methodology. For any currency pair, order quantity, and date/time, we create the tradefeedr/Global forecast of expected performance, duration, and risk. This is modeled off the full set of liquidity-seeking algorithms in our database on a rolling 12-month timeframe. Each historical execution is normalized by a proprietary Cost of Liquidity measure which allows us to compare like-for-like across executions run at varying times, currencies, sizes, and market conditions.
The forecasts work as well in the past as they do in the present, so today's forecasts in pre-trade match the future TCA in post-trade.
In addition, we model the fastest and slowest third of algos to create the tradefeedr/Fast and tradefeedr/Slow forecasts. Taken together with the tradefeedr/Global forecast, this forms a curve of forecast performance against duration and risk which supports reasoning about optimal algo duration. This is also useful for making the "RFQ against Algo" decision or for optimizing the time settings for TWAP algos.
Finally, where LPs have permissioned the publication of their algo forecasts, additional forecast models for these individual algos are given. Thus, all the information necessary for the creation of algo selection tools is available.
There are two relevant APIs with two separate 'API end-points':
v1/fx/algo/pre-trade-forecast
v1/fx/algo/post-trade-forecast
Conceptually, each API call has two components:
v1/fx/algo/pre-trade-forecast
. Parsing the endpoint name, one can conclude that it is API version 1 (v1), fx space, algo sub-space (meaning algo execution), and the actual function name is pre-trade-forecast.All API end-points return a JSON dictionary which can be translated into the Python pandas (examples below).
data = {
"ArrivalTime": ["2023-08-10 11:52", "2023-08-10 12:30",],
"Symbol": ['EURUSD', 'USDJPY'],
"OrderQuantityUSD": [50e6, 30e6]
}
request = ld.delivery.endpoint_request.Definition(
method=ld.delivery.endpoint_request.RequestMethod.POST,
url="tradefeedr/v1/fx/algo/pre-trade-forecast",
header_parameters={"Content-Type": "application/json"},
body_parameters={
"options": {
"select": [
#'ArrivalTime',
#'Symbol',
#'OrderQuantityUSD',
#'CostOfLiquidity',
#'RiskTransferBPS',
#'ArrivalVolatilityPct',
#'ForecastModel',
#'ForecastPerfBPS',
#'ForecastPerfStdErr',
#'ForecastDurationMins',
#'ForecastDurationStdErr',
#'ForecastRiskBPS',
#'AlphaBPS',
#'InformationRatio',
#'RunsToBeatRT95',
#'RunsToBeatRT85',
],
"filter": [
{"function": "in", "var": "ForecastModel", "pars": ["tradefeedr/Global", "tradefeedr/Fast", "tradefeedr/Slow"]},
#{"function": "like", "var": "ForecastModel", "pars": "*"} # Returns a row for each forecast model available
],
"data" : data
}})
response = request.get_data()
response_json = json.loads(response.data.raw)
result_df = pd.DataFrame(response_json["result"])
display(result_df)
ArrivalTime | Symbol | OrderQuantityUSD | RawCostOfLiquidity | CostOfLiquidity | TimeOfLiquidity | RiskTransferBPS | ArrivalVolatilityPct | ForecastModel | ForecastPerfBPS | ForecastPerfStdErr | ForecastDurationMins | ForecastDurationStdErr | ForecastRiskBPS | AlphaBPS | InformationRatio | RunsToBeatRT95 | RunsToBeatRT85 | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 1691668320000 | EURUSD | 50000000.0 | 0.245343 | 0.245343 | 0.245343 | -1.360694 | 7.851990 | tradefeedr/Fast | -1.333972 | 0.072994 | 3.578593 | 0.495002 | 1.401546 | 0.026723 | 0.019067 | 7443.621765 | 2952.378292 |
1 | 1691670600000 | USDJPY | 30000000.0 | 0.436924 | 0.436924 | 0.436924 | -1.441751 | 13.798835 | tradefeedr/Fast | -1.194812 | 0.057649 | 3.686780 | 0.475561 | 2.499986 | 0.246939 | 0.098776 | 277.349702 | 110.005756 |
2 | 1691668320000 | EURUSD | 50000000.0 | 0.245343 | 0.245343 | 0.245343 | -1.360694 | 7.851990 | tradefeedr/Global | -1.145207 | 0.038005 | 4.946555 | 0.201189 | 1.647793 | 0.215487 | 0.130773 | 158.231702 | 62.759750 |
3 | 1691670600000 | USDJPY | 30000000.0 | 0.436924 | 0.436924 | 0.436924 | -1.441751 | 13.798835 | tradefeedr/Global | -1.032183 | 0.029008 | 5.148461 | 0.193537 | 2.954286 | 0.409568 | 0.138635 | 140.793989 | 55.843396 |
4 | 1691668320000 | EURUSD | 50000000.0 | 0.245343 | 0.245343 | 0.245343 | -1.360694 | 7.851990 | tradefeedr/Slow | -1.095883 | 0.066236 | 7.091961 | 0.299572 | 1.973033 | 0.264811 | 0.134215 | 150.220172 | 59.582121 |
5 | 1691670600000 | USDJPY | 30000000.0 | 0.436924 | 0.436924 | 0.436924 | -1.441751 | 13.798835 | tradefeedr/Slow | -0.989566 | 0.047695 | 7.440875 | 0.292467 | 3.551615 | 0.452185 | 0.127318 | 166.936514 | 66.212357 |
Column | Description |
---|---|
ArrivalTime | Time of receipt of order by LP in GMT. |
Symbol | Currency pair. |
OrderQuantityUSD | Order quantity converted to USD. |
CostOfLiquidity | Tradefeedr model of cost of liquidity for the given Symbol, ArrivalTime, and ArrivalVolatilityPct. Based on the Tradefeedr risk transfer model for a regular market size, one can expect EURUSD in London time in quiet markets to be around 0.3, GBPUSD to be around 1.0, and EM currencies to range up to 5.0. |
RiskTransferBPS | Tradefeedr modeled risk transfer cost in BPS expressed as a negative number. |
ArrivalVolatilityPct | Tradefeedr modeled annualized intraday volatility for the given Symbol and ArrivalTime. |
ForecastModel | The specific Tradefeedr forecast model the statistics are derived for. |
ForecastPerfBPS | Arrival mid-price performance predicted by the selected Tradefeedr forecast. Effectively the cost of execution from arrival mid-price expressed as a negative number in BPS. |
ForecastPerfStdErr | One standard deviation of model uncertainty for the mean ForecastPerfBPS (not to be confused with the uncertainty of an actual outcome, which is ForecastRiskBPS below). |
ForecastDurationMins | Total execution duration in minutes predicted by the selected Tradefeedr forecast if the algo is allowed to run continuously. |
ForecastDurationStdErr | One standard deviation of model uncertainty for the mean ForecastDurationMins (again not to be confused with the uncertainty of actual outcomes). |
ForecastRiskBPS | One standard deviation of the forecast performance outcome. |
AlphaBPS | Performance improvement of the algo over risk transfer given by $$ForecastPerfBPS - RiskTransferBPS$$. |
InformationRatio | Similar to a Sharpe ratio, this is the risk-adjusted outperformance of the algo against risk transfer given by $$\frac{AlphaBPS}{ForecastRiskBPS}$$. |
RunsToBeatRT95 | A statistic showing how many times an algo with the given expected performance and risk would need to be run in the same conditions to beat the risk transfer price 95% of the time. |
RunsToBeatRT85 | As for RunsToBeatRT95 but to beat the risk transfer price 85% of the time. |
request = ld.delivery.endpoint_request.Definition(
method=ld.delivery.endpoint_request.RequestMethod.POST,
url="tradefeedr/v1/fx/algo/post-trade-forecast",
header_parameters={"Content-Type": "application/json"},
body_parameters={
"options": {
"groupby": [
#'Account',
#'Trader',
#'LP',
#'AlgoName',
#'Symbol',
#'ForecastModel',
],
"select": [
#'Count',
#'ArrivalTime',
#'ParentOrderID',
#'Account',
#'Trader',
#'LP',
#'AlgoName',
#'AlgoUrgency',
#'OrderQuantityUSD',
#'TradeQuantityUSD',
#'Side',
#'TradeCcy',
#'Symbol',
#'FillPct',
#'ForecastModel',
#'CostOfLiquidity',
#'RiskTransferBPS',
#'ArrivalMidPerfBPS',
#'ArrivalMidPerfTradeUserBPS',
#'ActiveArrivalMidPerfBPS',
#'ForecastPerfBPS',
#'ForecastPerfStdErr',
#'ActualToForecastPerfBPS',
#'OpportunityCostUSD',
#'DurationMins',
#'ActiveDurationMins',
#'ForecastDurationMins',
#'ForecastDurationStdErr',
#'SpeedPct',
#'ArrivalVolatilityPct',
#'AssumedRisk',
#'ForecastRiskBPS',
#'AlphaBPS',
#'InformationRatio',
#'RunsToBeatRT95',
#'RunsToBeatRT85',
#'ZScore',
],
"filter": [
{"function": "in", "var": "ForecastModel", "pars": ["tradefeedr/Global", "tradefeedr/Fast", "tradefeedr/Slow"]},
#{"function": "within", "var": "Date", "pars": ["2022-07-27", "2022-08-27"]},
#{"function": "within", "var": "ZScore", "pars": [1.0, 4.0]},
],
}})
response = request.get_data()
response_json = json.loads(response.data.raw)
result_df = pd.DataFrame(response_json["result"])
display(result_df)
Count | Date | SubmissionTime | ArrivalTime | ParentOrderID | Account | Trader | LP | AlgoName | AlgoUrgency | ... | ForecastDurationStdErr | SpeedPct | ArrivalVolatilityPct | AssumedRisk | ForecastRiskBPS | AlphaBPS | InformationRatio | RunsToBeatRT95 | RunsToBeatRT85 | ZScore | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 1 | 2022-03-01 | 1646121600000 | 1646121600000 | lim_20220301-A00 | Algo | Algo | LP2 | MidTracker | ... | 0.652041 | 6.296678 | 5.674559 | 10.839567 | 1.798190 | 0.673311 | 0.374438 | 19.300608 | 7.655238 | 0.359632 | |
1 | 1 | 2022-03-01 | 1646121600000 | 1646121600000 | lim_20220301-A01 | Algo | Algo | LP2 | AggressivePOL | ... | 0.700470 | 5.605190 | 12.348873 | 20.847926 | 2.985027 | 0.527149 | 0.176598 | 86.768433 | 34.415134 | 0.593807 | |
2 | 1 | 2022-03-01 | 1646121600000 | 1646121600000 | lim_20220301-A02 | Algo | Algo | LP1 | PassiveMidTracker | ... | 0.664805 | 6.202077 | 12.348873 | 20.847926 | 3.886587 | 1.194799 | 0.307416 | 28.633779 | 11.357072 | -0.963304 | |
3 | 1 | 2022-03-01 | 1646121600000 | 1646121600000 | lim_20220301-A00 | Algo | Algo | LP2 | MidTracker | ... | 0.368151 | 7.766871 | 5.674559 | 10.839567 | 1.997114 | 0.967460 | 0.484429 | 11.531108 | 4.573606 | 0.332508 | |
4 | 1 | 2022-03-01 | 1646121600000 | 1646121600000 | lim_20220301-A01 | Algo | Algo | LP2 | AggressivePOL | ... | 0.375449 | 6.711268 | 12.348873 | 20.847926 | 3.266295 | 0.742581 | 0.227347 | 52.354658 | 20.765531 | 0.583477 | |
... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
4930 | 1 | 2022-08-09 | 1660062870000 | 1660062870000 | 20220809-A05 | Algo | Algo | LP3 | Sweep | ... | 0.383509 | 8846.014523 | 9.175670 | 0.611315 | 3.641649 | 1.886060 | 0.517914 | 10.088276 | 4.001333 | 3.213584 | |
4931 | 1 | 2022-08-09 | 1660062870000 | 1660062870000 | 20220809-A05 | Algo | Algo | LP3 | Sweep | ... | 2.368688 | 27377.037545 | 9.175670 | 0.611315 | 6.406450 | 3.086242 | 0.481740 | 11.660220 | 4.624816 | 1.192153 | |
4932 | 1 | 2022-08-09 | 1660069952000 | 1660069952000 | 20220809-A06 | Algo | Algo | LP2 | MidTracker | ... | 0.479734 | 259.701428 | 11.594530 | 4.521770 | 3.436795 | 1.022487 | 0.297512 | 30.571996 | 12.125831 | 0.279688 | |
4933 | 1 | 2022-08-09 | 1660069952000 | 1660069952000 | 20220809-A06 | Algo | Algo | LP2 | MidTracker | ... | 0.271000 | 355.227601 | 11.594530 | 4.521770 | 4.019479 | 1.308198 | 0.325464 | 25.546098 | 10.132399 | 0.216531 | |
4934 | 1 | 2022-08-09 | 1660069952000 | 1660069952000 | 20220809-A06 | Algo | Algo | LP2 | MidTracker | ... | 1.144178 | 1069.910844 | 11.594530 | 4.521770 | 6.975739 | 1.956393 | 0.280457 | 34.403294 | 13.645446 | 0.073156 |
4935 rows × 41 columns
Column | Description |
---|---|
Count | Total number of parent algo orders for the given row (will be 1 unless using a groupby). |
ArrivalTime | Time of receipt of order by LP in GMT. |
ParentOrderID | Parent order identifier. |
Account | End user client name. |
Trader | Executing trader name. |
AlgoName | Executing algorithm name. |
Note: All groupbys return either weighted averages by order size or most recent entry for non-numeric fields.