Les ressources ont été chargées... Je charge...

La transaction quantifiée de la sphère monétaire est une nouveauté - qui vous rapproche de la quantification de la sphère monétaire.

Auteur:L'inventeur de la quantification - un petit rêve, Créé: 2021-06-04 10:08:48, Mis à jour: 2023-09-21 21:01:06

img

La quantité de transaction dans le cercle monétaire est nouvelle et vous rapproche de la quantité de transaction dans le cercle monétaire.

Dans le dernier article, nous avons commencé à travailler ensemble sur une stratégie de grille simple. Dans cet article, nous l'avons améliorée et étendue à une stratégie de grille en direct multifonctionnelle, et nous l'avons mise à l'essai sur le terrain. Le but n'est pas de trouver un "Coupe Sainte", mais de réfléchir et de trouver des solutions à partir de la conception stratégique.

La conception basée sur les besoins stratégiques

Comme dans l'article précédent, cet article est basé sur la quantification de l'inventeur.FMZ.COMLe blogueur a également publié un article intitulé:

  • Variété Je veux dire, je veux que cette stratégie de grille ne soit pas seulementBTC_USDTJe peux le faire.LTC_USDT/EOS_USDT/DOGE_USDT/ETC_USDT/ETH_USDTDans le même temps, les variétés qui veulent courir font également des transactions en grille.

    Je me suis dit que c'était une bonne idée de capturer les bouleversements de plusieurs sortes. Les besoins semblent simples, mais le problème survient au moment de la conception.

    • 1, d'abord l'acquisition de plusieurs types de marchés. C'est le premier problème à résoudre. Après avoir consulté les documents API des échanges, j'ai constaté que les échanges généraux offrent des interfaces de marché agrégées. OK, on utilise l'interface du marché agrégé pour obtenir les données.

    • 2, le deuxième problème rencontré est celui des actifs de compte. Comme il s'agit d'une stratégie multi-variété, il faut considérer chaque transaction comme une gestion d'actifs séparée. Et il faut obtenir toutes les données d'actifs en même temps. Pourquoi obtenir les données d'actifs de compte? Parce que vous devez juger des actifs disponibles au moment de la commande, ou vous devez les obtenir et les juger? Ou bien vous avez besoin de calculer le bénéfice, ou bien vous devez enregistrer une donnée d'actif de compte initiale, puis obtenir les données actuelles d'actif de compte et calculer le bénéfice et le déficit par rapport à la comparaison initiale? Heureusement, l'interface des comptes d'actifs d'une bourse renvoie généralement des données sur les actifs de toutes les devises, et nous n'avons besoin que d'une seule saisie pour traiter les données.

    • 3, la conception des paramètres stratégiques. La conception des paramètres de plusieurs variétés et la conception des paramètres d'une seule variété diffèrent beaucoup, car la logique de négociation des variétés de plusieurs variétés est la même, mais il est possible que les paramètres lors de la négociation soient différents. Par exemple, la stratégie de grille, il est possible de faire une paire de transactions BTC_USDT en espérant 0,01 BTC par transaction, mais si vous faites DOGE_USDT, il est évidemment inapproprié si ce paramètre (transaction de 0,01 pièces) est toujours utilisé, bien sûr, vous pouvez également traiter le montant USDT. Peut-être que d'autres étudiants réfléchiront à cette question et diront: " Je peux configurer plusieurs ensembles de paramètres pour contrôler séparément les différentes paires de transactions à effectuer. " Si je fais quatre variétés, ce n'est pas possible, mais je dois modifier la stratégie, ajouter des paramètres... Une solution consiste à concevoir les paramètres en tant que chaînes ordinaires ou en tant que chaînes JSON. Par exemple:

      ETHUSDT:100:0.002|LTCUSDT:20:0.1
      

      Les données de chaque espèce sont divisées en deux parties, ce qui signifie que les données de chaque espèce sont divisées en deux parties.ETHUSDT:100:0.002Il y a un problème avec le fait que les utilisateurs utilisent des logiciels de gestion de projet.LTCUSDT:20:0.1Le code LTC_USDT est utilisé pour contrôler la paire de transactions.ETHUSDT:100:0.002Dans ce cas, l'ETHUSDT indique la paire de transactions que vous allez effectuer, 100 est l'intervalle de la grille, 0.002 est le nombre de pièces d'ETH par transaction de la grille, et l'hypothèse est de diviser ces données (bien sûr, ces règles de paramètres sont établies par le concepteur de la stratégie, et vous pouvez concevoir ce que vous voulez). Ces chaînes contiennent des informations de paramètres pour chaque variété que vous allez faire, et vous pouvez les analyser dans la stratégie, en donnant des valeurs spécifiques aux variables de la stratégie, pour contrôler la logique de transaction de chaque variété. Comment cela se passe-t-il?

      function main() {
          var net = []  // 记录的网格参数,具体运行到网格交易逻辑时,使用这里面的数据
          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]              // 交易对名称
              var diff = parseFloat(arr[1])    // 网格间距
              var amount = parseFloat(arr[2])  // 网格下单量
              net.push({symbol : symbol, diff : diff, amount : amount})
          })
          Log("网格参数数据:", net)
      }
      

      img

      Vous pouvez aussi utiliser des chaînes JSON directement, c'est plus simple.

      function main() {        
          var params = '[{"symbol":"ETHUSDT","diff":100,"amount":0.002},{"symbol":"LTCUSDT","diff":20,"amount":0.1}]'
          var net = JSON.parse(params)  // 记录的网格参数,具体运行到网格交易逻辑时,使用这里面的数据        
          _.each(net, function(pair) {
              Log("交易对:", pair.symbol, pair)
          })
      }
      

      img

    • 4 - Persévérance des données Les stratégies de combat et les stratégies d'enseignement peuvent également être très différentes, la stratégie d'enseignement ci-dessus étant simplement un test initial de la stratégie logique, de la conception, et les questions à prendre en compte en temps de combat sont plus nombreuses. Lors du combat, il est possible d'allumer ou d'arrêter le disque. Dans ce cas, toutes les données lors de l'exécution du disque seront perdues. C'est là que l'on doit faire une sauvegarde persistante des données clés lors de l'exécution du disque réel, afin de pouvoir lire ces données lors d'un redémarrage et continuer à fonctionner. Il est disponible sur les plateformes d'échange quantitatif des inventeurs_G()Les fonctions, ou les fonctions utilisées pour gérer une base de donnéesDBExec()Vous pouvez consulter la documentation de l'API FMZ.

      Par exemple, nous avons conçu une fonction de balayage._G()Les fonctions qui stockent les données du réseau.

      var net = null 
      function main() {  // 策略主函数
          // 首先读取储存的net
          net = _G("net")
          
          // ...
      }
      
      function onExit() {
          _G("net", net)
          Log("执行扫尾处理,保存数据", "#FF0000")
      }
      
      function onexit() {    // 平台系统定义的退出扫尾函数,在点击实盘停止时触发执行
          onExit()
      }
      
      function onerror() {   // 平台系统定义的异常退出函数,在程序发生异常时触发执行
          onExit()
      }
      
    • 5 Limitations telles que la précision de la commande, la précision du prix de la commande, la quantité de commande minimale et le montant de la commande minimale

      Dans le système de retouche, il n'y a pas de restrictions aussi strictes sur le montant, l'exactitude du montant, etc., mais en temps réel, les échanges peuvent avoir des normes strictes pour le prix au moment de la facturation, le montant du montant, et ces restrictions ne sont pas les mêmes pour chaque paire de transactions.

      Dans le cas des variétés multiples, le besoin est plus complexe. Dans les stratégies mono-variétés, vous pouvez concevoir un paramètre pour spécifier des informations telles que la précision, mais lorsque vous concevez des stratégies multi-variétés, il est évident que ces informations sont écrites dans des paramètres qui semblent très paramétriques.

      Dans ce cas, il est nécessaire de consulter la documentation de l'API de l'échange pour voir si la documentation de l'échange contient des interfaces de transaction pour les informations pertinentes. Si elles existent, il est possible de concevoir des informations telles que la précision de l'interface d'accès automatique dans la stratégie, de la configurer dans les informations de transaction impliquées dans la transaction (en termes simples, ce qui est précis, est une demande d'accès automatique à l'échange, qui est ensuite adaptée aux variables liées aux paramètres de la stratégie).

    • 6. Adaptation à différents marchés Pourquoi mettre cette question en dernier? Comme les solutions mentionnées ci-dessus posent ce dernier problème, notre stratégie prévoit d'utiliser des interfaces de marché agrégées, d'accéder à l'échange, d'adapter les données à la précision des transactions, d'accéder à l'information des comptes pour traiter les transactions individuellement. Il y a des différences d'appels d'interfaces, des différences de mécanismes. Les différences sont légèrement plus petites pour les échanges sur place si cette stratégie de grille est étendue à une version à terme. Les différences entre les mécanismes d'échanges sont plus grandes. Une solution consiste à concevoir une bibliothèque de modèles FMZ. L'inconvénient est que cela nécessite de créer une bibliothèque de classes de modèles, et que ce modèle est spécifiquement conçu pour chaque échange.

Concevoir une bibliothèque de modèles

Sur la base de l'analyse ci-dessus, une bibliothèque de modèles a été conçue pour réduire la convergence entre les stratégies et les interfaces des mécanismes d'échange.

Nous pouvons concevoir cette bibliothèque de modèles comme ceci (partie de code omise):

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()
    
    // 需要实现的接口
    self.interfaceGetTickers = null   // 创建异步获取聚合行情数据线程的函数
    self.interfaceGetAcc = null       // 创建异步获取账户数据线程的函数
    self.interfaceGetPos = null       // 获取持仓
    self.interfaceTrade = null        // 创建并发下单
    self.waitTickers = null           // 等待并发行情数据 
    self.waitAcc = null               // 等待账户并发数据
    self.waitTrade = null             // 等待下单并发数据
    self.calcAmount = null            // 根据交易对精度等数据计算下单量
    self.init = null                  // 初始化工作,获取精度等数据
    
    // 执行配置函数,给对象配置
    funcConfigure(self)

    // 检测configList约定的接口是否都实现
    _.each(configList, function(funcName) {
        if (!self[funcName]) {
            throw "接口" + funcName + "未实现"
        }
    })
    
    return self
}

$.createBaseEx = createBaseEx
$.getConfigureFunc = function(exName) {
    dicRegister = {
        "Futures_OKCoin" : funcConfigure_Futures_OKCoin,    // OK期货的实现
        "Huobi" : funcConfigure_Huobi,
        "Futures_Binance" : funcConfigure_Futures_Binance,
        "Binance" : funcConfigure_Binance,
        "WexApp" : funcConfigure_WexApp,                    // wexApp的实现
    }
    return dicRegister
}

Dans les modèles, les échanges spécifiques peuvent être écrits, par exemple avec WexApp, l'analogue de FMZ:

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) {
        // 获取交易对信息
        var symbolInfo = self.getSymbolInfo(symbol)
        if (!symbol) {
            throw symbol + ",交易对信息查询不到"
        }
        var tradeAmount = null 
        var equalAmount = null  // 记录币数
        if (type == self.OPEN_LONG || type == self.COVER_SHORT) {
            tradeAmount = _N(amount * price, parseFloat(symbolInfo.pricePrecision))
            // 检查最小交易量
            if (tradeAmount < symbolInfo.min) {
                Log(self.name, " tradeAmount:", tradeAmount, "小于", symbolInfo.min)
                return false 
            }
            equalAmount = tradeAmount / price
        } else {
            tradeAmount = _N(amount, parseFloat(symbolInfo.amountPrecision))
            // 检查最小交易量
            if (tradeAmount < symbolInfo.min / price) {
                Log(self.name, " tradeAmount:", tradeAmount, "小于", symbolInfo.min / price)
                return false 
            }
            equalAmount = tradeAmount
        }
        return [tradeAmount, equalAmount]
    }

    self.init = function init() {   // 自动处理精度等条件的函数
        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
            })
        })        
    }
}

Il est facile d'utiliser ce modèle dans la stratégie:

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()
    
    // 测试获取行情
    ex.goGetTickers()
    var tickers = ex.getTickers()
    Log("tickers:", tickers)
    
    // 测试获取账户信息
    ex.goGetAcc(symbol, ts)
    
    _.each(arrTestSymbol, function(symbol) {        
        _.each(tickers, function(ticker) {
            if (symbol == ticker.originalSymbol) {
                // 打印行情数据
                Log(symbol, ticker)
            }
        })

        // 打印资产数据
        var acc = ex.getAcc(symbol, ts)
        Log("acc:", acc.symbol, acc)
    })
}

La stratégie en jeu

La stratégie de rédaction est très simple sur la base du modèle ci-dessus, la stratégie complète est d'environ 300 lignes, ce qui permet de réaliser une stratégie de grille multi-variété de la monnaie numérique.

img

img

Je suis en train de perdre de l'argent.T_TLe code source n'est pas disponible pour le moment.

Pour les personnes intéressées, vous pouvez accéder à WexApp en envoyant quelques codes d'enregistrement:

购买地址: https://www.fmz.com/m/s/284507
注册码: 
adc7a2e0a2cfde542e3ace405d216731
f5db29d05f57266165ce92dc18fd0a30
1735dca92794943ddaf277828ee04c27
0281ea107935015491cda2b372a0997d
1d0d8ef1ea0ea1415eeee40404ed09cc

Le plus grand avantage de la grille de stockage est que: vous pouvez dormir! La stabilité s'est rétablie, elle n'a pas bougé depuis le 27 mai, et le réseau de contrats à terme n'a pas osé essayer pour l'instant.


Relationnée

Plus de

La petite cuisine quantiqueMerci pour le barrage, quantifier.

Neuf soleilsLe président Meng Weiwu!

Les organismes de l'orbiteMerci.

L'inventeur de la quantification - un petit rêveMerci pour votre soutien!

L'inventeur de la quantification - un petit rêveMerci pour votre soutien!