Cryptocurrency trading application design

Currencies Introduction:

USDT: This a US Dollar tether, meaning that this acts like a cryptocurrency but is not a real cryptocurrency in that the price doesn’t actually change. It is a safe way to store currency on the exchange for when it does not make sense to have it in a more risky coin (for example, if BTC is going down and there are not other trades that appear beneficial for the alt coins, then it would make sense to keep the money in USDT until the situation changes).

BTC: This is is the dominant crypto-currency, it is usually more stable than the alt coins, however, it is still something that has to be actively traded, meaning that any money kept in BTC, instead of USDT, still has to be continually evaluated as holding a risk position. During times when BTC evaluating to a good hold signal it would make sense to keep currency reserves in here instead of USDT, however, if BTC is falling, it would likely make sense to keep reserves in USDT.

ALT-TYPE-1: These are currencies that can be traded from both BTC and USDT. These are usually the most popular alt-coins, such as ETH, LTC, etc.

There are most likely less than 10 of these types of alt coins at one time (like everything in crypto-currency, things can change fast)

ALT-TYPE-2: These are currencies that can be traded only from BTC. So, for these, the only possible way to trade is to have the amount needed in BTC (for example if the BTC balance is 0 but there is a balance in USDT it must first be converted to BTC to perform the trade). The disadvantage for these is that if these need to be converted to USDT (such as if BTC is not performing well at the moment so it is too risky to hold money in BTC), these must first be sold to get BTC, then that BTC would have to be sold to convert to USDT, thus incurring transaction fees twice.

There are most likely about 40-50 of these types of alt-coins that would be considered for trading.

A full list of currency pairs can be found here:

https://cryptocoincharts.info/markets/show/poloniex

Note that they have BTC or USDT as the second part of the pair, for example BTC/XRP. Internally we will always refer to a pair with either BTC or USDT first, to make things more clear, for example BTC_XRP.

Each relationship in the image below represents possible trades.

Every relationship indicates a conversion from one currency to another. These can be thought of as sales, similar to buying or selling a stock.

Each conversion is actually a transaction, however, meaning that it will incur a fee on the cryptocurrency exchange platform we are using (for now this is Poloniex, although that could change in the future).

Because of the fees involved, every potential trade / conversion has to also account for the fee to determine if it is worth doing.

Data Structures

Example time series dataset structure. For example, every 5 minutes new time series data would be loaded from poloniex. This is similar to the way that prices are reported in the stock market but instead these prices are for currency pairs. A currency pair refers to the price of a currency in terms of the other, for example, USDT_ETH is the price in USDT (which is a crypto currency that is designed to only track US Dollar directly) for ETH (Ethereum). An example is:

https://poloniex.com/exchange/#usdt_eth

For the purposes of this application, all trading calculations would be done in terms of USDT, because the base currency that it cares about gaining money in is the US Dollar. This can become confusing, because often cryptocurrency values are calculated in terms of BTC, for example, BTC_ETH.

For some currencies, Poloniex (which we use to get our time series data) only give price quotes in terms of BTC, so there are additional complications to calculating and trading these.

The data structure that is used within this application should be fully de-coupled from any exchange format, so it can be assumed that there would be a client application that calls the API to get the data and transforms it to the format that is used within this app. An application like this is relatively trivial and does not need to be part of the core application discussed in this document.

For each currency pair there would be a currencyTickSet, as in the example below. In back-testing, we would likely be working with at least 5 months worth of ticks (so that is data from every 5 minutes for 5 months). This is probably the minimum reasonable amount of data for running a back-test.

"currencyTickSet": [ [ { "time": "5:00-2017-5-11", "priceUSD": "300.00", "currencyPair": "USDT_ETH" }, { "time": "5:05-2017-5-11"", "priceUSD": "301.00", "currencyPair": "USDT_ETH" }, { "time": "5:10-2017-5-11"", "priceUSD": "302.50", "currencyPair": "USDT_ETH" }, ] ]

There would be one currencyTickSet for each currency pair, so there would probably be somewhere between 30 and 50 of these currencyTickSet’s, each of which contain the full set of ticks for that particular currency pair over the specified time period..

Algorithm

This algorithm describes back-testing as this is the initial use case, as, only once back testing is showing good results, would the algorithm be used in live trading. Live trading would be similar to this algorithm though, with some slight modifications..

Initially starts with a USDT account balance and all other accounts have a zero balance

The base iterator for the algorithm could be an integer that indicates the current tick. For example, if the time period being tested is:

March 1, 2017 - August 1, 2017

That would mean that there would be one iteration for every 5 minute period from March 1st through August 1st. This is because, the back-testing is replicating what would occur in live trading. In live trading, the application would be running at 5 minute intervals to determine what trades may be needed and then execute them.

For a tick, each currencyTickSet would be run through a function to calculate whether the current price indicates a buy or sell action. An example indicator that could be used initially is exponential moving average. This is a common indicator that seemed to show potential in the java proof of concept version of the app. This actually requires previous tick data (usually something like 26 previous ticks). So, in a back test it would iterate through the first n number of ticks until it was at a point where it had enough previous ticks to use in the calculation, only then would it start doing this calculation.

The buy / sell calculation is done completely independent of any data other than the currencyTickSet for that specific currency, meaning it only looks at the current tick for that curency and past ones, it does not look at other factors, such as tick data from other currencies, or the actual balance of that currency. Rather, it is just performing a simple analysis of whether a buy / sell is indicated, not whether one is actually possible or necessary.

The result of #3 would be two collections, one collection would be the buyCollection and the other would be the sellCollection. Each of these would contain currency pairs that corresponding to a buy / sell recommendation from step #3. There may be data for each currency that could be used to weight it against other currencies, for example, to determine if one is a “stronger” buy than another, however, this remains to be determined. It can be assumed, however, that this is a collection, not a set, so that there is no ordering to indicate this, rather, each item within the collection would need to be processed to determine this, if it did end up having any sort of “weighting” data.

This step can be thought of as an “allocator” step, in that it will have check the buyCollection and sellCollection and then also check the current account balances and determine which trades actually need to be made. At the start of this step we only know what currencies are recommended for buy / sell, but this has no basis yet in relation to our actual trading because, for example, there may be sell recommendations for currencies that we do not currently hold or there could be no currency available to spend, so buy orders would not be possible without first selling off other currencies. Possible actions that the allocator needs to perform, then, in order would be:

(Note: for back-testing we don’t require actual interaction with the Poloniex API for buying and selling, rather, it would just “mock” execute buy / sell orders at the exact price from the tick, however, the actual implementation should account for this so the code would need to be decoupled in such a way that this can be added in for live trading). It is important to keep in mind, as mentioned previously, that each transaction has a fee, so these must be accounted for when doing the actual trades in backtest. What we would want to have is to use functions that mock the behavior of interacting with the Poloniex API, so that this can do something like take an order and apply a fee, to mimic what would actually occur.

Check the sellCollection for currencies that are currently held, and then sell them. This must be done first as the funds from this may be used in the buy orders.

Submit buy orders for the buyCollection, if there is availabe currency to use for these. The actual allocation of what % of available funds to use for each currency could become complex. This must be fully decoupled from anything else, for now, we could use a basic allocation strategy of something like allocating a set % of total holdings to one currency. So, if we say that, at most, we can hold 20% of funds in one currency, then, if we are already holding 4 currencies at this point (after selling in step #1), and we have a buyCollection that has 5 currencies that have a buy indicated, only one of these could actually be processed as we would be then at 100% allocation.

The reality is that the allocation step could actually become one of the most complex parts of the entire application, as it may end up being the focal point of future improvements. So, for now, it may be best to start with having it be relatively basic but keeping in mind that it must be loosely coupled to allow for future changes. For example, we may want to create a few different allocation strategies in the future and then run a back test for each one to test which allocation strategy works better.

The process would continue with the end result being an output of data indicating total profit / loss, etc. Everything would be calculated in terms of USDT

Resources:

Useful for building JSON structures:

http://www.jsoneditoronline.org/

Useful for creating diagrams:

https://www.draw.io/

Posted on Dec 04, 2017