avatar of 发明者量化-小小梦 发明者量化-小小梦
집중하다 사신
4
집중하다
1271
수행원

DEX 거래소 양적 연습 (1) -- dYdX v4 사용자 가이드

만든 날짜: 2024-12-24 17:09:32, 업데이트 날짜: 2024-12-26 21:41:46
comments   0
hits   1049

[TOC]

DEX 거래소 양적 연습 (1) – dYdX v4 사용자 가이드

머리말

암호화폐 거래 분야에서 분산형 거래소(DEX)가 급속히 성장함에 따라, 양적 거래자들은 점차 효율적인 자동 거래를 위해 이러한 플랫폼으로 눈을 돌리기 시작했습니다. 가장 인기 있는 분산형 거래 플랫폼 중 하나인 dYdX는 강력한 거래 기능을 제공하고 선물 영구 계약 거래를 지원합니다. 최신 버전 v4는 성능과 사용자 경험을 최적화하여 많은 양적 거래자에게 첫 번째 선택이 되었습니다.

이 글에서는 dYdX v4에서 양적 거래를 실행하는 방법을 소개합니다. 여기에는 API를 사용하여 거래하고, 시장 데이터를 얻고, 계정을 관리하는 방법이 포함됩니다.

  • 테스트 환경 전환
  • 시장 정보 질의
  • 주문정보 및 위치정보 조회
  • 주문하기
  • 하위 계정 관리
  • 노드 메서드 요청

dYdX v4 DEX

  • dYdX 테스트넷 앱 페이지

DEX 거래소 양적 연습 (1) – dYdX v4 사용자 가이드

  • 그리고dYdX v3마찬가지로 거래는 보상을 생성합니다.dYdX토큰.

DEX 거래소 양적 연습 (1) – dYdX v4 사용자 가이드

지갑 연결, 로그인 및 구성 정보

이전 dYdX v3 프로토콜 DEX 거래소는 오프라인 상태였습니다. 현재 dYdX v4 앱 주소는 다음과 같습니다.

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

앱 페이지를 열면 오른쪽 상단에 지갑에 연결하는 버튼이 있습니다. QR 코드를 스캔하여 지갑에 연결하세요.

먼저 테스트 네트워크 환경을 테스트하고 익숙해지려면 테스트 네트워크를 사용할 수 있습니다.

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

또한 오른쪽 상단 모서리에 있는 지갑 연결 버튼을 클릭하고 QR 코드를 스캔하여 지갑을 연결하고 서명을 확인하세요. 지갑이 성공적으로 연결되면 dydx v4 주소가 자동으로 생성됩니다. 이 주소는 앱 페이지의 오른쪽 상단에 표시됩니다. 클릭하면 메뉴가 팝업됩니다. 여기에는 충전, 인출, 이체 등의 작업이 포함됩니다. dYdX 메인넷(생산 환경)과 테스트넷의 차이점 중 하나는 테스트넷에서 충전 버튼을 클릭하면 300개의 USDC 자산이 테스트를 위해 자동으로 포싯에 입금된다는 것입니다. dYdX에서 실제 거래를 하려면 USDC 자산을 입금해야 합니다. 충전도 매우 편리하고 여러 자산 및 체인과 호환됩니다.

  • dYdX v4 계정 주소 dYdX v4 계정 주소는 지갑 주소에서 파생됩니다. dYdX v4 계정 주소는 다음과 같습니다.dydx1xxxxxxxxxxxxxxxxxxxxq2ge5jr4nzfeljxxxx, 는 dydx1로 시작하는 주소입니다. 이 주소는 블록체인 탐색기에서 쿼리할 수 있습니다.

  • 기억술 오른쪽 상단 메뉴에 있는 “비밀번호 내보내기” 버튼을 클릭하면 현재 dYdX 주소 계정의 니모닉을 내보낼 수 있습니다. FMZ 플랫폼에 거래소를 추가할 때 이 니모닉을 구성해야 합니다.

니모닉은 FMZ 플랫폼에서 직접 구성하거나 관리자에게 로컬로 저장할 수 있습니다. dydx v4 교환 객체를 사용할 때 니모닉을 기록한 파일 내용이 읽히게 되며, 이는 이 문서의 실제 부분에서 설명됩니다.

메인넷과 테스트넷의 차이점

테스트넷 환경은 어떤 면에서 메인넷 환경과 다릅니다. 몇 가지 간단한 차이점을 소개합니다.

  • 하위 계정 자산 이전. 메인 네트워크에는 하위 계정 정리 메커니즘이 있습니다.subAccountNumber >= 128이 ID를 가진 하위 계정에 포지션이 없으면 자산은 자동으로 subAccountNumber 0인 하위 계정으로 청산됩니다. 테스트를 진행하는 동안, 테스트 네트워크에는 그러한 메커니즘이 없다는 것(또는 트리거 조건이 달라 테스트 네트워크에서 트리거되지 않았다는 것)이 발견되었습니다.

  • 일부 토큰 이름. 네이티브 토큰 dydx는 이름이 다릅니다: MainnetDYDX, 테스트 네트워크Dv4TNT

  • 체인 ID, 노드 주소, 인덱서 주소 등과 같은 주소 구성 다양한 노드와 구성이 있는데 그 중 하나는 다음과 같습니다.

    • 메인넷: 인덱서 주소:https://indexer.dydx.trade 체인 ID:dydx-mainnet-1 REST 노드:https://dydx-dao-api.polkachu.com:443

    • 테스트넷: 인덱서 주소:https://indexer.v4testnet.dydx.exchange 체인 ID:dydx-testnet-4 REST 노드:https://dydx-testnet-api.polkachu.com

dYdX v4 프로토콜 아키텍처

dYdX v4 프로토콜은 코스모스 생태계를 기반으로 개발되었습니다. dYdX v4 DEX 시스템 거래 관련 콘텐츠는 주로 두 부분으로 구성됩니다.

  • 시장 정보, 계좌 정보 등을 쿼리하는 역할을 하는 인덱서입니다.
  • dydx 블록체인 주문 메시지, 주문 취소 메시지, 이체 메시지 등

인덱서

인덱서 서비스는 REST 및 웹소켓 프로토콜을 제공합니다.

  • REST 프로토콜 REST 프로토콜 인터페이스는 시장 정보 쿼리, 계정 정보, 포지션 정보, 주문 정보 등을 지원하며, FMZ 플랫폼에서 통합 API 인터페이스로 캡슐화되었습니다.

  • 웹소켓 프로토콜 FMZ 플랫폼에서는 Dial 기능을 사용하여 웹소켓 연결을 생성하고 시장 정보를 구독할 수 있습니다.

dydx v4 인덱서는 중앙화된 거래소와 동일한 문제가 있다는 점에 유의해야 합니다. 즉, 데이터 업데이트가 시기적절하지 않습니다. 예를 들어, 주문을 한 직후에 쿼리를 실행하면 주문을 찾을 수 없는 경우가 있습니다. 특정 작업 후에는 다음이 권장됩니다.Sleep(n)) 다시 쿼리하기 전에 몇 초간 기다리세요.

다음은 Dial 함수를 사용하여 Websocket API 연결을 생성하고 주문서 데이터를 구독하는 예입니다.

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

dYdX 체인 노드 메시지 브로드캐스트

거래에서 가장 일반적으로 사용되는 메시지는 주문 메시지, 주문 취소 메시지, 이체 메시지입니다.

  • 주문 메시지 요약
  {
    "@type": "/dydxprotocol.clob.MsgPlaceOrder",
    "order": {
      "orderId": {
        "subaccountId": {
          "owner": "xxx"
        },
        "clientId": xxx,
        "orderFlags": 64,
        "clobPairId": 1
      },
      "side": "SIDE_BUY",
      "quantums": "2000000",
      "subticks": "3500000000",
      "goodTilBlockTime": 1742295981
    }
  }
  • 제한 주문: FMZ 플랫폼에 캡슐화된 주문 함수에서 지정가 주문에 사용되는 orderFlags 값은 다음과 같습니다.ORDER_FLAGS_LONG_TERM = 64 # 长期订单DYDX v4 프로토콜의 한계에 따라 가장 긴 주문 유효 기간인 90일이 사용됩니다(DYDX v4의 모든 유형의 주문에는 유효 기간이 있습니다).

  • 시장 주문: FMZ 플랫폼에 캡슐화된 주문 함수에서 시장 주문에 사용되는 orderFlags 값은 다음과 같습니다.ORDER_FLAGS_SHORT_TERM = 0 # 短期订单DYDX v4 프로토콜 권장 사항에 따르면:

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

    실제 시장 주문이 아니므로 오라클 가격에 플러스마이너스 5%의 슬리피지를 시장 주문으로 사용합니다. 단기 주문의 유효 기간 설정도 장기 주문과 다릅니다. 단기 주문은 블록 높이 유효 기간을 사용합니다. dydx v4의 권장 사항에 따르면 현재 블록 + 10 블록 높이로 설정됩니다. 만료되기 전에.

  • 주문 ID: 주문 작업이 체인에서 직접 수행되므로 메시지가 브로드캐스트된 후 인덱서에서 주문 ID가 생성되지 않으며 인덱서 주문은 플랫폼 주문 함수의 반환 값으로 사용할 수 없습니다. 고유성을 보장하기 위해 주문 ID와 주문 쿼리의 정확도를 기준으로 인덱서 주문이 반환됩니다. 주문 ID는 다음 정보로 구성됩니다(쉼표로 구분):

    • 거래 쌍
    • dydx 현재 계좌 주소
    • 하위 계정 번호(subaccountNumber)
    • clientId (무작위로 생성됨)
    • clobPairId(거래 심볼 ID)
    • orderFlags
    • goodTilData(밀리초)
  • 주문 취소 메시지 요약

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

FMZ 플랫폼 주문 인터페이스에서 반환된 주문 ID를 전달해야 합니다.

  • 메시지 요약 전송
  {
    "@type": "/dydxprotocol.sending.MsgCreateTransfer",
    "transfer": {
      "sender": {
        "owner": "xxx"
      },
      "recipient": {
        "owner": "xxx",
        "number": 128
      },
      "amount": "10000000"
    }
  }

현재 dydx v4 주소에서 많은 하위 계정을 만들 수 있습니다. subAccountNumber 0인 하위 계정은 자동으로 생성된 첫 번째 하위 계정입니다. subAccountNumber가 128 이상인 하위 계정 ID는 격리된 포지션 거래에 사용됩니다. 최소 20개의 USDC 자산이 필요합니다. 예를 들어, subAccountNumber 0 -> 128, 또는 subAccountNumber 128 -> 0으로 이동할 수 있습니다. 전송하려면 가스 요금을 소모해야 합니다. 가스 수수료는 USDC 및 dydx 토큰을 사용할 수 있습니다.

FMZ 플랫폼 dYdX v4 연습

위의 내용은 일부 패키징 세부 정보를 간략하게 설명합니다. 다음으로 구체적인 사용을 연습해 보겠습니다. 여기서는 데모를 위해 dYdX v4 테스트 네트워크를 사용합니다. 테스트 네트워크는 기본적으로 메인 네트워크와 동일하며 테스트 자산을 수신하는 자동 수도꼭지가 있습니다. . 관리자가 배치됩니다. 작업에 대한 세부 사항은 설명하지 않고 FMZ에서 실제 테스트를 생성합니다.

1. 구성

암호화폐 지갑(여기서는 imToken 지갑을 사용했습니다)을 사용하여 dYdX v4 앱에 성공적으로 연결한 후 테스트 자산을 청구하고 현재 dYdX v4 계정에 대한 니모닉(지갑에서 파생)을 내보냅니다.

DEX 거래소 양적 연습 (1) – dYdX v4 사용자 가이드

FMZ 플랫폼에서 니모닉을 구성합니다. 여기서는 로컬 파일 방법을 사용하여 구성합니다(직접 작성하여 플랫폼에 구성할 수도 있습니다. 니모닉은 일반 텍스트가 아닌 암호화 후에 구성됩니다).

  • 니모닉 파일: mnemonic.txt

DEX 거래소 양적 연습 (1) – dYdX v4 사용자 가이드

관리자 디렉토리 아래의 실제 디스크 ID 폴더 디렉토리에 넣으세요. 물론 다른 디렉토리에도 넣을 수 있습니다(구체적인 경로는 구성 중에 작성해야 함).

  • FMZ에서 교환을 구성하세요

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

니모닉 편집 상자에 내용을 입력하세요:file:///mnemonic.txt, 해당 실제 경로는 다음과 같습니다.托管者所在目录/logs/storage/594291

DEX 거래소 양적 연습 (1) – dYdX v4 사용자 가이드

2. 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()) 
}

테스트 네트워크 계정 정보를 읽어보세요:

{
	"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. 시장정보조회

테스트 네트워크로 전환하지 않고 메인 네트워크로 테스트

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

DEX 거래소 양적 연습 (1) – dYdX v4 사용자 가이드

4. 주문하기

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

DEX 거래소 양적 연습 (1) – dYdX v4 사용자 가이드

dYdX v4 앱 페이지:

DEX 거래소 양적 연습 (1) – dYdX v4 사용자 가이드

5. 주문정보

테스트 네트워크는 두 개의 주문을 미리 넣고, 현재 보류 중인 주문을 확보한 다음 해당 주문을 취소하는지 테스트합니다.

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

DEX 거래소 양적 연습 (1) – dYdX v4 사용자 가이드

6. 위치정보 조회

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

DEX 거래소 양적 연습 (1) – dYdX v4 사용자 가이드

7. 하위 계정 관리

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

DEX 거래소 양적 연습 (1) – dYdX v4 사용자 가이드

subAccountNumber가 128인 하위 계정으로 전환하면 GetAccount에서 반환되는 데이터는 다음과 같습니다.

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

subAccountNumber가 128인 하위 계정에서 20 USDC가 이체된 것을 볼 수 있습니다.

8. TxHash를 가져와 REST 노드 인터페이스를 호출합니다.

순서에 따라 TxHash를 얻어서 REST 노드를 호출하는 IO 메소드를 테스트한다.

주문의 TxHash를 얻는 방법은? 교환 객체 dydx는 주문 ID를 사용하여 쿼리할 수 있는 TxHash를 캐시합니다. 하지만 전략이 중단되면 캐시된 주문 tx 해시 맵은 지워집니다.

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

DEX 거래소 양적 연습 (1) – dYdX v4 사용자 가이드

TxHash를 통해 쿼리된 메시지:

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

내용이 너무 길기 때문에 설명을 위해 몇 가지 발췌 부분을 보여드리겠습니다.

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

위의 테스트는 최신 커스터디언을 기반으로 합니다. dYdX v4 DEX를 지원하려면 최신 커스터디언을 다운로드해야 합니다.

여러분의 지지에 감사드리며, 읽어주셔서 감사드립니다.