@barchart/portfolio-api-common 1.0.128 → 1.0.132
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/lib/processing/PositionContainer.js +102 -10
- package/lib/processing/PositionGroup.js +99 -10
- package/lib/processing/PositionItem.js +93 -16
- package/package.json +1 -1
- package/test/SpecRunner.js +294 -36
|
@@ -22,11 +22,11 @@ module.exports = (() => {
|
|
|
22
22
|
|
|
23
23
|
/**
|
|
24
24
|
* A container for positions which groups the positions into one or more
|
|
25
|
-
* trees for aggregation and display purposes. For example,
|
|
26
|
-
* grouped first by asset class then by position
|
|
25
|
+
* trees for aggregation and display purposes. For example, positions could be
|
|
26
|
+
* grouped first by asset class then by position.
|
|
27
27
|
*
|
|
28
28
|
* Furthermore, the container performs aggregation (driven primarily by price
|
|
29
|
-
* changes) for each level of grouping
|
|
29
|
+
* changes) for each level of grouping.
|
|
30
30
|
*
|
|
31
31
|
* @public
|
|
32
32
|
* @param {Array.<PositionTreeDefinition>} definitions
|
|
@@ -108,6 +108,20 @@ module.exports = (() => {
|
|
|
108
108
|
return map;
|
|
109
109
|
}, { });
|
|
110
110
|
|
|
111
|
+
this._symbolsDisplay = this._items.reduce((map, item) => {
|
|
112
|
+
const symbol = extractSymbolForDisplay(item.position);
|
|
113
|
+
|
|
114
|
+
if (symbol) {
|
|
115
|
+
if (!map.hasOwnProperty(symbol)) {
|
|
116
|
+
map[symbol] = [ ];
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
map[symbol].push(item);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
return map;
|
|
123
|
+
}, { });
|
|
124
|
+
|
|
111
125
|
this._currencies = this._items.reduce((map, item) => {
|
|
112
126
|
const position = item.position;
|
|
113
127
|
|
|
@@ -219,10 +233,14 @@ module.exports = (() => {
|
|
|
219
233
|
}, { });
|
|
220
234
|
}
|
|
221
235
|
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
236
|
+
/**
|
|
237
|
+
* Returns a distinct list of all symbols used by the positions
|
|
238
|
+
* within the container.
|
|
239
|
+
*
|
|
240
|
+
* @public
|
|
241
|
+
* @param {Boolean} display - If true, all "display" symbols are returned; otherwise Barchart symbols are returned.
|
|
242
|
+
* @returns {Array.<String>}
|
|
243
|
+
*/
|
|
226
244
|
getPositionSymbols(display) {
|
|
227
245
|
const symbols = this._items.reduce((symbols, item) => {
|
|
228
246
|
const position = item.position;
|
|
@@ -245,6 +263,14 @@ module.exports = (() => {
|
|
|
245
263
|
return array.unique(symbols);
|
|
246
264
|
}
|
|
247
265
|
|
|
266
|
+
/**
|
|
267
|
+
* Updates the quote for a single symbol; causing updates to any grouping
|
|
268
|
+
* level that contains the position(s) for the symbol.
|
|
269
|
+
*
|
|
270
|
+
* @public
|
|
271
|
+
* @param {String} symbol
|
|
272
|
+
* @param {Object} quote
|
|
273
|
+
*/
|
|
248
274
|
setPositionQuote(symbol, quote) {
|
|
249
275
|
assert.argumentIsRequired(symbol, 'symbol', String);
|
|
250
276
|
assert.argumentIsRequired(quote, 'quote', Object);
|
|
@@ -254,14 +280,34 @@ module.exports = (() => {
|
|
|
254
280
|
}
|
|
255
281
|
}
|
|
256
282
|
|
|
283
|
+
/**
|
|
284
|
+
* Returns all forex symbols that are required to do currency translations.
|
|
285
|
+
*
|
|
286
|
+
* @public
|
|
287
|
+
* @returns {Array.<String>}
|
|
288
|
+
*/
|
|
257
289
|
getForexSymbols() {
|
|
258
290
|
return this._forexSymbols;
|
|
259
291
|
}
|
|
260
292
|
|
|
293
|
+
/**
|
|
294
|
+
* Returns all current forex quotes.
|
|
295
|
+
*
|
|
296
|
+
* @public
|
|
297
|
+
* @returns {Array.<Object>}
|
|
298
|
+
*/
|
|
261
299
|
getForexQuotes() {
|
|
262
300
|
return this._forexQuotes;
|
|
263
301
|
}
|
|
264
302
|
|
|
303
|
+
/**
|
|
304
|
+
* Updates the forex quote for a single currency pair; causing updates to
|
|
305
|
+
* any grouping level that contains that requires translation.
|
|
306
|
+
*
|
|
307
|
+
* @public
|
|
308
|
+
* @param {String} symbol
|
|
309
|
+
* @param {Object} quote
|
|
310
|
+
*/
|
|
265
311
|
setForexQuote(symbol, quote) {
|
|
266
312
|
assert.argumentIsRequired(symbol, 'symbol', String);
|
|
267
313
|
assert.argumentIsRequired(quote, 'quote', Object);
|
|
@@ -279,10 +325,50 @@ module.exports = (() => {
|
|
|
279
325
|
Object.keys(this._trees).forEach(key => this._trees[key].walk(group => group.setForexRate(rate), true, false));
|
|
280
326
|
}
|
|
281
327
|
|
|
282
|
-
|
|
328
|
+
/**
|
|
329
|
+
* Updates fundamental data for a single symbol.
|
|
330
|
+
*
|
|
331
|
+
* @public
|
|
332
|
+
* @param {String} symbol
|
|
333
|
+
* @param {Object} data
|
|
334
|
+
*/
|
|
335
|
+
setPositionFundamentalData(symbol, data) {
|
|
283
336
|
return;
|
|
284
337
|
}
|
|
285
338
|
|
|
339
|
+
/**
|
|
340
|
+
* Indicates if a news article exists for a symbol.
|
|
341
|
+
*
|
|
342
|
+
* @public
|
|
343
|
+
* @param {String} symbol
|
|
344
|
+
* @param {Boolean} display
|
|
345
|
+
* @param {Boolean} exists
|
|
346
|
+
*/
|
|
347
|
+
setNewsArticleExists(symbol, display, exists) {
|
|
348
|
+
assert.argumentIsRequired(symbol, 'symbol', String);
|
|
349
|
+
assert.argumentIsRequired(display, 'display', Boolean);
|
|
350
|
+
assert.argumentIsRequired(exists, 'exists', Boolean);
|
|
351
|
+
|
|
352
|
+
let map;
|
|
353
|
+
|
|
354
|
+
if (display) {
|
|
355
|
+
map = this._symbols;
|
|
356
|
+
} else {
|
|
357
|
+
map = this._symbolsDisplay;
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
if (map.hasOwnProperty(symbol)) {
|
|
361
|
+
map[symbol].forEach(item => item.setNewsArticleExists(exists));
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
/**
|
|
366
|
+
* Returns a single level of grouping from one of the internal trees.
|
|
367
|
+
*
|
|
368
|
+
* @param {String} name
|
|
369
|
+
* @param {Array.<String> keys
|
|
370
|
+
* @returns {PositionGroup}
|
|
371
|
+
*/
|
|
286
372
|
getGroup(name, keys) {
|
|
287
373
|
assert.argumentIsRequired(name, 'name', String);
|
|
288
374
|
assert.argumentIsArray(keys, 'keys', Number);
|
|
@@ -290,6 +376,14 @@ module.exports = (() => {
|
|
|
290
376
|
return findNode(this._trees[name], keys).getValue();
|
|
291
377
|
}
|
|
292
378
|
|
|
379
|
+
/**
|
|
380
|
+
* Returns all child groups from a level of grouping within one of
|
|
381
|
+
* the internal trees.
|
|
382
|
+
*
|
|
383
|
+
* @param {String} name
|
|
384
|
+
* @param {Array.<String> keys
|
|
385
|
+
* @returns {Array.<PositionGroup>}
|
|
386
|
+
*/
|
|
293
387
|
getGroups(name, keys) {
|
|
294
388
|
assert.argumentIsRequired(name, 'name', String);
|
|
295
389
|
assert.argumentIsArray(keys, 'keys', Number);
|
|
@@ -301,8 +395,6 @@ module.exports = (() => {
|
|
|
301
395
|
assert.argumentIsRequired(name, 'name', String);
|
|
302
396
|
assert.argumentIsRequired(executor, 'executor', Function);
|
|
303
397
|
|
|
304
|
-
assert.argumentIsRequired(executor, 'executor', Function);
|
|
305
|
-
|
|
306
398
|
this._trees[name].walk(group => group.setSuspended(true), false, false);
|
|
307
399
|
|
|
308
400
|
executor(this);
|
|
@@ -10,7 +10,17 @@ module.exports = (() => {
|
|
|
10
10
|
'use strict';
|
|
11
11
|
|
|
12
12
|
/**
|
|
13
|
+
* A grouping of {@link PositionItem} instances. The group aggregates from across
|
|
14
|
+
* all the positions and performs currency translation, as necessary.
|
|
15
|
+
*
|
|
13
16
|
* @public
|
|
17
|
+
* @param {PositionContainer} container
|
|
18
|
+
* @param {PositionGroup|null} parent
|
|
19
|
+
* @param {Array.<PositionItem>} items
|
|
20
|
+
* @param {Currency} currency
|
|
21
|
+
* @param {String} key
|
|
22
|
+
* @param {String} description
|
|
23
|
+
* @param {Boolean=} single
|
|
14
24
|
*/
|
|
15
25
|
class PositionGroup {
|
|
16
26
|
constructor(container, parent, items, currency, key, description, single) {
|
|
@@ -30,15 +40,22 @@ module.exports = (() => {
|
|
|
30
40
|
this._suspended = false;
|
|
31
41
|
|
|
32
42
|
this._marketPercentChangeEvent = new Event(this);
|
|
43
|
+
this._excludedChangeEvent = new Event(this);
|
|
33
44
|
|
|
34
45
|
this._dataFormat = { };
|
|
35
46
|
this._dataActual = { };
|
|
36
47
|
|
|
37
48
|
this._dataFormat.key = this._key;
|
|
38
49
|
this._dataFormat.description = this._description;
|
|
39
|
-
this._dataFormat.
|
|
40
|
-
|
|
50
|
+
this._dataFormat.newsExists = false;
|
|
41
51
|
this._dataFormat.quantity = null;
|
|
52
|
+
this._dataFormat.basisPrice = null;
|
|
53
|
+
|
|
54
|
+
this._dataActual.key = this._key;
|
|
55
|
+
this._dataActual.description = this._description;
|
|
56
|
+
this._dataActual.newsExists = false;
|
|
57
|
+
this._dataActual.quantity = null;
|
|
58
|
+
this._dataActual.basisPrice = null;
|
|
42
59
|
|
|
43
60
|
if (this._single) {
|
|
44
61
|
const item = items[0];
|
|
@@ -117,35 +134,85 @@ module.exports = (() => {
|
|
|
117
134
|
|
|
118
135
|
calculatePriceData(this, this._container.getForexQuotes(), sender, false);
|
|
119
136
|
});
|
|
137
|
+
|
|
138
|
+
if (this._single) {
|
|
139
|
+
item.registerNewsExistsChangeHandler((exists, sender) => {
|
|
140
|
+
this._dataFormat.newsExists = exists;
|
|
141
|
+
this._dataFormat.newsExists = exists;
|
|
142
|
+
});
|
|
143
|
+
}
|
|
120
144
|
});
|
|
121
145
|
|
|
122
146
|
this.refresh();
|
|
123
147
|
}
|
|
124
148
|
|
|
149
|
+
/**
|
|
150
|
+
* The key of the group.
|
|
151
|
+
*
|
|
152
|
+
* @public
|
|
153
|
+
* @returns {String}
|
|
154
|
+
*/
|
|
125
155
|
get key() {
|
|
126
156
|
return this._key;
|
|
127
157
|
}
|
|
128
158
|
|
|
159
|
+
/**
|
|
160
|
+
* The description of the group.
|
|
161
|
+
*
|
|
162
|
+
* @public
|
|
163
|
+
* @returns {String}
|
|
164
|
+
*/
|
|
129
165
|
get description() {
|
|
130
166
|
return this._description;
|
|
131
167
|
}
|
|
132
168
|
|
|
169
|
+
/**
|
|
170
|
+
* The {@link Currency} which all aggregated data is presented in.
|
|
171
|
+
*
|
|
172
|
+
* @public
|
|
173
|
+
* @returns {Currency}
|
|
174
|
+
*/
|
|
133
175
|
get currency() {
|
|
134
176
|
return this._currency;
|
|
135
177
|
}
|
|
136
178
|
|
|
179
|
+
/**
|
|
180
|
+
* The {@link PositionItem} instances which for which aggregated data is compiled.
|
|
181
|
+
*
|
|
182
|
+
* @public
|
|
183
|
+
* @returns {Currency}
|
|
184
|
+
*/
|
|
137
185
|
get items() {
|
|
138
186
|
return this._items;
|
|
139
187
|
}
|
|
140
188
|
|
|
189
|
+
/**
|
|
190
|
+
* The string-based, human-readable aggregated data for the group.
|
|
191
|
+
*
|
|
192
|
+
* @public
|
|
193
|
+
* @returns {Object}
|
|
194
|
+
*/
|
|
141
195
|
get data() {
|
|
142
196
|
return this._dataFormat;
|
|
143
197
|
}
|
|
144
198
|
|
|
199
|
+
/**
|
|
200
|
+
* The raw aggregated data for the group (typically {@link Decimal} instances).
|
|
201
|
+
*
|
|
202
|
+
* @public
|
|
203
|
+
* @returns {Object}
|
|
204
|
+
*/
|
|
145
205
|
get actual() {
|
|
146
206
|
return this._dataActual;
|
|
147
207
|
}
|
|
148
208
|
|
|
209
|
+
/**
|
|
210
|
+
* Indicates if the group will only contain one {@link PositionItem} -- that is,
|
|
211
|
+
* indicates if the group represents a single position.
|
|
212
|
+
*
|
|
213
|
+
* @public
|
|
214
|
+
* @returns {Boolean}
|
|
215
|
+
*/
|
|
149
216
|
get single() {
|
|
150
217
|
return this._single;
|
|
151
218
|
}
|
|
@@ -154,10 +221,22 @@ module.exports = (() => {
|
|
|
154
221
|
return this._suspended;
|
|
155
222
|
}
|
|
156
223
|
|
|
224
|
+
/**
|
|
225
|
+
* Indicates if the group should be excluded from higher-level aggregations.
|
|
226
|
+
*
|
|
227
|
+
* @public
|
|
228
|
+
* @returns {Boolean}
|
|
229
|
+
*/
|
|
157
230
|
get excluded() {
|
|
158
231
|
return this._excluded;
|
|
159
232
|
}
|
|
160
233
|
|
|
234
|
+
/**
|
|
235
|
+
* Causes aggregated data to be recalculated using a new exchange rate.
|
|
236
|
+
*
|
|
237
|
+
* @public
|
|
238
|
+
* @param {Rate} rate
|
|
239
|
+
*/
|
|
161
240
|
setForexRate(rate) {
|
|
162
241
|
if (!this._bypassCurrencyTranslation) {
|
|
163
242
|
this.refresh();
|
|
@@ -168,11 +247,7 @@ module.exports = (() => {
|
|
|
168
247
|
assert.argumentIsRequired(value, 'value', Boolean);
|
|
169
248
|
|
|
170
249
|
if (this._excluded !== value) {
|
|
171
|
-
this.
|
|
172
|
-
this._items.forEach((item) => {
|
|
173
|
-
item.setExcluded(value);
|
|
174
|
-
});
|
|
175
|
-
});
|
|
250
|
+
this._excludedChangeEvent(this._excluded = value);
|
|
176
251
|
}
|
|
177
252
|
}
|
|
178
253
|
|
|
@@ -186,6 +261,11 @@ module.exports = (() => {
|
|
|
186
261
|
}
|
|
187
262
|
}
|
|
188
263
|
|
|
264
|
+
/**
|
|
265
|
+
* Causes all aggregated data to be recalculated.
|
|
266
|
+
*
|
|
267
|
+
* @public
|
|
268
|
+
*/
|
|
189
269
|
refresh() {
|
|
190
270
|
const rates = this._container.getForexQuotes();
|
|
191
271
|
|
|
@@ -193,6 +273,12 @@ module.exports = (() => {
|
|
|
193
273
|
calculatePriceData(this, rates, null, true);
|
|
194
274
|
}
|
|
195
275
|
|
|
276
|
+
/**
|
|
277
|
+
* Causes the percent of the position, with respect to the parent container's
|
|
278
|
+
* total, to be recalculated.
|
|
279
|
+
*
|
|
280
|
+
* @public
|
|
281
|
+
*/
|
|
196
282
|
refreshMarketPercent() {
|
|
197
283
|
calculateMarketPercent(this, this._container.getForexQuotes(), true);
|
|
198
284
|
}
|
|
@@ -246,7 +332,7 @@ module.exports = (() => {
|
|
|
246
332
|
|
|
247
333
|
const items = group._items;
|
|
248
334
|
|
|
249
|
-
group._bypassCurrencyTranslation = items.
|
|
335
|
+
group._bypassCurrencyTranslation = items.every(item => item.currency === currency);
|
|
250
336
|
|
|
251
337
|
const translate = (item, value) => {
|
|
252
338
|
let translated;
|
|
@@ -298,8 +384,11 @@ module.exports = (() => {
|
|
|
298
384
|
if (group.single) {
|
|
299
385
|
const item = group._items[0];
|
|
300
386
|
|
|
301
|
-
|
|
302
|
-
|
|
387
|
+
actual.quantity = item.position.snapshot.open;
|
|
388
|
+
actual.basisPrice = item.data.basisPrice;
|
|
389
|
+
|
|
390
|
+
format.quantity = formatDecimal(actual.quantity, 2);
|
|
391
|
+
format.basisPrice = formatCurrency(actual.basisPrice, currency);
|
|
303
392
|
}
|
|
304
393
|
}
|
|
305
394
|
|
|
@@ -11,7 +11,15 @@ module.exports = (() => {
|
|
|
11
11
|
'use strict';
|
|
12
12
|
|
|
13
13
|
/**
|
|
14
|
+
* A container for a single position, which handles quote changes and
|
|
15
|
+
* notifies observers -- which are typically parent-level {@link PositionGroup}
|
|
16
|
+
* instances.
|
|
17
|
+
*
|
|
14
18
|
* @public
|
|
19
|
+
* @param {Object} portfolio
|
|
20
|
+
* @param {Object} position
|
|
21
|
+
* @param {Object} currentSummary
|
|
22
|
+
* @param {Array.<Object>} previousSummaries
|
|
15
23
|
*/
|
|
16
24
|
class PositionItem {
|
|
17
25
|
constructor(portfolio, position, currentSummary, previousSummaries) {
|
|
@@ -27,10 +35,12 @@ module.exports = (() => {
|
|
|
27
35
|
this._data.basis = null;
|
|
28
36
|
|
|
29
37
|
this._currentQuote = null;
|
|
30
|
-
|
|
38
|
+
|
|
39
|
+
this._currentPrice = null;
|
|
40
|
+
this._previousPrice = null;
|
|
31
41
|
|
|
32
42
|
this._data.currentPrice = null;
|
|
33
|
-
this._data.
|
|
43
|
+
this._data.currentPricePrevious = null;
|
|
34
44
|
|
|
35
45
|
this._data.market = null;
|
|
36
46
|
this._data.marketChange = null;
|
|
@@ -50,74 +60,141 @@ module.exports = (() => {
|
|
|
50
60
|
this._data.income = null;
|
|
51
61
|
this._data.basisPrice = null;
|
|
52
62
|
|
|
53
|
-
this.
|
|
63
|
+
this._data.newsExists = false;
|
|
54
64
|
|
|
55
65
|
calculateStaticData(this);
|
|
56
66
|
calculatePriceData(this, null);
|
|
57
67
|
|
|
58
68
|
this._quoteChangedEvent = new Event(this);
|
|
59
|
-
this.
|
|
69
|
+
this._newsExistsChangedEvent = new Event(this);
|
|
60
70
|
}
|
|
61
71
|
|
|
72
|
+
/**
|
|
73
|
+
* The portfolio of the encapsulated position.
|
|
74
|
+
*
|
|
75
|
+
* @public
|
|
76
|
+
* @returns {Object}
|
|
77
|
+
*/
|
|
62
78
|
get portfolio() {
|
|
63
79
|
return this._portfolio;
|
|
64
80
|
}
|
|
65
81
|
|
|
82
|
+
/**
|
|
83
|
+
* The encapsulated position.
|
|
84
|
+
*
|
|
85
|
+
* @public
|
|
86
|
+
* @returns {Object}
|
|
87
|
+
*/
|
|
66
88
|
get position() {
|
|
67
89
|
return this._position;
|
|
68
90
|
}
|
|
69
91
|
|
|
92
|
+
/**
|
|
93
|
+
* The {@link Currency} of the encapsulated position.
|
|
94
|
+
*
|
|
95
|
+
* @public
|
|
96
|
+
* @returns {Object}
|
|
97
|
+
*/
|
|
70
98
|
get currency() {
|
|
71
99
|
return this._currency;
|
|
72
100
|
}
|
|
73
101
|
|
|
102
|
+
/**
|
|
103
|
+
* The year-to-date position summary of the encapsulated position.
|
|
104
|
+
*
|
|
105
|
+
* @public
|
|
106
|
+
* @returns {Object}
|
|
107
|
+
*/
|
|
74
108
|
get currentSummary() {
|
|
75
109
|
return this._currentSummary;
|
|
76
110
|
}
|
|
77
|
-
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Previous year's summaries for the encapsulated position.
|
|
114
|
+
*
|
|
115
|
+
* @public
|
|
116
|
+
* @returns {Object}
|
|
117
|
+
*/
|
|
78
118
|
get previousSummaries() {
|
|
79
119
|
return this._previousSummaries;
|
|
80
120
|
}
|
|
81
121
|
|
|
122
|
+
/**
|
|
123
|
+
* Various data regarding the encapsulated position.
|
|
124
|
+
*
|
|
125
|
+
* @public
|
|
126
|
+
* @returns {*}
|
|
127
|
+
*/
|
|
82
128
|
get data() {
|
|
83
129
|
return this._data;
|
|
84
130
|
}
|
|
85
131
|
|
|
132
|
+
/**
|
|
133
|
+
* The current quote for the symbol of the encapsulated position.
|
|
134
|
+
*
|
|
135
|
+
* @public
|
|
136
|
+
* @returns {null|{Object}}
|
|
137
|
+
*/
|
|
86
138
|
get quote() {
|
|
87
139
|
return this._currentQuote;
|
|
88
140
|
}
|
|
89
141
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
142
|
+
/**
|
|
143
|
+
* Sets the current quote -- causing position-level data (e.g. market value) to
|
|
144
|
+
* be recalculated.
|
|
145
|
+
*
|
|
146
|
+
* @public
|
|
147
|
+
* @param {Object} quote
|
|
148
|
+
*/
|
|
94
149
|
setQuote(quote) {
|
|
95
150
|
assert.argumentIsRequired(quote, 'quote', Object);
|
|
96
151
|
|
|
97
|
-
if (this.
|
|
152
|
+
if (this._currentPricePrevious !== quote.lastPrice) {
|
|
98
153
|
calculatePriceData(this, quote.lastPrice);
|
|
99
154
|
|
|
100
|
-
this.
|
|
155
|
+
this._currentPricePrevious = this._currentPrice;
|
|
156
|
+
this._currentPrice = quote.lastPrice;
|
|
157
|
+
|
|
101
158
|
this._currentQuote = quote;
|
|
102
159
|
|
|
103
160
|
this._quoteChangedEvent.fire(this._currentQuote);
|
|
104
161
|
}
|
|
105
162
|
}
|
|
106
163
|
|
|
107
|
-
|
|
164
|
+
/**
|
|
165
|
+
* Sets a flag which indicates if news article(s) exist for the encapsulated position's
|
|
166
|
+
* symbol.
|
|
167
|
+
*
|
|
168
|
+
* @public
|
|
169
|
+
* @param {Boolean} value
|
|
170
|
+
*/
|
|
171
|
+
setNewsArticleExists(value) {
|
|
108
172
|
assert.argumentIsRequired(value, 'value', Boolean);
|
|
109
173
|
|
|
110
|
-
if (this.
|
|
111
|
-
this.
|
|
174
|
+
if (this._data.newsExists !== value) {
|
|
175
|
+
this._newsExistsChangedEvent.fire(this._data.newsExists = value);
|
|
112
176
|
}
|
|
113
177
|
}
|
|
114
178
|
|
|
179
|
+
/**
|
|
180
|
+
* Registers an observer for quote changes, which is fired after internal recalculations
|
|
181
|
+
* of position data are complete.
|
|
182
|
+
*
|
|
183
|
+
* @public
|
|
184
|
+
* @param {Function} handler
|
|
185
|
+
*/
|
|
115
186
|
registerQuoteChangeHandler(handler) {
|
|
116
187
|
this._quoteChangedEvent.register(handler);
|
|
117
188
|
}
|
|
118
189
|
|
|
119
|
-
|
|
120
|
-
|
|
190
|
+
/**
|
|
191
|
+
* Registers an observer changes to the status of news existence.
|
|
192
|
+
*
|
|
193
|
+
* @public
|
|
194
|
+
* @param {Function} handler
|
|
195
|
+
*/
|
|
196
|
+
registerNewsExistsChangeHandler(handler) {
|
|
197
|
+
this._newsExistsChangedEvent.register(handler);
|
|
121
198
|
}
|
|
122
199
|
|
|
123
200
|
toString() {
|
package/package.json
CHANGED
package/test/SpecRunner.js
CHANGED
|
@@ -738,11 +738,11 @@ module.exports = (() => {
|
|
|
738
738
|
|
|
739
739
|
/**
|
|
740
740
|
* A container for positions which groups the positions into one or more
|
|
741
|
-
* trees for aggregation and display purposes. For example,
|
|
742
|
-
* grouped first by asset class then by position
|
|
741
|
+
* trees for aggregation and display purposes. For example, positions could be
|
|
742
|
+
* grouped first by asset class then by position.
|
|
743
743
|
*
|
|
744
744
|
* Furthermore, the container performs aggregation (driven primarily by price
|
|
745
|
-
* changes) for each level of grouping
|
|
745
|
+
* changes) for each level of grouping.
|
|
746
746
|
*
|
|
747
747
|
* @public
|
|
748
748
|
* @param {Array.<PositionTreeDefinition>} definitions
|
|
@@ -824,6 +824,20 @@ module.exports = (() => {
|
|
|
824
824
|
return map;
|
|
825
825
|
}, { });
|
|
826
826
|
|
|
827
|
+
this._symbolsDisplay = this._items.reduce((map, item) => {
|
|
828
|
+
const symbol = extractSymbolForDisplay(item.position);
|
|
829
|
+
|
|
830
|
+
if (symbol) {
|
|
831
|
+
if (!map.hasOwnProperty(symbol)) {
|
|
832
|
+
map[symbol] = [ ];
|
|
833
|
+
}
|
|
834
|
+
|
|
835
|
+
map[symbol].push(item);
|
|
836
|
+
}
|
|
837
|
+
|
|
838
|
+
return map;
|
|
839
|
+
}, { });
|
|
840
|
+
|
|
827
841
|
this._currencies = this._items.reduce((map, item) => {
|
|
828
842
|
const position = item.position;
|
|
829
843
|
|
|
@@ -935,10 +949,14 @@ module.exports = (() => {
|
|
|
935
949
|
}, { });
|
|
936
950
|
}
|
|
937
951
|
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
952
|
+
/**
|
|
953
|
+
* Returns a distinct list of all symbols used by the positions
|
|
954
|
+
* within the container.
|
|
955
|
+
*
|
|
956
|
+
* @public
|
|
957
|
+
* @param {Boolean} display - If true, all "display" symbols are returned; otherwise Barchart symbols are returned.
|
|
958
|
+
* @returns {Array.<String>}
|
|
959
|
+
*/
|
|
942
960
|
getPositionSymbols(display) {
|
|
943
961
|
const symbols = this._items.reduce((symbols, item) => {
|
|
944
962
|
const position = item.position;
|
|
@@ -961,6 +979,14 @@ module.exports = (() => {
|
|
|
961
979
|
return array.unique(symbols);
|
|
962
980
|
}
|
|
963
981
|
|
|
982
|
+
/**
|
|
983
|
+
* Updates the quote for a single symbol; causing updates to any grouping
|
|
984
|
+
* level that contains the position(s) for the symbol.
|
|
985
|
+
*
|
|
986
|
+
* @public
|
|
987
|
+
* @param {String} symbol
|
|
988
|
+
* @param {Object} quote
|
|
989
|
+
*/
|
|
964
990
|
setPositionQuote(symbol, quote) {
|
|
965
991
|
assert.argumentIsRequired(symbol, 'symbol', String);
|
|
966
992
|
assert.argumentIsRequired(quote, 'quote', Object);
|
|
@@ -970,14 +996,34 @@ module.exports = (() => {
|
|
|
970
996
|
}
|
|
971
997
|
}
|
|
972
998
|
|
|
999
|
+
/**
|
|
1000
|
+
* Returns all forex symbols that are required to do currency translations.
|
|
1001
|
+
*
|
|
1002
|
+
* @public
|
|
1003
|
+
* @returns {Array.<String>}
|
|
1004
|
+
*/
|
|
973
1005
|
getForexSymbols() {
|
|
974
1006
|
return this._forexSymbols;
|
|
975
1007
|
}
|
|
976
1008
|
|
|
1009
|
+
/**
|
|
1010
|
+
* Returns all current forex quotes.
|
|
1011
|
+
*
|
|
1012
|
+
* @public
|
|
1013
|
+
* @returns {Array.<Object>}
|
|
1014
|
+
*/
|
|
977
1015
|
getForexQuotes() {
|
|
978
1016
|
return this._forexQuotes;
|
|
979
1017
|
}
|
|
980
1018
|
|
|
1019
|
+
/**
|
|
1020
|
+
* Updates the forex quote for a single currency pair; causing updates to
|
|
1021
|
+
* any grouping level that contains that requires translation.
|
|
1022
|
+
*
|
|
1023
|
+
* @public
|
|
1024
|
+
* @param {String} symbol
|
|
1025
|
+
* @param {Object} quote
|
|
1026
|
+
*/
|
|
981
1027
|
setForexQuote(symbol, quote) {
|
|
982
1028
|
assert.argumentIsRequired(symbol, 'symbol', String);
|
|
983
1029
|
assert.argumentIsRequired(quote, 'quote', Object);
|
|
@@ -995,10 +1041,50 @@ module.exports = (() => {
|
|
|
995
1041
|
Object.keys(this._trees).forEach(key => this._trees[key].walk(group => group.setForexRate(rate), true, false));
|
|
996
1042
|
}
|
|
997
1043
|
|
|
998
|
-
|
|
1044
|
+
/**
|
|
1045
|
+
* Updates fundamental data for a single symbol.
|
|
1046
|
+
*
|
|
1047
|
+
* @public
|
|
1048
|
+
* @param {String} symbol
|
|
1049
|
+
* @param {Object} data
|
|
1050
|
+
*/
|
|
1051
|
+
setPositionFundamentalData(symbol, data) {
|
|
999
1052
|
return;
|
|
1000
1053
|
}
|
|
1001
1054
|
|
|
1055
|
+
/**
|
|
1056
|
+
* Indicates if a news article exists for a symbol.
|
|
1057
|
+
*
|
|
1058
|
+
* @public
|
|
1059
|
+
* @param {String} symbol
|
|
1060
|
+
* @param {Boolean} display
|
|
1061
|
+
* @param {Boolean} exists
|
|
1062
|
+
*/
|
|
1063
|
+
setNewsArticleExists(symbol, display, exists) {
|
|
1064
|
+
assert.argumentIsRequired(symbol, 'symbol', String);
|
|
1065
|
+
assert.argumentIsRequired(display, 'display', Boolean);
|
|
1066
|
+
assert.argumentIsRequired(exists, 'exists', Boolean);
|
|
1067
|
+
|
|
1068
|
+
let map;
|
|
1069
|
+
|
|
1070
|
+
if (display) {
|
|
1071
|
+
map = this._symbols;
|
|
1072
|
+
} else {
|
|
1073
|
+
map = this._symbolsDisplay;
|
|
1074
|
+
}
|
|
1075
|
+
|
|
1076
|
+
if (map.hasOwnProperty(symbol)) {
|
|
1077
|
+
map[symbol].forEach(item => item.setNewsArticleExists(exists));
|
|
1078
|
+
}
|
|
1079
|
+
}
|
|
1080
|
+
|
|
1081
|
+
/**
|
|
1082
|
+
* Returns a single level of grouping from one of the internal trees.
|
|
1083
|
+
*
|
|
1084
|
+
* @param {String} name
|
|
1085
|
+
* @param {Array.<String> keys
|
|
1086
|
+
* @returns {PositionGroup}
|
|
1087
|
+
*/
|
|
1002
1088
|
getGroup(name, keys) {
|
|
1003
1089
|
assert.argumentIsRequired(name, 'name', String);
|
|
1004
1090
|
assert.argumentIsArray(keys, 'keys', Number);
|
|
@@ -1006,6 +1092,14 @@ module.exports = (() => {
|
|
|
1006
1092
|
return findNode(this._trees[name], keys).getValue();
|
|
1007
1093
|
}
|
|
1008
1094
|
|
|
1095
|
+
/**
|
|
1096
|
+
* Returns all child groups from a level of grouping within one of
|
|
1097
|
+
* the internal trees.
|
|
1098
|
+
*
|
|
1099
|
+
* @param {String} name
|
|
1100
|
+
* @param {Array.<String> keys
|
|
1101
|
+
* @returns {Array.<PositionGroup>}
|
|
1102
|
+
*/
|
|
1009
1103
|
getGroups(name, keys) {
|
|
1010
1104
|
assert.argumentIsRequired(name, 'name', String);
|
|
1011
1105
|
assert.argumentIsArray(keys, 'keys', Number);
|
|
@@ -1017,8 +1111,6 @@ module.exports = (() => {
|
|
|
1017
1111
|
assert.argumentIsRequired(name, 'name', String);
|
|
1018
1112
|
assert.argumentIsRequired(executor, 'executor', Function);
|
|
1019
1113
|
|
|
1020
|
-
assert.argumentIsRequired(executor, 'executor', Function);
|
|
1021
|
-
|
|
1022
1114
|
this._trees[name].walk(group => group.setSuspended(true), false, false);
|
|
1023
1115
|
|
|
1024
1116
|
executor(this);
|
|
@@ -1072,7 +1164,17 @@ module.exports = (() => {
|
|
|
1072
1164
|
'use strict';
|
|
1073
1165
|
|
|
1074
1166
|
/**
|
|
1167
|
+
* A grouping of {@link PositionItem} instances. The group aggregates from across
|
|
1168
|
+
* all the positions and performs currency translation, as necessary.
|
|
1169
|
+
*
|
|
1075
1170
|
* @public
|
|
1171
|
+
* @param {PositionContainer} container
|
|
1172
|
+
* @param {PositionGroup|null} parent
|
|
1173
|
+
* @param {Array.<PositionItem>} items
|
|
1174
|
+
* @param {Currency} currency
|
|
1175
|
+
* @param {String} key
|
|
1176
|
+
* @param {String} description
|
|
1177
|
+
* @param {Boolean=} single
|
|
1076
1178
|
*/
|
|
1077
1179
|
class PositionGroup {
|
|
1078
1180
|
constructor(container, parent, items, currency, key, description, single) {
|
|
@@ -1092,15 +1194,22 @@ module.exports = (() => {
|
|
|
1092
1194
|
this._suspended = false;
|
|
1093
1195
|
|
|
1094
1196
|
this._marketPercentChangeEvent = new Event(this);
|
|
1197
|
+
this._excludedChangeEvent = new Event(this);
|
|
1095
1198
|
|
|
1096
1199
|
this._dataFormat = { };
|
|
1097
1200
|
this._dataActual = { };
|
|
1098
1201
|
|
|
1099
1202
|
this._dataFormat.key = this._key;
|
|
1100
1203
|
this._dataFormat.description = this._description;
|
|
1101
|
-
this._dataFormat.
|
|
1102
|
-
|
|
1204
|
+
this._dataFormat.newsExists = false;
|
|
1103
1205
|
this._dataFormat.quantity = null;
|
|
1206
|
+
this._dataFormat.basisPrice = null;
|
|
1207
|
+
|
|
1208
|
+
this._dataActual.key = this._key;
|
|
1209
|
+
this._dataActual.description = this._description;
|
|
1210
|
+
this._dataActual.newsExists = false;
|
|
1211
|
+
this._dataActual.quantity = null;
|
|
1212
|
+
this._dataActual.basisPrice = null;
|
|
1104
1213
|
|
|
1105
1214
|
if (this._single) {
|
|
1106
1215
|
const item = items[0];
|
|
@@ -1179,35 +1288,85 @@ module.exports = (() => {
|
|
|
1179
1288
|
|
|
1180
1289
|
calculatePriceData(this, this._container.getForexQuotes(), sender, false);
|
|
1181
1290
|
});
|
|
1291
|
+
|
|
1292
|
+
if (this._single) {
|
|
1293
|
+
item.registerNewsExistsChangeHandler((exists, sender) => {
|
|
1294
|
+
this._dataFormat.newsExists = exists;
|
|
1295
|
+
this._dataFormat.newsExists = exists;
|
|
1296
|
+
});
|
|
1297
|
+
}
|
|
1182
1298
|
});
|
|
1183
1299
|
|
|
1184
1300
|
this.refresh();
|
|
1185
1301
|
}
|
|
1186
1302
|
|
|
1303
|
+
/**
|
|
1304
|
+
* The key of the group.
|
|
1305
|
+
*
|
|
1306
|
+
* @public
|
|
1307
|
+
* @returns {String}
|
|
1308
|
+
*/
|
|
1187
1309
|
get key() {
|
|
1188
1310
|
return this._key;
|
|
1189
1311
|
}
|
|
1190
1312
|
|
|
1313
|
+
/**
|
|
1314
|
+
* The description of the group.
|
|
1315
|
+
*
|
|
1316
|
+
* @public
|
|
1317
|
+
* @returns {String}
|
|
1318
|
+
*/
|
|
1191
1319
|
get description() {
|
|
1192
1320
|
return this._description;
|
|
1193
1321
|
}
|
|
1194
1322
|
|
|
1323
|
+
/**
|
|
1324
|
+
* The {@link Currency} which all aggregated data is presented in.
|
|
1325
|
+
*
|
|
1326
|
+
* @public
|
|
1327
|
+
* @returns {Currency}
|
|
1328
|
+
*/
|
|
1195
1329
|
get currency() {
|
|
1196
1330
|
return this._currency;
|
|
1197
1331
|
}
|
|
1198
1332
|
|
|
1333
|
+
/**
|
|
1334
|
+
* The {@link PositionItem} instances which for which aggregated data is compiled.
|
|
1335
|
+
*
|
|
1336
|
+
* @public
|
|
1337
|
+
* @returns {Currency}
|
|
1338
|
+
*/
|
|
1199
1339
|
get items() {
|
|
1200
1340
|
return this._items;
|
|
1201
1341
|
}
|
|
1202
1342
|
|
|
1343
|
+
/**
|
|
1344
|
+
* The string-based, human-readable aggregated data for the group.
|
|
1345
|
+
*
|
|
1346
|
+
* @public
|
|
1347
|
+
* @returns {Object}
|
|
1348
|
+
*/
|
|
1203
1349
|
get data() {
|
|
1204
1350
|
return this._dataFormat;
|
|
1205
1351
|
}
|
|
1206
1352
|
|
|
1353
|
+
/**
|
|
1354
|
+
* The raw aggregated data for the group (typically {@link Decimal} instances).
|
|
1355
|
+
*
|
|
1356
|
+
* @public
|
|
1357
|
+
* @returns {Object}
|
|
1358
|
+
*/
|
|
1207
1359
|
get actual() {
|
|
1208
1360
|
return this._dataActual;
|
|
1209
1361
|
}
|
|
1210
1362
|
|
|
1363
|
+
/**
|
|
1364
|
+
* Indicates if the group will only contain one {@link PositionItem} -- that is,
|
|
1365
|
+
* indicates if the group represents a single position.
|
|
1366
|
+
*
|
|
1367
|
+
* @public
|
|
1368
|
+
* @returns {Boolean}
|
|
1369
|
+
*/
|
|
1211
1370
|
get single() {
|
|
1212
1371
|
return this._single;
|
|
1213
1372
|
}
|
|
@@ -1216,10 +1375,22 @@ module.exports = (() => {
|
|
|
1216
1375
|
return this._suspended;
|
|
1217
1376
|
}
|
|
1218
1377
|
|
|
1378
|
+
/**
|
|
1379
|
+
* Indicates if the group should be excluded from higher-level aggregations.
|
|
1380
|
+
*
|
|
1381
|
+
* @public
|
|
1382
|
+
* @returns {Boolean}
|
|
1383
|
+
*/
|
|
1219
1384
|
get excluded() {
|
|
1220
1385
|
return this._excluded;
|
|
1221
1386
|
}
|
|
1222
1387
|
|
|
1388
|
+
/**
|
|
1389
|
+
* Causes aggregated data to be recalculated using a new exchange rate.
|
|
1390
|
+
*
|
|
1391
|
+
* @public
|
|
1392
|
+
* @param {Rate} rate
|
|
1393
|
+
*/
|
|
1223
1394
|
setForexRate(rate) {
|
|
1224
1395
|
if (!this._bypassCurrencyTranslation) {
|
|
1225
1396
|
this.refresh();
|
|
@@ -1230,11 +1401,7 @@ module.exports = (() => {
|
|
|
1230
1401
|
assert.argumentIsRequired(value, 'value', Boolean);
|
|
1231
1402
|
|
|
1232
1403
|
if (this._excluded !== value) {
|
|
1233
|
-
this.
|
|
1234
|
-
this._items.forEach((item) => {
|
|
1235
|
-
item.setExcluded(value);
|
|
1236
|
-
});
|
|
1237
|
-
});
|
|
1404
|
+
this._excludedChangeEvent(this._excluded = value);
|
|
1238
1405
|
}
|
|
1239
1406
|
}
|
|
1240
1407
|
|
|
@@ -1248,6 +1415,11 @@ module.exports = (() => {
|
|
|
1248
1415
|
}
|
|
1249
1416
|
}
|
|
1250
1417
|
|
|
1418
|
+
/**
|
|
1419
|
+
* Causes all aggregated data to be recalculated.
|
|
1420
|
+
*
|
|
1421
|
+
* @public
|
|
1422
|
+
*/
|
|
1251
1423
|
refresh() {
|
|
1252
1424
|
const rates = this._container.getForexQuotes();
|
|
1253
1425
|
|
|
@@ -1255,6 +1427,12 @@ module.exports = (() => {
|
|
|
1255
1427
|
calculatePriceData(this, rates, null, true);
|
|
1256
1428
|
}
|
|
1257
1429
|
|
|
1430
|
+
/**
|
|
1431
|
+
* Causes the percent of the position, with respect to the parent container's
|
|
1432
|
+
* total, to be recalculated.
|
|
1433
|
+
*
|
|
1434
|
+
* @public
|
|
1435
|
+
*/
|
|
1258
1436
|
refreshMarketPercent() {
|
|
1259
1437
|
calculateMarketPercent(this, this._container.getForexQuotes(), true);
|
|
1260
1438
|
}
|
|
@@ -1308,7 +1486,7 @@ module.exports = (() => {
|
|
|
1308
1486
|
|
|
1309
1487
|
const items = group._items;
|
|
1310
1488
|
|
|
1311
|
-
group._bypassCurrencyTranslation = items.
|
|
1489
|
+
group._bypassCurrencyTranslation = items.every(item => item.currency === currency);
|
|
1312
1490
|
|
|
1313
1491
|
const translate = (item, value) => {
|
|
1314
1492
|
let translated;
|
|
@@ -1360,8 +1538,11 @@ module.exports = (() => {
|
|
|
1360
1538
|
if (group.single) {
|
|
1361
1539
|
const item = group._items[0];
|
|
1362
1540
|
|
|
1363
|
-
|
|
1364
|
-
|
|
1541
|
+
actual.quantity = item.position.snapshot.open;
|
|
1542
|
+
actual.basisPrice = item.data.basisPrice;
|
|
1543
|
+
|
|
1544
|
+
format.quantity = formatDecimal(actual.quantity, 2);
|
|
1545
|
+
format.basisPrice = formatCurrency(actual.basisPrice, currency);
|
|
1365
1546
|
}
|
|
1366
1547
|
}
|
|
1367
1548
|
|
|
@@ -1535,7 +1716,15 @@ module.exports = (() => {
|
|
|
1535
1716
|
'use strict';
|
|
1536
1717
|
|
|
1537
1718
|
/**
|
|
1719
|
+
* A container for a single position, which handles quote changes and
|
|
1720
|
+
* notifies observers -- which are typically parent-level {@link PositionGroup}
|
|
1721
|
+
* instances.
|
|
1722
|
+
*
|
|
1538
1723
|
* @public
|
|
1724
|
+
* @param {Object} portfolio
|
|
1725
|
+
* @param {Object} position
|
|
1726
|
+
* @param {Object} currentSummary
|
|
1727
|
+
* @param {Array.<Object>} previousSummaries
|
|
1539
1728
|
*/
|
|
1540
1729
|
class PositionItem {
|
|
1541
1730
|
constructor(portfolio, position, currentSummary, previousSummaries) {
|
|
@@ -1551,10 +1740,12 @@ module.exports = (() => {
|
|
|
1551
1740
|
this._data.basis = null;
|
|
1552
1741
|
|
|
1553
1742
|
this._currentQuote = null;
|
|
1554
|
-
|
|
1743
|
+
|
|
1744
|
+
this._currentPrice = null;
|
|
1745
|
+
this._previousPrice = null;
|
|
1555
1746
|
|
|
1556
1747
|
this._data.currentPrice = null;
|
|
1557
|
-
this._data.
|
|
1748
|
+
this._data.currentPricePrevious = null;
|
|
1558
1749
|
|
|
1559
1750
|
this._data.market = null;
|
|
1560
1751
|
this._data.marketChange = null;
|
|
@@ -1574,74 +1765,141 @@ module.exports = (() => {
|
|
|
1574
1765
|
this._data.income = null;
|
|
1575
1766
|
this._data.basisPrice = null;
|
|
1576
1767
|
|
|
1577
|
-
this.
|
|
1768
|
+
this._data.newsExists = false;
|
|
1578
1769
|
|
|
1579
1770
|
calculateStaticData(this);
|
|
1580
1771
|
calculatePriceData(this, null);
|
|
1581
1772
|
|
|
1582
1773
|
this._quoteChangedEvent = new Event(this);
|
|
1583
|
-
this.
|
|
1774
|
+
this._newsExistsChangedEvent = new Event(this);
|
|
1584
1775
|
}
|
|
1585
1776
|
|
|
1777
|
+
/**
|
|
1778
|
+
* The portfolio of the encapsulated position.
|
|
1779
|
+
*
|
|
1780
|
+
* @public
|
|
1781
|
+
* @returns {Object}
|
|
1782
|
+
*/
|
|
1586
1783
|
get portfolio() {
|
|
1587
1784
|
return this._portfolio;
|
|
1588
1785
|
}
|
|
1589
1786
|
|
|
1787
|
+
/**
|
|
1788
|
+
* The encapsulated position.
|
|
1789
|
+
*
|
|
1790
|
+
* @public
|
|
1791
|
+
* @returns {Object}
|
|
1792
|
+
*/
|
|
1590
1793
|
get position() {
|
|
1591
1794
|
return this._position;
|
|
1592
1795
|
}
|
|
1593
1796
|
|
|
1797
|
+
/**
|
|
1798
|
+
* The {@link Currency} of the encapsulated position.
|
|
1799
|
+
*
|
|
1800
|
+
* @public
|
|
1801
|
+
* @returns {Object}
|
|
1802
|
+
*/
|
|
1594
1803
|
get currency() {
|
|
1595
1804
|
return this._currency;
|
|
1596
1805
|
}
|
|
1597
1806
|
|
|
1807
|
+
/**
|
|
1808
|
+
* The year-to-date position summary of the encapsulated position.
|
|
1809
|
+
*
|
|
1810
|
+
* @public
|
|
1811
|
+
* @returns {Object}
|
|
1812
|
+
*/
|
|
1598
1813
|
get currentSummary() {
|
|
1599
1814
|
return this._currentSummary;
|
|
1600
1815
|
}
|
|
1601
|
-
|
|
1816
|
+
|
|
1817
|
+
/**
|
|
1818
|
+
* Previous year's summaries for the encapsulated position.
|
|
1819
|
+
*
|
|
1820
|
+
* @public
|
|
1821
|
+
* @returns {Object}
|
|
1822
|
+
*/
|
|
1602
1823
|
get previousSummaries() {
|
|
1603
1824
|
return this._previousSummaries;
|
|
1604
1825
|
}
|
|
1605
1826
|
|
|
1827
|
+
/**
|
|
1828
|
+
* Various data regarding the encapsulated position.
|
|
1829
|
+
*
|
|
1830
|
+
* @public
|
|
1831
|
+
* @returns {*}
|
|
1832
|
+
*/
|
|
1606
1833
|
get data() {
|
|
1607
1834
|
return this._data;
|
|
1608
1835
|
}
|
|
1609
1836
|
|
|
1837
|
+
/**
|
|
1838
|
+
* The current quote for the symbol of the encapsulated position.
|
|
1839
|
+
*
|
|
1840
|
+
* @public
|
|
1841
|
+
* @returns {null|{Object}}
|
|
1842
|
+
*/
|
|
1610
1843
|
get quote() {
|
|
1611
1844
|
return this._currentQuote;
|
|
1612
1845
|
}
|
|
1613
1846
|
|
|
1614
|
-
|
|
1615
|
-
|
|
1616
|
-
|
|
1617
|
-
|
|
1847
|
+
/**
|
|
1848
|
+
* Sets the current quote -- causing position-level data (e.g. market value) to
|
|
1849
|
+
* be recalculated.
|
|
1850
|
+
*
|
|
1851
|
+
* @public
|
|
1852
|
+
* @param {Object} quote
|
|
1853
|
+
*/
|
|
1618
1854
|
setQuote(quote) {
|
|
1619
1855
|
assert.argumentIsRequired(quote, 'quote', Object);
|
|
1620
1856
|
|
|
1621
|
-
if (this.
|
|
1857
|
+
if (this._currentPricePrevious !== quote.lastPrice) {
|
|
1622
1858
|
calculatePriceData(this, quote.lastPrice);
|
|
1623
1859
|
|
|
1624
|
-
this.
|
|
1860
|
+
this._currentPricePrevious = this._currentPrice;
|
|
1861
|
+
this._currentPrice = quote.lastPrice;
|
|
1862
|
+
|
|
1625
1863
|
this._currentQuote = quote;
|
|
1626
1864
|
|
|
1627
1865
|
this._quoteChangedEvent.fire(this._currentQuote);
|
|
1628
1866
|
}
|
|
1629
1867
|
}
|
|
1630
1868
|
|
|
1631
|
-
|
|
1869
|
+
/**
|
|
1870
|
+
* Sets a flag which indicates if news article(s) exist for the encapsulated position's
|
|
1871
|
+
* symbol.
|
|
1872
|
+
*
|
|
1873
|
+
* @public
|
|
1874
|
+
* @param {Boolean} value
|
|
1875
|
+
*/
|
|
1876
|
+
setNewsArticleExists(value) {
|
|
1632
1877
|
assert.argumentIsRequired(value, 'value', Boolean);
|
|
1633
1878
|
|
|
1634
|
-
if (this.
|
|
1635
|
-
this.
|
|
1879
|
+
if (this._data.newsExists !== value) {
|
|
1880
|
+
this._newsExistsChangedEvent.fire(this._data.newsExists = value);
|
|
1636
1881
|
}
|
|
1637
1882
|
}
|
|
1638
1883
|
|
|
1884
|
+
/**
|
|
1885
|
+
* Registers an observer for quote changes, which is fired after internal recalculations
|
|
1886
|
+
* of position data are complete.
|
|
1887
|
+
*
|
|
1888
|
+
* @public
|
|
1889
|
+
* @param {Function} handler
|
|
1890
|
+
*/
|
|
1639
1891
|
registerQuoteChangeHandler(handler) {
|
|
1640
1892
|
this._quoteChangedEvent.register(handler);
|
|
1641
1893
|
}
|
|
1642
1894
|
|
|
1643
|
-
|
|
1644
|
-
|
|
1895
|
+
/**
|
|
1896
|
+
* Registers an observer changes to the status of news existence.
|
|
1897
|
+
*
|
|
1898
|
+
* @public
|
|
1899
|
+
* @param {Function} handler
|
|
1900
|
+
*/
|
|
1901
|
+
registerNewsExistsChangeHandler(handler) {
|
|
1902
|
+
this._newsExistsChangedEvent.register(handler);
|
|
1645
1903
|
}
|
|
1646
1904
|
|
|
1647
1905
|
toString() {
|