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

Prática quantitativa de câmbio DEX (1) -- Guia do usuário do dYdX v4

Criado em: 2024-12-24 17:09:32, atualizado em: 2024-12-26 21:41:46
comments   0
hits   1049

[TOC]

Prática quantitativa de câmbio DEX (1) – Guia do usuário do dYdX v4

Prefácio

Com o rápido crescimento das exchanges descentralizadas (DEX) no campo de negociação de criptomoedas, os traders quantitativos começaram gradualmente a recorrer a essas plataformas para negociações automatizadas eficientes. Como uma das plataformas de negociação descentralizadas mais populares, a dYdX fornece funções de negociação poderosas e suporta negociação de contratos perpétuos de futuros. Sua versão mais recente v4 otimiza o desempenho e a experiência do usuário, tornando-a a primeira escolha para muitos traders quantitativos.

Este artigo apresentará como praticar negociação quantitativa no dYdX v4, incluindo como usar sua API para negociar, obter dados de mercado e gerenciar contas.

  • Troca de ambiente de teste
  • Consulta de informações de mercado
  • Consulta de informações de pedido e informações de posição
  • Faça um pedido
  • Gerenciamento de subcontas
  • Solicitação de método de nó

dYdX v4 DEX

  • Página do aplicativo dYdX Testnet

Prática quantitativa de câmbio DEX (1) – Guia do usuário do dYdX v4

  • edYdX v3Da mesma forma, as transações geram recompensas, recompensasdYdXFichas.

Prática quantitativa de câmbio DEX (1) – Guia do usuário do dYdX v4

Informações de conexão, login e configuração da carteira

A troca DEX do protocolo dYdX v3 anterior está offline. O endereço atual do aplicativo dYdX v4 é:

https://dydx.trade/trade/ETH-USD

Após abrir a página do App, há um botão para conectar à carteira no canto superior direito. Escaneie o código QR para conectar à carteira.

Se você quiser testar e se familiarizar com o ambiente de rede de teste primeiro, você pode usar a rede de teste:

https://v4.testnet.dydx.exchange/trade/ETH-USD

Além disso, clique no botão conectar carteira no canto superior direito, escaneie o código QR para conectar-se à carteira e verifique a assinatura. Após a carteira ser conectada com sucesso, um endereço dydx v4 será gerado automaticamente. Este endereço será exibido no canto superior direito da página do aplicativo. Um menu aparecerá após clicar nele. Isso inclui operações como recarga, saque e transferência. Uma das diferenças entre a mainnet dYdX (ambiente de produção) e a testnet é que quando você clica no botão de recarga na testnet, 300 USDC em ativos serão automaticamente depositados na faucet para teste. Se você quiser fazer transações reais no dYdX, você precisa depositar ativos USDC. A recarga também é muito conveniente e compatível com múltiplos ativos e cadeias.

  • Endereço da conta dYdX v4 O endereço da conta dYdX v4 é derivado do endereço da carteira. O endereço da conta dYdX v4 se parece com isso:dydx1xxxxxxxxxxxxxxxxxxxxq2ge5jr4nzfeljxxxx, é o endereço que começa com dydx1. Este endereço pode ser consultado em exploradores de blockchain.

  • Mnemônicos Você pode exportar o mnemônico da conta de endereço dYdX atual clicando no botão “Exportar senha” no menu do canto superior direito. Ao adicionar uma bolsa na plataforma FMZ, você precisa configurar este mnemônico.

Os mnemônicos podem ser configurados diretamente na plataforma FMZ ou salvos localmente no custodiante. Ao usar o objeto de troca dydx v4, o conteúdo do arquivo que grava os mnemônicos será lido, o que será demonstrado na parte prática deste artigo.

Diferenças entre Mainnet e Testnet

O ambiente testnet é diferente do ambiente mainnet em alguns aspectos. Aqui estão algumas diferenças simples.

  • Transferência de ativos de subconta. A rede principal tem um mecanismo de limpeza de subcontas.subAccountNumber >= 128Se a subconta com esse ID não tiver posições, os ativos serão automaticamente compensados ​​para a subconta com subAccountNumber 0. Durante os testes, foi descoberto que a rede de teste não tinha tal mecanismo (ou as condições de disparo eram diferentes e ele não havia sido disparado na rede de teste).

  • Alguns nomes simbólicos. O token nativo dydx tem um nome diferente: MainnetDYDX, rede de testeDv4TNT

  • Configuração de endereço, como ID da cadeia, endereço do nó, endereço do indexador, etc. Existem muitos nós e configurações, aqui está um deles:

    • Rede principal: Endereço do indexador:https://indexer.dydx.trade ID da cadeia:dydx-mainnet-1 Nó REST:https://dydx-dao-api.polkachu.com:443

    • Rede de teste: Endereço do indexador:https://indexer.v4testnet.dydx.exchange ID da cadeia:dydx-testnet-4 Nó REST:https://dydx-testnet-api.polkachu.com

Arquitetura do protocolo dYdX v4

O protocolo dYdX v4 é desenvolvido com base no ecossistema cosmos. O conteúdo relacionado à transação do sistema DEX dYdX v4 consiste principalmente em duas partes:

  • Um indexador responsável por consultar informações de mercado, informações de contas, etc.
  • mensagens de pedidos do blockchain dydx, mensagens de cancelamento de pedidos, mensagens de transferência, etc.

Indexador

O serviço indexador fornece protocolos REST e Websocket.

  • Protocolo REST A interface do protocolo REST oferece suporte à consulta de informações de mercado, informações de conta, informações de posição, informações de pedidos, etc., e foi encapsulada como uma interface de API unificada na plataforma FMZ.

  • Protocolo WebSocket Na plataforma FMZ, você pode usar a função Dial para criar uma conexão Websocket e assinar informações de mercado.

Deve-se notar que o indexador dydx v4 tem o mesmo problema que a troca centralizada, ou seja, as atualizações de dados não são tão oportunas. Por exemplo, às vezes o pedido pode não ser encontrado ao consultar imediatamente após fazer um pedido. Recomenda-se que após determinadas operações (Sleep(n)) Aguarde alguns segundos antes de consultar novamente.

Aqui está um exemplo de uso da função Dial para criar uma conexão de API Websocket e assinar dados do livro de pedidos:

function dYdXIndexerWSconnManager(streamingPoint) {
    var self = {}
    self.base = streamingPoint
    self.wsThread = null

    // 订阅
    self.CreateWsThread = function (msgSubscribe) {
        self.wsThread = threading.Thread(function (streamingPoint, msgSubscribe) {
            // 订单薄
            var orderBook = null 

            // 更新订单薄
            var updateOrderbook = function(orderbook, update) {
                // 更新 bids
                if (update.bids) {
                    update.bids.forEach(([price, size]) => {
                        const priceFloat = parseFloat(price)
                        const sizeFloat = parseFloat(size)

                        if (sizeFloat === 0) {
                            // 删除价格为 price 的买单
                            orderbook.bids = orderbook.bids.filter(bid => parseFloat(bid.price) !== priceFloat)
                        } else {
                            // 更新或新增买单
                            orderbook.bids = orderbook.bids.filter(bid => parseFloat(bid.price) !== priceFloat)
                            orderbook.bids.push({price: price, size: size})
                            // 按价格降序排序
                            orderbook.bids.sort((a, b) => parseFloat(b.price) - parseFloat(a.price))
                        }
                    })
                }

                // 更新 asks
                if (update.asks) {
                    update.asks.forEach(([price, size]) => {
                        const priceFloat = parseFloat(price)
                        const sizeFloat = parseFloat(size)

                        if (sizeFloat === 0) {
                            // 删除价格为 price 的卖单
                            orderbook.asks = orderbook.asks.filter(ask => parseFloat(ask.price) !== priceFloat)
                        } else {
                            // 更新或新增卖单
                            orderbook.asks = orderbook.asks.filter(ask => parseFloat(ask.price) !== priceFloat)
                            orderbook.asks.push({price: price, size: size})
                            // 按价格升序排序
                            orderbook.asks.sort((a, b) => parseFloat(a.price) - parseFloat(b.price))
                        }
                    })
                }

                return orderbook
            }

            var conn = Dial(`${streamingPoint}|reconnect=true&payload=${JSON.stringify(msgSubscribe)}`)
            if (!conn) {
                Log("createWsThread failed.")
                return
            }
            while (true) {
                var data = conn.read()
                if (data) {
                    var msg = null                    
                    try {
                        msg = JSON.parse(data)
                        if (msg["type"] == "subscribed") {
                            orderBook = msg["contents"]
                            threading.currentThread().postMessage(orderBook)
                        } else if (msg["type"] == "channel_data") {
                            orderBook = updateOrderbook(orderBook, msg["contents"])
                            threading.currentThread().postMessage(orderBook)
                        }
                    } catch (e) {
                        Log("e.name:", e.name, "e.stack:", e.stack, "e.message:", e.message)
                    }
                }
            }
        }, streamingPoint, msgSubscribe)
    }

    // 监听
    self.Peek = function () {
        return self.wsThread.peekMessage()
    }

    return self
}

function main() {
    // real : wss://indexer.dydx.trade/v4/ws
    // simulate : wss://indexer.v4testnet.dydx.exchange/v4/ws

    var symbol = "ETH-USD"
    var manager = dYdXIndexerWSconnManager("wss://indexer.dydx.trade/v4/ws")
    manager.CreateWsThread({"type": "subscribe", "channel": "v4_orderbook", "id": symbol})

    var redCode = "#FF0000"
    var greenCode = "#006400"
    while (true) {
        var depthTbl = {type: "table", title: symbol + " / depth", cols: ["level", "price", "amount"], rows: []}
        var depth = manager.Peek()
        if (depth) {
            for (var i = 0; i < depth.asks.length; i++) {
                if (i > 9) {
                    break
                }
                var ask = depth.asks[i]
                depthTbl.rows.push(["asks " + (i + 1) + greenCode, ask.price + greenCode, ask.size + greenCode])
            }
            depthTbl.rows.reverse()

            for (var i = 0; i < depth.bids.length; i++) {
                if (i > 9) {
                    break
                }
                var bid = depth.bids[i]
                depthTbl.rows.push(["bids " + (i + 1) + redCode, bid.price + redCode, bid.size + redCode])
            }
        }
        LogStatus(_D(), "\n`" + JSON.stringify(depthTbl) + "`")
    }
}

transmissão de mensagem de nó de cadeia dYdX

As mensagens mais comumente usadas em transações são mensagens de pedido, mensagens de cancelamento de pedido e mensagens de transferência.

  • Resumo da mensagem do pedido
  {
    "@type": "/dydxprotocol.clob.MsgPlaceOrder",
    "order": {
      "orderId": {
        "subaccountId": {
          "owner": "xxx"
        },
        "clientId": xxx,
        "orderFlags": 64,
        "clobPairId": 1
      },
      "side": "SIDE_BUY",
      "quantums": "2000000",
      "subticks": "3500000000",
      "goodTilBlockTime": 1742295981
    }
  }
  • Ordem Limitada: Na função de ordem encapsulada na plataforma FMZ, o valor orderFlags usado para ordens limitadas é:ORDER_FLAGS_LONG_TERM = 64 # 长期订单De acordo com as limitações do protocolo DYDX v4, é utilizado o maior período de validade de pedidos, que é de 90 dias (todos os tipos de pedidos no DYDX v4 têm um período de validade).

  • Ordem de Mercado: Na função de ordem encapsulada na plataforma FMZ, o valor orderFlags usado pela ordem de mercado é:ORDER_FLAGS_SHORT_TERM = 0 # 短期订单, de acordo com as recomendações do protocolo DYDX v4:

    // Recommend set to oracle price - 5% or lower for SELL, oracle price + 5% for BUY

    Como não é uma ordem de mercado verdadeira, o preço do oráculo é usado, mais ou menos 5% de deslizamento como ordem de mercado. A configuração do período de validade de ordens de curto prazo também é diferente daquela de ordens de longo prazo. Ordens de curto prazo usam o período de validade da altura do bloco. De acordo com a recomendação do dydx v4, ele é definido para o bloco atual + 10 alturas de bloco antes que expire.

  • ID do pedido: Como a operação de ordem é realizada diretamente na cadeia, não haverá ID de ordem gerada pelo indexador após a transmissão da mensagem, e a ordem do indexador não pode ser usada como o valor de retorno da função de ordem da plataforma. Para garantir a exclusividade do ID do pedido e da precisão da consulta do pedido, o pedido do indexador é retornado. O ID do pedido consiste nas seguintes informações (separadas por vírgula):

    • Pares de negociação
    • endereço da conta corrente dydx
    • Número da subconta (subaccountNumber)
    • clientId (gerado aleatoriamente)
    • clobPairId (ID do símbolo de transação)
    • orderFlags
    • goodTilData (milissegundos)
  • Resumo da mensagem de cancelamento do pedido

  {
    "@type": "/dydxprotocol.clob.MsgCancelOrder",
    "orderId": {
      "subaccountId": {
        "owner": "xxx"
      },
      "clientId": 2585872024,
      "orderFlags": 64,
      "clobPairId": 1
    },
    "goodTilBlockTime": 1742295981
  }

O ID do pedido retornado pela interface de pedidos da plataforma FMZ precisa ser informado.

  • Resumo da mensagem de transferência
  {
    "@type": "/dydxprotocol.sending.MsgCreateTransfer",
    "transfer": {
      "sender": {
        "owner": "xxx"
      },
      "recipient": {
        "owner": "xxx",
        "number": 128
      },
      "amount": "10000000"
    }
  }

Muitas subcontas podem ser criadas sob o endereço dydx v4 atual. A subconta com subAccountNumber 0 é a primeira subconta criada automaticamente. O ID da subconta com subAccountNumber maior ou igual a 128 é usado para negociação de posição isolada, que requer pelo menos 20 ativos USDC. Por exemplo, você pode ir de subAccountNumber 0 -> 128, ou de subAccountNumber 128 -> 0. A transferência requer o consumo de Taxa de Gás. A taxa de gás pode usar tokens USDC e dydx.

Plataforma FMZ dYdX v4 prática

O conteúdo acima explica brevemente alguns detalhes de empacotamento. Em seguida, vamos praticar o uso específico. Aqui usamos a rede de teste dYdX v4 para demonstração. A rede de teste é basicamente a mesma que a rede principal, e há uma torneira automática para receber ativos de teste . O custodiante implanta Não entrarei em detalhes sobre a operação e criarei um teste real no FMZ.

1. Configuração

Após conectar-se com sucesso ao aplicativo dYdX v4 usando uma carteira de criptomoeda (eu uso a carteira imToken aqui), reivindique seus ativos de teste e exporte o mnemônico para sua conta dYdX v4 atual (derivado de sua carteira).

Prática quantitativa de câmbio DEX (1) – Guia do usuário do dYdX v4

Configure o mnemônico na plataforma FMZ. Aqui usamos o método de arquivo local para configurá-lo (você também pode preenchê-lo diretamente e configurá-lo para a plataforma. O mnemônico é configurado após a criptografia, não em texto simples).

  • Arquivo mnemônico: mnemonic.txt

Prática quantitativa de câmbio DEX (1) – Guia do usuário do dYdX v4

Coloque-o no diretório da pasta real disk ID sob o diretório custodian. Claro, ele também pode ser colocado em outros diretórios (o caminho específico precisa ser escrito durante a configuração).

  • Configurar a troca na FMZ

https://www.fmz.com/m/platforms/add

Preencha a caixa de edição mnemônica:file:///mnemonic.txt, o caminho real correspondente é:托管者所在目录/logs/storage/594291

Prática quantitativa de câmbio DEX (1) – Guia do usuário do dYdX v4

2. Mude para a rede de teste dydx v4

function main() {
    // 切换测试链的索引器地址
    exchange.SetBase("https://indexer.v4testnet.dydx.exchange")

    // 切换测试链的ChainId 
    exchange.IO("chainId", "dydx-testnet-4")

    // 切换测试链的REST节点地址
    exchange.IO("restApiBase", "https://dydx-testnet-api.polkachu.com")

    // 读取账户信息测试
    Log(exchange.GetAccount()) 
}

Leia as informações da conta da rede de teste:

{
	"Info": {
		"subaccounts": [{
			"address": "dydx1fzsndj35a26maujxff88q2ge5jr4nzfeljn2ez",
			"subaccountNumber": 0,
			"equity": "300.386228",
			"latestProcessedBlockHeight": "28193227",
			"freeCollateral": "300.386228",
			"openPerpetualPositions": {},
			"assetPositions": {
				"USDC": {
					"subaccountNumber": 0,
					"size": "300.386228",
					"symbol": "USDC",
					"side": "LONG",
					"assetId": "0"
				}
			},
			"marginEnabled": true,
			"updatedAtHeight": "28063818"
		}, {
			"address": "dydx1fzsndj35a26maujxff88q2ge5jr4nzfeljn2ez",
			"equity": "0",
			"freeCollateral": "0",
			"openPerpetualPositions": {},
			"marginEnabled": true,
			"subaccountNumber": 1,
			"assetPositions": {},
			"updatedAtHeight": "27770289",
			"latestProcessedBlockHeight": "28193227"
		}, {
			"equity": "0",
			"openPerpetualPositions": {},
			"marginEnabled": true,
			"updatedAtHeight": "28063818",
			"latestProcessedBlockHeight": "28193227",
			"subaccountNumber": 128,
			"freeCollateral": "0",
			"assetPositions": {},
			"address": "dydx1fzsndj35a26maujxff88q2ge5jr4nzfeljn2ez"
		}],
		"totalTradingRewards": "0.021744179376211564"
	},
	"Stocks": 0,
	"FrozenStocks": 0,
	"Balance": 300.386228,
	"FrozenBalance": 0,
	"Equity": 300.386228,
	"UPnL": 0
}

3. Consulta de informações de mercado

Não mudou para a rede de teste, testado com a rede principal

function main() {
    var markets = exchange.GetMarkets()
    if (!markets) {
        throw "get markets error"
    }
    var tbl = {type: "table", title: "test markets", cols: ["key", "Symbol", "BaseAsset", "QuoteAsset", "TickSize", "AmountSize", "PricePrecision", "AmountPrecision", "MinQty", "MaxQty", "MinNotional", "MaxNotional", "CtVal"], rows: []}
    for (var symbol in markets) {
        var market = markets[symbol]
        tbl.rows.push([symbol, market.Symbol, market.BaseAsset, market.QuoteAsset, market.TickSize, market.AmountSize, market.PricePrecision, market.AmountPrecision, market.MinQty, market.MaxQty, market.MinNotional, market.MaxNotional, market.CtVal])
    }
    LogStatus("`" + JSON.stringify(tbl) +  "`")
}

Prática quantitativa de câmbio DEX (1) – Guia do usuário do dYdX v4

4. Faça um pedido

function main() {
    // 切换测试链的索引器地址
    exchange.SetBase("https://indexer.v4testnet.dydx.exchange")

    // 切换测试链的ChainId 
    exchange.IO("chainId", "dydx-testnet-4")

    // 切换测试链的REST节点地址
    exchange.IO("restApiBase", "https://dydx-testnet-api.polkachu.com")

    // 限价单,挂单
    var idSell = exchange.CreateOrder("ETH_USD.swap", "sell", 4000, 0.002)
    var idBuy = exchange.CreateOrder("ETH_USD.swap", "buy", 3000, 0.003)

    // 市价单
    var idMarket = exchange.CreateOrder("ETH_USD.swap", "buy", -1, 0.01)

    Log("idSell:", idSell)
    Log("idBuy:", idBuy)
    Log("idMarket:", idMarket)
}

Prática quantitativa de câmbio DEX (1) – Guia do usuário do dYdX v4

Página do aplicativo dYdX v4:

Prática quantitativa de câmbio DEX (1) – Guia do usuário do dYdX v4

5. Informações do pedido

A rede de testes faz dois pedidos com antecedência, testa a obtenção dos pedidos pendentes atuais e cancela os pedidos.

function main() {    
    // 切换测试链的索引器地址
    exchange.SetBase("https://indexer.v4testnet.dydx.exchange")

    // 切换测试链的ChainId 
    exchange.IO("chainId", "dydx-testnet-4")

    // 切换测试链的REST节点地址
    exchange.IO("restApiBase", "https://dydx-testnet-api.polkachu.com")

    var orders = exchange.GetOrders()
    Log("orders:", orders)
    for (var order of orders) {
        exchange.CancelOrder(order.Id, order)
        Sleep(2000)
    }

    var tbl = {type: "table", title: "test GetOrders", cols: ["Id", "Price", "Amount", "DealAmount", "AvgPrice", "Status", "Type", "Offset", "ContractType"], rows: []}
    for (var order of orders) {
        tbl.rows.push([order.Id, order.Price, order.Amount, order.DealAmount, order.AvgPrice, order.Status, order.Type, order.Offset, order.ContractType])
    }
    LogStatus("`" + JSON.stringify(tbl) +  "`")
}

Prática quantitativa de câmbio DEX (1) – Guia do usuário do dYdX v4

6. Consulta de informações de posição

function main() {
    // 切换测试链的索引器地址
    exchange.SetBase("https://indexer.v4testnet.dydx.exchange")

    // 切换测试链的ChainId 
    exchange.IO("chainId", "dydx-testnet-4")

    // 切换测试链的REST节点地址
    exchange.IO("restApiBase", "https://dydx-testnet-api.polkachu.com")

    var p1 = exchange.GetPositions("USD.swap")
    var p2 = exchange.GetPositions("ETH_USD.swap")
    var p3 = exchange.GetPositions()
    var p4 = exchange.GetPositions("SOL_USD.swap")

    var tbls = []
    for (var positions of [p1, p2, p3, p4]) {
        var tbl = {type: "table", title: "test GetPosition/GetPositions", cols: ["Symbol", "Amount", "Price", "FrozenAmount", "Type", "Profit", "Margin", "ContractType", "MarginLevel"], rows: []}
        for (var p of positions) {
            tbl.rows.push([p.Symbol, p.Amount, p.Price, p.FrozenAmount, p.Type, p.Profit, p.Margin, p.ContractType, p.MarginLevel])
        } 
        tbls.push(tbl)
    }

    LogStatus("`" + JSON.stringify(tbls) +  "`")
}

Prática quantitativa de câmbio DEX (1) – Guia do usuário do dYdX v4

7. Gestão de subcontas

function main() {
    // 切换测试链的索引器地址
    exchange.SetBase("https://indexer.v4testnet.dydx.exchange")

    // 切换测试链的ChainId 
    exchange.IO("chainId", "dydx-testnet-4")

    // 切换测试链的REST节点地址
    exchange.IO("restApiBase", "https://dydx-testnet-api.polkachu.com")

    // subAccountNumber 0 -> 128 : 20 USDC , Gas Fee 为 adv4tnt 即 dydx token
    var ret = exchange.IO("transferUSDCToSubaccount", 0, 128, "adv4tnt", 20)  
    Log("ret:", ret)

    // 切换到子账号subAccountNumber 128 ,读取账户信息检查
    exchange.IO("subAccountNumber", 128)

    var account = exchange.GetAccount()
    Log("account:", account)
}

Prática quantitativa de câmbio DEX (1) – Guia do usuário do dYdX v4

Mude para a subconta cujo subAccountNumber é 128, e os dados retornados por GetAccount são:

{
	"Info": {
		"subaccounts": [{
			"subaccountNumber": 0,
			"assetPositions": {
				"USDC": {
					"size": "245.696892",
					"symbol": "USDC",
					"side": "LONG",
					"assetId": "0",
					"subaccountNumber": 0
				}
			},
			"updatedAtHeight": "28194977",
			"latestProcessedBlockHeight": "28195008",
			"address": "dydx1fzsndj35a26maujxff88q2ge5jr4nzfeljn2ez",
			"freeCollateral": "279.5022142346",
			"openPerpetualPositions": {
				"ETH-USD": {
					"closedAt": null,
					"size": "0.01",
					"maxSize": "0.01",
					"exitPrice": null,
					"unrealizedPnl": "-0.17677323",
					"subaccountNumber": 0,
					"status": "OPEN",
					"createdAt": "2024-12-26T03:36:09.264Z",
					"createdAtHeight": "28194494",
					"sumClose": "0",
					"netFunding": "0",
					"market": "ETH-USD",
					"side": "LONG",
					"entryPrice": "3467.2",
					"realizedPnl": "0",
					"sumOpen": "0.01"
				}
			},
			"marginEnabled": true,
			"equity": "280.19211877"
		}, {
			"openPerpetualPositions": {},
			"assetPositions": {},
			"marginEnabled": true,
			"latestProcessedBlockHeight": "28195008",
			"address": "dydx1fzsndj35a26maujxff88q2ge5jr4nzfeljn2ez",
			"subaccountNumber": 1,
			"equity": "0",
			"freeCollateral": "0",
			"updatedAtHeight": "27770289"
		}, {
			"openPerpetualPositions": {},
			"updatedAtHeight": "28194977",
			"latestProcessedBlockHeight": "28195008",
			"address": "dydx1fzsndj35a26maujxff88q2ge5jr4nzfeljn2ez",
			"subaccountNumber": 128,
			"assetPositions": {
				"USDC": {
					"assetId": "0",
					"subaccountNumber": 128,
					"size": "20",
					"symbol": "USDC",
					"side": "LONG"
				}
			},
			"marginEnabled": true,
			"equity": "20",
			"freeCollateral": "20"
		}],
		"totalTradingRewards": "0.021886899964446858"
	},
	"Stocks": 0,
	"FrozenStocks": 0,
	"Balance": 20,
	"FrozenBalance": 0,
	"Equity": 20,
	"UPnL": 0
}

Pode-se observar que a subconta com subAccountNumber 128 transferiu 20 USDC.

8. Obtenha TxHash e chame a interface do nó REST

De acordo com a ordem, obtenha TxHash e teste o método de IO chamando o nó REST

Como obter o TxHash de uma ordem? O objeto de troca dydx armazenará em cache o TxHash, que pode ser consultado usando o ID da ordem. Entretanto, após a estratégia parar, o mapa de hash de transação de ordem armazenado em cache será limpo.

function main() {
    // 切换测试链的索引器地址
    exchange.SetBase("https://indexer.v4testnet.dydx.exchange")

    // 切换测试链的ChainId 
    exchange.IO("chainId", "dydx-testnet-4")

    // 切换测试链的REST节点地址
    exchange.IO("restApiBase", "https://dydx-testnet-api.polkachu.com")

    var id1 = exchange.CreateOrder("ETH_USD.swap", "buy", 3000, 0.002)
    var hash1 = exchange.IO("getTxHash", id1)
    Log("id1:", id1, "hash1:", hash1)

    var id2 = exchange.CreateOrder("ETH_USD.swap", "buy", 2900, 0.003)
    var hash2 = exchange.IO("getTxHash", id2)
    Log("id2:", id2, "hash2:", hash2)
    
    // 清空映射表可以使用:exchange.IO("getTxHash", "")
    var arr = [hash1, hash2]
    
    Sleep(10000)
    for (var txHash of arr) {
        // GET https://docs.cosmos.network   /cosmos/tx/v1beta1/txs/{hash}
        var ret = exchange.IO("api", "GET", "/cosmos/tx/v1beta1/txs/" + txHash)
        Log("ret:", ret)
    }
}

Prática quantitativa de câmbio DEX (1) – Guia do usuário do dYdX v4

Mensagens consultadas por meio do TxHash:

var ret = exchange.IO(“api”, “GET”, “/cosmos/tx/v1beta1/txs/” + txHash)

O conteúdo é muito longo, então aqui estão alguns trechos para demonstração:

{
	"tx_response": {
		"codespace": "",
		"code": 0,
		"logs": [],
		"info": "",
		"height": "28195603",
		"data": "xxx",
		"raw_log": "",
		"gas_wanted": "-1",
		"gas_used": "0",
		"tx": {
			"@type": "/cosmos.tx.v1beta1.Tx",
			"body": {
				"messages": [{
					"@type": "/dydxprotocol.clob.MsgPlaceOrder",
					"order": {
						"good_til_block_time": 1742961542,
						"condition_type": "CONDITION_TYPE_UNSPECIFIED",
						"order_id": {
							"clob_pair_id": 1,
							"subaccount_id": {
								"owner": "xxx",
								"number": 0
							},
							"client_id": 2999181974,
							"order_flags": 64
						},
						"side": "SIDE_BUY",
						"quantums": "3000000",
						"client_metadata": 0,
						"conditional_order_trigger_subticks": "0",
						"subticks": "2900000000",
						"time_in_force": "TIME_IN_FORCE_UNSPECIFIED",
						"reduce_only": false
					}
				}],
				"memo": "FMZ",
				"timeout_height": "0",
				"extension_options": [],
				"non_critical_extension_options": []
			},
      ...

THE END

Os testes acima são baseados no custodian mais recente. Você precisa baixar o custodian mais recente para dar suporte ao dYdX v4 DEX

Obrigado pelo seu apoio e obrigado pela leitura.