avatar of 发明者量化-小小梦 发明者量化-小小梦
konzentrieren Sie sich auf Private Nachricht
4
konzentrieren Sie sich auf
1271
Anhänger

Entwurf und Implementierung einer Überwachung der DEX-CEX-Börsenpreisunterschiede basierend auf der FMZ-Quantifizierung

Erstellt in: 2025-02-21 10:40:52, aktualisiert am: 2025-02-21 13:53:00
comments   0
hits   1232

Entwurf und Implementierung einer Überwachung der DEX-CEX-Börsenpreisunterschiede basierend auf der FMZ-Quantifizierung

Mehrere DEX-Börsen, darunter dydx_v4, hyperliquid, vertex und aevo, wurden auf FMZ gekapselt und verbunden. Da der Wettbewerb um Preisarbitrage an zentralisierten Börsen immer härter wird, haben viele quantitative Händler ihre Aufmerksamkeit auf dezentralisierte Börsen gerichtet. In diesem Artikel besprechen wir das Design und die Implementierung der Preisunterschiedsüberwachung zwischen DEX und CEX.

Der erste Schritt der Hedging-Arbitrage-Strategie besteht darin, die Preisdifferenz des Zielportfolios zu berechnen und zu beobachten und zu analysieren, ob Handelsmöglichkeiten bestehen. Daher ist die Entwicklung und Implementierung einer Preisdifferenzüberwachungsstrategie die erste grundlegende Aufgabe. Unsere Designanforderungen sind:

  • Die verwendete Programmiersprache ist Javascript.
  • Verwenden Sie die gekapselte REST-Schnittstelle.
  • DEX-Auswahl: Hyperliquid, Vertex.
  • CEX-Auswahl: Binance, Bybit.
  • Zum Anfordern von Auftragsbuchdaten werden gleichzeitige Anforderungen mit mehreren Threads verwendet.
  • Die Testprodukte sollten so weit wie möglich die Mainstream-Produkte sein, die von allen Börsen gemeinsam genutzt werden: ETH, BTC Spot-Handelspaare/unbefristete Verträge
  • Versuchen Sie, das Design zu vereinfachen und eine grundlegende Implementierung mit einfachem und leicht verständlichem Code bereitzustellen.

Code-Implementierung

Der Code umfasst weniger als 200 Zeilen und seine Funktion besteht lediglich darin, die Echtzeit-Preisdifferenz eines bestimmten Produkts an verschiedenen Börsen zu berechnen. Wenn die Strategie zum ersten Mal ausgeführt wird, werden alle für die Strategie konfigurierten Austauschobjekte in DEX-Gruppen und CEX-Gruppen eingeteilt. Jede Abfrage wird über die von der FMZ-Plattform gekapselte Multithread-Funktion Thread durchgeführt und fordert gleichzeitig die REST-Schnittstelle an: die Orderbuch-SchnittstelleGetDepth, erfassen Sie die gewünschten Kaufbestelllisten- und Verkaufsbestelllistendaten der benötigten Sorten. Anschließend werden die DEX-Gruppe und die CEX-Gruppe zu einer Differenzkombination (DEX-CEX-Kombination bzw. Arbitragepaar) zusammengefasst und die Preisdifferenz berechnet.

Bestimmung der Austauschart: Während der Initialisierung wird das hinzugefügte Austauschobjekt beurteilt, um festzustellen, ob es sich um Spot oder Futures handelt.

Verschiedene Börsen können für einen bestimmten Basiswert unterschiedliche Namen haben, daher muss der Name des Produkts angepasst werden: Das Programm muss entsprechend den Benennungsregeln der Symbole verschiedener Börsen angepasst werden. Beispielsweise werden die Handelspaare von Vertex-Kontrakten wie folgt benannt:XXX_USD, bei dem es sich eigentlich um einen unbefristeten Vertrag auf USDC-Basis handelt. Der Name von ETH an der Stelle von Vertex ist WETH.

Holen Sie sich Präzision: Während der Initialisierung werden sämtliche Marktinformationen abgerufen. Je nach angefordertem Symbol kann die entsprechende Genauigkeit für nachfolgende Datengenauigkeitsverarbeitungsvorgänge abgefragt werden.

Datenanforderung Bevor alle Tiefendaten abgerufen werden, wartet das Programm und prüft weiter, ob es Börsen gibt, deren Daten nicht aktualisiert wurden. Wenn die Daten nicht abgerufen werden konnten, schläft das Programm für 100 Millisekunden. Die angeforderten Auftragsbuchdaten werden in einem durch threading.Dict() erstellten Objekt aufgezeichnet (wird für die Interaktion mit gleichzeitigen Threads verwendet) und die Daten werden am Ende jeder Abfrage zurückgesetzt.

Zusammenfassen Diese Strategieumsetzung zeigt, wie man Preisunterschiede an mehreren Börsen in Echtzeit überwacht und mögliche Arbitragemöglichkeiten berechnet. Durch angemessene Symbolkorrektur, umfassende Datenerfassung, präzise Steuerung und Multithread-Betrieb kann das System Preisunterschiede in Echtzeit effizient überwachen. Für Strategielernende kann das Verständnis der Implementierungsideen dieses Codes dabei helfen, die Verwendung der API zum Abrufen von Transaktionsdaten, die Verarbeitung von Daten von mehreren Börsen, die Berechnung und Ausgabe von Transaktionsspreads und die Anwendung dieser Technologien in tatsächlichen Transaktionen zu erlernen.

let symbolList = []

function createEx(idx, exs) {
    let self = {}
    
    let cexEidList = ["Binance", "Bybit", "Futures_Binance", "Futures_Bybit"]
    let dexEidList = ["Vertex", "Hyperliquid", "Futures_Hyperliquid", "Futures_Vertex"]

    self.name = exs[idx].GetName()
    self.idx = idx
    self.e = exs[idx]
    self.depths = threading.Dict()
    self.markets = self.e.GetMarkets()

    if (!self.markets) {
        throw "GetMarkets error"
    }

    if (dexEidList.includes(self.name)) {
        self.type = "DEX"
    } else if (cexEidList.includes(self.name)) {
        self.type = "CEX"
    } else {
        throw "not support " + self.name
    }

    if (self.name.startsWith("Futures_")) {
        self.isFutures = true
    } else {
        self.isFutures = false
    }

    self.correctSymbol = function(symbol) {        
        if (self.name == "Vertex") {
            let correctList = {"BTC_USDC": "WBTC_USDC", "ETH_USDC": "WETH_USDC"}
            if (typeof(correctList[symbol]) != "undefined") {
                return correctList[symbol]
            }
        } else if (self.name == "Hyperliquid") {
            let correctList = {"BTC_USDC": "UBTC_USDC"}
            if (typeof(correctList[symbol]) != "undefined") {
                return correctList[symbol]
            }
        } else if (self.name == "Futures_Hyperliquid") {
            return symbol.replace("_USDC", "_USD")
        }
        
        return symbol
    }

    self.reqDepth = function(symbol) {
        symbol = self.correctSymbol(symbol)
        threading.Thread(function(idx, symbol, threadingDict) {
            let depth = exchanges[idx].GetDepth(symbol)
            if (depth) {
                threadingDict.set(symbol, depth)
            } else {
                threadingDict.set(symbol, null)
            }
        }, self.idx, symbol, self.depths)
    }
    
    self.getPrecision = function(symbol) {
        symbol = self.correctSymbol(symbol)
        let marketInfo = self.markets[symbol]
        if (marketInfo) {
            return [marketInfo.PricePrecision, marketInfo.AmountPrecision]
        } else {
            return [8, 8]
        }
    }

    self.init = function() {
        self.depths = threading.Dict()
    }

    self.getDepth = function(symbol) {
        symbol = self.correctSymbol(symbol)
        return self.depths.get(symbol)
    }

    return self
}

function createManager(symbolList, exs) {
    let self = {}

    self.symbolList = symbolList
    self.exchanges = []
    self.hedgePair = []

    self.initHedgePair = function () {
        for (let i in exs) {
            let ex = createEx(i, exs)
            self.exchanges.push(ex)
        }

        let arrDEX = self.exchanges.filter(item => item.type == "DEX")
        let arrCEX = self.exchanges.filter(item => item.type == "CEX")

        for (let dex of arrDEX) {
            for (let cex of arrCEX) {
                self.hedgePair.push({"dex": dex, "cex": cex})
            }
        }
    }

    self.calcHedgeData = function () {
        let beginTimestamp = new Date().getTime()
        for (let e of self.exchanges) {
            for (let symbol of self.symbolList) {
                e.reqDepth(symbol)
            }
        }

        while (true) {
            let isWait = false
            for (let e of self.exchanges) {
                for (let symbol of self.symbolList) {
                    let depth = e.getDepth(symbol)
                    if (depth == null || typeof(depth) == "undefined") {
                        isWait = true
                    }
                }
            }
            if (isWait) {
                Sleep(100)
            } else {
                break
            }
        }

        let tbls = []
        for (let symbol of self.symbolList) {
            let tbl = {"type": "table", "title": symbol + "差价", "cols": ["pair", "bid-ask", "ask-bid", "dex ask", "dex bid", "cex ask", "cex bid"], "rows": []}
            for (let p of self.hedgePair) {
                let dex = p["dex"]
                let cex = p["cex"]

                let pricePrecision = Math.max(dex.getPrecision(symbol)[0], cex.getPrecision(symbol)[0])

                let dexDepth = dex.getDepth(symbol)
                let cexDepth = cex.getDepth(symbol)
                if (dexDepth && cexDepth) {
                    p["bid-ask"] = _N(dexDepth.Bids[0].Price - cexDepth.Asks[0].Price, pricePrecision)
                    p["ask-bid"] = _N(dexDepth.Asks[0].Price - cexDepth.Bids[0].Price, pricePrecision)

                    // 输出信息、观察测试
                    Log(dex.name, cex.name, symbol, "bid-ask:", p["bid-ask"], ", ask-bid", p["ask-bid"])

                    p[dex.name + "-ask"] = dexDepth.Asks[0].Price + "/" + dexDepth.Asks[0].Amount
                    p[dex.name + "-bid"] = dexDepth.Bids[0].Price + "/" + dexDepth.Bids[0].Amount
                    p[cex.name + "-ask"] = cexDepth.Asks[0].Price + "/" + cexDepth.Asks[0].Amount
                    p[cex.name + "-bid"] = cexDepth.Bids[0].Price + "/" + cexDepth.Bids[0].Amount
                } else {
                    p["bid-ask"] = "--"
                    p["ask-bid"] = "--"
                    p[dex.name + "-ask"] = "--"
                    p[dex.name + "-bid"] = "--"
                    p[cex.name + "-ask"] = "--"
                    p[cex.name + "-bid"] = "--"
                }

                let pairName = dex.name + "-" + cex.name
                tbl["rows"].push([pairName, p["bid-ask"], p["ask-bid"], p[dex.name + "-ask"], p[dex.name + "-bid"], p[cex.name + "-ask"], p[cex.name + "-bid"]])
            }
            tbls.push(tbl)
        }
                
        for (let e of self.exchanges) {
            e.init()
        }

        let endTimestamp = new Date().getTime()
        return [tbls, (endTimestamp - beginTimestamp) + "毫秒"]
    }

    self.initHedgePair()
    return self
}

function main() {
    LogReset(1)
    let loopCount = 0

    symbolList = strSymbolList.split(",")
    let m = createManager(symbolList, exchanges)
    while (true) {
        let ret = m.calcHedgeData()
        loopCount++
        LogStatus(_D(), "耗时:", ret[1], ", 轮询次数:", loopCount, "\n", "`" + JSON.stringify(ret[0]) + "`")
        Sleep(1000)
    }
}

Parameterdesign:

Entwurf und Implementierung einer Überwachung der DEX-CEX-Börsenpreisunterschiede basierend auf der FMZ-Quantifizierung

Spotmarkt

Überwachen Sie ein Spotprodukt:

  • BTC_USDC Bitcoin zu USDC Spot

Entwurf und Implementierung einer Überwachung der DEX-CEX-Börsenpreisunterschiede basierend auf der FMZ-Quantifizierung

Vertragsmarkt

Überwachen Sie zwei Varianten:

  • ETH_USDC.swap Ethereum-Dauervertrag
  • BTC_USDC.swap Bitcoin-Dauervertrag

Entwurf und Implementierung einer Überwachung der DEX-CEX-Börsenpreisunterschiede basierend auf der FMZ-Quantifizierung

END

Ausdehnungsrichtung:

  • Schwellenwertüberwachung und Kapselung der Transaktionslogik.
  • Berechnen Sie die Gebühren und Kosten und kalkulieren Sie den angemessenen Spread-Bereich für die Absicherung.
  • Verwenden Sie die WebSocket-Schnittstelle, um Marktdaten abzurufen.

Die FMZ-Plattform wird ihren technischen Support für dezentrale Börsen (DEX) und dezentrale Finanzen (DeFi) weiter ausbauen und Funktionen und Produkte kontinuierlich weiterentwickeln und aktualisieren.

Vielen Dank fürs Lesen.