@millistream/millistream-widgets 1.0.2 → 1.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/millistream-widgets.js +396 -75
- package/package.json +1 -1
package/millistream-widgets.js
CHANGED
|
@@ -6,6 +6,7 @@ function Milli_Chart(settings) {
|
|
|
6
6
|
_this.scaleinfoY = {};
|
|
7
7
|
_this.scaleinfoY2 = {};
|
|
8
8
|
_this.instruments = [];
|
|
9
|
+
_this.movingAverage = [];
|
|
9
10
|
_this.settings = {
|
|
10
11
|
adjusted: true,
|
|
11
12
|
autodraw: true,
|
|
@@ -59,7 +60,8 @@ function Milli_Chart(settings) {
|
|
|
59
60
|
arr: [],
|
|
60
61
|
map: new Map()
|
|
61
62
|
};
|
|
62
|
-
|
|
63
|
+
var m_analyzisMethod = new Map();
|
|
64
|
+
var m_analyzisIndex = 0;
|
|
63
65
|
var m_resizing = {
|
|
64
66
|
resizing: false,
|
|
65
67
|
width: 0,
|
|
@@ -191,19 +193,6 @@ function Milli_Chart(settings) {
|
|
|
191
193
|
// Discard the time and time-zone information.
|
|
192
194
|
const utc1 = Date.UTC(a.getFullYear(), a.getMonth(), a.getDate());
|
|
193
195
|
const utc2 = Date.UTC(b.getFullYear(), b.getMonth(), b.getDate());
|
|
194
|
-
/*var start = new Date(utc1);
|
|
195
|
-
var end = new Date(utc2);
|
|
196
|
-
var days = 0;
|
|
197
|
-
console.log(start, end, a, b);
|
|
198
|
-
while (start < end) {
|
|
199
|
-
console.log(start, end);
|
|
200
|
-
if (start.getDay() != 0 && start.getDay() != 6)
|
|
201
|
-
days++;
|
|
202
|
-
start = new Date(start.getTime() + 86400000);
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
console.log(days, Math.floor((utc2 - utc1) / 86400000));
|
|
206
|
-
return days;*/
|
|
207
196
|
return Math.floor((utc2 - utc1) / 86400000); // ms per day
|
|
208
197
|
}
|
|
209
198
|
|
|
@@ -422,7 +411,7 @@ function Milli_Chart(settings) {
|
|
|
422
411
|
var data = _this.instruments[s][_this.scaleinfoY.type];
|
|
423
412
|
if (_this.scaleinfoY.type != 'history') {
|
|
424
413
|
if (_this.settings.chartlen == '1d' || _this.settings.chartlen == '0d' && !m_zoom.mousedown.timestamp) {
|
|
425
|
-
firstvalue = parseFloat(_this.instruments[s].closeprice1d);
|
|
414
|
+
firstvalue = parseFloat(_this.instruments[s].closeprice1d) * _this.instruments[s].factor;
|
|
426
415
|
}
|
|
427
416
|
}
|
|
428
417
|
var quantity = 0;
|
|
@@ -434,6 +423,7 @@ function Milli_Chart(settings) {
|
|
|
434
423
|
quantity = data[i].quantity;
|
|
435
424
|
}
|
|
436
425
|
if (data[i].timestamp < _this.scaleinfoX.startTimeStamp) {
|
|
426
|
+
if (_this.scaleinfoY.type == 'history') firstvalue = price;
|
|
437
427
|
continue;
|
|
438
428
|
}
|
|
439
429
|
if (data[i].timestamp > _this.scaleinfoX.endTimeStamp) {
|
|
@@ -446,11 +436,11 @@ function Milli_Chart(settings) {
|
|
|
446
436
|
}
|
|
447
437
|
|
|
448
438
|
if (firstvalue == null) {
|
|
449
|
-
if (_this.scaleinfoY.type == 'history')
|
|
439
|
+
if (_this.scaleinfoY.type == 'history') {
|
|
450
440
|
firstvalue = price;
|
|
451
|
-
else {
|
|
441
|
+
} else {
|
|
452
442
|
if (isToday(new Date(data[i].timestamp)) && !m_zoom.mousedown.timestamp) {
|
|
453
|
-
firstvalue = parseFloat(_this.instruments[s].closeprice1d);
|
|
443
|
+
firstvalue = parseFloat(_this.instruments[s].closeprice1d) * _this.instruments[s].factor;
|
|
454
444
|
} else
|
|
455
445
|
firstvalue = price;
|
|
456
446
|
}
|
|
@@ -465,7 +455,7 @@ function Milli_Chart(settings) {
|
|
|
465
455
|
if (_this.scaleinfoY.highLowerChart == null || _this.scaleinfoY.highLowerChart < quantity) _this.scaleinfoY.highLowerChart = quantity;
|
|
466
456
|
}
|
|
467
457
|
if (_this.settings.chartlen == '1d' || _this.settings.chartlen == '0d') { // if closeprice is used calch high/low on it
|
|
468
|
-
var cp = parseFloat(_this.instruments[s].closeprice1d);
|
|
458
|
+
var cp = parseFloat(_this.instruments[s].closeprice1d) * _this.instruments[s].factor;
|
|
469
459
|
if (_this.scaleinfoY.lowValue > cp) _this.scaleinfoY.lowValue = cp;
|
|
470
460
|
else
|
|
471
461
|
if (_this.scaleinfoY.highValue < cp) _this.scaleinfoY.highValue = cp;
|
|
@@ -481,6 +471,30 @@ function Milli_Chart(settings) {
|
|
|
481
471
|
_this.scaleinfoY.lowValue -= 1;
|
|
482
472
|
_this.scaleinfoY.highValue += 1;
|
|
483
473
|
}
|
|
474
|
+
// do we have any analyzis we need to take into account
|
|
475
|
+
|
|
476
|
+
for (const [key, a] of m_analyzisMethod.entries()) {
|
|
477
|
+
var data;
|
|
478
|
+
if (_this.scaleinfoY.type == 'history') data = a.history;
|
|
479
|
+
else data = a.trades;
|
|
480
|
+
for (var i = 0; i < data.length; i++) {
|
|
481
|
+
if (data[i].timestamp < _this.scaleinfoX.startTimeStamp) {
|
|
482
|
+
continue;
|
|
483
|
+
}
|
|
484
|
+
if (data[i].timestamp > _this.scaleinfoX.endTimeStamp) {
|
|
485
|
+
break;
|
|
486
|
+
}
|
|
487
|
+
if (typeof data[i].datapoints !== 'undefined') {
|
|
488
|
+
for (var x = 0; x < data[i].datapoints.length; x++) {
|
|
489
|
+
if (data[i].datapoints[x] < _this.scaleinfoY.lowValue) _this.scaleinfoY.lowValue = data[i].datapoints[x];
|
|
490
|
+
else
|
|
491
|
+
if (data[i].datapoints[x] > _this.scaleinfoY.highValue) _this.scaleinfoY.highValue = data[i].datapoints[x];
|
|
492
|
+
}
|
|
493
|
+
}
|
|
494
|
+
if (data[i].price < _this.scaleinfoY.lowValue) _this.scaleinfoY.lowValue = data[i].price;
|
|
495
|
+
if (data[i].price > _this.scaleinfoY.highValue) _this.scaleinfoY.highValue = data[i].price;
|
|
496
|
+
}
|
|
497
|
+
}
|
|
484
498
|
return 1;
|
|
485
499
|
}
|
|
486
500
|
|
|
@@ -800,7 +814,6 @@ function Milli_Chart(settings) {
|
|
|
800
814
|
_this.scaleinfoX.days = getNumberOfDays(starttime, endtime);
|
|
801
815
|
_this.scaleinfoX.lineLength = m_chartspaces.chart.right - m_chartspaces.chart.left;
|
|
802
816
|
var datesize = new Date('2888-12-28'); // bredaste datum jag kan komma på
|
|
803
|
-
//_this.scaleinfoX.itemwidth = getStringWidth(m_ctx, '88:88') * 2; // kolla rätt format en 8a för varje tecken
|
|
804
817
|
_this.scaleinfoX.itemwidth = getStringWidth(m_ctx, formatDate(datesize, _this.settings.dateformat)) * 2; // kolla rätt format en 8a för varje tecken
|
|
805
818
|
|
|
806
819
|
var maxLegendItems = _this.scaleinfoX.lineLength / (_this.scaleinfoX.itemwidth * 2);
|
|
@@ -875,7 +888,6 @@ function Milli_Chart(settings) {
|
|
|
875
888
|
}
|
|
876
889
|
}
|
|
877
890
|
if (draw) {
|
|
878
|
-
//drawXAxisGridlines({ 'x': x, y: m_canvas.height - m_chartCss.marginBottom });
|
|
879
891
|
drawXAxisGridlines({ 'x': x, y: m_chartspaces.chart.height - m_chartCss.marginBottom });
|
|
880
892
|
text = year;
|
|
881
893
|
if (_this.scaleinfoX.lineLength + m_chartspaces.chart.left > x - m_ctx.measureText(text).width) { // not to far right?
|
|
@@ -883,13 +895,12 @@ function Milli_Chart(settings) {
|
|
|
883
895
|
m_ctx.save(); // flip and write new years on top
|
|
884
896
|
var fontMetrix = m_ctx.measureText(text);
|
|
885
897
|
x = x + fontMetrix.actualBoundingBoxAscent + fontMetrix.actualBoundingBoxDescent + 2;
|
|
886
|
-
var y = m_chartspaces.chart.top;
|
|
898
|
+
var y = m_chartspaces.chart.top;
|
|
887
899
|
m_ctx.translate(x, y);
|
|
888
900
|
m_ctx.rotate(90 * Math.PI / 180);
|
|
889
901
|
m_ctx.fillText(text, 0, 0);
|
|
890
902
|
m_ctx.restore();
|
|
891
903
|
} else {
|
|
892
|
-
//m_ctx.fillText(text, x - (m_ctx.measureText(text).width / 2), m_canvas.height - m_chartCss.marginBottom + 10);
|
|
893
904
|
m_ctx.fillText(text, x - (m_ctx.measureText(text).width / 2), m_chartspaces.chart.height - m_chartCss.marginBottom + 10);
|
|
894
905
|
}
|
|
895
906
|
}
|
|
@@ -908,7 +919,6 @@ function Milli_Chart(settings) {
|
|
|
908
919
|
x = getXPosition(new Date(year.getFullYear() + '-07-01T00:00:00Z')); // 7
|
|
909
920
|
draw = true;
|
|
910
921
|
for (i = 0; i < legendItems.length; i++) {
|
|
911
|
-
//if (Math.abs(legendItems[i].x - x) < (getMaxDateWidth() / 2)) {
|
|
912
922
|
if (Math.abs(legendItems[i].x - x) < getMaxDateWidth()) {
|
|
913
923
|
draw = false;
|
|
914
924
|
}
|
|
@@ -1076,7 +1086,6 @@ function Milli_Chart(settings) {
|
|
|
1076
1086
|
else {
|
|
1077
1087
|
if (numticks < 2) numticks = 2;
|
|
1078
1088
|
x = _this.scaleinfoX.milliPerDay / numticks / 60000;
|
|
1079
|
-
//x = totalmilli / numticks / 60000;
|
|
1080
1089
|
if (totalmilli > 4 * 3600000) factor = 60; // 4 timmar
|
|
1081
1090
|
else
|
|
1082
1091
|
if (totalmilli > 2 * 3600000) factor = 30; // 2 timmar
|
|
@@ -1438,8 +1447,9 @@ function Milli_Chart(settings) {
|
|
|
1438
1447
|
return;
|
|
1439
1448
|
}
|
|
1440
1449
|
var highy = -1;
|
|
1441
|
-
var lowy = m_chartspaces.height;
|
|
1442
|
-
|
|
1450
|
+
var lowy = m_chartspaces.chart.height;
|
|
1451
|
+
var toolArray = [];
|
|
1452
|
+
for (x = 0; x < _this.instruments.length; x++) {
|
|
1443
1453
|
if (_this.instruments[x].insref != 0 && typeof obj.instruments[x] !== 'undefined') {
|
|
1444
1454
|
var instr = {};
|
|
1445
1455
|
instr.chartType = _this.scaleinfoY.type;
|
|
@@ -1475,16 +1485,6 @@ function Milli_Chart(settings) {
|
|
|
1475
1485
|
var pointerHeight = _this.instruments[x].toolTipPointer.offsetHeight + parseInt(pointerStyle.marginTop) + parseInt(pointerStyle.marginBottom);
|
|
1476
1486
|
_this.instruments[x].toolTip.innerHTML = ttip;
|
|
1477
1487
|
var posy = obj.instruments[x].y - (_this.instruments[x].toolTip.offsetHeight / 2);
|
|
1478
|
-
var tmp = Math.abs(posy - parseFloat(highy));
|
|
1479
|
-
var height = _this.instruments[x].toolTip.offsetHeight;
|
|
1480
|
-
if (tmp < height) {
|
|
1481
|
-
posy = parseFloat(highy) + height;
|
|
1482
|
-
}
|
|
1483
|
-
tmp = Math.abs(posy - parseFloat(lowy));
|
|
1484
|
-
if (tmp < 30) {
|
|
1485
|
-
// hur gör vi här? behövs det när vi sätter dom i ordning?
|
|
1486
|
-
//posy = parseFloat(highy) + 20;
|
|
1487
|
-
}
|
|
1488
1488
|
if (m_dataPoints.arr[i] + (_this.instruments[x].toolTip.offsetWidth * 1.5) > m_canvas.width || m_dataPoints.arr[i] + (_this.instruments[x].toolTip.offsetWidth * 1.5) > m_canvas.width) { // TODO +10 should be calculated better
|
|
1489
1489
|
// draw the hover to the left
|
|
1490
1490
|
_this.instruments[x].toolTip.style.left = (m_dataPoints.arr[i] - _this.instruments[x].toolTip.offsetWidth - (pointerWidth / 2)) + 1 + 'px';
|
|
@@ -1493,14 +1493,33 @@ function Milli_Chart(settings) {
|
|
|
1493
1493
|
_this.instruments[x].toolTip.style.left = (obj.instruments[x].x + (pointerWidth / 2)) + 'px';
|
|
1494
1494
|
}
|
|
1495
1495
|
_this.instruments[x].toolTip.style.top = posy + 'px';
|
|
1496
|
-
|
|
1496
|
+
toolArray.push({ top: (obj.instruments[x].y - (pointerHeight / 2)), instrument: x });
|
|
1497
1497
|
_this.instruments[x].toolTipPointer.style.left = (obj.instruments[x].x - (pointerWidth / 2)) + 1 + 'px'; // hmm plus 1??
|
|
1498
1498
|
_this.instruments[x].toolTipPointer.style.top = (obj.instruments[x].y - (pointerHeight / 2)) + 'px';
|
|
1499
1499
|
if (posy > highy) highy = posy;
|
|
1500
1500
|
if (posy < lowy) lowy = posy;
|
|
1501
1501
|
|
|
1502
|
+
} else {
|
|
1503
|
+
if (_this.instruments[x].toolTip) {
|
|
1504
|
+
_this.instruments[x].toolTip.parentNode.removeChild(_this.instruments[x].toolTip);
|
|
1505
|
+
_this.instruments[x].toolTipPointer.parentNode.removeChild(_this.instruments[x].toolTipPointer);
|
|
1506
|
+
_this.instruments[x].toolTip = undefined;
|
|
1507
|
+
_this.instruments[x].toolTipPointer = undefined;
|
|
1508
|
+
}
|
|
1502
1509
|
}
|
|
1503
1510
|
}
|
|
1511
|
+
toolArray.sort((a, b) => a.top - b.top);
|
|
1512
|
+
var lastTop = 0;
|
|
1513
|
+
for (x = 0; x < toolArray.length; x++) {
|
|
1514
|
+
if (x != 0) {
|
|
1515
|
+
//console.log(lastTop,_this.instruments[x-1].toolTip.offsetHeight , toolArray[x].top);
|
|
1516
|
+
if (lastTop + _this.instruments[x - 1].toolTip.offsetHeight > toolArray[x].top) {
|
|
1517
|
+
toolArray[x].top = lastTop + _this.instruments[x - 1].toolTip.offsetHeight;
|
|
1518
|
+
}
|
|
1519
|
+
}
|
|
1520
|
+
_this.instruments[toolArray[x].instrument].toolTip.style.top = toolArray[x].top + 'px';
|
|
1521
|
+
lastTop = toolArray[x].top;
|
|
1522
|
+
}
|
|
1504
1523
|
return;
|
|
1505
1524
|
}
|
|
1506
1525
|
|
|
@@ -1595,6 +1614,31 @@ function Milli_Chart(settings) {
|
|
|
1595
1614
|
if (m_zoom.div) m_canvas.parentNode.removeChild(m_zoom.div);
|
|
1596
1615
|
m_zoom.div = null;
|
|
1597
1616
|
m_zoom.isZooming = false;
|
|
1617
|
+
for (const [key, a] of m_analyzisMethod.entries()) {
|
|
1618
|
+
switch (a.method) {
|
|
1619
|
+
case 'sma':
|
|
1620
|
+
{
|
|
1621
|
+
a.history = simpleMovingAverage(_this.instruments[0].history, a.length);
|
|
1622
|
+
a.trades = simpleMovingAverage(_this.instruments[0].trades, a.length);
|
|
1623
|
+
}
|
|
1624
|
+
break;
|
|
1625
|
+
case 'ema':
|
|
1626
|
+
{
|
|
1627
|
+
a.history = exponentialMovingAverage(_this.instruments[0].history, a.length);
|
|
1628
|
+
a.trades = exponentialMovingAverage(_this.instruments[0].trades, a.length);
|
|
1629
|
+
break;
|
|
1630
|
+
}
|
|
1631
|
+
case 'bollinger':
|
|
1632
|
+
{
|
|
1633
|
+
a.history = bollingerBands(_this.instruments[0].history, a.length, a.stddev | 2);
|
|
1634
|
+
a = bollingerBands(_this.instruments[0].trades, a.length, a.stddev | 2);
|
|
1635
|
+
break;
|
|
1636
|
+
}
|
|
1637
|
+
default:
|
|
1638
|
+
break;
|
|
1639
|
+
}
|
|
1640
|
+
}
|
|
1641
|
+
|
|
1598
1642
|
}
|
|
1599
1643
|
m_lastDrawnInstrument = _this.instruments[0].insref;
|
|
1600
1644
|
if (m_ctx == null) return;
|
|
@@ -1685,6 +1729,12 @@ function Milli_Chart(settings) {
|
|
|
1685
1729
|
if (_this.instruments[i].insref != 0)
|
|
1686
1730
|
plotData(_this.instruments[i].trades, i);
|
|
1687
1731
|
}
|
|
1732
|
+
|
|
1733
|
+
for (const [key, a] of m_analyzisMethod.entries()) {
|
|
1734
|
+
if (a.method == 'bollinger') plotBollingerBand(a, 'trades');
|
|
1735
|
+
else plotMovingAverage(a, 'trades');
|
|
1736
|
+
}
|
|
1737
|
+
|
|
1688
1738
|
} else
|
|
1689
1739
|
if (period == 'm') {
|
|
1690
1740
|
if (m_zoom.mousedown.timestamp) {
|
|
@@ -1692,10 +1742,12 @@ function Milli_Chart(settings) {
|
|
|
1692
1742
|
_this.scaleinfoX.endTimeStamp = m_zoom.mousedown.timestamp > m_zoom.mouseup.timestamp ? m_zoom.mousedown.timestamp : m_zoom.mouseup.timestamp;
|
|
1693
1743
|
_this.scaleinfoX.endTimeStamp -= (_this.scaleinfoX.endTimeStamp % 3600000);
|
|
1694
1744
|
} else {
|
|
1745
|
+
var startdate = new Date().getTime() - (86400000 * 365 * (isNaN(len) ? 1 : len));
|
|
1746
|
+
|
|
1695
1747
|
_this.scaleinfoX.startTimeStamp = subtractMonth(new Date(), len);
|
|
1696
1748
|
_this.scaleinfoX.startTimeStamp = new Date(_this.scaleinfoX.startTimeStamp.toISOString().substring(0, 10) + 'T' + '00:00:00Z').getTime();
|
|
1697
1749
|
_this.scaleinfoX.startTimeStamp = findFirstWeekDay(_this.scaleinfoX.startTimeStamp).getTime();
|
|
1698
|
-
if (_this.instruments[0].history.
|
|
1750
|
+
if (_this.instruments[0].history.length > 1 && _this.scaleinfoX.startTimeStamp < _this.instruments[0].history[0].timestamp) _this.scaleinfoX.startTimeStamp = _this.instruments[0].history[0].timestamp;
|
|
1699
1751
|
_this.scaleinfoX.endTimeStamp = new Date();
|
|
1700
1752
|
_this.scaleinfoX.endTimeStamp = new Date(_this.scaleinfoX.endTimeStamp.toISOString().substring(0, 10) + 'T' + '00:00:00Z').getTime();
|
|
1701
1753
|
}
|
|
@@ -1712,25 +1764,30 @@ function Milli_Chart(settings) {
|
|
|
1712
1764
|
if (_this.instruments[i].insref != 0)
|
|
1713
1765
|
plotData(_this.instruments[i].history, i);
|
|
1714
1766
|
}
|
|
1767
|
+
for (const [key, a] of m_analyzisMethod.entries()) {
|
|
1768
|
+
if (a.method == 'bollinger') plotBollingerBand(a, 'history');
|
|
1769
|
+
else plotMovingAverage(a, 'history');
|
|
1770
|
+
}
|
|
1715
1771
|
} else
|
|
1716
|
-
if ((period == 'y' || _this.settings.chartlen == 'ytd' || _this.settings.chartlen == 'max')) {
|
|
1772
|
+
if ((period == 'y' || _this.settings.chartlen == 'ytd' || _this.settings.chartlen == 'max')) {
|
|
1717
1773
|
if (m_zoom.mousedown.timestamp) {
|
|
1718
1774
|
_this.scaleinfoX.startTimeStamp = m_zoom.mousedown.timestamp > m_zoom.mouseup.timestamp ? m_zoom.mouseup.timestamp : m_zoom.mousedown.timestamp;
|
|
1719
1775
|
_this.scaleinfoX.startTimeStamp -= (_this.scaleinfoX.startTimeStamp % 3600000);
|
|
1720
1776
|
_this.scaleinfoX.endTimeStamp = m_zoom.mousedown.timestamp > m_zoom.mouseup.timestamp ? m_zoom.mousedown.timestamp : m_zoom.mouseup.timestamp;
|
|
1721
1777
|
_this.scaleinfoX.endTimeStamp -= (_this.scaleinfoX.endTimeStamp % 3600000);
|
|
1722
1778
|
} else {
|
|
1723
|
-
var
|
|
1779
|
+
var startdateM;
|
|
1724
1780
|
if (_this.settings.chartlen == 'max' && _this.instruments[0].history.length > 1) {
|
|
1725
|
-
|
|
1781
|
+
startdateM = _this.instruments[0].history[0].timestamp;
|
|
1726
1782
|
} else
|
|
1727
1783
|
if (_this.settings.chartlen == 'ytd') {
|
|
1728
|
-
|
|
1784
|
+
//startdateM = new Date(new Date().getFullYear() - 1 + '-12-30').getTime(); // TODO, hur skall vi göra här om det inte finns data runt här?
|
|
1785
|
+
startdateM = new Date(new Date().getFullYear() + '-01-01').getTime(); // TODO, hur skall vi göra här om det inte finns data runt här?
|
|
1729
1786
|
} else {
|
|
1730
|
-
|
|
1787
|
+
startdateM = new Date().getTime() - (86400000 * 365 * (isNaN(len) ? 1 : len));
|
|
1731
1788
|
}
|
|
1732
|
-
if (_this.instruments[0].history.length > 1 &&
|
|
1733
|
-
_this.scaleinfoX.startTimeStamp =
|
|
1789
|
+
if (_this.instruments[0].history.length > 1 && startdateM < _this.instruments[0].history[0].timestamp) startdateM = _this.instruments[0].history[0].timestamp;
|
|
1790
|
+
_this.scaleinfoX.startTimeStamp = startdateM;
|
|
1734
1791
|
_this.scaleinfoX.startTimeStamp = findFirstWeekDay(_this.scaleinfoX.startTimeStamp).getTime();
|
|
1735
1792
|
_this.scaleinfoX.endTimeStamp = new Date();
|
|
1736
1793
|
_this.scaleinfoX.endTimeStamp = new Date(_this.scaleinfoX.endTimeStamp.toISOString().substring(0, 10) + 'T' + '00:00:00Z').getTime();
|
|
@@ -1748,6 +1805,12 @@ function Milli_Chart(settings) {
|
|
|
1748
1805
|
if (_this.instruments[i].insref != 0)
|
|
1749
1806
|
plotData(_this.instruments[i].history, i);
|
|
1750
1807
|
|
|
1808
|
+
for (const [key, a] of m_analyzisMethod.entries()) {
|
|
1809
|
+
if (a.method == 'bollinger') plotBollingerBand(a, 'history');
|
|
1810
|
+
else plotMovingAverage(a, 'history');
|
|
1811
|
+
}
|
|
1812
|
+
|
|
1813
|
+
|
|
1751
1814
|
}
|
|
1752
1815
|
drawBoxShadow(m_chartspaces.chart);
|
|
1753
1816
|
if (m_chartspaces.chart.percent != 100) {
|
|
@@ -1919,6 +1982,7 @@ function Milli_Chart(settings) {
|
|
|
1919
1982
|
};
|
|
1920
1983
|
|
|
1921
1984
|
function plotExternalHistoricalData(data) {
|
|
1985
|
+
// används för dividend osv
|
|
1922
1986
|
m_ctx.save();
|
|
1923
1987
|
var startpoint = { x: 0, y: 0 };
|
|
1924
1988
|
var endpoint = { x: 0, y: 0 };
|
|
@@ -1976,6 +2040,133 @@ function Milli_Chart(settings) {
|
|
|
1976
2040
|
m_ctx.restore();
|
|
1977
2041
|
}
|
|
1978
2042
|
|
|
2043
|
+
function calcAnalyzisLine(data, pricecol) {
|
|
2044
|
+
var startpoint = { x: 0, y: 0 };
|
|
2045
|
+
var endpoint = { x: 0, y: 0 };
|
|
2046
|
+
var startDate = _this.scaleinfoX.startTimeStamp;
|
|
2047
|
+
var len = data.length;
|
|
2048
|
+
var lastdate = new Date(_this.scaleinfoX.startTimeStamp);
|
|
2049
|
+
var offset = 0;
|
|
2050
|
+
var maxy = 0;
|
|
2051
|
+
var ret = [];
|
|
2052
|
+
for (var i = 0; i < len; i++) {
|
|
2053
|
+
var currentDate;
|
|
2054
|
+
var tmpx = startpoint.x;
|
|
2055
|
+
var tmp;
|
|
2056
|
+
if (data[i].timestamp < _this.scaleinfoX.startTimeStamp) {
|
|
2057
|
+
continue;
|
|
2058
|
+
}
|
|
2059
|
+
if (data[i].timestamp > _this.scaleinfoX.endTimeStamp) {
|
|
2060
|
+
break;
|
|
2061
|
+
}
|
|
2062
|
+
|
|
2063
|
+
if (_this.scaleinfoY.type != 'history' && (data[i].timestamp % 86400000 < _this.instruments[0].opentimestamp || data[i].timestamp % 86400000 > _this.instruments[0].closetimestamp)) {
|
|
2064
|
+
continue;
|
|
2065
|
+
}
|
|
2066
|
+
var endtimeToday = new Date(data[i].timestamp);
|
|
2067
|
+
if (endtimeToday.getDay() == 0 || endtimeToday.getDay() == 6) continue;
|
|
2068
|
+
if (_this.scaleinfoY.type != 'history') {
|
|
2069
|
+
endtimeToday = new Date(endtimeToday.toISOString().substring(0, 10) + 'T' + _this.instruments[0].marketclose + 'Z'); // borde räcka att göra 1 gång när det blir nytt datum
|
|
2070
|
+
}
|
|
2071
|
+
if (data[i].timestamp > endtimeToday.getTime()) {
|
|
2072
|
+
continue; // dataticks efter stängning ritas inte
|
|
2073
|
+
}
|
|
2074
|
+
currentDate = new Date(data[i].timestamp);
|
|
2075
|
+
currentDate.setHours(lastdate.getHours());
|
|
2076
|
+
currentDate.setMinutes(lastdate.getMinutes());
|
|
2077
|
+
currentDate.setSeconds(lastdate.getSeconds());
|
|
2078
|
+
if (lastdate.toISOString().substring(0, 10) != currentDate.toISOString().substring(0, 10)) { // new date
|
|
2079
|
+
tmp = new Date(lastdate.toISOString().substring(0, 10) + 'T' + _this.instruments[0].marketclose + 'Z');
|
|
2080
|
+
var nextDate = new Date(data[i].timestamp);
|
|
2081
|
+
tmp = tmp.getTime() + 86400000 - _this.scaleinfoX.milliPerDay; // increase to next days starttime
|
|
2082
|
+
|
|
2083
|
+
currentDate = new Date(tmp);
|
|
2084
|
+
while (dateDiffInDays(currentDate, nextDate) > 0) {
|
|
2085
|
+
if (currentDate.getDay() == 0 || currentDate.getDay() == 6)
|
|
2086
|
+
offset += 86400000 / _this.scaleinfoX.timePerPixel;
|
|
2087
|
+
else
|
|
2088
|
+
offset += ((86400000 - _this.scaleinfoX.milliPerDay) / _this.scaleinfoX.timePerPixel);
|
|
2089
|
+
currentDate = new Date(currentDate.getTime() + 86400000);
|
|
2090
|
+
}
|
|
2091
|
+
offset += ((86400000 - _this.scaleinfoX.milliPerDay) / _this.scaleinfoX.timePerPixel); // * dateDiffInDays(lastdate, currentDate);
|
|
2092
|
+
lastdate = currentDate;
|
|
2093
|
+
startpoint.x = Math.round(m_chartspaces.chart.left + ((data[i].timestamp - startDate) / _this.scaleinfoX.timePerPixel)) + 0.5 - offset;
|
|
2094
|
+
|
|
2095
|
+
// TODO: här blir det fel när det är från 00:00: 23:59 men göms av tmpx < startpoint.x
|
|
2096
|
+
if (_this.scaleinfoY.type == 'trades' && tmpx < startpoint.x) {
|
|
2097
|
+
ret.push(startpoint.x, startpoint.y);
|
|
2098
|
+
}
|
|
2099
|
+
}
|
|
2100
|
+
startpoint.y = Math.round(m_chartspaces.chart.height - m_chartCss.marginBottom - ((data[i].datapoints[pricecol] - _this.scaleinfoY.minValue) * _this.scaleinfoY.valuePerPixel)) + 0.5;
|
|
2101
|
+
maxy = maxy > startpoint.y ? maxy : startpoint.y;
|
|
2102
|
+
|
|
2103
|
+
startpoint.x = Math.round(m_chartspaces.chart.left + ((data[i].timestamp - _this.scaleinfoX.startDate.getTime()) / _this.scaleinfoX.timePerPixel)) + 0.5;
|
|
2104
|
+
startpoint.x -= offset;
|
|
2105
|
+
|
|
2106
|
+
if (startpoint.x != endpoint.x || startpoint.y != endpoint.y) {
|
|
2107
|
+
var x = Math.round(startpoint.x);
|
|
2108
|
+
if (endpoint.x != 0) {
|
|
2109
|
+
if (tmpx < startpoint.x) {
|
|
2110
|
+
if (_this.settings.hcurve) m_ctx.lineTo(startpoint.x, endpoint.y);
|
|
2111
|
+
ret.push({ x: startpoint.x, y: startpoint.y });
|
|
2112
|
+
}
|
|
2113
|
+
} else {
|
|
2114
|
+
ret.push({ x: startpoint.x, y: startpoint.y });
|
|
2115
|
+
}
|
|
2116
|
+
endpoint.x = startpoint.x;
|
|
2117
|
+
endpoint.y = startpoint.y;
|
|
2118
|
+
}
|
|
2119
|
+
}
|
|
2120
|
+
return ret;
|
|
2121
|
+
}
|
|
2122
|
+
|
|
2123
|
+
function plotMovingAverage(method, type) {
|
|
2124
|
+
var data = method[type];
|
|
2125
|
+
m_ctx.strokeStyle = method.color;
|
|
2126
|
+
m_ctx.lineWidth = method.lineWidth | 1;
|
|
2127
|
+
var line = calcAnalyzisLine(data, 0);
|
|
2128
|
+
if (line.length == 0) return;
|
|
2129
|
+
m_ctx.save();
|
|
2130
|
+
m_ctx.beginPath();
|
|
2131
|
+
m_ctx.closePath(); // clear path
|
|
2132
|
+
m_ctx.moveTo(line[0].x, line[0].y);
|
|
2133
|
+
for (var i = 1; i < line.length; i++) {
|
|
2134
|
+
m_ctx.lineTo(line[i].x, line[i].y);
|
|
2135
|
+
}
|
|
2136
|
+
m_ctx.stroke();
|
|
2137
|
+
m_ctx.restore();
|
|
2138
|
+
}
|
|
2139
|
+
|
|
2140
|
+
function plotBollingerBand(method, type) {
|
|
2141
|
+
var data = method[type];
|
|
2142
|
+
var upper = calcAnalyzisLine(data, 0, null);
|
|
2143
|
+
var lower = calcAnalyzisLine(data, 1, null);
|
|
2144
|
+
if (upper.length == 0 || lower.length == 0) return;
|
|
2145
|
+
m_ctx.strokeStyle = method.color;
|
|
2146
|
+
m_ctx.lineWidth = method.lineWidth | 1;
|
|
2147
|
+
m_ctx.save();
|
|
2148
|
+
m_ctx.beginPath();
|
|
2149
|
+
var upper = calcAnalyzisLine(data, 0, null);
|
|
2150
|
+
var lower = calcAnalyzisLine(data, 1, null);
|
|
2151
|
+
for (var i = 0; i < upper.length; i++) m_ctx.lineTo(upper[i].x, upper[i].y);
|
|
2152
|
+
m_ctx.lineTo(lower[lower.length - 1].x, lower[lower.length - 1].y);
|
|
2153
|
+
for (var i = lower.length - 1; i >= 0; i--) m_ctx.lineTo(lower[i].x, lower[i].y);
|
|
2154
|
+
if (method.border) m_ctx.stroke();
|
|
2155
|
+
m_ctx.closePath();
|
|
2156
|
+
if (method.fill) {
|
|
2157
|
+
m_ctx.fillStyle = method.fill;
|
|
2158
|
+
m_ctx.fill();
|
|
2159
|
+
}
|
|
2160
|
+
var sma = calcAnalyzisLine(data, 2);
|
|
2161
|
+
m_ctx.beginPath();
|
|
2162
|
+
m_ctx.closePath(); // clear path
|
|
2163
|
+
m_ctx.moveTo(sma[0].x, sma[0].y);
|
|
2164
|
+
for (var i = 0; i < sma.length; i++) m_ctx.lineTo(sma[i].x, sma[i].y);
|
|
2165
|
+
m_ctx.stroke();
|
|
2166
|
+
m_ctx.restore();
|
|
2167
|
+
return;
|
|
2168
|
+
}
|
|
2169
|
+
|
|
1979
2170
|
function plotData(data, instrument) {
|
|
1980
2171
|
m_ctx.save();
|
|
1981
2172
|
m_ctx.strokeStyle = m_instrumentCss[instrument].color;
|
|
@@ -2061,17 +2252,13 @@ function Milli_Chart(settings) {
|
|
|
2061
2252
|
}
|
|
2062
2253
|
offset += ((86400000 - _this.scaleinfoX.milliPerDay) / _this.scaleinfoX.timePerPixel); // * dateDiffInDays(lastdate, currentDate);
|
|
2063
2254
|
lastdate = currentDate;
|
|
2064
|
-
//console.log(startpoint.x);
|
|
2065
2255
|
startpoint.x = Math.round(m_chartspaces.chart.left + ((data[i].timestamp - startDate) / _this.scaleinfoX.timePerPixel)) + 0.5 - offset;
|
|
2066
|
-
//console.log(startpoint.x);
|
|
2067
2256
|
|
|
2068
2257
|
// TODO: här blir det fel när det är från 00:00: 23:59 men göms av tmpx < startpoint.x
|
|
2069
2258
|
if (_this.scaleinfoY.type == 'trades' && tmpx < startpoint.x) {
|
|
2070
2259
|
m_ctx.lineTo(startpoint.x, startpoint.y);
|
|
2071
2260
|
}
|
|
2072
|
-
//m_ctx.lineTo(startpoint.x, startpoint.y);
|
|
2073
2261
|
}
|
|
2074
|
-
//startpoint.y = Math.round(m_canvas.height - m_chartCss.marginBottom - (((data[i].price * factor) - _this.scaleinfoY.minValue) * _this.scaleinfoY.valuePerPixel)) + 0.5;
|
|
2075
2262
|
startpoint.y = Math.round(m_chartspaces.chart.height - m_chartCss.marginBottom - (((data[i].price * factor) - _this.scaleinfoY.minValue) * _this.scaleinfoY.valuePerPixel)) + 0.5;
|
|
2076
2263
|
maxy = maxy > startpoint.y ? maxy : startpoint.y;
|
|
2077
2264
|
|
|
@@ -2180,6 +2367,116 @@ function Milli_Chart(settings) {
|
|
|
2180
2367
|
m_zoom.mouseup.timestamp = null;
|
|
2181
2368
|
};
|
|
2182
2369
|
|
|
2370
|
+
function bollingerBands(prices, window, stddev) {
|
|
2371
|
+
if (!prices || prices.length < window) {
|
|
2372
|
+
return [];
|
|
2373
|
+
}
|
|
2374
|
+
|
|
2375
|
+
let index = window - 1;
|
|
2376
|
+
const length = prices.length + 1;
|
|
2377
|
+
const standardDeviations = [];
|
|
2378
|
+
while (++index < length) {
|
|
2379
|
+
const windowSlice = prices.slice(index - window, index);
|
|
2380
|
+
const mean = windowSlice.reduce((prev, curr) => prev + curr.price, 0) / window;
|
|
2381
|
+
const variance = Math.sqrt(windowSlice.reduce((a, b) => a + (b.price - mean) ** 2, 0) / window) * stddev;
|
|
2382
|
+
const uppervariance = mean + variance;
|
|
2383
|
+
const lowervariance = mean - variance;
|
|
2384
|
+
standardDeviations.push({ timestamp: prices[index - 1].timestamp, datapoints: [uppervariance, lowervariance, mean] });
|
|
2385
|
+
}
|
|
2386
|
+
return standardDeviations;
|
|
2387
|
+
}
|
|
2388
|
+
|
|
2389
|
+
function simpleMovingAverage(prices, window, n = Infinity) {
|
|
2390
|
+
if (!prices || prices.length < window) {
|
|
2391
|
+
return [];
|
|
2392
|
+
}
|
|
2393
|
+
|
|
2394
|
+
let index = window - 1;
|
|
2395
|
+
const length = prices.length + 1;
|
|
2396
|
+
|
|
2397
|
+
const simpleMovingAverages = [];
|
|
2398
|
+
|
|
2399
|
+
let numberOfSMAsCalculated = 0;
|
|
2400
|
+
|
|
2401
|
+
while (++index < length && numberOfSMAsCalculated++ < n) {
|
|
2402
|
+
const windowSlice = prices.slice(index - window, index);
|
|
2403
|
+
const sum = windowSlice.reduce((prev, curr) => prev + curr.price, 0);
|
|
2404
|
+
simpleMovingAverages.push({ timestamp: prices[index - 1].timestamp, datapoints: [sum / window] });
|
|
2405
|
+
}
|
|
2406
|
+
return simpleMovingAverages;
|
|
2407
|
+
}
|
|
2408
|
+
|
|
2409
|
+
function exponentialMovingAverage(prices, window) {
|
|
2410
|
+
if (!prices || prices.length < window) {
|
|
2411
|
+
return [];
|
|
2412
|
+
}
|
|
2413
|
+
let index = window - 1;
|
|
2414
|
+
let previousEmaIndex = 0;
|
|
2415
|
+
const length = prices.length;
|
|
2416
|
+
const smoothingFactor = 2 / (window + 1);
|
|
2417
|
+
const exponentialMovingAverages = [];
|
|
2418
|
+
|
|
2419
|
+
const [sma] = simpleMovingAverage(prices, window, 1);
|
|
2420
|
+
exponentialMovingAverages.push(sma);
|
|
2421
|
+
while (++index < length) {
|
|
2422
|
+
const value = prices[index].price;
|
|
2423
|
+
const previousEma = [exponentialMovingAverages[previousEmaIndex++].datapoints[0]];
|
|
2424
|
+
const currentEma = (value * smoothingFactor) + (previousEma * (1 - smoothingFactor));
|
|
2425
|
+
exponentialMovingAverages.push({ timestamp: prices[index].timestamp, datapoints: [currentEma] });
|
|
2426
|
+
}
|
|
2427
|
+
return exponentialMovingAverages;
|
|
2428
|
+
}
|
|
2429
|
+
_this.removeIndicator = function(index) {
|
|
2430
|
+
if (m_analyzisMethod.get(index)) {
|
|
2431
|
+
m_analyzisMethod.delete(index);
|
|
2432
|
+
_this.drawChart();
|
|
2433
|
+
return true;
|
|
2434
|
+
}
|
|
2435
|
+
return false;
|
|
2436
|
+
}
|
|
2437
|
+
|
|
2438
|
+
_this.addIndicator = function(method) {
|
|
2439
|
+
if (typeof method !== 'object' || method == null || typeof method.type == undefined) return;
|
|
2440
|
+
switch (method.method) {
|
|
2441
|
+
case 'sma':
|
|
2442
|
+
{
|
|
2443
|
+
if (typeof method.length === undefined) return;
|
|
2444
|
+
method.history = simpleMovingAverage(_this.instruments[0].history, method.length);
|
|
2445
|
+
method.trades = simpleMovingAverage(_this.instruments[0].trades, method.length);
|
|
2446
|
+
}
|
|
2447
|
+
break;
|
|
2448
|
+
case 'ema':
|
|
2449
|
+
{
|
|
2450
|
+
if (typeof method.length === undefined) return;
|
|
2451
|
+
method.index = m_analyzisIndex++;
|
|
2452
|
+
method.history = exponentialMovingAverage(_this.instruments[0].history, method.length);
|
|
2453
|
+
method.trades = exponentialMovingAverage(_this.instruments[0].trades, method.length);
|
|
2454
|
+
break;
|
|
2455
|
+
}
|
|
2456
|
+
case 'bollinger':
|
|
2457
|
+
{
|
|
2458
|
+
if (typeof method.length === undefined) return;
|
|
2459
|
+
if (!method.stddev) method.stddev = 2;
|
|
2460
|
+
if (!method.length) method.stddev = 20;
|
|
2461
|
+
method.index = m_analyzisIndex++;
|
|
2462
|
+
method.history = bollingerBands(_this.instruments[0].history, method.length, method.stddev | 2);
|
|
2463
|
+
method.trades = bollingerBands(_this.instruments[0].trades, method.length, method.stddev | 2);
|
|
2464
|
+
break;
|
|
2465
|
+
}
|
|
2466
|
+
default:
|
|
2467
|
+
if (typeof method.history !== 'undefined' && typeof method.trades !== 'undefined') {
|
|
2468
|
+
if (!Array.isArray(method.history) || !Array.isArray(method.trades)) {
|
|
2469
|
+
return -1;
|
|
2470
|
+
}
|
|
2471
|
+
}
|
|
2472
|
+
break;
|
|
2473
|
+
}
|
|
2474
|
+
method.index = m_analyzisIndex++;
|
|
2475
|
+
m_analyzisMethod.set(method.index, method);
|
|
2476
|
+
console.log(method, m_analyzisMethod);
|
|
2477
|
+
_this.drawChart();
|
|
2478
|
+
};
|
|
2479
|
+
|
|
2183
2480
|
_this.removeAllCompares = function() {
|
|
2184
2481
|
if (_this.instruments.length == 1) return;
|
|
2185
2482
|
for (var i = 0; i < 3; i++)
|
|
@@ -2191,7 +2488,6 @@ function Milli_Chart(settings) {
|
|
|
2191
2488
|
if (instrument == 0 || isNaN(instrument)) return;
|
|
2192
2489
|
for (var i = 0; i < _this.instruments.length; i++) {
|
|
2193
2490
|
if (_this.instruments[i].insref == instrument) {
|
|
2194
|
-
// _this.instruments.splice(i, 1);
|
|
2195
2491
|
_this.instruments[i] = { insref: 0 };
|
|
2196
2492
|
_this.drawChart();
|
|
2197
2493
|
}
|
|
@@ -2209,7 +2505,6 @@ function Milli_Chart(settings) {
|
|
|
2209
2505
|
if (_this.instruments[pos].insref == 0) break;
|
|
2210
2506
|
}
|
|
2211
2507
|
if (pos == 4) return 0;
|
|
2212
|
-
// if (_this.instruments.length > 3) return; // MAX 4 instruments (3 compares)
|
|
2213
2508
|
var instrument = parseInt(insref);
|
|
2214
2509
|
if (instrument == 0 || isNaN(instrument)) return 0;
|
|
2215
2510
|
for (i = 0; i < _this.instruments.length; i++) {
|
|
@@ -2226,12 +2521,17 @@ function Milli_Chart(settings) {
|
|
|
2226
2521
|
};
|
|
2227
2522
|
|
|
2228
2523
|
_this.instruments[pos] = instr;
|
|
2524
|
+
var oldfields = _this.settings.fields;
|
|
2229
2525
|
if (_this.settings.compare1 != '') {
|
|
2230
|
-
|
|
2526
|
+
_this.settings.fields = [...['name', 'tradecurrency', 'time', 'date', 'tradeprice', 'tradequantity', 'marketopen', 'marketclose', 'closeprice1d'], ...oldfields];
|
|
2527
|
+
var url = milli_data_api_url + "widget=intradaychart&token=" + _this.settings.token + "&target=buildwidget&fields=" + _this.settings.fields + "&language=sv&compress=1&insref=" + instrument + '&intradaylen=' + _this.settings.intradaylen;
|
|
2528
|
+
_this.settings.fields = oldfields;
|
|
2231
2529
|
millistream_data_api.fetch(url, function(data) {
|
|
2232
2530
|
drawCompare(data);
|
|
2233
2531
|
});
|
|
2234
|
-
|
|
2532
|
+
_this.settings.fields = [...['name', 'tradecurrency', 'date', 'closeprice', 'closequantity', 'marketopen', 'marketclose'], ...oldfields];
|
|
2533
|
+
url = milli_data_api_url + "widget=historychart&token=" + _this.settings.token + "&target=buildwidget&insref=" + instrument + "&fields=" + _this.settings.fields + "&language=sv&startdate=" + _this.settings.startdate + "&adjusted=1";
|
|
2534
|
+
_this.settings.fields = oldfields;
|
|
2235
2535
|
millistream_data_api.fetch(url, function(data) {
|
|
2236
2536
|
drawCompare(data);
|
|
2237
2537
|
});
|
|
@@ -2255,11 +2555,9 @@ function Milli_Chart(settings) {
|
|
|
2255
2555
|
var period = _this.settings.chartlen.substring(_this.settings.chartlen.length - 1);
|
|
2256
2556
|
var len = parseInt(_this.settings.chartlen.substring(0, _this.settings.chartlen.length - 1));
|
|
2257
2557
|
if ((period == 'd' && _this.settings.chartlen != 'ytd') && typeof resp[0].trades === 'undefined') {
|
|
2258
|
-
//console.log('typeof resp.trades', typeof resp[0].trades, period, _this.settings.chartlen);
|
|
2259
2558
|
return;
|
|
2260
2559
|
}
|
|
2261
2560
|
if ((period == 'm' || period == 'y' || _this.settings.chartlen == 'ytd' || _this.settings.chartlen == 'max') && typeof resp[0].history === 'undefined') {
|
|
2262
|
-
//console.log('typeof resp.history', typeof resp[0].history, resp);
|
|
2263
2561
|
return;
|
|
2264
2562
|
}
|
|
2265
2563
|
|
|
@@ -2324,17 +2622,14 @@ function Milli_Chart(settings) {
|
|
|
2324
2622
|
_this.drawChart();
|
|
2325
2623
|
|
|
2326
2624
|
if (_this.settings.streaming != false && typeof resp[0].trades !== 'undefined') {
|
|
2327
|
-
/*if (MillistreamWidgetApi_isObjectEmpty(_this.unsubscriptions) == false) {
|
|
2328
|
-
_this.settings.streaming.MillistreamWidgetStreamingApi_unsubscribe(_this);
|
|
2329
|
-
}*/
|
|
2330
2625
|
m_requestid = _this.settings.streaming.MillistreamWidgetStreamingApi_subscribeInstruments(_this, m_requestid, [_this.settings.instrument]);
|
|
2331
|
-
//_this.requestid = _this.settings.streaming.MillistreamWidgetStreamingApi_subscribeInstruments(_this, _this.requestid, m_insrefs);
|
|
2332
2626
|
}
|
|
2333
2627
|
if (_this.settings.onreadyCallback) _this.settings.onreadyCallback();
|
|
2334
2628
|
};
|
|
2335
2629
|
|
|
2336
2630
|
_this.streamingCallback = function(insref, mref, json) {
|
|
2337
2631
|
var update = false;
|
|
2632
|
+
var calcAnalyizis = false;
|
|
2338
2633
|
var instr = _this.instruments.find(function(item) {
|
|
2339
2634
|
return item.insref == insref;
|
|
2340
2635
|
});
|
|
@@ -2344,38 +2639,62 @@ function Milli_Chart(settings) {
|
|
|
2344
2639
|
if (json['3'] && json['36'] && json['13'] && (json['12'] || json['201'])) {
|
|
2345
2640
|
var timestamp = new Date(json['3'] + 'T' + json['36'].substring(0, 6) + '00' + 'Z').getTime();
|
|
2346
2641
|
|
|
2347
|
-
// TODO hash/strangle with YYYY-mm-dd hh:mm:00 trades and only draw once per minute
|
|
2348
2642
|
var data = instr.hashmap.get(timestamp);
|
|
2349
|
-
if (data
|
|
2643
|
+
if (typeof data === 'undefined') {
|
|
2350
2644
|
update = true;
|
|
2351
2645
|
data = {};
|
|
2352
2646
|
//data.tradereference = json['14'];
|
|
2353
2647
|
data.timestamp = timestamp;
|
|
2354
2648
|
instr.hashmap.set(data.timestamp, data);
|
|
2649
|
+
calcAnalyizis = true;
|
|
2355
2650
|
data.price = parseFloat(json['12']); // eller 201 för tradeyield
|
|
2356
2651
|
data.open = parseFloat(json['12']); // eller 201 för tradeyield
|
|
2357
2652
|
data.high = parseFloat(json['12']); // eller 201 för tradeyield
|
|
2358
2653
|
data.low = parseFloat(json['12']); // eller 201 för tradeyield
|
|
2359
2654
|
data.quantity = parseInt(json['13']);
|
|
2655
|
+
|
|
2360
2656
|
if (instr.trades.length != 0 && data.timestamp < instr.trades[instr.trades.length - 1].timestamp) {
|
|
2361
2657
|
//console.log("pushtrade is older than last trade ignoring, should file it on correct postition");
|
|
2362
2658
|
} else
|
|
2363
2659
|
instr.trades.push(data);
|
|
2364
2660
|
} else {
|
|
2661
|
+
if (data.price != parseFloat(json['12']))
|
|
2662
|
+
calcAnalyizis = true;
|
|
2365
2663
|
data.price = parseFloat(json['12']); // eller 201 för tradeyield
|
|
2366
2664
|
data.quantity += parseInt(json['13']);
|
|
2367
2665
|
update = true;
|
|
2368
2666
|
// updatera med quantity, open , high,low osv?
|
|
2369
2667
|
}
|
|
2370
2668
|
}
|
|
2371
|
-
if (
|
|
2669
|
+
if (calcAnalyizis) {
|
|
2670
|
+
for (const [key, a] of m_analyzisMethod.entries()) {
|
|
2671
|
+
switch (a.method) {
|
|
2672
|
+
case 'sma':
|
|
2673
|
+
a.trades = [];
|
|
2674
|
+
a.trades = simpleMovingAverage(_this.instruments[0].trades, a.length);
|
|
2675
|
+
break;
|
|
2676
|
+
case 'ema':
|
|
2677
|
+
a.trades = [];
|
|
2678
|
+
a.trades = exponentialMovingAverage(_this.instruments[0].trades, a.length);
|
|
2679
|
+
break;
|
|
2680
|
+
case 'bollinger':
|
|
2681
|
+
a.trades = [];
|
|
2682
|
+
a.trades = bollingerBands(_this.instruments[0].trades, a.length, a.stddev | 2);
|
|
2683
|
+
break;
|
|
2684
|
+
default:
|
|
2685
|
+
// draw custom added?
|
|
2686
|
+
break;
|
|
2687
|
+
}
|
|
2688
|
+
}
|
|
2689
|
+
}
|
|
2690
|
+
|
|
2691
|
+
if (update && _this.settings.chartlen != 'ytd' && _this.settings.chartlen.substring(_this.settings.chartlen.length - 1) == 'd') { // do not redraw if not tickchart
|
|
2692
|
+
_this.drawChart();
|
|
2693
|
+
}
|
|
2372
2694
|
};
|
|
2373
2695
|
|
|
2374
2696
|
function changeOrientation() {
|
|
2375
2697
|
if (m_canvas == null) return;
|
|
2376
|
-
// set size 0 so target div does not expand due to chartsize
|
|
2377
|
-
//readCss(); // TODO
|
|
2378
|
-
|
|
2379
2698
|
m_canvas.setAttribute('height', _this.settings.target.getBoundingClientRect().height);
|
|
2380
2699
|
m_canvas.setAttribute('width', _this.settings.target.getBoundingClientRect().width);
|
|
2381
2700
|
_this.drawChart();
|
|
@@ -2385,15 +2704,22 @@ function Milli_Chart(settings) {
|
|
|
2385
2704
|
var req = new XMLHttpRequest();
|
|
2386
2705
|
req.onload = function() {
|
|
2387
2706
|
_this.buildwidget(JSON.parse(this.responseText));
|
|
2388
|
-
}
|
|
2707
|
+
};
|
|
2389
2708
|
req.open("GET", url, true);
|
|
2390
2709
|
req.onerror = function(error) {
|
|
2391
2710
|
console.log('Fetch data error', error);
|
|
2392
|
-
}
|
|
2711
|
+
};
|
|
2393
2712
|
req.send();
|
|
2394
2713
|
}
|
|
2395
2714
|
|
|
2396
|
-
|
|
2715
|
+
_this.destroyWidget = function() {
|
|
2716
|
+
// if we have subscriptions send in an empty array to unsubscribe all and release it
|
|
2717
|
+
if (MillistreamWidgetApi_isObjectEmpty(_this.unsubscriptions) == false)
|
|
2718
|
+
_this.requestid = _this.settings.streaming.MillistreamWidgetStreamingApi_subscribeInstruments(_this, _this.requestid, []);
|
|
2719
|
+
return 0;
|
|
2720
|
+
};
|
|
2721
|
+
|
|
2722
|
+
_this.drawWidget = function() {
|
|
2397
2723
|
// remove standard fields from array, they will be requested anyway
|
|
2398
2724
|
_this.settings.fields = _this.settings.fields.filter(function(obj) {
|
|
2399
2725
|
return ['name', 'tradecurrency', 'time', 'date', 'tradeprice', 'tradequantity', 'marketopen', 'marketclose', 'closeprice1d', 'closeprice', 'closequantity'].indexOf(obj) == -1;
|
|
@@ -2405,15 +2731,13 @@ function Milli_Chart(settings) {
|
|
|
2405
2731
|
m_dummyDiv.style.display = 'none';
|
|
2406
2732
|
m_dummyDiv.setAttribute('class', 'millistream-chart');
|
|
2407
2733
|
_this.settings.target.appendChild(m_dummyDiv);
|
|
2408
|
-
_this.instruments
|
|
2409
|
-
var instr = {
|
|
2734
|
+
_this.instruments[0] = {
|
|
2410
2735
|
insref: _this.settings.instrument,
|
|
2411
2736
|
history: [],
|
|
2412
2737
|
trades: [],
|
|
2413
2738
|
hashmap: new Map(),
|
|
2414
2739
|
intradayQuantity: []
|
|
2415
2740
|
};
|
|
2416
|
-
_this.instruments.push(instr);
|
|
2417
2741
|
var d, url, oldfields;
|
|
2418
2742
|
if (_this.settings.intradaylen) {
|
|
2419
2743
|
d = new Date().getTime();
|
|
@@ -2431,7 +2755,6 @@ function Milli_Chart(settings) {
|
|
|
2431
2755
|
oldfields = _this.settings.fields;
|
|
2432
2756
|
_this.settings.fields = [...['name', 'tradecurrency', 'time', 'date', 'tradeprice', 'tradequantity', 'marketopen', 'marketclose', 'closeprice1d'], ...oldfields];
|
|
2433
2757
|
_this.settings.startdate = e.getFullYear() + '-' + zeroPad(e.getMonth() + 1, 2) + '-' + zeroPad(e.getDate(), 2);
|
|
2434
|
-
//_this.settings.startdateintraday = _this.settings.startdate;
|
|
2435
2758
|
url = MillistreamWidgetApi_buildQuery(_this, 'intradaychart');
|
|
2436
2759
|
_this.settings.fields = oldfields;
|
|
2437
2760
|
if (_this.settings.xhr) {
|
|
@@ -2479,9 +2802,7 @@ function Milli_Chart(settings) {
|
|
|
2479
2802
|
startdate -= 86400000 * 365 * len; // remember leapyear
|
|
2480
2803
|
break;
|
|
2481
2804
|
case 'x':
|
|
2482
|
-
//startdate -= 86400000 * 365 * 10; // remember leapyear
|
|
2483
2805
|
startdate = new Date('1970-01-01T00:00:00Z').getTime();
|
|
2484
|
-
//console.log(startdate);
|
|
2485
2806
|
break;
|
|
2486
2807
|
}
|
|
2487
2808
|
// must be reset when changing from intraday -> history and vice versa
|