Pratiques quantitatives sur DEX – Partie 1 : Guide d'utilisation de dYdX v4

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

[TOC]

Pratiques quantitatives sur DEX – Partie 1 : Guide d’utilisation de dYdX v4

Préface

Avec l’essor rapide des exchanges décentralisés (DEX) dans l’écosystème cryptographique, les traders quantitatifs se tournent progressivement vers ces plateformes pour effectuer des transactions automatisées efficaces. dYdX, l’une des plateformes de trading décentralisées les plus populaires, propose des fonctionnalités avancées incluant le trading de contrats perpétuels futures. Sa dernière version v4 améliore les performances et l’expérience utilisateur, devenant ainsi le choix privilégié de nombreux quant traders.

Cet article présente les pratiques de trading quantitatif sur dYdX v4, incluant l’utilisation de son API pour l’exécution d’ordres, l’accès aux données de marché et la gestion de compte.

  • Basculement environnement de test
  • Consultation des informations de marché
  • Requête des informations d’ordres et de positions
  • Passation d’ordres
  • Gestion des sous-comptes
  • Méthodes d’appel aux nœuds

dYdX v4 DEX

  • Interface de l’application testnet dYdX

Pratiques quantitatives sur DEX – Partie 1 : Guide d’utilisation de dYdX v4

  • Comme avec dYdX v3, les transactions génèrent des récompenses en tokens dYdX.

Pratiques quantitatives sur DEX – Partie 1 : Guide d’utilisation de dYdX v4

Connexion du portefeuille, authentification et configuration

L’ancienne version v3 du protocole dYdX DEX a été retirée. L’adresse actuelle de l’application dYdX v4 est :

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

Après ouverture de l’application, utilisez le bouton de connexion en haut à droite pour lier votre portefeuille via QR code.

Pour une prise en main préalable en environnement test, utilisez :

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

Le processus de connexion est identique : authentification par signature. Une adresse dYdX v4 est générée automatiquement après connexion, visible en haut à droite. Un menu contextuel permet les opérations de dépôt, retrait et transfert. La différence principale entre mainnet et testnet réside dans le robinet (faucet) automatique de 300 USDC sur le testnet via l’option de dépôt.

  • Adresse de compte dYdX v4 Dérivée de l’adresse du portefeuille, elle suit le format dydx1xxxxxxxxxxxxxxxxxxxxq2ge5jr4nzfeljxxxx (préfixe dydx1), consultable sur les explorers blockchain.

  • Phrase mnémonique Accessible via le bouton « Exporter la phrase secrète » dans le menu contextuel. Cette phrase est nécessaire pour configurer l’échange sur la plateforme FMZ.

La phrase peut être stockée directement sur FMZ ou localement. Les démonstrations pratiques suivantes illustreront son utilisation avec les objets d’échange dYdX v4.

Différences entre le réseau principal et le réseau de test

Plusieurs distinctions notables existent entre les environnements :

  • Transferts inter-sous-comptes Le mainnet implémente un mécanisme de nettoyage automatique pour les sous-comptes avec subAccountNumber >= 128 sans positions ouvertes. Ce comportement n’est pas observé sur le testnet.

  • Dénominations de tokens Le token natif diffère : DYDX (mainnet) vs Dv4TNT (testnet)

  • Configuration réseau Exemples de paramètres :

    • Mainnet : Indexer : https://indexer.dydx.trade Chain ID : dydx-mainnet-1 Nœud REST : https://dydx-dao-api.polkachu.com:443

    • Testnet : Indexer : https://indexer.v4testnet.dydx.exchange Chain ID : dydx-testnet-4 Nœud REST : https://dydx-testnet-api.polkachu.com

Architecture du protocole dYdX v4

Basé sur l’écosystème Cosmos, le système dYdX v4 repose sur deux composants majeurs :

  • L’indexeur pour les données de marché et de compte
  • La blockchain dYdX pour l’exécution des ordres et transactions

Indexeur

L’indexeur expose des API REST et WebSocket :

  • API REST Intégrée dans FMZ pour les requêtes standardisées : données de marché, positions, historiques…

  • WebSocket Utilisable via la fonction Dial sur FMZ pour l’abonnement en temps réel.

Une particularité importante : les mises à jour de l’indexeur présentent parfois des latences (exemple : délai d’apparition des nouveaux ordres). Il est recommandé d’implémenter des pauses (Sleep(n)) après les opérations critiques.

Exemple de connexion WebSocket pour le carnet d’ordres :

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

    // Abonnement
    self.CreateWsThread = function (msgSubscribe) {
        self.wsThread = threading.Thread(function (streamingPoint, msgSubscribe) {
            // Carnet d'ordres
            var orderBook = null 

            // Mise à jour du carnet
            var updateOrderbook = function(orderbook, update) {
                // Mise à jour des offres (bids)
                if (update.bids) {
                    update.bids.forEach(([price, size]) => {
                        const priceFloat = parseFloat(price)
                        const sizeFloat = parseFloat(size)

                        if (sizeFloat === 0) {
                            // Suppression de l'ordre au prix correspondant
orderbook.bids = orderbook.bids.filter(bid => parseFloat(bid.price) !== priceFloat)
                        } else {
                            // Mettre à jour ou ajouter une offre d'achat
                            orderbook.bids = orderbook.bids.filter(bid => parseFloat(bid.price) !== priceFloat)
                            orderbook.bids.push({price: price, size: size})
                            // Tri par prix décroissant
                            orderbook.bids.sort((a, b) => parseFloat(b.price) - parseFloat(a.price))
                        }
                    })
                }

                // Mettre à jour les asks
                if (update.asks) {
                    update.asks.forEach(([price, size]) => {
                        const priceFloat = parseFloat(price)
                        const sizeFloat = parseFloat(size)

                        if (sizeFloat === 0) {
                            // Supprimer l'offre de vente au prix price
                            orderbook.asks = orderbook.asks.filter(ask => parseFloat(ask.price) !== priceFloat)
                        } else {
                            // Mettre à jour ou ajouter une offre de vente
                            orderbook.asks = orderbook.asks.filter(ask => parseFloat(ask.price) !== priceFloat)
                            orderbook.asks.push({price: price, size: size})
                            // Tri par prix croissant
                            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("Échec de la création du thread WebSocket.")
                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)
    }

    // Écoute
    self.Peek = function () {
        return self.wsThread.peekMessage()
    }

    return self
}

function main() {
    // réel : wss://indexer.dydx.trade/v4/ws
    // simulation : wss://indexer.v4testnet.dydx.exchange/v4/ws

    var symbol = "ETH-USD"
    var manager = dYdXIndexerWSconnManager("wss://indexer.dydx.trade/v4/ws")
```fra_Latn
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 des messages de nœud de chaîne dYdX

Les messages les plus utilisés dans le trading sont : messages d’ordre, d’annulation et de transfert.

  • Synopsis des messages d’ordre

    {
    "@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 limite :
      Sur la plateforme FMZ, les fonctions d’ordre encapsulées utilisent la valeur ORDER_FLAGS_LONG_TERM = 64 # Ordre à long terme pour le paramètre orderFlags. Conformément aux restrictions du protocole dydx v4, la durée de validité maximale est utilisée (90 jours). Tous les types d’ordre sur dydx v4 ont une expiration.

    • Ordre au marché :
      Les fonctions d’ordre encapsulées utilisent ORDER_FLAGS_SHORT_TERM = 0 # Ordre à court terme. Selon les recommandations du protocole dydx v4 :

    // Recommandé : prix oracle -5% ou moins pour VENTE, prix oracle +5% pour ACHAT

    Ce n’étant pas un véritable ordre au marché, le prix oracle est utilisé avec un slippage de ±5%. La validité des ordres courts diffère : elle utilise la hauteur de bloc, configurée à bloc actuel + 10 selon les recommandations.

    • ID d’ordre :
      Les opérations s’effectuant directement sur la chaîne, il n’y a pas d’ID généré par l’indexeur. Pour garantir l’unicité et la traçabilité, l’ID de retour est composé de (séparés par des virgules) :

      • Paire de trading
      • Adresse du compte dydx actuel
      • Numéro de sous-compte (subaccountNumber)
      • clientId (généré aléatoirement)
      • clobPairId (ID de l’instrument)
      • orderFlags
      • goodTilData (millisecondes)
  • Synopsis des messages d’annulation

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

Requiert l’ID d’ordre retourné par l’interface FMZ.

  • Synopsis des messages de transfert
  {
    "@type": "/dydxprotocol.sending.MsgCreateTransfer",
    "transfer": {
      "sender": {
        "owner": "xxx"
      },
      "recipient": {
        "owner": "xxx",
        "number": 128
      },
      "amount": "10000000"
    }
  }

Sur dydx v4, un compte peut créer plusieurs sous-comptes. Le sous-compte 0 est créé automatiquement. Les sous-comptes avec subAccountNumber ≥ 128 sont dédiés aux produits isolés (requiert minimum 20 USDC).
Exemple : transfert possible entre sous-compte 0 ↔ 128. Les transferts consomment des frais de réseau (Gas Fee), payables en USDC ou token dydx.

Pratique de la plateforme FMZ avec dYdX v4

Le contenu ci-dessus explique brièvement certains détails d’encapsulation. Passons maintenant à la pratique concrète en utilisant le réseau de test dYdX v4 pour démonstration. Le réseau de test est quasi identique au réseau principal et dispose d’un robinet automatique pour obtenir des actifs de test. Les opérations de déploiement de l’hébergeur ne seront pas détaillées ici - nous procéderons directement à la création d’un test en conditions réelles sur FMZ.

1. Configuration

Après avoir connecté avec succès le portefeuille cryptographique à l’application dYdX v4 (ici via le portefeuille imToken), récupérez les actifs de test puis exportez la phrase mnémonique du compte dYdX v4 actuel (dérivé du portefeuille).

Pratiques quantitatives sur DEX – Partie 1 : Guide d’utilisation de dYdX v4

Configurez la phrase mnémonique sur la plateforme FMZ en utilisant une méthode par fichier local (possible aussi de la saisir directement - elle sera chiffrée avant stockage).

  • Fichier mnémonique : mnemonic.txt

Pratiques quantitatives sur DEX – Partie 1 : Guide d’utilisation de dYdX v4

Placez-le dans le répertoire de l’ID de stratégie du dossier de l’hébergeur. Autre répertoire possible (préciser le chemin absolu si différent).

  • Configuration de l’exchange sur FMZ

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

Dans le champ mnémonique, saisir : file:///mnemonic.txt. Chemin physique correspondant : répertoire de l'hébergeur/logs/storage/594291.

Pratiques quantitatives sur DEX – Partie 1 : Guide d’utilisation de dYdX v4

2. Basculer sur le réseau de test dydx v4

function main() {
    // Définir l'adresse de l'indexeur de la chaîne de test
    exchange.SetBase("https://indexer.v4testnet.dydx.exchange")

    // Modifier le ChainId pour la chaîne de test 
    exchange.IO("chainId", "dydx-testnet-4")

    // Définir l'adresse du nœud REST de test
    exchange.IO("restApiBase", "https://dydx-testnet-api.polkachu.com")

    // Test de lecture des informations du compte
    Log(exchange.GetAccount()) 
}

Résultat de la lecture des informations du compte 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. Requêtage des informations de marché

Test effectué sur le réseau principal sans basculement

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])
    }
### 4. Passer un ordre

```js
function main() {
    // Changer l'adresse de l'indexeur de la chaîne de test
    exchange.SetBase("https://indexer.v4testnet.dydx.exchange")

    // Modifier le ChainId de la chaîne de test
    exchange.IO("chainId", "dydx-testnet-4")

    // Changer l'adresse du nœud REST de la chaîne de test
    exchange.IO("restApiBase", "https://dydx-testnet-api.polkachu.com")

    // Ordre limite, passer un ordre
    var idSell = exchange.CreateOrder("ETH_USD.swap", "sell", 4000, 0.002)
    var idBuy = exchange.CreateOrder("ETH_USD.swap", "buy", 3000, 0.003)

    // Ordre au marché
    var idMarket = exchange.CreateOrder("ETH_USD.swap", "buy", -1, 0.01)

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

Pratiques quantitatives sur DEX – Partie 1 : Guide d’utilisation de dYdX v4

Page d’application dYdX v4 :

Pratiques quantitatives sur DEX – Partie 1 : Guide d’utilisation de dYdX v4

5. Informations sur les ordres

Test préalable de deux ordres sur le testnet, vérification de la récupération des ordres ouverts et annulation.

function main() {    
    // Changer l'adresse de l'indexeur de la chaîne de test
    exchange.SetBase("https://indexer.v4testnet.dydx.exchange")

    // Modifier le ChainId de la chaîne de test
    exchange.IO("chainId", "dydx-testnet-4")

    // Changer l'adresse du nœud REST de la chaîne de test
    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) +  "`")
}

Pratiques quantitatives sur DEX – Partie 1 : Guide d’utilisation de dYdX v4

6. Consultation des positions

function main() {
    // Changer l'adresse de l'indexeur de la chaîne de test
    exchange.SetBase("https://indexer.v4testnet.dydx.exchange")

    // Modifier le ChainId de la chaîne de test
    exchange.IO("chainId", "dydx-testnet-4")

    // Changer l'adresse du nœud REST de la chaîne de test
    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) +  "`")
}

Pratiques quantitatives sur DEX – Partie 1 : Guide d’utilisation de dYdX v4

7. Gestion des sous-comptes

function main() {
    // Changer l'adresse de l'indexeur de la chaîne de test
    exchange.SetBase("https://indexer.v4testnet.dydx.exchange")

    // Modifier le ChainId de la chaîne de test
    exchange.IO("chainId", "dydx-testnet-4")

    // Changer l'adresse du nœud REST de la chaîne de test
    exchange.IO("restApiBase", "https://dydx-testnet-api.polkachu.com")
exchange.IO("restApiBase", "https://dydx-testnet-api.polkachu.com")

    // subAccountNumber 0 -> 128 : 20 USDC , Frais de gaz adv4tnt (jeton dydx)
    var ret = exchange.IO("transferUSDCToSubaccount", 0, 128, "adv4tnt", 20)  
    Log("ret:", ret)

    // Basculer vers le sous-compte subAccountNumber 128 et vérifier les informations du compte
    exchange.IO("subAccountNumber", 128)

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

Pratiques quantitatives sur DEX – Partie 1 : Guide d’utilisation de dYdX v4

Après avoir basculé vers le sous-compte subAccountNumber 128, 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 subAccountNumber 128 a reçu un transfert de 20 USDC.

8. Obtenir le TxHash et appeler l’interface du nœud REST

Récupérer le TxHash d’un ordre et tester la méthode d’appel REST via IO

L’objet d’échange dydx met en cache les TxHash, consultables via l’ID de commande. Cependant, les mappages de hachage tx des ordres en cache sont effacés après l’arrêt de la stratégie.

function main() {
    // Changer l'adresse de l'indexeur de la chaîne de test
    exchange.SetBase("https://indexer.v4testnet.dydx.exchange")

    // Définir le ChainId de la chaîne de test 
    exchange.IO("chainId", "dydx-testnet-4")

    // Configurer l'adresse du nœud REST de la chaîne de test
    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)
    
    // Pour vider la table de hachage utiliser : 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)
    }
}

Pratiques quantitatives sur DEX – Partie 1 : Guide d’utilisation de dYdX v4

Résultat de la requête par TxHash :

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

Contenu tronqué 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": []
			},
      ...

FIN

Ce test est basé sur la dernière version de l’hôte géré - téléchargez la mise à jour pour supporter dYdX v4 DEX

Merci pour votre soutien et votre lecture attentive.