High frequency strategies for digital currencies

Author: The grass, Created: 2023-03-10 10:09:13, Updated: 2023-09-18 20:13:58

img

[TOC] I wrote an article in 2020 about high-frequency strategies, and I'm sure you've heard about them.https://www.fmz.com/digest-topic/6228Although it has received a lot of attention, it is not very in-depth. More than two years have passed, and the market has changed. After the publication of the article, my high-frequency strategy has been able to make a steady profit for a long time, but the slow profit has gradually decreased or even stopped.

Conditions for high-frequency trading

  • The current maker returns a commission of one hundred thousandth of 5 if the daily trading volume is 100 million U, and the commission is 5000 U. Of course, the taker is still based on the VIP rate, so if the strategy does not need to be paid, the VIP level does not have much effect on the high-frequency strategy. Generally, different levels of exchanges have different return rates, which need to maintain a high transaction rate.

  • Speed. The high-frequency policy is called high-frequency because it is fast. Joining an exchange colo server to get the lowest latency and the most stable connection is also one of the conditions for the internal volume. The internal time of the policy should also be as low as possible.

  • The right market. High-frequency trading is known as the pearl of quantitative trading. I believe that many programmatic traders have tried, but most people should stop because they do not make money and can not find a way to improve, the main reason should be to find the wrong trading market. The initial stage of the strategy should find a relatively easy market to make money to trade, so that the advantage is also improved feedback, which favors the progress of the strategy.

  • Facing competition. Any trading market is dynamically changing, no trading strategy can be done once and for all, high-frequency trading is more obvious, entering this market is directly competing with a group of the smartest, most diligent traders. In a zero-sum market, you earn more than others earn less.

High frequency principle

High-frequency strategies are divided into several types:

  • High-frequency hedging, the opportunity to find a hedge through this exchange or other exchanges, to profit from the advantage of speed to grab orders
  • High-frequency trends, profiting by judging short-term trends
  • As a market trader, you can register transactions on both sides of the trade, control your holdings, and make a profit by taking a commission back.
  • Many others, not all described.

My strategy is a combination of trends and marketers, first determining trends, then listing orders, immediately listing and selling after the transaction, without holding stock positions, below is a combination of strategy code introduction.

Strategic architecture

The following code is an architecture based on the Binance Perpetual Contract, which mainly subscribes to the websocket deep-depth order flow trades market, and position position information. Since market and account information are separate subscriptions, it is necessary to constantly use read ((-1) to determine whether to get the latest information, here the EventLoop ((1000) is used, avoiding direct dead loops, reducing the system load.

var datastream = null
var tickerstream = null
var update_listenKey_time = 0

function ConncetWss(){
    if (Date.now() - update_listenKey_time < 50*60*1000) {
        return
    }
    if(datastream || tickerstream){
        datastream.close()
        tickerstream.close()
    }
    //需要APIKEY
    let req = HttpQuery(Base+'/fapi/v1/listenKey', {method: 'POST',data: ''}, null, 'X-MBX-APIKEY:' + APIKEY) 
    let listenKey = JSON.parse(req).listenKey
    datastream = Dial("wss://fstream.binance.com/ws/" + listenKey + '|reconnect=true', 60)
    //Symbols是设定的交易对
    let trade_symbols_string = Symbols.toLowerCase().split(',')
    let wss_url = "wss://fstream.binance.com/stream?streams="+trade_symbols_string.join(Quote.toLowerCase()+"@aggTrade/")+Quote.toLowerCase()+"@aggTrade/"+trade_symbols_string.join(Quote.toLowerCase()+"@depth20@100ms/")+Quote.toLowerCase()+"@depth20@100ms"
    tickerstream = Dial(wss_url+"|reconnect=true", 60)
    update_listenKey_time = Date.now()
}

function ReadWss(){
    let data = datastream.read(-1)
    let ticker = tickerstream.read(-1)
    while(data){
        data = JSON.parse(data)
        if (data.e == 'ACCOUNT_UPDATE') {
            updateWsPosition(data)
        }
        if (data.e == 'ORDER_TRADE_UPDATE'){
            updateWsOrder(data)
        }        
        data = datastream.read(-1)
    }
    while(ticker){
        ticker = JSON.parse(ticker).data
        if(ticker.e == 'aggTrade'){
            updateWsTrades(ticker)
        }
        if(ticker.e == 'depthUpdate'){
            updateWsDepth(ticker)
        }
        ticker = tickerstream.read(-1)
    }
    makerOrder()
}

function main() {
    while(true){
        ConncetWss()
        ReadWss()
        worker()
        updateStatus()
        EventLoop(1000)
    }
}

Strategic indicators

As mentioned earlier, my high-frequency strategy requires the trend to be judged and then to execute a trade. Judging short-term trends is mainly based on transaction-by-transaction data, i.e. aggTrade in the subscription, which includes transaction direction, price, quantity, transaction time, etc. The main reference for buying and selling is depth and volume.

  • The average transaction volume per transaction, which is the sum of orders in the same direction and different prices within 100 ms, reflects the size of the buy and sell orders. This data weight is high, and it can be assumed that the buyer-dominated market is the case if the volume of orders is greater than the sales order.
  • Order frequency or order interval, also based on transaction-by-transit data, the previous average transaction is regardless of the concept of time, not entirely accurate, if the order in one direction although the average transaction is small, but the frequency is high, also contributes to the intensity of this direction. Average transaction * order frequency represents the total transaction at a fixed interval, can be used for direct comparison.
  • The average bid/ask spread, which is easier to understand, is selling one minus buying one. Most of the current bid/ask is a one-tick spread, and if the bid/ask spread is larger, it often represents a market emergence.
  • Average purchase price, calculating the average price of each transaction, and comparing it to the most recent price. For example, the most recent purchase price is greater than the average purchase price, which can be used to determine a breakthrough.

Strategic logic

Judging short-term trends

//bull代表短期看涨,bear短期看跌
let bull =  last_sell_price > avg_sell_price && last_buy_price > avg_buy_price &&
            avg_buy_amount / avg_buy_time > avg_sell_amount / avg_sell_time;
let bear =  last_sell_price < avg_sell_price && last_buy_price < avg_buy_price && 
            avg_buy_amount / avg_buy_time < avg_sell_amount / avg_sell_time;

If the latest sell price is higher than the average price of the sale order, the latest buy price is higher than the average price of the purchase order, and the value of the fixed interval buy is higher than the value of the sale order, then the short-term bullishness is judged.

Price of the order

function updatePrice(depth, bid_amount, ask_amount) {

    let buy_price = 0
    let sell_price = 0
    let acc_bid_amount = 0
    let acc_ask_amount = 0

    for (let i = 0; i < Math.min(depth.asks.length, depth.bids.length); i++) {
        acc_bid_amount += parseFloat(depth.bids[i][1])
        acc_ask_amount += parseFloat(depth.asks[i][1])
        if (acc_bid_amount > bid_amount  && buy_price == 0) {
            buy_price = parseFloat(depth.bids[i][0]) + tick_size
        }
        if (acc_ask_amount > ask_amount  && sell_price == 0) {
            sell_price = parseFloat(depth.asks[i][0]) - tick_size
        }
        if (buy_price > 0 && sell_price > 0) {
            break
        }
    }
    return [buy_price, sell_price]
}

Here, the old idea is to iterate the depth to the required amount, assuming a payment of 10 coins can be made within 1s, without taking into account the new order, the selling price is set to the position of the 10 coins.

Number of subscribers

let buy_amount = Ratio * avg_sell_amount / avg_sell_time
let sell_amount = Ratio * avg_buy_amount / avg_buy_time

Ratio represents a fixed ratio, where the quantity ordered represents a fixed proportion of the number of orders sold most recently. This strategy adapts itself to the size of the order based on the current activity.

Conditions

if(bull && (sell_price-buy_price) > N * avg_diff) {
    trade('buy', buy_price, buy_amount)
}else if(position.amount < 0){
    trade('buy', buy_price, -position.amount)
}
if(bear && (sell_price-buy_price) >  N * avg_diff) {
    trade('sell', sell_price, sell_amount)
}else if(position.amount > 0){
    trade('sell', sell_price, position.amount)
}

where avg_diff is the difference in the average discount, only when the current order buy/sell difference is greater than a certain multiple of this value and the buyer will only pay when the buyer is looking, if the empty order is held, this time will also be flat, avoiding long-term receipts. The buyer can place only-maker orders, ensuring that the order is transacted.

Concurrent architecture

var tasks = []
var jobs = []

function worker(){
    let new_jobs = []
    for(let i=0; i<tasks.length; i++){
        let task = tasks[i]
        jobs.push(exchange.Go.apply(this, task.param))
    }
    _.each(jobs, function(t){
        let ret = t.wait(-1)
        if(ret === undefined){
            new_jobs.push(t)//未返回的任务下次继续等待
        }
    })
    jobs = new_jobs
    tasks = []
}

/*
需要的任务参数写在param里
tasks.push({'type':'order','param': ["IO", "api", "POST","/fapi/v1/order",
        "symbol="+symbol+Quote+"&side="+side+"&type=LIMIT&timeInForce=GTX&quantity="+
        amount+"&price="+price+"&newClientOrderId=" + UUID() +"&timestamp="+Date.now()]})
*/

Monitored data

  • The importance of delay, high-frequency strategy speed has been emphasized, and the strategy should monitor and record various delays, such as down-order, withdrawal, position return, depth, order flow, position, overall cycle, etc.
  • The percentage of total transactions is calculated as the percentage of total transactions, and if the percentage is low, there is room to increase. At peak times, it is also possible for the strategic share to reach more than 10% of total transactions.
  • The flat rate of return, the statistically averaged flat rate of return, is the most important reference for judging the effectiveness of a strategy.
  • The percentage of returns on commissions, the statistical return on commissions as a percentage of total earnings, reflects the degree of dependency of the strategy on returns on commissions. Trading all different levels of returns, unprofitable strategies may be profitable if the return on commissions is one level higher.
  • The order failure rate is the rate at which the order is only pending, and may not be able to hang due to the delay of the order. If this rate is high, the speed of the strategy is not good.
  • The percentage of orders that are processed, platforms often have requirements for the process rate, if it is too low, indicates that the policy withdrawal is too frequent and needs to be addressed.
  • The average buy-sell order distance, which reflects the gap between the strategic order and the discount, can be seen to be largely occupied by the buy-sell position.

Other suggestions

  • Trading multi-currency, the high-frequency strategy of this article belongs to the single-currency market of single-exchange single-currency market, the limitations are large, most cases and most currencies are unprofitable, but it is also impossible to predict which currency will be profitable in the future, so you can trade multiple or even all currencies, do not miss the opportunity. Even with the frequency limit of the exchange, a robot can also trade multiple pairs of transactions, of course for optimal speed, one sub-account can trade one transaction, one server to one robot, just so the cost will be much higher.
  • Depending on the rate of return, the volume and conditions of the order are determined. Trading multi-currency will result in too high a cost of trying, if the monitoring is not profitable, use the minimum trading volume and reduce the frequency of trading until the strategic dynamic monitoring yield is positive, then gradually increase the trading volume to increase the return.
  • To get more information, high-frequency trading has another characteristic: more data is processed, more information is used. All market information on a single exchange's order-to-order pair should be referenced, and can also be referenced permanently to the data of the spot, or to the data of other exchanges on the same transaction, or even to other currencies. The more data, the greater the corresponding advantage.
  • Binance's servers are located in Tokyo, while other exchanges' servers are different, and exchange technicians can be consulted.
  • The policy code in this article is just a simple example code, removing a lot of cumbersome but necessary details, and the indicators used are for reference only, not direct use. The real running of a high-frequency policy requires a lot of attention to detail, which requires patience and refinement.

Related

More

mztcoinGod of the Grass

DANGOUGod of the Grass

77924998Which AWS server does Grasshopper use?

xukittyI'm not going to lie.

bwxiaokGrasshopper has a paid high-frequency program

My heart is still.Do you think this strategy works if you can make a copy?

Written by TradeManCalling Grasshopper, hoping to teach more, learn how to get into high-frequency trading

~ A wave in the wind ~Bully

fmzeroThe grass is greasy!

Orc quantifiedBully

The grassIt's too hard, it doesn't make much sense.