avatar of 发明者量化-小小梦 发明者量化-小小梦
Seguir Mensajes Privados
4
Seguir
1271
Seguidores

Práctica cuantitativa de DEX Exchange (1) -- Guía del usuario de dYdX v4

Creado el: 2024-12-24 17:09:32, Actualizado el: 2024-12-26 21:41:46
comments   0
hits   1049

[TOC]

Práctica cuantitativa de DEX Exchange (1) – Guía del usuario de dYdX v4

Prefacio

Con el rápido aumento de los intercambios descentralizados (DEX) en el campo del comercio de criptomonedas, los comerciantes cuantitativos han comenzado gradualmente a recurrir a estas plataformas para realizar operaciones automatizadas eficientes. Como una de las plataformas de negociación descentralizadas más populares, dYdX ofrece potentes funciones de negociación y admite la negociación de contratos perpetuos de futuros. Su última versión v4 optimiza el rendimiento y la experiencia del usuario, lo que la convierte en la primera opción para muchos operadores cuantitativos.

Este artículo presentará cómo practicar el trading cuantitativo en dYdX v4, incluido cómo usar su API para operar, obtener datos de mercado y administrar cuentas.

  • Cambio de entorno de prueba
  • Consulta de información del mercado
  • Información de pedidos y consulta de información de posición
  • Realizar un pedido
  • Gestión de subcuentas
  • Solicitud de método de nodo

dYdX v4 DEX

  • Página de la aplicación de la red de pruebas dYdX

Práctica cuantitativa de DEX Exchange (1) – Guía del usuario de dYdX v4

  • ydYdX v3De la misma manera, las transacciones generan recompensas, recompensasdYdXFichas.

Práctica cuantitativa de DEX Exchange (1) – Guía del usuario de dYdX v4

Información de conexión, inicio de sesión y configuración de la billetera

El intercambio DEX del protocolo dYdX v3 anterior estuvo fuera de línea. La dirección actual de la aplicación dYdX v4 es:

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

Después de abrir la página de la aplicación, hay un botón para conectarse a la billetera en la esquina superior derecha. Escanee el código QR para conectarse a la billetera.

Si desea probar y familiarizarse primero con el entorno de red de prueba, puede utilizar la red de prueba:

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

Además, haga clic en el botón conectar billetera en la esquina superior derecha, escanee el código QR para conectarse a la billetera y verificar la firma. Una vez que la billetera se haya conectado correctamente, se generará automáticamente una dirección dydx v4. Esta dirección se mostrará en la esquina superior derecha de la página de la aplicación. Aparecerá un menú después de hacer clic en él. Estas incluyen operaciones como recarga, retiro y transferencia. Una de las diferencias entre la red principal de dYdX (entorno de producción) y la red de prueba es que cuando hace clic en el botón de recarga en la red de prueba, se depositarán automáticamente 300 activos USDC en la faucet para realizar pruebas. Si desea realizar transacciones reales en dYdX, debe depositar activos en USDC. La recarga también es muy conveniente y compatible con múltiples activos y cadenas.

  • Dirección de cuenta de dYdX v4 La dirección de la cuenta de dYdX v4 se deriva de la dirección de la billetera. La dirección de la cuenta de dYdX v4 se ve así:dydx1xxxxxxxxxxxxxxxxxxxxq2ge5jr4nzfeljxxxx, es la dirección que comienza con dydx1. Esta dirección se puede consultar en los exploradores de blockchain.

  • Mnemotécnica Puede exportar el mnemónico de la cuenta de dirección dYdX actual haciendo clic en el botón “Exportar contraseña” en el menú de la esquina superior derecha. Al agregar un intercambio en la plataforma FMZ, debe configurar este mnemónico.

Los mnemónicos se pueden configurar directamente en la plataforma FMZ o guardar localmente en el custodio. Al utilizar el objeto de intercambio dydx v4, se leerá el contenido del archivo que registra los mnemónicos, lo que se demostrará en la parte práctica de este artículo.

Diferencias entre la red principal y la red de prueba

El entorno de la red de prueba es diferente del entorno de la red principal en algunos aspectos. A continuación se indican algunas diferencias simples.

  • Transferencia de activos de subcuenta. La red principal tiene un mecanismo de limpieza de subcuentas.subAccountNumber >= 128Si la subcuenta con este ID no tiene posiciones, los activos se transferirán automáticamente a la subcuenta con subAccountNumber 0. Durante las pruebas, se descubrió que la red de prueba no tenía dicho mecanismo (o las condiciones de activación eran diferentes y no se había activado en la red de prueba).

  • Algunos nombres simbólicos. El token nativo dydx se llama de manera diferente: MainnetDYDX, red de pruebaDv4TNT

  • Configuración de dirección, como ID de cadena, dirección de nodo, dirección del indexador, etc. Hay muchos nodos y configuraciones, aquí está uno de ellos:

    • Red principal: Dirección del indexador:https://indexer.dydx.trade Identificación de la cadena:dydx-mainnet-1 Nodo REST:https://dydx-dao-api.polkachu.com:443

    • Red de prueba: Dirección del indexador:https://indexer.v4testnet.dydx.exchange Identificación de la cadena:dydx-testnet-4 Nodo REST:https://dydx-testnet-api.polkachu.com

Arquitectura del protocolo dYdX v4

El protocolo dYdX v4 se desarrolló sobre la base del ecosistema cosmos. El contenido relacionado con las transacciones del sistema DEX dYdX v4 consta principalmente de dos partes:

  • Un indexador responsable de consultar información del mercado, información de cuentas, etc.
  • Mensajes de pedidos de blockchain dydx, mensajes de cancelación de pedidos, mensajes de transferencia, etc.

Indexador

El servicio de indexación proporciona protocolos REST y Websocket.

  • Protocolo REST La interfaz del protocolo REST admite consultas de información de mercado, información de cuenta, información de posición, información de pedido, etc. y se ha encapsulado como una interfaz API unificada en la plataforma FMZ.

  • Protocolo WebSocket En la plataforma FMZ, puede utilizar la función Dial para crear una conexión Websocket y suscribirse a información del mercado.

Cabe señalar que el indexador dydx v4 tiene el mismo problema que el intercambio centralizado, es decir, las actualizaciones de datos no son tan oportunas. Por ejemplo, a veces es posible que no se encuentre el pedido al realizar una consulta inmediatamente después de realizarlo. Se recomienda que después de ciertas operaciones (Sleep(n)) Espere unos segundos antes de volver a consultar.

A continuación se muestra un ejemplo de cómo utilizar la función Dial para crear una conexión API de Websocket y suscribirse a los datos del libro 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) + "`")
    }
}

Transmisión de mensajes del nodo de la cadena dYdX

Los mensajes más utilizados en las transacciones son los mensajes de pedido, los mensajes de cancelación de pedido y los mensajes de transferencia.

  • Resumen del mensaje del 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
    }
  }
  • Orden límite: En la función de orden encapsulada en la plataforma FMZ, el valor orderFlags utilizado para órdenes limitadas es:ORDER_FLAGS_LONG_TERM = 64 # 长期订单De acuerdo con las limitaciones del protocolo DYDX v4, se utiliza el período de validez de pedido más largo, que es de 90 días (todos los tipos de pedidos en DYDX v4 tienen un período de validez).

  • Orden de mercado: En la función de orden encapsulada en la plataforma FMZ, el valor orderFlags utilizado por la orden de mercado es:ORDER_FLAGS_SHORT_TERM = 0 # 短期订单, según las recomendaciones del protocolo DYDX v4:

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

    Dado que no es una verdadera orden de mercado, se utiliza el precio del oráculo, más o menos un deslizamiento del 5% como orden de mercado. La configuración del período de validez de las órdenes a corto plazo también es diferente de la de las órdenes a largo plazo. Las órdenes a corto plazo utilizan el período de validez de la altura del bloque. De acuerdo con la recomendación de dydx v4, se establece en el bloque actual + 10 alturas de bloque. antes de que expire.

  • ID del pedido: Dado que la operación de pedido se realiza directamente en la cadena, el indexador no generará ningún ID de pedido después de que se transmita el mensaje, y el pedido del indexador no se puede usar como valor de retorno de la función de pedido de la plataforma. Para garantizar la unicidad En función del ID del pedido y de la precisión de la consulta del pedido, se devuelve el orden del indexador. El ID del pedido consta de la siguiente información (separada por comas):

    • Pares comerciales
    • Dirección de cuenta corriente de dydx
    • Número de subcuenta (subaccountNumber)
    • clientId (generado aleatoriamente)
    • clobPairId (identificador del símbolo de transacción)
    • orderFlags
    • goodTilData (milisegundos)
  • Resumen del mensaje de cancelación de pedido

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

Es necesario pasar el ID de pedido devuelto por la interfaz de pedido de la plataforma FMZ.

  • Resumen del mensaje de transferencia
  {
    "@type": "/dydxprotocol.sending.MsgCreateTransfer",
    "transfer": {
      "sender": {
        "owner": "xxx"
      },
      "recipient": {
        "owner": "xxx",
        "number": 128
      },
      "amount": "10000000"
    }
  }

Se pueden crear muchas subcuentas con la dirección actual de dydx v4. La subcuenta con subAccountNumber 0 es la primera subcuenta creada automáticamente. El ID de subcuenta con subAccountNumber mayor o igual a 128 se utiliza para operaciones de posición aisladas. que requiere al menos 20 activos USDC. Por ejemplo, puede ir de subAccountNumber 0 -> 128, o de subAccountNumber 128 -> 0. La transferencia requiere el consumo de Tarifa de Gas. La tarifa de gas puede utilizar tokens USDC y dydx.

Práctica de la plataforma FMZ dYdX v4

El contenido anterior explica brevemente algunos detalles del empaquetado. A continuación, practiquemos el uso específico. Aquí usamos la red de prueba dYdX v4 para la demostración. La red de prueba es básicamente la misma que la red principal y hay una faucet automática para recibir activos de prueba. . El custodio se despliega No entraré en detalles sobre la operación y crearé una prueba real en FMZ.

1. Configuración

Después de conectarse exitosamente a la aplicación dYdX v4 usando una billetera de criptomonedas (yo uso la billetera imToken aquí), reclame sus activos de prueba y luego exporte el mnemónico para su cuenta dYdX v4 actual (derivada de su billetera).

Práctica cuantitativa de DEX Exchange (1) – Guía del usuario de dYdX v4

Configurar el mnemónico en la plataforma FMZ. Aquí usamos el método de archivo local para configurarlo (también puede completarlo directamente y configurarlo en la plataforma. El mnemónico se configura después del cifrado, no en texto plano).

  • Archivo mnemotécnico: mnemonic.txt

Práctica cuantitativa de DEX Exchange (1) – Guía del usuario de dYdX v4

Colóquelo en el directorio de la carpeta de ID de disco real, debajo del directorio de custodia. Por supuesto, también se puede colocar en otros directorios (la ruta específica se debe escribir durante la configuración).

  • Configurar el intercambio en FMZ

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

Complete el cuadro de edición mnemotécnica:file:///mnemonic.txt, la ruta real correspondiente es:托管者所在目录/logs/storage/594291

Práctica cuantitativa de DEX Exchange (1) – Guía del usuario de dYdX v4

2. Cambie a la red de prueba 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()) 
}

Lea la información de la cuenta de red de prueba:

{
	"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 información de mercado

No cambié a la red de prueba, probé con la red 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áctica cuantitativa de DEX Exchange (1) – Guía del usuario de dYdX v4

4. Realizar un 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áctica cuantitativa de DEX Exchange (1) – Guía del usuario de dYdX v4

Página de la aplicación dYdX v4:

Práctica cuantitativa de DEX Exchange (1) – Guía del usuario de dYdX v4

5. Información del pedido

La red de prueba coloca dos pedidos por adelantado, prueba a obtener los pedidos pendientes actuales y cancela los 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áctica cuantitativa de DEX Exchange (1) – Guía del usuario de dYdX v4

6. Consulta de información de posición

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áctica cuantitativa de DEX Exchange (1) – Guía del usuario de dYdX v4

7. Gestión de subcuentas

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áctica cuantitativa de DEX Exchange (1) – Guía del usuario de dYdX v4

Cambie a la subcuenta cuyo subAccountNumber es 128 y los datos devueltos por GetAccount son:

{
	"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
}

Se puede ver que la subcuenta con subAccountNumber 128 ha transferido 20 USDC.

8. Obtenga TxHash y llame a la interfaz del nodo REST

De acuerdo con el orden, obtenga TxHash y pruebe el método de IO que llama al nodo REST

¿Cómo obtener el TxHash de un pedido? El objeto de intercambio dydx almacenará en caché el TxHash, que se puede consultar mediante el ID del pedido. Sin embargo, una vez que la estrategia se detiene, el mapa hash de la transacción de órdenes almacenada en caché se borrará.

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áctica cuantitativa de DEX Exchange (1) – Guía del usuario de dYdX v4

Mensajes consultados a través de TxHash:

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

El contenido es demasiado largo, por lo que a continuación se presentan algunos extractos a modo de demostración:

{
	"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

Las pruebas anteriores se basan en el custodio más reciente. Debe descargar el custodio más reciente para admitir dYdX v4 DEX

Gracias por su apoyo y gracias por leer.