Dans les articles précédents sur FMZ Digest, nous avons conçu plusieurs stratégies synchrones d'ordre et de position.
Ces conceptions prennent le compte de référence et le compte synchrone dans la même stratégie à gérer pour réaliser la synchronisation des ordres et des positions.
Tout d'abord, nous avons besoin de quelques bonnes suggestions et exigences. Les deux précédentes stratégies de synchronisation d'ordres et de positions ont plusieurs inconvénients évidents.
1.Les utilisateurs qui mettent en œuvre la stratégie de synchronisation des robots doivent disposer de la CLAVE API de la plateforme de compte de référence et de la CLAVE API du compte de synchronisation. Pour le scénario d'utilisation, le problème est le suivant: il est normal que vos autres comptes de plateforme suivent l'un de vos propres comptes. Mais cela peut être gênant pour le scénario où le compte de référence et le compte de synchronisation n'ont pas le même propriétaire. Le propriétaire du compte de synchronisation est parfois réticent à fournir la CLAVE API de son compte de plateforme en raison de considérations de sécurité. Mais comment passer un ordre de trading synchronisé sans fournir la CLAVE API?
Résolution:
Utiliser l'API étendue FMZ, le propriétaire du compte de synchronisation (le superviseur des ordres) a seulement besoin d'enregistrer la plateforme de trading FMZ Quant, puis d'exécuter une stratégie (dans le système conçu dans cet article:Order Synchronous Management System (Synchronous Server)
Ensuite, la clé API étendue de FMZ (notez qu'il ne s'agit pas de la clé API du compte de la plateforme) et l'identifiant de bot du système de gestion de la synchronisation des commandes (serveur synchrone) seront fournis au propriétaire du compte de référence (le propriétaire de la commande).
Lorsque le bot du propriétaire du compte de référence (le propriétaire de l'ordre) (Order Synchronous Management System Library (Single Server)
Dans le cas où un robot de synchronisation (ou un robot de synchronisation) envoie un signal, le propriétaire du compte reçoit le signal de trading.
2.Beaucoup de développeurs ont de meilleures stratégies et ne peuvent pas utiliser les deux précédentes stratégies de synchronisation d'ordre et de position décrites ci-dessus. Parce que cela nécessite de fusionner leurs propres stratégies avec ces stratégies de synchronisation, et leurs stratégies peuvent devoir être considérablement modifiées, ce qui prend du temps et de la main-d'œuvre. Y a-t-il un bon moyen de mettre à niveau directement certaines de vos stratégies matures à celles avec la fonction de synchronisation d'ordre?
Résolution:
Vous pouvez concevoir une bibliothèque de modèles synchrones de commande (leOrder Synchronous Management System Library (Single Server)
L'expérience a montré qu'il est possible d'intégrer cette bibliothèque de modèles dans le système conçu dans l'article), de sorte que le propriétaire du compte de référence (le propriétaire de la commande) puisse insérer directement cette bibliothèque de modèles dans sa propre stratégie pour réaliser la synchronisation de l'ordre et de la position.
3.Réduire un bot supplémentaire Le dernier inconvénient est que si vous utilisez les deux précédentes stratégies de synchronisation des ordres et des positions décrites ci-dessus, il est nécessaire d'ouvrir une position supplémentaire du compte de référence (compte avec des ordres) pour la surveillance des bots. Résolution: Utilisez la bibliothèque de modèles pour intégrer la fonction dans la stratégie de compte de référence.
Par conséquent, le système se compose de deux parties: 1. bibliothèque de système de gestion synchrone de commande (serveur unique) 2.système de gestion synchrone des commandes (serveur synchrone)
Une fois que nous sommes sûrs de nos exigences, commençons à concevoir!
Veuillez noter qu'il ne s'agit pas ici d'une stratégie, mais d'une bibliothèque de modèles FMZ, qui peut être recherchée dans la documentation FMZ API et dont nous ne discuterons pas ici.
Code du modèle:
// 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)
}
}
La conception est très simple, la bibliothèque a 2 fonctions.Order Synchronous Management System Library (Single Server)
Cette stratégie peut alors utiliser les fonctions suivantes.
L'exemple d'utilisation est lemain
fonction dans la bibliothèque du système de gestion synchrone des commandes (serveur unique):
// 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)
}
}
Une bibliothèque de modèles elle-même peut également créer un bot de stratégie, qui est généralement utilisé pour tester la bibliothèque de modèles.main
la fonction dans le modèle est lamain
fonction d'une de vos propres stratégies.
Le code de test est écrit pour utiliser le bot simulé OKEX pour tester, et la clé API du bot simulé OKEX doit être configurée sur FMZ comme un compte de référence (avec des ordres), et la fonction principale commence à basculer vers le bot simulé. Ensuite, définissez la paire de trading sur ETH_USDT, et définissez le contrat pour échanger. Ensuite, entrez une boucle while. Dans la boucle, un ordre est placé toutes les 3 minutes pour simuler le déclenchement des transactions de stratégie.$.PosMonitor(0, "ETH_USDT", "swap")
est appelé dans la boucle while, et le premier paramètre de la fonction appelée est 0, ce qui signifie surveiller les échanges d'objets d'échange[0], la paire de trading ETH_USDT et le contrat de swap.$.getTbl()
pour obtenir les informations du graphique, et utiliserLogStatus(_D(), "\n" + "`" + JSON.stringify(tbl) + "`")
pour faire apparaître les données du graphique sur la barre d'état.
Vous voyez, tant que$.PosMonitor(0, "ETH_USDT", "swap")
est utilisé dans une stratégie qui appelle le modèle, la stratégie peut avoir pour fonction de surveiller une certaine position du symbole et de pousser le message de changement de position.
Avant l'essai, expliquer la conception des paramètres duOrder Synchronous Management System Library (Single Server)
stratégie:
Je viens de parler de la façon d'utiliser la fonction d'interface du modèle pour faire une mise à niveau de stratégie avec une fonction de transport des ordres.
La question de savoir à qui envoyer est configurée par les paramètres deorder synchronous management system library (Single Server)
.
Vous pouvez voir cinq paramètres, qui peuvent supporter au maximum cinq poussées (si vous avez besoin d'augmenter le nombre de poussées, vous pouvez l'étendre par vous-même); la valeur par défaut des paramètres est une chaîne vide, à savoir non traitée.
étiquette L'étiquette du compte synchrone, utilisée pour étiqueter un compte; le nom de l'étiquette peut être défini au hasard.
robotId
L'ID du bot; l'ID du bot duorder synchronous management system (Synchronous Server)
créée par le propriétaire du compte synchrone.
accèsClé La clé d'accès de l'API étendue FMZ.
Clé secrète La clé secrète de l'API étendue FMZ.
Ensuite, nous pouvons effectuer un test simple.
Commande de la bibliothèque du système de gestion synchrone (serveur unique) opération de bot:
Le bot du système de gestion synchrone de commande (serveur synchrone) a reçu le signal: Ordre Système de gestion synchrone (serveur synchrone) maintenant n'a pas été entièrement conçu par nous, et nous pouvons utiliser un code simple pour le réaliser, sans commerce, seulement l'impression de signal:
Code temporaire du système de gestion synchrone de commande (serveur synchrone):
function main() {
LogReset(1)
while (true) {
var cmd = GetCommand()
if (cmd) {
// cmd: ETH_USDT,swap,buy,1
Log("cmd: ", cmd)
}
Sleep(1000)
}
}
Comme vous pouvez le voir, le bot du propriétaire du compte synchrone a reçu le message:ETH_USDT,swap,buy,1
Je suis désolée.
Ainsi, dans l'étape suivante, nous pouvons superviser les ordres automatiquement, selon la paire de négociation, le code du contrat, la direction de négociation et le volume.
Actuellement,order synchronous management system (Synchronous Server)
est seulement un code temporaire, et nous pourrons en discuter plus en détail dans l'article suivant.