
Dans les articles précédents de la bibliothèque FMZ, nous avons conçu plusieurs stratégies de synchronisation des commandes et des positions.
Il s’agit de regrouper le compte de référence et le compte de synchronisation dans une seule stratégie pour gérer et synchroniser les commandes et les positions. Aujourd’hui, nous allons essayer une conception différente. En nous basant sur la puissante interface API étendue de la plateforme de trading quantitative FMZ, nous allons concevoir un système de gestion de la synchronisation des commandes.
Tout d’abord, nous avons besoin de bonnes suggestions et de bons besoins. Les deux stratégies de synchronisation des ordres et des positions ci-dessus présentent plusieurs problèmes évidents. Examinons-les ensemble :
Solution:
En utilisant l’interface API étendue de FMZ, le propriétaire du compte de synchronisation (follower) n’a besoin que d’enregistrer la plateforme de trading quantitative FMZ, puis d’exécuter une stratégie (dans le système conçu dans cet article :订单同步管理系统(Synchronous Server)Stratégie marché réel). Fournissez ensuite la clé API étendue FMZ (attention, pas la clé API du compte d’échange) et l’ID en temps réel du système de gestion de synchronisation des commandes (Synchronous Server) au propriétaire du compte de référence (la personne qui passe la commande) .
Lorsqu’il s’agit de la commande réelle du propriétaire du compte (celui avec la commande) (dans le système conçu dans cet article)订单同步管理系统类库(Single Server)) envoie un signal, le compte réel du propriétaire du compte synchronisé recevra le signal de trading et passera automatiquement une commande par la suite.
订单同步管理系统类库(Single Server)Stratégie), permettant au propriétaire du compte de référence (la personne qui prend la commande) d’intégrer directement cette bibliothèque de modèles dans sa propre stratégie pour réaliser la fonction de synchronisation des commandes et des positions.Ce système se compose donc de 2 parties : 1. Bibliothèque de classes du système de gestion de la synchronisation des commandes (serveur unique) 2. Commandez le système de gestion synchrone (serveur synchrone)
Maintenant que les exigences sont claires, commençons la conception !
Notez que ce n’est pas une stratégie. Il s’agit d’une bibliothèque de classes de modèles de FMZ. Le concept de bibliothèque de classes de modèles peut être recherché dans la documentation de l’API FMZ, je n’entrerai donc pas dans les détails ici.
Code de la bibliothèque de modèles :
// 全局变量
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)
}
}
La conception est très simple, cette bibliothèque de classes a 2 fonctions fonctionnelles. Lorsqu’une stratégie de trading programmatique sur la plateforme FMZ fait référence订单同步管理系统类库(Single Server)Après la bibliothèque de modèles. Cette stratégie peut être implémentée à l’aide de la fonction suivante.
$.PosMonitor La fonction est de surveiller les changements de position de l’objet d’échange dans la stratégie, puis d’envoyer des signaux de trading au marché réel défini dans les paramètres du modèle : Bibliothèque de classes du système de gestion de la synchronisation des ordres (serveur unique).
$.getTbl Renvoie les données de synchronisation surveillées.
L’exemple d’utilisation est dans : Bibliothèque de classes du système de gestion de la synchronisation des commandes (modèle de serveur unique)mainDans la fonction :
// 引用该模板类库的策略调用范例
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)
}
}
Une bibliothèque de modèles elle-même peut également créer de véritables stratégies, qui sont généralement utilisées pour tester la bibliothèque de modèles. Par exemple, un test de ce modèle. Vous pouvez comprendre le modèlemainUne fonction est une stratégie qui vous est propre.mainfonction.
Le code de test est écrit pour utiliser le test du disque de simulation OKEX. Il est nécessaire de configurer la clé API du disque de simulation OKEX sur FMZ comme compte de référence (avec commandes) et de commencer à basculer vers le disque de simulation dans la fonction principale. Définissez ensuite la paire de trading sur ETH_USDT et le contrat sur perpétuel (swap). Entrez ensuite une boucle while. Un ordre est passé toutes les 3 minutes dans le cycle pour simuler le déclenchement du trading de stratégie. La boucle while appelle$.PosMonitor(0, "ETH_USDT", "swap")Le premier paramètre de cette fonction est passé à 0, indiquant la surveillance des échanges[0] Cet objet d’échange surveille la paire de trading ETH_USDT et le contrat de swap. Alors appelle$.getTbl()Pour obtenir des informations sur le graphique, utilisezLogStatus(_D(), "\n" + "” + JSON.stringify(tbl) + “")Permet d’afficher les données du graphique dans la barre d’état.
Donc vous voyez, tant que vous l’utilisez dans une politique qui fait référence à ce modèle$.PosMonitor(0, "ETH_USDT", "swap"), la stratégie peut être équipée de la fonction de surveillance des positions d’un certain produit et d’envoi de messages en fonction des changements de position.
Avant de tester, veuillez expliquer订单同步管理系统类库(Single Server)Conception des paramètres de stratégie :
Je viens de parler de la façon d’utiliser la fonction d’interface de modèle pour permettre à une mise à niveau de stratégie d’avoir une fonction unique. Alors à qui est envoyé le signal lorsque la position change ?
La personne à qui cette question est envoyée est déterminée par订单同步管理系统类库(Single Server)Paramètres à configurer.

Vous pouvez voir qu’il y a 5 paramètres, prenant en charge jusqu’à 5 pushs (vous pouvez l’étendre si vous avez besoin de l’augmenter), et le paramètre par défaut est une chaîne vide, ce qui signifie qu’il n’est pas traité. Format de la chaîne de configuration : label, robotId, accessKey, secretKey
label L’étiquette du compte synchronisé est utilisée pour marquer un certain compte, et le nom peut être défini à volonté.
robotId
ID réel, créé par le propriétaire du compte de synchronisation订单同步管理系统(Synchronous Server)L’ID de la transaction réelle.
accessKey Accès étendu à l’API FMZKey
secretKey Clé secrète de l’API étendue de FMZ
Ensuite, nous pouvons faire un test simple.
Bibliothèque de classes du système de gestion de synchronisation des commandes (serveur unique) fonctionnement du disque réel :

Le système de gestion de synchronisation des commandes (Synchronous Server) a reçu le signal : Nous n’avons pas encore terminé la conception du système de gestion de la synchronisation des commandes (Synchronous Server). Commençons d’abord par l’implémenter avec un code simple qui ne fait pas de transactions mais imprime seulement des signaux :
Code temporaire du système de gestion de la synchronisation des commandes (Synchronous Server) :
function main() {
LogReset(1)
while (true) {
var cmd = GetCommand()
if (cmd) {
// cmd: ETH_USDT,swap,buy,1
Log("cmd: ", cmd)
}
Sleep(1000)
}
}

Vous pouvez voir que le compte réel du propriétaire du compte de synchronisation a reçu les informations :ETH_USDT,swap,buy,1。
De cette façon, l’étape suivante consiste à suivre automatiquement l’ordre en fonction de la paire de trading, du code du contrat, de la direction de trading et de la quantité dans les informations.
à l’heure actuelle订单同步管理系统(Synchronous Server)Il s’agit simplement d’un code temporaire, nous continuerons à explorer sa conception dans le prochain numéro.