|
164 | 164 | <div class="col-md-12 col-lg-12 col-sm-12 col-12">
|
165 | 165 | <div class="white-box">
|
166 | 166 | <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;"> |
168 | 168 | </div>
|
169 |
| - <script src="assets-wp/plotly.bundle.js" charset="utf8"></script> |
| 169 | + <script src="/assets-wp/echarts.bundle.js" charset="utf8"</script> |
170 | 170 | <script type="text/javascript">
|
171 | 171 |
|
172 | 172 | function unpack(rows, key, offset) {
|
173 | 173 | 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] ] }; |
180 | 175 | });
|
181 | 176 | }
|
182 | 177 |
|
|
189 | 184 | var my_trades = tradeData.my_trades;
|
190 | 185 | var offset = tradeData.tz_offset;
|
191 | 186 |
|
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')); |
221 | 188 |
|
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; |
227 | 191 |
|
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); |
254 | 204 | }
|
255 |
| - ] |
| 205 | + } |
| 206 | + } |
| 207 | + ], |
| 208 | + yAxis: [ |
| 209 | + { |
| 210 | + name: 'Price', |
| 211 | + position: 'right', |
| 212 | + scale: true |
256 | 213 | },
|
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 | + } |
264 | 227 | },
|
265 |
| - yaxis2: { |
266 |
| - title: 'Volume', |
267 |
| - side: 'left' |
| 228 | + tooltip : { |
| 229 | + trigger: 'axis', |
| 230 | + axisPointer: { |
| 231 | + type: 'cross', |
| 232 | + } |
268 | 233 | },
|
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 | + ] |
270 | 318 | };
|
271 | 319 |
|
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 |
281 | 323 | });
|
282 | 324 | }
|
283 | 325 |
|
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); |
285 | 349 |
|
286 | 350 | window.onresize = function() {
|
287 |
| - Plotly.Plots.resize('trades_plot'); |
| 351 | + trade_chart.resize(); |
288 | 352 | };
|
289 | 353 | }
|
290 | 354 | };
|
|
355 | 419 | <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>
|
356 | 420 | <td><%= moment(trade.time).format('YYYY-MM-DD HH:mm:ss') %></td>
|
357 | 421 | <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> |
359 | 423 | </tr>
|
360 | 424 | <% }); %>
|
361 | 425 | <% } %>
|
|
0 commit comments