avatar of 发明者量化-小小梦 发明者量化-小小梦
focar em Mensagem privada
4
focar em
1271
Seguidores

Projeto e implementação de monitoramento de diferença de preço de câmbio DEX-CEX com base na quantificação FMZ

Criado em: 2025-02-21 10:40:52, atualizado em: 2025-02-21 13:53:00
comments   0
hits   1232

Projeto e implementação de monitoramento de diferença de preço de câmbio DEX-CEX com base na quantificação FMZ

Várias exchanges DEX, incluindo dydx_v4, hyperliquid, vertex e aevo, foram encapsuladas e conectadas na FMZ. À medida que a competição por arbitragem de preços em exchanges centralizadas se torna cada vez mais acirrada, muitos traders quantitativos voltaram sua atenção para exchanges descentralizadas. Neste artigo, discutiremos o design e a implementação do monitoramento de diferença de preços entre DEX e CEX.

O primeiro passo da estratégia de arbitragem de hedge é calcular a diferença de preço do portfólio alvo e observar e analisar se há oportunidades de negociação. Portanto, projetar e implementar uma estratégia de monitoramento de diferença de preço é a primeira tarefa básica. Nossos requisitos de design são:

  • A linguagem de programação utilizada é Javascript.
  • Use a interface REST encapsulada.
  • Seleção DEX: hiperlíquido, vértice.
  • Seleção CEX: binance, bybit.
  • A solicitação de dados do livro de pedidos usa solicitações simultâneas multithread.
  • Os produtos de teste devem ser os produtos principais compartilhados por todas as bolsas, tanto quanto possível: ETH, pares de negociação à vista BTC/contratos perpétuos
  • Tente simplificar o design e fornecer uma implementação básica usando código simples e fácil de entender.

Implementação de código

O código tem menos de 200 linhas e sua função projetada é apenas calcular a diferença de preço em tempo real de um determinado produto em diferentes bolsas. Quando a estratégia for executada inicialmente, todos os objetos de troca configurados para a estratégia serão classificados em grupo DEX e grupo CEX. Cada pesquisa é realizada por meio da função multithread Thread encapsulada pela plataforma FMZ e solicita simultaneamente a interface REST: a interface do livro de ordensGetDepth, registre os dados da lista de ordens de compra e de venda solicitadas das variedades necessárias. Em seguida, o grupo DEX e o grupo CEX são combinados em uma combinação de diferença (combinação DEX-CEX, ou seja, par de arbitragem) e a diferença de preço é calculada.

Determinação do tipo de troca: Durante a inicialização, o objeto de câmbio adicionado será julgado para determinar se é à vista ou futuro.

Diferentes bolsas podem ter nomes diferentes para um determinado ativo subjacente, então o nome do produto precisa ser ajustado: O programa precisa ser ajustado de acordo com as regras de nomenclatura de símbolos de diferentes bolsas. Por exemplo, os pares de negociação dos contratos Vertex são nomeados da seguinte forma:XXX_USD, que na verdade é um contrato perpétuo baseado em USDC. O nome do ETH no spot da Vertex é WETH.

Obtenha precisão: Durante a inicialização, todas as informações de mercado são obtidas. De acordo com o símbolo específico solicitado, a precisão correspondente pode ser consultada para operações subsequentes de processamento de precisão de dados.

Solicitação de dados Antes que todos os dados de profundidade sejam obtidos, o programa aguardará e continuará verificando se há bolsas cujos dados não foram atualizados. Se os dados não forem obtidos, o programa ficará inativo por 100 milissegundos. Os dados do livro de ordens solicitados são registrados em um objeto criado por threading.Dict() (usado para interação com threads simultâneos), e os dados são redefinidos no final de cada pesquisa.

Resumir Esta implementação de estratégia mostra como monitorar diferenças de preços em diversas bolsas em tempo real e calcular possíveis oportunidades de arbitragem. Por meio de correção de símbolos razoável, captura profunda de dados, controle de precisão e operação multithread, o sistema pode monitorar com eficiência diferenças de preços em tempo real. Para alunos de estratégia, entender as ideias de implementação deste código pode ajudá-los a dominar como usar a API para obter dados de transações, como processar dados de várias bolsas, como calcular e gerar spreads de transações e como aplicar essas tecnologias em transações reais.

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)
    }
}

Projeto de parâmetros:

Projeto e implementação de monitoramento de diferença de preço de câmbio DEX-CEX com base na quantificação FMZ

Mercado Spot

Monitore um produto spot:

  • BTC_USDC Bitcoin para USDC à vista

Projeto e implementação de monitoramento de diferença de preço de câmbio DEX-CEX com base na quantificação FMZ

Mercado de Contratos

Monitore duas variedades:

  • ETH_USDC.swap Contrato Perpétuo Ethereum
  • BTC_USDC.swap Contrato Perpétuo de Bitcoin

Projeto e implementação de monitoramento de diferença de preço de câmbio DEX-CEX com base na quantificação FMZ

END

Direção de expansão:

  • Monitoramento de limites e encapsulamento de lógica de transação.
  • Calcule as taxas e os custos e calcule a faixa de spread de hedge razoável.
  • Use a interface websocket para obter dados de mercado.

A plataforma FMZ continuará aprimorando seu suporte técnico para exchanges descentralizadas (DEX) e finanças descentralizadas (DeFi), além de iterar e atualizar continuamente funções e produtos.

Obrigado pela leitura.