Với sự gia tăng nhanh chóng của sàn giao dịch phi tập trung (DEX) trong lĩnh vực giao dịch tiền điện tử, các nhà giao dịch định lượng đã dần chuyển sang các nền tảng này để giao dịch tự động hiệu quả. Là một trong những nền tảng giao dịch phi tập trung phổ biến nhất, dYdX cung cấp các chức năng giao dịch mạnh mẽ và hỗ trợ giao dịch hợp đồng vĩnh viễn tương lai. Phiên bản mới nhất của nó v4 tối ưu hóa hiệu suất và trải nghiệm người dùng, làm cho nó trở thành lựa chọn đầu tiên cho nhiều nhà giao dịch định lượng.
Bài viết này sẽ giới thiệu cách thực hành giao dịch định lượng trên dYdX v4, bao gồm cách sử dụng API của nó để giao dịch, thu thập dữ liệu thị trường và quản lý tài khoản.
dYdX v3
Với Ethereum, giao dịch tạo ra phần thưởng, đó là phần thưởngdYdX
tokens.Địa chỉ ứng dụng dYdX v4 hiện tại là:
Sau khi mở trang ứng dụng, có một nút để kết nối với ví ở góc trên bên phải.
Nếu bạn muốn thử nghiệm và làm quen với môi trường mạng thử nghiệm trước tiên, bạn có thể sử dụng mạng thử nghiệm:
Ngoài ra, nhấp vào nút kết nối ví ở góc trên bên phải, quét mã để kết nối ví và xác minh chữ ký. Sau khi ví được kết nối thành công, địa chỉ dydx v4 sẽ tự động được tạo ra. Địa chỉ này sẽ được hiển thị ở góc trên bên phải của trang Ứng dụng. Nhấp vào nó và một menu sẽ bật lên. Có các hoạt động như sạc, rút tiền và chuyển tiền. Một trong những khác biệt giữa dYdX mainnet (môi trường sản xuất) và testnet là khi bạn nhấp vào sạc trên testnet, 300 tài sản USDC sẽ tự động được sạc bằng vòi phun để thử nghiệm. Nếu bạn muốn thực hiện giao dịch thực trên dYdX, bạn cần sạc tài sản USDC. Sạc lại cũng rất thuận tiện và tương thích với nhiều tài sản và chuỗi để sạc lại.
Địa chỉ tài khoản dYdX v4
Địa chỉ tài khoản dYdX v4 được bắt nguồn từ địa chỉ ví. Địa chỉ tài khoản dYdX v4 trông như sau:dydx1xxxxxxxxxxxxxxxxxxxxq2ge5jr4nzfeljxxxx
, đó là một địa chỉ bắt đầu với dydx1.
Mnemonics
Bạn có thể sử dụng nút
Các mnemonics có thể được cấu hình trực tiếp trên nền tảng FMZ hoặc lưu cục bộ trên dock. Khi sử dụng đối tượng trao đổi dydx v4, nội dung tệp ghi các mnemonics sẽ được đọc, sẽ được chứng minh trong phần thực tế của bài viết này.
Môi trường testnet khác với môi trường mainnet trong một số khía cạnh.
subAccountNumber >= 128
, nếu tài khoản phụ của ID không có vị trí, tài sản sẽ tự động được xóa vào tài khoản phụ có số tài khoản phụ là 0.
Trong quá trình thử nghiệm, nó được tìm thấy rằng mạng thử nghiệm không có cơ chế này (hoặc các điều kiện kích hoạt khác nhau và nó đã không được kích hoạt trong mạng thử nghiệm).DYDX
, testnetDv4TNT
Mạng chính:
Địa chỉ chỉ mục:https://indexer.dydx.trade
ID chuỗi:dydx-mainnet-1
REST Node:https://dydx-dao-api.polkachu.com:443
Testnet:
Địa chỉ chỉ mục:https://indexer.v4testnet.dydx.exchange
ID chuỗi:dydx-testnet-4
REST Node:https://dydx-testnet-api.polkachu.com
Giao thức dYdX v4 được phát triển dựa trên hệ sinh thái vũ trụ.
Dịch vụ lập chỉ mục cung cấp các giao thức REST và Websocket.
REST giao thức Giao diện giao thức REST hỗ trợ truy vấn thông tin thị trường, thông tin tài khoản, thông tin vị trí, thông tin đơn đặt hàng và các truy vấn khác, và đã được đóng gói như một giao diện API thống nhất trên nền tảng FMZ.
Giao thức WebSocket Trên nền tảng FMZ, bạn có thể sử dụng chức năng Dial để tạo kết nối Websocket và đăng ký thông tin thị trường.
Cần lưu ý rằng trình lập chỉ mục của dydx v4 có cùng một vấn đề như các sàn giao dịch tập trung, tức là việc cập nhật dữ liệu không phải là kịp thời. Ví dụ, đôi khi bạn có thể không thể tìm thấy lệnh nếu bạn truy vấn nó ngay sau khi đặt lệnh.Sleep(n)
) một số hoạt động trước khi truy vấn.
Dưới đây là một ví dụ về việc sử dụng hàm Dial để tạo kết nối API Websocket và đăng ký dữ liệu sổ đặt hàng:
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) + "`")
}
}
Các tin nhắn được sử dụng phổ biến nhất trong giao dịch là tin nhắn đặt hàng, tin nhắn hủy đặt hàng và tin nhắn chuyển tiền.
{
"@type": "/dydxprotocol.clob.MsgPlaceOrder",
"order": {
"orderId": {
"subaccountId": {
"owner": "xxx"
},
"clientId": xxx,
"orderFlags": 64,
"clobPairId": 1
},
"side": "SIDE_BUY",
"quantums": "2000000",
"subticks": "3500000000",
"goodTilBlockTime": 1742295981
}
}
Trật tự giới hạn:
Trong hàm lệnh được đóng gói trên nền tảng FMZ, giá trị orderFlags được sử dụng cho các lệnh giới hạn là:ORDER_FLAGS_LONG_TERM = 64 # Long-term order
Theo các hạn chế của giao thức dydx v4, thời gian hợp lệ đặt hàng dài nhất được sử dụng, đó là 90 ngày (tất cả các loại lệnh trên dydx v4 đều có thời gian hợp lệ).
Trật tự thị trường:
Trong hàm lệnh được đóng gói trên nền tảng FMZ, giá trị orderFlags được sử dụng cho các lệnh thị trường là:ORDER_FLAGS_SHORT_TERM = 0 # Short-term order
, theo các khuyến nghị của giao thức dydx v4:
// Đề xuất đặt giá oracle - 5% hoặc thấp hơn cho SELL, giá oracle + 5% cho BUY
Vì nó không phải là lệnh thị trường thực sự, giá Oracle được sử dụng, cộng hoặc trừ 5% trượt như lệnh thị trường. Thời gian hiệu lực của lệnh ngắn hạn cũng khác với thời gian hiệu lực của lệnh dài hạn.
Các cặp giao dịch Địa chỉ tài khoản hiện tại dydx Số tài khoản phụ (subaccountNumber) clientId (được tạo ngẫu nhiên) clobPairId (định dạng ký hiệu giao dịch) orderTờ cờ goodTilData (tỷ số giây)
{
"@type": "/dydxprotocol.clob.MsgCancelOrder",
"orderId": {
"subaccountId": {
"owner": "xxx"
},
"clientId": 2585872024,
"orderFlags": 64,
"clobPairId": 1
},
"goodTilBlockTime": 1742295981
}
ID lệnh được trả về bởi giao diện lệnh nền tảng FMZ cần được truyền vào.
{
"@type": "/dydxprotocol.sending.MsgCreateTransfer",
"transfer": {
"sender": {
"owner": "xxx"
},
"recipient": {
"owner": "xxx",
"number": 128
},
"amount": "10000000"
}
}
Nhiều tài khoản phụ có thể được tạo dưới địa chỉ dydx v4 hiện tại. Tài khoản phụ với subAccountNumber 0 là tài khoản phụ được tạo tự động đầu tiên. ID tài khoản phụ với subAccountNumber lớn hơn hoặc bằng 128 được sử dụng cho giao dịch vị trí cô lập, đòi hỏi ít nhất 20 tài sản USDC. Ví dụ, bạn có thể đi từ subAccountNumber 0 -> 128, hoặc từ subAccountNumber 128 -> 0.
Nội dung trên giải thích một số chi tiết về gói một cách ngắn gọn. Tiếp theo, hãy thực hành việc sử dụng cụ thể. Ở đây chúng ta sử dụng mạng thử nghiệm dYdX v4 để chứng minh. Mạng thử nghiệm về cơ bản giống như mạng chính, và có một vòi nước tự động để nhận tài sản thử nghiệm. Hoạt động triển khai docker sẽ không được lặp lại. Tạo một thử nghiệm giao dịch trực tiếp trên FMZ.
Sau khi kết nối với ứng dụng dYdX v4 thành công bằng cách sử dụng ví tiền điện tử (tôi sử dụng ví imToken ở đây), yêu cầu tài sản thử nghiệm của bạn và sau đó xuất mnemonic cho tài khoản dYdX v4 hiện tại của bạn (được bắt nguồn từ ví của bạn).
Thiết lập mnemonic trên nền tảng FMZ. Ở đây chúng tôi sử dụng phương thức tập tin cục bộ để cấu hình nó (bạn cũng có thể điền trực tiếp và cấu hình nó trên nền tảng.
Đặt nó trong thư mục thư mục ID giao dịch trực tiếp dưới thư mục docker.
Điền vào hộp chỉnh sửa ký ức:file:///mnemonic.txt
, đường thực tế tương ứng là: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())
}
Đọc thông tin tài khoản mạng thử nghiệm:
{
"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
}
Không chuyển sang mạng thử nghiệm, được thử nghiệm với mạng chính
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)
}
Trang ứng dụng dYdX v4:
Mạng thử nghiệm đặt hai đơn đặt hàng trước, thử nghiệm lấy các đơn đặt hàng đang chờ và hủy các đơn đặt hàng.
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)
}
Thông tin nhật ký:
Chuyển sang tài khoản con có số tài khoản con là 128, và dữ liệu được trả về bởi GetAccount là:
{
"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
}
Có thể thấy rằng tài khoản phụ với tài khoản phụ số 128 đã chuyển 20 USDC.
Theo lệnh, lấy TxHash và kiểm tra phương pháp của IO gọi REST node
Làm thế nào để lấy TxHash của một lệnh? Đối tượng trao đổi dydx sẽ lưu trữ bộ nhớ cache TxHash, có thể được truy vấn bằng cách sử dụng ID lệnh. Tuy nhiên, sau khi chiến lược được dừng lại, bản đồ hash tx được lưu trữ sẽ được xóa.
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)
}
}
Tin nhắn được truy vấn qua TxHash:
var ret =exchange.IO("api",
GET , /cosmos/tx/v1beta1/txs/ + txHash)
Nội dung quá dài, vì vậy đây là một số đoạn trích để chứng minh:
{
"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": []
},
...
Các bài kiểm tra trên dựa trên docker mới nhất. Bạn cần tải xuống docker mới nhất để hỗ trợ dYdX v4 DEX
Cảm ơn sự ủng hộ của các bạn và cảm ơn đã đọc.