@millistream/millistream-widgets 1.0.33 → 1.0.35
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 +1669 -711
- package/package.json +1 -1
package/millistream-widgets.js
CHANGED
|
@@ -5,220 +5,8 @@
|
|
|
5
5
|
* Homepage: https://github.com/jondavidjohn/hidpi-canvas-polyfill
|
|
6
6
|
* Issue Tracker: https://github.com/jondavidjohn/hidpi-canvas-polyfill/issues
|
|
7
7
|
* License: Apache-2.0
|
|
8
|
+
* Modifed by: Millistream
|
|
8
9
|
*/
|
|
9
|
-
(function(prototype) {
|
|
10
|
-
|
|
11
|
-
var pixelRatio = (function() {
|
|
12
|
-
var canvas = document.createElement('canvas'),
|
|
13
|
-
context = canvas.getContext('2d');
|
|
14
|
-
/*backingStore = context.backingStorePixelRatio ||
|
|
15
|
-
context.webkitBackingStorePixelRatio ||
|
|
16
|
-
context.mozBackingStorePixelRatio ||
|
|
17
|
-
context.msBackingStorePixelRatio ||
|
|
18
|
-
context.oBackingStorePixelRatio ||
|
|
19
|
-
context.backingStorePixelRatio || 1;
|
|
20
|
-
return (window.devicePixelRatio || 1) / backingStore;
|
|
21
|
-
*/
|
|
22
|
-
})(),
|
|
23
|
-
forEach = function(obj, func) {
|
|
24
|
-
for (var p in obj) {
|
|
25
|
-
if (obj.hasOwnProperty(p)) {
|
|
26
|
-
func(obj[p], p);
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
},
|
|
30
|
-
|
|
31
|
-
ratioArgs = {
|
|
32
|
-
//'fillRect': 'all',
|
|
33
|
-
//'clearRect': 'all',
|
|
34
|
-
'strokeRect': 'all',
|
|
35
|
-
'moveTo': 'all',
|
|
36
|
-
'lineTo': 'all',
|
|
37
|
-
'arc': [0, 1, 2],
|
|
38
|
-
'arcTo': 'all',
|
|
39
|
-
'bezierCurveTo': 'all',
|
|
40
|
-
'isPointinPath': 'all',
|
|
41
|
-
'isPointinStroke': 'all',
|
|
42
|
-
'quadraticCurveTo': 'all',
|
|
43
|
-
'rect': 'all',
|
|
44
|
-
'translate': 'all',
|
|
45
|
-
'createRadialGradient': 'all',
|
|
46
|
-
//'createLinearGradient': 'all'
|
|
47
|
-
};
|
|
48
|
-
|
|
49
|
-
if (pixelRatio === 1) return;
|
|
50
|
-
|
|
51
|
-
function getPixelRatio(_this) {
|
|
52
|
-
/* var backingStore = this.backingStorePixelRatio ||
|
|
53
|
-
this.webkitBackingStorePixelRatio ||
|
|
54
|
-
this.mozBackingStorePixelRatio ||
|
|
55
|
-
this.msBackingStorePixelRatio ||
|
|
56
|
-
this.oBackingStorePixelRatio ||
|
|
57
|
-
this.backingStorePixelRatio || 1;*/
|
|
58
|
-
var backingStore = _this.backingStorePixelRatio ||
|
|
59
|
-
_this.webkitBackingStorePixelRatio ||
|
|
60
|
-
_this.mozBackingStorePixelRatio ||
|
|
61
|
-
_this.msBackingStorePixelRatio ||
|
|
62
|
-
_this.oBackingStorePixelRatio ||
|
|
63
|
-
_this.backingStorePixelRatio || 1;
|
|
64
|
-
return (window.devicePixelRatio || 1) / backingStore;
|
|
65
|
-
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
forEach(ratioArgs, function(value, key) {
|
|
69
|
-
prototype[key] = (function(_super) {
|
|
70
|
-
return function() {
|
|
71
|
-
var i, len,
|
|
72
|
-
args = Array.prototype.slice.call(arguments);
|
|
73
|
-
if (key == 'lineTo' || key == 'moveTo') { // PF
|
|
74
|
-
args = args.map(function(a) {
|
|
75
|
-
return a;
|
|
76
|
-
});
|
|
77
|
-
} else
|
|
78
|
-
if (value === 'all') {
|
|
79
|
-
args = args.map(function(a) {
|
|
80
|
-
return a * getPixelRatio(this);
|
|
81
|
-
});
|
|
82
|
-
} else if (Array.isArray(value)) {
|
|
83
|
-
for (i = 0, len = value.length; i < len; i++) {
|
|
84
|
-
args[value[i]] *= getPixelRatio(this);
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
return _super.apply(this, args);
|
|
89
|
-
};
|
|
90
|
-
})(prototype[key]);
|
|
91
|
-
});
|
|
92
|
-
|
|
93
|
-
// Stroke lineWidth adjustment
|
|
94
|
-
prototype.stroke = (function(_super) {
|
|
95
|
-
return function() {
|
|
96
|
-
this.lineWidth *= getPixelRatio(this);
|
|
97
|
-
_super.apply(this, arguments);
|
|
98
|
-
this.lineWidth /= getPixelRatio(this);
|
|
99
|
-
};
|
|
100
|
-
})(prototype.stroke);
|
|
101
|
-
|
|
102
|
-
prototype.measureText = (function(_super) {
|
|
103
|
-
return function() {
|
|
104
|
-
var args = Array.prototype.slice.call(arguments);
|
|
105
|
-
|
|
106
|
-
var tmp = this.font;
|
|
107
|
-
var _this = this;
|
|
108
|
-
this.font = this.font.replace(
|
|
109
|
-
/(\d+)(px|em|rem|pt)/g,
|
|
110
|
-
function(w, m, u) {
|
|
111
|
-
return Math.floor(m * getPixelRatio(_this)) + u;
|
|
112
|
-
}
|
|
113
|
-
);
|
|
114
|
-
var i = _super.apply(this, args);
|
|
115
|
-
|
|
116
|
-
this.font = tmp;
|
|
117
|
-
/*this.font = this.font.replace(
|
|
118
|
-
/(\d+)(px|em|rem|pt)/g,
|
|
119
|
-
function(w, m, u) {
|
|
120
|
-
return Math.floor(m / getPixelRatio()) + u;
|
|
121
|
-
}
|
|
122
|
-
);*/
|
|
123
|
-
return i;
|
|
124
|
-
};
|
|
125
|
-
})(prototype.measureText);
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
prototype.fillText = (function(_super) {
|
|
129
|
-
return function() {
|
|
130
|
-
var args = Array.prototype.slice.call(arguments);
|
|
131
|
-
var tmp = this.font;
|
|
132
|
-
var _this = this;
|
|
133
|
-
this.font = this.font.replace(
|
|
134
|
-
/(\d+)(px|em|rem|pt)/g,
|
|
135
|
-
function(w, m, u) {
|
|
136
|
-
return (m * getPixelRatio(_this)) + u;
|
|
137
|
-
}
|
|
138
|
-
);
|
|
139
|
-
_super.apply(this, args);
|
|
140
|
-
this.font = tmp;
|
|
141
|
-
};
|
|
142
|
-
})(prototype.fillText);
|
|
143
|
-
|
|
144
|
-
prototype.strokeText = (function(_super) {
|
|
145
|
-
return function() {
|
|
146
|
-
var args = Array.prototype.slice.call(arguments);
|
|
147
|
-
|
|
148
|
-
args[1] *= getPixelRatio(this); // x
|
|
149
|
-
args[2] *= getPixelRatio(this); // y
|
|
150
|
-
var tmp = this.font;
|
|
151
|
-
var _this = this;
|
|
152
|
-
this.font = this.font.replace(
|
|
153
|
-
/(\d+)(px|em|rem|pt)/g,
|
|
154
|
-
function(w, m, u) {
|
|
155
|
-
return (m * getPixelRatio(_this)) + u;
|
|
156
|
-
}
|
|
157
|
-
);
|
|
158
|
-
|
|
159
|
-
_super.apply(this, args);
|
|
160
|
-
this.font = tmp;
|
|
161
|
-
/*this.font = this.font.replace(
|
|
162
|
-
/(\d+)(px|em|rem|pt)/g,
|
|
163
|
-
function(w, m, u) {
|
|
164
|
-
return (m / getPixelRatio()) + u;
|
|
165
|
-
}
|
|
166
|
-
);*/
|
|
167
|
-
};
|
|
168
|
-
})(prototype.strokeText);
|
|
169
|
-
|
|
170
|
-
})(CanvasRenderingContext2D.prototype);
|
|
171
|
-
|
|
172
|
-
(function(prototype) {
|
|
173
|
-
var context = null;
|
|
174
|
-
|
|
175
|
-
function getPixelRatio() {
|
|
176
|
-
var backingStore = context.backingStorePixelRatio ||
|
|
177
|
-
context.webkitBackingStorePixelRatio ||
|
|
178
|
-
context.mozBackingStorePixelRatio ||
|
|
179
|
-
context.msBackingStorePixelRatio ||
|
|
180
|
-
context.oBackingStorePixelRatio ||
|
|
181
|
-
context.backingStorePixelRatio || 1;
|
|
182
|
-
|
|
183
|
-
return (window.devicePixelRatio || 1) / backingStore;
|
|
184
|
-
|
|
185
|
-
}
|
|
186
|
-
prototype.getContext = (function(_super) {
|
|
187
|
-
return function(type) {
|
|
188
|
-
//var backingStore, ratio;
|
|
189
|
-
context = _super.call(this, type);
|
|
190
|
-
|
|
191
|
-
if (type === '2d') {
|
|
192
|
-
|
|
193
|
-
/*backingStore = context.backingStorePixelRatio ||
|
|
194
|
-
context.webkitBackingStorePixelRatio ||
|
|
195
|
-
context.mozBackingStorePixelRatio ||
|
|
196
|
-
context.msBackingStorePixelRatio ||
|
|
197
|
-
context.oBackingStorePixelRatio ||
|
|
198
|
-
context.backingStorePixelRatio || 1;*/
|
|
199
|
-
|
|
200
|
-
var ratio = getPixelRatio();
|
|
201
|
-
if (ratio > 1) {
|
|
202
|
-
this.style.height = this.height + 'px';
|
|
203
|
-
this.style.width = this.width + 'px';
|
|
204
|
-
this.width *= ratio;
|
|
205
|
-
this.height *= ratio;
|
|
206
|
-
}
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
return context;
|
|
210
|
-
};
|
|
211
|
-
})(prototype.getContext);
|
|
212
|
-
|
|
213
|
-
prototype.setRect = (function(height, width) {
|
|
214
|
-
if (context == null) return;
|
|
215
|
-
this.style.height = height + 'px';
|
|
216
|
-
this.style.width = width + 'px';
|
|
217
|
-
this.width = width * getPixelRatio();
|
|
218
|
-
this.height = height * getPixelRatio();
|
|
219
|
-
});
|
|
220
|
-
|
|
221
|
-
})(HTMLCanvasElement.prototype);
|
|
222
10
|
|
|
223
11
|
// Millistream Chart
|
|
224
12
|
function Milli_Chart(settings) {
|
|
@@ -226,12 +14,26 @@ function Milli_Chart(settings) {
|
|
|
226
14
|
var _this = this;
|
|
227
15
|
_this.mdf_fields = [];
|
|
228
16
|
_this.scaleinfoX = {};
|
|
229
|
-
_this.scaleinfoY = {};
|
|
230
|
-
_this.scaleinfoY2 = {};
|
|
231
17
|
_this.instruments = [];
|
|
232
|
-
_this.movingAverage = [];
|
|
233
18
|
_this.unsubscriptions = {};
|
|
234
|
-
|
|
19
|
+
let scaleinfoY = {};
|
|
20
|
+
let scaleinfoY2 = {};
|
|
21
|
+
let scaleinfo = { // TODO: implement
|
|
22
|
+
y: {},
|
|
23
|
+
y2: {},
|
|
24
|
+
x: {},
|
|
25
|
+
ly: {}
|
|
26
|
+
};
|
|
27
|
+
let testscale = {
|
|
28
|
+
valuePerPixel: 0,
|
|
29
|
+
minValue: 0,
|
|
30
|
+
maxValue: 0,
|
|
31
|
+
lowValue: 0,
|
|
32
|
+
highValue: 0,
|
|
33
|
+
lineLength: 0,
|
|
34
|
+
decimals: 0, // behövs den?
|
|
35
|
+
tickSize: 0
|
|
36
|
+
};
|
|
235
37
|
_this.settings = {
|
|
236
38
|
adjusted: true,
|
|
237
39
|
absoluteScaling: false,
|
|
@@ -258,6 +60,7 @@ function Milli_Chart(settings) {
|
|
|
258
60
|
intradayDatePos: { x: 'center', y: 'bottom', orientation: 'horizontal', dateformat: 'd mmm' },
|
|
259
61
|
intradaylen: null,
|
|
260
62
|
messagetypes: 1030, // quote,trades and performance
|
|
63
|
+
newslanguage: ['sv'],
|
|
261
64
|
nochartlabel: 'No data to draw on',
|
|
262
65
|
onreadyCallback: null,
|
|
263
66
|
previousDayClose: true,
|
|
@@ -268,12 +71,20 @@ function Milli_Chart(settings) {
|
|
|
268
71
|
xhr: false,
|
|
269
72
|
yearLabelsPos: 'bottom',
|
|
270
73
|
priceIndicator: false,
|
|
74
|
+
type: 'ohlc ',
|
|
271
75
|
tooltip: {
|
|
272
76
|
display: 'block'
|
|
273
77
|
},
|
|
78
|
+
ohlc: {
|
|
79
|
+
offset: "3px"
|
|
80
|
+
},
|
|
81
|
+
candlestick: {
|
|
82
|
+
upColor: "#00ff00",
|
|
83
|
+
downColor: "#ff0000"
|
|
84
|
+
},
|
|
274
85
|
xAxisSpacing: 0,
|
|
275
86
|
yAxisSpacing: 4, // undocumented
|
|
276
|
-
xAxisModulo: 1 // undocumented
|
|
87
|
+
xAxisModulo: 1 // undocumented,
|
|
277
88
|
};
|
|
278
89
|
var m_startdate = null;
|
|
279
90
|
var m_chartspaces = {
|
|
@@ -286,6 +97,7 @@ function Milli_Chart(settings) {
|
|
|
286
97
|
height: 0
|
|
287
98
|
}
|
|
288
99
|
};
|
|
100
|
+
let chartType; // history or trades, set in drawChart
|
|
289
101
|
var m_dummyDiv = null; // dummy div For chartclasses
|
|
290
102
|
var m_canvas = null;
|
|
291
103
|
var m_ctx = null;
|
|
@@ -318,6 +130,9 @@ function Milli_Chart(settings) {
|
|
|
318
130
|
};
|
|
319
131
|
var m_lastDrawnInstrument = -1;
|
|
320
132
|
var m_priceIndicator = undefined;
|
|
133
|
+
const INDICATOR = 0;
|
|
134
|
+
const NEWSINDICATOR = 1;
|
|
135
|
+
const FUTUREINDICATOR = 2;
|
|
321
136
|
|
|
322
137
|
MillistreamWidgetApi_AssignObject(MillistreamWidgetSettings, _this.settings);
|
|
323
138
|
if (settings) {
|
|
@@ -404,7 +219,8 @@ function Milli_Chart(settings) {
|
|
|
404
219
|
}
|
|
405
220
|
|
|
406
221
|
function getScaledSetting(setting) {
|
|
407
|
-
return parseInt(setting)
|
|
222
|
+
return parseInt(setting);
|
|
223
|
+
// return parseInt(setting) * window.devicePixelRatio;
|
|
408
224
|
}
|
|
409
225
|
_this.get_lang_text = function(string) {
|
|
410
226
|
return string;
|
|
@@ -444,7 +260,7 @@ function Milli_Chart(settings) {
|
|
|
444
260
|
}
|
|
445
261
|
|
|
446
262
|
function getFontSize(obj) {
|
|
447
|
-
//return parseInt(obj.fontSize) *
|
|
263
|
+
//return parseInt(obj.fontSize) * 1;
|
|
448
264
|
return parseInt(obj.fontSize);
|
|
449
265
|
}
|
|
450
266
|
|
|
@@ -593,46 +409,149 @@ function Milli_Chart(settings) {
|
|
|
593
409
|
return value * Math.pow(10, x);
|
|
594
410
|
}
|
|
595
411
|
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
412
|
+
|
|
413
|
+
function drawYAxisIndicator(data, cs, legendItems) {
|
|
414
|
+
m_ctx.save();
|
|
415
|
+
m_ctx.font = m_yLegendCss.fontWeight + ' ' + m_yLegendCss.fontSize + ' ' + m_yLegendCss.fontFamily;
|
|
416
|
+
m_ctx.fillStyle = m_yLegendCss.color;
|
|
417
|
+
m_ctx.beginPath();
|
|
418
|
+
m_ctx.strokeStyle = m_gridVerticalCss.color;
|
|
419
|
+
m_ctx.moveTo(cs.left + 0.5, cs.top);
|
|
420
|
+
m_ctx.lineTo(cs.left + 0.5, cs.bottom);
|
|
421
|
+
m_ctx.stroke();
|
|
422
|
+
m_ctx.closePath();
|
|
423
|
+
var x = cs.left - 3;
|
|
424
|
+
var lineLength = cs.bottom - cs.top;
|
|
425
|
+
var numticks = lineLength / (getFontSize(m_yLegendCss) * 2);
|
|
426
|
+
if (numticks < 1) {
|
|
427
|
+
console.log('no space for legenditems', lineLength, m_chartspaces);
|
|
428
|
+
return null;
|
|
429
|
+
}
|
|
430
|
+
let sc = calculateIndicatorScale(data, cs);
|
|
431
|
+
if (sc == null) {
|
|
432
|
+
console.log('No scale');
|
|
433
|
+
return null;
|
|
434
|
+
}
|
|
435
|
+
if (typeof minvalue !== 'undefined') return sc;
|
|
436
|
+
if (numticks > 8) numticks = 8; // limit to 8 items on Y legend ( this is not an absolut count, since we calculate nice legend numbers
|
|
437
|
+
|
|
438
|
+
sc.valuePerPixel = (sc.maxValue - sc.minValue) / lineLength;
|
|
439
|
+
if (isNaN(sc.valuePerPixel) || !isFinite(sc.valuePerPixel)) {
|
|
440
|
+
console.log('cant draw valuePerPixel' + sc.valuePerPixel, lineLength, sc.maxValue);
|
|
441
|
+
return null;
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
m_ctx.strokeStyle = m_gridHorizontalCss.color;
|
|
445
|
+
m_ctx.fillStyle = m_yLegendCss.color;
|
|
446
|
+
|
|
447
|
+
m_ctx.textAlign = 'right';
|
|
448
|
+
var tickSize = getTickValue(sc.low, sc.high, numticks);
|
|
449
|
+
|
|
450
|
+
let value = sc.minValue;
|
|
451
|
+
if (sc.high == sc.low) { // only have one value so set values for 1 line only
|
|
452
|
+
sc.maxValue = sc.maxValue + tickSize;
|
|
453
|
+
sc.minValue = sc.minValue - tickSize;
|
|
454
|
+
value = Math.abs(sc.lowValue);
|
|
455
|
+
} else {
|
|
456
|
+
if (sc.minValue > 0)
|
|
457
|
+
value = sc.minValue - fmod(Math.abs(sc.minValue), tickSize) + tickSize;
|
|
458
|
+
else
|
|
459
|
+
value = sc.minValue + fmod(Math.abs(sc.minValue), tickSize) - tickSize;
|
|
460
|
+
}
|
|
461
|
+
for (let c = 0; c < 10; c++) { // max 10 legenditems
|
|
462
|
+
let y = Math.round(cs.height - cs.marginBottom - ((value - sc.minValue) * sc.valuePerPixel)) + 0.5;
|
|
463
|
+
y = Math.round((cs.bottom - cs.top) - ((value - sc.minValue) / sc.valuePerPixel)) + 0.5 + cs.top;
|
|
464
|
+
if (y <= cs.top) break;
|
|
465
|
+
if (y <= cs.bottom) {
|
|
466
|
+
if (_this.settings.gridHorizontalLines == true && legendItems) {
|
|
467
|
+
m_ctx.save();
|
|
468
|
+
if (_this.settings.gridHorizontalLinesStyle == 'dash') {
|
|
469
|
+
m_ctx.setLineDash([3, 3]);
|
|
470
|
+
}
|
|
471
|
+
m_ctx.beginPath();
|
|
472
|
+
m_ctx.moveTo(cs.left, y + 0.5);
|
|
473
|
+
m_ctx.lineTo(cs.right, y + 0.5);
|
|
474
|
+
m_ctx.stroke();
|
|
475
|
+
m_ctx.closePath();
|
|
476
|
+
m_ctx.restore();
|
|
477
|
+
} else
|
|
478
|
+
if (_this.settings.drawyaxis == true && legendItems == true) { // draw legenditem markers for price
|
|
479
|
+
m_ctx.beginPath();
|
|
480
|
+
m_ctx.moveTo(cs.left, y + 0.5);
|
|
481
|
+
m_ctx.lineTo(cs.left + 3, y + 0.5);
|
|
482
|
+
m_ctx.stroke();
|
|
483
|
+
m_ctx.closePath();
|
|
484
|
+
}
|
|
485
|
+
if (legendItems == true && _this.settings.drawyaxis == true) {
|
|
486
|
+
var label = formatLargeNumber(value, 0, _this);
|
|
487
|
+
var textpos = x - 5;
|
|
488
|
+
if (m_yLegendCss.verticalAlign == 'top') {
|
|
489
|
+
if (y - (getFontSize(m_yLegendCss)) > 0) // dont draw if cropped
|
|
490
|
+
m_ctx.fillText(label, textpos, y - ((getFontSize(m_yLegendCss) + 2)));
|
|
491
|
+
} else
|
|
492
|
+
m_ctx.fillText(label, textpos, y - (getFontSize(m_yLegendCss) / 2));
|
|
493
|
+
}
|
|
494
|
+
}
|
|
495
|
+
value += tickSize;
|
|
496
|
+
}
|
|
497
|
+
m_ctx.restore();
|
|
498
|
+
return sc;
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
function checkYLegendSpace(y, text) {
|
|
502
|
+
if (y - (getFontSize(m_yLegendCss)) - m_chartspaces.chart.top < 0) return false;
|
|
503
|
+
if (y > m_chartspaces.chart.bottom) return false;
|
|
504
|
+
return true;
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
function calcHighLow(scaleinfoY, scaleinfoY2) {
|
|
508
|
+
scaleinfoY.lowValue = null;
|
|
509
|
+
scaleinfoY.highValue = null;
|
|
510
|
+
scaleinfoY2.lowValue = null;
|
|
511
|
+
scaleinfoY2.highValue = null;
|
|
512
|
+
|
|
603
513
|
var data, i;
|
|
604
514
|
var useCloseprice = false;
|
|
605
515
|
var today = new Date().getTime();
|
|
606
516
|
today -= today % 86400000;
|
|
607
517
|
var lastTradeDate = new Date().getTime();
|
|
608
518
|
var todaysOpenTime = new Date(new Date().toISOString().substring(0, 10) + 'T' + _this.instruments[0].marketopen + 'Z').getTime();
|
|
519
|
+
|
|
609
520
|
if (typeof _this.instruments[0].trades !== 'undefined' && _this.instruments[0].trades.length > 0) {
|
|
610
521
|
lastTradeDate = new Date(_this.instruments[0].trades[_this.instruments[0].trades.length - 1].timestamp).getTime();
|
|
611
522
|
lastTradeDate -= lastTradeDate % 86400000;
|
|
612
523
|
}
|
|
613
|
-
var quote_timestamp = _this.instruments[0].quotedate + _this.instruments[0].quotetime;
|
|
614
524
|
|
|
525
|
+
var quote_timestamp = _this.instruments[0].quotedate + _this.instruments[0].quotetime;
|
|
615
526
|
if ((_this.instruments[0].quotedate == today && quote_timestamp > todaysOpenTime) || _this.instruments[0].quotedate == lastTradeDate) useCloseprice = true;
|
|
527
|
+
|
|
616
528
|
for (var s = 0; s < _this.instruments.length; s++) {
|
|
617
529
|
if (_this.instruments[s].insref == 0) continue;
|
|
618
530
|
_this.instruments[s].startValue = null;
|
|
619
|
-
data = _this.instruments[s][
|
|
620
|
-
if (
|
|
531
|
+
data = _this.instruments[s][chartType];
|
|
532
|
+
if (chartType != 'history' && useCloseprice) {
|
|
621
533
|
if ((_this.settings.chartlen == '1d' || _this.settings.chartlen == '0d') && !m_zoom.mousedown.timestamp) {
|
|
622
534
|
_this.instruments[s].startValue = parseFloat(_this.instruments[s].closeprice1d) * _this.instruments[s].factor;
|
|
623
535
|
}
|
|
624
536
|
}
|
|
625
|
-
var quantity = 0;
|
|
626
|
-
|
|
537
|
+
//var quantity = 0;
|
|
538
|
+
let prevPrice = null;
|
|
627
539
|
for (i = 0; i < data.length; i++) {
|
|
628
540
|
// only calc on visible data
|
|
629
541
|
var price = data[i].price * _this.instruments[s].factor;
|
|
630
|
-
|
|
631
|
-
|
|
542
|
+
let highprice = data[i].highprice * _this.instruments[s].factor;
|
|
543
|
+
let lowprice = data[i].lowprice * _this.instruments[s].factor;
|
|
544
|
+
|
|
545
|
+
//quantity = 0;
|
|
546
|
+
/*if (data[i].quantity !== 'undefined') {
|
|
632
547
|
quantity = data[i].quantity;
|
|
633
|
-
}
|
|
548
|
+
}*/
|
|
634
549
|
if (data[i].timestamp < _this.scaleinfoX.startTimeStamp) {
|
|
635
|
-
if (
|
|
550
|
+
if (chartType == 'history') {
|
|
551
|
+
//_this.instruments[s].startValue = price; // skall inte sättas eftersom vi inte ritar den i history
|
|
552
|
+
scaleinfoY2.lowValue = 0;
|
|
553
|
+
scaleinfoY2.highValue = 0;
|
|
554
|
+
}
|
|
636
555
|
//else if (_this.settings.chartlen != '1d' && _this.settings.chartlen != '0d' && !m_zoom.mousedown.timestamp) {
|
|
637
556
|
else if (useCloseprice == false || m_zoom.mousedown.timestamp) {
|
|
638
557
|
_this.instruments[s].startValue = price;
|
|
@@ -642,14 +561,15 @@ function Milli_Chart(settings) {
|
|
|
642
561
|
if (data[i].timestamp > _this.scaleinfoX.endTimeStamp) {
|
|
643
562
|
break;
|
|
644
563
|
}
|
|
564
|
+
_this.instruments[s].endValue = price;
|
|
645
565
|
|
|
646
|
-
if (
|
|
566
|
+
if (chartType != 'history' && (data[i].timestamp % 86400000 < _this.instruments[0].opentimestamp || data[i].timestamp % 86400000 > _this.instruments[0].closetimestamp)) {
|
|
647
567
|
// stämmer detta kan det bli överlapp vid sommartid/vintertid?
|
|
648
568
|
continue;
|
|
649
569
|
}
|
|
650
570
|
|
|
651
|
-
if (_this.instruments[s].startValue == null) {
|
|
652
|
-
if (
|
|
571
|
+
if (_this.instruments[s].startValue == null) { // no value before this date , use this date?
|
|
572
|
+
if (chartType == 'history') {
|
|
653
573
|
_this.instruments[s].startValue = price;
|
|
654
574
|
} else {
|
|
655
575
|
if (isToday(new Date(data[i].timestamp)) && !m_zoom.mousedown.timestamp) {
|
|
@@ -659,51 +579,64 @@ function Milli_Chart(settings) {
|
|
|
659
579
|
}
|
|
660
580
|
}
|
|
661
581
|
}
|
|
662
|
-
if
|
|
663
|
-
|
|
582
|
+
if(_this.settings.type == 'ohlc' || _this.settings.type == 'candlestick') {
|
|
583
|
+
if (scaleinfoY.lowValue == null || scaleinfoY.lowValue > lowprice) scaleinfoY.lowValue = lowprice;
|
|
584
|
+
if (scaleinfoY.highValue == null || scaleinfoY.highValue < highprice) scaleinfoY.highValue = highprice;
|
|
585
|
+
}
|
|
586
|
+
else {
|
|
587
|
+
if (scaleinfoY.lowValue == null || scaleinfoY.lowValue > price) scaleinfoY.lowValue = price;
|
|
588
|
+
if (scaleinfoY.highValue == null || scaleinfoY.highValue < price) scaleinfoY.highValue = price;
|
|
589
|
+
}
|
|
664
590
|
var diff = (price - _this.instruments[s].startValue);
|
|
665
591
|
if (diff != 0) diff = diff / _this.instruments[s].startValue * 100;
|
|
666
592
|
if (_this.instruments[s].startValue == null) diff = 0;
|
|
667
593
|
data[i].diff = diff;
|
|
668
|
-
|
|
669
|
-
if (
|
|
670
|
-
if (
|
|
671
|
-
if (
|
|
672
|
-
if (_this.scaleinfoY.highLowerChart == null || _this.scaleinfoY.highLowerChart < quantity) _this.scaleinfoY.highLowerChart = quantity;
|
|
594
|
+
if (scaleinfoY2.lowValue == null || scaleinfoY2.lowValue > diff) scaleinfoY2.lowValue = diff;
|
|
595
|
+
if (scaleinfoY2.highValue == null || scaleinfoY2.highValue < diff) scaleinfoY2.highValue = diff;
|
|
596
|
+
//if (scaleinfoY.lowLowerChart == null || scaleinfoY.lowLowerChart > quantity) scaleinfoY.lowLowerChart = quantity;
|
|
597
|
+
//if (scaleinfoY.highLowerChart == null || scaleinfoY.highLowerChart < quantity) scaleinfoY.highLowerChart = quantity;
|
|
673
598
|
}
|
|
674
599
|
if ((_this.settings.chartlen == '1d' || _this.settings.chartlen == '0d') && !m_zoom.mousedown.timestamp) { // if closeprice is used calch high/low on it
|
|
675
600
|
var cp = parseFloat(_this.instruments[s].closeprice1d) * _this.instruments[s].factor;
|
|
676
|
-
if (
|
|
601
|
+
if (scaleinfoY.lowValue > cp) scaleinfoY.lowValue = cp;
|
|
677
602
|
else
|
|
678
|
-
if (
|
|
603
|
+
if (scaleinfoY.highValue < cp) scaleinfoY.highValue = cp;
|
|
679
604
|
}
|
|
680
|
-
if (
|
|
681
|
-
if (
|
|
682
|
-
|
|
605
|
+
if (chartType != 'history') {
|
|
606
|
+
if (scaleinfoY2.lowValue > 0) {
|
|
607
|
+
scaleinfoY2.lowValue = 0;
|
|
683
608
|
} else {
|
|
684
|
-
if (
|
|
609
|
+
if (scaleinfoY2.highValue < 0) scaleinfoY2.highValue = 0;
|
|
685
610
|
}
|
|
686
611
|
}
|
|
687
|
-
if (_this.instruments[s].startValue) {
|
|
688
|
-
if (_this.instruments[s].startValue >
|
|
689
|
-
if (_this.instruments[s].startValue <
|
|
612
|
+
if (_this.instruments[s].startValue) { // ta bort? fråga mats
|
|
613
|
+
if (_this.instruments[s].startValue > scaleinfoY.highValue) scaleinfoY.highValue = _this.instruments[s].startValue;
|
|
614
|
+
if (_this.instruments[s].startValue < scaleinfoY.lowValue) scaleinfoY.lowValue = _this.instruments[s].startValue;
|
|
690
615
|
}
|
|
691
616
|
}
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
617
|
+
if (scaleinfoY.lowValue == null) {
|
|
618
|
+
scaleinfoY.lowValue = 0;
|
|
619
|
+
scaleinfoY.highValue = 100;
|
|
620
|
+
scaleinfoY2.lowValue = 0;
|
|
621
|
+
scaleinfoY2.highValue = 100;
|
|
622
|
+
return;
|
|
698
623
|
} else
|
|
699
|
-
if (
|
|
700
|
-
|
|
701
|
-
|
|
624
|
+
if (scaleinfoY.lowValue == scaleinfoY.highValue && scaleinfoY.lowValue == 0) {
|
|
625
|
+
scaleinfoY.lowValue -= 1;
|
|
626
|
+
scaleinfoY.highValue += 1;
|
|
627
|
+
scaleinfoY.lowValue -= 1;
|
|
628
|
+
scaleinfoY.highValue += 1;
|
|
702
629
|
}
|
|
703
630
|
// do we have any analyzis we need to take into account
|
|
704
631
|
for (i = 0; i < _this.settings.indicators.length; i++) {
|
|
705
|
-
if (_this.
|
|
706
|
-
|
|
632
|
+
if (_this.settings.indicators[i].method == 'rsi') continue;
|
|
633
|
+
if (_this.settings.indicators[i].method == 'quantity') continue;
|
|
634
|
+
if (_this.settings.indicators[i].method == 'news') continue;
|
|
635
|
+
if (_this.settings.indicators[i].target == 'lower') continue;
|
|
636
|
+
if (!_this.settings.indicators[i].timeseries || _this.settings.indicators[i].timeseries.length == 0) {
|
|
637
|
+
continue;
|
|
638
|
+
}
|
|
639
|
+
data = _this.settings.indicators[i].timeseries;
|
|
707
640
|
for (s = 0; s < data.length; s++) {
|
|
708
641
|
if (data[s].timestamp < _this.scaleinfoX.startTimeStamp) {
|
|
709
642
|
continue;
|
|
@@ -712,132 +645,214 @@ function Milli_Chart(settings) {
|
|
|
712
645
|
break;
|
|
713
646
|
}
|
|
714
647
|
if (typeof data[s].datapoints !== 'undefined') {
|
|
715
|
-
for (var x = 0; x < data[
|
|
716
|
-
if (data[s].datapoints[x] <
|
|
717
|
-
|
|
718
|
-
|
|
648
|
+
for (var x = 0; x < data[s].datapoints.length; x++) {
|
|
649
|
+
if (data[s].datapoints[x] < scaleinfoY.lowValue) {
|
|
650
|
+
scaleinfoY.lowValue = data[s].datapoints[x];
|
|
651
|
+
scaleinfoY2.lowValue = data[s].datapoints[x] - _this.instruments[0].startValue; // lower min diff to get full legend from bottom
|
|
652
|
+
} else {
|
|
653
|
+
if (data[s].datapoints[x] > scaleinfoY.highValue) {
|
|
654
|
+
scaleinfoY.highValue = data[s].datapoints[x];
|
|
655
|
+
scaleinfoY2.highValue = data[s].datapoints[x] - _this.instruments[0].startValue; // lower min diff to get full legend from bottom
|
|
656
|
+
}
|
|
657
|
+
}
|
|
719
658
|
}
|
|
720
659
|
}
|
|
721
660
|
}
|
|
722
661
|
}
|
|
723
|
-
|
|
724
|
-
|
|
662
|
+
scaleinfoY2.lowValue = (scaleinfoY.lowValue - _this.instruments[0].startValue) / _this.instruments[0].startValue * 100;
|
|
663
|
+
scaleinfoY2.highValue = (scaleinfoY.highValue - _this.instruments[0].startValue) / _this.instruments[0].startValue * 100;
|
|
725
664
|
return 1;
|
|
726
665
|
}
|
|
727
666
|
|
|
728
|
-
function
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
_this.scaleinfoY.highLowerChart = null;
|
|
667
|
+
function calcHighLow2(scale, cs, css, factorInfo) {
|
|
668
|
+
scale.lowValue = null;
|
|
669
|
+
scale.highValue = null;
|
|
732
670
|
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
if (numticks < 1) return;
|
|
740
|
-
if (numticks > 10) numticks = 10;
|
|
741
|
-
m_ctx.strokeStyle = m_gridHorizontalCss.color;
|
|
742
|
-
m_ctx.fillStyle = m_yLegendCss.color;
|
|
671
|
+
let data, i;
|
|
672
|
+
let useCloseprice = false;
|
|
673
|
+
let today = new Date().getTime();
|
|
674
|
+
today -= today % 86400000;
|
|
675
|
+
let lastTradeDate = new Date().getTime();
|
|
676
|
+
let todaysOpenTime = new Date(new Date().toISOString().substring(0, 10) + 'T' + _this.instruments[0].marketopen + 'Z').getTime();
|
|
743
677
|
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
var valuePerPixel = lineLength / maxValue;
|
|
748
|
-
if (isNaN(valuePerPixel) || !isFinite(valuePerPixel)) {
|
|
749
|
-
console.log('cant draw valuePerPixel' + valuePerPixel, lineLength, maxValue);
|
|
750
|
-
return false;
|
|
678
|
+
if (typeof _this.instruments[0].trades !== 'undefined' && _this.instruments[0].trades.length > 0) {
|
|
679
|
+
lastTradeDate = new Date(_this.instruments[0].trades[_this.instruments[0].trades.length - 1].timestamp).getTime();
|
|
680
|
+
lastTradeDate -= lastTradeDate % 86400000;
|
|
751
681
|
}
|
|
752
|
-
var value = 0;
|
|
753
|
-
for (i = 0; i < numticks; i++) {
|
|
754
|
-
var y = Math.round(m_chartspaces.lowerChart.bottom - (value * valuePerPixel));
|
|
755
682
|
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
683
|
+
var quote_timestamp = _this.instruments[0].quotedate + _this.instruments[0].quotetime;
|
|
684
|
+
if ((_this.instruments[0].quotedate == today && quote_timestamp > todaysOpenTime) || _this.instruments[0].quotedate == lastTradeDate) useCloseprice = true;
|
|
685
|
+
|
|
686
|
+
for (var s = 0; s < _this.instruments.length; s++) {
|
|
687
|
+
if (_this.instruments[s].insref == 0) continue;
|
|
688
|
+
_this.instruments[s].startValue = null;
|
|
689
|
+
data = _this.instruments[s][chartType];
|
|
690
|
+
if (chartType != 'history' && useCloseprice) {
|
|
691
|
+
if ((_this.settings.chartlen == '1d' || _this.settings.chartlen == '0d') && !m_zoom.mousedown.timestamp) {
|
|
692
|
+
_this.instruments[s].startValue = parseFloat(_this.instruments[s].closeprice1d) * _this.instruments[s].factor;
|
|
693
|
+
}
|
|
694
|
+
}
|
|
695
|
+
//var quantity = 0;
|
|
696
|
+
|
|
697
|
+
for (i = 0; i < data.length; i++) {
|
|
698
|
+
// only calc on visible data
|
|
699
|
+
var price = data[i].price * _this.instruments[s].factor;
|
|
700
|
+
|
|
701
|
+
//quantity = 0;
|
|
702
|
+
/*if (data[i].quantity !== 'undefined') {
|
|
703
|
+
quantity = data[i].quantity;
|
|
704
|
+
}*/
|
|
705
|
+
if (data[i].timestamp < _this.scaleinfoX.startTimeStamp) {
|
|
706
|
+
if (chartType == 'history') {
|
|
707
|
+
_this.instruments[s].startValue = price;
|
|
762
708
|
}
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
m_ctx.beginPath();
|
|
772
|
-
m_ctx.moveTo(m_chartspaces.lowerChart.left, y + 0.5);
|
|
773
|
-
m_ctx.lineTo(m_chartspaces.lowerChart.left + 3, y + 0.5);
|
|
774
|
-
m_ctx.stroke();
|
|
775
|
-
m_ctx.closePath();
|
|
709
|
+
//else if (_this.settings.chartlen != '1d' && _this.settings.chartlen != '0d' && !m_zoom.mousedown.timestamp) {
|
|
710
|
+
else if (useCloseprice == false || m_zoom.mousedown.timestamp) {
|
|
711
|
+
_this.instruments[s].startValue = price;
|
|
712
|
+
}
|
|
713
|
+
continue;
|
|
714
|
+
}
|
|
715
|
+
if (data[i].timestamp > _this.scaleinfoX.endTimeStamp) {
|
|
716
|
+
break;
|
|
776
717
|
}
|
|
777
718
|
|
|
778
|
-
if (
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
719
|
+
if (chartType != 'history' && (data[i].timestamp % 86400000 < _this.instruments[0].opentimestamp || data[i].timestamp % 86400000 > _this.instruments[0].closetimestamp)) { // summertime?
|
|
720
|
+
continue;
|
|
721
|
+
}
|
|
722
|
+
|
|
723
|
+
if (_this.instruments[s].startValue == null) { // no value before this date , use this date?
|
|
724
|
+
if (chartType == 'history') {
|
|
725
|
+
_this.instruments[s].startValue = price;
|
|
726
|
+
} else {
|
|
727
|
+
if (isToday(new Date(data[i].timestamp)) && !m_zoom.mousedown.timestamp) {
|
|
728
|
+
_this.instruments[s].startValue = parseFloat(_this.instruments[s].closeprice1d) * _this.instruments[s].factor;
|
|
729
|
+
} else {
|
|
730
|
+
_this.instruments[s].startValue = price;
|
|
731
|
+
}
|
|
732
|
+
}
|
|
733
|
+
}
|
|
734
|
+
if (typeof factorInfo === 'undefined') {
|
|
735
|
+
if (scale.lowValue == null || scale.lowValue > price) scale.lowValue = price;
|
|
736
|
+
if (scale.highValue == null || scale.highValue < price) scale.highValue = price;
|
|
737
|
+
} else {
|
|
738
|
+
let diff = (price - _this.instruments[s].startValue);
|
|
739
|
+
if (diff != 0) diff = diff / _this.instruments[s].startValue * 100;
|
|
740
|
+
if (_this.instruments[s].startValue == null) diff = 0;
|
|
741
|
+
data[i][factorInfo.name] = diff;
|
|
742
|
+
if (scale.lowValue == null || scale.lowValue > diff) scale.lowValue = diff;
|
|
743
|
+
if (scale.highValue == null || scale.highValue < diff) scale.highValue = diff;
|
|
744
|
+
}
|
|
745
|
+
}
|
|
746
|
+
// hur hantera om factorInfo
|
|
747
|
+
if ((_this.settings.chartlen == '1d' || _this.settings.chartlen == '0d') && !m_zoom.mousedown.timestamp) { // if closeprice is used calch high/low on it
|
|
748
|
+
var cp = parseFloat(_this.instruments[s].closeprice1d) * _this.instruments[s].factor;
|
|
749
|
+
if (scale.lowValue > cp) scale.lowValue = cp;
|
|
750
|
+
else
|
|
751
|
+
if (scale.highValue < cp) scale.highValue = cp;
|
|
752
|
+
}
|
|
753
|
+
if (chartType != 'history') {
|
|
754
|
+
consolle
|
|
755
|
+
if (scale.lowValue > 0) {
|
|
756
|
+
scale.lowValue = 0;
|
|
757
|
+
} else {
|
|
758
|
+
if (scale.highValue < 0) scale.highValue = 0;
|
|
759
|
+
}
|
|
760
|
+
}
|
|
761
|
+
if (typeof factorInfo === 'undefined') {
|
|
762
|
+
if (_this.instruments[s].startValue) { // ta bort? fråga mats
|
|
763
|
+
if (_this.instruments[s].startValue > scale.highValue) scale.highValue = _this.instruments[s].startValue;
|
|
764
|
+
if (_this.instruments[s].startValue < scale.lowValue) scale.lowValue = _this.instruments[s].startValue;
|
|
786
765
|
}
|
|
787
766
|
}
|
|
788
|
-
value += tickSize;
|
|
789
767
|
}
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
768
|
+
if (scale.lowValue == null) {
|
|
769
|
+
scale.lowValue = 0;
|
|
770
|
+
scale.highValue = 100;
|
|
771
|
+
} else
|
|
772
|
+
if (scale.lowValue == scale.highValue && scale.lowValue == 0) {
|
|
773
|
+
scale.lowValue -= 1;
|
|
774
|
+
scale.highValue += 1;
|
|
775
|
+
}
|
|
776
|
+
// do we have any analyzis we need to take into account
|
|
777
|
+
if (typeof factorInfo === 'undefined') {
|
|
778
|
+
for (i = 0; i < _this.settings.indicators.length; i++) {
|
|
779
|
+
if (_this.settings.indicators[i].method == 'rsi') continue;
|
|
780
|
+
if (_this.settings.indicators[i].method == 'quantity') continue;
|
|
781
|
+
if (!_this.settings.indicators[i].timeseries || _this.settings.indicators[i].timeseries.length == 0) continue;
|
|
782
|
+
data = _this.settings.indicators[i].timeseries;
|
|
783
|
+
for (s = 0; s < data.length; s++) {
|
|
784
|
+
if (data[s].timestamp < _this.scaleinfoX.startTimeStamp) {
|
|
785
|
+
continue;
|
|
786
|
+
}
|
|
787
|
+
if (data[s].timestamp > _this.scaleinfoX.endTimeStamp) {
|
|
788
|
+
break;
|
|
789
|
+
}
|
|
790
|
+
if (typeof data[s].datapoints !== 'undefined') {
|
|
791
|
+
for (var x = 0; x < data[i].datapoints.length; x++) {
|
|
792
|
+
if (data[s].datapoints[x] < scale.lowValue) {
|
|
793
|
+
scale.lowValue = data[s].datapoints[x];
|
|
794
|
+
} else {
|
|
795
|
+
if (data[s].datapoints[x] > scaleinfoY.highValue) {
|
|
796
|
+
scale.highValue = data[s].datapoints[x];
|
|
797
|
+
}
|
|
798
|
+
}
|
|
799
|
+
}
|
|
800
|
+
}
|
|
801
|
+
}
|
|
802
|
+
}
|
|
803
|
+
}
|
|
804
|
+
m_ctx.font = css.fontWeight + ' ' + css.fontSize + ' ' + css.fontFamily; // set font so measure works
|
|
793
805
|
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
806
|
+
let v = (scale.highValue - scale.lowValue) / scale.lineLength;
|
|
807
|
+
scale.maxValue = scale.highValue + (v * parseInt(css.fontSize));
|
|
808
|
+
scale.minValue = scale.lowValue - (v * parseInt(css.fontSize));
|
|
809
|
+
scale.lineLength = cs.bottom - cs.top;
|
|
810
|
+
|
|
811
|
+
let numticks = scale.lineLength / (getFontSize(css) * _this.settings.yAxisSpacing);
|
|
800
812
|
if (numticks > 8) numticks = 8; // limit to 8 items on Y legend ( this is not an absolut count, since we calculate nice legend numbers
|
|
813
|
+
scale.tickSize = getTickValue(scale.lowValue, scale.highValue, numticks);
|
|
814
|
+
scale.decimals = scale.tickSize.countDecimals();
|
|
801
815
|
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
m_ctx.stroke();
|
|
807
|
-
m_ctx.closePath();
|
|
808
|
-
var x = m_chartspaces.lowerChart.left - 3;
|
|
809
|
-
drawYLegendLower(x, numticks, lineLen, true);
|
|
810
|
-
m_ctx.restore();
|
|
811
|
-
}
|
|
816
|
+
if (typeof factorInfo === 'undefined') {
|
|
817
|
+
if (scale.decimals > 4) scale.decimals = 4;
|
|
818
|
+
else if (scale.decimals < 2) scale.decimals = 2;
|
|
819
|
+
}
|
|
812
820
|
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
if (
|
|
816
|
-
if (
|
|
821
|
+
let widestValue = (scale.lowValue < 0 ? '-' : '') + Math.max(Math.abs(scale.highValue), Math.abs(scale.lowValue));
|
|
822
|
+
let label = formatNiceNumber(widestValue, _this.settings.thousandseparator, _this.settings.decimalseparator, scale.decimals);
|
|
823
|
+
if (typeof factorInfo !== 'undefined' && typeof factorInfo.suffix !== 'undefined') label += factorInfo.suffix;
|
|
824
|
+
if (css.float != 'right') {
|
|
825
|
+
cs.left = 10 + Math.round(m_ctx.measureText(label).width); // + 'px'; // räkna fram hur hur mycket plats Y värdena tar och sätt margin till det, skall vi göra så?
|
|
826
|
+
} else {
|
|
827
|
+
if (css.textAlign == 'right') {
|
|
828
|
+
cs.right = m_canvas.getWidth() - (10 + Math.round(m_ctx.measureText(label).width)); // + 'px'; // räkna fram hur hur mycket plats Y värdena tar och sätt margin till det, skall vi göra så?
|
|
829
|
+
}
|
|
830
|
+
}
|
|
817
831
|
return true;
|
|
818
832
|
}
|
|
819
833
|
|
|
820
|
-
|
|
834
|
+
|
|
835
|
+
function drawY2Legend(scaleinfoY, scaleinfoY2, x) { // percent
|
|
821
836
|
if (_this.instruments[0].pricetype == 'yield') return;
|
|
822
837
|
if (_this.settings.absoluteScaling == true) {
|
|
823
838
|
for (var s = 1; s < _this.instruments.length; s++) {
|
|
824
839
|
if (_this.instruments[s].insref != 0) return;
|
|
825
840
|
}
|
|
826
841
|
}
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
842
|
+
if (_this.instruments[0].startValue == null || (scaleinfoY2.highValue == 100 && scaleinfoY2.lowValue == 0)) return false;
|
|
843
|
+
scaleinfoY2.maxValue = scaleinfoY2.highValue + (scaleinfoY2.tickSize * 0.2);
|
|
844
|
+
scaleinfoY2.minValue = scaleinfoY2.lowValue - (scaleinfoY2.tickSize * 0.2);
|
|
830
845
|
m_ctx.font = m_y2LegendCss.fontWeight + ' ' + m_y2LegendCss.fontSize + ' ' + m_y2LegendCss.fontFamily;
|
|
831
846
|
var value;
|
|
832
|
-
if (
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
value = Math.abs(
|
|
847
|
+
if (scaleinfoY2.highValue == scaleinfoY2.lowValue) {
|
|
848
|
+
scaleinfoY2.maxValue += scaleinfoY2.tickSize;
|
|
849
|
+
scaleinfoY2.minValue -= scaleinfoY2.tickSize;
|
|
850
|
+
value = Math.abs(scaleinfoY2.minValue);
|
|
836
851
|
} else {
|
|
837
|
-
if (
|
|
838
|
-
value =
|
|
852
|
+
if (scaleinfoY2.minValue > 0)
|
|
853
|
+
value = scaleinfoY2.minValue - fmod(Math.abs(scaleinfoY2.minValue), scaleinfoY2.tickSize) + scaleinfoY2.tickSize;
|
|
839
854
|
else {
|
|
840
|
-
value =
|
|
855
|
+
value = scaleinfoY2.minValue + fmod(Math.abs(scaleinfoY2.minValue), scaleinfoY2.tickSize) - scaleinfoY2.tickSize;
|
|
841
856
|
}
|
|
842
857
|
}
|
|
843
858
|
var startPrice = _this.instruments[0].startValue;
|
|
@@ -854,10 +869,9 @@ function Milli_Chart(settings) {
|
|
|
854
869
|
v = startPrice - (startPrice * (value / 100));
|
|
855
870
|
else
|
|
856
871
|
v = startPrice + (startPrice * (value / 100));
|
|
857
|
-
var y = Math.round(m_chartspaces.chart.height -
|
|
872
|
+
var y = Math.round(m_chartspaces.chart.height - m_chartspaces.chart.marginBottom - ((v - scaleinfoY.minValue) / scaleinfoY.valuePerPixel));
|
|
858
873
|
|
|
859
874
|
if (y <= m_chartspaces.chart.top) break;
|
|
860
|
-
//if (y > m_chartspaces.chart.bottom) break;
|
|
861
875
|
if (y <= m_chartspaces.chart.bottom) {
|
|
862
876
|
if (_this.settings.drawy2axis == true) { // draw legenditem markers for diff
|
|
863
877
|
m_ctx.beginPath();
|
|
@@ -872,7 +886,7 @@ function Milli_Chart(settings) {
|
|
|
872
886
|
m_ctx.stroke();
|
|
873
887
|
m_ctx.closePath();
|
|
874
888
|
}
|
|
875
|
-
var label = formatNiceNumber(value, _this.settings.thousandseparator, _this.settings.decimalseparator,
|
|
889
|
+
var label = formatNiceNumber(value, _this.settings.thousandseparator, _this.settings.decimalseparator, scaleinfoY2.decimals, true) + '%';
|
|
876
890
|
if (m_y2LegendCss.verticalAlign == 'top') {
|
|
877
891
|
if (checkYLegendSpace(y, label))
|
|
878
892
|
m_ctx.fillText(label, textpos, y - ((getFontSize(m_y2LegendCss) + 2)));
|
|
@@ -882,21 +896,18 @@ function Milli_Chart(settings) {
|
|
|
882
896
|
}
|
|
883
897
|
}
|
|
884
898
|
}
|
|
885
|
-
value +=
|
|
899
|
+
value += scaleinfoY2.tickSize;
|
|
886
900
|
}
|
|
887
901
|
return true;
|
|
888
902
|
}
|
|
889
903
|
|
|
890
904
|
function drawYLegend(si, x, gridHorizontalLines, number, draw) {
|
|
891
905
|
var value;
|
|
892
|
-
//
|
|
893
|
-
//si.minValue = si.lowValue - (si.tickSize * 0.2);
|
|
894
|
-
|
|
906
|
+
// add one fontsize to max and min values
|
|
895
907
|
let v = (si.highValue - si.lowValue) / si.lineLength;
|
|
896
908
|
si.maxValue = si.highValue + (v * parseInt(m_yLegendCss.fontSize));
|
|
897
909
|
si.minValue = si.lowValue - (v * parseInt(m_yLegendCss.fontSize));
|
|
898
910
|
|
|
899
|
-
|
|
900
911
|
m_ctx.font = m_yLegendCss.fontWeight + ' ' + m_yLegendCss.fontSize + ' ' + m_yLegendCss.fontFamily;
|
|
901
912
|
if (si.highValue == si.lowValue) { // only have one value so set values for 1 line only
|
|
902
913
|
si.maxValue = si.maxValue + si.tickSize;
|
|
@@ -908,22 +919,19 @@ function Milli_Chart(settings) {
|
|
|
908
919
|
else
|
|
909
920
|
value = si.minValue + fmod(Math.abs(si.minValue), si.tickSize) - si.tickSize;
|
|
910
921
|
}
|
|
911
|
-
si.valuePerPixel =
|
|
922
|
+
si.valuePerPixel = (si.maxValue - si.minValue) / si.lineLength;
|
|
923
|
+
|
|
912
924
|
if (isNaN(si.valuePerPixel) || !isFinite(si.valuePerPixel)) {
|
|
913
925
|
console.log('cant draw valuePerPixel', si.valuePerPixel, si.lineLength, si.maxValue, si.minValue);
|
|
914
926
|
return false;
|
|
915
927
|
}
|
|
916
928
|
var textpos;
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
console.log('failsafe break');
|
|
921
|
-
break;
|
|
922
|
-
}
|
|
923
|
-
var y = Math.round(m_chartspaces.chart.height - getScaledSetting(m_chartCss.marginBottom) - ((value - si.minValue) * si.valuePerPixel));
|
|
929
|
+
for (let c = 0; c < 11; c++) { // maximum of 10 legenditems
|
|
930
|
+
|
|
931
|
+
var y = Math.round(m_chartspaces.chart.height - m_chartspaces.chart.marginBottom - ((value - si.minValue) / si.valuePerPixel));
|
|
924
932
|
if (y <= m_chartspaces.chart.top) break;
|
|
925
933
|
if (y <= m_chartspaces.chart.bottom) {
|
|
926
|
-
if (gridHorizontalLines == true) {
|
|
934
|
+
if (gridHorizontalLines == true) { // draw horizontal lines
|
|
927
935
|
m_ctx.save();
|
|
928
936
|
if (_this.settings.gridHorizontalLinesStyle == 'dash') {
|
|
929
937
|
m_ctx.setLineDash([3, 3]);
|
|
@@ -939,7 +947,6 @@ function Milli_Chart(settings) {
|
|
|
939
947
|
} else {
|
|
940
948
|
textpos = x + 4;
|
|
941
949
|
}
|
|
942
|
-
|
|
943
950
|
} else
|
|
944
951
|
if (_this.settings.drawyaxis == true && number == 1 && draw) { // draw legenditem markers for price
|
|
945
952
|
if (!draw) return;
|
|
@@ -972,48 +979,220 @@ function Milli_Chart(settings) {
|
|
|
972
979
|
return true;
|
|
973
980
|
}
|
|
974
981
|
|
|
975
|
-
function
|
|
982
|
+
function calculateIndicatorScale(data, cs, minvalue) {
|
|
983
|
+
let sc = {};
|
|
984
|
+
sc.low = null;
|
|
985
|
+
sc.high = null;
|
|
986
|
+
for (let i = 0; i < data.length; i++) {
|
|
987
|
+
if (data[i].timestamp < _this.scaleinfoX.startTimeStamp) {
|
|
988
|
+
continue;
|
|
989
|
+
}
|
|
990
|
+
if (data[i].timestamp > _this.scaleinfoX.endTimeStamp) {
|
|
991
|
+
break; // continue?
|
|
992
|
+
}
|
|
993
|
+
|
|
994
|
+
if (typeof data[i].datapoints[0] !== 'undefined') {
|
|
995
|
+
if (sc.low == null || sc.low > data[i].datapoints[[0]]) sc.low = data[i].datapoints[0];
|
|
996
|
+
if (sc.high == null || sc.high < data[i].datapoints[[0]]) sc.high = data[i].datapoints[0];
|
|
997
|
+
}
|
|
998
|
+
}
|
|
999
|
+
if (sc.low == null || sc.high == null) return null;
|
|
1000
|
+
let v = (sc.high - sc.low) / (cs.bottom - cs.top);
|
|
1001
|
+
sc.maxValue = sc.high == 0 ? 100 : sc.high + (v * parseInt(m_yLegendCss.fontSize));
|
|
1002
|
+
sc.minValue = typeof minvalue == 'undefined' ? sc.lowValue - (v * parseInt(m_yLegendCss.fontSize)) : minvalue;
|
|
1003
|
+
|
|
1004
|
+
sc.maxValue = sc.high == 0 ? 100 : sc.high + (fabs(sc.high) * 0.2);
|
|
1005
|
+
sc.minValue = typeof minvalue === 'undefined' ? sc.low - (fabs(sc.low) * 0.2) : minvalue;
|
|
1006
|
+
sc.valuePerPixel = (sc.maxValue - sc.minValue) / (cs.bottom - cs.top);
|
|
1007
|
+
return sc;
|
|
1008
|
+
}
|
|
1009
|
+
|
|
1010
|
+
function drawYLegendNew(scale, cs, x, css, drawAxis, gridLines, factorInfo) {
|
|
1011
|
+
let value;
|
|
1012
|
+
// add one fontsize to max and min values
|
|
1013
|
+
let v = (scale.highValue - scale.lowValue) / scale.lineLength;
|
|
1014
|
+
scale.maxValue = scale.highValue + (v * parseInt(css.fontSize));
|
|
1015
|
+
scale.minValue = scale.lowValue - (v * parseInt(css.fontSize));
|
|
1016
|
+
if (scale.highValue == scale.lowValue) { // only have one value so set values for 1 line only
|
|
1017
|
+
scale.maxValue = scale.maxValue + scale.tickSize;
|
|
1018
|
+
scale.minValue = scale.minValue - scale.tickSize;
|
|
1019
|
+
value = Math.abs(scale.lowValue);
|
|
1020
|
+
} else {
|
|
1021
|
+
if (scale.minValue > 0)
|
|
1022
|
+
value = scale.minValue - fmod(Math.abs(scale.minValue), scale.tickSize) + scale.tickSize;
|
|
1023
|
+
else
|
|
1024
|
+
value = scale.minValue + fmod(Math.abs(scale.minValue), scale.tickSize) - scale.tickSize;
|
|
1025
|
+
}
|
|
1026
|
+
scale.valuePerPixel = (scale.maxValue - scale.minValue) / scale.lineLength;
|
|
1027
|
+
m_ctx.font = css.fontWeight + ' ' + css.fontSize + ' ' + css.fontFamily;
|
|
1028
|
+
|
|
1029
|
+
if (isNaN(scale.valuePerPixel) || !isFinite(scale.valuePerPixel)) {
|
|
1030
|
+
console.log('cant draw valuePerPixel', scale.valuePerPixel, scale.lineLength, scale.maxValue, scale.minValue);
|
|
1031
|
+
return false;
|
|
1032
|
+
}
|
|
1033
|
+
var textpos;
|
|
1034
|
+
for (let c = 0; c < 11; c++) { // maximum of 10 legenditems
|
|
1035
|
+
var y = Math.round(cs.height - cs.marginBottom - ((value - scale.minValue) / scale.valuePerPixel));
|
|
1036
|
+
if (y <= cs.top) break;
|
|
1037
|
+
if (y <= cs.bottom) {
|
|
1038
|
+
textpos = x;
|
|
1039
|
+
if (drawAxis == true && gridLines) { // draw horizontal lines
|
|
1040
|
+
m_ctx.save();
|
|
1041
|
+
if (_this.settings.gridHorizontalLinesStyle == 'dash') {
|
|
1042
|
+
m_ctx.setLineDash([3, 3]);
|
|
1043
|
+
}
|
|
1044
|
+
m_ctx.beginPath();
|
|
1045
|
+
m_ctx.moveTo(cs.left, y + 0.5);
|
|
1046
|
+
m_ctx.lineTo(cs.right, y + 0.5);
|
|
1047
|
+
m_ctx.stroke();
|
|
1048
|
+
m_ctx.closePath();
|
|
1049
|
+
m_ctx.restore();
|
|
1050
|
+
if ((css.float == 'left' && css.textAlign == 'left') || (css.float == 'right' && css.textAlign == 'left')) {
|
|
1051
|
+
textpos = x - 4;
|
|
1052
|
+
} else {
|
|
1053
|
+
textpos = x + 4;
|
|
1054
|
+
}
|
|
1055
|
+
} else
|
|
1056
|
+
if (drawAxis == true && gridLines) { // draw legenditem markers for price
|
|
1057
|
+
m_ctx.beginPath();
|
|
1058
|
+
m_ctx.moveTo(cs.left, y + 0.5);
|
|
1059
|
+
if ((css.float == 'left' && css.textAlign == 'left') || (css.float == 'right' && css.textAlign == 'left')) {
|
|
1060
|
+
m_ctx.lineTo(x - 3, y + 0.5);
|
|
1061
|
+
textpos = x - 4;
|
|
1062
|
+
} else {
|
|
1063
|
+
m_ctx.lineTo(x + 3, y + 0.5);
|
|
1064
|
+
textpos = x + 4;
|
|
1065
|
+
}
|
|
1066
|
+
m_ctx.stroke();
|
|
1067
|
+
m_ctx.closePath();
|
|
1068
|
+
}
|
|
1069
|
+
if (drawAxis == true) {
|
|
1070
|
+
var label = formatNiceNumber(value, _this.settings.thousandseparator, _this.settings.decimalseparator, scale.decimals, false);
|
|
1071
|
+
if (typeof factorInfo !== 'undefined' && typeof factorInfo.suffix !== 'undefined') label += factorInfo.suffix;
|
|
1072
|
+
if (css.verticalAlign == 'top') {
|
|
1073
|
+
if (checkYLegendSpace(y, label))
|
|
1074
|
+
m_ctx.fillText(label, textpos, y - ((getFontSize(css) + 2)));
|
|
1075
|
+
} else {
|
|
1076
|
+
if (checkYLegendSpace(y, label))
|
|
1077
|
+
m_ctx.fillText(label, textpos, y - (getFontSize(css) / 2));
|
|
1078
|
+
}
|
|
1079
|
+
}
|
|
1080
|
+
}
|
|
1081
|
+
value += scale.tickSize;
|
|
1082
|
+
}
|
|
1083
|
+
return true;
|
|
1084
|
+
}
|
|
1085
|
+
|
|
1086
|
+
function drawYAxisNew(scale, cs, css, drawAxis, gridLines, factor) {
|
|
1087
|
+
/*let scale = {};
|
|
1088
|
+
if (false == calcHighLow2(scale, factor)) {
|
|
1089
|
+
console.log('fail highlow');
|
|
1090
|
+
return;
|
|
1091
|
+
}*/
|
|
1092
|
+
m_ctx.save();
|
|
1093
|
+
m_ctx.strokeStyle = m_gridHorizontalCss.color;
|
|
1094
|
+
m_ctx.font = css.fontWeight + ' ' + css.fontSize + ' ' + css.fontFamily;
|
|
1095
|
+
m_ctx.fillStyle = css.color;
|
|
1096
|
+
scale.lineLength = cs.bottom - cs.top;
|
|
1097
|
+
/* let numticks = scale.lineLength / (getFontSize(css) * _this.settings.yAxisSpacing);
|
|
1098
|
+
if (numticks > 8) numticks = 8; // limit to 8 items on Y legend ( this is not an absolut count, since we calculate nice legend numbers
|
|
1099
|
+
scale.tickSize = getTickValue(scale.lowValue, scale.highValue, numticks);
|
|
1100
|
+
scale.decimals = scale.tickSize.countDecimals();*/
|
|
1101
|
+
//scale.decimals > 4 ? 4 : (scale.decimals < 2 ? 2 : scale.decimals);
|
|
1102
|
+
|
|
1103
|
+
|
|
1104
|
+
|
|
1105
|
+
|
|
1106
|
+
/* let widestValue = (scale.lowValue < 0 ? '-' : '') + Math.max(Math.abs(scale.highValue), Math.abs(scale.lowValue));
|
|
1107
|
+
let label = formatNiceNumber(widestValue, _this.settings.thousandseparator, _this.settings.decimalseparator, scale.decimals);
|
|
1108
|
+
console.log('testw', label, )
|
|
1109
|
+
if (drawAxis) {
|
|
1110
|
+
if (css.float != 'right') {
|
|
1111
|
+
cs.left = 10 + Math.round(m_ctx.measureText(label).width); // + 'px'; // räkna fram hur hur mycket plats Y värdena tar och sätt margin till det, skall vi göra så?
|
|
1112
|
+
} else {
|
|
1113
|
+
if (css.textAlign == 'right') {
|
|
1114
|
+
cs.right = m_canvas.getWidth() - (10 + Math.round(m_ctx.measureText(label).width)); // + 'px'; // räkna fram hur hur mycket plats Y värdena tar och sätt margin till det, skall vi göra så?
|
|
1115
|
+
}
|
|
1116
|
+
}
|
|
1117
|
+
}
|
|
1118
|
+
*/
|
|
1119
|
+
|
|
1120
|
+
|
|
1121
|
+
|
|
1122
|
+
|
|
1123
|
+
if (css.float != 'right' && drawAxis) { // do we need to add space for half a date? ie prices are to tiny so date will be trunkated
|
|
1124
|
+
m_ctx.save();
|
|
1125
|
+
m_ctx.font = m_xLegendCss.fontWeight + ' ' + m_xLegendCss.fontSize + ' ' + m_xLegendCss.fontFamily;
|
|
1126
|
+
if (getStringWidth(m_ctx, _this.settings.dateformat) / 2 + 5 > cs.left) {
|
|
1127
|
+
cs.left = getStringWidth(m_ctx, _this.settings.dateformat) / 2 + 5;
|
|
1128
|
+
}
|
|
1129
|
+
m_ctx.restore();
|
|
1130
|
+
}
|
|
1131
|
+
// draw line
|
|
1132
|
+
m_ctx.strokeStyle = m_gridVerticalCss.color;
|
|
1133
|
+
m_ctx.beginPath();
|
|
1134
|
+
m_ctx.moveTo(cs.left + 0.5, cs.top);
|
|
1135
|
+
m_ctx.lineTo(cs.left + 0.5, cs.height - cs.marginBottom);
|
|
1136
|
+
m_ctx.stroke();
|
|
1137
|
+
m_ctx.closePath();
|
|
1138
|
+
m_ctx.strokeStyle = m_gridHorizontalCss.color;
|
|
1139
|
+
var x;
|
|
1140
|
+
if (css.float == 'right')
|
|
1141
|
+
x = cs.right;
|
|
1142
|
+
else
|
|
1143
|
+
x = cs.left;
|
|
1144
|
+
if (css.textAlign == 'right') {
|
|
1145
|
+
m_ctx.textAlign = 'left';
|
|
1146
|
+
drawYLegendNew(scale, cs, x, css, drawAxis, gridLines, factor);
|
|
1147
|
+
} else {
|
|
1148
|
+
m_ctx.textAlign = 'right';
|
|
1149
|
+
drawYLegendNew(scale, cs, x, css, drawAxis, gridLines), factor;
|
|
1150
|
+
}
|
|
1151
|
+
m_ctx.restore();
|
|
1152
|
+
return scale;
|
|
1153
|
+
}
|
|
1154
|
+
|
|
1155
|
+
function drawYAxis(scaleinfoY, scaleinfoY2) {
|
|
976
1156
|
m_ctx.save();
|
|
977
1157
|
m_ctx.strokeStyle = m_gridHorizontalCss.color;
|
|
978
1158
|
m_ctx.font = m_yLegendCss.fontWeight + ' ' + m_yLegendCss.fontSize + ' ' + m_yLegendCss.fontFamily;
|
|
979
1159
|
m_ctx.fillStyle = m_yLegendCss.color;
|
|
980
|
-
if (0 == calcHighLow()) {
|
|
1160
|
+
if (0 == calcHighLow(scaleinfoY, scaleinfoY2)) {
|
|
981
1161
|
m_ctx.restore();
|
|
982
1162
|
console.log('fail highlow');
|
|
983
1163
|
return;
|
|
984
1164
|
}
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
var numticks =
|
|
1165
|
+
|
|
1166
|
+
scaleinfoY.lineLength = m_chartspaces.chart.bottom - m_chartspaces.chart.top;
|
|
1167
|
+
scaleinfoY2.lineLength = scaleinfoY.lineLength;
|
|
1168
|
+
var numticks = scaleinfoY.lineLength / (getFontSize(m_yLegendCss) * _this.settings.yAxisSpacing);
|
|
989
1169
|
if (numticks > 8) numticks = 8; // limit to 8 items on Y legend ( this is not an absolut count, since we calculate nice legend numbers
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
var label = formatNiceNumber(
|
|
1170
|
+
scaleinfoY.tickSize = getTickValue(scaleinfoY.lowValue, scaleinfoY.highValue, numticks);
|
|
1171
|
+
scaleinfoY.decimals = scaleinfoY.tickSize.countDecimals(); // räkna på diffen mellan high low kanske?
|
|
1172
|
+
scaleinfoY.decimals = scaleinfoY.decimals > 4 ? 4 : scaleinfoY.decimals;
|
|
1173
|
+
scaleinfoY.decimals = scaleinfoY.decimals < 2 ? 2 : scaleinfoY.decimals;
|
|
1174
|
+
var label = formatNiceNumber(scaleinfoY.highValue, _this.settings.thousandseparator, _this.settings.decimalseparator, scaleinfoY.decimals);
|
|
995
1175
|
if (_this.settings.drawyaxis) {
|
|
996
1176
|
if (m_yLegendCss.float != 'right') {
|
|
997
1177
|
m_chartspaces.chart.left = 10 + Math.round(m_ctx.measureText(label).width); // + 'px'; // räkna fram hur hur mycket plats Y värdena tar och sätt margin till det, skall vi göra så?
|
|
998
1178
|
m_chartspaces.lowerChart.left = m_chartspaces.chart.left;
|
|
999
1179
|
} else {
|
|
1000
1180
|
if (m_yLegendCss.textAlign == 'right') {
|
|
1001
|
-
m_chartspaces.chart.right = m_canvas.
|
|
1181
|
+
m_chartspaces.chart.right = m_canvas.getWidth() - (10 + Math.round(m_ctx.measureText(label).width)); // + 'px'; // räkna fram hur hur mycket plats Y värdena tar och sätt margin till det, skall vi göra så?
|
|
1002
1182
|
m_chartspaces.lowerChart.right = m_chartspaces.chart.right;
|
|
1003
1183
|
}
|
|
1004
1184
|
}
|
|
1005
1185
|
}
|
|
1006
1186
|
if (_this.settings.drawy2axis) { // calc space for y2
|
|
1007
|
-
|
|
1008
|
-
_this.scaleinfoY2.tickSize = getTickValue(_this.scaleinfoY2.lowValue, _this.scaleinfoY2.highValue, numticks);
|
|
1187
|
+
scaleinfoY2.tickSize = getTickValue(scaleinfoY2.lowValue, scaleinfoY2.highValue, numticks);
|
|
1009
1188
|
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1189
|
+
scaleinfoY2.decimals = scaleinfoY2.tickSize.countDecimals(); // räkna på diffen mellan high low kanske?
|
|
1190
|
+
scaleinfoY2.decimals = scaleinfoY2.decimals > 4 ? 4 : scaleinfoY2.decimals;
|
|
1191
|
+
scaleinfoY2.decimals = scaleinfoY2.decimals < 0 ? 0 : scaleinfoY2.decimals;
|
|
1013
1192
|
|
|
1014
|
-
var widestDiff = '-' + Math.max(Math.abs(
|
|
1015
|
-
if (_this.settings.priceIndicator == false) label = formatNiceNumber(widestDiff, _this.settings.thousandseparator, _this.settings.decimalseparator,
|
|
1016
|
-
else label = formatNiceNumber(widestDiff, _this.settings.thousandseparator, _this.settings.decimalseparator,
|
|
1193
|
+
var widestDiff = '-' + Math.max(Math.abs(scaleinfoY2.highValue), Math.abs(scaleinfoY2.lowValue));
|
|
1194
|
+
if (_this.settings.priceIndicator == false) label = formatNiceNumber(widestDiff, _this.settings.thousandseparator, _this.settings.decimalseparator, scaleinfoY2.decimals) + ' %';
|
|
1195
|
+
else label = formatNiceNumber(widestDiff, _this.settings.thousandseparator, _this.settings.decimalseparator, scaleinfoY2.decimals < 2 ? 2 : scaleinfoY2.decimals) + ' %'; // priceIndicator has 2 decimals
|
|
1017
1196
|
if (m_y2LegendCss.float != 'right') {
|
|
1018
1197
|
if (m_y2LegendCss.textAlign == 'left')
|
|
1019
1198
|
m_chartspaces.chart.left = 10 + Math.round(m_ctx.measureText(label).width); // + 'px'; // räkna fram hur hur mycket plats Y värdena tar och sätt margin till det, skall vi göra så?
|
|
@@ -1021,7 +1200,8 @@ function Milli_Chart(settings) {
|
|
|
1021
1200
|
} else {
|
|
1022
1201
|
// kolla setting om den skall vara "i diagrammet"
|
|
1023
1202
|
if (m_y2LegendCss.textAlign == 'right')
|
|
1024
|
-
m_chartspaces.chart.right = m_canvas.
|
|
1203
|
+
m_chartspaces.chart.right = m_canvas.getWidth() - (10 + Math.round(m_ctx.measureText(label).width)); // + 'px'; // räkna fram hur hur mycket plats Y värdena tar och sätt margin till det, skall vi göra så?
|
|
1204
|
+
//m_chartspaces.chart.right = (m_canvas.getWidth() / window.devicePixelRatio) - (10 + Math.round(m_ctx.measureText(label).width)); // + 'px'; // räkna fram hur hur mycket plats Y värdena tar och sätt margin till det, skall vi göra så?
|
|
1025
1205
|
m_chartspaces.lowerChart.right = m_chartspaces.chart.right;
|
|
1026
1206
|
}
|
|
1027
1207
|
}
|
|
@@ -1034,7 +1214,7 @@ function Milli_Chart(settings) {
|
|
|
1034
1214
|
m_ctx.strokeStyle = m_gridVerticalCss.color;
|
|
1035
1215
|
m_ctx.beginPath();
|
|
1036
1216
|
m_ctx.moveTo(m_chartspaces.chart.left + 0.5, m_chartspaces.chart.top);
|
|
1037
|
-
m_ctx.lineTo(m_chartspaces.chart.left + 0.5, m_chartspaces.chart.height -
|
|
1217
|
+
m_ctx.lineTo(m_chartspaces.chart.left + 0.5, m_chartspaces.chart.height - m_chartspaces.chart.marginBottom);
|
|
1038
1218
|
m_ctx.stroke();
|
|
1039
1219
|
m_ctx.closePath();
|
|
1040
1220
|
m_ctx.strokeStyle = m_gridHorizontalCss.color;
|
|
@@ -1045,10 +1225,10 @@ function Milli_Chart(settings) {
|
|
|
1045
1225
|
x = m_chartspaces.chart.left;
|
|
1046
1226
|
if (m_yLegendCss.textAlign == 'right') {
|
|
1047
1227
|
m_ctx.textAlign = 'left';
|
|
1048
|
-
drawYLegend(
|
|
1228
|
+
drawYLegend(scaleinfoY, x, _this.settings.gridHorizontalLines, 1, _this.settings.drawyaxis);
|
|
1049
1229
|
} else {
|
|
1050
1230
|
m_ctx.textAlign = 'right';
|
|
1051
|
-
drawYLegend(
|
|
1231
|
+
drawYLegend(scaleinfoY, x, _this.settings.gridHorizontalLines, 1, _this.settings.drawyaxis);
|
|
1052
1232
|
}
|
|
1053
1233
|
if (_this.settings.drawy2axis) {
|
|
1054
1234
|
if (m_y2LegendCss.float == 'right') {
|
|
@@ -1058,11 +1238,11 @@ function Milli_Chart(settings) {
|
|
|
1058
1238
|
}
|
|
1059
1239
|
if (m_y2LegendCss.textAlign == 'right') {
|
|
1060
1240
|
m_ctx.textAlign = 'left';
|
|
1061
|
-
drawY2Legend(x);
|
|
1241
|
+
drawY2Legend(scaleinfoY, scaleinfoY2, x);
|
|
1062
1242
|
|
|
1063
1243
|
} else {
|
|
1064
1244
|
m_ctx.textAlign = 'right';
|
|
1065
|
-
drawY2Legend(x);
|
|
1245
|
+
drawY2Legend(scaleinfoY, scaleinfoY2, x);
|
|
1066
1246
|
}
|
|
1067
1247
|
}
|
|
1068
1248
|
m_ctx.restore();
|
|
@@ -1163,8 +1343,8 @@ function Milli_Chart(settings) {
|
|
|
1163
1343
|
calcXScale(starttime, endtime);
|
|
1164
1344
|
if (_this.settings.drawxaxis != 0) {
|
|
1165
1345
|
m_ctx.beginPath();
|
|
1166
|
-
m_ctx.moveTo(m_chartspaces.chart.left, m_chartspaces.chart.height -
|
|
1167
|
-
m_ctx.lineTo(m_chartspaces.chart.right, m_chartspaces.chart.height -
|
|
1346
|
+
m_ctx.moveTo(m_chartspaces.chart.left, m_chartspaces.chart.height - m_chartspaces.chart.marginBottom + 0.5);
|
|
1347
|
+
m_ctx.lineTo(m_chartspaces.chart.right, m_chartspaces.chart.height - m_chartspaces.chart.marginBottom + 0.5);
|
|
1168
1348
|
m_ctx.stroke();
|
|
1169
1349
|
m_ctx.closePath();
|
|
1170
1350
|
}
|
|
@@ -1183,7 +1363,7 @@ function Milli_Chart(settings) {
|
|
|
1183
1363
|
}
|
|
1184
1364
|
}
|
|
1185
1365
|
if (draw) {
|
|
1186
|
-
drawXAxisGridlines({ 'x': x, y: m_chartspaces.chart.height -
|
|
1366
|
+
drawXAxisGridlines({ 'x': x, y: m_chartspaces.chart.height - m_chartspaces.chart.marginBottom });
|
|
1187
1367
|
text = year;
|
|
1188
1368
|
if (checkXLegendSides(x, text)) {
|
|
1189
1369
|
if (_this.settings.yearLabelsPos == 'top') {
|
|
@@ -1196,7 +1376,7 @@ function Milli_Chart(settings) {
|
|
|
1196
1376
|
m_ctx.fillText(text, 0, 0);
|
|
1197
1377
|
m_ctx.restore();
|
|
1198
1378
|
} else {
|
|
1199
|
-
m_ctx.fillText(text, x - (m_ctx.measureText(text).width / 2), m_chartspaces.chart.height -
|
|
1379
|
+
m_ctx.fillText(text, x - (m_ctx.measureText(text).width / 2), m_chartspaces.chart.height - m_chartspaces.chart.marginBottom + getScaledSetting(m_xLegendCss.paddingTop));
|
|
1200
1380
|
}
|
|
1201
1381
|
}
|
|
1202
1382
|
numItems++;
|
|
@@ -1219,10 +1399,10 @@ function Milli_Chart(settings) {
|
|
|
1219
1399
|
}
|
|
1220
1400
|
}
|
|
1221
1401
|
if (draw) {
|
|
1222
|
-
drawXAxisGridlines({ 'x': x, y: m_chartspaces.chart.height -
|
|
1402
|
+
drawXAxisGridlines({ 'x': x, y: m_chartspaces.chart.height - m_chartspaces.chart.marginBottom });
|
|
1223
1403
|
text = formatDate(year.getFullYear() + '-07-01', _this.settings.dateformat, _this);
|
|
1224
1404
|
if (checkXLegendSides(x, text)) {
|
|
1225
|
-
m_ctx.fillText(text, x - (m_ctx.measureText(text).width / 2), m_chartspaces.chart.height -
|
|
1405
|
+
m_ctx.fillText(text, x - (m_ctx.measureText(text).width / 2), m_chartspaces.chart.height - m_chartspaces.chart.marginBottom + getScaledSetting(m_xLegendCss.paddingTop));
|
|
1226
1406
|
}
|
|
1227
1407
|
numItems++;
|
|
1228
1408
|
legendItems.push({ 'text': text, timestamp: new Date(year + '-07-01T00:00:00Z'), 'x': x });
|
|
@@ -1248,10 +1428,10 @@ function Milli_Chart(settings) {
|
|
|
1248
1428
|
}
|
|
1249
1429
|
if (dontPrint) break;
|
|
1250
1430
|
if (draw) {
|
|
1251
|
-
drawXAxisGridlines({ 'x': x, y: m_chartspaces.chart.height -
|
|
1252
|
-
text = formatDate(year.getFullYear() + '-' + (year.getMonth() + 1) + '-01', _this.settings.dateformat, _this);
|
|
1431
|
+
drawXAxisGridlines({ 'x': x, y: m_chartspaces.chart.height - m_chartspaces.chart.marginBottom });
|
|
1432
|
+
text = formatDate(year.getFullYear() + '-' + ('0' + (year.getMonth() + 1)).slice(-2) + '-01', _this.settings.dateformat, _this);
|
|
1253
1433
|
if (checkXLegendSides(x, text)) {
|
|
1254
|
-
m_ctx.fillText(text, x - (m_ctx.measureText(text).width / 2), m_chartspaces.chart.height -
|
|
1434
|
+
m_ctx.fillText(text, x - (m_ctx.measureText(text).width / 2), m_chartspaces.chart.height - m_chartspaces.chart.marginBottom + getScaledSetting(m_xLegendCss.paddingTop));
|
|
1255
1435
|
}
|
|
1256
1436
|
}
|
|
1257
1437
|
legendItems.push({ 'text': text, timestamp: new Date(year + '-04-01T00:00:00Z'), 'x': x });
|
|
@@ -1271,10 +1451,10 @@ function Milli_Chart(settings) {
|
|
|
1271
1451
|
}
|
|
1272
1452
|
}
|
|
1273
1453
|
if (draw) {
|
|
1274
|
-
drawXAxisGridlines({ 'x': x, y: m_chartspaces.chart.height -
|
|
1275
|
-
text = formatDate(year.getFullYear() + '-' + (year.getMonth() + 1) + '-01', _this.settings.dateformat, _this);
|
|
1454
|
+
drawXAxisGridlines({ 'x': x, y: m_chartspaces.chart.height - m_chartspaces.chart.marginBottom });
|
|
1455
|
+
text = formatDate(year.getFullYear() + '-' + ('0' + (year.getMonth() + 1)).slice(-2) + '-01', _this.settings.dateformat, _this);
|
|
1276
1456
|
if (checkXLegendSides(x, text)) {
|
|
1277
|
-
m_ctx.fillText(text, x - (m_ctx.measureText(text).width / 2), m_chartspaces.chart.height -
|
|
1457
|
+
m_ctx.fillText(text, x - (m_ctx.measureText(text).width / 2), m_chartspaces.chart.height - m_chartspaces.chart.marginBottom + getScaledSetting(m_xLegendCss.paddingTop));
|
|
1278
1458
|
}
|
|
1279
1459
|
}
|
|
1280
1460
|
legendItems.push({ 'text': text, timestamp: new Date(year + '-10-01T00:00:00Z'), 'x': x });
|
|
@@ -1296,8 +1476,8 @@ function Milli_Chart(settings) {
|
|
|
1296
1476
|
calcXScale(starttime, endtime);
|
|
1297
1477
|
if (_this.settings.drawxaxis != 0) { // draw line
|
|
1298
1478
|
m_ctx.beginPath();
|
|
1299
|
-
m_ctx.moveTo(m_chartspaces.chart.left, m_chartspaces.chart.height -
|
|
1300
|
-
m_ctx.lineTo(m_chartspaces.chart.right, m_chartspaces.chart.height -
|
|
1479
|
+
m_ctx.moveTo(m_chartspaces.chart.left, m_chartspaces.chart.height - m_chartspaces.chart.marginBottom + 0.5);
|
|
1480
|
+
m_ctx.lineTo(m_chartspaces.chart.right, m_chartspaces.chart.height - m_chartspaces.chart.marginBottom + 0.5);
|
|
1301
1481
|
m_ctx.stroke();
|
|
1302
1482
|
m_ctx.closePath();
|
|
1303
1483
|
}
|
|
@@ -1351,7 +1531,7 @@ function Milli_Chart(settings) {
|
|
|
1351
1531
|
_this.scaleinfoX.itemwidth = getStringWidth(m_ctx, '88:88') * 2; // kolla rätt format en 8a för varje tecken
|
|
1352
1532
|
var maxLegendItems = Math.floor(_this.scaleinfoX.lineLength / (_this.scaleinfoX.itemwidth * 2));
|
|
1353
1533
|
|
|
1354
|
-
if (
|
|
1534
|
+
if (chartType != 'history') {
|
|
1355
1535
|
var arr = [];
|
|
1356
1536
|
var tmptime = starttime;
|
|
1357
1537
|
var i = 0;
|
|
@@ -1523,7 +1703,7 @@ function Milli_Chart(settings) {
|
|
|
1523
1703
|
m_ctx.fillText(date, middleX - (m_ctx.measureText(date).width / 2), m_chartspaces.chart.bottom + getScaledSetting(m_xLegendCss.paddingTop));
|
|
1524
1704
|
legendItems.push({ x: middleX, type: 0, text: date, width: m_ctx.measureText(date) });
|
|
1525
1705
|
} else if (_this.settings.intradayDatePos.y == 'bottom' && _this.settings.chartlen != '0d' && _this.settings.chartlen != '1d') {
|
|
1526
|
-
m_ctx.fillText(date, middleX - (m_ctx.measureText(date).width / 2), m_chartspaces.chart.bottom + getScaledSetting(m_xLegendCss.paddingTop) + parseInt(m_xLegendCss.fontSize) *
|
|
1706
|
+
m_ctx.fillText(date, middleX - (m_ctx.measureText(date).width / 2), m_chartspaces.chart.bottom + getScaledSetting(m_xLegendCss.paddingTop) + parseInt(m_xLegendCss.fontSize) * 1);
|
|
1527
1707
|
m_ctx.fillText(text, x - (m_ctx.measureText(text).width / 2), m_chartspaces.chart.bottom + getScaledSetting(m_xLegendCss.paddingTop));
|
|
1528
1708
|
legendItems.push({ x: x, type: 0, text: text });
|
|
1529
1709
|
} else {
|
|
@@ -1533,7 +1713,7 @@ function Milli_Chart(settings) {
|
|
|
1533
1713
|
if (_this.settings.intradayDatePos.orientation == 'vertical' && _this.settings.intradayDatePos.x != 'center') {
|
|
1534
1714
|
m_ctx.save();
|
|
1535
1715
|
var fontMetrix = m_ctx.measureText(date);
|
|
1536
|
-
var dx = (x + fontMetrix.actualBoundingBoxAscent + fontMetrix.actualBoundingBoxDescent + 3) /
|
|
1716
|
+
var dx = (x + fontMetrix.actualBoundingBoxAscent + fontMetrix.actualBoundingBoxDescent + 3) / 1;
|
|
1537
1717
|
var dy = m_chartCss.marginTop;
|
|
1538
1718
|
m_ctx.translate(dx, dy);
|
|
1539
1719
|
m_ctx.rotate(90 * Math.PI / 180);
|
|
@@ -1711,6 +1891,7 @@ function Milli_Chart(settings) {
|
|
|
1711
1891
|
var label = formatChartTime(currentDate.toTimeString().substring(0, 8), _this.settings.timeformat);
|
|
1712
1892
|
x = Math.round(x);
|
|
1713
1893
|
m_ctx.fillText(label, x - (m_ctx.measureText(label).width / 2), m_chartspaces.chart.bottom + getScaledSetting(m_xLegendCss.paddingTop));
|
|
1894
|
+
//m_ctx.fillText(label, 125, m_chartspaces.chart.bottom + getScaledSetting(m_xLegendCss.paddingTop));
|
|
1714
1895
|
legendItems.push({ x: x, type: 0, text: label });
|
|
1715
1896
|
}
|
|
1716
1897
|
drawXAxisGridlines({ 'x': x, y: m_chartspaces.chart.bottom }, false);
|
|
@@ -1729,9 +1910,9 @@ function Milli_Chart(settings) {
|
|
|
1729
1910
|
}
|
|
1730
1911
|
|
|
1731
1912
|
function drawClosePriceIndicator() {
|
|
1732
|
-
if (_this.settings.closePriceIndicator == false ||
|
|
1913
|
+
if (_this.settings.closePriceIndicator == false || chartType == 'history') return;
|
|
1733
1914
|
if (isNaN(_this.instruments[0].startValue) || !_this.instruments[0].startValue) return;
|
|
1734
|
-
var y = Math.round(m_chartspaces.chart.height -
|
|
1915
|
+
var y = Math.round(m_chartspaces.chart.height - m_chartspaces.chart.marginBottom - ((_this.instruments[0].startValue - scaleinfoY.minValue) / scaleinfoY.valuePerPixel)) + 0.5;
|
|
1735
1916
|
m_ctx.save();
|
|
1736
1917
|
m_ctx.strokeStyle = _this.settings.closePriceIndicator;
|
|
1737
1918
|
m_ctx.setLineDash([3, 3]);
|
|
@@ -1767,11 +1948,12 @@ function Milli_Chart(settings) {
|
|
|
1767
1948
|
oldValue = MillistreamWidgetApi_getElementNumber(_this, m_priceIndicator);
|
|
1768
1949
|
} else {
|
|
1769
1950
|
m_priceIndicator = document.createElement('div');
|
|
1951
|
+
//m_canvas.parentNode.appendChild(m_priceIndicator);
|
|
1770
1952
|
m_canvas.parentNode.appendChild(m_priceIndicator);
|
|
1771
1953
|
m_priceIndicator.setAttribute('class', 'millistream-chart-price-indicator');
|
|
1772
1954
|
}
|
|
1773
1955
|
m_priceIndicator.innerHTML = newValue;
|
|
1774
|
-
m_priceIndicator.style.left = (m_chartspaces.chart.right /
|
|
1956
|
+
m_priceIndicator.style.left = (m_chartspaces.chart.right / 1) - (offsetWidth == 0 ? -1 : m_priceIndicator.offsetWidth) + 'px'; // offsetWidth with devicePixelRatio???
|
|
1775
1957
|
m_priceIndicator.style.top = obj.instruments[0].y - (m_priceIndicator.offsetHeight / 2) + 'px';
|
|
1776
1958
|
newValue = MillistreamWidgetApi_getElementNumber(_this, m_priceIndicator);
|
|
1777
1959
|
MillistreamWidgetApi_flashElement(_this, m_priceIndicator, newValue, oldValue);
|
|
@@ -1779,7 +1961,7 @@ function Milli_Chart(settings) {
|
|
|
1779
1961
|
|
|
1780
1962
|
function onMouseOut(evt) {
|
|
1781
1963
|
if (typeof _this.settings.tooltip === 'object' && _this.settings.tooltip.preventOut) return;
|
|
1782
|
-
for (
|
|
1964
|
+
for (let i = 0; i < _this.instruments.length; i++) {
|
|
1783
1965
|
if (_this.instruments[i].insref != 0 && typeof _this.instruments[i].toolTip !== 'undefined') {
|
|
1784
1966
|
if (i == 0 && typeof _this.settings.tooltip == 'object' && typeof _this.settings.tooltip.mouseOut == 'function') _this.settings.tooltip.mouseOut.call();
|
|
1785
1967
|
_this.instruments[i].toolTip.parentNode.removeChild(_this.instruments[i].toolTip);
|
|
@@ -1788,7 +1970,13 @@ function Milli_Chart(settings) {
|
|
|
1788
1970
|
_this.instruments[i].toolTipPointer = undefined;
|
|
1789
1971
|
}
|
|
1790
1972
|
}
|
|
1791
|
-
|
|
1973
|
+
for (let i = 0; i < _this.settings.indicators.length; i++) {
|
|
1974
|
+
if (_this.settings.indicators[i].staticTooltip == true) continue;
|
|
1975
|
+
if (typeof _this.settings.indicators[i].toolTip !== 'undefined' && typeof _this.settings.indicators[i].toolTip.div !== 'undefined') {
|
|
1976
|
+
_this.settings.indicators[i].toolTip.div.parentNode.removeChild(_this.settings.indicators[i].toolTip.div);
|
|
1977
|
+
_this.settings.indicators[i].toolTip.div = undefined;
|
|
1978
|
+
}
|
|
1979
|
+
}
|
|
1792
1980
|
}
|
|
1793
1981
|
|
|
1794
1982
|
function clearZoom() {
|
|
@@ -1802,6 +1990,10 @@ function Milli_Chart(settings) {
|
|
|
1802
1990
|
_this.drawChart();
|
|
1803
1991
|
}
|
|
1804
1992
|
|
|
1993
|
+
function onMouseClick(evt) {
|
|
1994
|
+
if (m_zoom.mousedown && m_zoom.mousedown.pos != m_zoom.mouseup.pos) return;
|
|
1995
|
+
}
|
|
1996
|
+
|
|
1805
1997
|
function onMouseMove(pos) {
|
|
1806
1998
|
if (m_dataPoints.arr.length == 0) return;
|
|
1807
1999
|
var rect = m_canvas.getBoundingClientRect();
|
|
@@ -1816,14 +2008,14 @@ function Milli_Chart(settings) {
|
|
|
1816
2008
|
m_zoom.div.style.position = 'absolute';
|
|
1817
2009
|
}
|
|
1818
2010
|
if (x < m_chartspaces.chart.left) x = m_chartspaces.chart.left;
|
|
1819
|
-
m_zoom.div.style.top = m_chartspaces.chart.top /
|
|
1820
|
-
m_zoom.div.style.left = (m_zoom.mousedown.pos > x /
|
|
2011
|
+
m_zoom.div.style.top = m_chartspaces.chart.top / 1 + 'px';
|
|
2012
|
+
m_zoom.div.style.left = (m_zoom.mousedown.pos > x / 1 ? x / 1 : m_zoom.mousedown.pos) + 'px';
|
|
1821
2013
|
if (x > m_chartspaces.chart.right) x = m_chartspaces.chart.right;
|
|
1822
|
-
m_zoom.div.style.height = (m_chartspaces.chart.height /
|
|
1823
|
-
m_zoom.div.style.width = (m_zoom.mousedown.pos > (x /
|
|
2014
|
+
m_zoom.div.style.height = (m_chartspaces.chart.height / 1) - (m_chartCss.marginBottom / 1) - m_chartspaces.chart.top + 'px';
|
|
2015
|
+
m_zoom.div.style.width = (m_zoom.mousedown.pos > (x / 1) ? m_zoom.mousedown.pos - (x / 1) : (x / 1) - m_zoom.mousedown.pos) + 'px';
|
|
1824
2016
|
}
|
|
1825
2017
|
if (typeof _this.settings.tooltip != 'object' || typeof _this.settings.tooltip.formatter != 'function') return;
|
|
1826
|
-
if (x < m_chartspaces.chart.left || x > m_chartspaces.chart.right || y < m_chartspaces.chart.top || y > m_chartspaces.chart.height -
|
|
2018
|
+
if (x < m_chartspaces.chart.left || x > m_chartspaces.chart.right || y < m_chartspaces.chart.top || y > m_chartspaces.chart.height - m_chartspaces.chart.marginBottom) {
|
|
1827
2019
|
onMouseOut();
|
|
1828
2020
|
return;
|
|
1829
2021
|
}
|
|
@@ -1845,10 +2037,11 @@ function Milli_Chart(settings) {
|
|
|
1845
2037
|
var highy = -1;
|
|
1846
2038
|
var lowy = m_chartspaces.chart.height;
|
|
1847
2039
|
var toolArray = [];
|
|
2040
|
+
let pointerWidth = 0;
|
|
1848
2041
|
for (x = 0; x < _this.instruments.length; x++) {
|
|
1849
2042
|
if (_this.instruments[x].insref != 0 && typeof obj.instruments[x] !== 'undefined') {
|
|
1850
2043
|
var instr = {};
|
|
1851
|
-
instr.chartType =
|
|
2044
|
+
instr.chartType = chartType;
|
|
1852
2045
|
instr.name = _this.instruments[x].name;
|
|
1853
2046
|
instr.instrumenttype = _this.instruments[x].instrumenttype;
|
|
1854
2047
|
instr.pricetype = _this.instruments[x].pricetype;
|
|
@@ -1878,16 +2071,9 @@ function Milli_Chart(settings) {
|
|
|
1878
2071
|
|
|
1879
2072
|
}
|
|
1880
2073
|
var pointerStyle = getComputedStyle(_this.instruments[x].toolTipPointer);
|
|
1881
|
-
|
|
2074
|
+
pointerWidth = _this.instruments[x].toolTipPointer.offsetWidth + parseInt(pointerStyle.marginLeft) + parseInt(pointerStyle.marginRight);
|
|
1882
2075
|
var pointerHeight = _this.instruments[x].toolTipPointer.offsetHeight + parseInt(pointerStyle.marginTop) + parseInt(pointerStyle.marginBottom);
|
|
1883
2076
|
var posy = obj.instruments[x].y - (_this.instruments[x].toolTip.offsetHeight / 2);
|
|
1884
|
-
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
|
|
1885
|
-
// draw the hover to the left
|
|
1886
|
-
_this.instruments[x].toolTip.style.left = (obj.instruments[x].x - _this.instruments[x].toolTip.offsetWidth - (pointerWidth / 2)) + 1 + 'px';
|
|
1887
|
-
} else {
|
|
1888
|
-
// draw hover to the right
|
|
1889
|
-
_this.instruments[x].toolTip.style.left = (obj.instruments[x].x + (pointerWidth / 2)) + 'px';
|
|
1890
|
-
}
|
|
1891
2077
|
_this.instruments[x].toolTip.style.top = posy + 'px';
|
|
1892
2078
|
toolArray.push({ top: (obj.instruments[x].y - (pointerHeight / 2)), instrument: x });
|
|
1893
2079
|
_this.instruments[x].toolTipPointer.style.left = (obj.instruments[x].x - (pointerWidth / 2)) + 1 + 'px'; // hmm plus 1??
|
|
@@ -1895,6 +2081,13 @@ function Milli_Chart(settings) {
|
|
|
1895
2081
|
if (posy > highy) highy = posy;
|
|
1896
2082
|
if (posy < lowy) lowy = posy;
|
|
1897
2083
|
_this.instruments[x].toolTip.innerHTML = _this.settings.tooltip.formatter.call(instr, m_chartspaces, obj.instruments[x].x);
|
|
2084
|
+
if (m_dataPoints.arr[i] + (_this.instruments[x].toolTip.offsetWidth * 1.5) > m_canvas.getWidth()) { // || m_dataPoints.arr[i] + (_this.instruments[x].toolTip.offsetWidth * 1.5) > m_canvas.getWidth()) { // TODO +10 should be calculated better
|
|
2085
|
+
// draw the hover to the left
|
|
2086
|
+
_this.instruments[x].toolTip.style.left = (obj.instruments[x].x - _this.instruments[x].toolTip.offsetWidth - (pointerWidth / 2)) + 1 + 'px';
|
|
2087
|
+
} else {
|
|
2088
|
+
// draw hover to the right
|
|
2089
|
+
_this.instruments[x].toolTip.style.left = (obj.instruments[x].x + (pointerWidth / 2)) + 'px';
|
|
2090
|
+
}
|
|
1898
2091
|
} else {
|
|
1899
2092
|
if (_this.instruments[x].toolTip) {
|
|
1900
2093
|
_this.instruments[x].toolTip.parentNode.removeChild(_this.instruments[x].toolTip);
|
|
@@ -1904,15 +2097,66 @@ function Milli_Chart(settings) {
|
|
|
1904
2097
|
}
|
|
1905
2098
|
}
|
|
1906
2099
|
}
|
|
2100
|
+
//indicator hover
|
|
2101
|
+
for (x = 0; x < _this.settings.indicators.length; x++) {
|
|
2102
|
+
var px = getScaledSetting(pos.clientX) - getScaledSetting(rect.left) - 1;
|
|
2103
|
+
if (typeof _this.settings.indicators[x].toolTip === 'undefined') continue;
|
|
2104
|
+
if (_this.settings.indicators[x].staticTooltip == true) continue;
|
|
2105
|
+
var width = m_ctx.measureText(_this.settings.indicators[x].indicator).width;
|
|
2106
|
+
var remove = true;
|
|
2107
|
+
for (var xx = 0; xx < _this.settings.indicators[x].timeseries.length; xx++) {
|
|
2108
|
+
if (typeof _this.settings.indicators[x].timeseries[xx].pos === 'undefined') continue;
|
|
2109
|
+
if (typeof _this.settings.indicators[x].timeseries[xx].hl === 'undefined') continue;
|
|
2110
|
+
if (px >= _this.settings.indicators[x].timeseries[xx].pos.x - (width / 2) && px <= _this.settings.indicators[x].timeseries[xx].pos.x + (width / 2)) {
|
|
2111
|
+
if (typeof _this.settings.indicators[x].toolTip.div === 'undefined') {
|
|
2112
|
+
_this.settings.indicators[x].toolTip.div = document.createElement('div');
|
|
2113
|
+
_this.settings.indicators[x].toolTip.div.style.display = _this.settings.tooltip.display;
|
|
2114
|
+
_this.settings.indicators[x].toolTip.div.setAttribute('class', 'millistream-chart-tooltip'); // set class so we can measure it might change below depending on position
|
|
2115
|
+
_this.settings.indicators[x].toolTip.div.position = 'absolute';
|
|
2116
|
+
m_canvas.parentNode.appendChild(_this.settings.indicators[x].toolTip.div);
|
|
2117
|
+
}
|
|
2118
|
+
_this.settings.indicators[x].toolTip.div.style.left = _this.settings.indicators[x].timeseries[xx].pos.x / 1 + (pointerWidth / 2) + 'px'; // this i modified in the data for the instruments, but not for indicators
|
|
2119
|
+
_this.settings.indicators[x].toolTip.div.style.top = _this.settings.indicators[x].timeseries[xx].pos.y / 1 + 'px'; // this i modified in the data for the instruments, but not for indicators
|
|
2120
|
+
_this.settings.indicators[x].toolTip.div.innerHTML = _this.settings.indicators[x].toolTip.formatter.call(_this.settings.indicators[x].timeseries[xx]);
|
|
2121
|
+
remove = false;
|
|
2122
|
+
toolArray.push({ top: parseInt(_this.settings.indicators[x].toolTip.div.style.top), indicator: x });
|
|
2123
|
+
}
|
|
2124
|
+
|
|
2125
|
+
}
|
|
2126
|
+
if (remove) {
|
|
2127
|
+
if (_this.settings.indicators[x].toolTip.div && _this.settings.indicators[x].staticTooltip != true) {
|
|
2128
|
+
_this.settings.indicators[x].toolTip.div.parentNode.removeChild(_this.settings.indicators[x].toolTip.div);
|
|
2129
|
+
_this.settings.indicators[x].toolTip.div = undefined;
|
|
2130
|
+
}
|
|
2131
|
+
|
|
2132
|
+
}
|
|
2133
|
+
}
|
|
1907
2134
|
toolArray.sort((a, b) => a.top - b.top);
|
|
1908
2135
|
var lastTop = 0;
|
|
2136
|
+
let lastHeight = 0;
|
|
1909
2137
|
for (x = 0; x < toolArray.length; x++) {
|
|
1910
|
-
if (
|
|
1911
|
-
if (
|
|
1912
|
-
|
|
2138
|
+
if (typeof toolArray[x].instrument !== 'undefined') {
|
|
2139
|
+
//if (x != 0 && typeof _this.instruments[x - 1].toolTip !== 'undefined') {
|
|
2140
|
+
//if (lastTop + _this.instruments[x - 1].toolTip.offsetHeight > toolArray[x].top) {
|
|
2141
|
+
if (lastTop + lastHeight > toolArray[x].top) {
|
|
2142
|
+
//toolArray[x].top = (lastTop + _this.instruments[x - 1].toolTip.offsetHeight);
|
|
2143
|
+
toolArray[x].top = (lastTop + lastHeight);
|
|
2144
|
+
}
|
|
2145
|
+
//}
|
|
2146
|
+
} else {
|
|
2147
|
+
//if (lastTop + _this.settings.indicators[toolArray[x].indicator].toolTip.div.offsetHeight > toolArray[x].top) {
|
|
2148
|
+
if (lastTop + lastHeight > toolArray[x].top) {
|
|
2149
|
+
//toolArray[x].top = (lastTop + _this.settings.indicators[toolArray[x].indicator].toolTip.div.offsetHeight);
|
|
2150
|
+
toolArray[x].top = (lastTop + lastHeight);
|
|
1913
2151
|
}
|
|
1914
2152
|
}
|
|
1915
|
-
|
|
2153
|
+
if (typeof toolArray[x].instrument !== 'undefined') {
|
|
2154
|
+
_this.instruments[toolArray[x].instrument].toolTip.style.top = toolArray[x].top + 'px';
|
|
2155
|
+
lastHeight = _this.instruments[toolArray[x].instrument].toolTip.offsetHeight;
|
|
2156
|
+
} else {
|
|
2157
|
+
_this.settings.indicators[toolArray[x].indicator].toolTip.div.style.top = toolArray[x].top + 'px';
|
|
2158
|
+
lastHeight = _this.settings.indicators[toolArray[x].indicator].toolTip.div.offsetHeight;
|
|
2159
|
+
}
|
|
1916
2160
|
lastTop = toolArray[x].top;
|
|
1917
2161
|
}
|
|
1918
2162
|
return;
|
|
@@ -1948,13 +2192,13 @@ function Milli_Chart(settings) {
|
|
|
1948
2192
|
m_zoom.mouseup.timestamp = new Date(m_zoom.mouseup.timestamp + 'T00:00:00Z');
|
|
1949
2193
|
}
|
|
1950
2194
|
_this.settings.chartlen = 'max';
|
|
1951
|
-
|
|
2195
|
+
chartType = 'history';
|
|
1952
2196
|
_this.drawChart();
|
|
1953
2197
|
};
|
|
1954
2198
|
|
|
1955
2199
|
function calcCompareFactors(type) {
|
|
1956
2200
|
var i, s;
|
|
1957
|
-
var instrumentprice;
|
|
2201
|
+
//var instrumentprice;
|
|
1958
2202
|
|
|
1959
2203
|
for (s = 1; s < _this.instruments.length; s++) {
|
|
1960
2204
|
if (_this.instruments[s].insref != 0) {
|
|
@@ -1962,11 +2206,12 @@ function Milli_Chart(settings) {
|
|
|
1962
2206
|
if (_this.instruments[s].history[i].timestamp >= _this.scaleinfoX.startTimeStamp) {
|
|
1963
2207
|
for (var x = 0; x < _this.instruments[0].history.length; x++) {
|
|
1964
2208
|
if (_this.instruments[0].history[x].timestamp >= _this.instruments[s].history[i].timestamp) {
|
|
1965
|
-
instrumentprice = _this.instruments[0].history[x].price;
|
|
2209
|
+
//instrumentprice = _this.instruments[0].history[x].price;
|
|
2210
|
+
_this.instruments[s].factor = _this.instruments[0].history[x].price / _this.instruments[s].history[i].price;
|
|
1966
2211
|
break;
|
|
1967
2212
|
}
|
|
1968
2213
|
}
|
|
1969
|
-
_this.instruments[s].factor = instrumentprice / _this.instruments[s].history[i].price;
|
|
2214
|
+
//_this.instruments[s].factor = instrumentprice / _this.instruments[s].history[i].price;
|
|
1970
2215
|
break;
|
|
1971
2216
|
}
|
|
1972
2217
|
}
|
|
@@ -1976,14 +2221,17 @@ function Milli_Chart(settings) {
|
|
|
1976
2221
|
|
|
1977
2222
|
function checkChartData(data) {
|
|
1978
2223
|
var count = 0;
|
|
2224
|
+
//_this.instruments[0].timeseries = [];
|
|
1979
2225
|
for (var i = 0; i < data.length; i++) {
|
|
1980
2226
|
if (data[i].timestamp >= _this.scaleinfoX.startTimeStamp && data[i].timestamp <= _this.scaleinfoX.endTimeStamp) {
|
|
2227
|
+
// _this.instruments[0].timeseries.push(data[i]);
|
|
1981
2228
|
if (count++ > 0) {
|
|
1982
2229
|
return true;
|
|
1983
2230
|
}
|
|
1984
2231
|
}
|
|
1985
2232
|
}
|
|
1986
|
-
if (_this.
|
|
2233
|
+
//if (_this.instruments[0].timeseries.length > 1) return true;
|
|
2234
|
+
if (chartType == 'trades' && count > 0 && _this.instruments[0].closeprice1d) return true; // we can draw on closeprice 1d -> first trade
|
|
1987
2235
|
var y = (m_chartspaces.chart.bottom - m_chartspaces.chart.top) / 2 + m_chartspaces.chart.top;
|
|
1988
2236
|
var x = (m_chartspaces.chart.right - m_chartspaces.chart.left) / 2 + m_chartspaces.chart.left;
|
|
1989
2237
|
m_ctx.save();
|
|
@@ -1999,49 +2247,74 @@ function Milli_Chart(settings) {
|
|
|
1999
2247
|
}
|
|
2000
2248
|
|
|
2001
2249
|
function calcChartSpaces() {
|
|
2002
|
-
m_chartspaces.chart.height = Math.round(m_canvas.
|
|
2003
|
-
m_chartspaces.chart.
|
|
2250
|
+
m_chartspaces.chart.height = Math.round(m_canvas.getHeight() * (m_chartspaces.chart.percent / 100));
|
|
2251
|
+
m_chartspaces.chart.marginTop = getScaledSetting(m_chartCss.marginTop);
|
|
2252
|
+
m_chartspaces.chart.top = m_chartspaces.chart.marginTop;
|
|
2004
2253
|
m_chartspaces.chart.left = getScaledSetting(m_chartCss.marginLeft);
|
|
2005
|
-
m_chartspaces.chart.right = m_canvas.
|
|
2006
|
-
m_chartspaces.chart.
|
|
2007
|
-
m_chartspaces.chart.
|
|
2008
|
-
m_chartspaces.
|
|
2009
|
-
|
|
2254
|
+
m_chartspaces.chart.right = m_canvas.getWidth()- getScaledSetting(m_chartCss.marginRight) - 50;
|
|
2255
|
+
m_chartspaces.chart.marginBottom = getScaledSetting(m_chartCss.marginBottom);
|
|
2256
|
+
m_chartspaces.chart.bottom = (m_chartspaces.chart.height - m_chartspaces.chart.marginBottom);
|
|
2257
|
+
m_chartspaces.chart.width = m_canvas.getWidth()
|
|
2258
|
+
|
|
2259
|
+
m_chartspaces.lowerChart.marginBottom = getScaledSetting(20) / window.devicePixelRatio;
|
|
2260
|
+
m_chartspaces.lowerChart.marginTop = getScaledSetting(0);
|
|
2261
|
+
m_chartspaces.lowerChart.height = Math.round(m_canvas.getHeight() - m_chartspaces.chart.height);
|
|
2262
|
+
m_chartspaces.lowerChart.top = m_chartspaces.chart.height + m_chartspaces.lowerChart.marginTop;
|
|
2010
2263
|
m_chartspaces.lowerChart.left = m_chartspaces.chart.left;
|
|
2011
2264
|
m_chartspaces.lowerChart.right = m_chartspaces.chart.right;
|
|
2012
|
-
m_chartspaces.lowerChart.bottom = m_canvas.
|
|
2013
|
-
m_chartspaces.lowerChart.width = m_canvas.
|
|
2265
|
+
m_chartspaces.lowerChart.bottom = m_canvas.getHeight() - m_chartspaces.lowerChart.marginBottom;
|
|
2266
|
+
m_chartspaces.lowerChart.width = m_canvas.getWidth()
|
|
2014
2267
|
}
|
|
2015
2268
|
|
|
2016
|
-
|
|
2017
|
-
if (m_zoom.isZooming) {
|
|
2018
|
-
return; // prevent redraw due to push updates when zooming
|
|
2019
|
-
}
|
|
2020
|
-
|
|
2269
|
+
function calculateIndicators() {
|
|
2021
2270
|
for (var i = 0; i < _this.settings.indicators.length; i++) {
|
|
2022
2271
|
switch (_this.settings.indicators[i].method) {
|
|
2023
2272
|
case 'sma':
|
|
2024
|
-
|
|
2025
|
-
_this.settings.indicators[i].
|
|
2026
|
-
|
|
2027
|
-
|
|
2273
|
+
if (chartType == 'history')
|
|
2274
|
+
_this.settings.indicators[i].timeseries = simpleMovingAverage(_this.instruments[0].history, _this.settings.indicators[i].method_length);
|
|
2275
|
+
else
|
|
2276
|
+
_this.settings.indicators[i].timeseries = simpleMovingAverage(_this.instruments[0].trades, _this.settings.indicators[i].method_length);
|
|
2028
2277
|
break;
|
|
2029
2278
|
case 'ema':
|
|
2030
|
-
|
|
2031
|
-
_this.settings.indicators[i].
|
|
2032
|
-
|
|
2033
|
-
|
|
2034
|
-
|
|
2279
|
+
if (chartType == 'history')
|
|
2280
|
+
_this.settings.indicators[i].timeseries = exponentialMovingAverage(_this.instruments[0].history, _this.settings.indicators[i].method_length);
|
|
2281
|
+
else
|
|
2282
|
+
_this.settings.indicators[i].timeseries = exponentialMovingAverage(_this.instruments[0].trades, _this.settings.indicators[i].method_length);
|
|
2283
|
+
break;
|
|
2035
2284
|
case 'bb':
|
|
2036
|
-
|
|
2037
|
-
_this.settings.indicators[i].
|
|
2038
|
-
|
|
2039
|
-
|
|
2040
|
-
|
|
2285
|
+
if (chartType == 'history')
|
|
2286
|
+
_this.settings.indicators[i].timeseries = calculateBollingerBands(_this.instruments[0].history, _this.settings.indicators[i].method_length, _this.settings.indicators[i].stddev | 2);
|
|
2287
|
+
else
|
|
2288
|
+
_this.settings.indicators[i].timeseries = calculateBollingerBands(_this.instruments[0].trades, _this.settings.indicators[i].method_length, _this.settings.indicators[i].stddev | 2);
|
|
2289
|
+
break;
|
|
2290
|
+
case 'news':
|
|
2291
|
+
_this.settings.indicators[i].timeseries = calculateNews(_this.settings.indicators[i].news, _this.settings.indicators[i].method_length, _this.settings.indicators[i].stddev | 2);
|
|
2292
|
+
break;
|
|
2293
|
+
// future events osv?
|
|
2041
2294
|
default:
|
|
2042
2295
|
break;
|
|
2043
2296
|
}
|
|
2044
2297
|
}
|
|
2298
|
+
}
|
|
2299
|
+
|
|
2300
|
+
_this.drawChart = function() {
|
|
2301
|
+
if (m_zoom.isZooming) {
|
|
2302
|
+
return; // prevent redraw due to push updates when zooming
|
|
2303
|
+
}
|
|
2304
|
+
m_chartspaces.chart.percent = 100;
|
|
2305
|
+
m_chartspaces.lowerChart.percent = 0;
|
|
2306
|
+
for (let i = 0; i < _this.settings.indicators.length; i++) {
|
|
2307
|
+
if (_this.settings.indicators[i].target == 'lower') {
|
|
2308
|
+
m_chartspaces.chart.percent = 70;
|
|
2309
|
+
m_chartspaces.lowerChart.percent = 30;
|
|
2310
|
+
break;
|
|
2311
|
+
}
|
|
2312
|
+
}
|
|
2313
|
+
var period = _this.settings.chartlen.substring(_this.settings.chartlen.length - 1);
|
|
2314
|
+
var len = parseInt(_this.settings.chartlen.substring(0, _this.settings.chartlen.length - 1));
|
|
2315
|
+
if (period == 'd' && _this.settings.chartlen != 'ytd') chartType = 'trades';
|
|
2316
|
+
else chartType = 'history';
|
|
2317
|
+
|
|
2045
2318
|
if (m_lastDrawnInstrument != _this.instruments[0].insref) {
|
|
2046
2319
|
m_zoom.mousedown.pos = 0;
|
|
2047
2320
|
m_zoom.mousedown.i = 0;
|
|
@@ -2063,10 +2336,8 @@ function Milli_Chart(settings) {
|
|
|
2063
2336
|
}
|
|
2064
2337
|
calcChartSpaces();
|
|
2065
2338
|
|
|
2066
|
-
|
|
2067
|
-
|
|
2068
|
-
m_ctx.clearRect(0, 0, m_canvas.width, m_canvas.height);
|
|
2069
|
-
m_ctx.lineWidth = 1 / window.devicePixelRatio;
|
|
2339
|
+
m_ctx.clearRect(0, 0, m_canvas.getWidth(), m_canvas.getHeight());
|
|
2340
|
+
m_ctx.lineWidth = 1 / 1;
|
|
2070
2341
|
m_ctx.textBaseline = 'top'; // important!
|
|
2071
2342
|
var s;
|
|
2072
2343
|
if (period == 'd' && _this.settings.chartlen != 'ytd') {
|
|
@@ -2104,9 +2375,14 @@ function Milli_Chart(settings) {
|
|
|
2104
2375
|
_this.scaleinfoX.endTimeStamp -= _this.scaleinfoX.endTimeStamp - _this.scaleinfoX.endTimeStamp % 86400000;
|
|
2105
2376
|
_this.scaleinfoX.endTimeStamp += _this.instruments[0].quotedate; // set enddate = last Quotedate
|
|
2106
2377
|
}
|
|
2378
|
+
for (var i = 0; i < _this.settings.indicators.length; i++) {
|
|
2379
|
+
if (_this.settings.indicators[i].type == FUTUREINDICATOR) {
|
|
2380
|
+
let endDate = new Date(_this.settings.indicators[i].timeseries[0].timestamp).getTime();
|
|
2381
|
+
if (endDate > _this.scaleinfoX.endTimeStamp) _this.scaleinfoX.endTimeStamp = endDate;
|
|
2382
|
+
}
|
|
2383
|
+
}
|
|
2107
2384
|
}
|
|
2108
2385
|
setTimeSpanData();
|
|
2109
|
-
_this.scaleinfoY.type = 'trades';
|
|
2110
2386
|
if (_this.settings.absoluteScaling == true) {
|
|
2111
2387
|
for (s = 1; s < _this.instruments.length; s++) _this.instruments[s].factor = 1;
|
|
2112
2388
|
} else
|
|
@@ -2133,17 +2409,39 @@ function Milli_Chart(settings) {
|
|
|
2133
2409
|
}
|
|
2134
2410
|
_this.instruments[0].factor = 1;
|
|
2135
2411
|
if (false == checkChartData(_this.instruments[0].trades)) return;
|
|
2136
|
-
|
|
2412
|
+
calculateIndicators();
|
|
2413
|
+
drawYAxis(scaleinfoY, scaleinfoY2);
|
|
2137
2414
|
drawXAxisTick(_this.scaleinfoX.startTimeStamp, _this.scaleinfoX.endTimeStamp);
|
|
2138
2415
|
for (i = 0; i < _this.instruments.length; i++) {
|
|
2139
|
-
if (_this.instruments[i].insref != 0)
|
|
2140
|
-
plotData(_this.instruments[i].trades, i);
|
|
2416
|
+
if (_this.instruments[i].insref != 0) {
|
|
2417
|
+
plotData(_this.instruments[i].trades, i, scaleinfoY);
|
|
2418
|
+
}
|
|
2141
2419
|
}
|
|
2142
2420
|
|
|
2143
2421
|
for (i = 0; i < _this.settings.indicators.length; i++) {
|
|
2144
|
-
|
|
2145
|
-
|
|
2146
|
-
|
|
2422
|
+
switch (_this.settings.indicators[i].method) {
|
|
2423
|
+
case 'bb':
|
|
2424
|
+
plotBollingerBand(_this.settings.indicators[i], 'trades');
|
|
2425
|
+
break;
|
|
2426
|
+
case 'sma':
|
|
2427
|
+
case 'ema':
|
|
2428
|
+
plotIndicatorLine(_this.settings.indicators[i], scaleinfoY, m_chartspaces.chart);
|
|
2429
|
+
break;
|
|
2430
|
+
case 'rsi':
|
|
2431
|
+
case 'momentum':
|
|
2432
|
+
case 'quantity':
|
|
2433
|
+
break;
|
|
2434
|
+
case 'ohlc':
|
|
2435
|
+
case 'candlestick':
|
|
2436
|
+
break;
|
|
2437
|
+
default:
|
|
2438
|
+
if (_this.settings.indicators[i].style == 'line')
|
|
2439
|
+
plotIndicatorLine(_this.settings.indicators[i], scaleinfoY, m_chartspaces.chart);
|
|
2440
|
+
else {
|
|
2441
|
+
plotIndicator(_this.settings.indicators[i], scaleinfoY);
|
|
2442
|
+
}
|
|
2443
|
+
break;
|
|
2444
|
+
}
|
|
2147
2445
|
}
|
|
2148
2446
|
|
|
2149
2447
|
} else
|
|
@@ -2163,27 +2461,80 @@ function Milli_Chart(settings) {
|
|
|
2163
2461
|
|
|
2164
2462
|
_this.scaleinfoX.endTimeStamp = new Date().getTime();
|
|
2165
2463
|
_this.scaleinfoX.endTimeStamp = _this.scaleinfoX.endTimeStamp - (_this.scaleinfoX.endTimeStamp % 86400000); // TODO: detta kan vi nog ta bort eller skall det vara med closetime?
|
|
2464
|
+
for (var i = 0; i < _this.settings.indicators.length; i++) {
|
|
2465
|
+
if (_this.settings.indicators[i].type == FUTUREINDICATOR) {
|
|
2466
|
+
let endDate = new Date(_this.settings.indicators[i].timeseries[0].timestamp).getTime();
|
|
2467
|
+
if (endDate > _this.scaleinfoX.endTimeStamp) _this.scaleinfoX.endTimeStamp = endDate;
|
|
2468
|
+
}
|
|
2469
|
+
|
|
2470
|
+
}
|
|
2471
|
+
_this.scaleinfoX.endTimeStamp = _this.scaleinfoX.endTimeStamp - (_this.scaleinfoX.endTimeStamp % 86400000); // TODO: detta kan vi nog ta bort eller skall det vara med closetime?
|
|
2166
2472
|
}
|
|
2167
2473
|
setTimeSpanData();
|
|
2168
|
-
|
|
2474
|
+
|
|
2169
2475
|
if (_this.settings.absoluteScaling == true) {
|
|
2170
2476
|
for (s = 1; s < _this.instruments.length; s++) _this.instruments[s].factor = 1;
|
|
2171
2477
|
} else calcCompareFactors('history');
|
|
2172
2478
|
_this.instruments[0].factor = 1;
|
|
2173
2479
|
|
|
2174
2480
|
if (false == checkChartData(_this.instruments[0].history)) return;
|
|
2175
|
-
|
|
2481
|
+
calculateIndicators();
|
|
2482
|
+
|
|
2483
|
+
/*let scaleY = {};
|
|
2484
|
+
if (_this.settings.drawyaxis) {
|
|
2485
|
+
if (false == calcHighLow2(scaleY, m_chartspaces.chart, m_yLegendCss)) {
|
|
2486
|
+
console.log('fail highlow');
|
|
2487
|
+
return;
|
|
2488
|
+
}
|
|
2489
|
+
}
|
|
2490
|
+
let scaleY2 = {};
|
|
2491
|
+
let factorInfo = {
|
|
2492
|
+
name: 'diff',
|
|
2493
|
+
actor: _this.instruments[0].startValue,
|
|
2494
|
+
suffix: '%'
|
|
2495
|
+
};
|
|
2496
|
+
if (_this.settings.drawy2axis) {
|
|
2497
|
+
if (false == calcHighLow2(scaleY2, m_chartspaces.chart, m_y2LegendCss, factorInfo)) {
|
|
2498
|
+
console.log('fail highlow');
|
|
2499
|
+
return;
|
|
2500
|
+
}
|
|
2501
|
+
}
|
|
2502
|
+
|
|
2503
|
+
drawYAxisNew(scaleY, m_chartspaces.chart, m_yLegendCss, _this.settings.drawyaxis, _this.settings.gridHorizontalLines);
|
|
2504
|
+
drawYAxisNew(scaleY2, m_chartspaces.chart, m_y2LegendCss, _this.settings.drawy2axis, false, factorInfo); *
|
|
2505
|
+
*/
|
|
2506
|
+
drawYAxis(scaleinfoY, scaleinfoY2);
|
|
2176
2507
|
drawXAxisMonth(_this.scaleinfoX.startTimeStamp, _this.scaleinfoX.endTimeStamp);
|
|
2177
2508
|
|
|
2178
2509
|
for (i = 0; i < _this.instruments.length; i++) {
|
|
2179
2510
|
if (_this.instruments[i].insref != 0)
|
|
2180
|
-
|
|
2511
|
+
//plotData(_this.instruments[i].history, i, scaleY);
|
|
2512
|
+
plotData(_this.instruments[i].history, i, scaleinfoY);
|
|
2181
2513
|
}
|
|
2182
2514
|
|
|
2183
2515
|
for (i = 0; i < _this.settings.indicators.length; i++) {
|
|
2184
|
-
|
|
2185
|
-
|
|
2186
|
-
|
|
2516
|
+
switch (_this.settings.indicators[i].method) {
|
|
2517
|
+
case 'bb':
|
|
2518
|
+
plotBollingerBand(_this.settings.indicators[i], 'history', scaleinfoY);
|
|
2519
|
+
break;
|
|
2520
|
+
case 'sma':
|
|
2521
|
+
case 'ema':
|
|
2522
|
+
plotIndicatorLine(_this.settings.indicators[i], scaleinfoY, m_chartspaces.chart);
|
|
2523
|
+
break;
|
|
2524
|
+
case 'rsi':
|
|
2525
|
+
case 'momentum':
|
|
2526
|
+
case 'quantity':
|
|
2527
|
+
break;
|
|
2528
|
+
case 'ohlc':
|
|
2529
|
+
case 'candlestick':
|
|
2530
|
+
break;
|
|
2531
|
+
default:
|
|
2532
|
+
if (_this.settings.indicators[i].style == 'line')
|
|
2533
|
+
plotIndicatorLine(_this.settings.indicators[i], scaleinfoY, m_chartspaces.chart);
|
|
2534
|
+
else
|
|
2535
|
+
plotIndicator(_this.settings.indicators[i], scaleinfoY);
|
|
2536
|
+
break;
|
|
2537
|
+
}
|
|
2187
2538
|
}
|
|
2188
2539
|
} else
|
|
2189
2540
|
if ((period == 'y' || _this.settings.chartlen == 'ytd' || _this.settings.chartlen == 'max')) {
|
|
@@ -2206,51 +2557,126 @@ function Milli_Chart(settings) {
|
|
|
2206
2557
|
|
|
2207
2558
|
_this.scaleinfoX.endTimeStamp = new Date().getTime();
|
|
2208
2559
|
_this.scaleinfoX.endTimeStamp = _this.scaleinfoX.endTimeStamp - (_this.scaleinfoX.endTimeStamp % 86400000); // TODO: detta kan vi nog ta bort eller skall det vara med closetime?
|
|
2560
|
+
for (var i = 0; i < _this.settings.indicators.length; i++) {
|
|
2561
|
+
if (_this.settings.indicators[i].type == FUTUREINDICATOR) {
|
|
2562
|
+
let endDate = new Date(_this.settings.indicators[i].timeseries[0].timestamp).getTime();
|
|
2563
|
+
if (endDate > _this.scaleinfoX.endTimeStamp) _this.scaleinfoX.endTimeStamp = endDate;
|
|
2564
|
+
}
|
|
2565
|
+
}
|
|
2209
2566
|
}
|
|
2210
2567
|
setTimeSpanData();
|
|
2211
|
-
|
|
2568
|
+
|
|
2569
|
+
|
|
2570
|
+
_this.instruments[0].factor = 1;
|
|
2571
|
+
if (false == checkChartData(_this.instruments[0].history)) return;
|
|
2572
|
+
calculateIndicators();
|
|
2573
|
+
|
|
2212
2574
|
if (_this.settings.absoluteScaling == true) {
|
|
2213
2575
|
for (s = 1; s < _this.instruments.length; s++) _this.instruments[s].factor = 1;
|
|
2214
2576
|
} else calcCompareFactors('history');
|
|
2215
2577
|
|
|
2216
|
-
|
|
2217
|
-
if (false == checkChartData(_this.instruments[0].history)) return;
|
|
2218
|
-
drawYAxis();
|
|
2578
|
+
drawYAxis(scaleinfoY, scaleinfoY2);
|
|
2219
2579
|
drawXAxisYears(_this.scaleinfoX.startTimeStamp, _this.scaleinfoX.endTimeStamp);
|
|
2220
2580
|
for (i = 0; i < _this.instruments.length; i++)
|
|
2221
2581
|
if (_this.instruments[i].insref != 0)
|
|
2222
|
-
plotData(_this.instruments[i].history, i);
|
|
2582
|
+
plotData(_this.instruments[i].history, i, scaleinfoY);
|
|
2223
2583
|
|
|
2224
2584
|
for (i = 0; i < _this.settings.indicators.length; i++) {
|
|
2225
|
-
|
|
2226
|
-
|
|
2227
|
-
|
|
2585
|
+
switch (_this.settings.indicators[i].method) {
|
|
2586
|
+
case 'bb':
|
|
2587
|
+
plotBollingerBand(_this.settings.indicators[i], 'history', scaleinfoY);
|
|
2588
|
+
break;
|
|
2589
|
+
case 'sma':
|
|
2590
|
+
case 'ema':
|
|
2591
|
+
plotIndicatorLine(_this.settings.indicators[i], scaleinfoY, m_chartspaces.chart);
|
|
2592
|
+
break;
|
|
2593
|
+
case 'rsi':
|
|
2594
|
+
case 'momentum':
|
|
2595
|
+
case 'quantity':
|
|
2596
|
+
break;
|
|
2597
|
+
case 'ohlc':
|
|
2598
|
+
case 'candlestick':
|
|
2599
|
+
break;
|
|
2600
|
+
default:
|
|
2601
|
+
if (_this.settings.indicators[i].style == 'line')
|
|
2602
|
+
plotIndicatorLine(_this.settings.indicators[i], scaleinfoY, m_chartspaces.chart);
|
|
2603
|
+
else
|
|
2604
|
+
plotIndicator(_this.settings.indicators[i], scaleinfoY);
|
|
2605
|
+
break;
|
|
2606
|
+
}
|
|
2228
2607
|
}
|
|
2229
|
-
|
|
2230
|
-
/*for (const [key, a] of m_analyzisMethod.entries()) {
|
|
2231
|
-
if (a.method == 'bb') plotBollingerBand(a, 'history');
|
|
2232
|
-
else plotMovingAverage(a, 'history');
|
|
2233
|
-
}*/
|
|
2234
2608
|
}
|
|
2235
2609
|
drawBoxShadow(m_chartspaces.chart);
|
|
2236
|
-
|
|
2237
|
-
if (m_chartspaces.chart.percent != 100) {
|
|
2238
|
-
drawXAxisTickLowerChart();
|
|
2239
|
-
drawYAxisLower();
|
|
2240
|
-
drawBoxShadow(m_chartspaces.lowerChart);
|
|
2241
|
-
}
|
|
2610
|
+
drawLowerChart();
|
|
2242
2611
|
if (typeof m_chartCss.backgroundColor !== 'undefined') {
|
|
2243
2612
|
m_ctx.save();
|
|
2244
2613
|
//if (_this.settings.curveOnTop == false)
|
|
2245
2614
|
m_ctx.globalCompositeOperation = 'destination-over';
|
|
2246
2615
|
m_ctx.fillStyle = m_chartCss.backgroundColor;
|
|
2247
|
-
//m_ctx.fillRect(0, 0, m_canvas.
|
|
2248
|
-
m_ctx.fillRect(0, 0, m_canvas.
|
|
2616
|
+
//m_ctx.fillRect(0, 0, m_canvas.getWidth(), m_canvas.getHeight());
|
|
2617
|
+
m_ctx.fillRect(0, 0, m_canvas.getWidth(), m_canvas.getHeight());
|
|
2249
2618
|
m_ctx.restore();
|
|
2250
2619
|
}
|
|
2251
2620
|
//onMouseOut();
|
|
2252
2621
|
};
|
|
2253
2622
|
|
|
2623
|
+
function drawLowerChart() {
|
|
2624
|
+
let lowerScale = {};
|
|
2625
|
+
let lowerDrawn = false;
|
|
2626
|
+
for (let i = 0; i < _this.settings.indicators.length; i++) {
|
|
2627
|
+
switch (_this.settings.indicators[i].method) {
|
|
2628
|
+
case 'momentum':
|
|
2629
|
+
if (chartType == 'history') _this.settings.indicators[i].timeseries = calculateMomentum(_this.instruments[0].history, _this.settings.indicators[i].method_length);
|
|
2630
|
+
else _this.settings.indicators[i].timeseries = calculateMomentum(_this.instruments[0].trades, _this.settings.indicators[i].method_length);
|
|
2631
|
+
if (_this.settings.indicators[i].target == 'upper') {
|
|
2632
|
+
lowerScale = drawYAxisIndicator(_this.settings.indicators[i].timeseries, m_chartspaces.chart, false);
|
|
2633
|
+
plotIndicatorLine(_this.settings.indicators[i], lowerScale, m_chartspaces.chart);
|
|
2634
|
+
} else {
|
|
2635
|
+
if (lowerDrawn == false) {
|
|
2636
|
+
drawXAxisTickLowerChart();
|
|
2637
|
+
lowerScale = drawYAxisIndicator(_this.settings.indicators[i].timeseries, m_chartspaces.lowerChart, true);
|
|
2638
|
+
plotIndicatorLine(_this.settings.indicators[i], lowerScale, m_chartspaces.lowerChart);
|
|
2639
|
+
drawBoxShadow(m_chartspaces.lowerChart);
|
|
2640
|
+
lowerDrawn = true;
|
|
2641
|
+
}
|
|
2642
|
+
}
|
|
2643
|
+
break;
|
|
2644
|
+
case 'rsi':
|
|
2645
|
+
if (chartType == 'history') _this.settings.indicators[i].timeseries = calculateRSI(_this.instruments[0].history, _this.settings.indicators[i].method_length);
|
|
2646
|
+
else _this.settings.indicators[i].timeseries = calculateRSI(_this.instruments[0].trades, _this.settings.indicators[i].method_length);
|
|
2647
|
+
if (_this.settings.indicators[i].target == 'upper') {
|
|
2648
|
+
lowerScale = drawYAxisIndicator(_this.settings.indicators[i].timeseries, m_chartspaces.chart, false);
|
|
2649
|
+
plotIndicatorLine(_this.settings.indicators[i], lowerScale, m_chartspaces.chart);
|
|
2650
|
+
} else {
|
|
2651
|
+
if (lowerDrawn == false) {
|
|
2652
|
+
drawXAxisTickLowerChart();
|
|
2653
|
+
lowerScale = drawYAxisIndicator(_this.settings.indicators[i].timeseries, m_chartspaces.lowerChart, true);
|
|
2654
|
+
plotIndicatorLine(_this.settings.indicators[i], lowerScale, m_chartspaces.lowerChart);
|
|
2655
|
+
drawBoxShadow(m_chartspaces.lowerChart);
|
|
2656
|
+
lowerDrawn = true;
|
|
2657
|
+
}
|
|
2658
|
+
}
|
|
2659
|
+
break;
|
|
2660
|
+
case 'quantity':
|
|
2661
|
+
if (chartType == 'history') _this.settings.indicators[i].timeseries = calculateQuantity(_this.instruments[0].history, _this.settings.indicators[i].target);
|
|
2662
|
+
else _this.settings.indicators[i].timeseries = calculateQuantity(_this.instruments[0].trades, _this.settings.indicators[i].target);
|
|
2663
|
+
if (_this.settings.indicators[i].target == 'upper') {
|
|
2664
|
+
lowerScale = drawYAxisIndicator(_this.settings.indicators[i].timeseries, m_chartspaces.chart, false);
|
|
2665
|
+
plotBars(_this.settings.indicators[i], lowerScale, m_chartspaces.chart);
|
|
2666
|
+
break;
|
|
2667
|
+
} else {
|
|
2668
|
+
if (lowerDrawn == false) {
|
|
2669
|
+
drawXAxisTickLowerChart();
|
|
2670
|
+
lowerScale = drawYAxisIndicator(_this.settings.indicators[i].timeseries, m_chartspaces.lowerChart, true);
|
|
2671
|
+
plotBars(_this.settings.indicators[i], lowerScale, m_chartspaces.lowerChart, true);
|
|
2672
|
+
lowerDrawn = true;
|
|
2673
|
+
}
|
|
2674
|
+
}
|
|
2675
|
+
return;
|
|
2676
|
+
}
|
|
2677
|
+
}
|
|
2678
|
+
}
|
|
2679
|
+
|
|
2254
2680
|
function drawBoxShadow(space) {
|
|
2255
2681
|
if (typeof m_chartCss.boxShadow === 'undefined' || typeof m_chartCss.boxShadow.color === 'undefined') return;
|
|
2256
2682
|
m_ctx.save();
|
|
@@ -2293,6 +2719,9 @@ function Milli_Chart(settings) {
|
|
|
2293
2719
|
data.marketclose = '22:00:00';
|
|
2294
2720
|
}
|
|
2295
2721
|
}
|
|
2722
|
+
if (typeof data.diff1dprc !== 'undefined')
|
|
2723
|
+
instr.diff1dprc = data.diff1dprc;
|
|
2724
|
+
|
|
2296
2725
|
if (typeof data.date !== 'undefined') {
|
|
2297
2726
|
instr.quotedate = new Date(data.date).getTime();
|
|
2298
2727
|
instr.quotedate -= instr.quotedate % 86400000;
|
|
@@ -2340,6 +2769,7 @@ function Milli_Chart(settings) {
|
|
|
2340
2769
|
instr.trades.push(item);
|
|
2341
2770
|
instr.hashmap.set(item.timestamp, item);
|
|
2342
2771
|
// we might have recieved trades from push before dataapi
|
|
2772
|
+
// borde sorteras utanför loopen?
|
|
2343
2773
|
instr.trades.sort(function(a, b) {
|
|
2344
2774
|
return a.timestamp - b.timestamp;
|
|
2345
2775
|
});
|
|
@@ -2357,6 +2787,8 @@ function Milli_Chart(settings) {
|
|
|
2357
2787
|
item.timestamp = timestamp;
|
|
2358
2788
|
} else continue;
|
|
2359
2789
|
if (typeof data.history[i].closeprice !== 'undefined') item.price = parseFloat(data.history[i].closeprice) * factor;
|
|
2790
|
+
if (typeof data.history[i].closedayhighprice !== 'undefined') item.highprice = parseFloat(data.history[i].closedayhighprice) * factor;
|
|
2791
|
+
if (typeof data.history[i].closedaylowprice !== 'undefined') item.lowprice = parseFloat(data.history[i].closedaylowprice) * factor;
|
|
2360
2792
|
if (typeof data.history[i].openprice !== 'undefined') item.openprice = data.history[i].openprice;
|
|
2361
2793
|
if (typeof data.history[i].closequantity !== 'undefined') item.quantity = data.history[i].closequantity;
|
|
2362
2794
|
if (typeof data.history[i].dividend !== 'undefined') item.dividend = data.history[i].dividend;
|
|
@@ -2373,19 +2805,6 @@ function Milli_Chart(settings) {
|
|
|
2373
2805
|
}
|
|
2374
2806
|
}
|
|
2375
2807
|
|
|
2376
|
-
_this.addQuantity = function() {
|
|
2377
|
-
if (m_chartspaces.chart.percent == 100) {
|
|
2378
|
-
m_chartspaces.chart.percent = 70;
|
|
2379
|
-
m_chartspaces.lowerChart.percent = 30;
|
|
2380
|
-
} else {
|
|
2381
|
-
m_chartspaces.chart.percent = 100;
|
|
2382
|
-
m_chartspaces.lowerChart.percent = 0;
|
|
2383
|
-
_this.drawChart();
|
|
2384
|
-
return;
|
|
2385
|
-
}
|
|
2386
|
-
_this.drawChart();
|
|
2387
|
-
};
|
|
2388
|
-
|
|
2389
2808
|
function plotExternalHistoricalData(data) {
|
|
2390
2809
|
// används för dividend osv
|
|
2391
2810
|
m_ctx.save();
|
|
@@ -2429,14 +2848,13 @@ function Milli_Chart(settings) {
|
|
|
2429
2848
|
// TODO: här blir det fel när det är från 00:00: 23:59 men göms av tmpx < startpoint.x
|
|
2430
2849
|
|
|
2431
2850
|
}
|
|
2432
|
-
|
|
2433
|
-
startpoint.y = Math.round(m_chartspaces.chart.height - getScaledSetting(m_chartCss.marginBottom) - (((data[i].price * factor) - _this.scaleinfoY.minValue) * _this.scaleinfoY.valuePerPixel)) + 0.5;
|
|
2851
|
+
startpoint.y = Math.round(m_chartspaces.chart.height - m_chartspaces.chart.marginBottom - (((data[i].price * factor) - scaleinfoY.minValue) / scaleinfoY.valuePerPixel)) + 0.5;
|
|
2434
2852
|
maxy = maxy > startpoint.y ? maxy : startpoint.y;
|
|
2435
2853
|
|
|
2436
2854
|
startpoint.x = Math.round(m_chartspaces.chart.left + ((data[i].timestamp - _this.scaleinfoX.startDate.getTime()) / _this.scaleinfoX.timePerPixel)) + 0.5;
|
|
2437
2855
|
startpoint.x -= offset;
|
|
2438
2856
|
m_ctx.beginPath();
|
|
2439
|
-
m_ctx.arc(startpoint.x, startpoint.y - 20, 10, 0, 2 * Math.PI, false);
|
|
2857
|
+
m_ctx.arc(startpoint.x, startpoint.y - 20, 10, 0, 2 * Math.PI, false); // ritar en rund blob, ska nog va nåt annat
|
|
2440
2858
|
m_ctx.fillStyle = 'green';
|
|
2441
2859
|
m_ctx.fill();
|
|
2442
2860
|
m_ctx.stroke();
|
|
@@ -2445,7 +2863,8 @@ function Milli_Chart(settings) {
|
|
|
2445
2863
|
m_ctx.restore();
|
|
2446
2864
|
}
|
|
2447
2865
|
|
|
2448
|
-
function calcAnalyzisLine(data, pricecol) {
|
|
2866
|
+
function calcAnalyzisLine(data, pricecol, y, cs, sc) {
|
|
2867
|
+
let chartspace = typeof cs === 'undefined' ? m_chartspaces.chart : cs;
|
|
2449
2868
|
var startpoint = { x: 0, y: 0 };
|
|
2450
2869
|
var endpoint = { x: 0, y: 0 };
|
|
2451
2870
|
var startDate = _this.scaleinfoX.startTimeStamp;
|
|
@@ -2454,35 +2873,39 @@ function Milli_Chart(settings) {
|
|
|
2454
2873
|
var offset = 0;
|
|
2455
2874
|
var maxy = 0;
|
|
2456
2875
|
var ret = [];
|
|
2876
|
+
let num = 0;
|
|
2457
2877
|
for (var i = 0; i < len; i++) {
|
|
2458
2878
|
var currentDate;
|
|
2459
2879
|
var tmpx = startpoint.x;
|
|
2460
2880
|
var tmp;
|
|
2461
|
-
|
|
2881
|
+
var timestamp = data[i].timestamp;
|
|
2882
|
+
if (chartType == 'history') timestamp -= (timestamp % 86400000)
|
|
2883
|
+
if (timestamp < _this.scaleinfoX.startTimeStamp) {
|
|
2462
2884
|
continue;
|
|
2463
2885
|
}
|
|
2464
|
-
if (
|
|
2886
|
+
if (timestamp > _this.scaleinfoX.endTimeStamp) {
|
|
2887
|
+
console.log('to big', data[i].timestamp, _this.scaleinfoX.endTimeStamp);
|
|
2465
2888
|
break;
|
|
2466
2889
|
}
|
|
2467
2890
|
|
|
2468
|
-
if (
|
|
2891
|
+
if (chartType != 'history' && (data[i].timestamp % 86400000 < _this.instruments[0].opentimestamp || data[i].timestamp % 86400000 > _this.instruments[0].closetimestamp)) {
|
|
2469
2892
|
continue;
|
|
2470
2893
|
}
|
|
2471
|
-
var endtimeToday = new Date(
|
|
2894
|
+
var endtimeToday = new Date(timestamp);
|
|
2472
2895
|
if (endtimeToday.getDay() == 0 || endtimeToday.getDay() == 6) continue;
|
|
2473
|
-
if (
|
|
2896
|
+
if (chartType != 'history') {
|
|
2474
2897
|
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
|
|
2475
2898
|
}
|
|
2476
|
-
if (
|
|
2899
|
+
if (timestamp > endtimeToday.getTime()) {
|
|
2477
2900
|
continue; // dataticks efter stängning ritas inte
|
|
2478
2901
|
}
|
|
2479
|
-
currentDate = new Date(
|
|
2902
|
+
currentDate = new Date(timestamp);
|
|
2480
2903
|
currentDate.setHours(lastdate.getHours());
|
|
2481
2904
|
currentDate.setMinutes(lastdate.getMinutes());
|
|
2482
2905
|
currentDate.setSeconds(lastdate.getSeconds());
|
|
2483
2906
|
if (lastdate.toISOString().substring(0, 10) != currentDate.toISOString().substring(0, 10)) { // new date
|
|
2484
2907
|
tmp = new Date(lastdate.toISOString().substring(0, 10) + 'T' + _this.instruments[0].marketclose + 'Z');
|
|
2485
|
-
var nextDate = new Date(
|
|
2908
|
+
var nextDate = new Date(timestamp);
|
|
2486
2909
|
tmp = tmp.getTime() + 86400000 - _this.scaleinfoX.milliPerDay; // increase to next days starttime
|
|
2487
2910
|
|
|
2488
2911
|
currentDate = new Date(tmp);
|
|
@@ -2495,123 +2918,251 @@ function Milli_Chart(settings) {
|
|
|
2495
2918
|
}
|
|
2496
2919
|
offset += ((86400000 - _this.scaleinfoX.milliPerDay) / _this.scaleinfoX.timePerPixel); // * dateDiffInDays(lastdate, currentDate);
|
|
2497
2920
|
lastdate = currentDate;
|
|
2498
|
-
startpoint.x = Math.round(
|
|
2499
|
-
|
|
2500
|
-
|
|
2501
|
-
|
|
2502
|
-
|
|
2503
|
-
|
|
2921
|
+
startpoint.x = Math.round(chartspace.left + ((timestamp - startDate) / _this.scaleinfoX.timePerPixel)) + 0.5 - offset;
|
|
2922
|
+
}
|
|
2923
|
+
if (typeof data[i].datapoints === 'undefined' || typeof data[i].datapoints[pricecol] === 'undefined')
|
|
2924
|
+
startpoint.y = y;
|
|
2925
|
+
else {
|
|
2926
|
+
startpoint.y = Math.round((cs.bottom - cs.top) - ((data[i].datapoints[pricecol] - sc.minValue) * sc.valuePerPixel)) + 0.5 + cs.top;
|
|
2927
|
+
startpoint.y = Math.round((cs.bottom - cs.top) - ((data[i].datapoints[pricecol] - sc.minValue) / sc.valuePerPixel)) + 0.5 + cs.top;
|
|
2504
2928
|
}
|
|
2505
|
-
startpoint.y = Math.round(m_chartspaces.chart.height - getScaledSetting(m_chartCss.marginBottom) - ((data[i].datapoints[pricecol] - _this.scaleinfoY.minValue) * _this.scaleinfoY.valuePerPixel)) + 0.5;
|
|
2506
2929
|
maxy = maxy > startpoint.y ? maxy : startpoint.y;
|
|
2507
2930
|
|
|
2508
|
-
startpoint.x = Math.round(
|
|
2931
|
+
startpoint.x = Math.round(chartspace.left + ((timestamp - _this.scaleinfoX.startDate.getTime()) / _this.scaleinfoX.timePerPixel)) + 0.5;
|
|
2509
2932
|
startpoint.x -= offset;
|
|
2933
|
+
data[i].pos = { x: startpoint.x, y: startpoint.y };
|
|
2934
|
+
num++;
|
|
2510
2935
|
|
|
2511
|
-
if (startpoint.x != endpoint.x || startpoint.y != endpoint.y) {
|
|
2512
|
-
var x = Math.round(startpoint.x);
|
|
2936
|
+
/*if (startpoint.x != endpoint.x || startpoint.y != endpoint.y) {
|
|
2513
2937
|
if (endpoint.x != 0) {
|
|
2514
2938
|
if (tmpx < startpoint.x) {
|
|
2515
|
-
|
|
2516
|
-
|
|
2939
|
+
//ret.push({ x: startpoint.x, y: startpoint.y });
|
|
2940
|
+
data[i].pos = { x: startpoint.x, y: startpoint.y };
|
|
2941
|
+
num++;
|
|
2517
2942
|
}
|
|
2518
2943
|
} else {
|
|
2519
|
-
ret.push({ x: startpoint.x, y: startpoint.y });
|
|
2944
|
+
//ret.push({ x: startpoint.x, y: startpoint.y });
|
|
2945
|
+
data[i].pos = { x: startpoint.x, y: startpoint.y };
|
|
2946
|
+
num++;
|
|
2520
2947
|
}
|
|
2521
2948
|
endpoint.x = startpoint.x;
|
|
2522
2949
|
endpoint.y = startpoint.y;
|
|
2523
|
-
}
|
|
2950
|
+
}*/
|
|
2951
|
+
endpoint.x = startpoint.x;
|
|
2952
|
+
endpoint.y = startpoint.y;
|
|
2524
2953
|
}
|
|
2525
|
-
return
|
|
2954
|
+
return num;
|
|
2526
2955
|
}
|
|
2527
2956
|
|
|
2528
|
-
function
|
|
2529
|
-
|
|
2957
|
+
function plotBars(method, scale, cs) {
|
|
2958
|
+
let data = method.timeseries;
|
|
2959
|
+
let num = calcAnalyzisLine(data, 0, undefined, cs, scale);
|
|
2960
|
+
|
|
2961
|
+
if (num == 0) return;
|
|
2962
|
+
m_ctx.save();
|
|
2530
2963
|
m_ctx.strokeStyle = method.color;
|
|
2531
|
-
|
|
2532
|
-
|
|
2533
|
-
if (
|
|
2964
|
+
let width = Math.round(cs.width / (num + 1) / 2);
|
|
2965
|
+
if (_this.settings.chartlen == '1d') width = 2; // since we have do not fill the whole chart with all datapoints
|
|
2966
|
+
if (width < 2) width = 2;
|
|
2967
|
+
else if (width > 20) width = 20;
|
|
2968
|
+
m_ctx.lineWidth = width;
|
|
2969
|
+
|
|
2970
|
+
// let s = 0;
|
|
2971
|
+
for (var i = data.length - 1; i >= 0; i--) {
|
|
2972
|
+
if (typeof data[i].pos === 'undefined') break;
|
|
2973
|
+
|
|
2974
|
+
let x = (data[i].pos.x + 0.5);
|
|
2975
|
+
m_ctx.lineWidth = width;
|
|
2976
|
+
if (x - width <= cs.left) {
|
|
2977
|
+
m_ctx.lineWidth = width / 2;
|
|
2978
|
+
x += m_ctx.lineWidth / 2;
|
|
2979
|
+
} else
|
|
2980
|
+
if (x + width >= cs.right) {
|
|
2981
|
+
m_ctx.lineWidth = width / 2;
|
|
2982
|
+
x -= m_ctx.lineWidth / 2 + 1;
|
|
2983
|
+
}
|
|
2984
|
+
|
|
2985
|
+
m_ctx.beginPath();
|
|
2986
|
+
m_ctx.moveTo(x, cs.bottom);
|
|
2987
|
+
m_ctx.lineTo(x, data[i].pos.y - 0.5);
|
|
2988
|
+
m_ctx.closePath();
|
|
2989
|
+
m_ctx.stroke();
|
|
2990
|
+
}
|
|
2991
|
+
m_ctx.restore();
|
|
2992
|
+
return;
|
|
2993
|
+
}
|
|
2994
|
+
|
|
2995
|
+
function plotIndicatorLine(method, scale, cs) {
|
|
2996
|
+
let data = method.timeseries;
|
|
2997
|
+
let num = calcAnalyzisLine(data, 0, undefined, cs, scale);
|
|
2998
|
+
if (num == 0) return;
|
|
2534
2999
|
m_ctx.save();
|
|
2535
3000
|
m_ctx.beginPath();
|
|
2536
|
-
m_ctx.closePath();
|
|
2537
|
-
m_ctx.
|
|
2538
|
-
|
|
2539
|
-
|
|
3001
|
+
m_ctx.closePath();
|
|
3002
|
+
m_ctx.lineWidth = method.lineWidth | 1;
|
|
3003
|
+
m_ctx.strokeStyle = method.color;
|
|
3004
|
+
if (typeof method.lineStyle === 'string' && method.lineStyle == 'dash') m_ctx.setLineDash([3, 3]);
|
|
3005
|
+
|
|
3006
|
+
m_ctx.moveTo(data[data.length - 1].pos.x, data[data.length - 1].pos.y);
|
|
3007
|
+
let lastPos = null;
|
|
3008
|
+
for (var i = data.length - 2; i >= 0; i--) {
|
|
3009
|
+
if (typeof data[i].pos === 'undefined') break;
|
|
3010
|
+
m_ctx.lineTo(data[i].pos.x, data[i].pos.y);
|
|
3011
|
+
lastPos = data[i].pos;
|
|
3012
|
+
}
|
|
3013
|
+
if (method.method == 'FutureEvent' || method.method == 'FutureEvent2') { // just monthly for now // redo?
|
|
3014
|
+
var pos = m_dataPoints.map.get(m_dataPoints.arr[m_dataPoints.arr.length - 1]);
|
|
3015
|
+
m_ctx.lineTo(pos.instruments[0].x, pos.instruments[0].y);
|
|
2540
3016
|
}
|
|
3017
|
+
if (typeof method.callback === 'function') method.callback.call({ x: data[data.length - 1].pos.x, y: data[data.length - 1].pos.y });
|
|
2541
3018
|
m_ctx.stroke();
|
|
3019
|
+
m_ctx.lineTo(data[data.length - 1].pos.x, cs.bottom);
|
|
3020
|
+
m_ctx.restore();
|
|
3021
|
+
}
|
|
3022
|
+
|
|
3023
|
+
function plotIndicator(method, scale) {
|
|
3024
|
+
var data = method.timeseries;
|
|
3025
|
+
var width;
|
|
3026
|
+
method.timeseries.forEach(o => delete o.pos);
|
|
3027
|
+
let num = calcAnalyzisLine(data, 0, m_chartspaces.chart.top + 1, m_chartspaces.chart, scale); // + parseInt(method.fontSize));
|
|
3028
|
+
m_ctx.save();
|
|
3029
|
+
m_ctx.font = method.fontWeight + ' ' + method.fontSize + ' ' + method.fontFamily;
|
|
3030
|
+
m_ctx.fillStyle = method.color;
|
|
3031
|
+
m_ctx.fontStyle = method.fontStyle;
|
|
3032
|
+
let lastPos = { x: 0, y: 0 };
|
|
3033
|
+
let headlines = [];
|
|
3034
|
+
let hlPos = data.length - 1;
|
|
3035
|
+
for (var i = data.length - 1; i >= 0; i--) {
|
|
3036
|
+
//if (typeof data[i].pos === 'undefined') break;
|
|
3037
|
+
if (typeof data[i].pos === 'undefined') continue;
|
|
3038
|
+
if (data[i].image) {
|
|
3039
|
+
m_ctx.drawImage(data[i].image.source, data[i].pos.x - (data[i].image.width / 2), data[i].pos.y - (data[i].image.height / 2), data[i].image.width, data[i].image.height);
|
|
3040
|
+
} else if (data[i].indicator) {
|
|
3041
|
+
m_ctx.fillStyle = data[i].color;
|
|
3042
|
+
width = m_ctx.measureText(data[i].indicator).width;
|
|
3043
|
+
m_ctx.fillText(data[i].indicator, data[i].pos.x - (width / 2), data[i].pos.y);
|
|
3044
|
+
} else if (method.image) {
|
|
3045
|
+
width = method.image.width;
|
|
3046
|
+
if (method.type == NEWSINDICATOR) {
|
|
3047
|
+
if (fabs(lastPos.x - data[i].pos.x) > width || fabs(lastPos.y > data[i].pos.y) > width) {
|
|
3048
|
+
m_ctx.drawImage(method.image.source, data[i].pos.x - (width / 2), data[i].pos.y - (method.image.height / 2), method.image.width, method.image.height);
|
|
3049
|
+
lastPos = { x: data[i].pos.x, y: data[i].y };
|
|
3050
|
+
method.timeseries[i].hl = [{ timestamp: data[i].timestamp, headline: data[i].headline }];
|
|
3051
|
+
hlPos = i;
|
|
3052
|
+
} else {
|
|
3053
|
+
method.timeseries[hlPos].hl.push({ timestamp: data[i].timestamp, headline: data[i].headline });
|
|
3054
|
+
}
|
|
3055
|
+
} else {
|
|
3056
|
+
m_ctx.drawImage(method.image.source, data[i].pos.x - (width / 2), data[i].pos.y - (method.image.height / 2), method.image.width, method.image.height);
|
|
3057
|
+
}
|
|
3058
|
+
} else if (method.indicator) {
|
|
3059
|
+
m_ctx.fillStyle = method.color;
|
|
3060
|
+
width = m_ctx.measureText(method.indicator).width;
|
|
3061
|
+
if (method.type == NEWSINDICATOR) {
|
|
3062
|
+
if (fabs(lastPos.x - data[i].pos.x) > width || fabs(lastPos.y > data[i].pos.y) > width) {
|
|
3063
|
+
m_ctx.fillText(method.indicator, data[i].pos.x - (width / 2), data[i].pos.y);
|
|
3064
|
+
lastPos = { x: data[i].pos.x, y: data[i].y };
|
|
3065
|
+
method.timeseries[i].hl = [{ timestamp: data[i].timestamp, headline: data[i].headline }];
|
|
3066
|
+
hlPos = i;
|
|
3067
|
+
|
|
3068
|
+
} else {
|
|
3069
|
+
method.timeseries[hlPos].hl.push({ timestamp: data[i].timestamp, headline: data[i].headline });
|
|
3070
|
+
}
|
|
3071
|
+
} else m_ctx.fillText(method.indicator, data[i].pos.x - (width / 2), data[i].pos.y);
|
|
3072
|
+
|
|
3073
|
+
}
|
|
3074
|
+
}
|
|
2542
3075
|
m_ctx.restore();
|
|
2543
3076
|
}
|
|
2544
3077
|
|
|
2545
3078
|
function plotBollingerBand(method, type) {
|
|
2546
|
-
|
|
2547
|
-
var upper = calcAnalyzisLine(data, 0, null);
|
|
2548
|
-
var lower = calcAnalyzisLine(data, 1, null);
|
|
2549
|
-
if (upper.length == 0 || lower.length == 0) return;
|
|
3079
|
+
let data = method.timeseries;
|
|
2550
3080
|
m_ctx.strokeStyle = method.color;
|
|
2551
3081
|
m_ctx.lineWidth = method.lineWidth | 1;
|
|
2552
3082
|
m_ctx.save();
|
|
2553
3083
|
m_ctx.beginPath();
|
|
2554
|
-
|
|
2555
|
-
|
|
2556
|
-
|
|
2557
|
-
|
|
2558
|
-
|
|
2559
|
-
|
|
3084
|
+
let num = calcAnalyzisLine(data, 0, undefined, m_chartspaces.chart, scaleinfoY);
|
|
3085
|
+
for (let i = data.length - 1; i >= data.length - num; i--) {
|
|
3086
|
+
m_ctx.lineTo(data[i].pos.x, data[i].pos.y);
|
|
3087
|
+
}
|
|
3088
|
+
num = calcAnalyzisLine(data, 1, undefined, m_chartspaces.chart, scaleinfoY);
|
|
3089
|
+
m_ctx.lineTo(data[data.length - num].pos.x, data[data.length - num].pos.y);
|
|
3090
|
+
for (let i = data.length - num; i < data.length; i++) {
|
|
3091
|
+
m_ctx.lineTo(data[i].pos.x, data[i].pos.y);
|
|
3092
|
+
}
|
|
2560
3093
|
m_ctx.closePath();
|
|
2561
3094
|
if (method.fill) {
|
|
2562
3095
|
m_ctx.fillStyle = method.fill;
|
|
2563
3096
|
m_ctx.fill();
|
|
2564
3097
|
}
|
|
2565
|
-
|
|
3098
|
+
num = calcAnalyzisLine(data, 2, undefined, m_chartspaces.chart, scaleinfoY);
|
|
2566
3099
|
m_ctx.beginPath();
|
|
2567
3100
|
m_ctx.closePath(); // clear path
|
|
2568
|
-
m_ctx.moveTo(
|
|
2569
|
-
for (i =
|
|
3101
|
+
m_ctx.moveTo(data[data.length - num].x, data[data.length - num].y);
|
|
3102
|
+
for (let i = data.length - num; i < data.length; i++) {
|
|
3103
|
+
m_ctx.lineTo(data[i].pos.x, data[i].pos.y);
|
|
3104
|
+
}
|
|
2570
3105
|
m_ctx.stroke();
|
|
2571
3106
|
m_ctx.restore();
|
|
2572
3107
|
return;
|
|
2573
3108
|
}
|
|
3109
|
+
function drawCandlestick(data,factor,scaleinfoY,x) {
|
|
3110
|
+
let offset = 3;
|
|
3111
|
+
let y = Math.round(m_chartspaces.chart.height - m_chartspaces.chart.marginBottom - (((data.openprice * factor) - scaleinfoY.minValue) / scaleinfoY.valuePerPixel)) + 0.5;
|
|
3112
|
+
m_ctx.moveTo(x-offset, y);
|
|
3113
|
+
m_ctx.lineTo(x+offset , y);
|
|
3114
|
+
let oldy = y;
|
|
3115
|
+
y = Math.round(m_chartspaces.chart.height - m_chartspaces.chart.marginBottom - (((data.price * factor) - scaleinfoY.minValue) / scaleinfoY.valuePerPixel)) + 0.5;
|
|
3116
|
+
m_ctx.lineTo(x+offset , y);
|
|
3117
|
+
m_ctx.lineTo(x-offset , y);
|
|
3118
|
+
m_ctx.lineTo(x-offset,oldy);
|
|
3119
|
+
return;
|
|
3120
|
+
|
|
3121
|
+
|
|
3122
|
+
|
|
3123
|
+
y = Math.round(m_chartspaces.chart.height - m_chartspaces.chart.marginBottom - (((data.highprice * factor) - scaleinfoY.minValue) / scaleinfoY.valuePerPixel)) + 0.5;
|
|
3124
|
+
m_ctx.moveTo(x, y);
|
|
3125
|
+
y = Math.round(m_chartspaces.chart.height - m_chartspaces.chart.marginBottom - (((data.lowprice * factor) - scaleinfoY.minValue) / scaleinfoY.valuePerPixel)) + 0.5;
|
|
3126
|
+
m_ctx.lineTo(x, y);
|
|
3127
|
+
y = Math.round(m_chartspaces.chart.height - m_chartspaces.chart.marginBottom - (((data.price * factor) - scaleinfoY.minValue) / scaleinfoY.valuePerPixel)) + 0.5;
|
|
3128
|
+
m_ctx.moveTo(x, y);
|
|
3129
|
+
m_ctx.lineTo(x + offset, y);
|
|
3130
|
+
|
|
2574
3131
|
|
|
2575
|
-
function plotLower(valuePerPixel, lineLength) {
|
|
2576
|
-
m_ctx.save();
|
|
2577
|
-
m_ctx.strokeStyle = m_instrumentCss[0].color;
|
|
2578
|
-
m_ctx.lineWidth = m_instrumentCss[0].width;
|
|
2579
|
-
var width = Math.round(m_chartspaces.lowerChart.width / (m_datapoints.length + 1) / 2);
|
|
2580
|
-
if (width < 2) width = 2;
|
|
2581
|
-
else if (width > 20) width = 20;
|
|
2582
|
-
m_ctx.lineWidth = width;
|
|
2583
|
-
for (var i = 0; i < m_datapoints.length; i++) {
|
|
2584
|
-
var x = (m_datapoints[i].x + 0.5) * window.devicePixelRatio;
|
|
2585
|
-
m_ctx.lineWidth = width;
|
|
2586
|
-
if (x - width <= m_chartspaces.lowerChart.left) {
|
|
2587
|
-
m_ctx.lineWidth = width / 2;
|
|
2588
|
-
x += m_ctx.lineWidth / 2;
|
|
2589
|
-
} else
|
|
2590
|
-
if (x + width >= m_chartspaces.lowerChart.right) {
|
|
2591
|
-
m_ctx.lineWidth = width / 2;
|
|
2592
|
-
x -= m_ctx.lineWidth / 2 + 1;
|
|
2593
|
-
}
|
|
2594
|
-
m_ctx.beginPath();
|
|
2595
|
-
m_ctx.moveTo(x, m_chartspaces.lowerChart.bottom - 0.5);
|
|
2596
|
-
var y = Math.round(m_chartspaces.lowerChart.bottom - (m_datapoints[i].quantity * valuePerPixel)) - 1;
|
|
2597
|
-
m_ctx.closePath();
|
|
2598
|
-
m_ctx.lineTo(x, y - 0.5);
|
|
2599
|
-
m_ctx.stroke();
|
|
2600
|
-
}
|
|
2601
|
-
m_ctx.restore();
|
|
2602
3132
|
}
|
|
2603
3133
|
|
|
2604
|
-
function
|
|
3134
|
+
function drawOHLC(data,factor,scaleinfoY,x) {
|
|
3135
|
+
let offset = 3;
|
|
3136
|
+
let y = Math.round(m_chartspaces.chart.height - m_chartspaces.chart.marginBottom - (((data.openprice * factor) - scaleinfoY.minValue) / scaleinfoY.valuePerPixel)) + 0.5;
|
|
3137
|
+
m_ctx.moveTo(x-offset, y);
|
|
3138
|
+
m_ctx.lineTo(x , y);
|
|
3139
|
+
y = Math.round(m_chartspaces.chart.height - m_chartspaces.chart.marginBottom - (((data.highprice * factor) - scaleinfoY.minValue) / scaleinfoY.valuePerPixel)) + 0.5;
|
|
3140
|
+
m_ctx.moveTo(x, y);
|
|
3141
|
+
y = Math.round(m_chartspaces.chart.height - m_chartspaces.chart.marginBottom - (((data.lowprice * factor) - scaleinfoY.minValue) / scaleinfoY.valuePerPixel)) + 0.5;
|
|
3142
|
+
m_ctx.lineTo(x, y);
|
|
3143
|
+
y = Math.round(m_chartspaces.chart.height - m_chartspaces.chart.marginBottom - (((data.price * factor) - scaleinfoY.minValue) / scaleinfoY.valuePerPixel)) + 0.5;
|
|
3144
|
+
m_ctx.moveTo(x, y);
|
|
3145
|
+
m_ctx.lineTo(x + offset, y);
|
|
3146
|
+
|
|
3147
|
+
}
|
|
3148
|
+
function plotData(data, instrument, scaleinfoY) {
|
|
2605
3149
|
m_ctx.save();
|
|
2606
3150
|
if (_this.settings.curveOnTop == false)
|
|
2607
3151
|
m_ctx.globalCompositeOperation = 'destination-over'; // dont draw over labels inside the chart
|
|
2608
|
-
|
|
3152
|
+
let diff = _this.instruments[0].endValue - _this.instruments[0].startValue;
|
|
3153
|
+
|
|
3154
|
+
if(instrument == 0 && typeof m_instrumentCss[instrument].positiveColor !== 'undefined' && typeof m_instrumentCss[instrument].negativeColor !== 'undefined' ) {
|
|
3155
|
+
if(diff < 0) m_ctx.strokeStyle = m_instrumentCss[instrument].negativeColor;
|
|
3156
|
+
else if(diff > 0) m_ctx.strokeStyle = m_instrumentCss[instrument].positiveColor;
|
|
3157
|
+
else m_ctx.strokeStyle = m_instrumentCss[instrument].color;
|
|
3158
|
+
} else
|
|
3159
|
+
m_ctx.strokeStyle = m_instrumentCss[instrument].color;
|
|
2609
3160
|
var factor = _this.instruments[instrument].factor;
|
|
2610
3161
|
var startpoint = { x: 0, y: 0 };
|
|
2611
3162
|
var endpoint = { x: 0, y: 0 };
|
|
2612
3163
|
var startDate = _this.scaleinfoX.startTimeStamp;
|
|
2613
3164
|
var len = data.length;
|
|
2614
|
-
m_ctx.lineWidth = m_instrumentCss[instrument].width /
|
|
3165
|
+
m_ctx.lineWidth = m_instrumentCss[instrument].width / 1;
|
|
2615
3166
|
m_ctx.beginPath();
|
|
2616
3167
|
var startx = 0;
|
|
2617
3168
|
var starty = 0;
|
|
@@ -2622,9 +3173,10 @@ function Milli_Chart(settings) {
|
|
|
2622
3173
|
var hCurveLastPoint = null;
|
|
2623
3174
|
var quantity = 0;
|
|
2624
3175
|
var nextDate;
|
|
3176
|
+
var firstDataPoint = null;
|
|
3177
|
+
var lastDataPoint = null;
|
|
2625
3178
|
for (var i = 0; i < len; i++) {
|
|
2626
3179
|
var currentDate = new Date(data[i].timestamp);
|
|
2627
|
-
// var lastItem = data[i];
|
|
2628
3180
|
var tmpx = startpoint.x;
|
|
2629
3181
|
var tmp;
|
|
2630
3182
|
if (data[i].timestamp < _this.scaleinfoX.startTimeStamp) {
|
|
@@ -2637,44 +3189,42 @@ function Milli_Chart(settings) {
|
|
|
2637
3189
|
if (data[i].timestamp > new Date().getTime())
|
|
2638
3190
|
break;
|
|
2639
3191
|
|
|
2640
|
-
if (
|
|
3192
|
+
if (chartType != 'history' && (data[i].timestamp % 86400000 < _this.instruments[0].opentimestamp || data[i].timestamp % 86400000 > _this.instruments[0].closetimestamp)) {
|
|
2641
3193
|
// stämmer detta kan det bli överlapp vid sommartid/vintertid?
|
|
2642
3194
|
continue;
|
|
2643
3195
|
}
|
|
2644
3196
|
var endtimeToday = new Date(data[i].timestamp);
|
|
2645
3197
|
if (endtimeToday.getDay() == 0 || endtimeToday.getDay() == 6) continue; // do not draw weekends TODO: if main instrument has weekenddata draw it, but need to fix that in all drawfunctions
|
|
2646
|
-
if (
|
|
3198
|
+
if (chartType != 'history') {
|
|
2647
3199
|
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
|
|
2648
3200
|
}
|
|
2649
3201
|
if (data[i].timestamp > endtimeToday.getTime()) {
|
|
2650
3202
|
continue; // dataticks efter stängning ritas inte
|
|
2651
3203
|
}
|
|
2652
3204
|
|
|
2653
|
-
if (_this.
|
|
2654
|
-
//var point = { price: data[i].price, open: null, x: endpoint.x - 0.5, y: endpoint.y - 0.5, timestamp: data[i].timestamp };
|
|
2655
|
-
//m_datapoints.push(point);
|
|
2656
|
-
} else
|
|
2657
|
-
if (_this.settings.previousDayClose && addedcloseprice1d == false && m_zoom.mouseup.timestamp == null) { // only draw closeprice1d on today charts
|
|
3205
|
+
if (chartType != 'history' && _this.settings.previousDayClose && addedcloseprice1d == false && m_zoom.mouseup.timestamp == null && instrument == 0) { // only draw closeprice1d on today charts
|
|
2658
3206
|
currentDate = new Date(startDate);
|
|
2659
3207
|
if (_this.settings.chartlen == '1d' || _this.settings.chartlen == '0d') { // plot the closeprice1d
|
|
2660
|
-
endpoint.y = Math.round(m_chartspaces.chart.height -
|
|
3208
|
+
endpoint.y = Math.round(m_chartspaces.chart.height - m_chartspaces.chart.marginBottom - (((parseFloat(_this.instruments[instrument].closeprice1d * _this.instruments[instrument].factor)) - scaleinfoY.minValue) / scaleinfoY.valuePerPixel)) + 0.5;
|
|
2661
3209
|
endpoint.x = m_chartspaces.chart.left + 0.5 - offset;
|
|
2662
3210
|
} else {
|
|
2663
|
-
if (!isToday(new Date(data[i].timestamp))) {
|
|
2664
|
-
|
|
2665
|
-
|
|
2666
|
-
|
|
2667
|
-
|
|
2668
|
-
|
|
2669
|
-
|
|
2670
|
-
|
|
2671
|
-
}
|
|
2672
|
-
tmp = new Date(currentDate.toISOString().substring(0, 10) + 'T' + _this.instruments[0].marketopen + 'Z');
|
|
2673
|
-
endpoint.y = Math.round(m_chartspaces.chart.height - getScaledSetting(m_chartCss.marginBottom) - (((parseFloat(_this.instruments[instrument].startValue)) - _this.scaleinfoY.minValue) * _this.scaleinfoY.valuePerPixel)) + 0.5;
|
|
2674
|
-
endpoint.x = Math.round(m_chartspaces.chart.left + ((tmp.getTime() - startDate) / _this.scaleinfoX.timePerPixel)) + 0.5 - offset;
|
|
3211
|
+
//if (!isToday(new Date(data[i].timestamp))) { // remove, seems to mess with 2day charts if closed on friday
|
|
3212
|
+
nextDate = new Date(data[i].timestamp);
|
|
3213
|
+
while (dateDiffInDays(currentDate, nextDate) > 0) {
|
|
3214
|
+
if (currentDate.getDay() == 0 || currentDate.getDay() == 6)
|
|
3215
|
+
offset += 86400000 / _this.scaleinfoX.timePerPixel;
|
|
3216
|
+
else
|
|
3217
|
+
offset += ((86400000 - _this.scaleinfoX.milliPerDay) / _this.scaleinfoX.timePerPixel);
|
|
3218
|
+
currentDate = new Date(currentDate.getTime() + 86400000);
|
|
2675
3219
|
}
|
|
3220
|
+
tmp = new Date(currentDate.toISOString().substring(0, 10) + 'T' + _this.instruments[0].marketopen + 'Z');
|
|
3221
|
+
endpoint.y = Math.round(m_chartspaces.chart.height - m_chartspaces.chart.marginBottom - (((parseFloat(_this.instruments[instrument].startValue * _this.instruments[instrument].factor)) - scaleinfoY.minValue) / scaleinfoY.valuePerPixel)) + 0.5;
|
|
3222
|
+
endpoint.x = Math.round(m_chartspaces.chart.left + ((tmp.getTime() - startDate) / _this.scaleinfoX.timePerPixel)) + 0.5 - offset;
|
|
3223
|
+
//}
|
|
2676
3224
|
}
|
|
2677
|
-
|
|
3225
|
+
if(_this.settings.type == 'ohlc') drawOHLC(data[i],factor,scaleinfoY,endpoint.x);
|
|
3226
|
+
else if(_this.settings.type == 'candlestick') drawCandlestick(data[i],factor,scaleinfoY,endpoint.x);
|
|
3227
|
+
else m_ctx.moveTo(endpoint.x, endpoint.y);
|
|
2678
3228
|
lastdate = new Date(data[i].timestamp);
|
|
2679
3229
|
addedcloseprice1d = true;
|
|
2680
3230
|
startx = endpoint.x;
|
|
@@ -2702,39 +3252,59 @@ function Milli_Chart(settings) {
|
|
|
2702
3252
|
startpoint.x = Math.round(m_chartspaces.chart.left + ((data[i].timestamp - startDate) / _this.scaleinfoX.timePerPixel)) + 0.5 - offset;
|
|
2703
3253
|
|
|
2704
3254
|
// TODO: här blir det fel när det är från 00:00: 23:59 men göms av tmpx < startpoint.x
|
|
2705
|
-
if (
|
|
3255
|
+
if (chartType == 'trades' && tmpx < startpoint.x) {
|
|
2706
3256
|
m_ctx.lineTo(startpoint.x, startpoint.y);
|
|
2707
3257
|
}
|
|
2708
3258
|
}
|
|
2709
|
-
startpoint.y = Math.round(m_chartspaces.chart.height -
|
|
3259
|
+
startpoint.y = Math.round(m_chartspaces.chart.height - m_chartspaces.chart.marginBottom - (((data[i].price * factor) - scaleinfoY.minValue) / scaleinfoY.valuePerPixel)) + 0.5;
|
|
3260
|
+
|
|
2710
3261
|
maxy = maxy > startpoint.y ? maxy : startpoint.y;
|
|
2711
3262
|
|
|
2712
3263
|
startpoint.x = Math.round(m_chartspaces.chart.left + ((data[i].timestamp - _this.scaleinfoX.startDate.getTime()) / _this.scaleinfoX.timePerPixel)) + 0.5;
|
|
2713
3264
|
|
|
2714
3265
|
startpoint.x -= offset;
|
|
2715
3266
|
quantity += data[i].quantity;
|
|
3267
|
+
|
|
3268
|
+
// test
|
|
3269
|
+
var x = Math.floor(startpoint.x);
|
|
3270
|
+
if (!m_dataPoints.arr.includes(x)) {
|
|
3271
|
+
m_dataPoints.arr.push(x);
|
|
3272
|
+
}
|
|
3273
|
+
var obj = m_dataPoints.map.get(x);
|
|
3274
|
+
if (obj == null) {
|
|
3275
|
+
obj = {};
|
|
3276
|
+
obj.timestamp = data[i].timestamp;
|
|
3277
|
+
obj.instruments = [];
|
|
3278
|
+
m_dataPoints.map.set(x, obj);
|
|
3279
|
+
}
|
|
3280
|
+
obj.instruments[instrument] = { price: data[i].price, open: data[i].openprice, x: startpoint.x / 1 - 0.5, y: startpoint.y / 1 - 0.5, timestamp: data[i].timestamp, date: new Date(data[i].timestamp), insref: _this.instruments[instrument].insref, diff: data[i].diff, quantity: quantity };
|
|
3281
|
+
|
|
2716
3282
|
if (startpoint.x != endpoint.x || startpoint.y != endpoint.y) {
|
|
2717
|
-
var x = Math.round(startpoint.x);
|
|
3283
|
+
/*var x = Math.round (startpoint.x);
|
|
2718
3284
|
if (!m_dataPoints.arr.includes(x)) {
|
|
2719
3285
|
m_dataPoints.arr.push(x);
|
|
2720
|
-
}
|
|
2721
|
-
var obj = m_dataPoints.map.get(x);
|
|
3286
|
+
}*/
|
|
3287
|
+
/*var obj = m_dataPoints.map.get(x);
|
|
2722
3288
|
if (obj == null) {
|
|
2723
3289
|
obj = {};
|
|
2724
3290
|
obj.timestamp = data[i].timestamp;
|
|
2725
3291
|
obj.instruments = [];
|
|
2726
3292
|
m_dataPoints.map.set(x, obj);
|
|
2727
3293
|
}
|
|
2728
|
-
obj.instruments[instrument] = { price: data[i].price, open: data[i].openprice, x: startpoint.x /
|
|
3294
|
+
obj.instruments[instrument] = { price: data[i].price, open: data[i].openprice, x: startpoint.x / 1 - 0.5, y: startpoint.y / 1 - 0.5, timestamp: data[i].timestamp, date: new Date(data[i].timestamp), insref: _this.instruments[instrument].insref, diff: data[i].diff, quantity: quantity };*/
|
|
2729
3295
|
var point;
|
|
2730
3296
|
if (endpoint.x != 0) {
|
|
2731
3297
|
if (tmpx < startpoint.x) {
|
|
2732
|
-
if
|
|
2733
|
-
|
|
3298
|
+
if(_this.settings.type == 'ohlc') drawOHLC(data[i],factor,scaleinfoY,startpoint.x);
|
|
3299
|
+
else if(_this.settings.type == 'candlestick') drawCandlestick(data[i],factor,scaleinfoY,startpoint.x);
|
|
3300
|
+
else {
|
|
3301
|
+
if (_this.settings.hcurve) m_ctx.lineTo(startpoint.x, endpoint.y);
|
|
3302
|
+
m_ctx.lineTo(startpoint.x, startpoint.y);
|
|
3303
|
+
}
|
|
2734
3304
|
//m_ctx.bezierCurveTo(startpoint.x, startpoint.y, endpoint.x - 1, endpoint.y - 1, endpoint.x, endpoint.y); // läs på om detta för "runda linjer"
|
|
2735
3305
|
|
|
2736
3306
|
if (instrument == 0) {
|
|
2737
|
-
point = { price: data[i].price, open: data[i].openprice, x: startpoint.x /
|
|
3307
|
+
point = { price: data[i].price, open: data[i].openprice, x: startpoint.x / 1 - 0.5, y: startpoint.y / 1 - 0.5, timestamp: data[i].timestamp, date: new Date(data[i].timestamp), quantity: quantity };
|
|
2738
3308
|
if (typeof data[i].dividend !== 'undefined') point.dividend = data[i].dividend;
|
|
2739
3309
|
if (typeof data[i].diff !== 'undefined') point.diff = data[i].diff;
|
|
2740
3310
|
point.quantity = quantity;
|
|
@@ -2744,55 +3314,78 @@ function Milli_Chart(settings) {
|
|
|
2744
3314
|
}
|
|
2745
3315
|
} else {
|
|
2746
3316
|
if (instrument == 0) {
|
|
2747
|
-
point = { price: data[i].price, open: data[i].openprice, x: startpoint.x /
|
|
3317
|
+
point = { price: data[i].price, open: data[i].openprice, x: startpoint.x / 1 - 0.5, y: startpoint.y / 1 - 0.5, timestamp: data[i].timestamp, date: new Date(data[i].timestamp), insref: _this.instruments[instrument].insref, diff: data[i].diff, quantity: quantity };
|
|
2748
3318
|
m_datapoints.push(point);
|
|
2749
|
-
if (_this.settings.hcurve &&
|
|
3319
|
+
if (_this.settings.hcurve && chartType == 'history') {
|
|
2750
3320
|
if (isToday(currentDate)) {
|
|
2751
3321
|
// only 1 point in hcurve chart, draw line from start of chart to end date
|
|
2752
3322
|
m_ctx.moveTo(m_chartspaces.chart.left, startpoint.y);
|
|
2753
|
-
point = { price: data[i].price, open: data[i].openprice, x: m_chartspaces.chart.left /
|
|
3323
|
+
point = { price: data[i].price, open: data[i].openprice, x: m_chartspaces.chart.left / 1 - 0.5, y: startpoint.y / 1 - 0.5, timestamp: data[i].timestamp, date: new Date(data[i].timestamp), insref: _this.instruments[instrument].insref, diff: data[i].diff, quantity: quantity };
|
|
2754
3324
|
m_datapoints.push(point);
|
|
2755
|
-
point = { price: data[i].price, open: data[i].openprice, x: startpoint.x /
|
|
3325
|
+
point = { price: data[i].price, open: data[i].openprice, x: startpoint.x / 1 - 0.5, y: startpoint.y / 1 - 0.5, timestamp: data[i].timestamp, date: new Date(data[i].timestamp), insref: _this.instruments[instrument].insref, diff: data[i].diff, quantity: quantity };
|
|
2756
3326
|
m_datapoints.push(point);
|
|
2757
3327
|
startx = m_chartspaces.chart.left;
|
|
2758
3328
|
starty = startpoint.y;
|
|
2759
3329
|
// last point so break out and store startx and starty from fake point
|
|
2760
3330
|
break;
|
|
2761
3331
|
} else if (hCurveLastPoint) {
|
|
2762
|
-
/* var y = Math.round(m_canvas.
|
|
3332
|
+
/* var y = Math.round(m_canvas.getHeight() - m_chartspaces.chart.marginBottom - (((hCurveLastPoint.price * factor) - scaleinfoY.minValue) * scaleinfoY.valuePerPixel)) + 0.5;
|
|
2763
3333
|
m_ctx.moveTo(m_chartspaces.chart.left, y);
|
|
2764
3334
|
m_ctx.lineTo(startpoint.x, y);*/
|
|
2765
3335
|
}
|
|
2766
3336
|
}
|
|
2767
3337
|
quantity = 0;
|
|
2768
3338
|
}
|
|
2769
|
-
|
|
3339
|
+
if(_this.settings.type == 'ohlc') drawOHLC(data[i],factor,scaleinfoY,startpoint.x);
|
|
3340
|
+
else if(_this.settings.type == 'candlestick') drawCandlestick(data[i],factor,scaleinfoY,startpoint.x);
|
|
3341
|
+
else m_ctx.moveTo(startpoint.x, startpoint.y);
|
|
2770
3342
|
startx = startpoint.x;
|
|
2771
3343
|
starty = startpoint.y;
|
|
2772
3344
|
}
|
|
2773
3345
|
endpoint.x = startpoint.x;
|
|
2774
3346
|
endpoint.y = startpoint.y;
|
|
2775
3347
|
}
|
|
2776
|
-
if (data[i].dividend) {
|
|
2777
|
-
//console.log('div', data[i]);
|
|
2778
|
-
}
|
|
3348
|
+
if (data[i].dividend) {}
|
|
2779
3349
|
}
|
|
2780
3350
|
m_dataPoints.arr.sort(function(a, b) {
|
|
2781
3351
|
return a - b;
|
|
2782
3352
|
});
|
|
2783
3353
|
m_ctx.stroke();
|
|
2784
|
-
if (_this.settings.fillchart == true && instrument == 0)
|
|
2785
|
-
m_ctx.lineTo(startpoint.x, m_chartspaces.chart.height -
|
|
2786
|
-
m_ctx.lineTo(startx, m_chartspaces.chart.height -
|
|
3354
|
+
if (_this.settings.fillchart == true && instrument == 0 && _this.settings.ohlc != true) {
|
|
3355
|
+
m_ctx.lineTo(startpoint.x, m_chartspaces.chart.height - m_chartspaces.chart.marginBottom + 0.5);
|
|
3356
|
+
m_ctx.lineTo(startx, m_chartspaces.chart.height - m_chartspaces.chart.marginBottom + 0.5);
|
|
2787
3357
|
m_ctx.lineTo(startx, starty);
|
|
2788
3358
|
m_ctx.closePath();
|
|
2789
3359
|
if (typeof m_instrumentCss[0].backgroundLinearGradient !== 'undefined' && typeof m_instrumentCss[0].backgroundLinearGradient.topColor !== 'undefined' && typeof m_instrumentCss[0].backgroundLinearGradient.bottomColor !== 'undefined') {
|
|
2790
|
-
|
|
2791
|
-
|
|
2792
|
-
|
|
2793
|
-
|
|
3360
|
+
if(instrument == 0 && typeof m_instrumentCss[0].positiveBackgroundLinearGradient !== 'undefined' && typeof m_instrumentCss[0].negativeBackgroundLinearGradient !== 'undefined' ) {
|
|
3361
|
+
if(diff < 0 && typeof m_instrumentCss[0].negativeBackgroundLinearGradient.topColor !== 'undefined' && typeof m_instrumentCss[0].negativeBackgroundLinearGradient.bottomColor !== 'undefined') {
|
|
3362
|
+
var grd = m_ctx.createLinearGradient(0, 0, 0, m_chartspaces.chart.height - m_chartspaces.chart.top - m_chartspaces.chart.marginBottom);
|
|
3363
|
+
grd.addColorStop(0, m_instrumentCss[0].negativeBackgroundLinearGradient.topColor);
|
|
3364
|
+
grd.addColorStop(1, m_instrumentCss[0].negativeBackgroundLinearGradient.bottomColor);
|
|
3365
|
+
m_ctx.fillStyle = grd;
|
|
3366
|
+
} else if(diff > 0) {
|
|
3367
|
+
var grd = m_ctx.createLinearGradient(0, 0, 0, m_chartspaces.chart.height - m_chartspaces.chart.top - m_chartspaces.chart.marginBottom);
|
|
3368
|
+
grd.addColorStop(0, m_instrumentCss[0].positiveBackgroundLinearGradient.topColor);
|
|
3369
|
+
grd.addColorStop(1, m_instrumentCss[0].positiveBackgroundLinearGradient.bottomColor);
|
|
3370
|
+
m_ctx.fillStyle = grd;
|
|
3371
|
+
} else {
|
|
3372
|
+
var grd = m_ctx.createLinearGradient(0, 0, 0, m_chartspaces.chart.height - m_chartspaces.chart.top - m_chartspaces.chart.marginBottom);
|
|
3373
|
+
grd.addColorStop(0, m_instrumentCss[0].backgroundLinearGradient.topColor);
|
|
3374
|
+
grd.addColorStop(1, m_instrumentCss[0].backgroundLinearGradient.bottomColor);
|
|
3375
|
+
m_ctx.fillStyle = grd;
|
|
3376
|
+
}
|
|
3377
|
+
} else {
|
|
3378
|
+
var grd = m_ctx.createLinearGradient(0, 0, 0, m_chartspaces.chart.height - m_chartspaces.chart.top - m_chartspaces.chart.marginBottom);
|
|
3379
|
+
grd.addColorStop(0, m_instrumentCss[0].backgroundLinearGradient.topColor);
|
|
3380
|
+
grd.addColorStop(1, m_instrumentCss[0].backgroundLinearGradient.bottomColor);
|
|
3381
|
+
m_ctx.fillStyle = grd;
|
|
3382
|
+
}
|
|
2794
3383
|
} else {
|
|
2795
|
-
if
|
|
3384
|
+
if(instrument == 0 && typeof m_instrumentCss[instrument].positiveBackgroundColor !== 'undefined' && typeof m_instrumentCss[instrument].negativeBackgroundColor !== 'undefined' ) {
|
|
3385
|
+
if(diff < 0) m_ctx.fillStyle = m_instrumentCss[0].negativeBackgroundColor;
|
|
3386
|
+
else if(diff > 0) m_ctx.fillStyle = m_instrumentCss[0].positiveBackgroundColor;
|
|
3387
|
+
else if (typeof m_instrumentCss[0].backgroundColor !== 'undefined') m_ctx.fillStyle = m_instrumentCss[0].backgroundColor;
|
|
3388
|
+
} else if (typeof m_instrumentCss[0].backgroundColor !== 'undefined')
|
|
2796
3389
|
m_ctx.fillStyle = m_instrumentCss[0].backgroundColor;
|
|
2797
3390
|
}
|
|
2798
3391
|
m_ctx.fill();
|
|
@@ -2807,61 +3400,161 @@ function Milli_Chart(settings) {
|
|
|
2807
3400
|
m_ctx.restore();
|
|
2808
3401
|
}
|
|
2809
3402
|
|
|
2810
|
-
/* function drawCompare(resp) {
|
|
2811
|
-
parseData(resp[0], 1);
|
|
2812
|
-
_this.drawChart();
|
|
2813
|
-
requestStreaming();
|
|
2814
|
-
return;
|
|
2815
|
-
}
|
|
2816
|
-
*/
|
|
2817
|
-
|
|
2818
3403
|
_this.setChartLength = function(len) {
|
|
2819
3404
|
_this.settings.chartlen = len;
|
|
2820
3405
|
m_zoom.mousedown.timestamp = null;
|
|
2821
3406
|
m_zoom.mouseup.timestamp = null;
|
|
2822
3407
|
};
|
|
2823
3408
|
|
|
2824
|
-
function
|
|
3409
|
+
function calculateMomentum(data, len) {
|
|
3410
|
+
// borde returnera ett object med high/low också
|
|
3411
|
+
var values = [];
|
|
3412
|
+
for (var i = len; i < data.length; i++) {
|
|
3413
|
+
if (data[i].timestamp >= _this.scaleinfoX.startTimeStamp) {
|
|
3414
|
+
values.push({ timestamp: data[i].timestamp, datapoints: [data[i].price - data[i - len].price] });
|
|
3415
|
+
}
|
|
3416
|
+
}
|
|
3417
|
+
return values;
|
|
3418
|
+
|
|
3419
|
+
}
|
|
3420
|
+
|
|
3421
|
+
function calculateQuantity(data) {
|
|
3422
|
+
// borde returnera ett object med high/low också
|
|
3423
|
+
let quantity = [];
|
|
3424
|
+
for (let i = 0; i < data.length; i++) {
|
|
3425
|
+
if (data[i].timestamp >= _this.scaleinfoX.startTimeStamp) {
|
|
3426
|
+
quantity.push({ timestamp: data[i].timestamp, datapoints: [data[i].quantity] });
|
|
3427
|
+
}
|
|
3428
|
+
}
|
|
3429
|
+
return quantity;
|
|
3430
|
+
}
|
|
3431
|
+
|
|
3432
|
+
function calculateNews(data) {
|
|
3433
|
+
if (data == null) return [];
|
|
3434
|
+
|
|
3435
|
+
let timeseries = [];
|
|
3436
|
+
for (let i = 0; i < data.length; i++) {
|
|
3437
|
+
let s = 0;
|
|
3438
|
+
if (data[i].timestamp >= _this.scaleinfoX.startTimeStamp) {
|
|
3439
|
+
let item = null;
|
|
3440
|
+
for (s; s < _this.instruments[0][chartType].length; s++) {
|
|
3441
|
+
if (chartType == 'history') {
|
|
3442
|
+
if ((data[i].timestamp - (data[i].timestamp % 86400000)) < _this.instruments[0].history[s].timestamp) break;
|
|
3443
|
+
if ((data[i].timestamp - (data[i].timestamp % 86400000)) >= _this.instruments[0].history[s].timestamp) {
|
|
3444
|
+
item = data[i];
|
|
3445
|
+
item.datapoints = [_this.instruments[0].history[s].price];
|
|
3446
|
+
}
|
|
3447
|
+
} else {
|
|
3448
|
+
if ((data[i].timestamp) < _this.instruments[0].trades[s].timestamp) break;
|
|
3449
|
+
if ((data[i].timestamp) >= _this.instruments[0].trades[s].timestamp) {
|
|
3450
|
+
item = data[i];
|
|
3451
|
+
item.datapoints = [_this.instruments[0].trades[s].price];
|
|
3452
|
+
}
|
|
3453
|
+
}
|
|
3454
|
+
}
|
|
3455
|
+
timeseries.push(item);
|
|
3456
|
+
}
|
|
3457
|
+
}
|
|
3458
|
+
return timeseries;
|
|
3459
|
+
}
|
|
3460
|
+
|
|
3461
|
+
function calculateRSI(p, window) {
|
|
3462
|
+
// borde returnera ett object med high/low också
|
|
3463
|
+
let rsi = [];
|
|
3464
|
+
let up;
|
|
3465
|
+
let up_average;
|
|
3466
|
+
let up_average_old = 0;
|
|
3467
|
+
let sum_up = 0;
|
|
3468
|
+
|
|
3469
|
+
let down;
|
|
3470
|
+
let down_average;
|
|
3471
|
+
let sum_down = 0;
|
|
3472
|
+
let down_average_old = 0;
|
|
3473
|
+
|
|
3474
|
+
for (let i = 1; i < p.length; i++) {
|
|
3475
|
+
let change = p[i].price - p[i - 1].price;
|
|
3476
|
+
if (change > 0) {
|
|
3477
|
+
up = change;
|
|
3478
|
+
down = 0;
|
|
3479
|
+
} else if (change < 0) {
|
|
3480
|
+
down = Math.abs(change);
|
|
3481
|
+
up = 0;
|
|
3482
|
+
} else {
|
|
3483
|
+
up = 0;
|
|
3484
|
+
down = 0;
|
|
3485
|
+
}
|
|
3486
|
+
if (i < window) {
|
|
3487
|
+
sum_up += up;
|
|
3488
|
+
sum_down += down
|
|
3489
|
+
} else if (i == window) {
|
|
3490
|
+
up_average = sum_up / window;
|
|
3491
|
+
down_average = sum_down / window;
|
|
3492
|
+
up_average_old = up_average;
|
|
3493
|
+
down_average_old = down_average
|
|
3494
|
+
} else {
|
|
3495
|
+
up_average = (up_average_old * (window - 1) + up) / window;
|
|
3496
|
+
down_average = (down_average_old * (window - 1) + down) / window;
|
|
3497
|
+
up_average_old = up_average;
|
|
3498
|
+
down_average_old = down_average
|
|
3499
|
+
}
|
|
3500
|
+
if (i >= window) {
|
|
3501
|
+
var rs = up_average / down_average;
|
|
3502
|
+
rsi.push({ timestamp: p[i].timestamp, datapoints: [100 - 100 / (1 + rs)] });
|
|
3503
|
+
}
|
|
3504
|
+
}
|
|
3505
|
+
return rsi;
|
|
3506
|
+
}
|
|
3507
|
+
|
|
3508
|
+
function calculateBollingerBands(prices, window, stddev) {
|
|
3509
|
+
// borde returnera ett object med high/low också
|
|
3510
|
+
|
|
2825
3511
|
if (!prices || prices.length < window) {
|
|
2826
3512
|
return [];
|
|
2827
3513
|
}
|
|
2828
|
-
|
|
2829
3514
|
let index = window - 1;
|
|
2830
3515
|
const length = prices.length + 1;
|
|
2831
3516
|
const standardDeviations = [];
|
|
3517
|
+
const today = new Date().getTime();
|
|
3518
|
+
const startDate = _this.scaleinfoX.startTimeStamp - (window * 86400000);
|
|
2832
3519
|
while (++index < length) {
|
|
2833
3520
|
const windowSlice = prices.slice(index - window, index);
|
|
2834
|
-
|
|
2835
|
-
|
|
2836
|
-
|
|
2837
|
-
|
|
2838
|
-
|
|
2839
|
-
|
|
3521
|
+
if (windowSlice[window - 1].timestamp > startDate) {
|
|
3522
|
+
const mean = windowSlice.reduce((prev, curr) => prev + curr.price, 0) / window;
|
|
3523
|
+
const variance = Math.sqrt(windowSlice.reduce((a, b) => a + (b.price - mean) ** 2, 0) / window) * stddev;
|
|
3524
|
+
const uppervariance = mean + variance;
|
|
3525
|
+
const lowervariance = mean - variance;
|
|
3526
|
+
standardDeviations.push({ timestamp: prices[index - 1].timestamp, datapoints: [uppervariance, lowervariance, mean] });
|
|
3527
|
+
}
|
|
3528
|
+
if (typeof prices[index] == 'undefined' || prices[index].timestamp > today) break;
|
|
2840
3529
|
}
|
|
2841
3530
|
return standardDeviations;
|
|
2842
3531
|
}
|
|
2843
3532
|
|
|
2844
3533
|
function simpleMovingAverage(prices, window, n = Infinity) {
|
|
3534
|
+
// borde returnera ett object med high/low också
|
|
2845
3535
|
if (!prices || prices.length < window) {
|
|
2846
3536
|
return [];
|
|
2847
3537
|
}
|
|
2848
3538
|
let index = window - 1;
|
|
2849
3539
|
const length = prices.length + 1;
|
|
2850
|
-
|
|
2851
3540
|
const simpleMovingAverages = [];
|
|
2852
|
-
|
|
2853
3541
|
let numberOfSMAsCalculated = 0;
|
|
2854
|
-
|
|
2855
|
-
|
|
3542
|
+
const today = new Date().getTime();
|
|
3543
|
+
const startDate = _this.scaleinfoX.startTimeStamp - (window * 86400000);
|
|
3544
|
+
while (++index < length && numberOfSMAsCalculated < n) {
|
|
2856
3545
|
const windowSlice = prices.slice(index - window, index);
|
|
2857
|
-
|
|
2858
|
-
|
|
2859
|
-
|
|
3546
|
+
if (windowSlice[window - 1].timestamp > startDate) {
|
|
3547
|
+
const sum = windowSlice.reduce((prev, curr) => prev + curr.price, 0);
|
|
3548
|
+
simpleMovingAverages.push({ timestamp: prices[index - 1].timestamp, datapoints: [sum / window] });
|
|
3549
|
+
numberOfSMAsCalculated++;
|
|
3550
|
+
}
|
|
3551
|
+
if (typeof prices[index] == 'undefined' || prices[index].timestamp > today) break;
|
|
2860
3552
|
}
|
|
2861
3553
|
return simpleMovingAverages;
|
|
2862
3554
|
}
|
|
2863
3555
|
|
|
2864
3556
|
function exponentialMovingAverage(prices, window) {
|
|
3557
|
+
// borde returnera ett object med high/low också
|
|
2865
3558
|
if (!prices || prices.length < window) {
|
|
2866
3559
|
return [];
|
|
2867
3560
|
}
|
|
@@ -2873,15 +3566,16 @@ function Milli_Chart(settings) {
|
|
|
2873
3566
|
|
|
2874
3567
|
const [sma] = simpleMovingAverage(prices, window, 1);
|
|
2875
3568
|
exponentialMovingAverages.push(sma);
|
|
3569
|
+
|
|
2876
3570
|
while (++index < length) {
|
|
2877
3571
|
const value = prices[index].price;
|
|
2878
3572
|
const previousEma = [exponentialMovingAverages[previousEmaIndex++].datapoints[0]];
|
|
2879
3573
|
const currentEma = (value * smoothingFactor) + (previousEma * (1 - smoothingFactor));
|
|
2880
3574
|
exponentialMovingAverages.push({ timestamp: prices[index].timestamp, datapoints: [currentEma] });
|
|
2881
|
-
if (typeof prices[index] == 'undefined' || prices[index].timestamp > new Date().getTime()) break;
|
|
2882
3575
|
}
|
|
2883
3576
|
return exponentialMovingAverages;
|
|
2884
3577
|
}
|
|
3578
|
+
|
|
2885
3579
|
_this.removeAllIndicators = function(j) {
|
|
2886
3580
|
_this.settings.indicators = [];
|
|
2887
3581
|
_this.drawChart();
|
|
@@ -2893,7 +3587,16 @@ function Milli_Chart(settings) {
|
|
|
2893
3587
|
for (var i = 0; i < _this.settings.indicators.length; i++) {
|
|
2894
3588
|
if (_this.settings.indicators[i].method == obj.method && _this.settings.indicators[i].method_length == obj.method_length) {
|
|
2895
3589
|
if (obj.method != 'bb' || obj.stddev == _this.settings.indicators[i].stddev) {
|
|
3590
|
+
if (typeof _this.settings.indicators[i].onClose === 'function') _this.settings.indicators[i].onClose.call();
|
|
2896
3591
|
_this.settings.indicators.splice(i, 1);
|
|
3592
|
+
let lower = false;
|
|
3593
|
+
for (let s = 0; s < _this.settings.indicators.length; s++) {
|
|
3594
|
+
if (_this.settings.indicators[s].method == 'rsi' || _this.settings.indicators[s].method == 'quantity') lower = true;
|
|
3595
|
+
}
|
|
3596
|
+
if (lower == false) {
|
|
3597
|
+
m_chartspaces.chart.percent = 100;
|
|
3598
|
+
m_chartspaces.lowerChart.percent = 0;
|
|
3599
|
+
}
|
|
2897
3600
|
_this.drawChart();
|
|
2898
3601
|
return true;
|
|
2899
3602
|
}
|
|
@@ -2902,39 +3605,55 @@ function Milli_Chart(settings) {
|
|
|
2902
3605
|
return false;
|
|
2903
3606
|
};
|
|
2904
3607
|
|
|
3608
|
+
function indicatorAlreadyExists(obj) {
|
|
3609
|
+
for (var i = 0; i < _this.settings.indicators.length; i++) {
|
|
3610
|
+
if (_this.settings.indicators[i].method == obj.method && obj.method == 'quantity') return true;
|
|
3611
|
+
if (_this.settings.indicators[i].method == obj.method && _this.settings.indicators[i].method_length == obj.method_length) {
|
|
3612
|
+
if (obj.method != 'bb' || obj.stddev == _this.settings.indicators[i].stddev) {
|
|
3613
|
+
return true;
|
|
3614
|
+
}
|
|
3615
|
+
}
|
|
3616
|
+
}
|
|
3617
|
+
return false;
|
|
3618
|
+
}
|
|
3619
|
+
|
|
2905
3620
|
_this.addIndicator = function(method) {
|
|
2906
|
-
if (typeof method !== 'object' || method == null || typeof method.
|
|
3621
|
+
if (typeof method !== 'object' || method == null || typeof method.method == undefined) return;
|
|
3622
|
+
if (indicatorAlreadyExists(method)) return;
|
|
2907
3623
|
switch (method.method) {
|
|
2908
3624
|
case 'sma':
|
|
2909
3625
|
{
|
|
2910
3626
|
if (typeof method.method_length !== 'number') return;
|
|
2911
|
-
method.history = simpleMovingAverage(_this.instruments[0].history, method.method_length);
|
|
2912
|
-
method.trades = simpleMovingAverage(_this.instruments[0].trades, method.method_length);
|
|
2913
3627
|
}
|
|
2914
3628
|
break;
|
|
2915
3629
|
case 'ema':
|
|
2916
3630
|
{
|
|
2917
3631
|
if (typeof method.method_length !== 'number') return;
|
|
2918
|
-
method.history = exponentialMovingAverage(_this.instruments[0].history, method.method_length);
|
|
2919
|
-
method.trades = exponentialMovingAverage(_this.instruments[0].trades, method.method_length);
|
|
2920
3632
|
break;
|
|
2921
3633
|
}
|
|
2922
3634
|
case 'bb':
|
|
2923
3635
|
{
|
|
2924
3636
|
if (typeof method.method_length !== 'number' || typeof method.stddev !== 'number') return;
|
|
2925
|
-
method.history = bollingerBands(_this.instruments[0].history, method.method_length, method.stddev);
|
|
2926
|
-
method.trades = bollingerBands(_this.instruments[0].trades, method.method_length, method.stddev);
|
|
2927
3637
|
break;
|
|
2928
3638
|
}
|
|
2929
|
-
|
|
2930
|
-
|
|
2931
|
-
|
|
2932
|
-
|
|
2933
|
-
|
|
3639
|
+
case 'rsi':
|
|
3640
|
+
case 'quantity':
|
|
3641
|
+
case 'momentum':
|
|
3642
|
+
if (method.target == 'lower') {
|
|
3643
|
+
m_chartspaces.chart.percent = 70;
|
|
3644
|
+
m_chartspaces.lowerChart.percent = 30;
|
|
2934
3645
|
}
|
|
2935
3646
|
break;
|
|
3647
|
+
case 'news':
|
|
3648
|
+
break;
|
|
3649
|
+
default:
|
|
3650
|
+
method.timeseries.sort(function(a, b) {
|
|
3651
|
+
return a.timestamp - b.timestamp;
|
|
3652
|
+
});
|
|
3653
|
+
break;
|
|
2936
3654
|
}
|
|
2937
|
-
|
|
3655
|
+
if (typeof method.type === 'undefined') method.type = INDICATOR;
|
|
3656
|
+
_this.settings.indicators.unshift(method);
|
|
2938
3657
|
_this.drawChart();
|
|
2939
3658
|
};
|
|
2940
3659
|
|
|
@@ -2959,6 +3678,7 @@ function Milli_Chart(settings) {
|
|
|
2959
3678
|
});
|
|
2960
3679
|
//fetch data and redraw ( for no push charts)
|
|
2961
3680
|
};
|
|
3681
|
+
|
|
2962
3682
|
// Compare functions
|
|
2963
3683
|
_this.removeAllCompares = function() {
|
|
2964
3684
|
if (_this.instruments.length == 1) return;
|
|
@@ -3011,6 +3731,7 @@ function Milli_Chart(settings) {
|
|
|
3011
3731
|
return 1;
|
|
3012
3732
|
};
|
|
3013
3733
|
// Size functions
|
|
3734
|
+
|
|
3014
3735
|
function setChartSize() {
|
|
3015
3736
|
var offset = 0;
|
|
3016
3737
|
// set canvas size to 0 so it does not prevent the div to resize
|
|
@@ -3021,35 +3742,35 @@ function Milli_Chart(settings) {
|
|
|
3021
3742
|
}
|
|
3022
3743
|
_this.settings.target.style.height = (_this.settings.target.parentNode.offsetHeight - offset) + 'px';
|
|
3023
3744
|
_this.settings.target.style.width = _this.settings.target.parentNode.offsetWidth + 'px';
|
|
3024
|
-
//_this.settings.target.style.height = (_this.settings.target.parentNode.offsetHeight - offset) *
|
|
3025
|
-
//_this.settings.target.style.width = _this.settings.target.parentNode.offsetWidth *
|
|
3745
|
+
//_this.settings.target.style.height = (_this.settings.target.parentNode.offsetHeight - offset) * 1 + 'px';
|
|
3746
|
+
//_this.settings.target.style.width = _this.settings.target.parentNode.offsetWidth * 1 + 'px';
|
|
3026
3747
|
m_canvas.setRect(_this.settings.target.offsetHeight, _this.settings.target.offsetWidth);
|
|
3027
3748
|
}
|
|
3028
3749
|
|
|
3029
3750
|
_this.resizeStart = function(e, ui) {
|
|
3030
|
-
m_resizing.width = m_canvas.
|
|
3031
|
-
m_resizing.height = m_canvas.
|
|
3751
|
+
m_resizing.width = m_canvas.getWidth();
|
|
3752
|
+
m_resizing.height = m_canvas.getHeight();
|
|
3032
3753
|
};
|
|
3033
3754
|
|
|
3034
3755
|
_this.resizing = function(e, ui) {
|
|
3035
|
-
var diff = (m_resizing.height - m_canvas.
|
|
3756
|
+
var diff = (m_resizing.height - m_canvas.getHeight()) / m_canvas.getHeight() * 100;
|
|
3036
3757
|
if (Math.abs(diff) > 1) {
|
|
3037
3758
|
setChartSize();
|
|
3038
|
-
m_resizing.width = m_canvas.
|
|
3039
|
-
m_resizing.height = m_canvas.
|
|
3759
|
+
m_resizing.width = m_canvas.getWidth();
|
|
3760
|
+
m_resizing.height = m_canvas.getHeight();
|
|
3040
3761
|
_this.drawChart();
|
|
3041
3762
|
} else {
|
|
3042
|
-
diff = (m_resizing.width - m_canvas.
|
|
3763
|
+
diff = (m_resizing.width - m_canvas.getWidth()) / m_canvas.getWidth() * 100;
|
|
3043
3764
|
if (Math.abs(diff) > 1) {
|
|
3044
3765
|
setChartSize();
|
|
3045
|
-
//m_canvas.
|
|
3046
|
-
//m_canvas.
|
|
3047
|
-
m_resizing.width = m_canvas.
|
|
3048
|
-
m_resizing.height = m_canvas.
|
|
3766
|
+
//m_canvas.getHeight() = Math.floor(_this.settings.target.offsetHeight * 1);
|
|
3767
|
+
//m_canvas.getWidth() = Math.floor(_this.settings.target.offsetWidth * 1);
|
|
3768
|
+
m_resizing.width = m_canvas.getWidth();
|
|
3769
|
+
m_resizing.height = m_canvas.getHeight();
|
|
3049
3770
|
_this.drawChart();
|
|
3050
3771
|
}
|
|
3051
3772
|
}
|
|
3052
|
-
var cache = m_ctx.getImageData(0, 0, m_canvas.
|
|
3773
|
+
var cache = m_ctx.getImageData(0, 0, m_canvas.getWidth(), m_canvas.getHeight());
|
|
3053
3774
|
setChartSize();
|
|
3054
3775
|
m_ctx.putImageData(cache, 0, 0);
|
|
3055
3776
|
};
|
|
@@ -3074,12 +3795,31 @@ function Milli_Chart(settings) {
|
|
|
3074
3795
|
if (m_canvas == null) {
|
|
3075
3796
|
m_canvas = MillistreamWidgetApi_addElement(_this, 'canvas', 'millistream-chart-canvas', _this.settings.target);
|
|
3076
3797
|
m_ctx = m_canvas.getContext("2d");
|
|
3798
|
+
setHighDPICanvas(m_canvas);
|
|
3799
|
+
setHighDPIContext(m_ctx);
|
|
3077
3800
|
setChartSize();
|
|
3078
3801
|
m_canvas.addEventListener('mousemove', onMouseMove, false); // disable while loading and enable on drawReady
|
|
3079
3802
|
m_canvas.addEventListener('mouseout', onMouseOut, false);
|
|
3080
3803
|
m_canvas.style.cursor = "crosshair";
|
|
3081
3804
|
m_canvas.onmousedown = (function(evt) {
|
|
3082
3805
|
if (evt.which != 1) return; // ignore right and middle
|
|
3806
|
+
var rect = m_canvas.getBoundingClientRect();
|
|
3807
|
+
var x = getScaledSetting(evt.clientX) - getScaledSetting(rect.left) - 1;
|
|
3808
|
+
var y = getScaledSetting(evt.clientY) - getScaledSetting(rect.top);
|
|
3809
|
+
|
|
3810
|
+
for (let i = 0; i < _this.settings.indicators.length; i++) {
|
|
3811
|
+
var width = m_ctx.measureText(_this.settings.indicators[i].indicator).width;
|
|
3812
|
+
for (let s = 0; s < _this.settings.indicators[i].timeseries.length; s++) {
|
|
3813
|
+
if (x >= parseInt(_this.settings.indicators[i].timeseries[s].pos.x) - (width / 2) && x <= parseInt(_this.settings.indicators[i].timeseries[s].pos.x) + (width / 2)) {
|
|
3814
|
+
if (y >= _this.settings.indicators[i].timeseries[s].pos.y && y <= _this.settings.indicators[i].timeseries[s].pos.y + width) {
|
|
3815
|
+
if (typeof _this.settings.indicators[i].onclick === 'function') _this.settings.indicators[i].onclick.call(_this.settings.indicators[i]);
|
|
3816
|
+
}
|
|
3817
|
+
break;
|
|
3818
|
+
}
|
|
3819
|
+
}
|
|
3820
|
+
}
|
|
3821
|
+
|
|
3822
|
+
|
|
3083
3823
|
if (_this.settings.enablezoom == false) return;
|
|
3084
3824
|
if (m_datapoints.length == 0) return;
|
|
3085
3825
|
var rect = m_canvas.getBoundingClientRect();
|
|
@@ -3147,15 +3887,45 @@ function Milli_Chart(settings) {
|
|
|
3147
3887
|
function requestStreaming() {
|
|
3148
3888
|
if (_this.settings.streaming != false) {
|
|
3149
3889
|
var arr = [];
|
|
3890
|
+
var requestNews = 0;
|
|
3150
3891
|
_this.instruments.forEach(function(instr) {
|
|
3151
3892
|
if (instr.insref != 0) arr.push(instr.insref);
|
|
3152
3893
|
});
|
|
3894
|
+
_this.settings.indicators.forEach(function(indicator) {
|
|
3895
|
+
if (indicator.method == 'news' && typeof indicator.insrefs === 'object') {
|
|
3896
|
+
indicator.insrefs.forEach(function(insref) {
|
|
3897
|
+
if (insref != 0) {
|
|
3898
|
+
requestNews = 1;
|
|
3899
|
+
arr.push(insref);
|
|
3900
|
+
}
|
|
3901
|
+
});
|
|
3902
|
+
}
|
|
3903
|
+
});
|
|
3904
|
+
if (requestNews == 0) _this.settings.messagetypes = _this.settings.messagetypes & ~1;
|
|
3905
|
+
else _this.settings.messagetypes |= 1;
|
|
3153
3906
|
if (typeof _this.unsubscriptions === 'undefined' || typeof _this.unsubscriptions.insrefs === 'undefined' || _this.unsubscriptions.insrefs != arr.length) {
|
|
3154
3907
|
_this.requestid = _this.settings.streaming.MillistreamWidgetStreamingApi_subscribeInstruments(_this, _this.requestid, arr);
|
|
3155
3908
|
}
|
|
3156
3909
|
}
|
|
3157
3910
|
}
|
|
3158
3911
|
|
|
3912
|
+
function handleNewsStreaming(insref, json) {
|
|
3913
|
+
if (typeof json['167'] === 'undefined') return false;
|
|
3914
|
+
var found = false;
|
|
3915
|
+
for (var i = 0; i < _this.instruments.length; i++) {
|
|
3916
|
+
var s;
|
|
3917
|
+
for (s = 0; s < json['167'].length; s++) {
|
|
3918
|
+
if (json['167'][s] == _this.instruments[i].insref) {
|
|
3919
|
+
found = true;
|
|
3920
|
+
break;
|
|
3921
|
+
}
|
|
3922
|
+
}
|
|
3923
|
+
}
|
|
3924
|
+
if (found == false) {
|
|
3925
|
+
return false;
|
|
3926
|
+
}
|
|
3927
|
+
}
|
|
3928
|
+
|
|
3159
3929
|
_this.streamingCallback = function(insref, mref, json) {
|
|
3160
3930
|
var update = false;
|
|
3161
3931
|
var calcAnalyizis = false;
|
|
@@ -3163,6 +3933,9 @@ function Milli_Chart(settings) {
|
|
|
3163
3933
|
return item.insref == insref;
|
|
3164
3934
|
});
|
|
3165
3935
|
if (instr == null) {
|
|
3936
|
+
if (mref == 'newsheadline') {
|
|
3937
|
+
handleNewsStreaming(insref, json);
|
|
3938
|
+
}
|
|
3166
3939
|
return;
|
|
3167
3940
|
}
|
|
3168
3941
|
if (mref == 'performance') {
|
|
@@ -3176,6 +3949,10 @@ function Milli_Chart(settings) {
|
|
|
3176
3949
|
instr.closeprice1d = parseFloat(json['262']);
|
|
3177
3950
|
update = true;
|
|
3178
3951
|
}
|
|
3952
|
+
if (typeof json['1024'] !== 'undefined') {
|
|
3953
|
+
instr.diff1dprc = parseFloat(json['1024']);
|
|
3954
|
+
update = true;
|
|
3955
|
+
}
|
|
3179
3956
|
}
|
|
3180
3957
|
var timestamp;
|
|
3181
3958
|
if (mref == 'quote') {
|
|
@@ -3215,7 +3992,7 @@ function Milli_Chart(settings) {
|
|
|
3215
3992
|
}
|
|
3216
3993
|
obj.price = typeof price === 'undefined' ? obj.price : parseFloat(price);
|
|
3217
3994
|
obj.quantity = typeof quantity === 'undefined' ? obj.quantity : quantity;
|
|
3218
|
-
if (
|
|
3995
|
+
if (chartType == 'history') update = true; // TODO fix
|
|
3219
3996
|
} else {
|
|
3220
3997
|
if (json['3'] && json['36'] && (json['12'] || json['201'])) {
|
|
3221
3998
|
timestamp = new Date(json['3'] + 'T' + json['36'].substring(0, 6) + '00' + 'Z').getTime();
|
|
@@ -3253,14 +4030,14 @@ function Milli_Chart(settings) {
|
|
|
3253
4030
|
calcAnalyizis = true;
|
|
3254
4031
|
data.price = parseFloat(json['12']); // eller 201 för tradeyield
|
|
3255
4032
|
data.quantity += typeof json['13'] === 'undefined' ? 0 : parseInt(json['13']);
|
|
3256
|
-
if (
|
|
4033
|
+
if (chartType == 'trades') update = true;
|
|
3257
4034
|
} else {
|
|
3258
4035
|
if (instr.pricetype == 'yield') {
|
|
3259
4036
|
if (data.price != parseFloat(json['201']))
|
|
3260
4037
|
calcAnalyizis = true;
|
|
3261
4038
|
data.price = parseFloat(json['201']); // eller 201 för tradeyield
|
|
3262
4039
|
data.quantity += typeof json['13'] === 'undefined' ? 0 : parseInt(json['13']);
|
|
3263
|
-
if (
|
|
4040
|
+
if (chartType == 'trades') update = true;
|
|
3264
4041
|
}
|
|
3265
4042
|
// TODo: updatera med quantity, open , high,low osv?
|
|
3266
4043
|
}
|
|
@@ -3280,7 +4057,7 @@ function Milli_Chart(settings) {
|
|
|
3280
4057
|
break;
|
|
3281
4058
|
case 'bb':
|
|
3282
4059
|
_this.settings.indicators[i].trades = [];
|
|
3283
|
-
_this.settings.indicators[i].trades =
|
|
4060
|
+
_this.settings.indicators[i].trades = calculateBollingerBands(_this.instruments[0].trades, _this.settings.indicators[i].method_length, _this.settings.indicators[i].stddev | 2);
|
|
3284
4061
|
break;
|
|
3285
4062
|
default:
|
|
3286
4063
|
// draw custom added?
|
|
@@ -3300,7 +4077,7 @@ function Milli_Chart(settings) {
|
|
|
3300
4077
|
let ret = [];
|
|
3301
4078
|
var i;
|
|
3302
4079
|
var date, datestr;
|
|
3303
|
-
if (
|
|
4080
|
+
if (chartType == 'trades') {
|
|
3304
4081
|
if (_this.instruments.length > 0) {
|
|
3305
4082
|
for (i = 0; i < _this.instruments[0].trades.length; i++) {
|
|
3306
4083
|
date = new Date(_this.instruments[0].trades[i].timestamp - new Date().getTimezoneOffset() * 60000); // tz_offset in minutes
|
|
@@ -3338,6 +4115,180 @@ function Milli_Chart(settings) {
|
|
|
3338
4115
|
return 0;
|
|
3339
4116
|
};
|
|
3340
4117
|
|
|
4118
|
+
function fetchNews(indicator) {
|
|
4119
|
+
var url = milli_data_api_url + "widget=chartnews&token=" + _this.settings.token + "&target=buildwidget&fields=headline,date,time&language=" + "sv" + "&insref=" + indicator.insrefs.toString() + '&xhr=' + (_this.settings.xhr == true ? '1' : '0');
|
|
4120
|
+
url += '&instruments=' + _this.instruments[0].insref;
|
|
4121
|
+
|
|
4122
|
+
for (let i = 1; i < _this.instruments.length; i++) { // skall dessa vara med?
|
|
4123
|
+
if (_this.instruments[i].insref != 0) url += ',' + _this.instruments[i].insref;
|
|
4124
|
+
}
|
|
4125
|
+
|
|
4126
|
+
if (typeof _this.settings.newslanguage === 'object') url += '&newslanguage=' + _this.settings.newslanguage.toString();
|
|
4127
|
+
|
|
4128
|
+
if (_this.settings.xhr) {
|
|
4129
|
+
getXhrJson(url);
|
|
4130
|
+
} else {
|
|
4131
|
+
millistream_data_api.fetch(url, function(data) {
|
|
4132
|
+
indicator.news = data.headlines;
|
|
4133
|
+
indicator.news.sort(function(a, b) {
|
|
4134
|
+
return a.timestamp - b.timestamp;
|
|
4135
|
+
});
|
|
4136
|
+
indicator.method = 'news';
|
|
4137
|
+
indicator.type = NEWSINDICATOR;
|
|
4138
|
+
_this.addIndicator(indicator);
|
|
4139
|
+
requestStreaming();
|
|
4140
|
+
});
|
|
4141
|
+
}
|
|
4142
|
+
}
|
|
4143
|
+
|
|
4144
|
+
_this.addNews = function(indicator) {
|
|
4145
|
+
if (!indicator.method) return;
|
|
4146
|
+
var i;
|
|
4147
|
+
for (i = 0; i < _this.settings.indicators.length; i++) {
|
|
4148
|
+
if (_this.settings.indicators[i].method == indicator.method) {
|
|
4149
|
+
_this.removeIndicator(_this.settings.indicators[i]);
|
|
4150
|
+
return;
|
|
4151
|
+
}
|
|
4152
|
+
}
|
|
4153
|
+
fetchNews(indicator);
|
|
4154
|
+
};
|
|
4155
|
+
|
|
4156
|
+
function setHighDPIContext(context)
|
|
4157
|
+
{
|
|
4158
|
+
context.pixelRatio = (function() {
|
|
4159
|
+
var backingStore = this.backingStorePixelRatio ||
|
|
4160
|
+
this.webkitBackingStorePixelRatio ||
|
|
4161
|
+
this.mozBackingStorePixelRatio ||
|
|
4162
|
+
this.msBackingStorePixelRatio ||
|
|
4163
|
+
this.oBackingStorePixelRatio ||
|
|
4164
|
+
this.backingStorePixelRatio || 1;
|
|
4165
|
+
|
|
4166
|
+
return (window.devicePixelRatio || 1) / backingStore;
|
|
4167
|
+
});
|
|
4168
|
+
|
|
4169
|
+
let forEach = function(obj, func) {
|
|
4170
|
+
for (var p in obj) {
|
|
4171
|
+
if (obj.hasOwnProperty(p)) {
|
|
4172
|
+
func(obj[p], p);
|
|
4173
|
+
}
|
|
4174
|
+
}
|
|
4175
|
+
},
|
|
4176
|
+
ratioArgs = {
|
|
4177
|
+
'fillRect': 'all',
|
|
4178
|
+
'clearRect': 'all',
|
|
4179
|
+
'strokeRect': 'all',
|
|
4180
|
+
'moveTo': 'all',
|
|
4181
|
+
'lineTo': 'all',
|
|
4182
|
+
'arc': [0,1,2],
|
|
4183
|
+
'arcTo': 'all',
|
|
4184
|
+
'bezierCurveTo': 'all',
|
|
4185
|
+
'isPointinPath': 'all',
|
|
4186
|
+
'isPointinStroke': 'all',
|
|
4187
|
+
'quadraticCurveTo': 'all',
|
|
4188
|
+
'rect': 'all',
|
|
4189
|
+
'translate': 'all',
|
|
4190
|
+
'createRadialGradient': 'all',
|
|
4191
|
+
'createLinearGradient': 'all'
|
|
4192
|
+
};
|
|
4193
|
+
|
|
4194
|
+
if (context.pixelRatio === 1) return;
|
|
4195
|
+
|
|
4196
|
+
forEach(ratioArgs, function(value, key) {
|
|
4197
|
+
context[key] = (function(_super) {
|
|
4198
|
+
return function() {
|
|
4199
|
+
var i, len,
|
|
4200
|
+
args = Array.prototype.slice.call(arguments);
|
|
4201
|
+
|
|
4202
|
+
if (value === 'all') {
|
|
4203
|
+
args = args.map(function(a) {
|
|
4204
|
+
return a * context.pixelRatio();
|
|
4205
|
+
});
|
|
4206
|
+
}
|
|
4207
|
+
else if (Array.isArray(value)) {
|
|
4208
|
+
for (i = 0, len = value.length; i < len; i++) {
|
|
4209
|
+
args[value[i]] *= context.pixelRatio();
|
|
4210
|
+
}
|
|
4211
|
+
}
|
|
4212
|
+
|
|
4213
|
+
return _super.apply(this, args);
|
|
4214
|
+
};
|
|
4215
|
+
})(context[key]);
|
|
4216
|
+
});
|
|
4217
|
+
/*context.stroke = (function(_super) {
|
|
4218
|
+
return function() {
|
|
4219
|
+
this.lineWidth *= context.pixelRatio();
|
|
4220
|
+
_super.apply(this, arguments);
|
|
4221
|
+
this.lineWidth /= context.pixelRatio();
|
|
4222
|
+
};
|
|
4223
|
+
})(context.stroke);*/
|
|
4224
|
+
|
|
4225
|
+
context.fillText = (function(_super) {
|
|
4226
|
+
return function() {
|
|
4227
|
+
var args = Array.prototype.slice.call(arguments);
|
|
4228
|
+
args[1] *= context.pixelRatio(); // x
|
|
4229
|
+
args[2] *= context.pixelRatio(); // y
|
|
4230
|
+
var oldfont = this.font;
|
|
4231
|
+
this.font = this.font.replace(
|
|
4232
|
+
/(\d+)(px|em|rem|pt)/g,
|
|
4233
|
+
function(w, m, u) {
|
|
4234
|
+
return (Math.round(m * context.pixelRatio())) + u;
|
|
4235
|
+
}
|
|
4236
|
+
);
|
|
4237
|
+
_super.apply(this, args);
|
|
4238
|
+
this.font = oldfont;
|
|
4239
|
+
};
|
|
4240
|
+
})(context.fillText);
|
|
4241
|
+
|
|
4242
|
+
context.strokeText = (function(_super) {
|
|
4243
|
+
return function() {
|
|
4244
|
+
var args = Array.prototype.slice.call(arguments);
|
|
4245
|
+
args[1] *= context.pixelRatio(); // x
|
|
4246
|
+
args[2] *= context.pixelRatio(); // y
|
|
4247
|
+
var oldfont = this.font;
|
|
4248
|
+
this.font = this.font.replace(
|
|
4249
|
+
/(\d+)(px|em|rem|pt)/g,
|
|
4250
|
+
function(w, m, u) {
|
|
4251
|
+
return (m * context.pixelRatio()) + u;
|
|
4252
|
+
}
|
|
4253
|
+
);
|
|
4254
|
+
|
|
4255
|
+
_super.apply(this, args);
|
|
4256
|
+
this.font = oldfont;
|
|
4257
|
+
};
|
|
4258
|
+
})(context.strokeText);
|
|
4259
|
+
|
|
4260
|
+
}
|
|
4261
|
+
|
|
4262
|
+
function setHighDPICanvas(canvas) {
|
|
4263
|
+
canvas.getPixelRatio = (function() {
|
|
4264
|
+
var context = this.getContext('2d');
|
|
4265
|
+
var backingStore = context.backingStorePixelRatio ||
|
|
4266
|
+
context.webkitBackingStorePixelRatio ||
|
|
4267
|
+
context.mozBackingStorePixelRatio ||
|
|
4268
|
+
context.msBackingStorePixelRatio ||
|
|
4269
|
+
context.oBackingStorePixelRatio ||
|
|
4270
|
+
context.backingStorePixelRatio || 1;
|
|
4271
|
+
return (window.devicePixelRatio || 1) / backingStore;
|
|
4272
|
+
});
|
|
4273
|
+
canvas.setRect = (function(height, width) {
|
|
4274
|
+
let ratio = canvas.getPixelRatio();
|
|
4275
|
+
this.style.height = height + 'px';
|
|
4276
|
+
this.style.width = width + 'px';
|
|
4277
|
+
this.width = width * ratio;
|
|
4278
|
+
this.height = height * ratio;
|
|
4279
|
+
});
|
|
4280
|
+
canvas.getWidth = (function() {
|
|
4281
|
+
let ratio = this.getPixelRatio();
|
|
4282
|
+
return this.width / ratio;
|
|
4283
|
+
});
|
|
4284
|
+
canvas.getHeight = (function() {
|
|
4285
|
+
let ratio = this.getPixelRatio();
|
|
4286
|
+
//return this.height;
|
|
4287
|
+
return this.height / ratio;
|
|
4288
|
+
});
|
|
4289
|
+
return ;
|
|
4290
|
+
}
|
|
4291
|
+
|
|
3341
4292
|
function fetchTrades(instrument) {
|
|
3342
4293
|
var oldfields = _this.settings.fields;
|
|
3343
4294
|
_this.settings.fields = [...['name', 'tradecurrency', 'time', 'date', 'tradeprice', 'tradequantity', 'marketopen', 'marketclose', 'closeprice1d'], ...oldfields];
|
|
@@ -3435,14 +4386,19 @@ function Milli_Chart(settings) {
|
|
|
3435
4386
|
if (insrefs[i] != 0)
|
|
3436
4387
|
this.addCompare(insrefs[i]);
|
|
3437
4388
|
}
|
|
3438
|
-
|
|
4389
|
+
for (let i = 0; i < _this.settings.indicators.length; i++) {
|
|
4390
|
+
if (_this.settings.indicators[i].type == NEWSINDICATOR) {
|
|
4391
|
+
fetchNews(_this.settings.indicators[i]);
|
|
4392
|
+
break;
|
|
4393
|
+
}
|
|
4394
|
+
}
|
|
3439
4395
|
};
|
|
3440
4396
|
if (this.settings.autodraw == true) {
|
|
3441
4397
|
this.drawWidget();
|
|
3442
4398
|
}
|
|
3443
4399
|
|
|
3444
4400
|
(function updatePixelRatio() {
|
|
3445
|
-
matchMedia(`(resolution: ${
|
|
4401
|
+
matchMedia(`(resolution: ${1}dppx)`).addEventListener('change', updatePixelRatio, { once: true });
|
|
3446
4402
|
_this.drawChart();
|
|
3447
4403
|
})();
|
|
3448
4404
|
|
|
@@ -3452,7 +4408,8 @@ function Milli_Chart(settings) {
|
|
|
3452
4408
|
_this.drawChart();
|
|
3453
4409
|
}
|
|
3454
4410
|
});
|
|
3455
|
-
}
|
|
4411
|
+
};
|
|
4412
|
+
|
|
3456
4413
|
function Milli_OptionsList(settings) {
|
|
3457
4414
|
let _this = this;
|
|
3458
4415
|
let requestid = null;
|
|
@@ -6056,6 +7013,7 @@ function formatDate(date, format, widget) {
|
|
|
6056
7013
|
}
|
|
6057
7014
|
if (format == 'b dd') { // Jan 01
|
|
6058
7015
|
timeStamp = new Date(date);
|
|
7016
|
+
console.log(date,timeStamp);
|
|
6059
7017
|
mon = timeStamp.toDateString().split(' ');
|
|
6060
7018
|
day = timeStamp.getDate();
|
|
6061
7019
|
return mon[1] + ' ' + (day <= 9 ? '0' + day : day);
|