@barchart/portfolio-api-common 1.0.130 → 1.0.134
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 -14
- package/lib/processing/PositionGroup.js +85 -6
- package/lib/processing/PositionItem.js +109 -23
- package/package.json +1 -1
- package/test/SpecRunner.js +296 -43
|
@@ -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,19 +325,55 @@ 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
|
-
|
|
283
|
-
|
|
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) {
|
|
336
|
+
assert.argumentIsRequired(symbol, 'symbol', String);
|
|
337
|
+
assert.argumentIsRequired(data, 'data', Object);
|
|
338
|
+
|
|
339
|
+
if (this._symbols.hasOwnProperty(symbol)) {
|
|
340
|
+
this._symbols[symbol].forEach(item => item.setPositionFundamentalData(data));
|
|
341
|
+
}
|
|
284
342
|
}
|
|
285
343
|
|
|
286
|
-
|
|
344
|
+
/**
|
|
345
|
+
* Indicates if a news article exists for a symbol.
|
|
346
|
+
*
|
|
347
|
+
* @public
|
|
348
|
+
* @param {String} symbol
|
|
349
|
+
* @param {Boolean} display
|
|
350
|
+
* @param {Boolean} exists
|
|
351
|
+
*/
|
|
352
|
+
setNewsArticleExists(symbol, display, exists) {
|
|
287
353
|
assert.argumentIsRequired(symbol, 'symbol', String);
|
|
354
|
+
assert.argumentIsRequired(display, 'display', Boolean);
|
|
288
355
|
assert.argumentIsRequired(exists, 'exists', Boolean);
|
|
289
356
|
|
|
290
|
-
|
|
291
|
-
|
|
357
|
+
let map;
|
|
358
|
+
|
|
359
|
+
if (display) {
|
|
360
|
+
map = this._symbolsDisplay;
|
|
361
|
+
} else {
|
|
362
|
+
map = this._symbols;
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
if (map.hasOwnProperty(symbol)) {
|
|
366
|
+
map[symbol].forEach(item => item.setNewsArticleExists(exists));
|
|
292
367
|
}
|
|
293
368
|
}
|
|
294
369
|
|
|
370
|
+
/**
|
|
371
|
+
* Returns a single level of grouping from one of the internal trees.
|
|
372
|
+
*
|
|
373
|
+
* @param {String} name
|
|
374
|
+
* @param {Array.<String> keys
|
|
375
|
+
* @returns {PositionGroup}
|
|
376
|
+
*/
|
|
295
377
|
getGroup(name, keys) {
|
|
296
378
|
assert.argumentIsRequired(name, 'name', String);
|
|
297
379
|
assert.argumentIsArray(keys, 'keys', Number);
|
|
@@ -299,6 +381,14 @@ module.exports = (() => {
|
|
|
299
381
|
return findNode(this._trees[name], keys).getValue();
|
|
300
382
|
}
|
|
301
383
|
|
|
384
|
+
/**
|
|
385
|
+
* Returns all child groups from a level of grouping within one of
|
|
386
|
+
* the internal trees.
|
|
387
|
+
*
|
|
388
|
+
* @param {String} name
|
|
389
|
+
* @param {Array.<String> keys
|
|
390
|
+
* @returns {Array.<PositionGroup>}
|
|
391
|
+
*/
|
|
302
392
|
getGroups(name, keys) {
|
|
303
393
|
assert.argumentIsRequired(name, 'name', String);
|
|
304
394
|
assert.argumentIsArray(keys, 'keys', Number);
|
|
@@ -310,8 +400,6 @@ module.exports = (() => {
|
|
|
310
400
|
assert.argumentIsRequired(name, 'name', String);
|
|
311
401
|
assert.argumentIsRequired(executor, 'executor', Function);
|
|
312
402
|
|
|
313
|
-
assert.argumentIsRequired(executor, 'executor', Function);
|
|
314
|
-
|
|
315
403
|
this._trees[name].walk(group => group.setSuspended(true), false, false);
|
|
316
404
|
|
|
317
405
|
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,6 +40,7 @@ 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 = { };
|
|
@@ -52,10 +63,12 @@ module.exports = (() => {
|
|
|
52
63
|
this._dataFormat.portfolio = item.portfolio.portfolio;
|
|
53
64
|
this._dataFormat.position = item.position.position;
|
|
54
65
|
this._dataFormat.instrument = item.position.instrument;
|
|
66
|
+
this._dataFormat.fundamental = item.fundamental || { };
|
|
55
67
|
} else {
|
|
56
68
|
this._dataFormat.portfolio = null;
|
|
57
69
|
this._dataFormat.position = null;
|
|
58
70
|
this._dataFormat.instrument = null;
|
|
71
|
+
this._dataFormat.fundamental = { };
|
|
59
72
|
}
|
|
60
73
|
|
|
61
74
|
this._dataFormat.quoteLast = null;
|
|
@@ -126,8 +139,12 @@ module.exports = (() => {
|
|
|
126
139
|
|
|
127
140
|
if (this._single) {
|
|
128
141
|
item.registerNewsExistsChangeHandler((exists, sender) => {
|
|
142
|
+
this._dataActual.newsExists = exists;
|
|
129
143
|
this._dataFormat.newsExists = exists;
|
|
130
|
-
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
item._fundamentalDataChangeEvent((data, sender) => {
|
|
147
|
+
this._dataFormat.fundamental = data;
|
|
131
148
|
});
|
|
132
149
|
}
|
|
133
150
|
});
|
|
@@ -135,30 +152,73 @@ module.exports = (() => {
|
|
|
135
152
|
this.refresh();
|
|
136
153
|
}
|
|
137
154
|
|
|
155
|
+
/**
|
|
156
|
+
* The key of the group.
|
|
157
|
+
*
|
|
158
|
+
* @public
|
|
159
|
+
* @returns {String}
|
|
160
|
+
*/
|
|
138
161
|
get key() {
|
|
139
162
|
return this._key;
|
|
140
163
|
}
|
|
141
164
|
|
|
165
|
+
/**
|
|
166
|
+
* The description of the group.
|
|
167
|
+
*
|
|
168
|
+
* @public
|
|
169
|
+
* @returns {String}
|
|
170
|
+
*/
|
|
142
171
|
get description() {
|
|
143
172
|
return this._description;
|
|
144
173
|
}
|
|
145
174
|
|
|
175
|
+
/**
|
|
176
|
+
* The {@link Currency} which all aggregated data is presented in.
|
|
177
|
+
*
|
|
178
|
+
* @public
|
|
179
|
+
* @returns {Currency}
|
|
180
|
+
*/
|
|
146
181
|
get currency() {
|
|
147
182
|
return this._currency;
|
|
148
183
|
}
|
|
149
184
|
|
|
185
|
+
/**
|
|
186
|
+
* The {@link PositionItem} instances which for which aggregated data is compiled.
|
|
187
|
+
*
|
|
188
|
+
* @public
|
|
189
|
+
* @returns {Currency}
|
|
190
|
+
*/
|
|
150
191
|
get items() {
|
|
151
192
|
return this._items;
|
|
152
193
|
}
|
|
153
194
|
|
|
195
|
+
/**
|
|
196
|
+
* The string-based, human-readable aggregated data for the group.
|
|
197
|
+
*
|
|
198
|
+
* @public
|
|
199
|
+
* @returns {Object}
|
|
200
|
+
*/
|
|
154
201
|
get data() {
|
|
155
202
|
return this._dataFormat;
|
|
156
203
|
}
|
|
157
204
|
|
|
205
|
+
/**
|
|
206
|
+
* The raw aggregated data for the group (typically {@link Decimal} instances).
|
|
207
|
+
*
|
|
208
|
+
* @public
|
|
209
|
+
* @returns {Object}
|
|
210
|
+
*/
|
|
158
211
|
get actual() {
|
|
159
212
|
return this._dataActual;
|
|
160
213
|
}
|
|
161
214
|
|
|
215
|
+
/**
|
|
216
|
+
* Indicates if the group will only contain one {@link PositionItem} -- that is,
|
|
217
|
+
* indicates if the group represents a single position.
|
|
218
|
+
*
|
|
219
|
+
* @public
|
|
220
|
+
* @returns {Boolean}
|
|
221
|
+
*/
|
|
162
222
|
get single() {
|
|
163
223
|
return this._single;
|
|
164
224
|
}
|
|
@@ -167,10 +227,22 @@ module.exports = (() => {
|
|
|
167
227
|
return this._suspended;
|
|
168
228
|
}
|
|
169
229
|
|
|
230
|
+
/**
|
|
231
|
+
* Indicates if the group should be excluded from higher-level aggregations.
|
|
232
|
+
*
|
|
233
|
+
* @public
|
|
234
|
+
* @returns {Boolean}
|
|
235
|
+
*/
|
|
170
236
|
get excluded() {
|
|
171
237
|
return this._excluded;
|
|
172
238
|
}
|
|
173
239
|
|
|
240
|
+
/**
|
|
241
|
+
* Causes aggregated data to be recalculated using a new exchange rate.
|
|
242
|
+
*
|
|
243
|
+
* @public
|
|
244
|
+
* @param {Rate} rate
|
|
245
|
+
*/
|
|
174
246
|
setForexRate(rate) {
|
|
175
247
|
if (!this._bypassCurrencyTranslation) {
|
|
176
248
|
this.refresh();
|
|
@@ -181,11 +253,7 @@ module.exports = (() => {
|
|
|
181
253
|
assert.argumentIsRequired(value, 'value', Boolean);
|
|
182
254
|
|
|
183
255
|
if (this._excluded !== value) {
|
|
184
|
-
this.
|
|
185
|
-
this._items.forEach((item) => {
|
|
186
|
-
item.setExcluded(value);
|
|
187
|
-
});
|
|
188
|
-
});
|
|
256
|
+
this._excludedChangeEvent(this._excluded = value);
|
|
189
257
|
}
|
|
190
258
|
}
|
|
191
259
|
|
|
@@ -199,6 +267,11 @@ module.exports = (() => {
|
|
|
199
267
|
}
|
|
200
268
|
}
|
|
201
269
|
|
|
270
|
+
/**
|
|
271
|
+
* Causes all aggregated data to be recalculated.
|
|
272
|
+
*
|
|
273
|
+
* @public
|
|
274
|
+
*/
|
|
202
275
|
refresh() {
|
|
203
276
|
const rates = this._container.getForexQuotes();
|
|
204
277
|
|
|
@@ -206,6 +279,12 @@ module.exports = (() => {
|
|
|
206
279
|
calculatePriceData(this, rates, null, true);
|
|
207
280
|
}
|
|
208
281
|
|
|
282
|
+
/**
|
|
283
|
+
* Causes the percent of the position, with respect to the parent container's
|
|
284
|
+
* total, to be recalculated.
|
|
285
|
+
*
|
|
286
|
+
* @public
|
|
287
|
+
*/
|
|
209
288
|
refreshMarketPercent() {
|
|
210
289
|
calculateMarketPercent(this, this._container.getForexQuotes(), true);
|
|
211
290
|
}
|
|
@@ -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;
|
|
@@ -40,7 +50,7 @@ module.exports = (() => {
|
|
|
40
50
|
|
|
41
51
|
this._data.unrealized = null;
|
|
42
52
|
this._data.unrealizedChange = null;
|
|
43
|
-
|
|
53
|
+
|
|
44
54
|
this._data.summaryTotalCurrent = null;
|
|
45
55
|
this._data.summaryTotalCurrentChange = null;
|
|
46
56
|
|
|
@@ -51,70 +61,127 @@ module.exports = (() => {
|
|
|
51
61
|
this._data.basisPrice = null;
|
|
52
62
|
|
|
53
63
|
this._data.newsExists = false;
|
|
54
|
-
|
|
55
|
-
this._excluded = false;
|
|
64
|
+
this._data.fundamental = { };
|
|
56
65
|
|
|
57
66
|
calculateStaticData(this);
|
|
58
67
|
calculatePriceData(this, null);
|
|
59
68
|
|
|
60
69
|
this._quoteChangedEvent = new Event(this);
|
|
61
|
-
this._excludedChangeEvent = new Event(this);
|
|
62
70
|
this._newsExistsChangedEvent = new Event(this);
|
|
71
|
+
this._fundamentalDataChangeEvent = new Event(this);
|
|
63
72
|
}
|
|
64
73
|
|
|
74
|
+
/**
|
|
75
|
+
* The portfolio of the encapsulated position.
|
|
76
|
+
*
|
|
77
|
+
* @public
|
|
78
|
+
* @returns {Object}
|
|
79
|
+
*/
|
|
65
80
|
get portfolio() {
|
|
66
81
|
return this._portfolio;
|
|
67
82
|
}
|
|
68
83
|
|
|
84
|
+
/**
|
|
85
|
+
* The encapsulated position.
|
|
86
|
+
*
|
|
87
|
+
* @public
|
|
88
|
+
* @returns {Object}
|
|
89
|
+
*/
|
|
69
90
|
get position() {
|
|
70
91
|
return this._position;
|
|
71
92
|
}
|
|
72
93
|
|
|
94
|
+
/**
|
|
95
|
+
* The {@link Currency} of the encapsulated position.
|
|
96
|
+
*
|
|
97
|
+
* @public
|
|
98
|
+
* @returns {Object}
|
|
99
|
+
*/
|
|
73
100
|
get currency() {
|
|
74
101
|
return this._currency;
|
|
75
102
|
}
|
|
76
103
|
|
|
104
|
+
/**
|
|
105
|
+
* The year-to-date position summary of the encapsulated position.
|
|
106
|
+
*
|
|
107
|
+
* @public
|
|
108
|
+
* @returns {Object}
|
|
109
|
+
*/
|
|
77
110
|
get currentSummary() {
|
|
78
111
|
return this._currentSummary;
|
|
79
112
|
}
|
|
80
|
-
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Previous year's summaries for the encapsulated position.
|
|
116
|
+
*
|
|
117
|
+
* @public
|
|
118
|
+
* @returns {Object}
|
|
119
|
+
*/
|
|
81
120
|
get previousSummaries() {
|
|
82
121
|
return this._previousSummaries;
|
|
83
122
|
}
|
|
84
123
|
|
|
124
|
+
/**
|
|
125
|
+
* Various data regarding the encapsulated position.
|
|
126
|
+
*
|
|
127
|
+
* @public
|
|
128
|
+
* @returns {*}
|
|
129
|
+
*/
|
|
85
130
|
get data() {
|
|
86
131
|
return this._data;
|
|
87
132
|
}
|
|
88
133
|
|
|
134
|
+
/**
|
|
135
|
+
* The current quote for the symbol of the encapsulated position.
|
|
136
|
+
*
|
|
137
|
+
* @public
|
|
138
|
+
* @returns {null|{Object}}
|
|
139
|
+
*/
|
|
89
140
|
get quote() {
|
|
90
141
|
return this._currentQuote;
|
|
91
142
|
}
|
|
92
143
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
144
|
+
/**
|
|
145
|
+
* Sets the current quote -- causing position-level data (e.g. market value) to
|
|
146
|
+
* be recalculated.
|
|
147
|
+
*
|
|
148
|
+
* @public
|
|
149
|
+
* @param {Object} quote
|
|
150
|
+
*/
|
|
97
151
|
setQuote(quote) {
|
|
98
152
|
assert.argumentIsRequired(quote, 'quote', Object);
|
|
99
153
|
|
|
100
|
-
if (this.
|
|
154
|
+
if (this._currentPricePrevious !== quote.lastPrice) {
|
|
101
155
|
calculatePriceData(this, quote.lastPrice);
|
|
102
156
|
|
|
103
|
-
this.
|
|
157
|
+
this._currentPricePrevious = this._currentPrice;
|
|
158
|
+
this._currentPrice = quote.lastPrice;
|
|
159
|
+
|
|
104
160
|
this._currentQuote = quote;
|
|
105
161
|
|
|
106
162
|
this._quoteChangedEvent.fire(this._currentQuote);
|
|
107
163
|
}
|
|
108
164
|
}
|
|
109
165
|
|
|
110
|
-
|
|
111
|
-
|
|
166
|
+
/**
|
|
167
|
+
* Sets fundamental data for the position.
|
|
168
|
+
*
|
|
169
|
+
* @public
|
|
170
|
+
* @param {Object} data
|
|
171
|
+
*/
|
|
172
|
+
setPositionFundamentalData(data) {
|
|
173
|
+
assert.argumentIsRequired(data, 'data', Object);
|
|
112
174
|
|
|
113
|
-
|
|
114
|
-
this._excludedChangeEvent.fire(this._excluded = value);
|
|
115
|
-
}
|
|
175
|
+
this._fundamentalDataChangeEvent(this._data.fundamental = data);
|
|
116
176
|
}
|
|
117
177
|
|
|
178
|
+
/**
|
|
179
|
+
* Sets a flag which indicates if news article(s) exist for the encapsulated position's
|
|
180
|
+
* symbol.
|
|
181
|
+
*
|
|
182
|
+
* @public
|
|
183
|
+
* @param {Boolean} value
|
|
184
|
+
*/
|
|
118
185
|
setNewsArticleExists(value) {
|
|
119
186
|
assert.argumentIsRequired(value, 'value', Boolean);
|
|
120
187
|
|
|
@@ -123,14 +190,33 @@ module.exports = (() => {
|
|
|
123
190
|
}
|
|
124
191
|
}
|
|
125
192
|
|
|
193
|
+
/**
|
|
194
|
+
* Registers an observer for quote changes, which is fired after internal recalculations
|
|
195
|
+
* of position data are complete.
|
|
196
|
+
*
|
|
197
|
+
* @public
|
|
198
|
+
* @param {Function} handler
|
|
199
|
+
*/
|
|
126
200
|
registerQuoteChangeHandler(handler) {
|
|
127
201
|
this._quoteChangedEvent.register(handler);
|
|
128
202
|
}
|
|
129
203
|
|
|
130
|
-
|
|
131
|
-
|
|
204
|
+
/**
|
|
205
|
+
* Registers an observer for fundamental data changes.
|
|
206
|
+
*
|
|
207
|
+
* @public
|
|
208
|
+
* @param {Function} handler
|
|
209
|
+
*/
|
|
210
|
+
registerFundamentalDataChangeHandler(handler) {
|
|
211
|
+
this._fundamentalDataChangeEvent.register(handler);
|
|
132
212
|
}
|
|
133
213
|
|
|
214
|
+
/**
|
|
215
|
+
* Registers an observer changes to the status of news existence.
|
|
216
|
+
*
|
|
217
|
+
* @public
|
|
218
|
+
* @param {Function} handler
|
|
219
|
+
*/
|
|
134
220
|
registerNewsExistsChangeHandler(handler) {
|
|
135
221
|
this._newsExistsChangedEvent.register(handler);
|
|
136
222
|
}
|
|
@@ -259,10 +345,10 @@ module.exports = (() => {
|
|
|
259
345
|
data.unrealizedChange = Decimal.ZERO;
|
|
260
346
|
}
|
|
261
347
|
}
|
|
262
|
-
|
|
348
|
+
|
|
263
349
|
function calculateSummaryTotal(summary) {
|
|
264
350
|
let returnRef;
|
|
265
|
-
|
|
351
|
+
|
|
266
352
|
if (summary) {
|
|
267
353
|
const period = summary.period;
|
|
268
354
|
|
|
@@ -270,7 +356,7 @@ module.exports = (() => {
|
|
|
270
356
|
} else {
|
|
271
357
|
returnRef = Decimal.ZERO;
|
|
272
358
|
}
|
|
273
|
-
|
|
359
|
+
|
|
274
360
|
return returnRef;
|
|
275
361
|
}
|
|
276
362
|
|
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,19 +1041,55 @@ 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
|
-
|
|
999
|
-
|
|
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) {
|
|
1052
|
+
assert.argumentIsRequired(symbol, 'symbol', String);
|
|
1053
|
+
assert.argumentIsRequired(data, 'data', Object);
|
|
1054
|
+
|
|
1055
|
+
if (this._symbols.hasOwnProperty(symbol)) {
|
|
1056
|
+
this._symbols[symbol].forEach(item => item.setPositionFundamentalData(data));
|
|
1057
|
+
}
|
|
1000
1058
|
}
|
|
1001
1059
|
|
|
1002
|
-
|
|
1060
|
+
/**
|
|
1061
|
+
* Indicates if a news article exists for a symbol.
|
|
1062
|
+
*
|
|
1063
|
+
* @public
|
|
1064
|
+
* @param {String} symbol
|
|
1065
|
+
* @param {Boolean} display
|
|
1066
|
+
* @param {Boolean} exists
|
|
1067
|
+
*/
|
|
1068
|
+
setNewsArticleExists(symbol, display, exists) {
|
|
1003
1069
|
assert.argumentIsRequired(symbol, 'symbol', String);
|
|
1070
|
+
assert.argumentIsRequired(display, 'display', Boolean);
|
|
1004
1071
|
assert.argumentIsRequired(exists, 'exists', Boolean);
|
|
1005
1072
|
|
|
1006
|
-
|
|
1007
|
-
|
|
1073
|
+
let map;
|
|
1074
|
+
|
|
1075
|
+
if (display) {
|
|
1076
|
+
map = this._symbolsDisplay;
|
|
1077
|
+
} else {
|
|
1078
|
+
map = this._symbols;
|
|
1079
|
+
}
|
|
1080
|
+
|
|
1081
|
+
if (map.hasOwnProperty(symbol)) {
|
|
1082
|
+
map[symbol].forEach(item => item.setNewsArticleExists(exists));
|
|
1008
1083
|
}
|
|
1009
1084
|
}
|
|
1010
1085
|
|
|
1086
|
+
/**
|
|
1087
|
+
* Returns a single level of grouping from one of the internal trees.
|
|
1088
|
+
*
|
|
1089
|
+
* @param {String} name
|
|
1090
|
+
* @param {Array.<String> keys
|
|
1091
|
+
* @returns {PositionGroup}
|
|
1092
|
+
*/
|
|
1011
1093
|
getGroup(name, keys) {
|
|
1012
1094
|
assert.argumentIsRequired(name, 'name', String);
|
|
1013
1095
|
assert.argumentIsArray(keys, 'keys', Number);
|
|
@@ -1015,6 +1097,14 @@ module.exports = (() => {
|
|
|
1015
1097
|
return findNode(this._trees[name], keys).getValue();
|
|
1016
1098
|
}
|
|
1017
1099
|
|
|
1100
|
+
/**
|
|
1101
|
+
* Returns all child groups from a level of grouping within one of
|
|
1102
|
+
* the internal trees.
|
|
1103
|
+
*
|
|
1104
|
+
* @param {String} name
|
|
1105
|
+
* @param {Array.<String> keys
|
|
1106
|
+
* @returns {Array.<PositionGroup>}
|
|
1107
|
+
*/
|
|
1018
1108
|
getGroups(name, keys) {
|
|
1019
1109
|
assert.argumentIsRequired(name, 'name', String);
|
|
1020
1110
|
assert.argumentIsArray(keys, 'keys', Number);
|
|
@@ -1026,8 +1116,6 @@ module.exports = (() => {
|
|
|
1026
1116
|
assert.argumentIsRequired(name, 'name', String);
|
|
1027
1117
|
assert.argumentIsRequired(executor, 'executor', Function);
|
|
1028
1118
|
|
|
1029
|
-
assert.argumentIsRequired(executor, 'executor', Function);
|
|
1030
|
-
|
|
1031
1119
|
this._trees[name].walk(group => group.setSuspended(true), false, false);
|
|
1032
1120
|
|
|
1033
1121
|
executor(this);
|
|
@@ -1081,7 +1169,17 @@ module.exports = (() => {
|
|
|
1081
1169
|
'use strict';
|
|
1082
1170
|
|
|
1083
1171
|
/**
|
|
1172
|
+
* A grouping of {@link PositionItem} instances. The group aggregates from across
|
|
1173
|
+
* all the positions and performs currency translation, as necessary.
|
|
1174
|
+
*
|
|
1084
1175
|
* @public
|
|
1176
|
+
* @param {PositionContainer} container
|
|
1177
|
+
* @param {PositionGroup|null} parent
|
|
1178
|
+
* @param {Array.<PositionItem>} items
|
|
1179
|
+
* @param {Currency} currency
|
|
1180
|
+
* @param {String} key
|
|
1181
|
+
* @param {String} description
|
|
1182
|
+
* @param {Boolean=} single
|
|
1085
1183
|
*/
|
|
1086
1184
|
class PositionGroup {
|
|
1087
1185
|
constructor(container, parent, items, currency, key, description, single) {
|
|
@@ -1101,6 +1199,7 @@ module.exports = (() => {
|
|
|
1101
1199
|
this._suspended = false;
|
|
1102
1200
|
|
|
1103
1201
|
this._marketPercentChangeEvent = new Event(this);
|
|
1202
|
+
this._excludedChangeEvent = new Event(this);
|
|
1104
1203
|
|
|
1105
1204
|
this._dataFormat = { };
|
|
1106
1205
|
this._dataActual = { };
|
|
@@ -1123,10 +1222,12 @@ module.exports = (() => {
|
|
|
1123
1222
|
this._dataFormat.portfolio = item.portfolio.portfolio;
|
|
1124
1223
|
this._dataFormat.position = item.position.position;
|
|
1125
1224
|
this._dataFormat.instrument = item.position.instrument;
|
|
1225
|
+
this._dataFormat.fundamental = item.fundamental || { };
|
|
1126
1226
|
} else {
|
|
1127
1227
|
this._dataFormat.portfolio = null;
|
|
1128
1228
|
this._dataFormat.position = null;
|
|
1129
1229
|
this._dataFormat.instrument = null;
|
|
1230
|
+
this._dataFormat.fundamental = { };
|
|
1130
1231
|
}
|
|
1131
1232
|
|
|
1132
1233
|
this._dataFormat.quoteLast = null;
|
|
@@ -1197,8 +1298,12 @@ module.exports = (() => {
|
|
|
1197
1298
|
|
|
1198
1299
|
if (this._single) {
|
|
1199
1300
|
item.registerNewsExistsChangeHandler((exists, sender) => {
|
|
1301
|
+
this._dataActual.newsExists = exists;
|
|
1200
1302
|
this._dataFormat.newsExists = exists;
|
|
1201
|
-
|
|
1303
|
+
});
|
|
1304
|
+
|
|
1305
|
+
item._fundamentalDataChangeEvent((data, sender) => {
|
|
1306
|
+
this._dataFormat.fundamental = data;
|
|
1202
1307
|
});
|
|
1203
1308
|
}
|
|
1204
1309
|
});
|
|
@@ -1206,30 +1311,73 @@ module.exports = (() => {
|
|
|
1206
1311
|
this.refresh();
|
|
1207
1312
|
}
|
|
1208
1313
|
|
|
1314
|
+
/**
|
|
1315
|
+
* The key of the group.
|
|
1316
|
+
*
|
|
1317
|
+
* @public
|
|
1318
|
+
* @returns {String}
|
|
1319
|
+
*/
|
|
1209
1320
|
get key() {
|
|
1210
1321
|
return this._key;
|
|
1211
1322
|
}
|
|
1212
1323
|
|
|
1324
|
+
/**
|
|
1325
|
+
* The description of the group.
|
|
1326
|
+
*
|
|
1327
|
+
* @public
|
|
1328
|
+
* @returns {String}
|
|
1329
|
+
*/
|
|
1213
1330
|
get description() {
|
|
1214
1331
|
return this._description;
|
|
1215
1332
|
}
|
|
1216
1333
|
|
|
1334
|
+
/**
|
|
1335
|
+
* The {@link Currency} which all aggregated data is presented in.
|
|
1336
|
+
*
|
|
1337
|
+
* @public
|
|
1338
|
+
* @returns {Currency}
|
|
1339
|
+
*/
|
|
1217
1340
|
get currency() {
|
|
1218
1341
|
return this._currency;
|
|
1219
1342
|
}
|
|
1220
1343
|
|
|
1344
|
+
/**
|
|
1345
|
+
* The {@link PositionItem} instances which for which aggregated data is compiled.
|
|
1346
|
+
*
|
|
1347
|
+
* @public
|
|
1348
|
+
* @returns {Currency}
|
|
1349
|
+
*/
|
|
1221
1350
|
get items() {
|
|
1222
1351
|
return this._items;
|
|
1223
1352
|
}
|
|
1224
1353
|
|
|
1354
|
+
/**
|
|
1355
|
+
* The string-based, human-readable aggregated data for the group.
|
|
1356
|
+
*
|
|
1357
|
+
* @public
|
|
1358
|
+
* @returns {Object}
|
|
1359
|
+
*/
|
|
1225
1360
|
get data() {
|
|
1226
1361
|
return this._dataFormat;
|
|
1227
1362
|
}
|
|
1228
1363
|
|
|
1364
|
+
/**
|
|
1365
|
+
* The raw aggregated data for the group (typically {@link Decimal} instances).
|
|
1366
|
+
*
|
|
1367
|
+
* @public
|
|
1368
|
+
* @returns {Object}
|
|
1369
|
+
*/
|
|
1229
1370
|
get actual() {
|
|
1230
1371
|
return this._dataActual;
|
|
1231
1372
|
}
|
|
1232
1373
|
|
|
1374
|
+
/**
|
|
1375
|
+
* Indicates if the group will only contain one {@link PositionItem} -- that is,
|
|
1376
|
+
* indicates if the group represents a single position.
|
|
1377
|
+
*
|
|
1378
|
+
* @public
|
|
1379
|
+
* @returns {Boolean}
|
|
1380
|
+
*/
|
|
1233
1381
|
get single() {
|
|
1234
1382
|
return this._single;
|
|
1235
1383
|
}
|
|
@@ -1238,10 +1386,22 @@ module.exports = (() => {
|
|
|
1238
1386
|
return this._suspended;
|
|
1239
1387
|
}
|
|
1240
1388
|
|
|
1389
|
+
/**
|
|
1390
|
+
* Indicates if the group should be excluded from higher-level aggregations.
|
|
1391
|
+
*
|
|
1392
|
+
* @public
|
|
1393
|
+
* @returns {Boolean}
|
|
1394
|
+
*/
|
|
1241
1395
|
get excluded() {
|
|
1242
1396
|
return this._excluded;
|
|
1243
1397
|
}
|
|
1244
1398
|
|
|
1399
|
+
/**
|
|
1400
|
+
* Causes aggregated data to be recalculated using a new exchange rate.
|
|
1401
|
+
*
|
|
1402
|
+
* @public
|
|
1403
|
+
* @param {Rate} rate
|
|
1404
|
+
*/
|
|
1245
1405
|
setForexRate(rate) {
|
|
1246
1406
|
if (!this._bypassCurrencyTranslation) {
|
|
1247
1407
|
this.refresh();
|
|
@@ -1252,11 +1412,7 @@ module.exports = (() => {
|
|
|
1252
1412
|
assert.argumentIsRequired(value, 'value', Boolean);
|
|
1253
1413
|
|
|
1254
1414
|
if (this._excluded !== value) {
|
|
1255
|
-
this.
|
|
1256
|
-
this._items.forEach((item) => {
|
|
1257
|
-
item.setExcluded(value);
|
|
1258
|
-
});
|
|
1259
|
-
});
|
|
1415
|
+
this._excludedChangeEvent(this._excluded = value);
|
|
1260
1416
|
}
|
|
1261
1417
|
}
|
|
1262
1418
|
|
|
@@ -1270,6 +1426,11 @@ module.exports = (() => {
|
|
|
1270
1426
|
}
|
|
1271
1427
|
}
|
|
1272
1428
|
|
|
1429
|
+
/**
|
|
1430
|
+
* Causes all aggregated data to be recalculated.
|
|
1431
|
+
*
|
|
1432
|
+
* @public
|
|
1433
|
+
*/
|
|
1273
1434
|
refresh() {
|
|
1274
1435
|
const rates = this._container.getForexQuotes();
|
|
1275
1436
|
|
|
@@ -1277,6 +1438,12 @@ module.exports = (() => {
|
|
|
1277
1438
|
calculatePriceData(this, rates, null, true);
|
|
1278
1439
|
}
|
|
1279
1440
|
|
|
1441
|
+
/**
|
|
1442
|
+
* Causes the percent of the position, with respect to the parent container's
|
|
1443
|
+
* total, to be recalculated.
|
|
1444
|
+
*
|
|
1445
|
+
* @public
|
|
1446
|
+
*/
|
|
1280
1447
|
refreshMarketPercent() {
|
|
1281
1448
|
calculateMarketPercent(this, this._container.getForexQuotes(), true);
|
|
1282
1449
|
}
|
|
@@ -1560,7 +1727,15 @@ module.exports = (() => {
|
|
|
1560
1727
|
'use strict';
|
|
1561
1728
|
|
|
1562
1729
|
/**
|
|
1730
|
+
* A container for a single position, which handles quote changes and
|
|
1731
|
+
* notifies observers -- which are typically parent-level {@link PositionGroup}
|
|
1732
|
+
* instances.
|
|
1733
|
+
*
|
|
1563
1734
|
* @public
|
|
1735
|
+
* @param {Object} portfolio
|
|
1736
|
+
* @param {Object} position
|
|
1737
|
+
* @param {Object} currentSummary
|
|
1738
|
+
* @param {Array.<Object>} previousSummaries
|
|
1564
1739
|
*/
|
|
1565
1740
|
class PositionItem {
|
|
1566
1741
|
constructor(portfolio, position, currentSummary, previousSummaries) {
|
|
@@ -1576,10 +1751,12 @@ module.exports = (() => {
|
|
|
1576
1751
|
this._data.basis = null;
|
|
1577
1752
|
|
|
1578
1753
|
this._currentQuote = null;
|
|
1579
|
-
|
|
1754
|
+
|
|
1755
|
+
this._currentPrice = null;
|
|
1756
|
+
this._previousPrice = null;
|
|
1580
1757
|
|
|
1581
1758
|
this._data.currentPrice = null;
|
|
1582
|
-
this._data.
|
|
1759
|
+
this._data.currentPricePrevious = null;
|
|
1583
1760
|
|
|
1584
1761
|
this._data.market = null;
|
|
1585
1762
|
this._data.marketChange = null;
|
|
@@ -1589,7 +1766,7 @@ module.exports = (() => {
|
|
|
1589
1766
|
|
|
1590
1767
|
this._data.unrealized = null;
|
|
1591
1768
|
this._data.unrealizedChange = null;
|
|
1592
|
-
|
|
1769
|
+
|
|
1593
1770
|
this._data.summaryTotalCurrent = null;
|
|
1594
1771
|
this._data.summaryTotalCurrentChange = null;
|
|
1595
1772
|
|
|
@@ -1600,70 +1777,127 @@ module.exports = (() => {
|
|
|
1600
1777
|
this._data.basisPrice = null;
|
|
1601
1778
|
|
|
1602
1779
|
this._data.newsExists = false;
|
|
1603
|
-
|
|
1604
|
-
this._excluded = false;
|
|
1780
|
+
this._data.fundamental = { };
|
|
1605
1781
|
|
|
1606
1782
|
calculateStaticData(this);
|
|
1607
1783
|
calculatePriceData(this, null);
|
|
1608
1784
|
|
|
1609
1785
|
this._quoteChangedEvent = new Event(this);
|
|
1610
|
-
this._excludedChangeEvent = new Event(this);
|
|
1611
1786
|
this._newsExistsChangedEvent = new Event(this);
|
|
1787
|
+
this._fundamentalDataChangeEvent = new Event(this);
|
|
1612
1788
|
}
|
|
1613
1789
|
|
|
1790
|
+
/**
|
|
1791
|
+
* The portfolio of the encapsulated position.
|
|
1792
|
+
*
|
|
1793
|
+
* @public
|
|
1794
|
+
* @returns {Object}
|
|
1795
|
+
*/
|
|
1614
1796
|
get portfolio() {
|
|
1615
1797
|
return this._portfolio;
|
|
1616
1798
|
}
|
|
1617
1799
|
|
|
1800
|
+
/**
|
|
1801
|
+
* The encapsulated position.
|
|
1802
|
+
*
|
|
1803
|
+
* @public
|
|
1804
|
+
* @returns {Object}
|
|
1805
|
+
*/
|
|
1618
1806
|
get position() {
|
|
1619
1807
|
return this._position;
|
|
1620
1808
|
}
|
|
1621
1809
|
|
|
1810
|
+
/**
|
|
1811
|
+
* The {@link Currency} of the encapsulated position.
|
|
1812
|
+
*
|
|
1813
|
+
* @public
|
|
1814
|
+
* @returns {Object}
|
|
1815
|
+
*/
|
|
1622
1816
|
get currency() {
|
|
1623
1817
|
return this._currency;
|
|
1624
1818
|
}
|
|
1625
1819
|
|
|
1820
|
+
/**
|
|
1821
|
+
* The year-to-date position summary of the encapsulated position.
|
|
1822
|
+
*
|
|
1823
|
+
* @public
|
|
1824
|
+
* @returns {Object}
|
|
1825
|
+
*/
|
|
1626
1826
|
get currentSummary() {
|
|
1627
1827
|
return this._currentSummary;
|
|
1628
1828
|
}
|
|
1629
|
-
|
|
1829
|
+
|
|
1830
|
+
/**
|
|
1831
|
+
* Previous year's summaries for the encapsulated position.
|
|
1832
|
+
*
|
|
1833
|
+
* @public
|
|
1834
|
+
* @returns {Object}
|
|
1835
|
+
*/
|
|
1630
1836
|
get previousSummaries() {
|
|
1631
1837
|
return this._previousSummaries;
|
|
1632
1838
|
}
|
|
1633
1839
|
|
|
1840
|
+
/**
|
|
1841
|
+
* Various data regarding the encapsulated position.
|
|
1842
|
+
*
|
|
1843
|
+
* @public
|
|
1844
|
+
* @returns {*}
|
|
1845
|
+
*/
|
|
1634
1846
|
get data() {
|
|
1635
1847
|
return this._data;
|
|
1636
1848
|
}
|
|
1637
1849
|
|
|
1850
|
+
/**
|
|
1851
|
+
* The current quote for the symbol of the encapsulated position.
|
|
1852
|
+
*
|
|
1853
|
+
* @public
|
|
1854
|
+
* @returns {null|{Object}}
|
|
1855
|
+
*/
|
|
1638
1856
|
get quote() {
|
|
1639
1857
|
return this._currentQuote;
|
|
1640
1858
|
}
|
|
1641
1859
|
|
|
1642
|
-
|
|
1643
|
-
|
|
1644
|
-
|
|
1645
|
-
|
|
1860
|
+
/**
|
|
1861
|
+
* Sets the current quote -- causing position-level data (e.g. market value) to
|
|
1862
|
+
* be recalculated.
|
|
1863
|
+
*
|
|
1864
|
+
* @public
|
|
1865
|
+
* @param {Object} quote
|
|
1866
|
+
*/
|
|
1646
1867
|
setQuote(quote) {
|
|
1647
1868
|
assert.argumentIsRequired(quote, 'quote', Object);
|
|
1648
1869
|
|
|
1649
|
-
if (this.
|
|
1870
|
+
if (this._currentPricePrevious !== quote.lastPrice) {
|
|
1650
1871
|
calculatePriceData(this, quote.lastPrice);
|
|
1651
1872
|
|
|
1652
|
-
this.
|
|
1873
|
+
this._currentPricePrevious = this._currentPrice;
|
|
1874
|
+
this._currentPrice = quote.lastPrice;
|
|
1875
|
+
|
|
1653
1876
|
this._currentQuote = quote;
|
|
1654
1877
|
|
|
1655
1878
|
this._quoteChangedEvent.fire(this._currentQuote);
|
|
1656
1879
|
}
|
|
1657
1880
|
}
|
|
1658
1881
|
|
|
1659
|
-
|
|
1660
|
-
|
|
1882
|
+
/**
|
|
1883
|
+
* Sets fundamental data for the position.
|
|
1884
|
+
*
|
|
1885
|
+
* @public
|
|
1886
|
+
* @param {Object} data
|
|
1887
|
+
*/
|
|
1888
|
+
setPositionFundamentalData(data) {
|
|
1889
|
+
assert.argumentIsRequired(data, 'data', Object);
|
|
1661
1890
|
|
|
1662
|
-
|
|
1663
|
-
this._excludedChangeEvent.fire(this._excluded = value);
|
|
1664
|
-
}
|
|
1891
|
+
this._fundamentalDataChangeEvent(this._data.fundamental = data);
|
|
1665
1892
|
}
|
|
1666
1893
|
|
|
1894
|
+
/**
|
|
1895
|
+
* Sets a flag which indicates if news article(s) exist for the encapsulated position's
|
|
1896
|
+
* symbol.
|
|
1897
|
+
*
|
|
1898
|
+
* @public
|
|
1899
|
+
* @param {Boolean} value
|
|
1900
|
+
*/
|
|
1667
1901
|
setNewsArticleExists(value) {
|
|
1668
1902
|
assert.argumentIsRequired(value, 'value', Boolean);
|
|
1669
1903
|
|
|
@@ -1672,14 +1906,33 @@ module.exports = (() => {
|
|
|
1672
1906
|
}
|
|
1673
1907
|
}
|
|
1674
1908
|
|
|
1909
|
+
/**
|
|
1910
|
+
* Registers an observer for quote changes, which is fired after internal recalculations
|
|
1911
|
+
* of position data are complete.
|
|
1912
|
+
*
|
|
1913
|
+
* @public
|
|
1914
|
+
* @param {Function} handler
|
|
1915
|
+
*/
|
|
1675
1916
|
registerQuoteChangeHandler(handler) {
|
|
1676
1917
|
this._quoteChangedEvent.register(handler);
|
|
1677
1918
|
}
|
|
1678
1919
|
|
|
1679
|
-
|
|
1680
|
-
|
|
1920
|
+
/**
|
|
1921
|
+
* Registers an observer for fundamental data changes.
|
|
1922
|
+
*
|
|
1923
|
+
* @public
|
|
1924
|
+
* @param {Function} handler
|
|
1925
|
+
*/
|
|
1926
|
+
registerFundamentalDataChangeHandler(handler) {
|
|
1927
|
+
this._fundamentalDataChangeEvent.register(handler);
|
|
1681
1928
|
}
|
|
1682
1929
|
|
|
1930
|
+
/**
|
|
1931
|
+
* Registers an observer changes to the status of news existence.
|
|
1932
|
+
*
|
|
1933
|
+
* @public
|
|
1934
|
+
* @param {Function} handler
|
|
1935
|
+
*/
|
|
1683
1936
|
registerNewsExistsChangeHandler(handler) {
|
|
1684
1937
|
this._newsExistsChangedEvent.register(handler);
|
|
1685
1938
|
}
|
|
@@ -1808,10 +2061,10 @@ module.exports = (() => {
|
|
|
1808
2061
|
data.unrealizedChange = Decimal.ZERO;
|
|
1809
2062
|
}
|
|
1810
2063
|
}
|
|
1811
|
-
|
|
2064
|
+
|
|
1812
2065
|
function calculateSummaryTotal(summary) {
|
|
1813
2066
|
let returnRef;
|
|
1814
|
-
|
|
2067
|
+
|
|
1815
2068
|
if (summary) {
|
|
1816
2069
|
const period = summary.period;
|
|
1817
2070
|
|
|
@@ -1819,7 +2072,7 @@ module.exports = (() => {
|
|
|
1819
2072
|
} else {
|
|
1820
2073
|
returnRef = Decimal.ZERO;
|
|
1821
2074
|
}
|
|
1822
|
-
|
|
2075
|
+
|
|
1823
2076
|
return returnRef;
|
|
1824
2077
|
}
|
|
1825
2078
|
|