avatar of 发明者量化-小小梦 发明者量化-小小梦
Suivre Messages privés
4
Suivre
1271
Abonnés

Pratique quantitative de l'échange DEX (1) -- Guide de l'utilisateur dYdX v4

Créé le: 2024-12-24 17:09:32, Mis à jour le: 2024-12-26 21:41:46
comments   0
hits   1049

[TOC]

Pratique quantitative de l’échange DEX (1) – Guide de l’utilisateur dYdX v4

Préface

Avec l’essor rapide des échanges décentralisés (DEX) dans le domaine du trading de crypto-monnaie, les traders quantitatifs ont progressivement commencé à se tourner vers ces plateformes pour un trading automatisé efficace. En tant que l’une des plateformes de trading décentralisées les plus populaires, dYdX offre de puissantes fonctions de trading et prend en charge le trading de contrats à terme perpétuels. Sa dernière version v4 optimise les performances et l’expérience utilisateur, ce qui en fait le premier choix de nombreux traders quantitatifs.

Cet article présentera comment pratiquer le trading quantitatif sur dYdX v4, notamment comment utiliser son API pour trader, obtenir des données de marché et gérer des comptes.

  • Changement d’environnement de test
  • Demande d’informations sur le marché
  • Demande d’informations sur les commandes et les positions
  • Passer une commande
  • Gestion des sous-comptes
  • Demande de méthode de nœud

dYdX v4 DEX

  • Page de l’application de test dYdX

Pratique quantitative de l’échange DEX (1) – Guide de l’utilisateur dYdX v4

  • etdYdX v3De même, les transactions génèrent des récompenses, des récompensesdYdXJetons.

Pratique quantitative de l’échange DEX (1) – Guide de l’utilisateur dYdX v4

Informations de connexion, de connexion et de configuration du portefeuille

L’échange DEX du protocole dYdX v3 précédent est hors ligne. L’adresse actuelle de l’application dYdX v4 est :

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

Après avoir ouvert la page de l’application, un bouton permettant de se connecter au portefeuille se trouve dans le coin supérieur droit. Scannez le code QR pour vous connecter au portefeuille.

Si vous souhaitez d’abord tester et vous familiariser avec l’environnement réseau de test, vous pouvez utiliser le réseau de test :

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

Cliquez également sur le bouton Connecter le portefeuille dans le coin supérieur droit, scannez le code QR pour vous connecter au portefeuille et vérifiez la signature. Une fois le portefeuille correctement connecté, une adresse dydx v4 sera automatiquement générée. Cette adresse sera affichée dans le coin supérieur droit de la page de l’application. Un menu apparaîtra après avoir cliqué dessus. Il s’agit notamment d’opérations telles que la recharge, le retrait et le transfert. L’une des différences entre le réseau principal dYdX (environnement de production) et le réseau de test est que lorsque vous cliquez sur le bouton de rechargement du réseau de test, 300 actifs USDC seront automatiquement déposés dans le robinet pour les tests. Si vous souhaitez effectuer des transactions réelles sur dYdX, vous devez déposer des actifs USDC. La recharge est également très pratique et compatible avec plusieurs actifs et chaînes.

  • Adresse du compte dYdX v4 L’adresse du compte dYdX v4 est dérivée de l’adresse du portefeuille. L’adresse du compte dYdX v4 ressemble à ceci :dydx1xxxxxxxxxxxxxxxxxxxxq2ge5jr4nzfeljxxxx, est l’adresse commençant par dydx1. Cette adresse peut être interrogée dans les explorateurs de blockchain.

  • Mnémotechnique Vous pouvez exporter le mnémonique du compte d’adresse dYdX actuel en cliquant sur le bouton « Exporter le mot de passe » dans le menu du coin supérieur droit. Lors de l’ajout d’un échange sur la plateforme FMZ, vous devez configurer ce mnémonique.

Les mnémoniques peuvent être configurées directement sur la plateforme FMZ ou enregistrées localement sur le dépositaire. Lors de l’utilisation de l’objet d’échange dydx v4, le contenu du fichier enregistrant les mnémoniques sera lu, ce qui sera démontré dans la partie pratique de cet article.

Différences entre Mainnet et Testnet

L’environnement du réseau de test est différent de l’environnement du réseau principal sur certains aspects. Voici quelques différences simples.

  • Transfert d’actifs de sous-compte. Le réseau principal dispose d’un mécanisme de nettoyage des sous-comptes.subAccountNumber >= 128Si le sous-compte avec cet ID n’a pas de positions, les actifs seront automatiquement transférés vers le sous-compte avec le subAccountNumber 0. Lors des tests, il a été constaté que le réseau de test ne disposait pas d’un tel mécanisme (ou que les conditions de déclenchement étaient différentes et qu’il n’avait pas été déclenché sur le réseau de test).

  • Quelques noms symboliques. Le jeton natif dydx est nommé différemment : MainnetDYDX, réseau de testDv4TNT

  • Configuration d’adresse, telle que l’ID de chaîne, l’adresse du nœud, l’adresse de l’indexeur, etc. Il existe de nombreux nœuds et configurations, en voici un :

    • Réseau principal : Adresse de l’indexeur :https://indexer.dydx.trade ID de la chaîne :dydx-mainnet-1 Nœud REST :https://dydx-dao-api.polkachu.com:443

    • Réseau de test : Adresse de l’indexeur :https://indexer.v4testnet.dydx.exchange ID de la chaîne :dydx-testnet-4 Nœud REST :https://dydx-testnet-api.polkachu.com

Architecture du protocole dYdX v4

Le protocole dYdX v4 est développé sur la base de l’écosystème cosmos. Le contenu des transactions du système dYdX v4 DEX se compose principalement de deux parties :

  • Un indexeur chargé d’interroger les informations de marché, les informations de compte, etc.
  • messages de commande de la blockchain dydx, messages d’annulation de commande, messages de transfert, etc.

Indexeur

Le service d’indexation fournit les protocoles REST et Websocket.

  • Protocole REST L’interface du protocole REST prend en charge les requêtes d’informations de marché, les informations de compte, les informations de position, les informations de commande, etc., et a été encapsulée en tant qu’interface API unifiée sur la plate-forme FMZ.

  • Protocole WebSocket Sur la plateforme FMZ, vous pouvez utiliser la fonction Dial pour créer une connexion Websocket et vous abonner aux informations du marché.

Il convient de noter que l’indexeur dydx v4 présente le même problème que l’échange centralisé, à savoir que les mises à jour des données ne sont pas aussi rapides. Par exemple, il arrive parfois que la commande ne soit pas trouvée lors d’une requête immédiatement après avoir passé une commande. Il est recommandé qu’après certaines opérations (Sleep(n)) Attendez quelques secondes avant de relancer la requête.

Voici un exemple d’utilisation de la fonction Dial pour créer une connexion API Websocket et s’abonner aux données du carnet de commandes :

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) + "`")
    }
}

Diffusion de messages du nœud de chaîne dYdX

Les messages les plus couramment utilisés dans les transactions sont les messages de commande, les messages d’annulation de commande et les messages de transfert.

  • Résumé du message de commande
  {
    "@type": "/dydxprotocol.clob.MsgPlaceOrder",
    "order": {
      "orderId": {
        "subaccountId": {
          "owner": "xxx"
        },
        "clientId": xxx,
        "orderFlags": 64,
        "clobPairId": 1
      },
      "side": "SIDE_BUY",
      "quantums": "2000000",
      "subticks": "3500000000",
      "goodTilBlockTime": 1742295981
    }
  }
  • Ordre limité : Dans la fonction de commande encapsulée sur la plateforme FMZ, la valeur orderFlags utilisée pour les ordres à cours limité est :ORDER_FLAGS_LONG_TERM = 64 # 长期订单Conformément aux limitations du protocole DYDX v4, la période de validité de commande la plus longue est utilisée, qui est de 90 jours (tous les types de commandes sur DYDX v4 ont une période de validité).

  • Ordre du marché : Dans la fonction de commande encapsulée sur la plateforme FMZ, la valeur orderFlags utilisée par l’ordre au marché est :ORDER_FLAGS_SHORT_TERM = 0 # 短期订单, selon les recommandations du protocole DYDX v4 :

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

    Puisqu’il ne s’agit pas d’un véritable ordre de marché, le prix de l’oracle est utilisé, plus ou moins 5 % de glissement comme ordre de marché. Le réglage de la période de validité des ordres à court terme est également différent de celui des ordres à long terme. Les ordres à court terme utilisent la période de validité de la hauteur de bloc. Selon la recommandation de dydx v4, elle est définie sur le bloc actuel + 10 hauteurs de bloc avant son expiration.

  • Numéro de commande : Étant donné que l’opération de commande est effectuée directement sur la chaîne, aucun identifiant de commande ne sera généré par l’indexeur après la diffusion du message, et l’ordre de l’indexeur ne peut pas être utilisé comme valeur de retour de la fonction de commande de la plateforme. Afin de garantir l’unicité En fonction de l’ID de commande et de l’exactitude de la requête de commande, l’ordre de l’indexeur est renvoyé. L’ID de commande comprend les informations suivantes (séparées par des virgules) :

    • Paires de trading
    • adresse du compte courant dydx
    • Numéro de sous-compte (subaccountNumber)
    • clientId (généré aléatoirement)
    • clobPairId (ID du symbole de transaction)
    • orderFlags
    • goodTilData (millisecondes)
  • Résumé du message d’annulation de commande

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

L’ID de commande renvoyé par l’interface de commande de la plateforme FMZ doit être transmis.

  • Résumé du message de transfert
  {
    "@type": "/dydxprotocol.sending.MsgCreateTransfer",
    "transfer": {
      "sender": {
        "owner": "xxx"
      },
      "recipient": {
        "owner": "xxx",
        "number": 128
      },
      "amount": "10000000"
    }
  }

De nombreux sous-comptes peuvent être créés sous l’adresse dydx v4 actuelle. Le sous-compte avec le subAccountNumber 0 est le premier sous-compte créé automatiquement. L’ID de sous-compte avec le subAccountNumber supérieur ou égal à 128 est utilisé pour le trading de position isolée, qui nécessite au moins 20 USDC d’actifs. Par exemple, vous pouvez passer de subAccountNumber 0 -> 128, ou de subAccountNumber 128 -> 0. Le transfert nécessite la consommation de frais de gaz. Les frais de gaz peuvent utiliser les jetons USDC et dydx.

Pratique de la plateforme FMZ dYdX v4

Le contenu ci-dessus explique brièvement certains détails du packaging. Ensuite, pratiquons l’utilisation spécifique. Ici, nous utilisons le réseau de test dYdX v4 pour la démonstration. Le réseau de test est fondamentalement le même que le réseau principal, et il existe un robinet automatique pour recevoir les ressources de test . Le gardien déploie Je n’entrerai pas dans les détails de l’opération, et créerai un véritable test sur FMZ.

1. Configuration

Après vous être connecté avec succès à l’application dYdX v4 à l’aide d’un portefeuille de crypto-monnaie (j’utilise ici le portefeuille imToken), réclamez vos actifs de test, puis exportez le mnémonique de votre compte dYdX v4 actuel (dérivé de votre portefeuille).

Pratique quantitative de l’échange DEX (1) – Guide de l’utilisateur dYdX v4

Configurer le mnémonique sur la plateforme FMZ. Ici, nous utilisons la méthode du fichier local pour le configurer (vous pouvez également le remplir directement et le configurer sur la plateforme. Le mnémonique est configuré après le chiffrement, pas en texte brut).

  • Fichier mnémonique : mnemonic.txt

Pratique quantitative de l’échange DEX (1) – Guide de l’utilisateur dYdX v4

Placez-le dans le répertoire du dossier ID du disque réel sous le répertoire du dépositaire. Bien entendu, il peut également être placé dans d’autres répertoires (le chemin spécifique doit être écrit lors de la configuration).

  • Configurer l’échange sur FMZ

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

Remplissez la zone d’édition mnémonique :file:///mnemonic.txt, le chemin réel correspondant est :托管者所在目录/logs/storage/594291

Pratique quantitative de l’échange DEX (1) – Guide de l’utilisateur dYdX v4

2. Passer au réseau de test 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()) 
}

Lisez les informations du compte réseau de test :

{
	"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. Demande d’informations sur le marché

Je n’ai pas basculé sur le réseau de test, j’ai testé avec le réseau 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) +  "`")
}

Pratique quantitative de l’échange DEX (1) – Guide de l’utilisateur dYdX v4

4. Passer une commande

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

Pratique quantitative de l’échange DEX (1) – Guide de l’utilisateur dYdX v4

Page de l’application dYdX v4 :

Pratique quantitative de l’échange DEX (1) – Guide de l’utilisateur dYdX v4

5. Informations sur la commande

Le réseau de test place deux commandes à l’avance, teste l’obtention des commandes en attente actuelles et annule les commandes.

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) +  "`")
}

Pratique quantitative de l’échange DEX (1) – Guide de l’utilisateur dYdX v4

6. Demande d’informations sur la position

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) +  "`")
}

Pratique quantitative de l’échange DEX (1) – Guide de l’utilisateur dYdX v4

7. Gestion des sous-comptes

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

Pratique quantitative de l’échange DEX (1) – Guide de l’utilisateur dYdX v4

Passez au sous-compte dont le subAccountNumber est 128 et les données renvoyées par GetAccount sont :

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

On peut voir que le sous-compte avec le sous-compte numéro 128 a transféré 20 USDC.

8. Obtenez TxHash et appelez l’interface du nœud REST

Selon la commande, obtenez TxHash et testez la méthode d’appel IO du nœud REST

Comment obtenir le TxHash d’une commande ? L’objet d’échange dydx mettra en cache le TxHash, qui peut être interrogé à l’aide de l’ID de commande. Cependant, une fois la stratégie arrêtée, la carte de hachage de l’ordre tx mis en cache sera effacée.

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

Pratique quantitative de l’échange DEX (1) – Guide de l’utilisateur dYdX v4

Messages interrogés via TxHash :

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

Le contenu est trop long, voici donc quelques extraits pour démonstration :

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

Les tests ci-dessus sont basés sur le dernier dépositaire. Vous devez télécharger le dernier dépositaire pour prendre en charge dYdX v4 DEX

Merci pour votre soutien et merci de votre lecture.