在回测系统或实盘页面状态栏输出信息。
LogStatus(…msgs)
参数msg为输出的内容,参数msg可以传入多个。
msg
false
string / number / bool / object / array / any (平台支持的任意类型)
function main() {
LogStatus('This is a normal status message')
LogStatus('This is a red font status message#ff0000')
LogStatus('This is a multi-line status message\nI am the second line')
}```
```python
def main():
LogStatus('This is a normal status message')
LogStatus('This is a red font status message#ff0000')
LogStatus('This is a multi-line status message\nI am the second line')```
```cpp
void main() {
LogStatus("This is a normal status message");
LogStatus("This is a red font status message#ff0000");
LogStatus("This is a multi-line status message\nI am the second line");
}```
支持设置输出内容的颜色:
```javascript
function main() {
var table = {type: 'table', title: 'Position Info', cols: ['Column 1', 'Column 2'], rows: [ ['abc', 'def'], ['ABC', 'support color #ff0000']]}
// JSON序列化后两边加上`字符,视为复杂消息格式(当前支持表格)
LogStatus('`' + JSON.stringify(table) + '`')
// 表格信息也可以在多行中显示
LogStatus('First line message\n`' + JSON.stringify(table) + '`\nThird line message')
// 支持同时显示多个表格,将以TAB形式显示在一组中
LogStatus('`' + JSON.stringify([table, table]) + '`')
// 也可以在表格中构造按钮,策略通过GetCommand接收cmd属性的内容
var table = {
type: 'table',
title: 'Position Operation',
cols: ['Column 1', 'Column 2', 'Action'],
rows: [
['abc', 'def', {'type':'button', 'cmd': 'coverAll', 'name': 'Close All'}]
]
}
LogStatus('`' + JSON.stringify(table) + '`')
// 或者构造一个独立的按钮
LogStatus('`' + JSON.stringify({'type':'button', 'cmd': 'coverAll', 'name': 'Close All'}) + '`')
// 可以自定义按钮样式(Bootstrap的按钮属性)
LogStatus('`' + JSON.stringify({'type':'button', 'class': 'btn btn-xs btn-danger', 'cmd': 'coverAll', 'name': 'Close All'}) + '`')
}```
```python
import json
def main():
table = {"type": "table", "title": "Position Info", "cols": ["Column 1", "Column 2"], "rows": [["abc", "def"], ["ABC", "support color #ff0000"]]}
LogStatus('`' + json.dumps(table) + '`')
LogStatus('First line message\n`' + json.dumps(table) + '`\nThird line message')
LogStatus('`' + json.dumps([table, table]) + '`')
table = {
"type" : "table",
"title" : "Position Operation",
"cols" : ["Column 1", "Column 2", "Action"],
"rows" : [
["abc", "def", {"type": "button", "cmd": "coverAll", "name": "Close All"}]
]
}
LogStatus('`' + json.dumps(table) + '`')
LogStatus('`' + json.dumps({"type": "button", "cmd": "coverAll", "name": "Close All"}) + '`')
LogStatus('`' + json.dumps({"type": "button", "class": "btn btn-xs btn-danger", "cmd": "coverAll", "name": "Close All"}) + '`')```
```cpp
void main() {
json table = R"({"type": "table", "title": "Position Info", "cols": ["Column 1", "Column 2"], "rows": [["abc", "def"], ["ABC", "support color #ff0000"]]})"_json;
LogStatus("`" + table.dump() + "`");
LogStatus("First line message\n`" + table.dump() + "`\nThird line message");
json arr = R"([])"_json;
arr.push_back(table);
arr.push_back(table);
LogStatus("`" + arr.dump() + "`");
table = R"({
"type" : "table",
"title" : "Position Operation",
"cols" : ["Column 1", "Column 2", "Action"],
"rows" : [
["abc", "def", {"type": "button", "cmd": "coverAll", "name": "Close All"}]
]
})"_json;
LogStatus("`" + table.dump() + "`");
LogStatus("`" + R"({"type": "button", "cmd": "coverAll", "name": "Close All"})"_json.dump() + "`");
LogStatus("`" + R"({"type": "button", "class": "btn btn-xs btn-danger", "cmd": "coverAll", "name": "Close All"})"_json.dump() + "`");
}```
状态栏数据输出示例:
```javascript
function main() {
var table = {
type: "table",
title: "Status Bar Button Styles",
cols: ["Default", "Primary", "Success", "Info", "Warning", "Danger"],
rows: [
[
{"type":"button", "class": "btn btn-xs btn-default", "name": "Default"},
{"type":"button", "class": "btn btn-xs btn-primary", "name": "Primary"},
{"type":"button", "class": "btn btn-xs btn-success", "name": "Success"},
{"type":"button", "class": "btn btn-xs btn-info", "name": "Info"},
{"type":"button", "class": "btn btn-xs btn-warning", "name": "Warning"},
{"type":"button", "class": "btn btn-xs btn-danger", "name": "Danger"}
]
]
}
LogStatus("`" + JSON.stringify(table) + "`")
}```
```python
import json
def main():
table = {
"type": "table",
"title": "Status Bar Button Styles",
"cols": ["Default", "Primary", "Success", "Info", "Warning", "Danger"],
"rows": [
[
{"type":"button", "class": "btn btn-xs btn-default", "name": "Default"},
{"type":"button", "class": "btn btn-xs btn-primary", "name": "Primary"},
{"type":"button", "class": "btn btn-xs btn-success", "name": "Success"},
{"type":"button", "class": "btn btn-xs btn-info", "name": "Info"},
{"type":"button", "class": "btn btn-xs btn-warning", "name": "Warning"},
{"type":"button", "class": "btn btn-xs btn-danger", "name": "Danger"}
]
]
}
LogStatus("`" + json.dumps(table) + "`")```
```cpp
void main() {
json table = R"({
"type": "table",
"title": "Status Bar Button Styles",
"cols": ["Default", "Primary", "Success", "Info", "Warning", "Danger"],
"rows": [
[
{"type":"button", "class": "btn btn-xs btn-default", "name": "Default"},
{"type":"button", "class": "btn btn-xs btn-primary", "name": "Primary"},
{"type":"button", "class": "btn btn-xs btn-success", "name": "Success"},
{"type":"button", "class": "btn btn-xs btn-info", "name": "Info"},
{"type":"button", "class": "btn btn-xs btn-warning", "name": "Warning"},
{"type":"button", "class": "btn btn-xs btn-danger", "name": "Danger"}
]
]
})"_json;
LogStatus("`" + table.dump() + "`");
}```
支持在状态栏中设计按钮控件(旧版按钮结构):
```javascript
function main() {
var table = {
type: "table",
title: "Status Bar Button Disable and Description Test",
cols: ["Column 1", "Column 2", "Column 3"],
rows: []
}
var button1 = {"type": "button", "name": "Button 1", "cmd": "button1", "description": "This is the first button"}
var button2 = {"type": "button", "name": "Button 2", "cmd": "button2", "description": "This is the second button, set to disabled", "disabled": true}
var button3 = {"type": "button", "name": "Button 3", "cmd": "button3", "description": "This is the third button, set to enabled", "disabled": false}
table.rows.push([button1, button2, button3])
LogStatus("`" + JSON.stringify(table) + "`")
}```
```python
import json
def main():
table = {
"type": "table",
"title": "Status Bar Button Disable and Description Test",
"cols": ["Column 1", "Column 2", "Column 3"],
"rows": []
}
button1 = {"type": "button", "name": "Button 1", "cmd": "button1", "description": "This is the first button"}
button2 = {"type": "button", "name": "Button 2", "cmd": "button2", "description": "This is the second button, set to disabled", "disabled": True}
button3 = {"type": "button", "name": "Button 3", "cmd": "button3", "description": "This is the third button, set to enabled", "disabled": False}
table["rows"].append([button1, button2, button3])
LogStatus("`" + json.dumps(table) + "`")```
```cpp
void main() {
json table = R"({
"type": "table",
"title": "Status Bar Button Disable and Description Test",
"cols": ["Column 1", "Column 2", "Column 3"],
"rows": []
})"_json;
json button1 = R"({"type": "button", "name": "Button 1", "cmd": "button1", "description": "This is the first button"})"_json;
json button2 = R"({"type": "button", "name": "Button 2", "cmd": "button2", "description": "This is the second button, set to disabled", "disabled": true})"_json;
json button3 = R"({"type": "button", "name": "Button 3", "cmd": "button3", "description": "This is the third button, set to enabled", "disabled": false})"_json;
json arr = R"([])"_json;
arr.push_back(button1);
arr.push_back(button2);
arr.push_back(button3);
table["rows"].push_back(arr);
LogStatus("`" + table.dump() + "`");
}```
设置状态栏按钮的禁用和描述功能(旧版按钮结构):
```javascript
function test1() {
Log("Calling custom function")
}
function main() {
while (true) {
var table = {
type: 'table',
title: 'Operation',
cols: ['Column 1', 'Column 2', 'Action'],
rows: [
['a', '1', {
'type': 'button',
'cmd': "CoverAll",
'name': 'Close All'
}],
['b', '1', {
'type': 'button',
'cmd': 10,
'name': 'Send Number'
}],
['c', '1', {
'type': 'button',
'cmd': _D(),
'name': 'Call Function'
}],
['d', '1', {
'type': 'button',
'cmd': 'test1',
'name': 'Call Custom Function'
}]
]
}
LogStatus(_D(), "\n", '`' + JSON.stringify(table) + '`')
var str_cmd = GetCommand()
if (str_cmd) {
Log("Received interaction data str_cmd:", "Type:", typeof(str_cmd), "Value:", str_cmd)
if(str_cmd == "test1") {
test1()
}
}
Sleep(500)
}
}```
```python
import json
def test1():
Log("Calling custom function")
def main():
while True:
table = {
"type": "table",
"title": "Operation",
"cols": ["Column 1", "Column 2", "Action"],
"rows": [
["a", "1", {
"type": "button",
"cmd": "CoverAll",
"name": "Close All"
}],
["b", "1", {
"type": "button",
"cmd": 10,
"name": "Send Number"
}],
["c", "1", {
"type": "button",
"cmd": _D(),
"name": "Call Function"
}],
["d", "1", {
"type": "button",
"cmd": "test1",
"name": "Call Custom Function"
}]
]
}
LogStatus(_D(), "\n", "`" + json.dumps(table) + "`")
str_cmd = GetCommand()
if str_cmd:
Log("Received interaction data str_cmd", "Type:", type(str_cmd), "Value:", str_cmd)
if str_cmd == "test1":
test1()
Sleep(500)```
```cpp
void test1() {
Log("Calling custom function");
}
void main() {
while(true) {
json table = R"({
"type": "table",
"title": "Operation",
"cols": ["Column 1", "Column 2", "Action"],
"rows": [
["a", "1", {
"type": "button",
"cmd": "CoverAll",
"name": "Close All"
}],
["b", "1", {
"type": "button",
"cmd": 10,
"name": "Send Number"
}],
["c", "1", {
"type": "button",
"cmd": "",
"name": "Call Function"
}],
["d", "1", {
"type": "button",
"cmd": "test1",
"name": "Call Custom Function"
}]
]
})"_json;
table["rows"][2][2]["cmd"] = _D();
LogStatus(_D(), "\n", "`" + table.dump() + "`");
auto str_cmd = GetCommand();
if(str_cmd != "") {
Log("Received interaction data str_cmd", "Type:", typeid(str_cmd).name(), "Value:", str_cmd);
if(str_cmd == "test1") {
test1();
}
}
Sleep(500);
}
}```
结合```GetCommand()```函数,构造状态栏按钮交互功能(旧版按钮结构):
```javascript
function main() {
var tbl = {
type: "table",
title: "Operation",
cols: ["Column 1", "Column 2"],
rows: [
["Open Position", {"type": "button", "cmd": "open", "name": "Open", "input": {"name": "Quantity", "type": "number", "defValue": 1}}],
["Close Position", {"type": "button", "cmd": "coverAll", "name": "Close All"}]
]
}
LogStatus(_D(), "\n", "`" + JSON.stringify(tbl) + "`")
while (true) {
var cmd = GetCommand()
if (cmd) {
Log("cmd:", cmd)
}
Sleep(1000)
}
}```
```python
import json
def main():
tbl = {
"type": "table",
"title": "Operation",
"cols": ["Column 1", "Column 2"],
"rows": [
["Open Position", {"type": "button", "cmd": "open", "name": "Open", "input": {"name": "Quantity", "type": "number", "defValue": 1}}],
["Close Position", {"type": "button", "cmd": "coverAll", "name": "Close All"}]
]
}
LogStatus(_D(), "\n", "`" + json.dumps(tbl) + "`")
while True:
cmd = GetCommand()
if cmd:
Log("cmd:", cmd)
Sleep(1000)```
```cpp
void main() {
json tbl = R"({
"type": "table",
"title": "Operation",
"cols": ["Column 1", "Column 2"],
"rows": [
["Open Position", {"type": "button", "cmd": "open", "name": "Open", "input": {"name": "Quantity", "type": "number", "defValue": 1}}],
["Close Position", {"type": "button", "cmd": "coverAll", "name": "Close All"}]
]
})"_json;
LogStatus(_D(), "\n", "`" + tbl.dump() + "`");
while(true) {
auto cmd = GetCommand();
if(cmd != "") {
Log("cmd:", cmd);
}
Sleep(1000);
}
}```
在构造状态栏按钮进行交互时也支持输入数据,交互指令最终由```GetCommand()```函数捕获。
给状态栏中的按钮控件的数据结构中增加```input```项(旧版按钮结构),例如给```{"type": "button", "cmd": "open", "name": "Open"}```增加:```"input": {"name": "Quantity", "type": "number", "defValue": 1}```,即可使按钮在被点击时弹出一个带输入框控件的弹窗(输入框中默认值为1,即```defValue```设置的数据),可以输入数据并与按钮命令一起发送。例如以下测试代码运行时,点击「开仓」按钮后,会弹出一个带输入框的弹窗,在输入框中输入111后点击「确定」,```GetCommand()```函数将捕获消息:```open:111```。
```javascript
function main() {
var tbl = {
type: "table",
title: "Group Button Control Demo",
cols: ["Operation"],
rows: []
}
// 创建分组按钮控件结构
var groupBtn = {
type: "button",
cmd: "open",
name: "Open",
group: [
{"name": "orderType", "description": "下单方式|order type", "type": "selected", "defValue": "市价单|挂单"},
{"name": "tradePrice@orderType==1", "description": "交易价格|trade price", "type": "number", "defValue": 100},
{"name": "orderAmount", "description": "委托数量|order amount", "type": "string", "defValue": 100},
{"name": "boolean", "description": "是/否|boolean", "type": "boolean", "defValue": true}
]
}
// 测试按钮1
var testBtn1 = {"type": "button", "name": "Button 1", "cmd": "button1", "description": "This is the first button"}
var testBtn2 = {"type": "button", "name": "Button 2", "cmd": "button2", "description": "This is the second button", "input": {"name": "Quantity", "type": "number", "defValue": 1}}
// 在tbl中添加groupBtn
tbl.rows.push([groupBtn])
// 支持状态栏表格的一个单元格内设置多个按钮,即一个单元格内的数据为一个按钮结构数组:[testBtn1, testBtn2]
tbl.rows.push([[testBtn1, testBtn2]])
while (true) {
LogStatus("`" + JSON.stringify(tbl) + "`", "\n", "Group button controls can be set directly on the status bar in addition to status bar tables:", "`" + JSON.stringify(groupBtn) + "`")
var cmd = GetCommand()
if (cmd) {
Log("cmd:", cmd)
}
Sleep(5000)
}
}```
```python
import json
def main():
tbl = {
"type": "table",
"title": "Group Button Control Demo",
"cols": ["Operation"],
"rows": []
}
groupBtn = {
"type": "button",
"cmd": "open",
"name": "Open",
"group": [
{"name": "orderType", "description": "下单方式|order type", "type": "selected", "defValue": "市价单|挂单"},
{"name": "tradePrice@orderType==1", "description": "交易价格|trade price", "type": "number", "defValue": 100},
{"name": "orderAmount", "description": "委托数量|order amount", "type": "string", "defValue": 100},
{"name": "boolean", "description": "是/否|boolean", "type": "boolean", "defValue": True}
]
}
testBtn1 = {"type": "button", "name": "Button 1", "cmd": "button1", "description": "This is the first button"}
testBtn2 = {"type": "button", "name": "Button 2", "cmd": "button2", "description": "This is the second button", "input": {"name": "Quantity", "type": "number", "defValue": 1}}
tbl["rows"].append([groupBtn])
tbl["rows"].append([[testBtn1, testBtn2]])
while True:
LogStatus("`" + json.dumps(tbl) + "`", "\n", "Group button controls can be set directly on the status bar in addition to status bar tables:", "`" + json.dumps(groupBtn) + "`")
cmd = GetCommand()
if cmd:
Log("cmd:", cmd)
Sleep(5000)```
```cpp
void main() {
json tbl = R"({
"type": "table",
"title": "Group Button Control Demo",
"cols": ["Operation"],
"rows": []
})"_json;
json groupBtn = R"({
"type": "button",
"name": "Open",
"cmd": "open",
"group": [
{"name": "orderType", "description": "下单方式|order type", "type": "selected", "defValue": "市价单|挂单"},
{"name": "tradePrice@orderType==1", "description": "交易价格|trade price", "type": "number", "defValue": 100},
{"name": "orderAmount", "description": "委托数量|order amount", "type": "string", "defValue": 100},
{"name": "boolean", "description": "是/否|boolean", "type": "boolean", "defValue": true}
]})"_json;
json testBtn1 = R"({"type": "button", "name": "Button 1", "cmd": "button1", "description": "This is the first button"})"_json;
json testBtn2 = R"({"type": "button", "name": "Button 2", "cmd": "button2", "description": "This is the second button", "input": {"name": "Quantity", "type": "number", "defValue": 1}})"_json;
tbl["rows"].push_back({groupBtn});
tbl["rows"].push_back({{testBtn1, testBtn2}});
while(true) {
LogStatus("`" + tbl.dump() + "`", "\n", "Group button controls can be set directly on the status bar in addition to status bar tables:", "`" + groupBtn.dump() + "`");
auto cmd = GetCommand();
if(cmd != "") {
Log("cmd:", cmd);
}
Sleep(5000);
}
}```
支持分组按钮控件(旧版按钮结构),功能与**支持输入数据的状态栏按钮**(使用"input"字段设置)一致。交互指令最终由```GetCommand()```函数捕获。区别在于使用```"group"```字段设置,当点击按钮触发交互时,页面弹出的对话框中包含设置好的**一组**输入控件,可以一次性输入一组数据。
关于状态栏按钮控件和分组按钮控件结构中```"group"```字段,需要注意以下几点:
- group中```type```属性仅支持以下4种类型,```defValue```属性为默认值。
"selected":下拉框控件,设置下拉框中每个选项时使用```|```符号分隔。
"number":数值输入框控件。
"string":字符串输入框控件。
"boolean":勾选框控件,勾选为布尔值真,不勾选为布尔值假。
- 交互输入控件支持依赖设置:
例如以下示例中的:```"name": "tradePrice@orderType==1"```设置,该设置使**交易价格**(```tradePrice```)输入控件仅当**下单方式**(orderType)下拉框控件选择为**挂单**时可用。
- 交互输入控件名称支持双语设置:
例如以下示例中的:"description": "下单方式|order type"设置,使用```|```符号分隔中英文描述内容。
- group中的```name```、```description```与按钮结构中的```name```、```description```虽然字段名一致,但定义并不相同。
group中的```name```与input中的```name```定义也不同。
- 分组按钮控件触发后,发送交互内容的格式为:按钮的cmd字段值、group字段相关数据。例如以下示例测试时```Log("cmd:", cmd)```语句输出的内容:
```cmd: open:{"orderType":1,"tradePrice":99,"orderAmount":"99","boolean":true}```,即发生交互操作时```GetCommand()```函数返回的内容:```open:{"orderType":1,"tradePrice":99,"orderAmount":"99","boolean":true}```。
- 按钮控件的```type```属性仅支持:```"button"```:
支持输入数据的按钮控件,即设置了```input```属性的控件,```input```字段的配置信息中的```type```属性支持多种控件类型。
参考以下示例:
```javascript
function main() {
// 状态栏按钮控件(设置input字段实现)testBtn1按钮触发的页面中的下拉框控件使用options字段设置选项,使用defValue字段设置默认选项。区别于本章其它例子中直接使用defValue设置选项。
var testBtn1 = {
type: "button",
name: "testBtn1",
cmd: "cmdTestBtn1",
input: {name: "testBtn1ComboBox", type: "selected", options: ["A", "B"], defValue: 1}
}
/*
状态栏按钮控件(设置input字段实现)testBtn2按钮触发的页面中的下拉框控件使用options字段设置选项,options字段中的选项不仅支持字符串,
也支持使用```{text: "描述", value: "值"}```结构。使用defValue字段设置默认选项,默认选项可以是多选(通过数组结构实现多选)。多选需要设置额外的字段multiple为真值(true)。
*/
var testBtn2 = {
type: "button",
name: "testBtn2",
cmd: "cmdTestBtn2",
input: {
name: "testBtn2MultiComboBox",
type: "selected",
description: "Implement multi-select dropdown",
options: [{text: "Option A", value: "A"}, {text: "Option B", value: "B"}, {text: "Option C", value: "C"}],
defValue: ["A", "C"],
multiple: true
}
}
// 状态栏分组按钮控件(设置group字段实现)testBtn3按钮触发的页面中的下拉框控件使用options字段设置选项,也支持直接使用defValue设置选项。
var testBtn3 = {
type: "button",
name: "testBtn3",
cmd: "cmdTestBtn3",
group: [
{name: "comboBox1", label: "labelComboBox1", description: "Dropdown 1", type: "selected", defValue: 1, options: ["A", "B"]},
{name: "comboBox2", label: "labelComboBox2", description: "下拉框2", type: "selected", defValue: "A|B"},
{name: "comboBox3", label: "labelComboBox3", description: "Dropdown 3", type: "selected", defValue: [0, 2], multiple: true, options: ["A", "B", "C"]},
{
name: "comboBox4",
label: "labelComboBox4",
description: "Dropdown 4",
type: "selected",
defValue: ["A", "C"],
multiple: true,
options: [{text: "Option A", value: "A"}, {text: "Option B", value: "B"}, {text: "Option C", value: "C"}, {text: "Option D", value: "D"}]
}
]
}
while (true) {
LogStatus("`" + JSON.stringify(testBtn1) + "`\n", "`" + JSON.stringify(testBtn2) + "`\n", "`" + JSON.stringify(testBtn3) + "`\n")
var cmd = GetCommand()
if (cmd) {
Log(cmd)
}
Sleep(5000)
}
}```
```python
import json
def main():
testBtn1 = {
"type": "button",
"name": "testBtn1",
"cmd": "cmdTestBtn1",
"input": {"name": "testBtn1ComboBox", "type": "selected", "options": ["A", "B"], "defValue": 1}
}
testBtn2 = {
"type": "button",
"name": "testBtn2",
"cmd": "cmdTestBtn2",
"input": {
"name": "testBtn2MultiComboBox",
"type": "selected",
"description": "Implement multi-select dropdown",
"options": [{"text": "Option A", "value": "A"}, {"text": "Option B", "value": "B"}, {"text": "Option C", "value": "C"}],
"defValue": ["A", "C"],
"multiple": True
}
}
testBtn3 = {
"type": "button",
"name": "testBtn3",
"cmd": "cmdTestBtn3",
"group": [
{"name": "comboBox1", "label": "labelComboBox1", "description": "Dropdown 1", "type": "selected", "defValue": 1, "options": ["A", "B"]},
{"name": "comboBox2", "label": "labelComboBox2", "description": "Dropdown 2", "type": "selected", "defValue": "A|B"},
{"name": "comboBox3", "label": "labelComboBox3", "description": "Dropdown 3", "type": "selected", "defValue": [0, 2], "multiple": True, "options": ["A", "B", "C"]},
{
"name": "comboBox4",
"label": "labelComboBox4",
"description": "Dropdown 4",
"type": "selected",
"defValue": ["A", "C"],
"multiple": True,
"options": [{"text": "Option A", "value": "A"}, {"text": "Option B", "value": "B"}, {"text": "Option C", "value": "C"}, {"text": "Option D", "value": "D"}]
}
]
}
while True:
LogStatus("`" + json.dumps(testBtn1) + "`\n", "`" + json.dumps(testBtn2) + "`\n", "`" + json.dumps(testBtn3) + "`\n")
cmd = GetCommand()
if cmd:
Log(cmd)
Sleep(5000)```
```cpp
void main() {
json testBtn1 = R"({
"type": "button",
"name": "testBtn1",
"cmd": "cmdTestBtn1",
"input": {"name": "testBtn1ComboBox", "type": "selected", "options": ["A", "B"], "defValue": 1}
})"_json;
json testBtn2 = R"({
"type": "button",
"name": "testBtn2",
"cmd": "cmdTestBtn2",
"input": {
"name": "testBtn2MultiComboBox",
"type": "selected",
"description": "Implement multi-select dropdown",
"options": [{"text": "Option A", "value": "A"}, {"text": "Option B", "value": "B"}, {"text": "Option C", "value": "C"}],
"defValue": ["A", "C"],
"multiple": true
}
})"_json;
json testBtn3 = R"({
"type": "button",
"name": "testBtn3",
"cmd": "cmdTestBtn3",
"group": [
{"name": "comboBox1", "label": "labelComboBox1", "description": "Dropdown 1", "type": "selected", "defValue": 1, "options": ["A", "B"]},
{"name": "comboBox2", "label": "labelComboBox2", "description": "Dropdown 2", "type": "selected", "defValue": "A|B"},
{"name": "comboBox3", "label": "labelComboBox3", "description": "Dropdown 3", "type": "selected", "defValue": [0, 2], "multiple": true, "options": ["A", "B", "C"]},
{
"name": "comboBox4",
"label": "labelComboBox4",
"description": "Dropdown 4",
"type": "selected",
"defValue": ["A", "C"],
"multiple": true,
"options": [{"text": "Option A", "value": "A"}, {"text": "Option B", "value": "B"}, {"text": "Option C", "value": "C"}, {"text": "Option D", "value": "D"}]
}
]
})"_json;
while (true) {
LogStatus("`" + testBtn1.dump() + "`\n", "`" + testBtn2.dump() + "`\n", "`" + testBtn3.dump() + "`\n");
auto cmd = GetCommand();
if (cmd != "") {
Log(cmd);
}
Sleep(5000);
}
}```
状态栏分组按钮控件(通过设置```group```字段实现)与状态栏按钮控件(通过设置```input```字段实现)被点击触发交互时(旧版按钮结构),页面弹出的对话框中的下拉框控件也支持多选。以下示例演示如何设计包含多选选项的下拉框控件:
```javascript
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() {
var arrManager = []
_.each(symbols, function(symbol) {
arrManager.push({
"symbol": symbol,
})
})
// Btn
var tmpBtnOpen = {
"type": "button",
"cmd": "open",
"name": "Open Position",
"group": [{
"type": "selected",
"name": "tradeType",
"label": "Order Type",
"description": "Market order, Limit order",
"default": 0,
"group": "Trade Settings",
"settings": {
"options": ["Market Order", "Limit Order"],
"required": true,
}
}, {
"type": "selected",
"name": "direction",
"label": "Trade Direction",
"description": "Buy, Sell",
"default": "buy",
"group": "Trade Settings",
"settings": {
"render": "segment",
"required": true,
"options": [{"name": "Buy", "value": "buy"}, {"name": "Sell", "value": "sell"}],
}
}, {
"type": "number",
"name": "price",
"label": "Price",
"description": "Order price",
"group": "Trade Settings",
"filter": "tradeType==1",
"settings": {
"required": true,
}
}, {
"type": "number",
"name": "amount",
"label": "Order Amount",
"description": "Order amount",
"group": "Trade Settings",
"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": "Symbol", "default": m["symbol"], "settings": {"required": true}}])
tbl["rows"].push([m["symbol"], btnOpen])
})
var cmd = GetCommand()
if (cmd) {
Log("Received interaction:", 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("Symbol:", msg["symbol"], ", Direction:", msg["direction"], ", Order type:", msg["tradeType"] == 0 ? "Market order" : "Limit order", msg["tradeType"] == 0 ? ", Price: Current market price" : ", Price:" + msg["price"], ", Amount:", msg["amount"])
}
}
LogStatus(_D(), "\n", "`" + JSON.stringify(tbl) + "`")
Sleep(1000)
}
}```
```python
import json
symbols = ["BTC_USDT.swap", "ETH_USDT.swap", "LTC_USDT.swap", "BNB_USDT.swap", "SOL_USDT.swap"]
def createBtn(tmp, group):
btn = json.loads(json.dumps(tmp))
for eleByGroup in group:
btn["group"].insert(0, eleByGroup)
return btn
def main():
arrManager = []
for symbol in symbols:
arrManager.append({"symbol": symbol})
# Btn
tmpBtnOpen = {
"type": "button",
"cmd": "open",
"name": "Open Position",
"group": [{
"type": "selected",
"name": "tradeType",
"label": "Order Type",
"description": "Market order, Limit order",
"default": 0,
"group": "Trade Settings",
"settings": {
"options": ["Market Order", "Limit Order"],
"required": True,
}
}, {
"type": "selected",
"name": "direction",
"label": "Trade Direction",
"description": "Buy, Sell",
"default": "buy",
"group": "Trade Settings",
"settings": {
"render": "segment",
"required": True,
"options": [{"name": "Buy", "value": "buy"}, {"name": "Sell", "value": "sell"}],
}
}, {
"type": "number",
"name": "price",
"label": "Price",
"description": "Order price",
"group": "Trade Settings",
"filter": "tradeType==1",
"settings": {
"required": True,
}
}, {
"type": "number",
"name": "amount",
"label": "Order Amount",
"description": "Order amount",
"group": "Trade Settings",
"settings": {
"required": True,
}
}],
}
while True:
tbl = {"type": "table", "title": "dashboard", "cols": ["symbol", "actionOpen"], "rows": []}
for m in arrManager:
btnOpen = createBtn(tmpBtnOpen, [{"type": "string", "name": "symbol", "label": "Symbol", "default": m["symbol"], "settings": {"required": True}}])
tbl["rows"].append([m["symbol"], btnOpen])
cmd = GetCommand()
if cmd != "" and cmd != None:
Log("Received interaction:", cmd)
# 解析交互消息:open:{"symbol":"LTC_USDT.swap","tradeType":0,"direction":"buy","amount":111}
# 根据第一个冒号之前的指令判断是哪种按钮模板触发的消息
arrCmd = cmd.split(":")
if arrCmd[0] == "open":
msg = json.loads(cmd[5:])
Log("Symbol:", msg["symbol"], ", Direction:", msg["direction"], ", Order type:", "Market order" if msg["tradeType"] == 0 else "Limit order", ", Price: Current market price" if msg["tradeType"] == 0 else ", Price:" + str(msg["price"]), ", Amount:", msg["amount"])
# 输出状态栏信息
LogStatus(_D(), "\n", "`" + json.dumps(tbl) + "`")
Sleep(1000)```
```cpp
// 略...```
使用当前最新的按钮结构,构造状态栏表格中的按钮,点击按钮触发交互时弹出一个多控件弹窗。
详细内容可以参考:[用户指南-状态栏中的交互控件](https://www.fmz.com/user-guide#%E7%8A%B6%E6%80%81%E6%A0%8F%E4%B8%AD%E7%9A%84%E4%BA%A4%E4%BA%92%E6%8E%A7%E4%BB%B6)。
```javascript
function main() {
var table = {
type: 'table',
title: 'Position Operation',
cols: ['Column 1', 'Column 2', 'Action'],
rows: [
['abc', 'def', {'type':'button', 'cmd': 'coverAll', 'name': 'Close'}]
]
}
var ticker = exchange.GetTicker()
// 添加一行数据,将第一个和第二个单元格合并,并在合并后的单元格内输出ticker变量
table.rows.push([{body : JSON.stringify(ticker), colspan : 2}, "abc"])
LogStatus('`' + JSON.stringify(table) + '`')
}```
```python
import json
def main():
table = {
"type" : "table",
"title" : "Position Operation",
"cols" : ["Column 1", "Column 2", "Action"],
"rows" : [
["abc", "def", {"type": "button", "cmd": "coverAll", "name": "Close"}]
]
}
ticker = exchange.GetTicker()
table["rows"].append({"body": json.dumps(ticker), "colspan": 2}, "abc"])
LogStatus("`" + json.dumps(table) + "`")```
```cpp
void main() {
json table = R"({
"type" : "table",
"title" : "Position Operation",
"cols" : ["Column 1", "Column 2", "Action"],
"rows" : [
["abc", "def", {"type": "button", "cmd": "coverAll", "name": "Close"}]
]
})"_json;
auto ticker = exchange.GetTicker();
json jsonTicker = R"({"Buy": 0, "Sell": 0, "High": 0, "Low": 0, "Volume": 0, "Last": 0, "Time": 0})"_json;
jsonTicker["Buy"] = ticker.Buy;
jsonTicker["Sell"] = ticker.Sell;
jsonTicker["Last"] = ticker.Last;
jsonTicker["Volume"] = ticker.Volume;
jsonTicker["Time"] = ticker.Time;
jsonTicker["High"] = ticker.High;
jsonTicker["Low"] = ticker.Low;
json arr = R"([{"body": {}, "colspan": 2}, "abc"])"_json;
arr[0]["body"] = jsonTicker;
table["rows"].push_back(arr);
LogStatus("`" + table.dump() + "`");
}```
横向合并```LogStatus()```函数绘制的表格中的单元格:
```javascript
function main() {
var table = {
type: 'table',
title: 'Table Demo',
cols: ['Column A', 'Column B', 'Column C'],
rows: [
['A1', 'B1', {'type':'button', 'cmd': 'coverAll', 'name': 'C1'}]
]
}
var ticker = exchange.GetTicker()
var name = exchange.GetName()
table.rows.push([{body : "A2 + B2:" + JSON.stringify(ticker), colspan : 2}, "C2"])
table.rows.push([{body : "A3 + A4 + A5:" + name, rowspan : 3}, "B3", "C3"])
// A3 被上一行第一个单元格合并
table.rows.push(["B4", "C4"])
// A4 被上一行第一个单元格合并
table.rows.push(["B5", "C5"])
table.rows.push(["A6", "B6", "C6"])
LogStatus('`' + JSON.stringify(table) + '`')
}```
```python
import json
def main():
table = {
"type" : "table",
"title" : "Table Demo",
"cols" : ["Column A", "Column B", "Column C"],
"rows" : [
["A1", "B1", {"type": "button", "cmd": "coverAll", "name": "C1"}]
]
}
ticker = exchange.GetTicker()
name = exchange.GetName()
table["rows"].append([{"body": "A2 + B2:" + json.dumps(ticker), "colspan": 2}, "C2"])
table["rows"].append([{"body": "A3 + A4 + A5:" + name, "rowspan": 3}, "B3", "C3"])
table["rows"].append(["B4", "C4"])
table["rows"].append(["B5", "C5"])
table["rows"].append(["A6", "B6", "C6"])
LogStatus("`" + json.dumps(table) + "`")```
```cpp
void main() {
json table = R"({
"type" : "table",
"title" : "Table Demo",
"cols" : ["Column A", "Column B", "Column C"],
"rows" : [
["A1", "B1", {"type": "button", "cmd": "coverAll", "name": "C1"}]
]
})"_json;
// 为便于测试,使代码简短易读,此处使用构造的数据
json jsonTicker = R"({"High": 0, "Low": 0, "Buy": 0, "Sell": 0, "Last": 0, "Time": 0, "Volume": 0})"_json;
auto name = exchange.GetName();
json arr1 = R"([{"body": "", "colspan": 2}, "C2"])"_json;
arr1[0]["body"] = "A2 + B2:" + jsonTicker.dump();
json arr2 = R"([{"body": "", "rowspan": 3}, "B3", "C3"])"_json;
arr2[0]["body"] = "A3 + A4 + A5:" + name;
table["rows"].push_back(arr1);
table["rows"].push_back(arr2);
table["rows"].push_back(R"(["B4", "C4"])"_json);
table["rows"].push_back(R"(["B5", "C5"])"_json);
table["rows"].push_back(R"(["A6", "B6", "C6"])"_json);
LogStatus("`" + table.dump() + "`");
}```
纵向合并 ```LogStatus()``` 函数绘制的表格中的单元格:
```javascript
function main() {
var table1 = {type: 'table', title: 'table1', cols: ['Column 1', 'Column 2'], rows: [ ['abc', 'def'], ['ABC', 'support color #ff0000']]}
var table2 = {type: 'table', title: 'table2', cols: ['Column 1', 'Column 2'], rows: [ ['abc', 'def'], ['ABC', 'support color #ff0000']]}
LogStatus('`' + JSON.stringify([table1, table2]) + '`')
}```
```python
import json
def main():
table1 = {"type": "table", "title": "table1", "cols": ["Column 1", "Column 2"], "rows": [ ["abc", "def"], ["ABC", "support color #ff0000"]]}
table2 = {"type": "table", "title": "table2", "cols": ["Column 1", "Column 2"], "rows": [ ["abc", "def"], ["ABC", "support color #ff0000"]]}
LogStatus("`" + json.dumps([table1, table2]) + "`")```
```cpp
void main() {
json table1 = R"({"type": "table", "title": "table1", "cols": ["Column 1", "Column 2"], "rows": [ ["abc", "def"], ["ABC", "support color #ff0000"]]})"_json;
json table2 = R"({"type": "table", "title": "table2", "cols": ["Column 1", "Column 2"], "rows": [ ["abc", "def"], ["ABC", "support color #ff0000"]]})"_json;
json arr = R"([])"_json;
arr.push_back(table1);
arr.push_back(table2);
LogStatus("`" + arr.dump() + "`");
}```
状态栏表格分页显示:
```javascript
function main(){
var tab1 = {
type : "table",
title : "Table 1",
cols : ["1", "2"],
rows : []
}
var tab2 = {
type : "table",
title : "Table 2",
cols : ["1", "2", "3"],
rows : []
}
var tab3 = {
type : "table",
title : "Table 3",
cols : ["A", "B", "C"],
rows : []
}
tab1.rows.push(["jack", "lucy"])
tab2.rows.push(["A", "B", "C"])
tab3.rows.push(["A", "B", "C"])
LogStatus('`' + JSON.stringify(tab1) + '`\n' +
'`' + JSON.stringify(tab2) + '`\n' +
'`' + JSON.stringify(tab3) + '`')
Log("exit")
}```
```python
import json
def main():
tab1 = {
"type": "table",
"title": "Table 1",
"cols": ["1", "2"],
"rows": []
}
tab2 = {
"type": "table",
"title": "Table 2",
"cols": ["1", "2", "3"],
"rows": []
}
tab3 = {
"type": "table",
"title": "Table 3",
"cols": ["A", "B", "C"],
"rows": []
}
tab1["rows"].append(["jack", "lucy"])
tab2["rows"].append(["A", "B", "C"])
tab3["rows"].append(["A", "B", "C"])
LogStatus("`" + json.dumps(tab1) + "`\n" +
"`" + json.dumps(tab2) + "`\n" +
"`" + json.dumps(tab3) + "`")```
```cpp
void main() {
json tab1 = R"({
"type": "table",
"title": "Table 1",
"cols": ["1", "2"],
"rows": []
})"_json;
json tab2 = R"({
"type": "table",
"title": "Table 2",
"cols": ["1", "2", "3"],
"rows": []
})"_json;
json tab3 = R"({
"type": "table",
"title": "Table 3",
"cols": ["A", "B", "C"],
"rows": []
})"_json;
tab1["rows"].push_back(R"(["jack", "lucy"])"_json);
tab2["rows"].push_back(R"(["A", "B", "C"])"_json);
tab3["rows"].push_back(R"(["A", "B", "C"])"_json);
LogStatus("`" + tab1.dump() + "`\n" +
"`" + tab2.dump() + "`\n" +
"`" + tab3.dump() + "`");
}```
除了可以分页显示表格外,还可以将多个表格自上而下排列显示:
```javascript
function main() {
var tbl = {
type : "table",
title : "test scroll",
scroll : "auto",
cols : ["col 0", "col 1", "col 2", "col 3", "col 4", "col 5", "col 6", "col 7", "col 8", "col 9", "col 10",
"col 11", "col 12", "col 13", "col 14", "col 15", "col 16", "col 17", "col 18", "col 19", "col 20"],
rows : []
}
for (var i = 1 ; i < 100 ; i++) {
tbl.rows.push([i, "1," + i, "2," + i, "3," + i, "4," + i, "5," + i, "6," + i, "7," + i, "8," + i, "9," + i, "10," + i,
"11," + i, "12," + i, "13," + i, "14," + i, "15," + i, "16," + i, "17," + i, "18," + i, "19," + i, "20," + i])
}
LogStatus("`" + JSON.stringify(tbl) + "`")
}```
```python
import json
def main():
tbl = {
"type" : "table",
"title" : "test scroll",
"scroll" : "auto",
"cols" : ["col 0", "col 1", "col 2", "col 3", "col 4", "col 5", "col 6", "col 7", "col 8", "col 9", "col 10",
"col 11", "col 12", "col 13", "col 14", "col 15", "col 16", "col 17", "col 18", "col 19", "col 20"],
"rows" : []
}
for index in range(1, 100):
i = str(index)
tbl["rows"].append([i, "1," + i, "2," + i, "3," + i, "4," + i, "5," + i, "6," + i, "7," + i, "8," + i, "9," + i, "10," + i,
"11," + i, "12," + i, "13," + i, "14," + i, "15," + i, "16," + i, "17," + i, "18," + i, "19," + i, "20," + i])
LogStatus("`" + json.dumps(tbl) + "`")```
```cpp
void main() {
json table = R"({
"type" : "table",
"title" : "test scroll",
"scroll" : "auto",
"cols" : ["col 0", "col 1", "col 2", "col 3", "col 4", "col 5", "col 6", "col 7", "col 8", "col 9", "col 10",
"col 11", "col 12", "col 13", "col 14", "col 15", "col 16", "col 17", "col 18", "col 19", "col 20"],
"rows" : []
})"_json;
for (int index = 1; index < 100; ++index) {
std::string i = std::to_string(index);
table["rows"].push_back({i, "1," + i, "2," + i, "3," + i, "4," + i, "5," + i, "6," + i, "7," + i, "8," + i, "9," + i, "10," + i,
"11," + i, "12," + i, "13," + i, "14," + i, "15," + i, "16," + i, "17," + i, "18," + i, "19," + i, "20," + i});
}
LogStatus("`" + table.dump() + "`");
}```
支持设置状态栏表格的横向和纵向滚动模式。将```scroll```属性设置为```"auto"```时,当状态栏表格的纵向行数超过20行时,内容将自动滚动显示;当横向列数超出页面显示范围时,将进行横向滚动显示。使用```scroll```属性可以有效缓解实盘运行时状态栏中大量数据写入导致的卡顿问题。
参考以下测试示例:
实盘运行时,```LogStatus()```函数输出的信息不保存到实盘数据库,仅更新当前实盘的状态栏内容。
```LogStatus()```函数支持打印```base64```编码后的图片,以``` ` ```开头,以``` ` ```结尾。例如:```LogStatus("`data:image/png;base64,AAAA`")```。
```LogStatus()```函数支持直接传入```Python```的```matplotlib.pyplot```对象,只要该对象包含```savefig```方法即可作为参数传入```LogStatus()```函数,例如:
```python
import matplotlib.pyplot as plt
def main():
plt.plot([3,6,2,4,7,1])
LogStatus(plt)
策略实盘运行时,在实盘页面如果翻看历史记录,状态栏会进入休眠状态并停止更新。只有当日志处于第一页时,状态栏数据才会刷新。支持在状态栏输出base64编码后的图片,也支持在状态栏显示的表格中输出base64编码后的图片。由于编码后的图片字符串数据通常很长,因此不再展示示例代码。
{@fun/Global/GetCommand GetCommand}