Logo

dev-resources.site

for different kinds of informations.

The Logic of Crypto Currency Futures Trading

Published at
6/18/2024
Categories
trading
cryptocurrency
futures
fmzquant
Author
fmzquant
Author
8 person written this
fmzquant
open
The Logic of Crypto Currency Futures Trading

Problem scene

For a long time, the data delay problem of the API interface of the crypto currency exchange has always troubled me. I haven't found a suitable way to deal with it. I will reproduce the scene of this problem.

Usually the market order provided by the contract exchange is actually the counterparty price, so sometimes the so-called "market order" is somewhat unreliable. Therefore, when we write crypto currency futures trading strategies, most of them use limit orders. After each order is placed, we need to check the position to see if the order is filled and the corresponding position is held.

The problem lies in this position information. If the order is closed, the data returned by the exchange position information interface (that is, the exchange interface that the bottom layer actually accesses when we call exchange.GetPosition) should contain the information of the newly opened position, but If the data returned by the exchange is old data, that is, the position information of the order just placed before the transaction is completed, this will cause a problem.

The trading logic may consider that the order has not been filled and continue to place the order. However, the order placement interface of the exchange is not delayed, but the transaction is fast, and the order is executed. This will cause a serious consequence that the strategy will repeatedly place orders when triggering the operation of opening a position.

Actual Experience

Because of this problem, I have seen a strategy to fill a long position crazy, fortunately, the market was risen at that time, and the floating profit once exceeded 10BTC. Fortunately, the market has skyrocketed. If it is a plunge, the ending can be imagined.

Try To Solve

  • Plan 1
    It is possible to design the logic of order placement for the strategy to place only one order. The order placing price is a large slippage for the price gap of opponent price at the time, and a certain depth of opponent orders can be executed. The advantage of this is that only one order is placed, and it is not judged based on position information. This can avoid the problem of repeated placing orders, but sometimes when the price changes relatively large, the order will trigger the exchange's price limit mechanism, and it may lead to that the large slippage order is still not completed, and missed the trading opportunity.

  • Plan 2
    Using the "market price" function of the exchange, the price pass -1 on the FMZ is the "market price". At present, the OKEX futures interface has been upgraded to support "real market price".

  • Plan 3
    We still use the previous trading logic and place a limit order, but we add some detection to the trading logic to try to solve the problem caused by the delay of the position data. After the order is placed, if the order is not cancelled, it disappears directly in the list of pending orders (the list of pending orders disappears in two possible ways: 1 withdraw order, 2 executed), detect such situation and place the order amount again. The amount of the last order is the same. At this time, it is necessary to pay attention to whether the position data is delayed. Let the program enter the waiting logic to reacquire the position information. You can even continue to optimize and increase the number of triggering waits. If it exceeds a certain number of times, the position interface data is delayed. The problem is serious, let the transaction logic terminate.

Design based on Plan 3

// Parameter
/*
var MinAmount = 1
var SlidePrice = 5
var Interval = 500
*/

function GetPosition(e, contractType, direction) {
    e.SetContractType(contractType)
    var positions = _C(e.GetPosition);
    for (var i = 0; i < positions.length; i++) {
        if (positions[i].ContractType == contractType && positions[i].Type == direction) {
            return positions[i]
        }
    }

    return null
}

function Open(e, contractType, direction, opAmount) {
    var initPosition = GetPosition(e, contractType, direction);
    var isFirst = true;
    var initAmount = initPosition ? initPosition.Amount : 0;
    var nowPosition = initPosition;
    var directBreak = false 
    var preNeedOpen = 0
    var timeoutCount = 0
    while (true) {
        var ticker = _C(e.GetTicker)
        var needOpen = opAmount;
        if (isFirst) {
            isFirst = false;
        } else {
            nowPosition = GetPosition(e, contractType, direction);
            if (nowPosition) {
                needOpen = opAmount - (nowPosition.Amount - initAmount);
            }
            // Detect directBreak and the position has not changed
            if (preNeedOpen == needOpen && directBreak) {
                Log("Suspected position data is delayed, wait 30 seconds", "#FF0000")
                Sleep(30000)
                nowPosition = GetPosition(e, contractType, direction);
                if (nowPosition) {
                    needOpen = opAmount - (nowPosition.Amount - initAmount);
                }
                /*
                timeoutCount++
                if (timeoutCount > 10) {
                    Log("Suspected position delay for 10 consecutive times, placing order fails!", "#FF0000")
                    break
                }
                */
            } else {
                timeoutCount = 0
            }
        }
        if (needOpen < MinAmount) {
            break;
        }

        var amount = needOpen;
        preNeedOpen = needOpen
        e.SetDirection(direction == PD_LONG ? "buy" : "sell");
        var orderId;
        if (direction == PD_LONG) {
            orderId = e.Buy(ticker.Sell + SlidePrice, amount, "Open long position", contractType, ticker);
        } else {
            orderId = e.Sell(ticker.Buy - SlidePrice, amount, "Open short position", contractType, ticker);
        }

        directBreak = false
        var n = 0
        while (true) {
            Sleep(Interval);
            var orders = _C(e.GetOrders);
            if (orders.length == 0) {
                if (n == 0) {
                    directBreak = true
                }
                break;
            }
            for (var j = 0; j < orders.length; j++) {
                e.CancelOrder(orders[j].Id);
                if (j < (orders.length - 1)) {
                    Sleep(Interval);
                }
            }
            n++
        }
    }

    var ret = {
        price: 0,
        amount: 0,
        position: nowPosition
    };
    if (!nowPosition) {
        return ret;
    }
    if (!initPosition) {
        ret.price = nowPosition.Price;
        ret.amount = nowPosition.Amount;
    } else {
        ret.amount = nowPosition.Amount - initPosition.Amount;
        ret.price = _N(((nowPosition.Price * nowPosition.Amount) - (initPosition.Price * initPosition.Amount)) / ret.amount);
    }
    return ret;
}

function Cover(e, contractType, opAmount, direction) {
    var initPosition = null;
    var position = null;
    var isFirst = true;

    while (true) {
        while (true) {
            Sleep(Interval);
            var orders = _C(e.GetOrders);
            if (orders.length == 0) {
                break;
            }
            for (var j = 0; j < orders.length; j++) {
                e.CancelOrder(orders[j].Id);
                if (j < (orders.length - 1)) {
                    Sleep(Interval);
                }
            }
        }

        position = GetPosition(e, contractType, direction)
        if (!position) {
            break
        }
        if (isFirst == true) {
            initPosition = position;
            opAmount = Math.min(opAmount, initPosition.Amount)
            isFirst = false;
        }

        var amount = opAmount - (initPosition.Amount - position.Amount)
        if (amount <= 0) {
            break
        }

        var ticker = _C(exchange.GetTicker)
        if (position.Type == PD_LONG) {
            e.SetDirection("closebuy");
            e.Sell(ticker.Buy - SlidePrice, amount, "Close long position", contractType, ticker);
        } else if (position.Type == PD_SHORT) {
            e.SetDirection("closesell");
            e.Buy(ticker.Sell + SlidePrice, amount, "Close short position", contractType, ticker);
        }

        Sleep(Interval)
    }

    return position
}

$.OpenLong = function(e, contractType, amount) {
    if (typeof(e) == "string") {
        amount = contractType
        contractType = e
        e = exchange
    }

    return Open(e, contractType, PD_LONG, amount);
}

$.OpenShort = function(e, contractType, amount) {
    if (typeof(e) == "string") {
        amount = contractType
        contractType = e
        e = exchange
    }

    return Open(e, contractType, PD_SHORT, amount);
};

$.CoverLong = function(e, contractType, amount) {
    if (typeof(e) == "string") {
        amount = contractType
        contractType = e
        e = exchange
    }

    return Cover(e, contractType, amount, PD_LONG);
};

$.CoverShort = function(e, contractType, amount) {
    if (typeof(e) == "string") {
        amount = contractType
        contractType = e
        e = exchange
    }

    return Cover(e, contractType, amount, PD_SHORT);
};


function main() {
    Log(exchange.GetPosition())
    var info = $.OpenLong(exchange, "quarter", 100)
    Log(info, "#FF0000")

    Log(exchange.GetPosition())
    info = $.CoverLong(exchange, "quarter", 30)
    Log(exchange.GetPosition())
    Log(info, "#FF0000")

    info = $.CoverLong(exchange, "quarter", 80)
    Log(exchange.GetPosition())
    Log(info, "#FF0000")
}
Enter fullscreen mode Exit fullscreen mode

Template address: https://www.fmz.com/strategy/203258

The way to call the template interface is just like $.OpenLong and $.CoverLong in the main function above.

The template is a beta version, any suggestions are welcome, i will continue to optimize to deal with the problem of delays in position data.

From: https://www.fmz.com/digest-topic/5908

fmzquant Article's
30 articles in total
Favicon
FMZ Funding Rate Acquisition and Monitoring Strategy
Favicon
Exploring FMZ: Practice of Communication Protocol Between Live Trading Strategies
Favicon
Exploring FMZ: New Application of Status Bar Buttons (Part 1)
Favicon
Detailed Explanation of FMZ Quant API Upgrade: Improving the Strategy Design Experience
Favicon
FMZ Quant & OKX: How Do Ordinary People Master Quantitative Trading? The Answers Are All Here!
Favicon
Detailed Explanation of Digital Currency Pair Trading Strategy
Favicon
Preliminary Study on Backtesting of Digital Currency Options Strategy
Favicon
Add an alarm clock to the trading strategy
Favicon
Quantitative typing rate trading strategy
Favicon
Use trading terminal plug-in to facilitate manual trading
Favicon
Balance strategy and grid strategy
Favicon
Graphical Martingale Trading Strategy
Favicon
Introduction to the Source Code of Digital Currency Pair Trading Strategy and the Latest API of FMZ Platform
Favicon
Multi-robot market quotes sharing solution
Favicon
Evaluation of backtest capital curve using "pyfolio" tool
Favicon
Bottom shape ZDZB strategy
Favicon
Python version iceberg commission strategy
Favicon
Python version iceberg commission strategy
Favicon
The Logic of Crypto Currency Futures Trading
Favicon
Analysis and Realization of Commodity Futures Volume Footprint Chart
Favicon
High-frequency backtest system based on each transaction and the defects of K-line backtest
Favicon
Interfacing with FMZ robot using "Tradingview" indicator
Favicon
Some Thoughts on the Logic of Crypto Currency Futures Trading
Favicon
Solution of numerical calculation accuracy problem in JavaScript strategy design
Favicon
Teach you to encapsulate a Python strategy into a local file
Favicon
Teach you to implement a market quotes collector
Favicon
Python Version Commodity Futures Moving Average Strategy
Favicon
Market quotes collector upgrade again
Favicon
FMZ simulation level backtest mechanism explanation
Favicon
Commodity Futures High Frequency Trading Strategy written by C++

Featured ones: