With a major update of the FMZ Quant Trading Platform API interface, the platform’s strategy interface parameters, interactive controls and other functions have been adjusted, and many new functions have been added. The previous article introduced the updated content of interface parameters and interactive controls in detail. This article continues to explore the application of the newly introduced status bar button of FMZ.COM.
Every strategy developer hopes to build a UI interface that is easy to use, powerful and simple in design. In order to achieve this standard, FMZ.COM spares no effort to upgrade platform functions and improve user experience. Designing interactive controls directly in the status bar of the strategy page is an upgrade based on this demand.
Next, let’s look at its application in a multi-variety strategy scenario.
Whether it is a fully automatic multi-variety arbitrage strategy or a semi-manual multi-variety timing strategy, there will be some functional interactive buttons on the strategy UI interface, such as take profit, stop loss, full liquidation, planned entrustment, etc. for a certain product.
Then let’s explore the new features of the status bar button with a simplest usage scenario. Suppose our strategy trades multiple varieties:
BTC_USDT Perpetual Contract, ETH_USDT Perpetual Contract, LTC_USDT Perpetual Contract, BNB_USDT Perpetual Contract, SOL_USDT Perpetual Contract
While the strategy is executing automatic trading, we hope to design an open position button for each product in the status bar of the strategy interface. However, this open position button requires a series of detailed settings, such as:
Before this upgrade, the status bar button only triggered a button interaction message. There was no way to bind a series of controls to set complex messages. This upgrade to interaction solves the problem. Let’s take a look at the code design. The detailed comments added to the code make it easy to understand how to build such a function.
Design examples:
// Set the types of operations BTC_USDT.swap is the type format defined by the FMZ platform, indicating the U-standard perpetual contract of BTC
var symbols = ["BTC_USDT.swap", "ETH_USDT.swap", "LTC_USDT.swap", "BNB_USDT.swap", "SOL_USDT.swap"]
// Construct a button based on a button template
function createBtn(tmp, group) {
var btn = JSON.parse(JSON.stringify(tmp))
_.each(group, function(eleByGroup) {
btn["group"].unshift(eleByGroup)
})
return btn
}
function main() {
LogReset(1)
var arrManager = []
_.each(symbols, function(symbol) {
arrManager.push({
"symbol": symbol,
})
})
// Btn
var tmpBtnOpen = {
"type": "button",
"cmd": "open",
"name": "Open a position and place an order",
"group": [{
"type": "selected",
"name": "tradeType",
"label": "OrderType",
"description": "Market order, limit order",
"default": 0,
"group": "Trading setup",
"settings": {
"options": ["Market order", "Limit order"],
"required": true,
}
}, {
"type": "selected",
"name": "direction",
"label": "Trading direction",
"description": "Buy, sell",
"default": "buy",
"group": "Trading setup",
"settings": {
"render": "segment",
"required": true,
"options": [{"name": "buy", "value": "buy"}, {"name": "sell", "value": "sell"}],
}
}, {
"type": "number",
"name": "price",
"label": "price",
"description": "The price of the order",
"group": "Trading setup",
"filter": "tradeType==1",
"settings": {
"required": true,
}
}, {
"type": "number",
"name": "amount",
"label": "Order quantity",
"description": "Order quantity",
"group": "Trading setup",
"settings": {
"required": true,
}
}],
}
while (true) {
var tbl = {"type": "table", "title": "dashboard", "cols": ["symbol", "actionOpen"], "rows": []}
_.each(arrManager, function(m) {
var btnOpen = createBtn(tmpBtnOpen, [{"type": "string", "name": "symbol", "label": "trading instruments", "default": m["symbol"], "settings": {"required": true}}])
tbl["rows"].push([m["symbol"], btnOpen])
})
var cmd = GetCommand()
if (cmd) {
Log("Receive interaction:", cmd)
// Parsing interaction messages: open:{"symbol":"LTC_USDT.swap","tradeType":0,"direction":"buy","amount":111}
// According to the first colon: the previous instruction determines which button template triggers the message
var arrCmd = cmd.split(":", 2)
if (arrCmd[0] == "open") {
var msg = JSON.parse(cmd.slice(5))
Log("Trading instruments:", msg["symbol"], ", Trading direction:", msg["direction"], ", Order type:", msg["tradeType"] == 0 ? "Market order" : "Limit order", msg["tradeType"] == 0 ? ", Order price: current market price" : ", Order price:" + msg["price"], ", Quantity of order:", msg["amount"])
}
}
// Output status bar information
LogStatus(_D(), "\n", "`" + JSON.stringify(tbl) + "`")
Sleep(1000)
}
}
Let’s take a look at the running effect first, and then explain the design of the button control in detail. The strategy code runs as shown in the figure:
Click a button and a pop-up window will appear to configure the specific order information:
After filling in the opening position information we designed, we can see that the strategy received the message in the Logs column, and in the code we parsed the message and output the various settings of the order. Next, let’s take a look at how this button is constructed:
First, we define a button template, which is a JSON object, and assign it to the variable tmpBtnOpen. I write the specific instructions directly in the code comments below.
{
"type": "button", // The type of status bar output control. Currently only buttons are supported.
"cmd": "open", // The message prefix received by the GetCommand function in the strategy when the button is triggered, such as this example: open:{"symbol":"LTC_USDT.swap","tradeType":0,"direction":"buy","amount":111}
"name": "Open a position and place an order", // Strategy interface, the content displayed on the button on the status bar, refer to the above picture
"group": [{ // When the button is triggered, the controls in the pop-up box are configured and set. The group field value of this layer is an array, and the controls in the pop-up box are arranged from top to bottom according to the order of this array.
"type": "selected", // The first control type is: selected, drop-down box
"name": "tradeType", // When the status bar button is triggered, the message contains the settings of the control, and tradeType is the key name of the value currently entered in the drop-down box control. If the first option "Market Order" is selected, the message received by the GetCommand function contains the key-value pair information of "tradeType":0.
"label": "orderType", // When the button is triggered, the title of the current control in the pop-up box
"description": "Market order, limit order", // The description information of the current control will be displayed when the mouse is placed on the "small question mark" icon on the right side of the control.
"default": 0, // The default value of the current control. For example, if the current control is a drop-down box, if no selection is made, the default value is the first option in the drop-down box. Usually, the default value of a drop-down box refers to the index of the drop-down box option, that is, the first one is 0, then 1, and so on. If the options of the drop-down box are in key-value format, the default value refers to value.
"group": "Trading setup", // If there are many controls in the pop-up box, they can be grouped. This field can set the grouping information.
"settings": { // The specific settings of this drop-down box
"options": ["Market order", "Limit order"], // Options is a setting related to the drop-down box. It is used to set the options in the drop-down box. The value of this field is an array, which arranges the options in the drop-down box in sequence.
"required": true, // Required indicates whether it is set as mandatory (required) content.
}
}, {
"type": "selected", // This is also a Selected type
"name": "direction",
"label": "Trading direction",
"description": "Buy, sell",
"default": "buy",
"group": "Trading setup",
"settings": {
"render": "segment", // Unlike the default drop-down box control, the drop-down box can be replaced with a "segment selector" through the render field, such as the "buy/sell" control in the figure above.
"required": true,
"options": [{"name": "buy", "value": "buy"}, {"name": "sell", "value": "sell"}], // Use key-value to set options
}
}, {
"type": "number", // Numeric input box type control
"name": "price",
"label": "price",
"description": "The price of the order",
"group": "Trading setup",
"filter": "tradeType==1", // The filter can be used to determine whether to display the current control. When tradeType==1, it means it is a market order, so there is no need to set the price for this control, so it is not displayed.
"settings": {
"required": true, // Required when the control is activated (required)
}
}, {
"type": "number",
"name": "amount",
"label": "Order quantity",
"description": "Order quantity",
"group": "Trading setup",
"settings": {
"required": true,
}
}],
}
group Because this is just an example, there may be more requirements in actual design and use, not limited to the order direction, price, quantity, and order type set when opening a position. There may also be the design of exit rules such as take-profit and stop-loss plan orders. Therefore, the new version of the UI supports the group field, which is convenient for grouping a group of controls in the pop-up box together for display, such as the folding setting of “Trading Settings” in the above screenshot.
required The control set in the group field in the button structure adds the required setting field to set whether it is required. If it is set to required but is not filled in (selected) during use, you cannot click the OK button to send the interactive information, and a red prompt message is displayed.
filter The filter field is added to set the filter dependency. For example, in the above example, if the market order type is selected, the order price is not necessary. You can hide the control with type “number” and name “price”.
render For these basic types of controls (type field settings): number, string, selected, boolean. Added field render to set control rendering, each control has its own multiple rendering components. For example, in the above example, it is more appropriate to render the selected drop-down box control as a “segment selector”, because the drop-down box needs to be clicked twice (the first time to expand the drop-down box, the second time to select an option). Using the segment selector component, you only need to click once to select the required option.
Finally, careful readers may ask, I don’t see the control information in the pop-up box where you wrote “Trading symbol” in the screenshot above, and this “Trading symbol” does not belong to the “Trading setup” group (that is:
"group": "Trading setup"
this setting is implemented).
Here is a demonstration of a design that binds the buttons in the status bar table to other information in the status bar. The createBtn
function is used to construct the final button structure according to the template tmpBtnOpen
, and other information is written into the button structure during construction.
// When constructing a button, bind the name of the current row and other information, add a control to the button's pop-up box, and place it first
var btnOpen = createBtn(tmpBtnOpen, [{"type": "string", "name": "symbol", "label": "Trading symbols", "default": m["symbol"], "settings": {"required": true}}])
So the final effect is that when you click the button with the line symbol
of BNB_USDT.swap
in the status bar of the strategy interface, the “Trading symbol” input box in the pop-up box will be filled with BNB_USDT.swap
automatically.
This article only introduces a small part of the application of the new version of UI. In view of the fact that the overall length, we will continue to discuss the design of other demand scenarios in the next article.
Thank you for your support!