資源の読み込みに... 荷物...

新人,チェックアウト 仮想通貨量的な取引に連れて行きます (6)

作者: リン・ハーンニナバダス作成日:2022-04-21 18:13:03 更新日:2022-04-22 12:00:05 更新日:2022-04-22 更新日:2022-04-22 更新日:2022-04-22 12:00:05 更新日:2022-04-22 更新日:2022-04-22 12:00:05 更新日:2022-04-22 更新日:2022-04-22 12:00:05 更新日:2022-04-22 更新日:2022-04-22 12:00:05

新人,チェックアウト 仮想通貨量的な取引に連れて行きます (6)

前回の記事では,シンプルなグリッド戦略を一緒に作りました. この記事では,この戦略をマルチシンボルスポットグリッド戦略にアップグレードし,拡張し,この戦略を実践でテストしてみましょう. 目的は"聖杯"を見つけるのではなく,戦略の設計過程で様々な問題や解決策を議論することです. この記事では,戦略の設計における私の経験の一部を説明します. この記事の内容は少し複雑で,プログラミングの基礎が必要です.

戦略要求に基づくデザインの思考

この記事では,前回の記事と同様に,FMZ量子取引プラットフォーム (FMZ.COM).

  • 複数のシンボル ネットワーク戦略は 単にBTC_USDT,しかしまたLTC_USDT/EOS_USDT/DOGE_USDT/ETC_USDT/ETH_USDT取引したいすべてのシンボルのグリッド取引を同時に実行します.

    複数のシンボルの 振動する市場コートを 捉えることが良い気分です
    シンプルに聞こえるかもしれませんが デザインを始めると 難しくなります

      1. まず,複数のシンボルの市場コートを取得します. これは解決すべき最初の問題です. プラットフォーム API ドキュメンテーションを読んだ後,プラットフォームは通常,総括されたインターフェースを提供することを発見しました. いいですか,私たちはデータを取得するために総括された市場データインターフェースを使用します.
      1. 2つ目の問題はアカウント資産です.マルチシンボル戦略を実行したい場合は,各取引ペアの資産を別々に管理し,すべての資産データを入手し,一度記録することを検討する必要があります.なぜアカウント資産データを入手すべきですか?そしてなぜそれぞれの取引ペアを別々に記録すべきですか?

    注文をするときに利用可能な資産を判断する必要があるので,判断する前にデータを入手する必要はありませんか? また,収益を計算する必要があります. まず最初の資産データを記録すべきですか? そして,現在口座の資産データを取得し,最初のものと比較して利益と損失を計算すべきですか? 幸運にも プラットフォームの資産アカウントインターフェイスは 通常すべての通貨資産データを返します だから一度だけ取得し データを処理する必要があります

      1. 戦略パラメータデザイン.マルチシンボル戦略のパラメータデザインは,単シンボル戦略のパラメータデザインとはかなり異なります.マルチシンボル戦略の各シンボルの取引論理も同じであるため,取引中に各シンボルのパラメータが異なる可能性もあります.例えば,グリッド戦略では,BTC_USDT取引ペアを行うときに毎回0.01 BTCを取引したいかもしれませんが,DOGE_USDTを行うときにこのパラメータ (0.01通貨の取引) を使用することは明らかに不適切です.もちろん,USDTの金額によって処理することもできます.しかし,まだ問題があります.BTC_USDTで1000UとDOGE_USDTで10Uを取引したい場合はどうでしょうか?需要は決して満たされません. 複数のパラメータのグループを設定し,操作される異なる取引ペアのパラメータを別々に制御することができます. パラメータのどのグループを設定すべきか? 3つのグループを設定します. 4つのシンボルを操作したい場合はどうですか? 戦略を変更しパラメータを増やす必要がありますか? そのため,マルチシンボルの戦略パラメータを設計する際に差別化が必要であることを十分に考えましょう. 解決策の一つは,パラメータを共通の文字列またはJSON文字列に設計することです.
        例えば:
      ETHUSDT:100:0.002|LTCUSDT:20:0.1
      

      を表示する記号は,各記号のデータを分割するために使用されます.ETHUSDT:100:0.002取引ペア ETH_USDT を制御し,LTCUSDT:20:0.1中央のはセグメントの役割を果たします. 中へETHUSDT:100:0.002, ETHUSDTは,あなたが操作したい取引ペアを表します. 100はグリッド間隔です. 0.002は各グリッドの取引されたETH金額です. :は,上記のデータを分割するために使用されます (もちろん,パラメータのルールは戦略デザイナーによって作られます.あなたのニーズに基づいて,あなたが望むものをデザインすることができます).
      この文字列には,既に操作に必要な各シンボルのパラメータ情報が含まれています.文字列を解析し,各シンボルの取引論理を制御するために戦略内の変数に値を割り当てることができます. どのように解析しますか?上記の例を使用しましょう.

      function main() {
          var net = []  // the recorded grid parameters; when specifically running the grid trading logic, use the data from here 
          var params = "ETHUSDT:100:0.002|LTCUSDT:20:0.1"
          var arrPair = params.split("|")
          _.each(arrPair, function(pair) {
              var arr = pair.split(":")
              var symbol = arr[0]              // trading pair name 
              var diff = parseFloat(arr[1])    // grid spacing 
              var amount = parseFloat(arr[2])  // grid order amount 
              net.push({symbol : symbol, diff : diff, amount : amount})
          })
          Log("Grid parameter data:", net)
      }
      

      img

      JSON 文字列を直接使うこともできます.

      function main() {        
          var params = '[{"symbol":"ETHUSDT","diff":100,"amount":0.002},{"symbol":"LTCUSDT","diff":20,"amount":0.1}]'
          var net = JSON.parse(params)  // the recorded grid parameters; when specifically running the grid trading logic, use the data from here         
          _.each(net, function(pair) {
              Log("Trading pair:", pair.symbol, pair)
          })
      }
      

      img

      1. データの持続性 実践戦略と教学戦略には大きな違いがあります. 前回の教学戦略は,戦略の論理と設計の初期テストのためにのみです. ボットで実際に戦略を実行するときに懸念すべき問題が多くあります. ボットを実行するときに,ボットが起動し停止することができます. その時点で,ボットを実行中にすべてのデータが失われます. ボットが停止した後,ボットを再起動する際に以前の状態をどのように継続しますか? ここで,ボットが実行しているときにキーデータを継続的に保存する必要があります. これにより,データが読み取られ,ボットが再起動するとボットが実行し続けます. 薬剤師が やってくれたら_G()FMZ Quant の関数,または操作関数を使用するDBExec()詳細については FMZ API 文書に問い合わせることができます

      この関数を使って,この関数から,_G()格子データを保存する

      var net = null 
      function main() {  // strategy main function 
          // first read the stored net 
          net = _G("net")
          
          // ...
      }
      
      function onExit() {
          _G("net", net)
          Log("Execute the clean-up processing, and save the data", "#FF0000")
      }
      
      function onexit() {    // the onexit function defined by the platform system, which will be triggered when clicking the bot to stop 
          onExit()
      }
      
      function onerror() {   // the onerror function defined by the platform system, which will be triggered when the program exception occurs 
          onExit()
      }
      
      1. 注文金額の精度,注文価格の精度,最低注文量,最低注文金額の制限など

      バックテストシステムには,注文量と注文精度にそのような厳格な制限はありません.しかし,ボットでは,各プラットフォームは注文価格と注文量に対する厳格な基準を持ち,異なる取引ペアには異なる制限があります.したがって,初心者はしばしばバックテストシステムでOKEXをテストします.ボットで戦略を実行すると,取引が起動するとさまざまな問題が発生し,エラーメッセージの内容は読み取れないし,さまざまな狂気の現象が現れます.

      複数のシンボルの場合,要求はより複雑である.単一のシンボルの戦略では,精度などの情報を指定するパラメータを設計することができます.しかし,複数のシンボルの戦略を設計する場合は,パラメータに情報を書き込むことがパラメータを非常に退屈なものにするのは明らかです.

      この時点で,プラットフォームのAPIドキュメントをチェックして,ドキュメントに取引ペアに関連する情報にインターフェースがあるかどうかを確認する必要があります.これらのインターフェースがある場合は,精度などの情報を取得するために戦略に自動アクセスインターフェースを設計し,取引中の取引ペア情報に設定できます (要するに,精度はプラットフォームから自動的に取得され,戦略パラメータに関連する変数に適応します).

      1. 異なるプラットフォームの適応 なぜこの問題は最後に言及されるのか? 上記すべての問題の処理は,最後の問題につながります. 我々は戦略で集計市場インターフェースを使用することを計画しています. 私たちの戦略は 総合市場インターフェースを使用することを計画しているため プラットフォームの取引ペアの精度や その他のデータ適応へのアクセスや 各取引ペアを別々に処理するためのアカウント情報へのアクセスなどのソリューションは 異なるプラットフォームにより 大きな違いをもたらすでしょう インターフェイスコールとメカニズムの違いがある.スポットプラットフォームでは,グリッド戦略をフューチャーバージョンに拡張すると,違いは比較的小さい.各プラットフォームのメカニズムの違いはさらに大きい.解決策の一つは,FMZテンプレートライブラリを設計すること.戦略自体とプラットフォームの間の結合を減らすためにライブラリ内の差別化を実装するデザインを書く. テンプレートライブラリを書いて そのテンプレートで それぞれのプラットフォームに基づいて 差別化を実装する必要があります

テンプレートライブラリを設計する

上記の分析に基づいて 戦略,プラットフォームメカニズム,インターフェースの結合を減らすために テンプレートライブラリを設計しました
テンプレートライブラリはこのように設計できます (コードの一部は省略されています):

function createBaseEx(e, funcConfigure) {
    var self = {}
    self.e = e 
    
    self.funcConfigure = funcConfigure
    self.name = e.GetName()
    self.type = self.name.includes("Futures_") ? "Futures" : "Spot"
    self.label = e.GetLabel()
    
    // the interfaces that need to be implemented 
    self.interfaceGetTickers = null   // create a function that asynchronously obtains the aggregated market quote threads
    self.interfaceGetAcc = null       // create a function that asynchronously obtains the account data threads 
    self.interfaceGetPos = null       // obtain positions 
    self.interfaceTrade = null        // create concurrent orders 
    self.waitTickers = null           // wait for the concurrent market quote data  
    self.waitAcc = null               // wait for the account concurrent data 
    self.waitTrade = null             // wait for order concurrent data
    self.calcAmount = null            // calculate the order amount according to the trading pair precision and other data 
    self.init = null                  // initialization; obtain the precision and other data 
    
    // execute the configuration function, to configure objects 
    funcConfigure(self)

    // detect whether all the interfaces arranged by configList can be implemented 
    _.each(configList, function(funcName) {
        if (!self[funcName]) {
            throw "interface" + funcName + "not implemented"
        }
    })
    
    return self
}

$.createBaseEx = createBaseEx
$.getConfigureFunc = function(exName) {
    dicRegister = {
        "Futures_OKCoin" : funcConfigure_Futures_OKCoin,    //  the implementation of OKEX Futures 
        "Huobi" : funcConfigure_Huobi,
        "Futures_Binance" : funcConfigure_Futures_Binance,
        "Binance" : funcConfigure_Binance,
        "WexApp" : funcConfigure_WexApp,                    // the implementation of wexApp
    }
    return dicRegister
}

テンプレートでは,特定のプレイ形式を対象としたコード書きを実装します.例としてFMZシミュレーションボットWexAppを挙げましょう.

function funcConfigure_WexApp(self) {
    var formatSymbol = function(originalSymbol) {
        // BTC_USDT
        var arr = originalSymbol.split("_")
        var baseCurrency = arr[0]
        var quoteCurrency = arr[1]
        return [originalSymbol, baseCurrency, quoteCurrency]
    }

    self.interfaceGetTickers = function interfaceGetTickers() {
        self.routineGetTicker = HttpQuery_Go("https://api.wex.app/api/v1/public/tickers")
    }

    self.waitTickers = function waitTickers() {
        var ret = []
        var arr = JSON.parse(self.routineGetTicker.wait()).data
        _.each(arr, function(ele) {
            ret.push({
                bid1: parseFloat(ele.buy), 
                bid1Vol: parseFloat(-1),
                ask1: parseFloat(ele.sell), 
                ask1Vol: parseFloat(-1),
                symbol: formatSymbol(ele.market)[0],
                type: "Spot", 
                originalSymbol: ele.market
            })
        })
        return ret 
    }

    self.interfaceGetAcc = function interfaceGetAcc(symbol, updateTS) {
        if (self.updateAccsTS != updateTS) {
            self.routineGetAcc = self.e.Go("GetAccount")
        }
    }

    self.waitAcc = function waitAcc(symbol, updateTS) {
        var arr = formatSymbol(symbol)
        var ret = null 
        if (self.updateAccsTS != updateTS) {
            ret = self.routineGetAcc.wait().Info
            self.bufferGetAccRet = ret 
        } else {
            ret = self.bufferGetAccRet
        }
        if (!ret) {
            return null 
        }        
        var acc = {symbol: symbol, Stocks: 0, FrozenStocks: 0, Balance: 0, FrozenBalance: 0, originalInfo: ret}
        _.each(ret.exchange, function(ele) {
            if (ele.currency == arr[1]) {
                // baseCurrency
                acc.Stocks = parseFloat(ele.free)
                acc.FrozenStocks = parseFloat(ele.frozen)
            } else if (ele.currency == arr[2]) {
                // quoteCurrency
                acc.Balance = parseFloat(ele.free)
                acc.FrozenBalance = parseFloat(ele.frozen)
            }
        })
        return acc
    }

    self.interfaceGetPos = function interfaceGetPos(symbol, price, initSpAcc, nowSpAcc) {
        var symbolInfo = self.getSymbolInfo(symbol)
        var sumInitStocks = initSpAcc.Stocks + initSpAcc.FrozenStocks
        var sumNowStocks = nowSpAcc.Stocks + nowSpAcc.FrozenStocks
        var diffStocks = _N(sumNowStocks - sumInitStocks, symbolInfo.amountPrecision)
        if (Math.abs(diffStocks) < symbolInfo.min / price) {
            return []
        }
        return [{symbol: symbol, amount: diffStocks, price: null, originalInfo: {}}]
    }

    self.interfaceTrade = function interfaceTrade(symbol, type, price, amount) {
        var tradeType = ""
        if (type == self.OPEN_LONG || type == self.COVER_SHORT) {
            tradeType = "bid"
        } else {
            tradeType = "ask"
        }
        var params = {
            "market": symbol,
            "side": tradeType,
            "amount": String(amount),
            "price" : String(-1),
            "type" : "market"
        }
        self.routineTrade = self.e.Go("IO", "api", "POST", "/api/v1/private/order", self.encodeParams(params))
    }

    self.waitTrade = function waitTrade() {
        return self.routineTrade.wait()
    }

    self.calcAmount = function calcAmount(symbol, type, price, amount) {
        // obtain the trading pair information 
        var symbolInfo = self.getSymbolInfo(symbol)
        if (!symbol) {
            throw symbol + ",trading pair information not found"
        }
        var tradeAmount = null 
        var equalAmount = null  // record the symbol amount  
        if (type == self.OPEN_LONG || type == self.COVER_SHORT) {
            tradeAmount = _N(amount * price, parseFloat(symbolInfo.pricePrecision))
            // detect the minimum trading amount 
            if (tradeAmount < symbolInfo.min) {
                Log(self.name, " tradeAmount:", tradeAmount, "less than", symbolInfo.min)
                return false 
            }
            equalAmount = tradeAmount / price
        } else {
            tradeAmount = _N(amount, parseFloat(symbolInfo.amountPrecision))
            // detect the minimum trading amount 
            if (tradeAmount < symbolInfo.min / price) {
                Log(self.name, " tradeAmount:", tradeAmount, "less than", symbolInfo.min / price)
                return false 
            }
            equalAmount = tradeAmount
        }
        return [tradeAmount, equalAmount]
    }

    self.init = function init() {   // the function that automatically processes conditions like precision, etc.  
        var ret = JSON.parse(HttpQuery("https://api.wex.app/api/v1/public/markets"))
        _.each(ret.data, function(symbolInfo) {
            self.symbolsInfo.push({
                symbol: symbolInfo.pair,
                amountPrecision: parseFloat(symbolInfo.basePrecision),
                pricePrecision: parseFloat(symbolInfo.quotePrecision),
                multiplier: 1,
                min: parseFloat(symbolInfo.minQty),
                originalInfo: symbolInfo
            })
        })        
    }
}

戦略のテンプレートを使うのはとても簡単です.

function main() {
    var fuExName = exchange.GetName()
    var fuConfigureFunc = $.getConfigureFunc()[fuExName]
    var ex = $.createBaseEx(exchange, fuConfigureFunc)

    var arrTestSymbol = ["LTC_USDT", "ETH_USDT", "EOS_USDT"]
    var ts = new Date().getTime()
    
    // test to obtain the market quotes 
    ex.goGetTickers()
    var tickers = ex.getTickers()
    Log("tickers:", tickers)
    
    // test to obtain the account information 
    ex.goGetAcc(symbol, ts)
    
    _.each(arrTestSymbol, function(symbol) {        
        _.each(tickers, function(ticker) {
            if (symbol == ticker.originalSymbol) {
                // print the market quote data 
                Log(symbol, ticker)
            }
        })

        // print asset data 
        var acc = ex.getAcc(symbol, ts)
        Log("acc:", acc.symbol, acc)
    })
}

戦略ボット

上記のテンプレートに基づいて戦略を設計し書くことは非常に簡単です. 戦略全体には約300行以上のコードがあります. それは仮想通貨スポットマルチシンボルグリッド戦略を実装します.

img

img

今,それは損失を持っているT_Tソースコードは提供されません.

登録コードはいくつかあります.興味がある場合は,wexAppで試してみてください:

Purchase Address: https://www.fmz.com/m/s/284507
Registration Code:
adc7a2e0a2cfde542e3ace405d216731
f5db29d05f57266165ce92dc18fd0a30
1735dca92794943ddaf277828ee04c27
0281ea107935015491cda2b372a0997d
1d0d8ef1ea0ea1415eeee40404ed09cc

スポット・グリッド戦略の最大の利点は: 眠るのに安心して! スポット・グリッド戦略の最大の利点は: 眠るのに安心して! 戦略の安定性は良好で 5月27日以降は変更していません 臨時的にフューチャー・グリッド戦略を試してみる気はありません


もっと