Skip to content

Commit 05fdc75

Browse files
defkevDeviaVir
authored andcommitted
Web UI: Replace plotly.js with echarts (DeviaVir#1240)
* Web UI: Replace plotly.js with echarts This should drastically improve loading and response time of the dashboard with many datapoints. * Web UI: More * Limit initial zoom to 100 trades * Move candle to the back * Add plot for my_trades * Web UI: Move Volume behind candle * Web UI: Chart * increase dataZoom startValue to 500 trades * reduce left/right margin * hide Chinese tooltips * Web UI: Fix candlestick data order * Web UI: Fix profit not printed if 0
1 parent 4581bad commit 05fdc75

File tree

5 files changed

+172
-109
lines changed

5 files changed

+172
-109
lines changed

package.json

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@
4545
"convnetjs": "0.3.0",
4646
"counterup": "^1.0.2",
4747
"css-loader": "^0.28.7",
48+
"echarts": "^4.0.2",
4849
"ejs": "^2.5.7",
4950
"exports-loader": "^0.7.0",
5051
"expose-loader": "^0.7.4",
@@ -78,7 +79,6 @@
7879
"number-abbreviate": "^2.0.0",
7980
"numbro": "highvelocityspace/numbro",
8081
"path": "^0.12.7",
81-
"plotly.js": "^1.32.0",
8282
"poloniex.js": "0.0.8",
8383
"popper.js": "^1.12.9",
8484
"postcss-loader": "^2.0.9",
@@ -97,7 +97,6 @@
9797
"superagent": "^3.8.2",
9898
"talib": "^1.0.4",
9999
"timebucket": "^0.4.0",
100-
"transform-loader": "^0.2.4",
101100
"trend": "0.3.0",
102101
"url-loader": "^0.6.2",
103102
"uuid": "^3.1.0",

templates/dashboard.ejs

Lines changed: 156 additions & 92 deletions
Original file line numberDiff line numberDiff line change
@@ -164,19 +164,14 @@
164164
<div class="col-md-12 col-lg-12 col-sm-12 col-12">
165165
<div class="white-box">
166166
<h3 class="box-title"><%= exchange.name.toUpperCase() %> <%= asset.toUpperCase() %>/<%= currency.toUpperCase() %> Trade chart</h3>
167-
<div id="trades_plot" style="height: 505px;">
167+
<div id="trade_chart" style="height: 505px;">
168168
</div>
169-
<script src="assets-wp/plotly.bundle.js" charset="utf8"></script>
169+
<script src="/assets-wp/echarts.bundle.js" charset="utf8"</script>
170170
<script type="text/javascript">
171171
172172
function unpack(rows, key, offset) {
173173
return rows.map(function(row) {
174-
if (key == 'time') {
175-
// Plotly’s date format is 'yyyy-mm-dd HH:MM:SS.ssssss'
176-
return new Date(row.time - offset * 60000).toISOString().replace(/T/g, ' ').replace(/Z/g, '');
177-
} else {
178-
return row[key];
179-
}
174+
return { value: [ row.time - offset * 60000, row[key] ] };
180175
});
181176
}
182177
@@ -189,102 +184,171 @@
189184
var my_trades = tradeData.my_trades;
190185
var offset = tradeData.tz_offset;
191186
192-
var price = {
193-
type: "scatter",
194-
name: 'Price',
195-
mode: 'lines+markers',
196-
x: unpack(trades, 'time', offset),
197-
y: unpack(trades, 'price')
198-
};
199-
200-
var volume = {
201-
type: 'bar',
202-
name: 'Volume',
203-
yaxis: 'y2',
204-
opacity: '0.25',
205-
x: unpack(trades, 'time', offset),
206-
y: unpack(trades, 'size'),
207-
width: 3600*4
208-
};
209-
210-
var ohlc = {
211-
type: 'ohlc',
212-
name: 'OHLC',
213-
x: unpack(lookback, 'time', offset),
214-
open: unpack(lookback, 'open'),
215-
high: unpack(lookback, 'high'),
216-
low: unpack(lookback, 'low'),
217-
close: unpack(lookback, 'close')
218-
};
219-
220-
var data = [ price, volume, ohlc ];
187+
var trade_chart = echarts.init(document.getElementById('trade_chart'));
221188
222-
var lastTrade = new Date(price.x[price.x.length - 1]);
223-
lastTrade.setMinutes(lastTrade.getMinutes() + 1);
224-
var rangeEnd = new Date(lastTrade - ((new Date()).getTimezoneOffset() * 60000)).toISOString().replace(/T/g, ' ').replace(/Z/g, '');
225-
lastTrade.setMinutes(lastTrade.getMinutes() - 31);
226-
var rangeStart = new Date(lastTrade - ((new Date()).getTimezoneOffset() * 60000)).toISOString().replace(/T/g, ' ').replace(/Z/g, '');
189+
var lastTrade = trades[trades.length < 500 ? 0 : trades.length - 500].time;
190+
var rangeStart = lastTrade - offset * 60000;
227191
228-
var layout = {
229-
showlegend: false,
230-
xaxis: {
231-
range: [ rangeStart, rangeEnd ],
232-
rangeselector: {
233-
buttons: [
234-
{
235-
count: 5,
236-
label: '5m',
237-
step: 'minute',
238-
stepmode: 'todate'
239-
},
240-
{
241-
count: 30,
242-
label: '30m',
243-
step: 'minute',
244-
stepmode: 'todate'
245-
},
246-
{
247-
count: 1,
248-
label: '1h',
249-
step: 'hour',
250-
stepmode: 'backward'
251-
},
252-
{
253-
step: 'all'
192+
var options = {
193+
useUTC: true,
194+
grid: {
195+
left: 60,
196+
right: 60
197+
},
198+
xAxis: [
199+
{
200+
type: 'time',
201+
axisLabel: {
202+
formatter: function (value) {
203+
return echarts.format.formatTime('yyyy-MM-dd hh:mm:ss', value, true);
254204
}
255-
]
205+
}
206+
}
207+
],
208+
yAxis: [
209+
{
210+
name: 'Price',
211+
position: 'right',
212+
scale: true
256213
},
257-
rangeslider: {},
258-
type: 'date'
259-
},
260-
yaxis: {
261-
title: 'Price',
262-
overlaying: 'y2',
263-
side: 'right'
214+
{
215+
name: 'Volume',
216+
scale: true
217+
}
218+
],
219+
toolbox: {
220+
show: true,
221+
showTitle: false,
222+
feature: {
223+
dataZoom: {},
224+
restore: {},
225+
saveAsImage: {}
226+
}
264227
},
265-
yaxis2: {
266-
title: 'Volume',
267-
side: 'left'
228+
tooltip : {
229+
trigger: 'axis',
230+
axisPointer: {
231+
type: 'cross',
232+
}
268233
},
269-
annotations: []
234+
dataZoom: [
235+
{
236+
startValue: rangeStart
237+
},
238+
{
239+
type: 'inside'
240+
},
241+
],
242+
series: [
243+
{
244+
name: 'Price',
245+
type: 'line',
246+
data: unpack(trades, 'price', offset)
247+
},
248+
{
249+
name: 'Volume',
250+
type: 'bar',
251+
yAxisIndex: 1,
252+
z: 1,
253+
itemStyle: {
254+
opacity: 0.25
255+
},
256+
data: unpack(trades, 'size', offset)
257+
},
258+
{
259+
name: 'High',
260+
type: 'candlestick',
261+
z: 1,
262+
itemStyle: {
263+
color: 'rgba(40,167,69,0.5)', // bullish
264+
borderColor: '#28a745',
265+
color0: 'rgba(220,53,69,0.5)', // bearish
266+
borderColor0: '#dc3545'
267+
},
268+
data: []
269+
},
270+
{
271+
type: 'line',
272+
smooth: true,
273+
lineStyle: {
274+
type: 'dotted'
275+
},
276+
data: unpack(my_trades, 'price', offset),
277+
tooltip: {
278+
show: false
279+
}
280+
},
281+
{
282+
name: 'Buy',
283+
type: 'scatter',
284+
symbol: 'triangle',
285+
data: [],
286+
itemStyle: {
287+
color: '#28a745'
288+
},
289+
markPoint: {
290+
symbol: 'arrow',
291+
itemStyle: {
292+
color: '#28a745'
293+
},
294+
symbolOffset: [ 0, 10 ],
295+
data: []
296+
}
297+
},
298+
{
299+
name: 'Sell',
300+
type: 'scatter',
301+
symbol: 'triangle',
302+
symbolRotate: 180,
303+
data: [],
304+
itemStyle: {
305+
color: '#dc3545'
306+
},
307+
markPoint: {
308+
symbol: 'arrow',
309+
itemStyle: {
310+
color: '#dc3545'
311+
},
312+
symbolRotate: 180,
313+
symbolOffset: [ 0, -10 ],
314+
data: []
315+
}
316+
}
317+
]
270318
};
271319
272-
for (i = 0; i < my_trades.length; i++) {
273-
layout.annotations.push({
274-
x: new Date(my_trades[i].time - offset * 60000).toISOString().replace(/T/g, ' ').replace(/Z/g, ''),
275-
y: my_trades[i].price,
276-
xref: 'x',
277-
yref: 'y',
278-
text: my_trades[i].type,
279-
ax: 0,
280-
ay: -50
320+
for (i = 0; i < lookback.length; i++) {
321+
options.series[2].data.push({
322+
value: [ lookback[i].close_time - offset * 60000, lookback[i].open, lookback[i].close, lookback[i].low, lookback[i].high ] // OCLH -> OHLC
281323
});
282324
}
283325
284-
Plotly.newPlot('trades_plot', data, layout);
326+
for (i = 0; i < my_trades.length; i++) {
327+
if (my_trades[i].type == 'buy') {
328+
options.series[4].data.push({
329+
value: [ my_trades[i].time - offset * 60000, my_trades[i].price ]
330+
});
331+
options.series[4].markPoint.data.push({
332+
xAxis: my_trades[i].time - offset * 60000,
333+
yAxis: my_trades[i].price,
334+
value: 'Bought',
335+
});
336+
} else {
337+
options.series[5].data.push({
338+
value: [ my_trades[i].time - offset * 60000, my_trades[i].price ]
339+
});
340+
options.series[5].markPoint.data.push({
341+
xAxis: my_trades[i].time - offset * 60000,
342+
yAxis: my_trades[i].price,
343+
value: 'Sold',
344+
});
345+
}
346+
}
347+
348+
trade_chart.setOption(options);
285349
286350
window.onresize = function() {
287-
Plotly.Plots.resize('trades_plot');
351+
trade_chart.resize();
288352
};
289353
}
290354
};
@@ -355,7 +419,7 @@
355419
<td><span class="text-<% if (trade.slippage > 0) { %>danger<% } else { %>success<% } %>"><%= new Intl.NumberFormat("en-US", {style: "percent", useGrouping: false, minimumFractionDigits: 4, maximumFractionDigits: 4}).format(trade.slippage) %></span></td>
356420
<td><%= moment(trade.time).format('YYYY-MM-DD HH:mm:ss') %></td>
357421
<td><%= moment.duration(trade.execution_time).humanize() %></td>
358-
<td><% if (trade.profit) { %><span class="text-<% if(trade.profit < 0) { %>danger<% } else { %>success<% } %>"><%= new Intl.NumberFormat("en-US", {style: "percent", useGrouping: false, minimumFractionDigits: 2, maximumFractionDigits: 2}).format(trade.profit) %></span><% } else { %>-<% } %></td>
422+
<td><% if (trade.profit != null) { %><span class="text-<% if(trade.profit < 0) { %>danger<% } else { %>success<% } %>"><%= new Intl.NumberFormat("en-US", {style: "percent", useGrouping: false, minimumFractionDigits: 2, maximumFractionDigits: 2}).format(trade.profit) %></span><% } else { %>-<% } %></td>
359423
</tr>
360424
<% }); %>
361425
<% } %>

webpack-src/js/echarts.js

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
var echarts = require('echarts/lib/echarts');
2+
3+
require('echarts/lib/chart/line');
4+
require('echarts/lib/chart/bar');
5+
require('echarts/lib/chart/candlestick');
6+
require('echarts/lib/chart/scatter');
7+
require('echarts/lib/component/tooltip');
8+
require('echarts/lib/component/dataZoom');
9+
require('echarts/lib/component/markPoint');
10+
require('echarts/lib/component/toolbox');
11+
12+
module.exports = echarts;

webpack-src/js/plotly.js

Lines changed: 0 additions & 8 deletions
This file was deleted.

webpack.config.js

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ const webpack = require('webpack')
77
module.exports = {
88
entry: {
99
app: './webpack-src/js/app.js',
10-
plotly: './webpack-src/js/plotly.js'
10+
echarts: './webpack-src/js/echarts.js'
1111
},
1212
plugins: [
1313
new webpack.ProvidePlugin({
@@ -62,14 +62,10 @@ module.exports = {
6262
}]
6363
},
6464
{
65-
test: /\.js$/,
66-
use: 'transform-loader?plotly.js/tasks/util/compress_attributes.js',
67-
},
68-
{
69-
test: require.resolve('./webpack-src/js/plotly.js'),
65+
test: require.resolve('./webpack-src/js/echarts.js'),
7066
use: [{
7167
loader: 'expose-loader',
72-
options: 'Plotly'
68+
options: 'echarts'
7369
}]
7470
}
7571
],

0 commit comments

Comments
 (0)