Skip to main content

Ember handling of exchange commissions

Overview

Recent survey of Exchange APIs found that less than 10% of crypto exchanges provide amount of fee charged with their trade notification messages. Similarly, only about half of exchanges provide information on Maker vs Taker flag on fill notifications. To overcome this problem Deltix come up with a method of estimating fees based on schedules published by each exchange.

This document describes a component used by Deltix to estimate commission from different exchanges.

Background

Kinds of Fee Schedule

  • Flat (BTCBox, Bittrex)
  • Different fee for Makers and Takers (Deribit)
  • Different fee for each contract with a difference for Makers and Takers (Cryptofacilities, Huobi)
  • Tiered fee structure where fee depends on rolling 30-day trading volume and is different for Makers and Takers. This is the most popular schedule (Coinbase Pro, Kraken, etc).

Additional variations

  • On some exchanges (Korbit, SeedCX) makers receive rebates (rather than pay fees).
  • On some exchanges fee may depend on instrument type (e.g. spot vs futures) or type of coins (stable vs normal).

Loyalty coins

Some exchanges (Cuoine/Liquid, Binance) reduce fees or promote clients into higher trading volume tier based on the amount of exchange coins held or used to pay commission.

Fee Rounding

All exchanges round fees up (up to two decimal points). For example; a fee of 0.111 will be charged as 0.12.

Design Considerations

Deltix designed customizable Commission Rules engine that has the following approach to manage unknowns (imperfections of exchange APIs):

  • Client should have an ability to override official schedule fee. For example, some OTC desks that primarily use SMART order routing to seek liquidity predominantly trade as market takers. While other deployments (such as Market Maker may use “post only” maker orders). Such knowledge can be captured in a custom commission schedule.
  • Some clients negotiate special fees with exchanges.
  • If maker/taker side of the deal is unknown, assume taker (higher commission).
  • If 30-days trading volume is unknown, assume the lowest (higher commission).

Commission Rule Engine

Each trading connector can define optional fee schedule in Execution Server configuration file (ember.conf). Let’s consider fee schedule of COINBASE exchange as an example:

Priciing TierTaker FeeMaker Fee
<$100K0.25%0.15%
10K-1M0.20%0.10%
1-10M0.18%0.08%
10-50M0.15%0.05%
50-100M0.10%0.0%

Here is how this fee schedule is configured in ember.conf:

COINBASE: ${template.connector.COINBASE} {
...
feeSchedule {
fees: [
{ tradingVolume = 0, takerFee = 0.25, makerFee = 0.15 }
{ tradingVolume = 100000, takerFee = 0.20, makerFee = 0.10 }
{ tradingVolume = 1000000, takerFee = 0.18, makerFee = 0.08 }
{ tradingVolume = 10000000, takerFee = 0.15, makerFee = 0.50 }
{ tradingVolume = 50000000, takerFee = 0.10, makerFee = 0.00 }
// etc ...
]
}
}

Each fee schedule entry can use the following attributes:

  • tradingVolume - Optional. 30 days trading volume. Rules Engine will rely on TimeBase stream “tradingVolumes”. Stream can be updated regularly using simple.
    Trading volume currency usually will be USD, but may be exchange-dependent (e.g. KRW for Korbit).
  • symbol - Optional. Symbol (or instrument), such as BTCUSD.
  • currency - Optional. For example, BTC. Currency and Symbol are mutually exclusive attributes.
  • takerFee - Required. Fee that takers pay, in percentage from total fill value. Can be zero.
  • makerFee - Required. Fee that makers pay, in percentage from total fill value. Can be zero or negative (in case of exchange rebate).

Inverse Futures

Normally commission amount is computed as production of

Fee = Trade Quantity * Average Trade Price * FeeRate

For inverse futures fee computation uses slightly different formula:

Fee = ( Trade Quantity / Average Trade Price ) * FeeRate

To mark fee schedule as inverse use special flag (default is false):

feeSchedule {
isInverse = true
fees: [
{tradingVolume = 0, takerFee = 0.075, makerFee = 0}
]
}

More examples

  • Flat fee:
feeSchedule {
fees: [
{ takerFee = 0.25, makerFee = 0.25 }
]
}
  • Different Maker/Taker fee:
feeSchedule {
fees: [
{ takerFee = 0.15, makerFee = 0.25 }
]
}
  • Currency-dependent fee:
feeSchedule {
fees: [
{ currency = BTC, takerFee = 0.25, makerFee = 0.25 }
{ currency = ETH, takerFee = 0.25, makerFee = 0.25 }
{ currency = LTC, takerFee = 0.25, makerFee = 0.25 }
]
}
  • Symbol and trading volume
feeSchedule {
fees: [
{ symbol = BTCUSD, tradingVolume = 0, takerFee = 0.25, makerFee = 0.15 }
{ symbol = BTCUSD, tradingVolume = 100000, takerFee = 0.20, makerFee = 0.10 }
{ symbol = BTCUSD, tradingVolume = 1000000, takerFee = 0.18, makerFee = 0.08 }
{ symbol = BTCUSD, tradingVolume = 10000000, takerFee = 0.15, makerFee = 0.50 }
{ symbol = BTCUSD, tradingVolume = 50000000, takerFee = 0.10, makerFee = 0.00 }

{ symbol = LTCUSD, tradingVolume = 0, takerFee = 0.25, makerFee = 0.15 }
{ symbol = LTCUSD, tradingVolume = 100000, takerFee = 0.20, makerFee = 0.10 }
{ symbol = LTCUSD, tradingVolume = 1000000, takerFee = 0.18, makerFee = 0.08 }
{ symbol = LTCUSD, tradingVolume = 10000000, takerFee = 0.15, makerFee = 0.50 }
{ symbol = LTCUSD, tradingVolume = 50000000, takerFee = 0.10, makerFee = 0.00 }
]
}

Daily Trading Volume

Ember Commission Engine expects trading volume data in the following format in a TimeBase stream called “tradingVolumes”. Here is a sample. Complete schema of the stream can be found in Appendix A.

TimestampSymbol(Exchange)Volume
6/15/2019 00:00:00.000 COINBASE  132142.03
6/16/2019 00:00:00.000COINBASE 100.00
6/17/2019 00:00:00.000 COINBASE  230598.76
.........
  • Timestamp - will identify the date of the trading volume record. Trading days begin at midnight UTC. Multiple records that belong to the same day will have their reported volumes combined.
  • Symbol - this field will be populated with exchange ID (or destination ID as it is defined in ember.conf).
  • Volume - trading volume reported on that date. For exchanges that use USD currency for trade volume discounts units are USD (Otherwise exchange-specific currency, for example BINANCE uses BTC).
    • Transactions made on books quoted in USD, e.g. BTC-USD, are counted as the total USD amount of each filled order.
    • Transactions made on non-USD books are converted to USD based on the most recent fill price on the respective book. For example, a purchase of 1 ETH on the ETH-BTC book will be immediately converted to a USD equivalent based on the most recent fill price on the ETH-USD book.
note

When loading trading volume from CSV file using ManualVolumeReporting tool this column uses yyyy-MM-dd HH:mm:ss timestamp format in UTC timezone. For example, 2019-06-19T17:00:00

note

As in other areas of Deltix products exchange must use `ALPHANUMERIC(10)`` format (limited to upper-case English letters, digits and punctuation symbols, up to 10 characters long).

Multiple trading systems must report their trading volumes into multiple streams. Commission Engine will allow defining additional trading volume streams.

When calculating commission discounts Ember will total volumes reported for the last 30 calendar days.

Multiple sources of trading volume

You can setup multiple publishers of trading volume, each in different stream. System will use combined trading volume grouped by each exchange.

Trading Volume diagram

Configuration

By default, Ember looks for commissions in “tradingVolumes” stream. Additional streams can be configured as shown:

feeSchedule.settings.streams = [ tradingVolumes, tradingVolumesMarketMaker ]

Trading volume is recalculated once a day at midnight UTC. You can override this using the following settings:

feeSchedule {
settings {
calculationTimeOfDay = "23:59:59.999"
timezone = America/New_York
}
}

Trading Volume timestamps and time zone

Trading volume computation routine uses the following approach.

  • Routine uses the last midnight in UTC timezone and subtracts 30 calendar days from it.
  • It loads all messages from trading volume stream starting from this timestamp (inclusive) till end of stream.
  • Messages are grouped by exchange and volume is totaled.

Logging

Ember logs commission information for each exchange on start up. Here is a sample:

Calculated 30-day trading volume for COINBASE is 30000700. Commissions: taker=0.0015 maker=0.005
Trading volume is unknown for KRAKEN. Commissions: taker=0.0026 maker=0.0016

Manual Tool (BETA)

Deltix provides simple command line tool to load trading volume from CSV file into TimeBase.

Input format sample is similar to described above. Here is a working sample:

;Timestamp, Exchange, Volume
2019-06-16 17:00:00, COINBASE, 100
2019-06-17 17:00:00, COINBASE, 200
2019-06-18 17:00:00, COINBASE, 300

Tool takes two arguments: TimeBase URI and Input file name. Example:

deltix.ember.app.fee.tb.ManualVolumeReporter dxtick://localhost:8011 tradeVolume.csv
caution

records are loaded into TimeBase with TRUNCATE append mode. This means re-loading already loaded records may introduce issues (Stream truncated every time when loader writes messages earlier that last). You should avoid re-loading records if you don’t know what you are doing.

Daily Volume Publisher Tool

Deltix provides command line tool to compute trading volume from trading events in journal and load it into TimeBase. The name of the script running the tool is dv-publisher. It takes these parameters:

Usage: dv-publisher -marketStreams <arg> [-timebase <arg>] [-volumeStream <arg>]
[-currency <arg>] [-maxDays <arg>] [-dryRun]

-marketStreams <arg> Comma-separated list of market streams that provide
data about market prices of currencies on exchanges
-timebase <arg> Timebase URL (default is dxtick://localhost:8011)
-volumeStream <arg> Volume stream where computed trading volume records
will be written (default is "tradingVolumes")
-currency <arg> Currency in which trading volume is computed
(default "USD")
-maxDays <arg> Maximum number of days for which trading volume
is computed (default is 30)
-dryRun Execute a dry run with trading volumes written
to the console only

Limitations

  • Commissions will be recorded into Ember journal during fill processing time. Subsequent changes to fee schedule will not affect past commissions.
  • Trading Volume computation may yield approximate results. For example, on some exchanges today’s recent trades are included in 30-day trading volume.
  • Trading Volume computation won’t be able to factor external trades happening on the same account.
  • Fee Schedule changes will require Ember restart.
  • Support for fees based on asset class is not implemented.

Out of scope

  • An ability to pay commissions with exchange loyalty coins to get reduced rate.
  • Support past/future fee schedules
  • Auction trade fees

Appendix: Trading Volume Stream Schema

<?xml version="1.0" encoding="UTF-8"?>
<schema xmlns="http://xml.deltixlab.com/internal/quantserver" xmlns:ns2="http://xml.deltixlab.com/internal/quantserver/3.0">
<isFixed>true</isFixed>
<descriptors xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="ns2:recordClass">
<ns2:name>deltix.ember.app.fee.tb.DailyTradingVolumeMessage</ns2:name>
<ns2:title />
<ns2:description />
<ns2:guid>a9fee77cc97d3mws2sov_3</ns2:guid>
<ns2:abstract>false</ns2:abstract>
<ns2:field xsi:type="ns2:nonStaticDataField">
<ns2:name>Source Sequence Number</ns2:name>
<ns2:title>Source Sequence Number</ns2:title>
<ns2:description />
<ns2:type xsi:type="ns2:INTEGER">
<ns2:encoding>INT64</ns2:encoding>
<ns2:nullable>true</ns2:nullable>
</ns2:type>
<ns2:pk>false</ns2:pk>
<ns2:displayIdentifier>false</ns2:displayIdentifier>
</ns2:field>
<ns2:field xsi:type="ns2:nonStaticDataField">
<ns2:name>Volume</ns2:name>
<ns2:title>Volume</ns2:title>
<ns2:description />
<ns2:type xsi:type="ns2:FLOAT">
<ns2:encoding>IEEE64</ns2:encoding>
<ns2:nullable>false</ns2:nullable>
</ns2:type>
<ns2:pk>false</ns2:pk>
<ns2:displayIdentifier>false</ns2:displayIdentifier>
</ns2:field>
</descriptors>
<selection>0</selection>
</schema>