Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

BSIP67: Dynamic Market Fees #133

Open
wants to merge 34 commits into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
183 changes: 183 additions & 0 deletions bsip-00XX Dynamic market fees.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,183 @@
BSIP: TBD
Title: Dynamic Market Fees
Authors: OpenLedgerApp <https://github.com/OpenLedgerApp>
Status: Draft
Type: Protocol
Created: 2018-12-17
Updated: 2018-12-17
Discussion:
Worker: TBD

# Abstract
UIA owners do not have many marketing tools to increase trade volume of their assets.

One of the ways to increase the trade volume can be Dynamic Market Fees that will provide additional discounts for active traders.
For example, to set lower fees for trading larger volumes.

So, instead of market fee, an asset owner can optionally set up dynamic_market_fee_percent property that may look like a following example table.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please elaborate. Since the given table is only meant as an example, how is that property to be set up and evaluated, and which degrees of freedom does this allow?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A table is an example. UIA owner can edit this table, set up a percent and trading volume.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That still doesnt define what the degrees of freedom are

**Please refer to the general notes below for terms (maker, taker) explanation.**
xeroc marked this conversation as resolved.
Show resolved Hide resolved

Trade daily volume | Maker fee, % | Taker fee, %
---|---|---
<=500 | 0.19% | 0.20%
\> 500 | 0.18% | 0.20%
\> 1K | 0.17% | 0.20%
\> 2.5K | 0.16% | 0.19%
\> 5K | 0.15% | 0.18%
\> 7.5K | 0.14% | 0.17%
\> 10K | 0.1% | 0.15%
\> 15K | 0.075% | 0.13%
\> 20K | 0.05% | 0.12%
\> 25K | 0.025% | 0.11%
\> 50K | 0.01% | 0.07%


## Motivation
- To provide additional marketing tools to encourage traders.
- To increase trading volume on BitShares.
- To attract traders to the ecosystem.

# Rationale

## Use cases:
**1) Supporting market makers.**
Every trade occurs between two parties: the maker, whose order exists on the order book prior to the trade, and the taker, who places the order that matches (or "takes") the maker's order.

Makers are so named because their orders make the liquidity in a market. Takers are the ones who remove this liquidity by matching makers' orders with their own.

The maker-taker model encourages market liquidity by rewarding the makers of that liquidity with a fee discount. It also results in a tighter market spread due to the increased incentive for makers to outbid each other. The higher fee that the taker pays is usually offset by the better prices this tighter spread provides.

**2) Supporting heavy volume traders.**
Fees are charged and deduced on a per-trade basis. The bigger “trading volume” users have traded, the lower fee they get on subsequent trades.

# General notes
Each asset will have either usual market fee or a table with dynamic market fees that will represent the table above.

A switch **market_fee_type (REGULAR, DYNAMIC)** should clearly indicate, which market fee type is used.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is a switch here necessary?

All assets can support this market fee. The default is how it is now, and if the dynamic one is set, the dynamic one will be used.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the current implementation, the switch provides supplementary features for UIA owners.
We consider the switching to be the most convenient way for users as a table is restored in one click.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this already implemented?


**Makers** are the ones who put up their orders first.

And **takers** are the ones to put up their orders later in time than makers.
Copy link
Collaborator

@sschiessl-bcp sschiessl-bcp Jan 21, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd suggest to enhance this BSIP by allowing maker/taker differentiation also for normal market fee (default is only one value for market fee, which is then used for maker and taker)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's a good point! We will update BSIP.


The following table
# Discussion

We have had a discussion what's the best way to average out Trading Volume.

There are a few ways of doing this:

- Use an **average volume since day the beginning of trading**.
Up for discussion is - what to take as a day 1. 1st trade of this asset? 1st trade minus 30 days? Account open date?
This way we have a normal fair average volume if we figure out the fair beginning interval date.
However, if a trader started trading this asset a few years ago he might be in a significant disadvantage.

- **Average trading volume over the last 30 days - sliding window**.
This way it is a bit clearer how to calculate.
However there might be extreme but real cases where this kind of calculation might not be fair:
a. when a person who usually trades high volumes throughout the year goes to vacation for 30 days. Suddenly all his discount is gone when he comes back
b. When another person comes in and makes 1 or 2 high volume trades while trading really low volumes before that. Suddenly this person might have a big discount.
30-day volume
This mehod gives enough information to figure out last 30-days traders habits with much lower memory requirements but slightly less precision than the 30-day average sliding window.
Average trading volume over the last 365 days (a year) is a variation of this method.

- **30-day volume method**
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is the difference of "Average trading volume over the last 30 days" to "30-day volume".

avg(30-day-volume) vs. sum(30-day-volume) as the metric to calculate the discount?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The difference is in the methods of updating statistics.
In the first case, statistics are updated every day on the principle of a sliding window: the trading volume of the previous day is subtracted from statistics.
In the second case, the average number of trades volume for the entire period is subtracted.

Copy link
Contributor

@nathanielhourt nathanielhourt Apr 2, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not use an Exponentially Weighted Moving Average? This would seem the obvious win to me, as EWMAs are efficient to calculate (linear in the number of samples) and store (constant state size).

This is quite similar to the 30-day average method and shares it's advantages and drawbacks.

# Technical Specifications

We suggest using average total volume for a particular asset. However, it's open for the discussion.

## Statistics Storage

There are two options for storing account statistics for trading:

1. expand class account_statistics_object by adding a map of trade_statistics_object for each asset
2. create a new type trade_statistics_object and a new index
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You'll need a statistic for every base asset (think USD) that you have traded.
Also stats should be reset after x weeks (4)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Of course, there will be many of such objects per user (for each asset).
trade_statistics_objects will be stored in trade_statistics_index ordered by statistics object owner (user), asset.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This can clutter the up the current state database significantly. Please indicate how garbage collection will work

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We plan to collect garbage while maintenance interval once a day in order to remove old data from the index.



## Statistics Update
Statistics updates during fill_order.
We need to update statistics for the user and for the specific asset at the same time.



## Calculations

### Average since Day 1

**Trader Activity** is estimated as average trading volume of a user for a given asset for 1 day.

`Trader_activity = total_volume / (Now - first_start_date) //(in days).`

This way we accumulate total bought volume for each user for each asset and average out daily volumes for his entire term of trading of this asset (per day).

Volume discounts are estimated based on the average daily `Trader_Activity * 30 days.`

_Trade statistics object_


```
class trade_statistics_object
OpenLedgerApp marked this conversation as resolved.
Show resolved Hide resolved
{

account_id_type owner;
asset_id_type asset;
timestamp first_trade_date; //first trade date for this asset
share_type total_volume; //total bought asset volume
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can't use share_type for this data due to the high possibility of overflow. I guess a 128-bit data type would be sufficient, and in the implementation still need to deal with overflows.

};
```

### 30-day sliding window average

In **trade_statistics_object** we need to store the queue of volumes aggregated by 1 day. In other words, for each asset a user should have a queue of 30 daily volumes.

During the first maintenance interval of the day, yesterday's volume will be added to the queue and the oldest volume will be deleted (for each asset even for assets where there was no trade done).
OpenLedgerApp marked this conversation as resolved.
Show resolved Hide resolved

This way it will cost significant memory usage!!

Technically we can store only the aggregated sum for 30 days and take the first day volumes from the blockchain. This will take less memory but will take more CPU time.


### 30-day volume method

Alternative way would be to store one 30-day volume for each asset for each user. This way we would only need one 30-day volume and one aggregated daily volume for today. i.e. only 2 values for each asset.

So the memory requirements will be at least 30 times less than in a previous method.

The algorithm is like this:

```
For example, the 30-day volume is 90. Hence daily average is 3.
Let's say today's volume is 13.
First of all, we subtract average daily volume from the 30-day volume. 90-3 =87.
Then we add today's volume. So the new 30-day volume would be 87+13 = 100.
A new daily average would be 100/30 = 3.33333
```

### 365-day sliding window average

This is similar to the 30-day sliding window average except the memory requirements for the stored values are SIGNIFICANTLY larger.

## Potential issues
We need to make sure that the suggested calculations will not lead to the significantly wrong results or the blockchain abuse.
We need to consider border conditions: For example, when there is no statistics at all, unusual statistics of many very small orders, very large order at the beginning of the average window and then no activity registered, etc.


## Technical challenges
Some problems include performance as an additional search and update new index are required.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add a easy-to-understand Summary for the Shareholders

What are the additional leverages created for BTS holders, what are the benefits? Also, where are the risks?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Dynamic market fee is an additional marketing tool to encourage traders. So, this BSIP helps to boost trading volume on BitShares and attract new traders to the ecosystem.

# Copyright
This document is placed in the public domain.

# See Also

High-level proposal and discussion https://github.com/bitshares/bsips/issues/130

# CORE TEAM TASK LIST
- [ ] Evaluate / Prioritize Feature Request
- [ ] Refine User Stories / Requirements
- [ ] Define Test Cases
- [ ] Design / Develop Solution
- [ ] Perform QA/Testing
- [ ] Update Documentation