Einige Gedanken zur Logik des Digital-Währungs-Futures-Handels

Schriftsteller:Lydia., Erstellt: 2022-11-30 17:12:20, Aktualisiert: 2023-09-11 19:59:55

img

Einige Gedanken zur Logik des Digital-Währungs-Futures-Handels

Problemszenario

Seit langem stört mich das Datenverzögerungsproblem der Position API-Schnittstelle des digitalen Währungsaustauschs immer. Ich habe keinen ordnungsgemäßen Weg gefunden, um mit diesem Problem umzugehen. Lassen Sie mich die Szene des Problems reproduzieren. Normalerweise ist der vom Vertragsaustausch bereitgestellte Marktpreisbefehl tatsächlich der Gegenparteipreis, so dass es manchmal nicht zuverlässig ist, diesen sogenannten Marktpreisbefehl zu verwenden. Wenn wir daher digitale Währungs-Futures-Handelsstrategien schreiben, verwenden wir am meisten die Limit-Order. Nach jeder Auftragserteilung müssen wir die Position überprüfen, um zu sehen, ob die Bestellung geschlossen und die entsprechende Position gehalten wird. Das Problem liegt in dieser Informationsposition. Wenn die Bestellung geschlossen ist, sollte der Datenbefehl durch die Positionsinformationsschnittstelle der Börse zurückgegeben werden (d. h. die Schnittstelle, auf die die untere Ebene tatsächlich zugegriffen wird, wenn wir den Austausch ausfüllen.Get Position sehr

Praxiserfahrung

Aufgrund dieses Problems habe ich gesehen, wie eine Strategie voller Long-Positionen verrückt geöffnet wurde. Glücklicherweise stieg der Markt zu dieser Zeit an und der schwimmende Gewinn überstieg 10 BTC. Glücklicherweise stieg der Markt stark an. Wenn er stark sank, können wir uns das Ergebnis vorstellen.

Lösungen

  • Lösung 1 Die Strategie kann so konzipiert werden, dass nur ein Auftrag erteilt wird, und der Auftragspreis ist der Preis des aktuellen Handelsgegners plus ein großer gleitender Preis, um eine gewisse Tiefe der Auftragsgegnung des Gegners zu erreichen. Der Vorteil ist, dass nur ein Auftrag erteilt wird und nicht anhand der Positionsinformationen beurteilt wird. Dies kann das Problem der wiederholten Aufträge vermeiden, aber manchmal kann die Platzierung eines Auftrags den Preislimitmechanismus der Börse auslösen, wenn die Preisänderung relativ groß ist, und es ist möglich, den gleitenden Preis zu erhöhen und trotzdem keinen Deal zu machen, wodurch die Gelegenheit verpasst wird.

  • Lösung 2 Mit der Marktpreis-Orderfunktion der Börse wird der Preis auf - 1 auf dem FMZ als Marktpreis-Order übertragen.

  • Lösung 3 Wir verwenden immer noch die vorherige Handelslogik und platzieren Aufträge mit Preislimit-Orders, aber wir fügen etwas Erkennung in die Handelslogik hinzu, um zu versuchen, das Problem zu lösen, das durch die Verzögerung der Positionsdaten verursacht wird. Überprüfen Sie, ob die Bestellung direkt aus der Liste der ausstehenden Aufträge ohne Stornierung verschwunden ist (es gibt zwei Möglichkeiten zum Verschwinden aus der Liste der ausstehenden Aufträge: 1. Stornierung und 2. Ausgefüllt). Wenn eine solche Situation erkannt wird und die Menge der erneut platzierten Bestellung die gleiche ist wie die der letzten Bestellung, ist es wichtig zu beachten, ob die Positionsdaten verzögert sind. Lassen Sie das Programm die Wartelogik eingeben, um die Positionsinformationen wiederzuerlangen, oder sogar die Anzahl der Wartezeiten auszulösen, wenn sie eine bestimmte Anzahl von Positionsdaten überschreitet, zeigt dies an, dass die Interfaceverzögerung ernst ist, was dazu führt, dass die Handelslogik beendet wird.

Konstruktion auf der Grundlage der Lösung 3

// Parameters
/*
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);
            }
            // Check directBreak and the position remains unchanged
            if (preNeedOpen == needOpen && directBreak) {
                Log("Suspected position data is delayed, wait for 30 seconds", "#FF0000")
                Sleep(30000)
                nowPosition = GetPosition(e, contractType, direction);
                if (nowPosition) {
                    needOpen = opAmount - (nowPosition.Amount - initAmount);
                }
                /*
                timeoutCount++
                if (timeoutCount > 10) {
                    Log("Suspected position is delayed for 10 consecutive times, and the order is failed!", "#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 positions", contractType, ticker);
        } else {
            orderId = e.Sell(ticker.Buy - SlidePrice, amount, "open short positions", 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 positions", contractType, ticker);
        } else if (position.Type == PD_SHORT) {
            e.SetDirection("closesell");
            e.Buy(ticker.Sell + SlidePrice, amount, "close short positions", 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")
}

Adresse der Vorlage:https://www.fmz.com/strategy/203258

Die Schablonenoberfläche wird auf die gleiche Weise aufgerufen wie$.OpenLong, $.CoverLongin der oberen Hauptfunktion. Die Vorlage ist eine Beta-Version, und Sie sind herzlich eingeladen, Vorschläge zu machen. Wir werden sie weiterhin optimieren, damit wir mit dem Problem der Verzögerung der Positionsdaten umgehen können.


Verwandt

Mehr