{ "cells": [ { "attachments": { "cuemacro_logo.png": { "image/png": "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" } }, "cell_type": "markdown", "metadata": {}, "source": [ "![cuemacro_logo.png](attachment:cuemacro_logo.png)\n", "\n", "# Compliance and other more involved TCA calculations\n", "\n", "**Saeed Amen / Founder of Cuemacro**\n", "\n", "https://www.cuemacro.com / saeed@cuemacro.com / @saeedamenfx / All material is copyright Cuemacro / 2020" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "tcapy is a transaction cost analysis library in Python and one of the first open source TCA library. Typically, internal solutions can cost hundreds of thousands of dollars to develop and maintain. Using external services to do TCA also often have a licence cost.\n", "\n", "This notebook assumes that you have already \n", "* installed it by following the instructions [here](https://github.com/cuemacro/tcapy/blob/master/INSTALL.md)) \n", "* read the introductory tcapy notebook [here](https://github.com/cuemacro/tcapy/blob/master/tcapy_notebooks/introducing_tcapy.ipynb)\n", "\n", "In this notebook, we show how we can do more involved TCA calculations with tcapy. We will show users how to construct Python based queries to:\n", "\n", "* Calculate notionals executed with each LP (liquidity provider)\n", "* Flag trades which have outlying slippage\n", "\n", "We shall also show you how to do to use some of the lower level parts of tcapy." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Benchmark machines\n", "\n", "For reference, the benchmark times quoted in the text are for the following hardware setup, which is designed to replicate a typical environment, where databases are running on a different system. In our case, we are running on Windows and WSL/Ubuntu on our primary machine. This setup is the best of both worlds, allowing us to use features like Celery and Dash/web GUI undex Linux, but still using Windows, so we could also interact with applications like Excel easily. Note, that the times we quote are from running once (in practice, we should take an average over many runs).\n", "\n", "tcapy is running on\n", "* Processor: Intel(R) Core(TM) i9-7940X CPU @ 3.10GHz, 14 Core(s)\n", "* Memory: 64 GB RAM\n", "* Hard disk: NVMe m.2 SSD\n", "* OS: Windows Version 10.0.18362 and WSL/Windows Subsystem for Linux (Ubuntu 18.04) running Celery/Redis/Memcached backend\n", "\n", "Databases are running on (Arctic/MongoDB 3.6.5 for market tick data and Microsoft SQL Server 14.0.2027)\n", "* Intel(R) Xeon(R) CPU E3-1505M v6 @ 3.00GHz, 4 Core(s)\n", "* Memory: 32 GB RAM and \n", "* Hard disk: NVMe m.2 SSD\n", "* OS: Windows Version 10.0.17763" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Our first step is to add the tcapy library to our `PYTHONPATH`. You may need to change these lines. Note, that in our setup, we are running the Jupyter notebook on Windows, and the backend Celery workers on Linux. If you are running everything in the same environment, the paths are likely to be same." ] }, { "cell_type": "code", "execution_count": 1, "metadata": { "ExecuteTime": { "end_time": "2020-07-27T14:16:47.335783Z", "start_time": "2020-07-27T14:16:47.329783Z" } }, "outputs": [], "source": [ "import sys\n", "import os\n", "\n", "windows_tcapy_path = 'e:/cuemacro/tcapy' # Windows platform\n", "linux_tcapy_path = '/home/tcapyuser/cuemacro/tcapy' # Linux platform\n", "local_test_data_path = '../test/resources/' # Windows platform\n", "remote_test_data_path = '../test/resources/' # WSL drive\n", "\n", "# Assuming the front end is on Linux\n", "sys.path.insert(0, windows_tcapy_path)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "If the Python path now includes tcapy, we can do all the imports from it, that we'll need later. We'll also import all the other Python libraries we'll use." ] }, { "cell_type": "code", "execution_count": 2, "metadata": { "ExecuteTime": { "end_time": "2020-07-27T14:16:53.266782Z", "start_time": "2020-07-27T14:16:47.337784Z" } }, "outputs": [], "source": [ "from collections import OrderedDict\n", "\n", "# This is the entry point for our TCA analysis\n", "from tcapy.analysis.tcaengine import TCAEngineImpl\n", "\n", "# To construct the parameters for our TCA calculation\n", "from tcapy.analysis.tcarequest import TCARequest\n", "\n", "# To access trade and market data\n", "from tcapy.data.databasesource import DatabaseSourceCSVBinary, \\\n", " DatabaseSourceDataFrame, DatabaseSourceDukascopy\n", "\n", "# Import all the metrics and benchmarks we'll use\n", "from tcapy.analysis.algos.benchmark import BenchmarkArrival, BenchmarkMarketSpreadToMid\n", "from tcapy.analysis.algos.metric import MetricSlippage, MetricTransientMarketImpact\n", "\n", "# To aggregate the TCA results\n", "from tcapy.analysis.algos.resultsform import TimelineResultsForm, DistResultsForm, \\\n", " BarResultsForm, TableResultsForm, JoinTables\n", "\n", "# To help display the output of a TCA calculation\n", "from tcapy.vis.tcaresults import TCAResults\n", "from tcapy.vis.report.tcareport import TCAReport\n", "from tcapy.vis.displaylisteners import PlotRender\n", "\n", "# General classes\n", "from tcapy.conf.constants import Constants\n", "from tcapy.util.mediator import Mediator\n", "\n", "# Prevent requests from displaying debug messages for certain libraries\n", "import logging\n", "\n", "logging.getLogger(\"findatapy\").setLevel(logging.WARNING)\n", "logging.getLogger(\"requests\").setLevel(logging.WARNING)\n", "logging.getLogger(\"urllib3\").setLevel(logging.WARNING)\n", "\n", "# For plotting later\n", "import plotly.io as pio\n", "\n", "# For interactive plots (but these disappear when we reopen Jupyter)\n", "pio.renderers.default = \"notebook\" \n", "\n", "# Using https://github.com/plotly/Kaleido to generate static plot images\n", "# pio.renderers.default = \"svg\"\n", "pio.renderers.default = \"png\" \n", "\n", "import plotly\n", "\n", "from chartpy import Chart, Style\n", "\n", "# default size for Plotly charts we use\n", "chart_width = 800\n", "chart_height = 500\n", "\n", "chart = Chart()\n", "constants = Constants()\n", "style = Style(width=chart_width, height=chart_height, scale_factor=-1, silent_display=True)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Let's specify the paths of the trade/order data CSVs in the test folder of tcapy, which are included in the package." ] }, { "cell_type": "code", "execution_count": 3, "metadata": { "ExecuteTime": { "end_time": "2020-07-27T14:16:53.276783Z", "start_time": "2020-07-27T14:16:53.268783Z" } }, "outputs": [], "source": [ "csv_trade_order_mapping = {'trade_df' : os.path.join(local_test_data_path, 'small_test_trade_df.csv'),\n", " 'order_df' : os.path.join(local_test_data_path, 'small_test_order_df.csv')}\n", "\n", "# The test trade/order data is populated between 25 Apr 2017-05 Jun 2017\n", "# with trades/orders for 'EURUSD', 'USDJPY' and 'EURJPY'\n", "local_csv_trade_order_mapping = OrderedDict([('trade_df', os.path.join(local_test_data_path, 'small_test_trade_df.csv')),\n", " ('order_df', os.path.join(local_test_data_path, 'small_test_order_df.csv'))])\n", "\n", "remote_csv_trade_order_mapping = OrderedDict([('trade_df', os.path.join(remote_test_data_path, 'small_test_trade_df.csv')),\n", " ('order_df', os.path.join(remote_test_data_path, 'small_test_order_df.csv'))])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We need to create the `TCAEngineImpl` object, which is the entry point for dealing with TCA calculations." ] }, { "cell_type": "code", "execution_count": 4, "metadata": { "ExecuteTime": { "end_time": "2020-07-27T14:16:53.338783Z", "start_time": "2020-07-27T14:16:53.278783Z" } }, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "2020-07-27 15:16:53,331; INFO:tcapy.analysis.tcaengine: Init TCAEngine version: pro - Env: desktop_laptop_linux (tcaengine.py:53)\n" ] } ], "source": [ "tca_version = constants.tcapy_version\n", "tca_engine = TCAEngineImpl(version=tca_version)\n", "\n", "volatile_cache = Mediator.get_volatile_cache()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Creating a TCA calculation to flag outlying slippage on trades\n", "\n", "In this section, we show how to do TCA calculations with tcapy to\n", "\n", "* flag trades/orders which have a spread which are outliers\n", "* get the total notional executed by each broker\n", "* get the average slippage per broker\n", "\n", "We'll also aggregate some of these results into a single DataFrame.\n", "\n", "As a first step, let's specify our `MetricSlippage` object. We also create a `BenchmarkMarketSpreadToMid` object, which will take the market data and the then calculate the spread from the bid/ask to the mid. For those market data sources, without a bid/ask and only mid, we specify 1 bp as our outlier amount (if bid/ask exist, tcapy will ignore this given we've specified `overwrite_bid_ask=False`." ] }, { "cell_type": "code", "execution_count": 5, "metadata": { "ExecuteTime": { "end_time": "2020-07-27T14:16:53.344783Z", "start_time": "2020-07-27T14:16:53.340782Z" } }, "outputs": [], "source": [ "metric_slippage = MetricSlippage()\n", "benchmark_spread_to_mid = BenchmarkMarketSpreadToMid(overwrite_bid_ask=False, bid_mid_bp=1, ask_mid_bp=1)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Let's create a `TableResultsForm` which will look at the `slippage` of all the trades and pick out only those which are anomalous. The resulting DataFrame, will be ordered by the worst slippage." ] }, { "cell_type": "code", "execution_count": 6, "metadata": { "ExecuteTime": { "end_time": "2020-07-27T14:16:53.354783Z", "start_time": "2020-07-27T14:16:53.345783Z" } }, "outputs": [], "source": [ "# Display a table of all the anomalous trades by slippage (ie. outside bid/ask)\n", "table_results_form = TableResultsForm(market_trade_order_list=['trade_df'],\n", " metric_name='slippage',\n", " \n", " # Order by the worst slippage\n", " filter_by='worst_all', \n", " \n", " # Only flag trades outside bid/ask\n", " tag_value_combinations={'slippage_anomalous': 1.0},\n", " \n", " # Only display a small number of fields\n", " keep_fields=['executed_notional_in_reporting_currency', 'side'],\n", " \n", " # Don't round any of the figures\n", " round_figures_by=None)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Here we create a `BarResultsForm` object to aggregate notional executed per broker." ] }, { "cell_type": "code", "execution_count": 7, "metadata": { "ExecuteTime": { "end_time": "2020-07-27T14:16:53.364783Z", "start_time": "2020-07-27T14:16:53.356784Z" } }, "outputs": [], "source": [ " # Get the total notional executed by broker (in reporting currency)\n", "bar_results_form_notional = BarResultsForm(market_trade_order_list=['trade_df'], # Trade\n", " # Aggregate by broker name\n", " aggregate_by_field='broker_id', \n", " \n", " # Analyse notional\n", " metric_name='executed_notional_in_reporting_currency',\n", " \n", " # Sum the notional\n", " aggregation_metric='sum', \n", " \n", " # No need for a multipler\n", " scalar=1, \n", " \n", " # Round to nearest unit\n", " round_figures_by=0)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now let's create a `BarResultsForm` to calculate the average slippage per broker (weighted by trade size)." ] }, { "cell_type": "code", "execution_count": 8, "metadata": { "ExecuteTime": { "end_time": "2020-07-27T14:16:53.373782Z", "start_time": "2020-07-27T14:16:53.366786Z" } }, "outputs": [], "source": [ "# Get average slippage per broker (weighted by notional)\n", "bar_results_form_slippage = BarResultsForm(market_trade_order_list=['trade_df'],\n", " \n", " # Aggregate the trades by broker_id\n", " aggregate_by_field='broker_id',\n", " \n", " # Do calculations on the slippage field\n", " metric_name='slippage',\n", " aggregation_metric='mean',\n", " \n", " # Weight the mean by the amount executed in reported currency (usually USD)\n", " weighting_field='executed_notional_in_reporting_currency',\n", " \n", " # Multiply the slippage by 10000 (converting to bp)\n", " scalar=10000.0,\n", " \n", " # Round all output to 2 decimal places\n", " round_figures_by=2)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Lastly, create a `JoinTables` object to combine the total notional per broker and the associated slippage for each broker." ] }, { "cell_type": "code", "execution_count": 9, "metadata": { "ExecuteTime": { "end_time": "2020-07-27T14:16:53.383782Z", "start_time": "2020-07-27T14:16:53.375784Z" } }, "outputs": [], "source": [ "join_tables_notional_slippage = JoinTables(tables_dict={'table_name': 'jointables_broker_id',\n", "\n", " # Fetch the following calculated tables\n", " 'table_list': ['bar_trade_df_executed_notional_in_reporting_currency_by/sum/broker_id',\n", " 'bar_trade_df_slippage_by/mean/broker_id'],\n", "\n", " # Append to the columns of each table\n", " 'column_list': ['notional (rep cur)', 'slippage (bp)']})" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Here we create a detailed `TCARequest` loading our trade data from CSV files for a single ticker (in this case EURUSD). Given that we are downloading directly from Dukascopy, we shall set `use_multithreading=False` as the current downloader is not thread safe. If we want to use multithreading/Celery, we can use other data sources, such as a database (eg. Arctic/MongoDB). In general, it is better to use a market data database, which has been prepopulated from an external source, rather than repeatedly calling an external source, which is very slow (in particular when accessing a long history).\n", "\n", "Note, we are using the various `Metric`, `Benchmark`, `ResultsForm` and `JoinTables` objects which we have already defined earlier." ] }, { "cell_type": "code", "execution_count": 10, "metadata": { "ExecuteTime": { "end_time": "2020-07-27T14:16:53.396783Z", "start_time": "2020-07-27T14:16:53.385782Z" } }, "outputs": [], "source": [ "# We are conducting a TCA computation for trade/order data between 05 May-10 May 2017 for EURUSD\n", "# The trade dataset is from CSV and the market data is downloaded from Dukascopy on the fly\n", "tca_request = TCARequest(start_date='05 May 2017', finish_date='10 May 2017', ticker=['EURUSD'],\n", " tca_type='detailed',\n", " trade_data_store='csv', market_data_store='dukascopy',\n", " trade_order_mapping=local_csv_trade_order_mapping,\n", " metric_calcs=[metric_slippage],\n", " results_form=[table_results_form, \n", " bar_results_form_notional, \n", " bar_results_form_slippage],\n", " benchmark_calcs=[benchmark_spread_to_mid],\n", " join_tables=[join_tables_notional_slippage],\n", " use_multithreading=False)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Let's run the TCA calculation from our `TCARequest`. The output is a dictionary of DataFrames (and Figures)." ] }, { "cell_type": "code", "execution_count": 11, "metadata": { "ExecuteTime": { "end_time": "2020-07-27T14:17:03.225184Z", "start_time": "2020-07-27T14:16:53.398782Z" } }, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "2020-07-27 15:16:53,411; DEBUG:tcapy.analysis.tcamarkettradeloader: Start loading trade/data/computation (tcamarkettradeloader.py:241)\n", "2020-07-27 15:16:53,414; DEBUG:tcapy.analysis.tcatickerloaderimpl: Get market and trade/order data for EURUSD from 2017-05-05 00:00:00+00:00 - 2017-05-10 00:00:00+00:00 (tcatickerloaderimpl.py:80)\n", "2020-07-27 15:16:53,416; DEBUG:tcapy.data.volatilecache: Attempting to get list from cache: ['dukascopy_EURUSD_2017-05-05 00:00:00+00:00_2017-05-10 00:00:00+00:00_market_df_None_comp'] (volatilecache.py:540)\n", "2020-07-27 15:16:53,419; DEBUG:tcapy.data.volatilecache: Attempting to get list from cache: ['dukascopy_EURUSD_2017-05-05 00:00:00+00:00_2017-05-10 00:00:00+00:00_market_df_None_comp'] (volatilecache.py:540)\n", "2020-07-27 15:16:53,597; DEBUG:tcapy.data.databasesource: Downloading 2017-05-05 00:00:00 - 2017-05-10 00:00:00 for EURUSD (databasesource.py:3819)\n", "2020-07-27 15:17:01,925; WARNING:tcapy.analysis.algos.benchmark: mid not in market data (benchmark.py:90)\n", "2020-07-27 15:17:01,926; DEBUG:tcapy.data.volatilecache: Attempting to push ['dukascopy_EURUSD_2017-05-05 00:00:00+00:00_2017-05-10 00:00:00+00:00_market_df_None_comp'] to cache (volatilecache.py:426)\n", "2020-07-27 15:17:02,035; DEBUG:tcapy.util.deltaizeserialize: Pandas dataframe of size: ----------- 17.08 MB ----------- in 1 chunk(s) (deltaizeserialize.py:219)\n", "2020-07-27 15:17:02,088; DEBUG:tcapy.data.volatilecache: Now pushing ['dukascopy_EURUSD_2017-05-05 00:00:00+00:00_2017-05-10 00:00:00+00:00_market_df_None_comp'] to cache (volatilecache.py:443)\n", "2020-07-27 15:17:02,147; DEBUG:tcapy.data.volatilecache: Pushed ['dukascopy_EURUSD_2017-05-05 00:00:00+00:00_2017-05-10 00:00:00+00:00_market_df_None_comp'] to cache (volatilecache.py:461)\n", "2020-07-27 15:17:02,149; DEBUG:tcapy.data.volatilecache: Attempting to push ['dukascopy_EURUSD_2017-05-05 00:00:00+00:00_2017-05-10 00:00:00+00:00_market_df_None_comp'] to cache (volatilecache.py:426)\n", "2020-07-27 15:17:02,256; DEBUG:tcapy.util.deltaizeserialize: Pandas dataframe of size: ----------- 17.08 MB ----------- in 1 chunk(s) (deltaizeserialize.py:219)\n", "2020-07-27 15:17:02,301; DEBUG:tcapy.data.volatilecache: Now pushing ['dukascopy_EURUSD_2017-05-05 00:00:00+00:00_2017-05-10 00:00:00+00:00_market_df_None_comp'] to cache (volatilecache.py:443)\n", "2020-07-27 15:17:02,367; DEBUG:tcapy.data.volatilecache: Pushed ['dukascopy_EURUSD_2017-05-05 00:00:00+00:00_2017-05-10 00:00:00+00:00_market_df_None_comp'] to cache (volatilecache.py:461)\n", "2020-07-27 15:17:02,369; DEBUG:tcapy.analysis.tcatickerloader: Get trade order holder for EURUSD from 2017-05-05 00:00:00+00:00 - 2017-05-10 00:00:00+00:00 (tcatickerloader.py:386)\n", "2020-07-27 15:17:02,415; WARNING:tcapy.data.datafactory: Dataframe empty for ticker USDEUR (datafactory.py:97)\n", "2020-07-27 15:17:02,417; DEBUG:tcapy.data.volatilecache: Attempting to get list from cache: ['dukascopy_EURUSD_2017-05-05 00:00:00+00:00_2017-05-10 00:00:00+00:00_market_df_None_comp'] (volatilecache.py:540)\n", "2020-07-27 15:17:02,828; WARNING:tcapy.data.datafactory: Dataframe empty for ticker USDEUR (datafactory.py:97)\n", "2020-07-27 15:17:02,829; DEBUG:tcapy.data.volatilecache: Attempting to get list from cache: ['dukascopy_EURUSD_2017-05-05 00:00:00+00:00_2017-05-10 00:00:00+00:00_market_df_None_comp'] (volatilecache.py:540)\n", "2020-07-27 15:17:02,897; DEBUG:tcapy.analysis.tcatickerloader: Filter the market date by start/finish date (tcatickerloader.py:761)\n", "2020-07-27 15:17:02,904; DEBUG:tcapy.analysis.tcatickerloader: Combine trade/order data (tcatickerloader.py:782)\n", "2020-07-27 15:17:02,915; DEBUG:tcapy.analysis.tcatickerloader: Calculating BenchmarkMarketSpreadToMid for market data (tcatickerloader.py:600)\n", "2020-07-27 15:17:02,943; DEBUG:tcapy.analysis.tcatickerloader: Filter trades by venue (tcatickerloader.py:458)\n", "2020-07-27 15:17:02,945; DEBUG:tcapy.analysis.tcatickerloader: Calculating derived fields and benchmarks (tcatickerloader.py:508)\n", "2020-07-27 15:17:02,946; DEBUG:tcapy.analysis.tcatickerloader: Calculating execution fields (tcatickerloader.py:510)\n", "2020-07-27 15:17:02,957; DEBUG:tcapy.analysis.tcatickerloader: Calculating benchmarks (tcatickerloader.py:536)\n", "2020-07-27 15:17:02,958; DEBUG:tcapy.analysis.tcatickerloader: Calculating metrics (tcatickerloader.py:554)\n", "2020-07-27 15:17:02,959; DEBUG:tcapy.analysis.tcatickerloader: Calculating MetricSlippage for trade_df (tcatickerloader.py:560)\n", "2020-07-27 15:17:02,978; DEBUG:tcapy.analysis.tcatickerloader: Calculating MetricSlippage for order_df (tcatickerloader.py:560)\n", "2020-07-27 15:17:02,998; DEBUG:tcapy.analysis.tcatickerloader: Completed derived field calculations for EURUSD (tcatickerloader.py:568)\n", "2020-07-27 15:17:02,999; DEBUG:tcapy.analysis.tcatickerloaderimpl: Generating downsampled market data for potentional display (tcatickerloaderimpl.py:275)\n", "2020-07-27 15:17:03,025; DEBUG:tcapy.analysis.tcatickerloaderimpl: About to join (tcatickerloaderimpl.py:340)\n", "2020-07-27 15:17:03,029; DEBUG:tcapy.analysis.tcatickerloaderimpl: Finished joining (tcatickerloaderimpl.py:356)\n", "2020-07-27 15:17:03,032; DEBUG:tcapy.analysis.tcatickerloaderimpl: About to join (tcatickerloaderimpl.py:340)\n", "2020-07-27 15:17:03,035; DEBUG:tcapy.analysis.tcatickerloaderimpl: Finished joining (tcatickerloaderimpl.py:356)\n", "2020-07-27 15:17:03,172; DEBUG:tcapy.analysis.tcamarkettradeloader: Finished loading data and calculating metrics on individual tickers (tcamarkettradeloader.py:248)\n", "2020-07-27 15:17:03,174; DEBUG:tcapy.analysis.tcamarkettradeloaderimpl: Constructing results form to summarize analysis... (tcamarkettradeloaderimpl.py:74)\n", "2020-07-27 15:17:03,214; DEBUG:tcapy.analysis.tcamarkettradeloaderimpl: Now join table results... (tcamarkettradeloaderimpl.py:122)\n", "2020-07-27 15:17:03,220; DEBUG:tcapy.analysis.tcamarkettradeloaderimpl: Finished calculating results form and join table results! (tcamarkettradeloaderimpl.py:135)\n" ] } ], "source": [ "Mediator.get_volatile_cache().clear_cache()\n", "\n", "# Dictionary of (mostly) dataframes as output from TCA calculation\n", "dict_of_df = tca_engine.calculate_tca(tca_request)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Let's have a look inside the output of our TCA calculation." ] }, { "cell_type": "code", "execution_count": 12, "metadata": { "ExecuteTime": { "end_time": "2020-07-27T14:17:03.240184Z", "start_time": "2020-07-27T14:17:03.227184Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "odict_keys(['trade_df', 'order_df', 'sparse_market_trade_df', 'sparse_market_order_df', 'market_df_downsampled', 'candlestick_fig', 'table_trade_df_slippage_by_worst_all', 'bar_trade_df_executed_notional_in_reporting_currency_by/sum/broker_id', 'bar_trade_df_slippage_by/mean/broker_id', 'jointables_broker_id', 'market_df'])\n" ] } ], "source": [ "print(dict_of_df.keys())" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Below we explain what each of the keys in the dictionary output represent.\n", "\n", "* `trade_df` - trade data, with additional calculated fields\n", "* `order_df` - order data, with additional calculated fields\n", "* `sparse_market_trade_df` - combined downsampled market data with trade data\n", "* `sparse_market_order_df` - combined downsampled market data with order data\n", "* `market_df_downsampled` - downsampled market data\n", "* `candlestick_fig` - candlesticks of resampled market data as a Plotly Figure\n", "* `market_df` - this empty given default `dummy_market=True` set\n", "\n", "We also have various keys associated with the `ResultForm` and `JoinTable` objects we created.\n", "\n", "* `table_trade_df_slippage_by_worst_all` - table with trades which have outlying slippage\n", "* `bar_trade_df_executed_notional_in_reporting_currency_by/sum/broker_id` - total notional by broker\n", "* `bar_trade_df_slippage_by/mean/broker_id` - average slippage by broker\n", "* `jointables_broker_id` - combining the notional and slippage tables" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Let's use the `TCAResults` object to simplify the output into an easier form and create Plotly Figure charts/HTML styled tables." ] }, { "cell_type": "code", "execution_count": 13, "metadata": { "ExecuteTime": { "end_time": "2020-07-27T14:17:03.630185Z", "start_time": "2020-07-27T14:17:03.243194Z" } }, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "2020-07-27 15:17:03,248; DEBUG:tcapy.vis.displaylisteners: Plotting main timeline 2214 (displaylisteners.py:988)\n", "2020-07-27 15:17:03,492; DEBUG:tcapy.vis.displaylisteners: Rendered plot 2214 and (displaylisteners.py:998)\n", "2020-07-27 15:17:03,495; DEBUG:tcapy.vis.displaylisteners: Plotting main timeline 2208 (displaylisteners.py:988)\n", "2020-07-27 15:17:03,550; DEBUG:tcapy.vis.displaylisteners: Rendered plot 2208 and (displaylisteners.py:998)\n" ] } ], "source": [ "tca_results = TCAResults(dict_of_df, tca_request)\n", "tca_results.render_computation_charts()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We can now access the DataFrames via properties like `bar`, `table` and `jointables`." ] }, { "cell_type": "code", "execution_count": 14, "metadata": { "ExecuteTime": { "end_time": "2020-07-27T14:17:03.645185Z", "start_time": "2020-07-27T14:17:03.632185Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "dict_keys(['trade_df_executed_notional_in_reporting_currency_by/sum/broker_id', 'trade_df_slippage_by/mean/broker_id'])\n", "dict_keys(['trade_df_slippage_by_worst_all'])\n", "dict_keys(['broker_id'])\n" ] } ], "source": [ "print(tca_results.bar.keys())\n", "print(tca_results.table.keys())\n", "print(tca_results.join_tables.keys())" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Let's view the data related to the `BarResultsForm` for the executed notional for each broker, firstly as a DataFrame and secondly as a bar chart by accessing the `bar_charts` property of the `TCAResults` object." ] }, { "cell_type": "code", "execution_count": 15, "metadata": { "ExecuteTime": { "end_time": "2020-07-27T14:17:03.660184Z", "start_time": "2020-07-27T14:17:03.647186Z" } }, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
broker_id
broker_id_index
broker219743083.0
broker321398742.0
broker43586887.0
broker58986275.0
broker627237125.0
\n", "
" ], "text/plain": [ " broker_id\n", "broker_id_index \n", "broker2 19743083.0\n", "broker3 21398742.0\n", "broker4 3586887.0\n", "broker5 8986275.0\n", "broker6 27237125.0" ] }, "execution_count": 15, "metadata": {}, "output_type": "execute_result" } ], "source": [ "tca_results.bar['trade_df_executed_notional_in_reporting_currency_by/sum/broker_id']" ] }, { "cell_type": "code", "execution_count": 16, "metadata": { "ExecuteTime": { "end_time": "2020-07-27T14:17:07.696617Z", "start_time": "2020-07-27T14:17:03.662185Z" } }, "outputs": [ { "data": { "image/png": "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" }, "metadata": {}, "output_type": "display_data" } ], "source": [ "tca_results.bar_charts['trade_df_executed_notional_in_reporting_currency_by/sum/broker_id']" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We can also show the DataFrame with the outlier trades, which are outside the bid/ask from Dukascopy data." ] }, { "cell_type": "code", "execution_count": 17, "metadata": { "ExecuteTime": { "end_time": "2020-07-27T14:17:07.711616Z", "start_time": "2020-07-27T14:17:07.698619Z" } }, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
executed_notional_in_reporting_currencysideslippage_benchmarkslippageslippage_anomalous
2017-05-08 10:31:33.011000+00:003.586887e+0611.094680-0.0000211.0
2017-05-05 14:56:49.373000+00:006.811655e+0611.098875-0.0000161.0
2017-05-08 14:37:25.382000+00:001.551467e+0711.093750-0.0000151.0
2017-05-05 06:27:26.514000+00:001.976319e+07-11.097445-0.0000131.0
2017-05-09 11:18:39.206000+00:001.293143e+07-11.089700-0.0000131.0
Avg1.463584e+0701.094755-0.0000141.0
\n", "
" ], "text/plain": [ " executed_notional_in_reporting_currency \\\n", "2017-05-08 10:31:33.011000+00:00 3.586887e+06 \n", "2017-05-05 14:56:49.373000+00:00 6.811655e+06 \n", "2017-05-08 14:37:25.382000+00:00 1.551467e+07 \n", "2017-05-05 06:27:26.514000+00:00 1.976319e+07 \n", "2017-05-09 11:18:39.206000+00:00 1.293143e+07 \n", "Avg 1.463584e+07 \n", "\n", " side slippage_benchmark slippage \\\n", "2017-05-08 10:31:33.011000+00:00 1 1.094680 -0.000021 \n", "2017-05-05 14:56:49.373000+00:00 1 1.098875 -0.000016 \n", "2017-05-08 14:37:25.382000+00:00 1 1.093750 -0.000015 \n", "2017-05-05 06:27:26.514000+00:00 -1 1.097445 -0.000013 \n", "2017-05-09 11:18:39.206000+00:00 -1 1.089700 -0.000013 \n", "Avg 0 1.094755 -0.000014 \n", "\n", " slippage_anomalous \n", "2017-05-08 10:31:33.011000+00:00 1.0 \n", "2017-05-05 14:56:49.373000+00:00 1.0 \n", "2017-05-08 14:37:25.382000+00:00 1.0 \n", "2017-05-05 06:27:26.514000+00:00 1.0 \n", "2017-05-09 11:18:39.206000+00:00 1.0 \n", "Avg 1.0 " ] }, "execution_count": 17, "metadata": {}, "output_type": "execute_result" } ], "source": [ "tca_results.table['trade_df_slippage_by_worst_all']" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We can view the DataFrame for the combination of total amount executed per broker and the slippage (weighted by notional)." ] }, { "cell_type": "code", "execution_count": 18, "metadata": { "ExecuteTime": { "end_time": "2020-07-27T14:17:07.726616Z", "start_time": "2020-07-27T14:17:07.713617Z" } }, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
broker_id notional (rep cur)broker_id slippage (bp)
broker219743083.0-0.14
broker321398742.0-0.11
broker43586887.0-0.21
broker58986275.0-0.10
broker627237125.0-0.12
\n", "
" ], "text/plain": [ " broker_id notional (rep cur) broker_id slippage (bp)\n", "broker2 19743083.0 -0.14\n", "broker3 21398742.0 -0.11\n", "broker4 3586887.0 -0.21\n", "broker5 8986275.0 -0.10\n", "broker6 27237125.0 -0.12" ] }, "execution_count": 18, "metadata": {}, "output_type": "execute_result" } ], "source": [ "tca_results.join_tables['broker_id']" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We can see the styled table, is a string of HTML code within an HTML IFrame. We could write this to disk as an HTML file or display to a user." ] }, { "cell_type": "code", "execution_count": 19, "metadata": { "ExecuteTime": { "end_time": "2020-07-27T14:17:07.741615Z", "start_time": "2020-07-27T14:17:07.728622Z" } }, "outputs": [ { "data": { "text/plain": [ "Iframe(height='300px', sandbox='', srcDoc='\\n\\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n
broker_id notional (rep cur)broker_id slippage (bp)
broker219743083.0-0.14
broker321398742.0-0.11
broker43586887.0-0.21
broker58986275.0-0.10
broker627237125.0-0.12
', width='975px', style={'border': 'thin lightgrey solid', 'padding': '0', 'margin': '0'})" ] }, "execution_count": 19, "metadata": {}, "output_type": "execute_result" } ], "source": [ "tca_results.styled_join_tables['broker_id']" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Conclusion\n", "\n", "We have seen how to call tcapy programatically for more involved usage, in particular how to use it for compliance purposes.\n", "\n", "If you are interesting supporting this project, such as sponsoring new features or to get commerical support, please contact saeed@cuemacro.com." ] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.6.10" }, "toc": { "base_numbering": 1, "nav_menu": {}, "number_sections": true, "sideBar": true, "skip_h1_title": false, "title_cell": "Table of Contents", "title_sidebar": "Contents", "toc_cell": false, "toc_position": {}, "toc_section_display": true, "toc_window_display": true } }, "nbformat": 4, "nbformat_minor": 4 }