Gestaltung eines FMZ-basierten Auftragssynchronmanagementsystems (1)

Schriftsteller:- Ich bin ein Idiot., Erstellt: 2022-04-06 15:08:26, Aktualisiert: 2022-04-24 18:00:51

Gestaltung eines FMZ-basierten Auftragssynchronmanagementsystems (1)

In den vorherigen Artikeln des FMZ Digest haben wir mehrere ordnungs- und positionssynchrone Strategien entwickelt.

Diese Entwürfe nehmen das Referenzkonto und das synchrone Konto in die gleiche Strategie ein, um die Synchronisierung von Aufträgen und Positionen zu realisieren.

Designdenken

Zunächst einmal brauchen wir einige gute Vorschläge und Anforderungen. Die oben genannten beiden vorherigen Orders und Positions-Synchronisierungsstrategien haben mehrere offensichtliche Nachteile. Lassen Sie uns sie gemeinsam diskutieren:

  • 1.Die Benutzer, die die Strategie-Bot-Synchronisierung implementieren, müssen über den API-Schlüssel der Referenzkontoplattform und den API-Schlüssel des Synchronisierungskontos verfügen. Für das Nutzungsszenario ist das Problem: es ist in Ordnung, wenn Ihre anderen Plattformkonten einem Ihrer eigenen Konten folgen. Aber es kann für das Szenario, in dem das Referenzkonto und das Synchronisierungskonto nicht denselben Besitzer haben, schwierig sein. Der Besitzer des Synchronisierungskontos ist manchmal aus Sicherheitsgründen nicht bereit, den API-Key seines Plattformkontos zur Verfügung zu stellen. Aber wie kann man eine Bestellung für den Handel synchron ohne die Bereitstellung des API-Key platzieren?

    Lösung: Mit der erweiterten FMZ-API muss der Inhaber des Synchronisationskontos (der Auftragsüberwacher) nur die FMZ Quant-Handelsplattform registrieren und dann eine Strategie ausführen (im in diesem Artikel entworfenen System:Order Synchronous Management System (Synchronous Server)Dann werden der erweiterte API-Key von FMZ (beachten Sie, dass es sich nicht um den API-Key des Plattformkontos handelt) und die Bot-ID des Auftrags-Synchronisierungsmanagementsystems (Synchronous Server) dem Eigentümer des Referenzkontos (dem Auftragsbesitzer) zur Verfügung gestellt. Wenn der Bot des Referenzkontoinhabers (der Auftragsinhaber) (Order Synchronous Management System Library (Single Server)In diesem Fall wird der Auftrag später automatisch platziert.

  • 2.Viele Entwickler haben bessere Strategien und können die beiden vorherigen Strategien zur Synchronisierung von Reihenfolge und Position, die oben beschrieben wurden, nicht verwenden. Weil dies ihre eigenen Strategien mit diesen Synchronisierungsstrategien zusammenführen muss, und ihre Strategien möglicherweise stark geändert werden müssen, was zeitaufwendig und arbeitsintensiv ist. Gibt es eine gute Möglichkeit, einige Ihrer ausgereiften Strategien direkt auf diejenigen mit der Reihenfolge Synchronisierungsfunktion zu aktualisieren?

    Lösung: Sie können eine synchrone Template-Bibliothek (dieOrder Synchronous Management System Library (Single Server)Strategie im im Artikel entworfenen System), so daß der Inhaber des Referenzkontos (der Auftragseigentümer) diese Vorlagenbibliothek direkt in seine eigene Strategie einfügen kann, um eine Synchronisierung von Reihenfolge und Position zu erreichen.

  • 3.Reduzieren Sie einen zusätzlichen Bot Der letzte Nachteil besteht darin, dass, wenn Sie die beiden vorherigen Befehle und die oben beschriebenen Positionssynchronisationsstrategien verwenden, eine zusätzliche Position des Referenzkontos (Konto mit Aufträgen) für die Bot-Überwachung eröffnet werden muss. Lösung: Verwenden Sie die Template-Bibliothek, um die Funktion in die Referenzkonto-Strategie einzubauen.

Das System besteht daher aus zwei Teilen: 1.Order synchrone Verwaltungssystembibliothek (Single Server) 2.Synchrone Verwaltung von Aufträgen (Synchrone Server)

Sobald wir unsere Forderungen erkannt haben, fangen wir an zu entwerfen!

Entwurf 1: Bibliothek des Synchronmanagementsystems (Single Server) bestellen

Beachten Sie, dass es sich hier nicht um eine Strategie handelt, sondern um eine FMZ-Vorlagebibliothek, die in der FMZ-API-Dokumentation durchsucht werden kann und die wir hier nicht diskutieren werden.

Code der Muster:

// Global variable
var keyName_label = "label"
var keyName_robotId = "robotId"
var keyName_extendAccessKey = "extendAccessKey"
var keyName_extendSecretKey = "extendSecretKey"
var fmzExtendApis = parseConfigs([config1, config2, config3, config4, config5])
var mapInitRefPosAmount = {}

function parseConfigs(configs) {
    var arr = []
    _.each(configs, function(config) {
        if (config == "") {
            return 
        }
        var strArr = config.split(",")
        if (strArr.length != 4) {
            throw "configs error!"
        }
        var obj = {}
        obj[keyName_label] = strArr[0]
        obj[keyName_robotId] = strArr[1]
        obj[keyName_extendAccessKey] = strArr[2]
        obj[keyName_extendSecretKey] = strArr[3]
        arr.push(obj)
    })
    return arr 
}

function getPosAmount(pos, ct) {
    var longPosAmount = 0
    var shortPosAmount = 0
    _.each(pos, function(ele) {
        if (ele.ContractType == ct && ele.Type == PD_LONG) {
            longPosAmount = ele.Amount
        } else if (ele.ContractType == ct && ele.Type == PD_SHORT) {
            shortPosAmount = ele.Amount
        }
    })
    var timestamp = new Date().getTime()
    return {ts: timestamp, long: longPosAmount, short: shortPosAmount}
}

function sendCommandRobotMsg (robotId, accessKey, secretKey, msg) {
    // https://www.fmz.com/api/v1?access_key=xxx&secret_key=yyyy&method=CommandRobot&args=[186515,"ok12345"]
    var url = "https://www.fmz.com/api/v1?access_key=" + accessKey + "&secret_key=" + secretKey + "&method=CommandRobot&args=[" + robotId + ',"' + msg + '"]'
    Log(url)
    var ret = HttpQuery(url)
    return ret 
}

function follow(nowPosAmount, symbol, ct, type, delta) {
    var msg = ""
    var nowAmount = type == PD_LONG ? nowPosAmount.long : nowPosAmount.short
    if (delta > 0) {
        // Open position
        var tradeDirection = type == PD_LONG ? "buy" : "sell"
        // Send signal
        msg = symbol + "," + ct + "," + tradeDirection + "," + Math.abs(delta)        
    } else if (delta < 0) {
        // Open position 
        var tradeDirection = type == PD_LONG ? "closebuy" : "closesell"
        if (nowAmount <= 0) {
            Log("No position detected")
            return 
        }
        // Send signal 
        msg = symbol + "," + ct + "," + tradeDirection + "," + Math.abs(delta)
    } else {
        throw "error"
    }
    if (msg) {
        _.each(fmzExtendApis, function(extendApiConfig) {
            var ret = sendCommandRobotMsg(extendApiConfig[keyName_robotId], extendApiConfig[keyName_extendAccessKey], extendApiConfig[keyName_extendSecretKey], msg)
            Log("Call CommandRobot interface,", "label:", extendApiConfig[keyName_label], ", msg:", msg, ", ret:", ret)
            Sleep(1000)
        })
    }
}

$.PosMonitor = function(exIndex, symbol, ct) {    
    var ts = new Date().getTime()
    var ex = exchanges[exIndex]
    // Judge the type of ex
    var exName = ex.GetName()
    var isFutures = exName.includes("Futures_")
    var exType = isFutures ? "futures" : "spot"
    if (!isFutures) {
        throw "Only support futures order supervising"
    }

    if (exType == "futures") {
        // Cache symbol ct
        var buffSymbol = ex.GetCurrency()
        var buffCt = ex.GetContractType()

        // Switch to the corresponding trading pair and contract code 
        ex.SetCurrency(symbol)
        if (!ex.SetContractType(ct)) {
            throw "SetContractType failed"
        }

        // Monitor position 
        var keyInitRefPosAmount = "refPos-" + exIndex + "-" + symbol + "-" + ct    // refPos-exIndex-symbol-contractType
        var initRefPosAmount = mapInitRefPosAmount[keyInitRefPosAmount]
        if (!initRefPosAmount) {
            // The data is not initialized; initialize it          
            mapInitRefPosAmount[keyInitRefPosAmount] = getPosAmount(_C(ex.GetPosition), ct)
            initRefPosAmount = mapInitRefPosAmount[keyInitRefPosAmount]
        }

        // Monitor
        var nowRefPosAmount = getPosAmount(_C(ex.GetPosition), ct)
        // Calculate position changes 
        var longPosDelta = nowRefPosAmount.long - initRefPosAmount.long
        var shortPosDelta = nowRefPosAmount.short - initRefPosAmount.short

        // Detect changes 
        if (!(longPosDelta == 0 && shortPosDelta == 0)) {
            // Execute long position action 
            if (longPosDelta != 0) {
                Log(ex.GetName(), ex.GetLabel(), symbol, ct, "Execute long position order supervision, change volume:", longPosDelta)
                follow(nowRefPosAmount, symbol, ct, PD_LONG, longPosDelta)
            }
            // Execute short position action 
            if (shortPosDelta != 0) {
                Log(ex.GetName(), ex.GetLabel(), symbol, ct, "Execute short position order supervision, change volume:", shortPosDelta)
                follow(nowRefPosAmount, symbol, ct, PD_SHORT, shortPosDelta)
            }

            // After executing the order supervision operation, update  
            mapInitRefPosAmount[keyInitRefPosAmount] = nowRefPosAmount
        }

        // Recover symbol ct
        ex.SetCurrency(buffSymbol)
        ex.SetContractType(buffCt)
    } else if (exType == "spot") {
        // Spot 
    }
}

$.getTbl = function() {
    var tbl = {
        "type" : "table", 
        "title" : "Synchrodata", 
        "cols" : [], 
        "rows" : []
    }
    // Construct the table title 
    tbl.cols.push("Monitoring account:refPos-exIndex-symbol-contractType")
    tbl.cols.push(`Mintoring position:{"timestamp":xxx,"long position volume":xxx,"short position volume":xxx}`)
    _.each(fmzExtendApis, function(extendApiData, index) {
        tbl.cols.push(keyName_robotId + "-" + index)
    })
    
    // Write in the data 
    _.each(mapInitRefPosAmount, function(initRefPosAmount, key) {
        var arr = [key, JSON.stringify(initRefPosAmount)]
        _.each(fmzExtendApis, function(extendApiData) {
            arr.push(extendApiData[keyName_robotId])
        })
        tbl.rows.push(arr)
    })

    return tbl
}

// Invocation example of the strategy in the template
function main() {
    // Clear all logs
    LogReset(1)

    //Switch to OKEX simulated bot test
    exchanges[0].IO("simulate", true)

    // Set contract 
    exchanges[0].SetCurrency("ETH_USDT")
    exchanges[0].SetContractType("swap")

    // Timed trading time interval
    var tradeInterval = 1000 * 60 * 3        // trade every three minutes, to observe the order supervising signal  
    var lastTradeTS = new Date().getTime()
    
    while (true) {
        // Other logic of the strategy...

        // Used to test the simulated trade trigger  
        var ts = new Date().getTime()
        if (ts - lastTradeTS > tradeInterval) {
            Log("Simulated strategy with orders has trades, and positions changed", "#FF0000")
            exchanges[0].SetDirection("buy")
            exchanges[0].Buy(-1, 1)
            lastTradeTS = ts
        }

        // Call the interface function in the template 
        $.PosMonitor(0, "ETH_USDT", "swap")    // You can set multiple monitors, to minitor different exchange objects in the strategy with orders
        var tbl = $.getTbl()
        
        // Display the status bar 
        LogStatus(_D(), "\n" + "`" + JSON.stringify(tbl) + "`")
        Sleep(1000)
    }
}

Das Design ist sehr einfach, die Bibliothek hat 2 Funktionen.Order Synchronous Management System Library (Single Server)Diese Strategie kann dann die folgenden Funktionen verwenden.

  • $. PosMonitor Diese Funktion hat die Aufgabe, die Positionsänderungen der Austauschobjekte in der Strategie zu überwachen und dann Handelssignale an den Bot zu senden, der in den Parametern der Vorlage: order synchronous management system library (Single Server) festgelegt ist.
  • $. GetTbl Die Funktion gibt die überwachten synchronen Daten zurück.

Das Anwendungsbeispiel istmainFunktion in der Bibliothek des ordnungssynchronen Managementsystems (Single Server):

// Invocation example of the strategy in the template 
function main() {
    // Clear all logs 
    LogReset(1)

    // Switch to OKEX simulated bot test 
    exchanges[0].IO("simulate", true)

    // Set contract 
    exchanges[0].SetCurrency("ETH_USDT")
    exchanges[0].SetContractType("swap")

    // Timed trading time interval
    var tradeInterval = 1000 * 60 * 3        // trade every three minutes, to observe the order supervising signal  
    var lastTradeTS = new Date().getTime()
    
    while (true) {
        // Other logic of the strateg...

        // Used to test the simulated trade trigger  
        var ts = new Date().getTime()
        var ts = new Date().getTime()
        if (ts - lastTradeTS > tradeInterval) {
            Log("Simulated strategy with orders has trades, and positions changed", "#FF0000")
            exchanges[0].SetDirection("buy")
            exchanges[0].Buy(-1, 1)
            lastTradeTS = ts
        }

        // Use the interface function of the template 
        $.PosMonitor(0, "ETH_USDT", "swap")    // You can set multiple monitors to monitor different exchange objects on an strategy with orders
        var tbl = $.getTbl()
        
        // Display the status bar
        LogStatus(_D(), "\n" + "`" + JSON.stringify(tbl) + "`")
        Sleep(1000)
    }
}

Eine Template-Bibliothek selbst kann auch einen Strategie-Bot erstellen, der normalerweise verwendet wird, um die Template-Bibliothek zu testen.mainFunktion in der Vorlage ist diemainSie ist eine Funktion einer Ihrer eigenen Strategien.

Der Testcode wird geschrieben, um den OKEX simulierten Bot zu testen, und der API KEY des OKEX simulierten Bots muss auf FMZ als Referenzkonto (mit Orders) konfiguriert werden, und die Hauptfunktion beginnt, auf den simulierten Bot zu wechseln. Setzen Sie dann das Handelspaar auf ETH_USDT und setzen Sie den Vertrag auf Swap. Dann geben Sie eine While-Schleife ein. In der Schleife wird alle 3 Minuten ein Auftrag platziert, um den Auslöser der Strategie-Trades zu simulieren.$.PosMonitor(0, "ETH_USDT", "swap")wird in der while-Schleife aufgerufen, und der erste Parameter der aufgerufenen Funktion ist 0, was bedeutet, dass die Exchange-Objekt-Exchanges[0], das Handelspärchen ETH_USDT und den Swap-Kontrakt überwacht werden.$.getTbl()Sie können die Informationen aus dem Diagramm erhalten und verwenden.LogStatus(_D(), "\n" + "`" + JSON.stringify(tbl) + "`")um die auf der Statusleiste angezeigten Diagrammdaten zu erstellen.

Also sehen Sie, solange$.PosMonitor(0, "ETH_USDT", "swap")wird in einer Strategie verwendet, die die Vorlage aufruft, kann die Strategie die Funktion haben, eine bestimmte Symbolposition zu überwachen und die Positionsänderungsmeldung zu senden.

Vor der Prüfung ist die Parameterkonstruktion des Prüfgerätes zu erklären.Order Synchronous Management System Library (Single Server)Strategie: Ich habe gerade darüber gesprochen, wie man die Schnittstellenfunktion der Vorlage nutzt, um ein Strategie-Upgrade mit einer Funktion der Auftragsabwicklung zu machen. Die Frage, an wen man senden soll, wird durch die Parameter derorder synchronous management system library (Single Server).

img

Sie können fünf Parameter sehen, die maximal fünf Pushes unterstützen können (wenn Sie die Push-Nummer erhöhen müssen, können Sie sie selbst erweitern); der Standard der Parameter ist eine leere Zeichenfolge, nämlich nicht verarbeitet.

  • Etikett Das Etikett des synchronen Kontos, das verwendet wird, um ein Konto zu kennzeichnen; der Etikettenname kann zufällig festgelegt werden.

  • RobotId Die Bot-ID; die Bot-ID desorder synchronous management system (Synchronous Server)vom Eigentümer des synchronen Kontos erstellt.

  • Zugriffsschlüssel Der AccessKey der FMZ erweiterte API.

  • Geheimer Schlüssel Der geheime Schlüssel der FMZ erweiterte API.

Dann können wir einen einfachen Test durchführen.

Befehl der Bot-Bedienung für die Synchronous Management System Library (Single Server):

img

Der Bot des Synchronous Management Systems (Synchronous Server) erhielt das Signal: Order Synchronous Management System (Synchronous Server) ist jetzt noch nicht vollständig von uns entworfen worden, und wir können einen einfachen Code verwenden, um es zu realisieren, ohne Handel, nur Drucksignal:

Bestellung Synchronous Management System (Synchronous Server) vorübergehender Code:

function main() {
    LogReset(1)
    while (true) {
        var cmd = GetCommand()
        if (cmd) {
            // cmd: ETH_USDT,swap,buy,1
            Log("cmd: ", cmd)
        }
        Sleep(1000)
    }
}

img

Wie Sie sehen können, erhielt der Bot des Eigentümers des synchronen Kontos die Nachricht:ETH_USDT,swap,buy,1- Ich weiß. So können wir im nächsten Schritt automatisch Aufträge nach Handelspaar, Vertragskode, Handelsrichtung und Volumen überwachen.

Derzeitorder synchronous management system (Synchronous Server)ist nur ein vorübergehender Code, und wir können seinen Entwurf im nächsten Artikel weiter besprechen.


Mehr