LogStatus-table
Status bar table output with LogStatus: columns can set number formats, up/down colors and units; cells can be merged or hold buttons; several tables can be shown as tabs.
Examples
-
Outputs a table with 3 rows and 3 columns.
javascriptfunction main() { var tbl = { type: "table", title: "Title", cols: ["Column 1", "Column 2", "Column 3"], rows: [ ["Row 1 Column 1", "Row 1 Column 2", "Row 1 Column 3"], ["Row 2 Column 1", "Row 2 Column 2", "Row 2 Column 3"], ["Row 3 Column 1", "Row 3 Column 2", "Row 3 Column 3"] ] } // A lone table object gets backticks automatically LogStatus(tbl) }pythondef main(): tbl = { "type": "table", "title": "Title", "cols": ["Column 1", "Column 2", "Column 3"], "rows": [ ["Row 1 Column 1", "Row 1 Column 2", "Row 1 Column 3"], ["Row 2 Column 1", "Row 2 Column 2", "Row 2 Column 3"], ["Row 3 Column 1", "Row 3 Column 2", "Row 3 Column 3"] ] } # A lone table dict gets backticks automatically LogStatus(tbl)rustfn main() { let tbl = r#"{"type": "table", "title": "Title", "cols": ["Column 1", "Column 2", "Column 3"], "rows": [["Row 1 Column 1", "Row 1 Column 2", "Row 1 Column 3"], ["Row 2 Column 1", "Row 2 Column 2", "Row 2 Column 3"], ["Row 3 Column 1", "Row 3 Column 2", "Row 3 Column 3"]]}"#; // Rust strings get no automatic backticks; the JSON inside must be one line LogStatus!(format!("`{}`", tbl.replace('\n', ""))); } -
The last 10 daily K-lines: column formats and up/down colors, plus a cell object with its own color.
javascriptfunction main() { var r = exchange.GetRecords(PERIOD_D1) if (!r || r.length < 11) return var rows = [] for (var i = r.length - 1; i >= r.length - 10; i--) { var chg = r[i].Close / r[i - 1].Close - 1 var note = Math.abs(chg) > 0.05 ? {value: "Big move", color: "warning"} : "" rows.push([_D(r[i].Time, "yyyy-MM-dd"), r[i].Close, chg, r[i].Volume, note]) } LogStatus({type: "table", title: "Last 10 days", rows: rows, cols: [ "Date", {title: "Close", format: {precision: 2}, align: "right"}, {title: "Change", format: {percent: true, precision: 2}, color: "sign", align: "right"}, {title: "Volume", format: {compact: true}, align: "right"}, "Note" ]}) }pythondef main(): r = exchange.GetRecords(PERIOD_D1) if not r or len(r) < 11: return rows = [] for i in range(len(r) - 1, len(r) - 11, -1): chg = r[i]["Close"] / r[i - 1]["Close"] - 1 note = {"value": "Big move", "color": "warning"} if abs(chg) > 0.05 else "" rows.append([_D(r[i]["Time"] / 1000, "%Y-%m-%d"), r[i]["Close"], chg, r[i]["Volume"], note]) pct = {"percent": True, "precision": 2} LogStatus({"type": "table", "title": "Last 10 days", "rows": rows, "cols": [ "Date", {"title": "Close", "format": {"precision": 2}, "align": "right"}, {"title": "Change", "format": pct, "color": "sign", "align": "right"}, {"title": "Volume", "format": {"compact": True}, "align": "right"}, "Note" ]})rustfn main() { let Ok(r) = exchange.GetRecords(None, PERIOD_D1, None) else { return }; if r.len() < 11 { return; } let rows: Vec<String> = (r.len() - 10..r.len()).rev().map(|i| { let chg = r[i].Close / r[i - 1].Close - 1.0; let big = r#"{"value": "Big move", "color": "warning"}"#; let note = if chg.abs() > 0.05 { big } else { r#""""# }; let date = &_D(r[i].Time)[..10]; format!(r#"["{}", {}, {}, {}, {}]"#, date, r[i].Close, chg, r[i].Volume, note) }).collect(); let table = format!(r#"{{"type": "table", "title": "Last 10 days", "rows": [{}], "cols": [ "Date", {{"title": "Close", "format": {{"precision": 2}}, "align": "right"}}, {{"title": "Change", "format": {{"percent": true, "precision": 2}}, "color": "sign", "align": "right"}}, {{"title": "Volume", "format": {{"compact": true}}, "align": "right"}}, "Note"]}}"#, rows.join(",")); // The JSON inside backticks must be one line LogStatus!(format!("`{}`", table.replace('\n', ""))); } -
Horizontally merge cells in the table drawn by the
LogStatus()function.javascriptfunction 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() // Add a row of data, merge the first and second cells, and output the ticker variable in the merged cell table.rows.push([{body : JSON.stringify(ticker), colspan : 2}, "abc"]) LogStatus('`' + JSON.stringify(table) + '`') }pythonimport 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) + "`")rustfn main() { let table_tpl = String::from(r#"{"type": "table", "title": "Position Operation", "cols": ["Column 1", "Column 2", "Action"], "rows": ["#) + r#"["abc", "def", {"type": "button", "cmd": "coverAll", "name": "Close"}],"# + r#"__ROW2__"# + r#"]}"#; let ticker = exchange.GetTicker(None).unwrap(); let json_ticker = format!( r#"{{"Buy": {}, "Sell": {}, "High": {}, "Low": {}, "Volume": {}, "Last": {}, "Time": {}}}"#, ticker.Buy, ticker.Sell, ticker.High, ticker.Low, ticker.Volume, ticker.Last, ticker.Time ); // Add a row of data, merge the first and second cells, and output the ticker data in the merged cell // body is a string (corresponding to JS's JSON.stringify(ticker)); its internal quotes must be escaped before being embedded into the JSON let row2 = format!(r#"[{{"body": "{}", "colspan": 2}}, "abc"]"#, json_ticker.replace('"', "\\\"")); let table = table_tpl.replace("__ROW2__", &row2); LogStatus!(format!("`{}`", table)); } -
Vertically merge cells in a table drawn by the
LogStatus()function.javascriptfunction 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"]) // A4 is merged into the first cell of the previous row table.rows.push(["B4", "C4"]) // A5 is merged into the first cell of the previous row table.rows.push(["B5", "C5"]) table.rows.push(["A6", "B6", "C6"]) LogStatus('`' + JSON.stringify(table) + '`') }pythonimport 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) + "`")rustfn main() { // For ease of testing, constructed data is used here to keep the code short and readable let json_ticker = r#"{"High": 0, "Low": 0, "Buy": 0, "Sell": 0, "Last": 0, "Time": 0, "Volume": 0}"#; let name = exchange.GetName(); let mut rows: Vec<String> = Vec::new(); rows.push(String::from(r#"["A1", "B1", {"type": "button", "cmd": "coverAll", "name": "C1"}]"#)); // body is a string, and the quotes inside it must be escaped before they can be embedded in JSON let body = format!("A2 + B2:{}", json_ticker).replace('"', "\\\""); rows.push(format!(r#"[{{"body": "{}", "colspan": 2}}, "C2"]"#, body)); rows.push(format!(r#"[{{"body": "A3 + A4 + A5:{}", "rowspan": 3}}, "B3", "C3"]"#, name)); // A4 is merged into the first cell of the previous row rows.push(String::from(r#"["B4", "C4"]"#)); // A5 is merged into the first cell of the previous row rows.push(String::from(r#"["B5", "C5"]"#)); rows.push(String::from(r#"["A6", "B6", "C6"]"#)); let table = format!(r#"{{"type": "table", "title": "Table Demo", "cols": ["Column A", "Column B", "Column C"], "rows": [{}]}}"#, rows.join(",")); LogStatus!(format!("`{}`", table)); } -
Display tables with pagination in the status bar.
javascriptfunction 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]) + '`') }pythonimport 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]) + "`")rustfn main() { let table1 = r#"{"type": "table", "title": "table1", "cols": ["Column 1", "Column 2"], "rows": [["abc", "def"], ["ABC", "support color #ff0000"]]}"#; let table2 = r#"{"type": "table", "title": "table2", "cols": ["Column 1", "Column 2"], "rows": [["abc", "def"], ["ABC", "support color #ff0000"]]}"#; LogStatus!(format!("`[{},{}]`", table1, table2)); } -
In addition to displaying tables with pagination, you can also arrange multiple tables from top to bottom.
javascriptfunction 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") }pythonimport 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) + "`")rustfn main() { // In Rust, write the row data directly into the JSON string let tab1 = r#"{"type": "table", "title": "Table 1", "cols": ["1", "2"], "rows": [["jack", "lucy"]]}"#; let tab2 = r#"{"type": "table", "title": "Table 2", "cols": ["1", "2", "3"], "rows": [["A", "B", "C"]]}"#; let tab3 = r#"{"type": "table", "title": "Table 3", "cols": ["A", "B", "C"], "rows": [["A", "B", "C"]]}"#; LogStatus!(format!("`{}`\n`{}`\n`{}`", tab1, tab2, tab3)); Log!("exit"); } -
Supports setting horizontal and vertical scroll modes for the status bar table. After setting the
scrollattribute toauto, when the number of vertical rows in the status bar table exceeds 20, the content will scroll automatically; when the number of horizontal columns exceeds the visible range of the page, horizontal scrolling will be applied. Using thescrollattribute can help mitigate the lag caused by writing large amounts of data to the status bar during live trading.Refer to the following test example:
javascriptfunction 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) + "`") }pythonimport 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) + "`")rustfn main() { let tbl_tpl = String::from(r#"{"type": "table", "title": "test scroll", "scroll": "auto", "cols": ["#) + r#""col 0", "col 1", "col 2", "col 3", "col 4", "col 5", "col 6", "col 7", "col 8", "col 9", "col 10","# + r#""col 11", "col 12", "col 13", "col 14", "col 15", "col 16", "col 17", "col 18", "col 19", "col 20""# + r#"], "rows": [__ROWS__]}"#; let mut rows: Vec<String> = Vec::new(); for index in 1..100 { let i = index.to_string(); rows.push(format!( r#"[{}, "1,{}", "2,{}", "3,{}", "4,{}", "5,{}", "6,{}", "7,{}", "8,{}", "9,{}", "10,{}", "11,{}", "12,{}", "13,{}", "14,{}", "15,{}", "16,{}", "17,{}", "18,{}", "19,{}", "20,{}"]"#, i, i, i, i, i, i, i, i, i, i, i, i, i, i, i, i, i, i, i, i, i )); } let tbl = tbl_tpl.replace("__ROWS__", &rows.join(",")); LogStatus!(format!("`{}`", tbl)); }
Attributes
| Name | Type | Description |
type | string | Required. Always |
title | string | Table title. |
cols | array | Required. Column headers: each item is a string or a column definition object with |
rows | array | Required. 2D array, one array per row with one item per column. A cell can be text (a trailing |
scroll | string |
|
cols[].title | string | Column header. |
cols[].format | object | Number format of the column |
cols[].color | string | Color of the column's numbers: |
cols[].unit | string | Unit after the column's numbers. |
cols[].align | string | Alignment: |
rows[][].value | number / string | Value of a formatted cell. |
rows[][].format | object | Number format of the cell, taking precedence over the column. |
rows[][].color | string | Color of the cell, same values as |
rows[][].unit | string | Unit of the cell. |
See Also
Remarks
Column definitions apply only to the column's numbers; strings are shown as is, and cell objects take precedence over the column. Formatted text still sorts by the raw numbers; search and CSV export in the table use the formatted text.
To output a table on its own, JavaScript and Python pass the table object directly (backticks are added automatically) or write LogStatus("`" + JSON.stringify(tbl) + "`"); Rust writes format!("`{}`", table). Inside grid, tabs or an array with components no backticks are needed.
An array of tables wrapped in backticks is shown as tabs; tables on separate lines are stacked top to bottom. For buttons in cells see LogStatus-btnTypeTwo.