FMZ資料庫の過去の記事では,いくつかのオーダー,収納,同期戦略を設計しました.
参考アカウントと同期アカウントを1つの戦略にまとめて,オーダーの実現管理,収納同期を図る.今日,少し違ったデザインを試し,FMZ量化取引プラットフォームの強力な拡張APIインターフェースをベースに,オーダーの同期管理システムを設計します.
まず,いくつかの良い提案や要求が必要です. 上記の2つの先行オーダーや,同期戦略のいくつかの明らかな痛みは,一緒に議論しましょう.
1, 同期戦略の実用化者は,参照アカウントの取引所API KEY,同期アカウントの取引所API KEY を必要とする. この使用シナリオの問題は,自分の他の取引所アカウントが自分のアカウントをフォローすることは問題ではない.しかし,参照アカウントと同期アカウントが所有者でないシナリオでは,問題はあります.同期アカウントの所有者は,セキュリティ上の理由で,自分の取引所アカウントのAPI KEYを提供することを拒否することがあります.しかし,API KEYを提供しないと,単一の取引をどのように同期することができますか.
解決策は
FMZの拡張APIインターフェイスを使用して,同期アカウントの所有者 (追記者) は,FMZ量化取引プラットフォームに登録し,このプログラムで設計されたシステムで1つのポリシーを実行するだけです.订单同步管理系统(Synchronous Server)
FMZの拡張API KEY (注:取引所のアカウントのAPI KEYではない) と,オーダーシンクロノースサーバーのリアルディスクIDを参照アカウントの所有者に提供できます.
参照アカウント所有者の実ディスク (本文で設計されたシステム) は,订单同步管理系统类库(Single Server)
) 信号を送信すると,同期口座所有者の実機は取引信号を受け取り,自動的に下注されます.
2,多くの開発者が比較して良い戦略を持っているが,上記2つの先行オーダー,または持参同期戦略を使用することはできません. それは,自分の戦略とこれらの同期戦略を統合する必要があるため,戦略は大きく変更され,苦労する必要があります. 自分の成熟した戦略の一部を直接オーダー同期機能にアップグレードするための良い方法がありますか?
解決策は
注文同期テンプレートクラスバックリ (本文で設計したシステム) を設計できます.订单同步管理系统类库(Single Server)
参照アカウントの所有者 (バンド) は,このテンプレートクラスを自分のポリシーに直接埋め込むことで,注文,保管同期機能を実現することができます.
3 余分な実盤を減らします. 最後の痛みは,上記の2つの先行オーダー,保持同期戦略を使用した場合,さらに実体モニタリング参照口座 (帯持口座) を開く必要があることです. 解決策は テンプレートクラスライブラリを使用して,機能を参照アカウントポリシーに埋め込む.
このシステムには2つの部分があります. 1, 注文同期管理システムクラスデータベース (Single Server) 2, 同期注文管理システム (Synchronous Server)
デザインを始めてください.
注意,これは策略ではなく,FMZのテンプレートデータベースであり,テンプレートデータベースの概念はFMZ APIのドキュメントで検索できます.
模板クラスライブラリコード:
// 全局变量
var keyName_label = "label"
var keyName_robotId = "robotId"
var keyName_extendAccessKey = "extendAccessKey"
var keyName_extendSecretKey = "extendSecretKey"
var fmzExtendApis = parseConfigs([config1, config2, config3, config4, config5])
var mapInitRefPosAmount = {}
function parseConfigs(configs) {
var arr = []
_.each(configs, function(config) {
if (config == "") {
return
}
var strArr = config.split(",")
if (strArr.length != 4) {
throw "configs error!"
}
var obj = {}
obj[keyName_label] = strArr[0]
obj[keyName_robotId] = strArr[1]
obj[keyName_extendAccessKey] = strArr[2]
obj[keyName_extendSecretKey] = strArr[3]
arr.push(obj)
})
return arr
}
function getPosAmount(pos, ct) {
var longPosAmount = 0
var shortPosAmount = 0
_.each(pos, function(ele) {
if (ele.ContractType == ct && ele.Type == PD_LONG) {
longPosAmount = ele.Amount
} else if (ele.ContractType == ct && ele.Type == PD_SHORT) {
shortPosAmount = ele.Amount
}
})
var timestamp = new Date().getTime()
return {ts: timestamp, long: longPosAmount, short: shortPosAmount}
}
function sendCommandRobotMsg (robotId, accessKey, secretKey, msg) {
// https://www.fmz.com/api/v1?access_key=xxx&secret_key=yyyy&method=CommandRobot&args=[186515,"ok12345"]
var url = "https://www.fmz.com/api/v1?access_key=" + accessKey + "&secret_key=" + secretKey + "&method=CommandRobot&args=[" + robotId + ',"' + msg + '"]'
Log(url)
var ret = HttpQuery(url)
return ret
}
function follow(nowPosAmount, symbol, ct, type, delta) {
var msg = ""
var nowAmount = type == PD_LONG ? nowPosAmount.long : nowPosAmount.short
if (delta > 0) {
// 开仓
var tradeDirection = type == PD_LONG ? "buy" : "sell"
// 发送信号
msg = symbol + "," + ct + "," + tradeDirection + "," + Math.abs(delta)
} else if (delta < 0) {
// 平仓
var tradeDirection = type == PD_LONG ? "closebuy" : "closesell"
if (nowAmount <= 0) {
Log("未检测到持仓")
return
}
// 发送信号
msg = symbol + "," + ct + "," + tradeDirection + "," + Math.abs(delta)
} else {
throw "错误"
}
if (msg) {
_.each(fmzExtendApis, function(extendApiConfig) {
var ret = sendCommandRobotMsg(extendApiConfig[keyName_robotId], extendApiConfig[keyName_extendAccessKey], extendApiConfig[keyName_extendSecretKey], msg)
Log("调用CommandRobot接口,", "label:", extendApiConfig[keyName_label], ", msg:", msg, ", ret:", ret)
Sleep(1000)
})
}
}
$.PosMonitor = function(exIndex, symbol, ct) {
var ts = new Date().getTime()
var ex = exchanges[exIndex]
// 判断ex类型
var exName = ex.GetName()
var isFutures = exName.includes("Futures_")
var exType = isFutures ? "futures" : "spot"
if (!isFutures) {
throw "仅支持期货跟单"
}
if (exType == "futures") {
// 缓存 symbol ct
var buffSymbol = ex.GetCurrency()
var buffCt = ex.GetContractType()
// 切换到对应的交易对、合约代码
ex.SetCurrency(symbol)
if (!ex.SetContractType(ct)) {
throw "SetContractType failed"
}
// 监控持仓
var keyInitRefPosAmount = "refPos-" + exIndex + "-" + symbol + "-" + ct // refPos-exIndex-symbol-contractType
var initRefPosAmount = mapInitRefPosAmount[keyInitRefPosAmount]
if (!initRefPosAmount) {
// 没有初始化数据,初始化
mapInitRefPosAmount[keyInitRefPosAmount] = getPosAmount(_C(ex.GetPosition), ct)
initRefPosAmount = mapInitRefPosAmount[keyInitRefPosAmount]
}
// 监控
var nowRefPosAmount = getPosAmount(_C(ex.GetPosition), ct)
// 计算仓位变动
var longPosDelta = nowRefPosAmount.long - initRefPosAmount.long
var shortPosDelta = nowRefPosAmount.short - initRefPosAmount.short
// 检测变动
if (!(longPosDelta == 0 && shortPosDelta == 0)) {
// 执行多头动作
if (longPosDelta != 0) {
Log(ex.GetName(), ex.GetLabel(), symbol, ct, "执行多头跟单,变动量:", longPosDelta)
follow(nowRefPosAmount, symbol, ct, PD_LONG, longPosDelta)
}
// 执行空头动作
if (shortPosDelta != 0) {
Log(ex.GetName(), ex.GetLabel(), symbol, ct, "执行空头跟单,变动量:", shortPosDelta)
follow(nowRefPosAmount, symbol, ct, PD_SHORT, shortPosDelta)
}
// 执行跟单操作后,更新
mapInitRefPosAmount[keyInitRefPosAmount] = nowRefPosAmount
}
// 恢复 symbol ct
ex.SetCurrency(buffSymbol)
ex.SetContractType(buffCt)
} else if (exType == "spot") {
// 现货
}
}
$.getTbl = function() {
var tbl = {
"type" : "table",
"title" : "同步数据",
"cols" : [],
"rows" : []
}
// 构造表头
tbl.cols.push("监控账户:refPos-exIndex-symbol-contractType")
tbl.cols.push(`监控持仓:{"时间戳":xxx,"多头持仓量":xxx,"空头持仓量":xxx}`)
_.each(fmzExtendApis, function(extendApiData, index) {
tbl.cols.push(keyName_robotId + "-" + index)
})
// 写入数据
_.each(mapInitRefPosAmount, function(initRefPosAmount, key) {
var arr = [key, JSON.stringify(initRefPosAmount)]
_.each(fmzExtendApis, function(extendApiData) {
arr.push(extendApiData[keyName_robotId])
})
tbl.rows.push(arr)
})
return tbl
}
// 引用该模板类库的策略调用范例
function main() {
// 清除所有日志
LogReset(1)
// 切换到OKEX 模拟盘测试
exchanges[0].IO("simulate", true)
// 设置合约
exchanges[0].SetCurrency("ETH_USDT")
exchanges[0].SetContractType("swap")
// 定时交易时间间隔
var tradeInterval = 1000 * 60 * 3 // 三分钟交易一次,用于观察跟单信号
var lastTradeTS = new Date().getTime()
while (true) {
// 策略其它逻辑...
// 用于测试的模拟交易触发
var ts = new Date().getTime()
if (ts - lastTradeTS > tradeInterval) {
Log("模拟带单策略发生交易,持仓变化", "#FF0000")
exchanges[0].SetDirection("buy")
exchanges[0].Buy(-1, 1)
lastTradeTS = ts
}
// 使用模板的接口函数
$.PosMonitor(0, "ETH_USDT", "swap") // 可以设置多个监控,监控带单策略上的不同的exchange对象
var tbl = $.getTbl()
// 显示状态栏
LogStatus(_D(), "\n" + "`" + JSON.stringify(tbl) + "`")
Sleep(1000)
}
}
FMZのプラットフォーム上のプログラム化取引戦略が引用されたとき,このデータベースは,订单同步管理系统类库(Single Server)
テンプレートクラスライブラリの後ろに. このシートには,次の関数を使用できます.
$PosMonitor をクリックします この機能の役割は,取引所の対象の保有変動を監視する方針であり,その後,テンプレート:オーダーシンクロマネジメントシステム (Single Server) のパラメータに設定されたリアルディスク取引信号を送信する.
$2.getTbl は 監視された同期データを返します.
使用例は: 注文同期管理システムクラスバックリ (Single Server) のテンプレートmain
この関数は,
// 引用该模板类库的策略调用范例
function main() {
// 清除所有日志
LogReset(1)
// 切换到OKEX 模拟盘测试
exchanges[0].IO("simulate", true)
// 设置合约
exchanges[0].SetCurrency("ETH_USDT")
exchanges[0].SetContractType("swap")
// 定时交易时间间隔
var tradeInterval = 1000 * 60 * 3 // 三分钟交易一次,用于观察跟单信号
var lastTradeTS = new Date().getTime()
while (true) {
// 策略其它逻辑...
// 用于测试的模拟交易触发
var ts = new Date().getTime()
if (ts - lastTradeTS > tradeInterval) {
Log("模拟带单策略发生交易,持仓变化", "#FF0000")
exchanges[0].SetDirection("buy")
exchanges[0].Buy(-1, 1)
lastTradeTS = ts
}
// 使用模板的接口函数
$.PosMonitor(0, "ETH_USDT", "swap") // 可以设置多个监控,监控带单策略上的不同的exchange对象
var tbl = $.getTbl()
// 显示状态栏
LogStatus(_D(), "\n" + "`" + JSON.stringify(tbl) + "`")
Sleep(1000)
}
}
テンプレートクラスバックリ自体は,通常,テンプレートクラスバックリをテストするために使用される ポリシーディスクを作成することもできます. 例えば,このテンプレートのテストです. テンプレートの中で理解することができます.main
この関数は,あなたの自分の戦略です.main
この関数は,
テストコードは,OKEX アナログディスクを使ってテストするために書かれたもので,FMZで OKEX アナログディスクのAPI KEYを参照アカウントとして設定し,メイン関数でアナログディスクに切り替える.その後,取引対をETH_USDTに設定し,契約を永久に設定します.その後,while ループに入ります.ループの3分ごとに1回注文取引を行い,アナログ戦略取引を誘発するために使用します.while ループで呼び出されます.$.PosMonitor(0, "ETH_USDT", "swap")
この関数の呼び出しの最初のパラメータは,monitor exchanges[0]を表示し,この取引所のオブジェクトを監視し,ETH_USDT取引対,スワップ契約を呼び出す.$.getTbl()
グラフの情報を取得し,それを使用しますLogStatus(_D(), "\n" + "`" + JSON.stringify(tbl) + "`")
グラフのデータを状態バーに表示します.
テンプレートに引用する戦略で使えばいいのです$.PosMonitor(0, "ETH_USDT", "swap")
策略には,ある品種を監視し,その品種がメッセージを送信する動きを監視する機能が与えられます.
テストの前に説明してください.订单同步管理系统类库(Single Server)
戦略のパラメータ設計:
テンプレートのインターフェース関数を活用して,ある戦略をアップグレードし,バンド機能を持つようにする方法を説明しました.
メールは誰に送るかという問題は订单同步管理系统类库(Single Server)
設定されたパラメータです.
パラメータは5つあり,最大5つのプッシュをサポートしている (追加が必要で自律的に拡張できる),パラメータは空の文字列でデフォルトで処理されません.
レーベル 同期アカウントのタグは,特定のアカウントにタグ付けされ,名前を任意に設定することができます.
ロボットId
リアルディスクIDは,同期アカウントの所有者が作成したものです订单同步管理系统(Synchronous Server)
リアルディスクのID.
アクセスキー FMZの拡張APIのアクセスキー
シークレットキー FMZの拡張APIの secretKey
簡単なテストを行います. 簡単なテストを行います.
注文同期管理システムクラスバックリ (Single Server) の実装台を実行する:
注文同期管理システム (Synchronous Server) のディスクに信号が受信されました. 同期サーバー (Synchronous Server) の設計はまだ完了していませんが,まずは簡単なコードで実行します. 取引を行わず,信号を印刷します.
注文同期管理システム (Synchronous Server) 暫定コード:
function main() {
LogReset(1)
while (true) {
var cmd = GetCommand()
if (cmd) {
// cmd: ETH_USDT,swap,buy,1
Log("cmd: ", cmd)
}
Sleep(1000)
}
}
シンクロアカウント所有者の実機にメッセージが受信されているのが見えます.ETH_USDT,swap,buy,1
│ │
取引先の情報や契約コード,取引方向,取引量などに合わせて,次のステップを自動的に実行できます.
現在订单同步管理系统(Synchronous Server)
デザインについては,次の記事で詳しく説明します.
ミンジ1005リストを実行するには 2 つのディスクが必要です. 1 つはクラスディスク, 1 つはオーダー管理システムディスク.
ミンジ1005設定が間違っています
アール逆行リストのパラメータを変更する必要があります.
アールこの2つのディスクを組み合わせて使えますか? 信号を送るディスクと受信するディスクです.
発明者 量化 - 微かな夢このクラスは,バンドライダーのポリシー行に直接埋め込むツールであり,バンド機能が機能すると,設定されたバンドライダーのアカウントにメッセージを送信し,バンドライダーはメッセージを受け取ります. 簡単に言うと,このような状況です.
発明者 量化 - 微かな夢記事,配置情報:タグ,実ディスクID,accesskey,secretkey を参照してください. このエラーを報告するのは,あなたの情報が正しく配置されていないことを意味します.
ミンジ1005誤り configs error!, 注文同期管理システムデータベース (Single Server) に,帯主ディスクと2つのKEYをすべて埋め込み,その後実ディスクに注文同期管理システムデータベース (Single Server) を参照し,エラー,エラー configs error! を返します.
ミンジ1005設定が間違っています!
発明者 量化 - 微かな夢誤った情報を報告する方法を確認します.
発明者 量化 - 微かな夢戦略を変える必要がある.
発明者 量化 - 微かな夢オープンソースで,必要に応じて変更することもできます.