Dengan peningkatan pertukaran terdesentralisasi (DEX) yang pesat dalam bidang perdagangan mata wang kripto, pedagang kuantitatif telah beralih kepada platform ini secara beransur-ansur untuk perdagangan automatik yang cekap. Sebagai salah satu platform perdagangan terdesentralisasi yang paling popular, dYdX menyediakan fungsi perdagangan yang kuat dan menyokong perdagangan kontrak kekal niaga hadapan. Versi terbarunya v4 mengoptimumkan prestasi dan pengalaman pengguna, menjadikannya pilihan pertama bagi banyak pedagang kuantitatif.
Artikel ini akan memperkenalkan cara mengamalkan perdagangan kuantitatif di dYdX v4, termasuk cara menggunakan API untuk berdagang, mendapatkan data pasaran, dan menguruskan akaun.
dYdX v3
Dengan Ethereum, perdagangan menjana ganjaran, yang merupakan ganjarandYdX
tokens.Pertukaran DEX protokol dYdX v3 sebelum ini telah di luar talian. Alamat aplikasi dYdX v4 semasa adalah:
Selepas membuka halaman Aplikasi, terdapat butang untuk menyambung ke dompet di sudut kanan atas. Imbas kod QR untuk menyambung ke dompet.
Jika anda ingin menguji dan membiasakan diri dengan persekitaran rangkaian ujian terlebih dahulu, anda boleh menggunakan rangkaian ujian:
Selain itu, klik butang menyambung dompet di sudut kanan atas, imbas kod untuk menyambung dompet, dan mengesahkan tandatangan. Selepas dompet disambungkan dengan berjaya, alamat dydx v4 akan dijana secara automatik. Alamat ini akan dipaparkan di sudut kanan atas halaman Aplikasi. Kliknya dan menu akan muncul. Terdapat operasi seperti pengecasan, pengeluaran, dan pemindahan. Salah satu perbezaan antara dYdX mainnet (lingkungan pengeluaran) dan testnet adalah apabila anda mengklik pengecasan di testnet, aset 300 USDC akan dikenakan secara automatik menggunakan keran untuk ujian. Jika anda ingin melakukan transaksi sebenar di dYdX, anda perlu mengenakan aset USDC. Pengisian semula juga sangat mudah dan serasi dengan pelbagai aset dan rantaian untuk pengecasan semula.
Alamat akaun dYdX v4
Alamat akaun dYdX v4 berasal dari alamat dompet. Alamat akaun dYdX v4 kelihatan seperti:dydx1xxxxxxxxxxxxxxxxxxxxq2ge5jr4nzfeljxxxx
, yang merupakan alamat yang bermula dengan dydx1. Alamat ini boleh ditanyakan dalam penjelajah blockchain.
Mnemonik
Anda boleh menggunakan butang
Mnemonics boleh dikonfigurasi secara langsung di platform FMZ atau disimpan secara tempatan di docker. Apabila menggunakan objek pertukaran dydx v4, kandungan fail yang merakam mnemonics akan dibaca, yang akan ditunjukkan dalam bahagian praktikal artikel ini.
Kawasan testnet berbeza dengan persekitaran mainnet dalam beberapa aspek.
subAccountNumber >= 128
, jika sub- akaun ID tidak mempunyai kedudukan, aset akan dibasmi secara automatik ke sub- akaun yang subAccountNumber adalah 0.
Semasa ujian, didapati bahawa rangkaian ujian tidak mempunyai mekanisme ini (atau keadaan pencetus berbeza dan ia tidak dicetuskan dalam rangkaian ujian).DYDX
, testnetDv4TNT
Rangkaian utama:
Alamat penanda:https://indexer.dydx.trade
ID rantaian:dydx-mainnet-1
REST Node:https://dydx-dao-api.polkachu.com:443
Rangkaian ujian:
Alamat penanda:https://indexer.v4testnet.dydx.exchange
ID rantaian:dydx-testnet-4
REST Node:https://dydx-testnet-api.polkachu.com
Protokol dYdX v4 dibangunkan berdasarkan ekosistem kosmos.
Perkhidmatan pengindeksan menyediakan protokol REST dan Websocket.
Protokol REST Antara muka protokol REST menyokong pertanyaan maklumat pasaran, maklumat akaun, maklumat kedudukan, maklumat pesanan dan pertanyaan lain, dan telah disusun sebagai antara muka API bersatu pada platform FMZ.
Protokol WebSocket Pada platform FMZ, anda boleh menggunakan fungsi Dial untuk membuat sambungan Websocket dan melanggan maklumat pasaran.
Perlu diperhatikan bahawa indexer dydx v4 mempunyai masalah yang sama seperti pertukaran terpusat, iaitu, kemas kini data tidak begitu tepat pada masanya.Sleep(n)
) operasi tertentu sebelum membuat pertanyaan.
Berikut adalah contoh menggunakan fungsi Dial untuk membuat sambungan Websocket API dan melanggan data buku pesanan:
function dYdXIndexerWSconnManager(streamingPoint) {
var self = {}
self.base = streamingPoint
self.wsThread = null
// subscription
self.CreateWsThread = function (msgSubscribe) {
self.wsThread = threading.Thread(function (streamingPoint, msgSubscribe) {
// Order book
var orderBook = null
// Update order book
var updateOrderbook = function(orderbook, update) {
// Update bids
if (update.bids) {
update.bids.forEach(([price, size]) => {
const priceFloat = parseFloat(price)
const sizeFloat = parseFloat(size)
if (sizeFloat === 0) {
// Delete the buy order with price
orderbook.bids = orderbook.bids.filter(bid => parseFloat(bid.price) !== priceFloat)
} else {
// Update or add a buy order
orderbook.bids = orderbook.bids.filter(bid => parseFloat(bid.price) !== priceFloat)
orderbook.bids.push({price: price, size: size})
// Sort by price descending
orderbook.bids.sort((a, b) => parseFloat(b.price) - parseFloat(a.price))
}
})
}
// Update asks
if (update.asks) {
update.asks.forEach(([price, size]) => {
const priceFloat = parseFloat(price)
const sizeFloat = parseFloat(size)
if (sizeFloat === 0) {
// Delete the sell order with price
orderbook.asks = orderbook.asks.filter(ask => parseFloat(ask.price) !== priceFloat)
} else {
// Update or add a sell order
orderbook.asks = orderbook.asks.filter(ask => parseFloat(ask.price) !== priceFloat)
orderbook.asks.push({price: price, size: size})
// Sort by price ascending
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)
}
// monitor
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) + "`")
}
}
Mesej yang paling biasa digunakan dalam transaksi adalah mesej pesanan, mesej pembatalan pesanan, dan mesej pemindahan.
{
"@type": "/dydxprotocol.clob.MsgPlaceOrder",
"order": {
"orderId": {
"subaccountId": {
"owner": "xxx"
},
"clientId": xxx,
"orderFlags": 64,
"clobPairId": 1
},
"side": "SIDE_BUY",
"quantums": "2000000",
"subticks": "3500000000",
"goodTilBlockTime": 1742295981
}
}
Perintah had:
Dalam fungsi pesanan yang dikemas dalam platform FMZ, nilai orderFlags yang digunakan untuk pesanan had ialah:ORDER_FLAGS_LONG_TERM = 64 # Long-term order
Menurut batasan protokol dydx v4, tempoh sah pesanan terpanjang digunakan, iaitu 90 hari (semua jenis pesanan pada dydx v4 mempunyai tempoh sah).
Perintah pasaran:
Dalam fungsi pesanan yang dikemas dalam platform FMZ, nilai orderFlags yang digunakan untuk pesanan pasaran adalah:ORDER_FLAGS_SHORT_TERM = 0 # Short-term order
, mengikut cadangan protokol dydx v4:
// mengesyorkan ditetapkan kepada harga oracle - 5% atau lebih rendah untuk menjual, harga oracle + 5% untuk membeli
Oleh kerana ini bukan pesanan pasaran yang sebenar, harga oracle digunakan, ditambah atau dikurangkan 5% slippage sebagai pesanan pasaran. Tempoh kelayakan pesanan jangka pendek juga berbeza dengan pesanan jangka panjang. Perintah jangka pendek menggunakan tempoh kelayakan ketinggian blok, yang ditetapkan pada blok semasa + 10 ketinggian blok mengikut cadangan dydx v4.
Pasangan Dagangan alamat akaun semasa dydx Nombor sub akaun (sub akaunNombor) clientId (dijana secara rawak) clobPairId (ID simbol transaksi) PerintahBendera goodTilData (milisaat)
{
"@type": "/dydxprotocol.clob.MsgCancelOrder",
"orderId": {
"subaccountId": {
"owner": "xxx"
},
"clientId": 2585872024,
"orderFlags": 64,
"clobPairId": 1
},
"goodTilBlockTime": 1742295981
}
ID pesanan yang dikembalikan oleh antara muka pesanan platform FMZ perlu dihantar.
{
"@type": "/dydxprotocol.sending.MsgCreateTransfer",
"transfer": {
"sender": {
"owner": "xxx"
},
"recipient": {
"owner": "xxx",
"number": 128
},
"amount": "10000000"
}
}
Banyak sub-akaun boleh dicipta di bawah alamat dydx v4 semasa. Sub-akaun dengan subAccountNumber 0 adalah sub-akaun pertama yang dicipta secara automatik. ID sub-akaun dengan subAccountNumber lebih besar daripada atau sama dengan 128 digunakan untuk perdagangan kedudukan yang terpencil, yang memerlukan sekurang-kurangnya 20 aset USDC. Sebagai contoh, anda boleh pergi dari subAccountNumber 0 -> 128, atau dari subAccountNumber 128 -> 0. Pemindahan memerlukan Bayaran Gas. Bayaran Gas boleh USDC atau token dydx.
Kandungan di atas menjelaskan beberapa butiran pembungkusan secara ringkas. Seterusnya, mari kita berlatih penggunaan tertentu. Di sini kita menggunakan rangkaian ujian dYdX v4 untuk demonstrasi. Rangkaian ujian pada dasarnya sama dengan rangkaian utama, dan terdapat keran automatik untuk menerima aset ujian. Operasi penggunaan docker tidak akan diulang. Buat ujian perdagangan langsung di FMZ.
Selepas menyambung ke Aplikasi dYdX v4 dengan berjaya dengan menggunakan dompet cryptocurrency (saya menggunakan dompet imToken di sini), menuntut aset ujian anda dan kemudian mengeksport mnemonik untuk akaun dYdX v4 semasa anda (berasal dari dompet anda).
Mengkonfigurasi mnemonic pada platform FMZ. Di sini kita menggunakan kaedah fail tempatan untuk mengkonfigurasi ia (anda juga boleh mengisi secara langsung dan mengkonfigurasi ia ke platform. mnemonic dikonfigurasi selepas penyulitan, bukan dalam teks biasa).
Letakkan ia dalam direktori folder ID perdagangan langsung di bawah direktori docker.
Isi kotak penyuntingan mnemonik:file:///mnemonic.txt
, laluan sebenar yang sepadan adalah:docker directory/logs/storage/594291
.
function main() {
// Switch the indexer address of the test chain
exchange.SetBase("https://indexer.v4testnet.dydx.exchange")
// Switch the ChainId of the test chain
exchange.IO("chainId", "dydx-testnet-4")
// Switch the REST node address of the test chain
exchange.IO("restApiBase", "https://dydx-testnet-api.polkachu.com")
// Read account information test
Log(exchange.GetAccount())
}
Baca maklumat akaun rangkaian ujian:
{
"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
}
Tidak beralih ke rangkaian ujian, diuji dengan rangkaian utama
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) + "`")
}
function main() {
// Switch the indexer address of the test chain
exchange.SetBase("https://indexer.v4testnet.dydx.exchange")
// Switch the ChainId of the test chain
exchange.IO("chainId", "dydx-testnet-4")
// Switch the REST node address of the test chain
exchange.IO("restApiBase", "https://dydx-testnet-api.polkachu.com")
// Limit order, pending order
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)
}
Laman aplikasi dYdX v4:
Rangkaian ujian meletakkan dua pesanan terlebih dahulu, ujian mendapatkan pesanan yang sedang menunggu, dan membatalkan pesanan.
function main() {
// Switch the indexer address of the test chain
exchange.SetBase("https://indexer.v4testnet.dydx.exchange")
// Switch the ChainId of the test chain
exchange.IO("chainId", "dydx-testnet-4")
// Switch the REST node address of the test chain
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) + "`")
}
function main() {
// Switch the indexer address of the test chain
exchange.SetBase("https://indexer.v4testnet.dydx.exchange")
// Switch the ChainId of the test chain
exchange.IO("chainId", "dydx-testnet-4")
// Switch the REST node address of the test chain
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) + "`")
}
function main() {
// Switch the indexer address of the test chain
exchange.SetBase("https://indexer.v4testnet.dydx.exchange")
// Switch the ChainId of the test chain
exchange.IO("chainId", "dydx-testnet-4")
// Switch the REST node address of the test chain
exchange.IO("restApiBase", "https://dydx-testnet-api.polkachu.com")
// subAccountNumber 0 -> 128 : 20 USDC, Gas Fee is adv4tnt, i.e. dydx token
// var ret = exchange.IO("transferUSDCToSubaccount", 0, 128, "adv4tnt", 20)
// Log("ret:", ret)
// Switch to subaccount subAccountNumber 128 and read account information to check
exchange.IO("subAccountNumber", 128)
var account = exchange.GetAccount()
Log("account:", account)
}
Maklumat log:
Bertukar ke subaccount yang subAccountNumber adalah 128, dan data yang dikembalikan oleh GetAccount adalah:
{
"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
}
Kita boleh lihat bahawa sub-akaun dengan sub-akaun nombor 128 telah memindahkan 20 USDC.
Menurut perintah, mendapatkan TxHash dan menguji kaedah IO memanggil nod REST
Bagaimana untuk mendapatkan TxHash pesanan? objek pertukaran dydx akan cache TxHash, yang boleh ditanyakan dengan menggunakan ID pesanan. Walau bagaimanapun, selepas strategi dihentikan, peta hash pesanan tx yang disimpan akan dihapuskan.
function main() {
// Switch the indexer address of the test chain
exchange.SetBase("https://indexer.v4testnet.dydx.exchange")
// Switch the ChainId of the test chain
exchange.IO("chainId", "dydx-testnet-4")
// Switch the REST node address of the test chain
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)
// To clear the mapping table, use: 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)
}
}
Mesej yang ditanyakan melalui TxHash:
var ret =exchange.IO("api",
GET , /cosmos/tx/v1beta1/txs/ + txHash)
Kandungannya terlalu panjang, jadi berikut adalah beberapa petikan untuk demonstrasi:
{
"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": []
},
...
Ujian di atas adalah berdasarkan docker terbaru. anda perlu memuat turun docker terbaru untuk menyokong dYdX v4 DEX
Terima kasih atas sokongan anda dan terima kasih kerana membaca.