Chart
Custom chart plotting function.
Chart(options)Examples
-
Create a line chart and append the latest price every 5 seconds.
javascriptfunction main() { var chart = Chart({ title: {text: "Last price"}, xAxis: {type: "datetime"}, series: [{name: "Last", data: []}] }) chart.reset() while (true) { var ticker = exchange.GetTicker() if (ticker) { chart.add(0, [Date.now(), ticker.Last]) } Sleep(5000) } }pythonimport time def main(): chart = Chart({ "title": {"text": "Last price"}, "xAxis": {"type": "datetime"}, "series": [{"name": "Last", "data": []}] }) chart.reset() while True: ticker = exchange.GetTicker() if ticker: chart.add(0, [time.time() * 1000, ticker["Last"]]) Sleep(5000)rustfn main() { let chart = Chart::new(r#"{"title": {"text": "Last price"}, "xAxis": {"type": "datetime"}, "series": [{"name": "Last", "data": []}]}"#); chart.reset(0); loop { if let Ok(ticker) = exchange.GetTicker(None) { chart.add(0, &format!("[{}, {}]", Unix() * 1000, ticker.Last), -1); } Sleep(5000); } } -
Multi-chart drawing configuration notes:
extension.layoutproperty
When this property is set to "single", the chart will not be displayed stacked with other charts (i.e., it is not presented as tabbed pages), but is instead tiled separately.extension.heightproperty
This property is used to set the height of the chart. The value can be a numeric type, or it can be set in the form of "300px".extension.colproperty
This property is used to set the width of the chart. The page width is divided into 12 units in total; setting it to 8 means the chart occupies 8 units of width.
javascriptfunction main() { var cfgA = { extension: { layout: 'single', // Not included in grouping, displayed separately; the default is grouping 'group' height: 300, // Specify height }, title: { text: 'Order Book Chart' }, xAxis: { type: 'datetime' }, series: [{ name: 'Bid 1', data: [], }, { name: 'Ask 1', data: [], }] } var cfgB = { title: { text: 'Spread Chart' }, xAxis: { type: 'datetime' }, series: [{ name: 'Spread', type: 'column', data: [], }] } var cfgC = { __isStock: false, title: { text: 'Pie Chart' }, series: [{ type: 'pie', name: 'one', data: [ ["A", 25], ["B", 25], ["C", 25], ["D", 25], // After specifying the initial data, there is no need to use the add function to // update; you can update the data series simply by modifying the chart configuration // directly. ] }] }; var cfgD = { extension: { layout: 'single', col: 8, // Specify the number of units the width occupies; the total number of units is 12 height: '300px', }, title: { text: 'Order Book Chart' }, xAxis: { type: 'datetime' }, series: [{ name: 'Bid 1', data: [], }, { name: 'Ask 1', data: [], }] } var cfgE = { __isStock: false, extension: { layout: 'single', col: 4, height: '300px', }, title: { text: 'Pie Chart 2' }, series: [{ type: 'pie', name: 'one', data: [ ["A", 25], ["B", 25], ["C", 25], ["D", 25], ] }] }; var chart = Chart([cfgA, cfgB, cfgC, cfgD, cfgE]); chart.reset() // Append a data point to the pie chart; add can only update data points that were added via // the add method, built-in data points cannot be updated later chart.add(3, { name: "ZZ", y: Math.random() * 100 }); while (true) { Sleep(1000) var ticker = exchange.GetTicker() if (!ticker) { continue; } var diff = ticker.Sell - ticker.Buy cfgA.subtitle = { text: 'Bid ' + ticker.Buy + ', Ask ' + ticker.Sell, }; cfgB.subtitle = { text: 'Spread ' + diff, }; chart.add([0, [new Date().getTime(), ticker.Buy]]); chart.add([1, [new Date().getTime(), ticker.Sell]]); // Equivalent to updating the first data series of the second chart chart.add([2, [new Date().getTime(), diff]]); chart.add(4, [new Date().getTime(), ticker.Buy]); chart.add(5, [new Date().getTime(), ticker.Buy]); cfgC.series[0].data[0][1] = Math.random() * 100; cfgE.series[0].data[0][1] = Math.random() * 100; // update is actually equivalent to resetting the chart configuration chart.update([cfgA, cfgB, cfgC, cfgD, cfgE]); } }pythonimport random import time def main(): cfgA = { "extension" : { "layout" : "single", "height" : 300, "col" : 8 }, "title" : { "text" : "Order Book Chart" }, "xAxis" : { "type" : "datetime" }, "series" : [{ "name" : "Bid 1", "data" : [] }, { "name" : "Ask 1", "data" : [] }] } cfgB = { "title" : { "text" : "Spread Chart" }, "xAxis" : { "type" : "datetime", }, "series" : [{ "name" : "Spread", "type" : "column", "data" : [] }] } cfgC = { "__isStock" : False, "title" : { "text" : "Pie Chart" }, "series" : [{ "type" : "pie", "name" : "one", "data" : [ ["A", 25], ["B", 25], ["C", 25], ["D", 25], ] }] } cfgD = { "extension" : { "layout" : "single", "col" : 8, "height" : "300px" }, "title" : { "text" : "Order Book Chart" }, "series" : [{ "name" : "Bid 1", "data" : [] }, { "name" : "Ask 1", "data" : [] }] } cfgE = { "__isStock" : False, "extension" : { "layout" : "single", "col" : 4, "height" : "300px" }, "title" : { "text" : "Pie Chart 2" }, "series" : [{ "type" : "pie", "name" : "one", "data" : [ ["A", 25], ["B", 25], ["C", 25], ["D", 25] ] }] } chart = Chart([cfgA, cfgB, cfgC, cfgD, cfgE]) chart.reset() chart.add(3, { "name" : "ZZ", "y" : random.random() * 100 }) while True: Sleep(1000) ticker = exchange.GetTicker() if not ticker : continue diff = ticker["Sell"] - ticker["Buy"] cfgA["subtitle"] = { "text" : "Bid " + str(ticker["Buy"]) + " Ask " + str(ticker["Sell"]) } cfgB["subtitle"] = { "text" : "Spread " + str(diff) } chart.add(0, [time.time() * 1000, ticker["Buy"]]) chart.add(1, [time.time() * 1000, ticker["Sell"]]) chart.add(2, [time.time() * 1000, diff]) chart.add(4, [time.time() * 1000, ticker["Buy"]]) chart.add(5, [time.time() * 1000, ticker["Buy"]]) cfgC["series"][0]["data"][0][1] = random.random() * 100 cfgE["series"][0]["data"][0][1] = random.random() * 100 chart.update([cfgA, cfgB, cfgC, cfgD, cfgE])rustfn main() { // In Rust, the chart configuration is a JSON string; variable parts are represented with // placeholders, which are replaced when updating to rebuild the configuration let cfg_a_tpl = r#"{ "extension": { "layout": "single", "height": 300 }, "title": {"text": "Order Book Chart"}, "subtitle": {"text": "__SUBTITLE__"}, "xAxis": {"type": "datetime"}, "series": [{"name": "Bid 1", "data": []}, {"name": "Ask 1", "data": []}] }"#; let cfg_b_tpl = r#"{ "title": {"text": "Spread Chart"}, "subtitle": {"text": "__SUBTITLE__"}, "xAxis": {"type": "datetime"}, "series": [{"name": "Spread", "type": "column", "data": []}] }"#; let cfg_c_tpl = r#"{ "__isStock": false, "title": {"text": "Pie Chart"}, "series": [{ "type": "pie", "name": "one", "data": [["A", __Y__], ["B", 25], ["C", 25], ["D", 25]] }] }"#; let cfg_d = r#"{ "extension": { "layout": "single", "col": 8, "height": "300px" }, "title": {"text": "Order Book Chart"}, "xAxis": {"type": "datetime"}, "series": [{"name": "Bid 1", "data": []}, {"name": "Ask 1", "data": []}] }"#; let cfg_e_tpl = r#"{ "__isStock": false, "extension": { "layout": "single", "col": 4, "height": "300px" }, "title": {"text": "Pie Chart 2"}, "series": [{ "type": "pie", "name": "one", "data": [["A", __Y__], ["B", 25], ["C", 25], ["D", 25]] }] }"#; let cfg_a = cfg_a_tpl.replace("__SUBTITLE__", ""); let cfg_b = cfg_b_tpl.replace("__SUBTITLE__", ""); let cfg_c = cfg_c_tpl.replace("__Y__", "25"); let cfg_e = cfg_e_tpl.replace("__Y__", "25"); let chart = Chart::new(&format!("[{},{},{},{},{}]", cfg_a, cfg_b, cfg_c, cfg_d, cfg_e)); chart.reset(0); // Append a data point to the pie chart; add can only update data points that were added via the // add method, built-in data points cannot be updated later let y = (UnixNano() % 100) as f64; // Use the timestamp to simulate a random number chart.add(3, &format!(r#"{{"name": "ZZ", "y": {}}}"#, y), -1); loop { Sleep(1000); let ticker = match exchange.GetTicker(None) { Ok(t) => t, Err(_) => continue, }; let diff = ticker.Sell - ticker.Buy; let cfg_a = cfg_a_tpl.replace("__SUBTITLE__", &format!("Bid {}, Ask {}", ticker.Buy, ticker.Sell)); let cfg_b = cfg_b_tpl.replace("__SUBTITLE__", &format!("Spread {}", diff)); let now = Unix() * 1000; chart.add(0, &format!("[{}, {}]", now, ticker.Buy), -1); chart.add(1, &format!("[{}, {}]", now, ticker.Sell), -1); // Equivalent to updating the first data series of the second chart chart.add(2, &format!("[{}, {}]", now, diff), -1); chart.add(4, &format!("[{}, {}]", now, ticker.Buy), -1); chart.add(5, &format!("[{}, {}]", now, ticker.Buy), -1); let cfg_c = cfg_c_tpl.replace("__Y__", &format!("{}", (UnixNano() % 100) as f64)); let cfg_e = cfg_e_tpl.replace("__Y__", &format!("{}", (UnixNano() % 100) as f64)); // update is actually equivalent to resetting the chart configuration chart.update(&format!("[{},{},{},{},{}]", cfg_a, cfg_b, cfg_c, cfg_d, cfg_e)); } } -
A simple charting example.
javascript// In JavaScript, chart is an object; before calling the Chart function, we need to declare an // object variable chart used to configure the chart var chart = { // This field marks whether the chart is an ordinary chart; interested readers can change it to // false and run it to see the effect __isStock: true, // Tooltip tooltip: {xDateFormat: '%Y-%m-%d %H:%M:%S, %A'}, // Title title : { text : 'Spread Analysis Chart'}, // Range selector rangeSelector: { buttons: [{type: 'hour',count: 1, text: '1h'}, {type: 'hour',count: 3, text: '3h'}, {type: 'hour', count: 8, text: '8h'}, {type: 'all',text: 'All'}], selected: 0, inputEnabled: false }, // Horizontal axis (i.e., the x-axis); the currently set type is: datetime xAxis: { type: 'datetime'}, // Vertical axis (i.e., the y-axis); by default the values are automatically adjusted according // to the data size yAxis : { // Title title: {text: 'Spread'}, // Whether to enable the right-side vertical axis opposite: false }, // Data series; this property holds each data series (line charts, candlestick charts, labels, // etc.) series : [ // Index 0; the data array stores the data for the series at this index {name : "line1", id : "Line 1,buy1Price", data : []}, // Index 1; dashStyle: 'shortdash' is set, i.e., it is set as a dashed line {name : "line2", id : "Line 2,lastPrice", dashStyle : 'shortdash', data : []} ] } function main(){ // Call the Chart function to initialize the chart var ObjChart = Chart(chart) // Clear ObjChart.reset() while(true){ // Get the timestamp of this poll (i.e., a millisecond-level timestamp), used to determine // the X-axis position written to the chart var nowTime = new Date().getTime() // Get the ticker data var ticker = _C(exchange.GetTicker) // Get the best bid price from the return value of the ticker data var buy1Price = ticker.Buy // Get the last traded price; to prevent the two lines from overlapping, add 1 to it here var lastPrice = ticker.Last + 1 // Pass the timestamp as the X value and the best bid price as the Y value into the data // series at index 0 ObjChart.add(0, [nowTime, buy1Price]) // Same as above ObjChart.add(1, [nowTime, lastPrice]) Sleep(2000) } }pythonimport time chart = { "__isStock" : True, "tooltip" : {"xDateFormat" : "%Y-%m-%d %H:%M:%S, %A"}, "title" : {"text" : "Spread Analysis Chart"}, "rangeSelector" : { "buttons" : [{"type": "hour", "count": 1, "text": "1h"}, {"type": "hour", "count": 3, "text": "3h"}, {"type": "hour", "count": 8, "text": "8h"}, {"type": "all", "text": "All"}], "selected": 0, "inputEnabled": False }, "xAxis": {"type": "datetime"}, "yAxis": { "title": {"text": "Spread"}, "opposite": False }, "series": [{ "name": "line1", "id": "Line 1,buy1Price", "data": [] }, { "name": "line2", "id": "Line 2,lastPrice", "dashStyle": "shortdash", "data": [] }] } def main(): ObjChart = Chart(chart) ObjChart.reset() while True: nowTime = time.time() * 1000 ticker = exchange.GetTicker() buy1Price = ticker["Buy"] lastPrice = ticker["Last"] + 1 ObjChart.add(0, [nowTime, buy1Price]) ObjChart.add(1, [nowTime, lastPrice]) Sleep(2000)rustfn main() { // In Rust, the chart configuration is a JSON string; before calling the Chart::new function, // define the chart configuration first let chart = r#"{ "__isStock": true, "tooltip": {"xDateFormat": "%Y-%m-%d %H:%M:%S, %A"}, "title": {"text": "Spread Analysis Chart"}, "rangeSelector": { "buttons": [{"type": "hour", "count": 1, "text": "1h"}, {"type": "hour", "count": 3, "text": "3h"}, {"type": "hour", "count": 8, "text": "8h"}, {"type": "all", "text": "All"}], "selected": 0, "inputEnabled": false }, "xAxis": {"type": "datetime"}, "yAxis": { "title": {"text": "Spread"}, "opposite": false }, "series": [ {"name": "line1", "id": "Line 1,buy1Price", "data": []}, {"name": "line2", "id": "Line 2,lastPrice", "dashStyle": "shortdash", "data": []} ] }"#; // Call the Chart::new function to initialize the chart let obj_chart = Chart::new(chart); // Clear obj_chart.reset(0); loop { // Get the timestamp of this poll (i.e., a millisecond-level timestamp), used to determine // the X-axis position written to the chart let now_time = Unix() * 1000; // Get the ticker data let ticker = _C!(exchange.GetTicker(None)); // Get the best bid price from the return value of the ticker data let buy1_price = ticker.Buy; // Get the last traded price; to prevent the two lines from overlapping, add 1 to it here let last_price = ticker.Last + 1.0; // Pass the timestamp as the X value and the best bid price as the Y value into the data // series at index 0 obj_chart.add(0, &format!("[{}, {}]", now_time, buy1_price), -1); // Same as above obj_chart.add(1, &format!("[{}, {}]", now_time, last_price), -1); Sleep(2000); } } -
Example of drawing trigonometric function curves.
javascript// Configuration object used to initialize the chart var chart = { // Chart title title: {text: "Line value triggers plotLines value"}, // Y-axis related settings yAxis: { // A horizontal line perpendicular to the Y-axis, used as a trigger line; this is an array // of structs, and multiple trigger lines can be set plotLines: [{ // The value of the trigger line; the line will be displayed at the corresponding // numerical position value: 0, // Set the color of the trigger line color: 'red', // Line width width: 2, // The displayed label label: { // Label text text: 'Trigger Value', // Center-align the label align: 'center' } }] }, // X-axis related settings; here the type is set to a datetime axis xAxis: {type: "datetime"}, series: [ {name: "sin", type: "spline", data: []}, // Data series; multiple can be set and controlled via array indices {name: "cos", type: "spline", data: []} ] } function main(){ // Pi var pi = 3.1415926535897 // Variable used to record the timestamp var time = 0 // Angle var angle = 0 // The y-coordinate value, used to receive the sine or cosine value var y = 0 // Call the API interface to initialize the chart using the chart object var objChart = Chart(chart) // Clear the chart during initialization objChart.reset() // Set the value of the trigger line to 1 chart.yAxis.plotLines[0].value = 1 // Loop while(true){ // Get the timestamp of the current moment time = new Date().getTime() // Every 5 seconds, increase the angle by 5 degrees and calculate the sine value y = Math.sin(angle * 2 * pi / 360) // Write the calculated y value into the data series at the corresponding index in the // chart; the first parameter of the add function is the specified data series index objChart.add(0, [time, y]) // Calculate the cosine value y = Math.cos(angle * 2 * pi / 360) objChart.add(1, [time, y]) // Increase by 5 degrees angle += 5 // Pause for 5 seconds to avoid plotting too frequently and data growing too fast Sleep(5000) } }pythonimport math import time chart = { "title": {"text": "Line value triggers plotLines value"}, "yAxis": { "plotLines": [{ "value": 0, "color": "red", "width": 2, "label": { "text": "Trigger Value", "align": "center" } }] }, "xAxis": {"type": "datetime"}, "series": [{"name": "sin", "type": "spline", "data": []}, {"name": "cos", "type": "spline", "data": []}] } def main(): pi = 3.1415926535897 ts = 0 angle = 0 y = 0 objChart = Chart(chart) objChart.reset() chart["yAxis"]["plotLines"][0]["value"] = 1 while True: ts = time.time() * 1000 y = math.sin(angle * 2 * pi / 360) objChart.add(0, [ts, y]) y = math.cos(angle * 2 * pi / 360) objChart.add(1, [ts, y]) angle += 5 Sleep(5000)rustfn main() { // JSON configuration string used to initialize the chart; the trigger line value is set // directly to 1 in the configuration let chart = r#"{ "title": {"text": "Line value triggers plotLines value"}, "yAxis": { "plotLines": [{ "value": 1, "color": "red", "width": 2, "label": { "text": "Trigger Value", "align": "center" } }] }, "xAxis": {"type": "datetime"}, "series": [{"name": "sin", "type": "spline", "data": []}, {"name": "cos", "type": "spline", "data": []}] }"#; // Pi let pi = 3.1415926535897_f64; // Angle let mut angle = 0.0_f64; // Call the API interface to initialize the chart using the chart configuration let obj_chart = Chart::new(chart); // Clear the chart during initialization obj_chart.reset(0); // Loop loop { // Get the millisecond timestamp of the current moment let ts = Unix() * 1000; // Increase the angle by 5 degrees and calculate the sine value let mut y = (angle * 2.0 * pi / 360.0).sin(); // Write the calculated y value into the data series at the corresponding index in the // chart; the first parameter of the add function is the specified data series index obj_chart.add(0, &format!("[{}, {}]", ts, y), -1); // Calculate the cosine value y = (angle * 2.0 * pi / 360.0).cos(); obj_chart.add(1, &format!("[{}, {}]", ts, y), -1); // Increase by 5 degrees angle += 5.0; // Pause for 5 seconds to avoid plotting too frequently and data growing too fast Sleep(5000); } } -
A complex example using a mixed chart.
javascript/*backtest start: 2020-03-11 00:00:00 end: 2020-04-09 23:59:00 period: 1d exchanges: [{"eid":"Bitfinex","currency":"BTC_USD"}] */ var chartCfg = { subtitle: { text: "subtitle", }, yAxis: [{ height: "40%", lineWidth: 2, title: { text: 'PnL', }, tickPixelInterval: 20, minorGridLineWidth: 1, minorTickWidth: 0, opposite: true, labels: { align: "right", x: -3, } }, { title: { text: 'Profit', }, top: "42%", height: "18%", offset: 0, lineWidth: 2 }, { title: { text: 'Vol', }, top: '62%', height: '18%', offset: 0, lineWidth: 2 }, { title: { text: 'Asset', }, top: '82%', height: '18%', offset: 0, lineWidth: 2 }], series: [{ name: 'PnL', data: [], id: 'primary', tooltip: { xDateFormat: '%Y-%m-%d %H:%M:%S' }, yAxis: 0 }, { type: 'column', lineWidth: 2, name: 'Profit', data: [], yAxis: 1, }, { type: 'column', name: 'Trade', data: [], yAxis: 2 }, { type: 'area', step: true, lineWidth: 0, name: 'Long', data: [], yAxis: 2 }, { type: 'area', step: true, lineWidth: 0, name: 'Short', data: [], yAxis: 2 }, { type: 'line', step: true, color: '#5b4b00', name: 'Asset', data: [], yAxis: 3 }, { type: 'pie', innerSize: '70%', name: 'Random', data: [], center: ['3%', '6%'], size: '15%', dataLabels: { enabled: false }, startAngle: -90, endAngle: 90, }], }; function main() { let c = Chart(chartCfg); let preTicker = null; while (true) { let t = exchange.GetTicker(); c.add(0, [t.Time, t.Last]); // PnL c.add(1, [t.Time, preTicker ? t.Last - preTicker.Last : 0]); // profit let r = Math.random(); var pos = parseInt(t.Time/86400); c.add(2, [t.Time, pos/2]); // Vol c.add(3, [t.Time, r > 0.8 ? pos : null]); // Long c.add(4, [t.Time, r < 0.8 ? -pos : null]); // Short c.add(5, [t.Time, Math.random() * 100]); // Asset // update pie chartCfg.series[chartCfg.series.length-1].data = [ ["A", Math.random()*100], ["B", Math.random()*100], ]; c.update(chartCfg) preTicker = t; } }python'''backtest start: 2020-03-11 00:00:00 end: 2020-04-09 23:59:00 period: 1d exchanges: [{"eid":"Bitfinex","currency":"BTC_USD"}] ''' import random chartCfg = { "subtitle": { "text": "subtitle" }, "yAxis": [{ "height": "40%", "lineWidth": 2, "title": { "text": 'PnL' }, "tickPixelInterval": 20, "minorGridLineWidth": 1, "minorTickWidth": 0, "opposite": True, "labels": { "align": "right", "x": -3 } }, { "title": { "text": 'Profit' }, "top": "42%", "height": "18%", "offset": 0, "lineWidth": 2 }, { "title": { "text": 'Vol' }, "top": '62%', "height": '18%', "offset": 0, "lineWidth": 2 }, { "title": { "text": 'Asset' }, "top": '82%', "height": '18%', "offset": 0, "lineWidth": 2 }], "series": [{ "name": 'PnL', "data": [], "id": 'primary', "tooltip": { "xDateFormat": '%Y-%m-%d %H:%M:%S' }, "yAxis": 0 }, { "type": 'column', "lineWidth": 2, "name": 'Profit', "data": [], "yAxis": 1 }, { "type": 'column', "name": 'Trade', "data": [], "yAxis": 2 }, { "type": 'area', "step": True, "lineWidth": 0, "name": 'Long', "data": [], "yAxis": 2 }, { "type": 'area', "step": True, "lineWidth": 0, "name": 'Short', "data": [], "yAxis": 2 }, { "type": 'line', "step": True, "color": '#5b4b00', "name": 'Asset', "data": [], "yAxis": 3 }, { "type": 'pie', "innerSize": '70%', "name": 'Random', "data": [], "center": ['3%', '6%'], "size": '15%', "dataLabels": { "enabled": False }, "startAngle": -90, "endAngle": 90 }] } def main(): c = Chart(chartCfg) preTicker = None while True: t = exchange.GetTicker() c.add(0, [t["Time"], t["Last"]]) profit = t["Last"] - preTicker["Last"] if preTicker else 0 c.add(1, [t["Time"], profit]) r = random.random() pos = t["Time"] / 86400 c.add(2, [t["Time"], pos / 2]) long = pos if r > 0.8 else None c.add(3, [t["Time"], long]) short = -pos if r < 0.8 else None c.add(4, [t["Time"], short]) c.add(5, [t["Time"], random.random() * 100]) # update pie chartCfg["series"][len(chartCfg["series"]) - 1]["data"] = [ ["A", random.random() * 100], ["B", random.random() * 100] ] c.update(chartCfg) preTicker = trust/*backtest start: 2020-03-11 00:00:00 end: 2020-04-09 23:59:00 period: 1d exchanges: [{"eid":"Bitfinex","currency":"BTC_USD"}] */ fn main() { // In Rust, the chart configuration is represented as a JSON string; the pie chart data is // marked with the placeholder __PIE_DATA__, which is replaced to rebuild the configuration on // update let chart_cfg_tpl = r##"{ "subtitle": {"text": "subtitle"}, "yAxis": [{ "height": "40%", "lineWidth": 2, "title": {"text": "PnL"}, "tickPixelInterval": 20, "minorGridLineWidth": 1, "minorTickWidth": 0, "opposite": true, "labels": {"align": "right", "x": -3} }, { "title": {"text": "Profit"}, "top": "42%", "height": "18%", "offset": 0, "lineWidth": 2 }, { "title": {"text": "Vol"}, "top": "62%", "height": "18%", "offset": 0, "lineWidth": 2 }, { "title": {"text": "Asset"}, "top": "82%", "height": "18%", "offset": 0, "lineWidth": 2 }], "series": [{ "name": "PnL", "data": [], "id": "primary", "tooltip": {"xDateFormat": "%Y-%m-%d %H:%M:%S"}, "yAxis": 0 }, { "type": "column", "lineWidth": 2, "name": "Profit", "data": [], "yAxis": 1 }, { "type": "column", "name": "Trade", "data": [], "yAxis": 2 }, { "type": "area", "step": true, "lineWidth": 0, "name": "Long", "data": [], "yAxis": 2 }, { "type": "area", "step": true, "lineWidth": 0, "name": "Short", "data": [], "yAxis": 2 }, { "type": "line", "step": true, "color": "#5b4b00", "name": "Asset", "data": [], "yAxis": 3 }, { "type": "pie", "innerSize": "70%", "name": "Random", "data": __PIE_DATA__, "center": ["3%", "6%"], "size": "15%", "dataLabels": {"enabled": false}, "startAngle": -90, "endAngle": 90 }] }"##; let c = Chart::new(&chart_cfg_tpl.replace("__PIE_DATA__", "[]")); let mut pre_ticker: Option<Ticker> = None; loop { let t = exchange.GetTicker(None).unwrap(); c.add(0, &format!("[{}, {}]", t.Time, t.Last), -1); // PnL let profit = if let Some(p) = &pre_ticker { t.Last - p.Last } else { 0.0 }; c.add(1, &format!("[{}, {}]", t.Time, profit), -1); // profit // use the timestamp to simulate a random number let r = (UnixNano() % 100) as f64 / 100.0; let pos = (t.Time / 86400) as f64; c.add(2, &format!("[{}, {}]", t.Time, pos / 2.0), -1); // Vol c.add(3, &format!("[{}, {}]", t.Time, if r > 0.8 { pos.to_string() } else { "null".to_string() }), -1); // Long c.add(4, &format!("[{}, {}]", t.Time, if r < 0.8 { (-pos).to_string() } else { "null".to_string() }), -1); // Short c.add(5, &format!("[{}, {}]", t.Time, (UnixNano() % 10000) as f64 / 100.0), -1); // Asset // update pie let pie = format!(r#"[["A", {}], ["B", {}]]"#, (UnixNano() % 100) as f64, (UnixNano() % 100) as f64); c.update(&chart_cfg_tpl.replace("__PIE_DATA__", &pie)); pre_ticker = Some(t); } } -
The
pietype chart does not have a time axis, so you need to update the chart configuration directly when updating the data. For example, in the code of the example above, after updating the data, simply callc.update(chartCfg)to refresh the chart, as shown below.javascript// update pie chartCfg.series[chartCfg.series.length-1].data = [ ["A", Math.random()*100], ["B", Math.random()*100], ]; c.update(chartCfg)python# update pie chartCfg["series"][len(chartCfg["series"]) - 1]["data"] = [ ["A", random.random() * 100], ["B", random.random() * 100] ] c.update(chartCfg)rust// update pie // In Rust the chart configuration is a JSON string; rebuild the configuration containing the new // data and then call update to refresh the chart let pie = format!(r#"[["A", {}], ["B", {}]]"#, (UnixNano() % 100) as f64, (UnixNano() % 100) as f64); c.update(&chart_cfg_tpl.replace("__PIE_DATA__", &pie));
Returns
| Type | Description |
object | A chart object, see |
Arguments
| Name | Type | Required | Description |
options | object / object array | Yes | Chart configuration. The |
See Also
Remarks
The chart object returned by Chart() has four methods, add(), reset(), update() and del(), to write data, clear data, update the configuration and delete a data series or the whole chart; their parameters are described in Chart-return.