前回の記事では,シンプルな格子戦略を一緒に作りましたが,この記事では,この戦略を拡張し,多種多様な現貨格子戦略に拡張し,この戦略を実用化テストにしました. 目的は"聖杯"を見つけることではなく,戦略設計からデザイン戦略の様々な問題を検討し,考え,解決策を探すことでした. この記事では,この戦略を設計する際に私が経験したいくつかのことを説明します. この内容は,少し複雑で,プログラムを書くための基礎が必要です.
この記事も前回の記事と同様に,発明者の量化に基づいています.FMZ.COMデザインについて
多種
この格子戦略は 単にBTC_USDT
やってもいいLTC_USDT
/EOS_USDT
/DOGE_USDT
/ETC_USDT
/ETH_USDT
逆に,現貨の取引対,走りたい品種は同時にネット取引をする.
1、まずは複数の種類の市場を取得する。これが解決すべき最初の問題である。取引所のAPIドキュメントを閲覧した後,一般取引所が集積市場インターフェースを提供していることを発見しました。 OK,集計市場インターフェイスでデータを取得します.
2、2つ目の問題は口座資産である. 多種多様な戦略であるため,各取引がそれぞれの資産を管理することを考慮し,すべての資産のデータを一度に取得し,記録する必要があります. なぜ口座資産データを取得するのか?また各取引対記録を分離する必要があります. 商品の価格が上がり,価格が下がり,価格が下がり,価格が下がり,価格が下がり,価格が下がり,価格が下がり,価格が下がり,価格が下がり,価格が下がり,価格が下がり,価格が下がり,価格が下がり,価格が下がり,価格が下がり,価格が下がり,価格が下がり,価格が下がり. また,収益を計算する必要があり,最初の口座資産データを記録し,現在の口座資産データを取得し,最初の対比で利益と損失を計算する必要がありますか? 取引所の資産アカウントインターフェースは,通常,すべての通貨の資産データを返します.
3, 戦略パラメータ設計. 多種多様なパラメータデザインと単種多様なパラメータデザインの違いは大きい. 多種多様なパラメータの各種の取引論理は同じであるが,取引時にパラメータが異なる可能性がある. 例えば,格子戦略,BTC_USDT取引をすると,各取引に0.01BTCを希望するかもしれない. しかし,DOGE_USDTを行うとき,このパラメータも (取引0.01コイン) は明らかに不適切である. もちろん,USDT金額で処理することもできます. しかし,それでも問題があるでしょう. この問題について考える仲間もいるかもしれません. そしてこう言うかもしれません. "はい,私は複数のパラメータをセットして,異なる取引ペアのパラメータを分離して制御することができます". 設定したパラメータの3つのセットは,もし私が4つの種類を作ったら? 戦略を変更し,パラメータを追加することは難しいです. 多種策の参数を設計する際には,このような差異化参数の必要性を十分に考慮する必要があります. 解決策の一つは,参数を通常の文字列またはJSON文字列として設計することです. 例えば:
ETHUSDT:100:0.002|LTCUSDT:20:0.1
種ごとにデータを分割したものです.ETHUSDT:100:0.002
取引相手は,ETH_USDTの取引対を制御している.LTCUSDT:20:0.1
LTC_USDTの取引対を制御する. 中間の"google"は分割する役割を果たします.ETHUSDT:100:0.002
100は格子間隔,0.002は格子ごとに取引されたETHコインの数,
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)
}
JSON 文字列で直接解析することもできます.
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)
})
}
4 データ永続性
実戦の戦略と教学的戦略は大きく異なる.上記の教学的戦略は,単なる初期テスト戦略の論理,設計,実戦時に考慮される問題はもっと多い.実戦時,実戦中に起動,停止する可能性がある.このとき,実戦中にすべてのデータが失われた.
この場合は,実機が起動する際に重要なデータの永続保存を行う必要があり,再起動時に読み取られ,実行を続けます.
発明者による量化取引プラットフォームで利用できます_G()
データベース操作の関数です.DBExec()
FMZ APIのドキュメントを参照してください.
この式は,この式を,この式で表します._G()
グラッドのデータを保存する関数.
var net = null
function main() { // 策略主函数
// 首先读取储存的net
net = _G("net")
// ...
}
function onExit() {
_G("net", net)
Log("执行扫尾处理,保存数据", "#FF0000")
}
function onexit() { // 平台系统定义的退出扫尾函数,在点击实盘停止时触发执行
onExit()
}
function onerror() { // 平台系统定义的异常退出函数,在程序发生异常时触发执行
onExit()
}
5. 単位の精度,単位の価格精度,最小単位の量,最小単位の金額などの制限
復習システムでは,次回数,次回数精度などに対してそれほど厳しい制限は施されていないが,実況では各取引所が報名時の価格,次回数について厳しい基準を持つことができるし,各取引対のこれらの制限は同じではない.したがって,よく新しい復習システムのテストOKがある.
複数種の場合,この必要性はより複雑である.単一種戦略では,精度などの情報を指定するためのパラメータを設計することができますが,複数種戦略を設計すると,明らかにこれらの情報がパラメータに書き込まれると,パラメータが非常に薄くなるでしょう.
このとき,取引所API文書を見て,取引所文書に関連する情報に対するインターフェースがないか確認する必要があります. もしそのようなインターフェースがある場合,戦略の中で自動アクセスインターフェースの取得精度などの情報を設計し,取引に参加する取引の取得情報に配置することができます.
6. 異なる取引所に適応する なぜこの質問を最後に置くのか? 上記の問題の解決方法が最後の問題を引き起こしているため,我々の戦略は,集計市場インターフェースを使用し,取引の精度などのデータに適応し,取引の対数をそれぞれ処理するアカウント情報にアクセスするなど,これらのソリューションが取引所によって大きく異なることを計画している. インターフェース呼び出しの違い,機構の違いがある. 現場取引所では,この格子戦略がフューチャー版に拡張された場合,格子戦略の違いが少し小さい. 各取引所の仕組みの違いが大きい. 解決策の一つは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()
// 需要实现的接口
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
}
模板では,特定の取引所向けに書き込みを行います.
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
})
})
}
}
この模板は,このサイトで検索したものです.
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)
})
}
上記のテンプレートに基づいて設計し,策略を書くことは簡単です. 全体の策略は約300+行で,デジタル通貨現貨の多種格子策略を実現します.
今では損をしている.T_T
ソースコードは一時的に公開されていません.
WexAppでプレイする興味のある方は,いくつかの登録コードを送信してください.
购买地址: https://www.fmz.com/m/s/284507
注册码:
adc7a2e0a2cfde542e3ace405d216731
f5db29d05f57266165ce92dc18fd0a30
1735dca92794943ddaf277828ee04c27
0281ea107935015491cda2b372a0997d
1d0d8ef1ea0ea1415eeee40404ed09cc
200U以上で,すぐに走ったとき,大きな片側行事が起き,ゆっくり血を流します. 現金網の最大の利点は,あなたが眠ることができるということです! 5月27日以降,安定が再び凝縮され,フューチャー・ネットは一時的に試行錯誤している.
小
9つの太陽モンウェル武将軍!
軌道生物ありがとうございました.
発明者 量化 - 微かな夢ありがとうございました!
発明者 量化 - 微かな夢ありがとうございました!