In previous articles in FMZ’s library, we have designed several kinds of synchronization strategies for order and position.
These manage reference accounts and synchronized accounts in one strategy to achieve order and position synchronization. And today we will try a different design, we will design an order synchronization management system based on the powerful extended API interface of FMZ Quant Trading Platform.
First, we need some good suggestions and needs. The two previous order and position synchronization strategies above, which have several obvious shortcomings, which we will discuss together.
Solutions:
Use the FMZ’s extended API interface, the owner of the synchronized account (order follower) only needs to register an account on FMZ Quant Trading Platform, then run a strategy (in the system designed in this article: Order Synchronous Server
Strategy in Real Bot). Then just provide the FMZ extended API KEY (note that it is not the API KEY of the exchange account) and the Order Synchronous Server real bot ID to the owner of the reference account (order leader).
When the reference account owner’s (order follower’s) real bot (the Order Synchronization Management System Class Library (Single Server)
in the system designed in this article) sends a signal, the synchronization account owner’s real bot will receive the trade signal and place the subsequent order automatically.
Order Synchronization Management System Class Library (Single Server)
strategy in the system designed in this article), so that the owner of the reference account (order-leader) can embed this template class library into his own strategy directly to achieve the function of order and position synchronization.So the system consists of 2 parts:
Once we’ve defined our needs, let’s start designing!
Note that this is not a strategy. It is a template class library of FMZ. The concept of a template class library can be searched in the FMZ API documentation and we will not repeat it again.
Template class library code:
// Global variables
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 the position
var tradeDirection = type == PD_LONG ? "buy" : "sell"
// send signals
msg = symbol + "," + ct + "," + tradeDirection + "," + Math.abs(delta)
} else if (delta < 0) {
// close the position
var tradeDirection = type == PD_LONG ? "closebuy" : "closesell"
if (nowAmount <= 0) {
Log("no positions found")
return
}
// send signals
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 the 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 future-following is supported"
}
if (exType == "futures") {
// caching symbol ct
var buffSymbol = ex.GetCurrency()
var buffCt = ex.GetContractType()
// switch to the corresponding contract pair, contract code
ex.SetCurrency(symbol)
if (!ex.SetContractType(ct)) {
throw "SetContractType failed"
}
// monitor positions
var keyInitRefPosAmount = "refPos-" + exIndex + "-" + symbol + "-" + ct // refPos-exIndex-symbol-contractType
var initRefPosAmount = mapInitRefPosAmount[keyInitRefPosAmount]
if (!initRefPosAmount) {
// no initialization data, initialize it
mapInitRefPosAmount[keyInitRefPosAmount] = getPosAmount(_C(ex.GetPosition), ct)
initRefPosAmount = mapInitRefPosAmount[keyInitRefPosAmount]
}
// monitor
var nowRefPosAmount = getPosAmount(_C(ex.GetPosition), ct)
// calculate the position changes
var longPosDelta = nowRefPosAmount.long - initRefPosAmount.long
var shortPosDelta = nowRefPosAmount.short - initRefPosAmount.short
// detect changes
if (!(longPosDelta == 0 && shortPosDelta == 0)) {
// Perform long positions
if (longPosDelta != 0) {
Log(ex.GetName(), ex.GetLabel(), symbol, ct, "Perform long position-following, changes in volume:", longPosDelta)
follow(nowRefPosAmount, symbol, ct, PD_LONG, longPosDelta)
}
// Perform short positions
if (shortPosDelta != 0) {
Log(ex.GetName(), ex.GetLabel(), symbol, ct, "Perform short position-following, changes in volume:", shortPosDelta)
follow(nowRefPosAmount, symbol, ct, PD_SHORT, shortPosDelta)
}
// Update after performing the order-following operation
mapInitRefPosAmount[keyInitRefPosAmount] = nowRefPosAmount
}
// restore symbol ct
ex.SetCurrency(buffSymbol)
ex.SetContractType(buffCt)
} else if (exType == "spot") {
// Spots
}
}
$.getTbl = function() {
var tbl = {
"type" : "table",
"title" : "synchronization of data",
"cols" : [],
"rows" : []
}
// construct the table headers
tbl.cols.push("monitor the account: refPos-exIndex-symbol-contractType")
tbl.cols.push(`monitor the position: {"timestamp":xxx,"long positions":xxx,"short positions":xxx}`)
_.each(fmzExtendApis, function(extendApiData, index) {
tbl.cols.push(keyName_robotId + "-" + index)
})
// Write data in
_.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
}
// Example of the strategy call that references the template class library
function main() {
// Clear all logs
LogReset(1)
// Switch to OKEX demo to test
exchanges[0].IO("simulate", true)
// Set the contract
exchanges[0].SetCurrency("ETH_USDT")
exchanges[0].SetContractType("swap")
// Timed trading interval
var tradeInterval = 1000 * 60 * 3 // Trade for every three minutes to observe the order-following signals
var lastTradeTS = new Date().getTime()
while (true) {
// Other logic of the strategy...
// Simulated trading triggers for testing
var ts = new Date().getTime()
if (ts - lastTradeTS > tradeInterval) {
Log("Trade the simulation order-leading strategies, position changes", "#FF0000")
exchanges[0].SetDirection("buy")
exchanges[0].Buy(-1, 1)
lastTradeTS = ts
}
// Interface functions that use templates
$.PosMonitor(0, "ETH_USDT", "swap") // Multiple monitors can be set up to monitor different exchange objects on the order-following strategy
var tbl = $.getTbl()
// Display status bar
LogStatus(_D(), "\n" + "`" + JSON.stringify(tbl) + "`")
Sleep(1000)
}
}
The design is very simple, the class library has 2 functional functions. When a programmatic trading strategy on the FMZ platform references the template class library of Order Synchronization Management System Class Library (Single Server)
. Then the strategy can use the following functions.
$.PosMonitor The purpose of this function is to monitor the position changes of the exchange objects in the strategy and then send trading signals to the real bot market set in the parameters of the template: Order Synchronization Management System class library (Single Server).
$.getTbl Return to the monitored synchronization data.
Example of use is in the main
function of the Order Synchronization Management System Class Library (Single Server) template:
// Example of the strategy call that references the template class library
function main() {
// Clear all logs
LogReset(1)
// Switch to OKEX demo to test
exchanges[0].IO("simulate", true)
// Set the contract
exchanges[0].SetCurrency("ETH_USDT")
exchanges[0].SetContractType("swap")
// Timed trading interval
var tradeInterval = 1000 * 60 * 3 // Trade for every three minutes to observe the order-following signals
var lastTradeTS = new Date().getTime()
while (true) {
// Other logic of the strategy...
// Simulated trading triggers for testing
var ts = new Date().getTime()
if (ts - lastTradeTS > tradeInterval) {
Log("Trade the simulation order-leading strategies, position changes", "#FF0000")
exchanges[0].SetDirection("buy")
exchanges[0].Buy(-1, 1)
lastTradeTS = ts
}
// Interface functions by using templates
$.PosMonitor(0, "ETH_USDT", "swap") // Multiple monitors can be set up to monitor different exchange objects on the order-following strategy
var tbl = $.getTbl()
// Display status bar
LogStatus(_D(), "\n" + "`" + JSON.stringify(tbl) + "`")
Sleep(1000)
}
}
A template class library can also create a strategy real bot by itself, which is usually used to test the template class library, such as the testing of the template. You can deem that the main
function in a template is the main
function of one of your own strategies.
The test code is written as using the OKEX demo to test, you need to configure the OKEX demo API KEY on FMZ as a reference account (order-leading), and it starts switching to demo in the main function. Then set the trading pair to ETH_USDT and set the contract to swap. Then it enters a while loop. In the loop, an order is placed every 3 minutes to simulate the triggering of strategy transactions. $.PosMonitor(0, "ETH_USDT", "swap")
is called in the while loop, the first parameter of this function is passed to 0, which means to monitor thes exchange object exchanges[0], monitor ETH_USDT trading pair, swap contract. Then it will call $.getTbl()
to get chart information, using LogStatus(_D(), "\n" + "`" + JSON.stringify(tbl) + "`")
to make the chart data displayed on the status bar.
So we can see that we can make the strategy have the ability to monitor the positions of a certain species, and the position changes to send messages by using $.PosMonitor(0, "ETH_USDT", "swap")
in a strategy that references the template.
Before testing, we will explain the strategy parameters design of the Order Synchronization Management System Class Library (Single Server)
.
We have just talked about how to use the interface function of a template to upgrade a strategy to have a function of order-leading. What about the signal sent when the position changes, to whom will it sent?
The question of whom to send is configured by the parameters of the Order Synchronization Management System Class Library (Single Server)
.
We can see that there are 5 parameters, supporting up to 5 pushes (it can be extended by themselves if it need increase), the default parameters are empty strings, that is, not processed. Configuration string format: label,robotId,accessKey,secretKey
label A label for a sync account, it is used to set a label for an account with a name that can be set at will.
robotId
Robot ID, the ID of the Order Synchronous Server
real bot created by the owner of the synchronous account.
accessKey Extended API accessKey of FMZ
secretKey Extended API secretKey of FMZ
The temporary code of Order Synchronization Management System (Synchronous Server):
function main() {
LogReset(1)
while (true) {
var cmd = GetCommand()
if (cmd) {
// cmd: ETH_USDT,swap,buy,1
Log("cmd: ", cmd)
}
Sleep(1000)
}
}
We can see that the real bot of synchronized account owner received the message: ETH_USDT,swap,buy,1
.
Then it will allow us to make our own automatic order-following in the next step based on the tradiing pairs, contract codes, trade directions, and amount in the information.
So far, the Order Synchronization Management System (Synchronous Server)
is the temporary code, we will continue to explore its design in the next issue.