In previous articles in FMZ's library, we have designed several kinds of synchronization strategies for order and position.
- Realize a Simple Order Supervising Bot of Cryptocurrency Spot
- Cryptocurrency Contract Simple Order-Supervising Bot
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.
Design Ideas
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.
- 1. Users of synchronization strategies real bot must have the exchange API KEY of the reference account, and the exchange API KEY of the synchronization account.
This issue is fine for the usage situation where one's other exchange accounts follow his or her own account. However, it can be troublesome for the situation where the reference account and the sync account are not the same owner. Sometimes the owner of the synchronized account does not want to provide the API KEY of his own exchange account for security reasons, but how to synchronize the order transactions without providing the API KEY? 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 (theOrder 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. - 2. Many developers have good strategies, but they cannot use the 2 past order and position synchronization strategies described above. Because they need to integrate their own strategies with these synchronized strategies, and the strategies may need to be changed drastically, which will cost a lot of work and effort. Is there a good way to upgrade some of your mature strategies directly to the order synchronization function?
Solutions:
You can design an order synchronization template class library (theOrder 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. - 3. Reduce an additional real bot.
The last shortcoming is that if you use the 2 past orders, positions synchronization strategy described above. It is necessary to open an additional real bot to monitor the positions of reference account (account for order leaders).
Solutions:
Use the template class library to embed functionality in the reference account strategy.
So the system consists of 2 parts:
- Order synchronization management system class library (Single Server)
- Order synchronization management system (Synchronous Server)
Once we've defined our needs, let's start designing!
Design 1: Order synchronization management system class library (Single Server)
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 theOrder 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.