Quantitative Praktiken für DEX-Börsen (1) – Leitfaden zu dYdX v4

Erstellt in: 2024-12-24 17:09:32, aktualisiert am: 2024-12-26 21:41:46
comments   0
hits   233

[TOC]

Quantitative Praktiken für DEX-Börsen (1) – Leitfaden zu dYdX v4

Einführung

Mit dem rasanten Aufstieg dezentraler Börsen (DEX) im Kryptohandel wenden sich quantitative Händler zunehmend diesen Plattformen für effizientes automatisiertes Trading zu. dYdX, als eine der beliebtesten dezentralen Handelsplattformen, bietet leistungsstarke Handelsfunktionen mit Unterstützung für Perpetual Futures. Die neueste Version v4 optimiert Performance und Benutzererfahrung, wodurch sie zur ersten Wahl für viele Quantitative Trading-Strategien wird.

Dieser Artikel beschreibt die praktische Umsetzung quantitativen Handels auf dYdX v4, inklusive API-Nutzung für Orderausführung, Marktdatenabfrage und Kontomanagement.

  • Testumgebungswechsel
  • Marktinformationsabfrage
  • Order- und Positionsabfragen
  • Orderplatzierung
  • Unterkontoverwaltung
  • Node-Methodenanfragen

dYdX v4 DEX

  • dYdX Testnet App-Oberfläche

Quantitative Praktiken für DEX-Börsen (1) – Leitfaden zu dYdX v4

  • Wie bei dYdX v3 generiert Trading Belohnungen in dYdX-Token.

Quantitative Praktiken für DEX-Börsen (1) – Leitfaden zu dYdX v4

Wallet-Verbindung, Anmeldung und Konfiguration

Die frühere dYdX v3 Protocol DEX wurde eingestellt. Die aktuelle dYdX v4 App-Adresse lautet:

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

Nach dem Öffnen der App-Oberfläche findet sich oben rechts ein Wallet-Verbindungsbutton für QR-Code-Linking.

Für Testnetz-Experimente verwenden Sie:

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

Nach erfolgreicher Wallet-Verbindung via Signaturvalidierung generiert das System automatisch eine dYdX v4-Adresse (sichtbar oben rechts). Das Kontextmenü ermöglicht Einzahlungen, Abhebungen und Transfers. Ein Hauptunterschied zwischen Mainnet und Testnet: Im Testnetz erhalten Sie per Faucet automatisch 300 USDC Testguthaben. Für reales Trading sind USDC-Einzahlungen erforderlich, die über mehrere Chains unterstützt werden.

  • dYdX v4 Kontoadresse
    Abgeleitet von der Wallet-Adresse, zeigt das Format dydx1xxxxxxxxxxxxxxxxxxxxq2ge5jr4nzfeljxxxx (beginnt mit dydx1). Diese Adresse ist über Blockchain-Explorer einsehbar.

  • Mnemonic-Phrase
    Über das Kontextmenü (“Exportiere Passphrase”) lässt sich die Mnemonic-Phrase des aktuellen Kontos exportieren. Bei der Exchange-Konfiguration auf FMZ ist diese Phrase erforderlich.

Die Mnemonic-Phrase kann direkt auf FMZ hinterlegt oder lokal gespeichert werden. Im Praxisteil demonstrieren wir die Nutzung über Dateieinbindung.

Mainnet/Testnet-Unterschiede

Testnetz und Mainnet zeigen folgende relevante Unterschiede:

  • Unterkonto-Transfers
    Mainnet implementiert automatische Guthabenbereinigung bei subAccountNumber >= 128 (leere Positionen werden zu Subkonto 0 transferiert). Im Testnetz fehlt dieser Mechanismus (oder hat abweichende Triggerbedingungen).

  • Token-Nomenklatur
    Native Token-Bezeichnungen differieren: Mainnet DYDX vs. Testnet Dv4TNT

  • Netzwerkkonfiguration
    Chain-IDs und Node-Adressen variieren:

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

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

dYdX v4 Protokollarchitektur

Das dYdX v4 Protokoll basiert auf dem Cosmos-Ökosystem. Das Handelssystem besteht aus zwei Kernkomponenten:

  1. Indexer-Service für Marktdaten und Kontoinformationen
  2. Blockchain-Operationen (Orders, Stornierungen, Transfers)

Indexer

Der Indexer-Service bietet REST- und WebSocket-Schnittstellen.

  • REST-Protokoll
    Ermöglicht Abfragen von Marktdaten, Kontoständen, Positionen und Orderbüchern. FMZ bietet hierfür standardisierte API-Wrapper.

  • WebSocket-Protokoll
    Nutzbar via Dial-Funktion für Echtzeitdaten (z.B. Orderbuch-Updates).

Achtung: Wie bei zentralisierten Börsen können Indexer-Datenverzögerungen auftreten. Nach Orderplatzierungen empfiehlt sich eine Verzögerung (Sleep(n)) vor Folgeabfragen.

Beispiel für WebSocket-Nutzung mit Orderbuch-Subscription:

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

    // Subscription
    self.CreateWsThread = function (msgSubscribe) {
        self.wsThread = threading.Thread(function (streamingPoint, msgSubscribe) {
            // Orderbuch-Objekt
            var orderBook = null 

            // Orderbuch-Update-Logik
            var updateOrderbook = function(orderbook, update) {
                // Bids aktualisieren
                if (update.bids) {
                    update.bids.forEach(([price, size]) => {
                        const priceFloat = parseFloat(price)
                        const sizeFloat = parseFloat(size)

                        if (sizeFloat === 0) {
                            // Lösche Buy-Order bei Preisstufe
orderbook.bids = orderbook.bids.filter(bid => parseFloat(bid.price) !== priceFloat)
                        } else {
                            // Kauforder aktualisieren oder hinzufügen
                            orderbook.bids = orderbook.bids.filter(bid => parseFloat(bid.price) !== priceFloat)
                            orderbook.bids.push({price: price, size: size})
                            // Nach Preis absteigend sortieren
                            orderbook.bids.sort((a, b) => parseFloat(b.price) - parseFloat(a.price))
                        }
                    })
                }

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

                        if (sizeFloat === 0) {
                            // Verkaufsorder mit Preis price entfernen
                            orderbook.asks = orderbook.asks.filter(ask => parseFloat(ask.price) !== priceFloat)
                        } else {
                            // Verkaufsorder aktualisieren oder hinzufügen
                            orderbook.asks = orderbook.asks.filter(ask => parseFloat(ask.price) !== priceFloat)
                            orderbook.asks.push({price: price, size: size})
                            // Nach Preis aufsteigend sortieren
                            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("Erstellen des WebSocket-Threads fehlgeschlagen.")
                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)
    }

    // Überwachung
    self.Peek = function () {
        return self.wsThread.peekMessage()
    }

    return self
}

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

    var symbol = "ETH-USD"
    var manager = dYdXIndexerWSconnManager("wss://indexer.dydx.trade/v4/ws")
```javascript
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) + "`")
    }
}

dYdX-Chain-Knoten-Nachrichtenbroadcasting

Die am häufigsten verwendeten Nachrichten im Handel sind Auftragsnachrichten, Stornierungsnachrichten und Überweisungsnachrichten.

  • Zusammenfassung der Auftragsnachrichten

    {
    "@type": "/dydxprotocol.clob.MsgPlaceOrder",
    "order": {
      "orderId": {
        "subaccountId": {
          "owner": "xxx"
        },
        "clientId": xxx,
        "orderFlags": 64,
        "clobPairId": 1
      },
      "side": "SIDE_BUY",
      "quantums": "2000000",
      "subticks": "3500000000",
      "goodTilBlockTime": 1742295981
    }
    }
    
    • Limit-Order:
      Die auf der FMZ-Plattform gekapselte Orderfunktion verwendet für Limit-Orders den orderFlags-Wert:

    ORDER_FLAGS_LONG_TERM = 64 # Langzeit-Order.
    Gemäß den Einschränkungen des dydx v4-Protokolls wird die maximale Gültigkeitsdauer von 90 Tagen genutzt (alle Ordertypen auf dydx v4 haben eine Verfallszeit).

    • Market-Order:
      Für Market-Orders wird der orderFlags-Wert verwendet:

    ORDER_FLAGS_SHORT_TERM = 0 # Kurzzeit-Order.
    Entsprechend der dydx v4-Empfehlung:

    // Empfohlen wird, den Oracle-Preis minus 5 % oder niedriger für SELL und Oracle-Preis plus 5 % für BUY festzulegen

    Da es sich nicht um echte Market-Orders handelt, wird der Oracle-Preis mit einem Aufschlag/Abzug von 5 % als Ausführungspreis verwendet. Die Gültigkeitsdauer von Kurzzeit-Orders basiert auf Blockhöhen und wird gemäß Protokollvorgabe auf aktuelle Blockhöhe + 10 Blöcke gesetzt.

    • Order-ID:
      Da die Orderausführung direkt on-chain erfolgt, gibt es keine Indexer-generierte Order-ID. Um Eindeutigkeit und Abfragegenauigkeit zu gewährleisten, setzt sich die Order-ID aus folgenden Komponenten zusammen (englische Kommatrennung):

      • Trading-Paar
      • Aktuelle dydx-Kontoadresse
      • Subkontonummer (subaccountNumber)
      • Zufällig generierte clientId
      • Handelsinstrumenten-ID (clobPairId)
      • orderFlags
      • goodTilData (Millisekunden)
  • Zusammenfassung der Stornierungsnachrichten

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

Erfordert die Übergabe der über FMZ-Schnittstelle zurückgegebenen Order-ID.

  • Zusammenfassung der Überweisungsnachrichten
  {
    "@type": "/dydxprotocol.sending.MsgCreateTransfer",
    "transfer": {
      "sender": {
        "owner": "xxx"
      },
      "recipient": {
        "owner": "xxx",
        "number": 128
      },
      "amount": "10000000"
    }
  }

Aktuell können unter einer dydx v4-Adresse viele Subkonten erstellt werden. Dabei ist subAccountNumber 0 das erste automatisch erstellte Subkonto. Subkonten-IDs mit einem subAccountNumber ≥ 128 werden für isolierte Handelsinstrumente verwendet und erfordern mindestens 20 USDC an Vermögen.
Beispielsweise können Transfers von subAccountNumber 0 → 128 oder 128 → 0 durchgeführt werden. Überweisungen verbrauchen Gas-Gebühren, die in USDC oder dydx-Token bezahlt werden können.

Praxisbeispiel für dYdX v4 auf der FMZ-Plattform

Die vorherigen Abschnitte haben grundlegende Implementierungsdetails erläutert. Nun wollen wir die praktische Anwendung untersuchen. Hier verwenden wir das dYdX v4 Testnetz für die Demonstration. Das Testnetz entspricht weitgehend dem Hauptnetz und verfügt über einen automatischen Faucet für Testguthaben. Die Deployment-Prozedur für Host-Nodes wird nicht erneut beschrieben, da wir direkt Live-Tests auf FMZ durchführen.

1. Konfiguration

Nach erfolgreicher Verbindung der Krypto-Wallet mit der dYdX v4 App (hier: imToken Wallet) und Bezug der Testassets, exportieren Sie den Mnemonic des aktuellen dYdX v4 Kontos (wallet-abgeleitet).

Quantitative Praktiken für DEX-Börsen (1) – Leitfaden zu dYdX v4

Konfigurieren Sie den Mnemonic auf der FMZ-Plattform mittels lokaler Datei (alternativ direkte Eingabe - Mnemonics werden verschlüsselt gespeichert, nicht im Klartext).

  • Mnemonic-Datei: mnemonic.txt

Quantitative Praktiken für DEX-Börsen (1) – Leitfaden zu dYdX v4

Speichern Sie die Datei im Host-Node-Verzeichnis unter der Live-Test-ID (alternativ beliebiger Pfad mit entsprechender Pfadangabe).

  • Exchange-Konfiguration auf FMZ

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

Mnemonic-Feld eintragen: file:///mnemonic.txt (entspricht physischem Pfad: Host-Node-Verzeichnis/logs/storage/594291).

Quantitative Praktiken für DEX-Börsen (1) – Leitfaden zu dYdX v4

2. Wechsel zum dYdX v4 Testnetz

function main() {
    // Indexer-Adresse der Testnetzkette ändern
    exchange.SetBase("https://indexer.v4testnet.dydx.exchange")

    // ChainId des Testnetzes setzen
    exchange.IO("chainId", "dydx-testnet-4")

    // REST-API-Endpoint des Testnetzes konfigurieren
    exchange.IO("restApiBase", "https://dydx-testnet-api.polkachu.com")

    // Test des Kontoinformationsabrufs
    Log(exchange.GetAccount()) 
}

Ergebnis des Kontoinformationsabrufs:

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

Nicht zum Testnetz gewechselt, Test mit dem Hauptnetz durchgeführt

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. Orderaufgabe

```js
function main() {
    // Wechseln Sie die Indexer-Adresse der Testnetzkette
    exchange.SetBase("https://indexer.v4testnet.dydx.exchange")

    // Wechseln Sie die ChainId der Testnetzkette
    exchange.IO("chainId", "dydx-testnet-4")

    // Wechseln Sie die REST-Node-Adresse der Testnetzkette
    exchange.IO("restApiBase", "https://dydx-testnet-api.polkachu.com")

    // Limit-Order, Order platzieren
    var idSell = exchange.CreateOrder("ETH_USD.swap", "sell", 4000, 0.002)
    var idBuy = exchange.CreateOrder("ETH_USD.swap", "buy", 3000, 0.003)

    // Market-Order
    var idMarket = exchange.CreateOrder("ETH_USD.swap", "buy", -1, 0.01)

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

Quantitative Praktiken für DEX-Börsen (1) – Leitfaden zu dYdX v4

dYdX v4 App-Oberfläche:

Quantitative Praktiken für DEX-Börsen (1) – Leitfaden zu dYdX v4

5. Orderinformationen

Im Testnetz zwei Orders im Voraus platzieren, um das Abrufen aktueller Orders und das Stornieren von Orders zu testen.

function main() {    
    // Wechseln Sie die Indexer-Adresse der Testnetzkette
    exchange.SetBase("https://indexer.v4testnet.dydx.exchange")

    // Wechseln Sie die ChainId der Testnetzkette
    exchange.IO("chainId", "dydx-testnet-4")

    // Wechseln Sie die REST-Node-Adresse der Testnetzkette
    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) +  "`")
}

Quantitative Praktiken für DEX-Börsen (1) – Leitfaden zu dYdX v4

6. Positionsabfrage

function main() {
    // Wechseln Sie die Indexer-Adresse der Testnetzkette
    exchange.SetBase("https://indexer.v4testnet.dydx.exchange")

    // Wechseln Sie die ChainId der Testnetzkette
    exchange.IO("chainId", "dydx-testnet-4")

    // Wechseln Sie die REST-Node-Adresse der Testnetzkette
    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) +  "`")
}

Quantitative Praktiken für DEX-Börsen (1) – Leitfaden zu dYdX v4

7. Unterkontenverwaltung

function main() {
    // Wechseln Sie die Indexer-Adresse der Testnetzkette
    exchange.SetBase("https://indexer.v4testnet.dydx.exchange")

    // Wechseln Sie die ChainId der Testnetzkette
    exchange.IO("chainId", "dydx-testnet-4")

    // Wechseln Sie die REST-Node-Adresse der Testnetzkette
    exchange.IO("restApiBase", "https://dydx-testnet-api.polkachu.com")

exchange.IO(“restApiBase”, “https://dydx-testnet-api.polkachu.com”)

// SubAccountNumber 0 -> 128: 20 USDC, Gas Fee entspricht adv4tnt (dydx-Token)
var ret = exchange.IO("transferUSDCToSubaccount", 0, 128, "adv4tnt", 20)  
Log("ret:", ret)

// Wechsel zu Subaccount 128 zur Kontostandsprüfung
exchange.IO("subAccountNumber", 128)

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

}


![Quantitative Praktiken für DEX-Börsen (1) – Leitfaden zu dYdX v4](/upload/asset/175bd506389b9e8966ca.png)

Auszug aus den zurückgegebenen Daten nach Wechsel zu Subaccount 128:

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

Der Subaccount mit der Nummer 128 zeigt erfolgreich transferierte 20 USDC an.

8. TxHash-Erfassung über REST-Node-Interface

Abfrage von TxHash über Order-ID mittels REST-Node

TxHash-Ermittlung: Die dydx-Exchange-Instanz speichert TxHash temporär. Die Abfrage erfolgt über Order-ID. Hinweis: Bei Strategiestopp wird der Cache geleert.

function main() {
    // Wechseln Sie die Indexer-Adresse der Testchain
    exchange.SetBase("https://indexer.v4testnet.dydx.exchange")

    // ChainId der Testchain setzen
    exchange.IO("chainId", "dydx-testnet-4")

    // REST-Node-Adresse der Testchain setzen
    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)
    
    // Zum Leeren der Mapping-Tabelle kann verwendet werden: 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)
    }
}

Quantitative Praktiken für DEX-Börsen (1) – Leitfaden zu dYdX v4

Über TxHash abgefragte Nachricht:

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

Inhalt zu lang, Auszug zur Demonstration:

{
	"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": []
			},
      ...

ENDE

Dieser Test basiert auf dem aktuellsten Custodian. Der neueste Custodian muss heruntergeladen werden, um dYdX v4 DEX zu unterstützen

Vielen Dank für Ihre Unterstützung und für das Lesen dieses Artikels.