Getting Started with Tradefeedr API¶

This document¶

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/.

API Logic¶

Conceptually, each API call has two components:

  1. 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.

  2. 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: Variables by which the results would have to be grouped. For example: {'groupby':['Symbol']} implies that results have to be grouped by Symbol.
    • var: Variables that should be returned in the endpoints. For example, 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"}).
    • filter: How to filter the results. For example, {"function": "within", "var": "Date", "pars": ["2014-01-01", "2021-11-30"]} filters the data to be within a certain range.
    • Domain: The range of the possible variables in the database. For symbol-like variables, the whole selection is returned, while for floats and dates, only min and max (range) is returned by API if domain is requested.

All API endpoints return a JSON dictionary which can be translated into Python pandas (examples below).

API Groups¶

Tradefeedr API can be split into the following groups:

  • Algo API: Covers algo execution workflows. The set of Tradefeedr Algo APIs allow the user to perform any task from calculating top-level algo performance summary table to investigating the quality of individual child fills.
  • RFS API: Covers request for stream workflow. The APIs allow the user to analyze RFQ flow characteristics such as markouts, spread paid per different segments of order flows. This analysis can be the basis of "bilateral sharing" (see Bilateral RFS API).
  • RFQ API: Covers request for quote (RFQ) workflow. The APIs allow the liquidity consumer to analyze LP performance in an RFQ panel, optimize the RFQ panel size. This analysis can be done.
  • Bilateral RFS API: These endpoints define analytics for "shared" datasets. Tradefeedr allows liquidity consumers to share their aggregated statistics such as market share and markouts with their liquidity providers. This is purely a liquidity consumer choice and Tradefeedr has to be instructed by the liquidity consumer explicitly. These shared datasets allow liquidity providers to analyze how competitive they are in the stack and engage in data-driven dialogue with liquidity consumers.

Each group contains a number of "functions" to perform specific tasks. In what follows, those functions are described for each group.

In [1]:
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()
Out[1]:
<lseg.data.session.Definition object at 0x13c0670e590 {name='ppe'}>

Algo API¶

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¶

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:

  • groupby: What columns should the result set be aggregated by.
  • select: What columns should be returned in the result set.
  • filter: What filters should be applied to the result set before they are returned.
  • risk_price_benchmark: See below explanation.
  • notation: Whether the result should be expressed as performance (positive numbers are good, negative are bad) or as shortfall (positive numbers are bad).

The user can specify risk_price_benchmark as an additional field in the Query. The four possible values are described below:

  • TradefeedrModel: (Default) This is Tradefeedr risk transfer benchmark constructed from the data collected from individual algo runs and fitted to volatility, time of the day, and trade size.
  • BankReported: This is the benchmark reported by the algo provider. This is only available for those providers who submit this data. None is reported for others.
  • OwnRiskPriceStatic: This is provided by the user (via uploading spread matrices) for their own internal use.
  • OwnRiskPriceVolAdjusted: This adjusts OwnRiskPriceStatic for volatility.
In [2]:
# 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¶

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:

  • select: Which variables should be returned in the end result. For example, ArrivalMidPerfBPS. The full list of possible values can be found at the end of this notebook.
  • filter: How the underlying data should be filtered.
In [3]:
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¶

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.

In [4]:
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
In [5]:
display(px.bar(result_df.sort_values('TradeQuantityUSD'), x='ExecVenue', y='TradeQuantityUSD'))

v1/fx/algo/markouts¶

v1/fx/algo/markouts returns the markout curves information.

Different Markout Types are supported:

  • Markout: Markout Curves starting at SpreadPNL at time zero. Those curves represent the P&L of the counterparty.
  • MarkoutsAtZero: Markout Curves starting at 0 at time 0. Those curves represent price impact curves and do not include Spread Paid.
  • MarkoutsAtZeroAverage: Average (as opposed to weighted average) version of MarkoutsAtZero.
  • Volatilities: Std of each markout point for confidence intervals.

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.

In [6]:
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¶

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:

  • select: Which fields should be returned in the end result. For example, SpreadPnLPM. The full list of possible values is given below.
  • filter: How the underlying data should be filtered.
In [7]:
parent_order_df.ParentOrderID.iloc[-1]
Out[7]:
'm20220809-A00'
In [8]:
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¶

v1/fx/algo/market-data give back the market data during algo exec.:

In [9]:
parent_order_df.ParentOrderID.iloc[-1]
Out[9]:
'm20220809-A00'
In [10]:
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¶

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:

In [11]:
parent_order_df.ParentOrderID.iloc[-1]
Out[11]:
'm20220809-A00'
In [12]:
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

RFS¶

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.

image.png

v1/fx/rfs/summary-stats¶

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.

In [13]:
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¶

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.

In [14]:
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¶

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.

In [15]:
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¶

v1/fx/rfs/markouts returns the markout curves.

Different types of markout curves are supported:

  • Markout - Markout Curves starting at SpreadPNL at time zero. Those curve represent the P&L of counterparty
  • MarkoutsAtZero - Markout Curves starting at 0 at time 0. Those curves represent price impact curves and do not include Spread Paid.
  • MarkoutsAtZeroAverage - Average (as opposed to weighted average) version of MarkoutsAtZero.
  • Volatilities - Std of each markout point for confidence intervals

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.

In [16]:
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

FX Swaps and Outrights API¶

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:

  1. Liquidity consumer (LC) identifies a set (henceforth referred to as LP stack) of Liquidity providers (LPs).
  2. LC sends the request for quotes in a given size and currency pair/instrument. The quote request can be two-sided (asking for bid and offer) or one-sided.
  3. LC waits for some time for those LPs to come with quotes.
  4. LC selects the best quote according to some rules (in the vast majority of cases it is simply the highest bid or lowest offer depending on the side).

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¶

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.

In [17]:
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¶

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.

In [18]:
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¶

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:

Hit Stats¶

  • NumberOfParticipations: Number of RFQs LP participated in.
  • NumberOfWins: Number of times a specific LP is a winner (trade is booked against them).
  • ActualWinRatio: NumberOfWins divided by NumberOfParticipations.
  • ExpectedWins: Expected number of wins. For each RFQ, the expected win is 1/PanelSize. For example, for an LP participating in 20 RFQs each with 4 LPs, the expected number of wins will be 20 x (1/4) = 5.
  • ExpectedWinRatio: 100 times ExpectedWins divided by NumberOfParticipations.
  • AverageRFQPanelSize: Average size of the RFQ panel for this LP.

Volume Stats¶

  • VolumeParticipated: Volume of RFQs LP participated in.
  • VolumeWon: Volume of trading specific LP is a winner (trade is booked against them).
  • ActualVolumeWinRatio: VolumeWon as a percentage of VolumeParticipated.
  • ExpectedWinVolume: Expected volume. For each RFQ, the expected probability of winning is 1/PanelSize. For example, for an LP participating in 20 RFQs each with 4 LPs, the expected number of wins will be 20 x (1/4) = 5. For volume stats, each RFQ is adjusted by its volume.
  • ExpectedVolumeWinRatio: 100 times ExpectedWinVolume divided by VolumeParticipated.

Outperformance Stats¶

  • WinPerformanceScore: ActualWinRatio minus ExpectedWinRatio.
  • VolumePerformanceScore: ActualVolumeWinRatio minus ExpectedVolumeWinRatio.
In [19]:
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¶

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

In [20]:
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¶

v1/fx/rfq-outrights/markouts calculated spot markouts:

In [21]:
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

FX Swaps¶

v1/fx/rfq-swaps/execution-history¶

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.

In [22]:
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¶

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.

In [ ]:
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¶

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:

Hit Stats¶

  • NumberOfParticipations: Number of RFQs LP participated in.
  • NumberOfWins: Number of times a specific LP is a winner (trade is booked against them).
  • ActualWinRatio: NumberOfWins divided by NumberOfParticipations.
  • ExpectedWins: Expected number of wins. For each RFQ, the expected win is 1/PanelSize. For example, for an LP participating in 20 RFQs each with 4 LPs, the expected number of wins will be 20 x (1/4) = 5.
  • ExpectedWinRatio: 100 times ExpectedWins divided by NumberOfParticipations.
  • AverageRFQPanelSize: Average size of the RFQ panel for this LP.

Volume Stats¶

  • VolumeParticipated: Volume of RFQs LP participated in.
  • VolumeWon: Volume of trading specific LP is a winner (trade is booked against them).
  • ActualVolumeWinRatio: VolumeWon as a percentage of VolumeParticipated.
  • ExpectedWinVolume: Expected volume. For each RFQ, the expected probability of winning is 1/PanelSize. For example, for an LP participating in 20 RFQs each with 4 LPs, the expected number of wins will be 20 x (1/4) = 5. For volume stats, each RFQ is adjusted by its volume.
  • ExpectedVolumeWinRatio: 100 times ExpectedWinVolume divided by VolumeParticipated.

Outperformance Stats¶

  • WinPerformanceScore: ActualWinRatio minus ExpectedWinRatio.
  • VolumePerformanceScore: ActualVolumeWinRatio minus ExpectedVolumeWinRatio.
In [24]:
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¶

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.

In [25]:
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¶

v1/fx/rfq-swaps/markouts calculated spots markouts around swap trades

In [48]:
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

v1/fx/rfq-swaps/execution-stats¶

In [ ]:
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

Stats API¶

v1/fx/stats/risk-transfer-cost¶

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.

In [27]:
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¶

v1/fx/stats/intraday-volatility attempts to create an approximation of fair price of immediate execution.

In [28]:
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

Tradefeedr Algo Forecast Pre and Post-Trade API Documentation¶

Background¶

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.

APIs 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:

  1. API end-point: This can be thought of as a function doing a specific job. Consider, for example, API endpoint 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.
  2. JSON string: This contains a set of parameters for the API end-point function. This follows the general format for Tradefeedr APIs as detailed in the getting started docs, but specific examples are given below.

All API end-points return a JSON dictionary which can be translated into the Python pandas (examples below).

In [29]:
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

Pre-Trade Field Explanations¶

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.

v1/fx/algo/post-trade-forecast¶

In [30]:
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

Post-Trade Field Explanations¶

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.