
Avec une mise à jour majeure de l’interface API de la plateforme de trading quantitative, les paramètres de l’interface de stratégie de la plateforme, les contrôles interactifs et d’autres fonctions ont été ajustés, et de nombreuses nouvelles fonctions ont été ajoutées. L’article précédent a présenté en détail les mises à jour des paramètres d’interface et des contrôles interactifs. Cet article continue d’explorer l’application du nouveau bouton de barre d’état introduit de FMZ.COM.
Chaque développeur de stratégie souhaite créer une interface utilisateur facile à utiliser, puissante et simple dans sa conception. Afin d’atteindre cette norme, FMZ.COM ne ménage aucun effort pour mettre à niveau les fonctions de la plateforme et améliorer l’expérience utilisateur. La conception de contrôles interactifs directement dans la barre d’état de la page de stratégie est une mise à niveau basée sur cette demande.
Ensuite, examinons son application dans un scénario de stratégie multivariée.
Qu’il s’agisse d’une stratégie d’arbitrage multivarié entièrement automatique ou d’une stratégie de synchronisation multivarié semi-manuelle. L’interface utilisateur de la stratégie devra disposer de boutons interactifs fonctionnels, tels que take profit, stop loss, liquidation, confiage planifié, etc. pour un certain produit.
Explorons ensuite les nouvelles fonctionnalités du bouton de la barre d’état avec un scénario d’utilisation le plus simple. Supposons que notre stratégie négocie plusieurs symboles :
Contrat perpétuel BTC_USDT, Contrat perpétuel ETH_USDT, Contrat perpétuel LTC_USDT, Contrat perpétuel BNB_USDT, Contrat perpétuel SOL_USDT
Pendant que la stratégie exécute le trading automatique, nous espérons concevoir un bouton d’ouverture pour chaque produit dans la barre d’état de l’interface de stratégie. Mais ce bouton de position ouverte nécessite une série de paramètres détaillés, tels que :
Avant cette mise à niveau de la plateforme, le bouton de la barre d’état déclenchait simplement un message d’interaction avec le bouton. Il n’existe aucun moyen de lier une série de contrôles pour configurer des messages complexes. Cette mise à niveau de l’interaction résout ce besoin. Jetons un œil à la conception du code. Des commentaires détaillés sont ajoutés au code pour faciliter la compréhension de la création d’une telle fonction.
Exemples de conception :
// 设置操作的各个品种 BTC_USDT.swap 为FMZ平台定义的品种格式,表示BTC的U本位永续合约
var symbols = ["BTC_USDT.swap", "ETH_USDT.swap", "LTC_USDT.swap", "BNB_USDT.swap", "SOL_USDT.swap"]
// 根据按钮模板构造按钮
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": "开仓下单",
"group": [{
"type": "selected",
"name": "tradeType",
"label": "下单类型",
"description": "市价单、限价单",
"default": 0,
"group": "交易设置",
"settings": {
"options": ["市价单", "限价单"],
"required": true,
}
}, {
"type": "selected",
"name": "direction",
"label": "交易方向",
"description": "买入、卖出",
"default": "buy",
"group": "交易设置",
"settings": {
"render": "segment",
"required": true,
"options": [{"name": "买入", "value": "buy"}, {"name": "卖出", "value": "sell"}],
}
}, {
"type": "number",
"name": "price",
"label": "价格",
"description": "订单的价格",
"group": "交易设置",
"filter": "tradeType==1",
"settings": {
"required": true,
}
}, {
"type": "number",
"name": "amount",
"label": "下单量",
"description": "订单的下单量",
"group": "交易设置",
"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": "交易品种", "default": m["symbol"], "settings": {"required": true}}])
tbl["rows"].push([m["symbol"], btnOpen])
})
var cmd = GetCommand()
if (cmd) {
Log("收到交互:", cmd)
// 解析交互消息: open:{"symbol":"LTC_USDT.swap","tradeType":0,"direction":"buy","amount":111}
// 根据第一个冒号:之前的指令判断是哪种按钮模板触发的消息
var arrCmd = cmd.split(":", 2)
if (arrCmd[0] == "open") {
var msg = JSON.parse(cmd.slice(5))
Log("交易品种:", msg["symbol"], ",交易方向:", msg["direction"], ",订单类型:", msg["tradeType"] == 0 ? "市价单" : "限价单", msg["tradeType"] == 0 ? ",订单价格:当前市价" : ",订单价格:" + msg["price"], ",订单数量:", msg["amount"])
}
}
// 输出状态栏信息
LogStatus(_D(), "\n", "`" + JSON.stringify(tbl) + "`")
Sleep(1000)
}
}
Jetons d’abord un œil à l’effet de course, puis expliquons en détail la conception du contrôle des boutons. Le code de stratégie s’exécute comme indiqué ci-dessous :

Cliquez sur un bouton et une fenêtre contextuelle apparaîtra pour configurer les informations de commande spécifiques :

Après avoir rempli les informations d’ouverture, nous avons conçu.

Vous pouvez voir que la stratégie a reçu le message, et dans le code, nous avons analysé le message et généré les différents paramètres de la commande. Ensuite, regardons comment ce bouton est construit :
Tout d’abord, nous définissons un modèle de bouton, qui est un objet JSON, et l’affectons à la variable tmpBtnOpen. J’ai inclus les instructions spécifiques directement dans les commentaires de code ci-dessous.
{
"type": "button", // 状态栏输出控件的类型,目前仅支持按钮
"cmd": "open", // 当按钮触发时,策略中GetCommand函数收到的消息前缀,例如这个例子:open:{"symbol":"LTC_USDT.swap","tradeType":0,"direction":"buy","amount":111}
"name": "开仓下单", // 策略界面,状态栏上的按钮上显示的内容,参考上图
"group": [{ // 当按钮触发时,弹框中的控件配置设置,这一层的group字段值是一个数组,弹框中的控件根据这个数组顺序自上而下排列
"type": "selected", // 第一个控件类型是:selected ,下拉框
"name": "tradeType", // 当状态栏按钮触发时,消息中包含该控件的设置内容,tradeType就是当前这个下拉框控件输入的值的键名。如果选择第一个选项「市价单」GetCommand函数收到的消息中就包含 "tradeType":0 的键值对信息。
"label": "下单类型", // 按钮触发时,弹框中当前控件的标题
"description": "市价单、限价单", // 当前控件的说明信息,鼠标放在控件右侧“小问号”图标上就会显示这个说明信息。
"default": 0, // 当前控件的默认值,例如当前是下拉框控件,如果不做选择,默认为下拉框第一个选项,通常下拉框的默认值指的是下拉框选项的索引,即第一个是0,然后是1,以此类推。如果下拉框的选项options是key-value形式则默认值指的是value。
"group": "交易设置", // 弹框中的控件如果很多,可以分组,这个字段可以设置分组信息
"settings": { // 当前这个下拉框的具体设置
"options": ["市价单", "限价单"], // options和下拉框相关的设置,用于设置下拉框中的选项,这个字段值是一个数组,依次排列下拉框中的选项。
"required": true, // required表示是否设置为必选(必填)内容。
}
}, {
"type": "selected", // 这也是一个下拉框类型
"name": "direction",
"label": "交易方向",
"description": "买入、卖出",
"default": "buy",
"group": "交易设置",
"settings": {
"render": "segment", // 和默认下拉框控件不同的是,通过render字段可以把下拉框替换为“分段选择器”,如上图中的“买入/卖出”控件。
"required": true,
"options": [{"name": "买入", "value": "buy"}, {"name": "卖出", "value": "sell"}], // 使用 key-value方式设置options
}
}, {
"type": "number", // 数值输入框类型控件
"name": "price",
"label": "价格",
"description": "订单的价格",
"group": "交易设置",
"filter": "tradeType==1", // 过滤器,可以用于确定是否显示当前控件,当tradeType==1时,表示是市价单,所以不需要该控件设置价格,所以不显示。
"settings": {
"required": true, // 当该控件激活显示时为必选(必填)
}
}, {
"type": "number",
"name": "amount",
"label": "下单量",
"description": "订单的下单量",
"group": "交易设置",
"settings": {
"required": true,
}
}],
}
group
Comme il ne s’agit que d’un exemple, il peut y avoir davantage d’exigences en termes de conception et d’utilisation réelles, qui ne se limitent pas à la direction de l’ordre, au prix, à la quantité et au type d’ordre définis lors de l’ouverture d’une position. Il peut également y avoir des règles de sortie conçues, telles que des ordres de take-profit et de stop-loss. La nouvelle version de l’interface utilisateur prend donc en chargegroupChamp qui permet de regrouper facilement un groupe de contrôles dans la boîte contextuelle pour l’affichage, comme le paramètre réduit « Paramètres de transaction » dans la capture d’écran ci-dessus.
required
Structure des boutonsgroupLes contrôles mis en place sur le terrain ont été renforcésrequiredLe champ de paramétrage permet de définir s’il est obligatoire (obligatoire). S’il est défini comme obligatoire (obligatoire) mais n’est pas renseigné (sélectionné) lors de l’utilisation, vous ne pouvez pas cliquer sur le bouton OK pour envoyer les informations interactives, et un message rouge un message d’invite s’affiche.
filter
AjoutéfilterLe champ est utilisé pour définir les dépendances de filtre. Par exemple, dans l’exemple ci-dessus, si le type d’ordre au marché est sélectionné, le prix de l’ordre n’est pas nécessaire.typeest “numéro”,nameLes commandes pour le « prix » sont masquées.
render
Pour ces types de contrôles de base (paramètres de champ de type) : nombre, chaîne, sélectionné, booléen. Champs ajoutésrenderUtilisé pour définir le rendu du contrôle. Chaque contrôle possède ses propres composants de rendu multiples. Par exemple, dans l’exemple ci-dessus, il est plus approprié de rendre le contrôle de liste déroulante sélectionné comme un « sélecteur de segment », car la liste déroulante doit être cliquée deux fois (la première fois pour développer la liste déroulante). , et la deuxième fois pour sélectionner une option). Utilisez le composant de sélection de segment, cliquez simplement et sélectionnez l’option souhaitée.
Enfin, les lecteurs attentifs peuvent se demander, dans la capture d’écran ci-dessus, je ne vois pas les informations de contrôle dans la boîte contextuelle où vous avez écrit « Type de trading », et ce « Type de trading » n’appartient pas au groupe « Paramètres de trading » (c’est-à-dire:
"group": "交易设置"Ce paramètre implémente).
Voici une démonstration d’une conception qui lie les boutons du tableau de la barre d’état à d’autres informations de la barre d’état.createBtnFonction basée sur un modèletmpBtnOpenConstruisez la structure finale du bouton et écrivez d’autres informations dans la structure du bouton pendant la construction.
// 构造按钮的时候,绑定当前行的品种名称等信息,给按钮的弹框增加一个控件,并排在首位
var btnOpen = createBtn(tmpBtnOpen, [{"type": "string", "name": "symbol", "label": "交易品种", "default": m["symbol"], "settings": {"required": true}}])
Donc l’effet final est que lorsque vous cliquez sur la barre d’état de l’interface de stratégiesymbolpourBNB_USDT.swapLorsque vous cliquez sur le bouton de cette ligne, la zone de saisie « Type de trading » dans la fenêtre contextuelle sera automatiquement remplie.BNB_USDT.swap。
Cet article ne présente qu’une petite partie de l’application de la nouvelle version de l’interface utilisateur. Comme la longueur globale ne peut pas être trop longue, nous continuerons à discuter de la conception d’autres scénarios de demande dans le prochain article.
Merci pour votre soutien !