
dydx_v4、hyperliquid、vertex、aevoなど、いくつかのDEX取引所がカプセル化され、FMZに接続されています。中央集権型取引所での価格裁定競争が激化するにつれ、多くの定量トレーダーが分散型取引所に注目するようになりました。この記事では、DEXとCEX間の価格差監視の設計と実装について説明します。
ヘッジ・アービトラージ戦略の最初のステップは、対象ポートフォリオの価格差を計算し、取引機会があるかどうかを観察して分析することです。したがって、価格差監視戦略の設計と実装が最初の基本的なタスクとなります。設計要件は次のとおりです。
コードは 200 行未満で、設計された機能は、異なる取引所における特定の商品のリアルタイムの価格差を計算することだけです。戦略が最初に実行されると、戦略用に設定されたすべての交換オブジェクトは、DEX グループと CEX グループに分類されます。各ポーリングは、FMZプラットフォームによってカプセル化されたマルチスレッド関数スレッドを通じて実行され、同時にRESTインターフェース(注文書インターフェース)を要求します。GetDepth、要求された品種の買い注文リストと売り注文リストデータを記録します。次に、DEX グループと CEX グループを差分組み合わせ (DEX-CEX 組み合わせ、つまり裁定ペア) に組み合わせ、価格差を計算します。
交換タイプの決定: 初期化中に、追加された取引所オブジェクトがスポットか先物かが判断されます。
取引所によって特定の原資産の名称が異なる場合があるため、商品名を調整する必要があります。
プログラムは、さまざまな取引所のシンボルの命名規則に従って調整する必要があります。たとえば、Vertex 契約の取引ペアは次のように命名されます。XXX_USDこれは実際には USDC に基づく永久契約です。 VertexのスポットにおけるETHの名前はWETHです。
精度を得る: 初期化中に、市場情報全体が取得されます。要求された特定のシンボルに応じて、後続のデータ精度処理操作で対応する精度を照会できます。
データリクエスト すべての深度データが取得される前に、プログラムは待機し、データが更新されていない取引所があるかどうかを確認し続けます。データが取得されていない場合、プログラムは 100 ミリ秒間スリープします。 要求された注文書データは、threading.Dict() によって作成されたオブジェクト (同時スレッドとのやり取りに使用) に記録され、各ポーリングの終了時にデータがリセットされます。
要約する この戦略の実装では、複数の取引所間の価格差をリアルタイムで監視し、裁定取引の機会を計算する方法を示します。合理的なシンボル補正、詳細なデータキャプチャ、精密制御、マルチスレッド操作により、システムはリアルタイムの価格差を効率的に監視できます。戦略学習者にとって、このコードの実装のアイデアを理解することは、API を使用して取引データを取得する方法、複数の取引所からのデータを処理する方法、取引スプレッドを計算して出力する方法、およびこれらのテクノロジーを実際の取引に適用する方法を習得するのに役立ちます。
let symbolList = []
function createEx(idx, exs) {
let self = {}
let cexEidList = ["Binance", "Bybit", "Futures_Binance", "Futures_Bybit"]
let dexEidList = ["Vertex", "Hyperliquid", "Futures_Hyperliquid", "Futures_Vertex"]
self.name = exs[idx].GetName()
self.idx = idx
self.e = exs[idx]
self.depths = threading.Dict()
self.markets = self.e.GetMarkets()
if (!self.markets) {
throw "GetMarkets error"
}
if (dexEidList.includes(self.name)) {
self.type = "DEX"
} else if (cexEidList.includes(self.name)) {
self.type = "CEX"
} else {
throw "not support " + self.name
}
if (self.name.startsWith("Futures_")) {
self.isFutures = true
} else {
self.isFutures = false
}
self.correctSymbol = function(symbol) {
if (self.name == "Vertex") {
let correctList = {"BTC_USDC": "WBTC_USDC", "ETH_USDC": "WETH_USDC"}
if (typeof(correctList[symbol]) != "undefined") {
return correctList[symbol]
}
} else if (self.name == "Hyperliquid") {
let correctList = {"BTC_USDC": "UBTC_USDC"}
if (typeof(correctList[symbol]) != "undefined") {
return correctList[symbol]
}
} else if (self.name == "Futures_Hyperliquid") {
return symbol.replace("_USDC", "_USD")
}
return symbol
}
self.reqDepth = function(symbol) {
symbol = self.correctSymbol(symbol)
threading.Thread(function(idx, symbol, threadingDict) {
let depth = exchanges[idx].GetDepth(symbol)
if (depth) {
threadingDict.set(symbol, depth)
} else {
threadingDict.set(symbol, null)
}
}, self.idx, symbol, self.depths)
}
self.getPrecision = function(symbol) {
symbol = self.correctSymbol(symbol)
let marketInfo = self.markets[symbol]
if (marketInfo) {
return [marketInfo.PricePrecision, marketInfo.AmountPrecision]
} else {
return [8, 8]
}
}
self.init = function() {
self.depths = threading.Dict()
}
self.getDepth = function(symbol) {
symbol = self.correctSymbol(symbol)
return self.depths.get(symbol)
}
return self
}
function createManager(symbolList, exs) {
let self = {}
self.symbolList = symbolList
self.exchanges = []
self.hedgePair = []
self.initHedgePair = function () {
for (let i in exs) {
let ex = createEx(i, exs)
self.exchanges.push(ex)
}
let arrDEX = self.exchanges.filter(item => item.type == "DEX")
let arrCEX = self.exchanges.filter(item => item.type == "CEX")
for (let dex of arrDEX) {
for (let cex of arrCEX) {
self.hedgePair.push({"dex": dex, "cex": cex})
}
}
}
self.calcHedgeData = function () {
let beginTimestamp = new Date().getTime()
for (let e of self.exchanges) {
for (let symbol of self.symbolList) {
e.reqDepth(symbol)
}
}
while (true) {
let isWait = false
for (let e of self.exchanges) {
for (let symbol of self.symbolList) {
let depth = e.getDepth(symbol)
if (depth == null || typeof(depth) == "undefined") {
isWait = true
}
}
}
if (isWait) {
Sleep(100)
} else {
break
}
}
let tbls = []
for (let symbol of self.symbolList) {
let tbl = {"type": "table", "title": symbol + "差价", "cols": ["pair", "bid-ask", "ask-bid", "dex ask", "dex bid", "cex ask", "cex bid"], "rows": []}
for (let p of self.hedgePair) {
let dex = p["dex"]
let cex = p["cex"]
let pricePrecision = Math.max(dex.getPrecision(symbol)[0], cex.getPrecision(symbol)[0])
let dexDepth = dex.getDepth(symbol)
let cexDepth = cex.getDepth(symbol)
if (dexDepth && cexDepth) {
p["bid-ask"] = _N(dexDepth.Bids[0].Price - cexDepth.Asks[0].Price, pricePrecision)
p["ask-bid"] = _N(dexDepth.Asks[0].Price - cexDepth.Bids[0].Price, pricePrecision)
// 输出信息、观察测试
Log(dex.name, cex.name, symbol, "bid-ask:", p["bid-ask"], ", ask-bid", p["ask-bid"])
p[dex.name + "-ask"] = dexDepth.Asks[0].Price + "/" + dexDepth.Asks[0].Amount
p[dex.name + "-bid"] = dexDepth.Bids[0].Price + "/" + dexDepth.Bids[0].Amount
p[cex.name + "-ask"] = cexDepth.Asks[0].Price + "/" + cexDepth.Asks[0].Amount
p[cex.name + "-bid"] = cexDepth.Bids[0].Price + "/" + cexDepth.Bids[0].Amount
} else {
p["bid-ask"] = "--"
p["ask-bid"] = "--"
p[dex.name + "-ask"] = "--"
p[dex.name + "-bid"] = "--"
p[cex.name + "-ask"] = "--"
p[cex.name + "-bid"] = "--"
}
let pairName = dex.name + "-" + cex.name
tbl["rows"].push([pairName, p["bid-ask"], p["ask-bid"], p[dex.name + "-ask"], p[dex.name + "-bid"], p[cex.name + "-ask"], p[cex.name + "-bid"]])
}
tbls.push(tbl)
}
for (let e of self.exchanges) {
e.init()
}
let endTimestamp = new Date().getTime()
return [tbls, (endTimestamp - beginTimestamp) + "毫秒"]
}
self.initHedgePair()
return self
}
function main() {
LogReset(1)
let loopCount = 0
symbolList = strSymbolList.split(",")
let m = createManager(symbolList, exchanges)
while (true) {
let ret = m.calcHedgeData()
loopCount++
LogStatus(_D(), "耗时:", ret[1], ", 轮询次数:", loopCount, "\n", "`" + JSON.stringify(ret[0]) + "`")
Sleep(1000)
}
}
パラメータ設計:

スポット製品を監視する:

2 種類を監視します。

拡張方向:
FMZ プラットフォームは、分散型取引所 (DEX) と分散型金融 (DeFi) に対する技術サポートを継続的に強化し、機能と製品を継続的に反復および更新していきます。
読んでいただきありがとうございます。