FMZダイジェストの前の記事では,いくつかの順序と位置の同期戦略を設計しました.
このデザインでは,参照アカウントと同期アカウントを同じ戦略に組み,注文とポジションの同期を実現するために管理することができます.今日,私たちは異なるデザインを試してみることができます. FMZの強力な拡張 API インターフェースに基づいて,ここで注文同期管理システムを設計します.
まず,いくつかの良い提案と要求が必要です.上記の2つの以前のオーダーとポジションの同期戦略にはいくつかの明らかな欠点があります.一緒に議論しましょう:
1. 戦略ボット同期を実装するユーザーは,参照アカウントプラットフォームのAPI KEYと同期アカウントのAPI KEYを持っている必要があります. 使用シナリオでは,問題は,他のプラットフォームアカウントが自分のアカウントの1つをフォローすることは問題ありません.しかし,参照アカウントと同期アカウントが同じ所有者でないシナリオでは問題になります.同期アカウントの所有者は,セキュリティ上の考慮のために,自分のプラットフォームアカウントの API KEY を提供したくない場合もあります.しかし,API KEY を提供せずに同期取引の注文をどのように行うか?
解決策:
FMZ拡張APIを使用すると,同期アカウントの所有者 (オーダー監督者) は,FMZ Quant取引プラットフォームを登録し,その後戦略を実行する必要があります (この記事で設計されたシステムでは:Order Synchronous Management System (Synchronous Server)
その後,FMZの拡張 API KEY (プラットフォームアカウントの API KEY ではないことに注意) とオーダー同期管理システムのbot ID (同期サーバー) は参照アカウントの所有者 (オーダー所有者) に提供されます.
参照口座所有者のボット (オーダー所有者) が (Order Synchronous Management System Library (Single Server)
オーダーが自動的に後日配置されます. オーダーが送信されたときに,オーダーが送信されたときに,オーダーが送信されたときに,オーダーが送信されたときに,オーダーが送信されたときに,オーダーが送信されたときに,オーダーが送信されたときに,オーダーが送信されたときに,オーダーが送信されたときに,オーダーが送信されたときに,オーダーが送信されたときに,オーダーが送信されたときに,オーダーが送信されたときに,オーダーが送信されたときに,オーダーが送信されたときに,オーダーが送信されたときに,オーダーが送信されたときに,オーダーが送信されたときに,オーダーが送信されたときに,オーダーが送信されたときに,オーダーが送信されたときに,オーダーが送信されたときに,オーダーが送信されたときに,オーダーが送信されたときに,オーダーが送信されたときに,オーダーが送信されたときに,オーダーが送信されたときに,オーダーが送信されたときに,オーダーが送信されたときに,オーダーが送信されたときに,オーダーが送信されたときに,オーダーが送信された場合,オーダーが送信された場合,オーダーが送信された場合,オーダーが送信された場合
2.多くの開発者はより良い戦略を持っているが,上述の2つの以前の順序と位置同期戦略を使用することはできません.それはこれらの同期戦略と独自の戦略を合併する必要があるため,その戦略は大幅に変更する必要があるかもしれません.これは時間と労力を消費するものです.あなたの成熟した戦略の一部を順序同期機能を持つものに直接アップグレードする良い方法がありますか?
解決法
オーダー同期テンプレートライブラリ (theOrder Synchronous Management System Library (Single Server)
参照アカウントの所有者 (注文所有者) が,直接このテンプレートライブラリを自分の戦略に挿入して順序と位置の同期を達成できるようにします.
3.追加ボットを減らす 最後の欠点は,上記2つの前回の注文と位置同期戦略を使用すると,ボットモニタリングのために参照アカウントの追加の位置 (注文付きアカウント) を開く必要があることです. 解決策: テンプレートライブラリを使用して,関数を参照アカウント戦略に埋め込む.
したがって,このシステムは2つの部分で構成されています. 1.オーダー同期管理システムライブラリ (シングルサーバー) 2.同期管理システム (同期サーバー)
要求を確かめると デザインを始めよう!
FMZ APIのドキュメントで検索できる FMZ テンプレートライブラリであり,ここで議論することはありません.
モデルコード:
// Global variable
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) {
// Open position
var tradeDirection = type == PD_LONG ? "buy" : "sell"
// Send signal
msg = symbol + "," + ct + "," + tradeDirection + "," + Math.abs(delta)
} else if (delta < 0) {
// Open position
var tradeDirection = type == PD_LONG ? "closebuy" : "closesell"
if (nowAmount <= 0) {
Log("No position detected")
return
}
// Send signal
msg = symbol + "," + ct + "," + tradeDirection + "," + Math.abs(delta)
} else {
throw "error"
}
if (msg) {
_.each(fmzExtendApis, function(extendApiConfig) {
var ret = sendCommandRobotMsg(extendApiConfig[keyName_robotId], extendApiConfig[keyName_extendAccessKey], extendApiConfig[keyName_extendSecretKey], msg)
Log("Call CommandRobot interface,", "label:", extendApiConfig[keyName_label], ", msg:", msg, ", ret:", ret)
Sleep(1000)
})
}
}
$.PosMonitor = function(exIndex, symbol, ct) {
var ts = new Date().getTime()
var ex = exchanges[exIndex]
// Judge the type of ex
var exName = ex.GetName()
var isFutures = exName.includes("Futures_")
var exType = isFutures ? "futures" : "spot"
if (!isFutures) {
throw "Only support futures order supervising"
}
if (exType == "futures") {
// Cache symbol ct
var buffSymbol = ex.GetCurrency()
var buffCt = ex.GetContractType()
// Switch to the corresponding trading pair and contract code
ex.SetCurrency(symbol)
if (!ex.SetContractType(ct)) {
throw "SetContractType failed"
}
// Monitor position
var keyInitRefPosAmount = "refPos-" + exIndex + "-" + symbol + "-" + ct // refPos-exIndex-symbol-contractType
var initRefPosAmount = mapInitRefPosAmount[keyInitRefPosAmount]
if (!initRefPosAmount) {
// The data is not initialized; initialize it
mapInitRefPosAmount[keyInitRefPosAmount] = getPosAmount(_C(ex.GetPosition), ct)
initRefPosAmount = mapInitRefPosAmount[keyInitRefPosAmount]
}
// Monitor
var nowRefPosAmount = getPosAmount(_C(ex.GetPosition), ct)
// Calculate position changes
var longPosDelta = nowRefPosAmount.long - initRefPosAmount.long
var shortPosDelta = nowRefPosAmount.short - initRefPosAmount.short
// Detect changes
if (!(longPosDelta == 0 && shortPosDelta == 0)) {
// Execute long position action
if (longPosDelta != 0) {
Log(ex.GetName(), ex.GetLabel(), symbol, ct, "Execute long position order supervision, change volume:", longPosDelta)
follow(nowRefPosAmount, symbol, ct, PD_LONG, longPosDelta)
}
// Execute short position action
if (shortPosDelta != 0) {
Log(ex.GetName(), ex.GetLabel(), symbol, ct, "Execute short position order supervision, change volume:", shortPosDelta)
follow(nowRefPosAmount, symbol, ct, PD_SHORT, shortPosDelta)
}
// After executing the order supervision operation, update
mapInitRefPosAmount[keyInitRefPosAmount] = nowRefPosAmount
}
// Recover symbol ct
ex.SetCurrency(buffSymbol)
ex.SetContractType(buffCt)
} else if (exType == "spot") {
// Spot
}
}
$.getTbl = function() {
var tbl = {
"type" : "table",
"title" : "Synchrodata",
"cols" : [],
"rows" : []
}
// Construct the table title
tbl.cols.push("Monitoring account:refPos-exIndex-symbol-contractType")
tbl.cols.push(`Mintoring position:{"timestamp":xxx,"long position volume":xxx,"short position volume":xxx}`)
_.each(fmzExtendApis, function(extendApiData, index) {
tbl.cols.push(keyName_robotId + "-" + index)
})
// Write in the data
_.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
}
// Invocation example of the strategy in the template
function main() {
// Clear all logs
LogReset(1)
//Switch to OKEX simulated bot test
exchanges[0].IO("simulate", true)
// Set contract
exchanges[0].SetCurrency("ETH_USDT")
exchanges[0].SetContractType("swap")
// Timed trading time interval
var tradeInterval = 1000 * 60 * 3 // trade every three minutes, to observe the order supervising signal
var lastTradeTS = new Date().getTime()
while (true) {
// Other logic of the strategy...
// Used to test the simulated trade trigger
var ts = new Date().getTime()
if (ts - lastTradeTS > tradeInterval) {
Log("Simulated strategy with orders has trades, and positions changed", "#FF0000")
exchanges[0].SetDirection("buy")
exchanges[0].Buy(-1, 1)
lastTradeTS = ts
}
// Call the interface function in the template
$.PosMonitor(0, "ETH_USDT", "swap") // You can set multiple monitors, to minitor different exchange objects in the strategy with orders
var tbl = $.getTbl()
// Display the status bar
LogStatus(_D(), "\n" + "`" + JSON.stringify(tbl) + "`")
Sleep(1000)
}
}
FMZプラットフォームのプログラム取引戦略は,このライブラリを呼び出す.Order Synchronous Management System Library (Single Server)
テンプレートクラスライブラリです この戦略は次の関数を使用できます
この例は,main
オーダー同期管理システムライブラリ (シングルサーバー) の機能:
// Invocation example of the strategy in the template
function main() {
// Clear all logs
LogReset(1)
// Switch to OKEX simulated bot test
exchanges[0].IO("simulate", true)
// Set contract
exchanges[0].SetCurrency("ETH_USDT")
exchanges[0].SetContractType("swap")
// Timed trading time interval
var tradeInterval = 1000 * 60 * 3 // trade every three minutes, to observe the order supervising signal
var lastTradeTS = new Date().getTime()
while (true) {
// Other logic of the strateg...
// Used to test the simulated trade trigger
var ts = new Date().getTime()
var ts = new Date().getTime()
if (ts - lastTradeTS > tradeInterval) {
Log("Simulated strategy with orders has trades, and positions changed", "#FF0000")
exchanges[0].SetDirection("buy")
exchanges[0].Buy(-1, 1)
lastTradeTS = ts
}
// Use the interface function of the template
$.PosMonitor(0, "ETH_USDT", "swap") // You can set multiple monitors to monitor different exchange objects on an strategy with orders
var tbl = $.getTbl()
// Display the status bar
LogStatus(_D(), "\n" + "`" + JSON.stringify(tbl) + "`")
Sleep(1000)
}
}
テンプレートライブラリ自体は,通常テンプレートライブラリをテストするために使用される戦略ボットも作成できます.例えば,このテンプレートのテストです.main
テンプレート内の関数はmain
自分の戦略の一つの機能です.
テストコードは,OKEXシミュレーションボットをテストするために使用するために書かれ,OKEXシミュレーションボットのAPI KEYは,FMZで参照アカウント (オーダーとともに) として設定され,メイン機能がシミュレーションボットに切り替えるようになります.その後,取引ペアをETH_USDTに設定し,契約をスワップに設定します.その後, whileループを入力します.ループでは,戦略取引のトリガーをシミュレートするために3分ごとにオーダーが配置されます.$.PosMonitor(0, "ETH_USDT", "swap")
呼び出された関数の最初のパラメータは0で,交換オブジェクト[0],取引ペアETH_USDT,およびスワップ契約を監視することを意味します.$.getTbl()
グラフの情報を入手し,LogStatus(_D(), "\n" + "`" + JSON.stringify(tbl) + "`")
状態バーに表示されるチャートデータを作ります
解明できる限り$.PosMonitor(0, "ETH_USDT", "swap")
テンプレートを呼び出す戦略で使用される場合,その戦略は特定のシンボルの位置を監視し,位置変更メッセージを押す機能を持つことができます.
試験の前に,パラメータ設計を説明します.Order Synchronous Management System Library (Single Server)
戦略
ポジションが変わると信号は誰に送られるのか? ポジションが変わると信号は誰に送られるのか?
送信する相手は,order synchronous management system library (Single Server)
.
設定された文字列フォーマットでは: label, robotId, accessKey, secretKey. 設定された文字列フォーマットでは: label, robotId, accessKey, secretKey.
ラベル 同期アカウントのラベル,アカウントのラベルに使用される.ラベル名はランダムに設定できます.
ロボット
ボットID;ボットIDのorder synchronous management system (Synchronous Server)
同期アカウント所有者が作成したものです
アクセスKey FMZのアクセスキーで拡張されたAPIです
秘密キー FMZの秘密キーで 拡張されたAPIです
簡単なテストを行います
オーダー 同期管理システムライブラリ (シングルサーバー) ボット操作:
命令同期管理システム (同期サーバー) ボットは信号を受け取った: オーダー同期管理システム (同期サーバー) は,まだ完全に設計されていません. そして,我々は,取引なしで,それを実現するために簡単なコードを使用することができます.
オーダー シンクロン管理システム (シンクロンサーバー) 暫定コード:
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
- わかった
取引ペア,契約コード,取引方向,取引量によって 自動的に注文を監視できます
現在ではorder synchronous management system (Synchronous Server)
その設計については 次の記事で詳しく説明します