@barchart/portfolio-api-common 1.0.161 → 1.0.165
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 +194 -113
- package/lib/processing/PositionGroup.js +24 -1
- package/lib/processing/definitions/PositionLevelDefinition.js +99 -2
- package/lib/processing/definitions/PositionTreeDefinition.js +1 -1
- package/package.json +1 -1
- package/test/SpecRunner.js +335 -148
|
@@ -48,17 +48,9 @@ module.exports = (() => {
|
|
|
48
48
|
const currentSummaryFrame = PositionSummaryFrame.YTD;
|
|
49
49
|
const currentSummaryRange = array.last(currentSummaryFrame.getRecentRanges(0));
|
|
50
50
|
|
|
51
|
-
this.
|
|
52
|
-
|
|
53
|
-
const addGroupBinding = (group, dispoable) => {
|
|
54
|
-
const id = group.id;
|
|
55
|
-
|
|
56
|
-
if (!this._groupBindings.hasOwnProperty(id)) {
|
|
57
|
-
this._groupBindings[id] = new DisposableStack();
|
|
58
|
-
}
|
|
51
|
+
this._definitions = definitions;
|
|
59
52
|
|
|
60
|
-
|
|
61
|
-
};
|
|
53
|
+
this._groupBindings = { };
|
|
62
54
|
|
|
63
55
|
this._portfolios = portfolios.reduce((map, portfolio) => {
|
|
64
56
|
map[portfolio.portfolio] = portfolio;
|
|
@@ -164,132 +156,82 @@ module.exports = (() => {
|
|
|
164
156
|
return Rate.fromPair(Decimal.ONE, symbol);
|
|
165
157
|
});
|
|
166
158
|
|
|
167
|
-
this._trees =
|
|
159
|
+
this._trees = this._definitions.reduce((map, treeDefinition) => {
|
|
168
160
|
const tree = new Tree();
|
|
169
161
|
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
const parent = currentTree.getValue() || null;
|
|
176
|
-
|
|
177
|
-
const levelDefinition = levelDefinitions[0];
|
|
178
|
-
|
|
179
|
-
const populatedObjects = array.groupBy(items, levelDefinition.keySelector);
|
|
180
|
-
const populatedGroups = Object.keys(populatedObjects).reduce((list, key) => {
|
|
181
|
-
const items = populatedObjects[key];
|
|
182
|
-
const first = items[0];
|
|
162
|
+
createGroups.call(this, tree, tree, this._items, treeDefinition, treeDefinition.definitions);
|
|
163
|
+
|
|
164
|
+
map[treeDefinition.name] = tree;
|
|
183
165
|
|
|
184
|
-
|
|
166
|
+
return map;
|
|
167
|
+
}, { });
|
|
168
|
+
}
|
|
185
169
|
|
|
186
|
-
|
|
187
|
-
|
|
170
|
+
addPortfolio(portfolio) {
|
|
171
|
+
assert.argumentIsRequired(portfolio, 'portfolio', Object);
|
|
172
|
+
assert.argumentIsRequired(portfolio.portfolio, 'portfolio.portfolio', String);
|
|
173
|
+
assert.argumentIsRequired(portfolio.name, 'portfolio.name', String);
|
|
188
174
|
|
|
189
|
-
|
|
190
|
-
.map((key) => {
|
|
191
|
-
return levelDefinition.requiredGroups.find(g => g.key === key);
|
|
192
|
-
});
|
|
175
|
+
const key = portfolio.portfolio;
|
|
193
176
|
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
});
|
|
177
|
+
if (!this._portfolios.hasOwnProperty(key)) {
|
|
178
|
+
this._portfolios[key] = portfolio;
|
|
197
179
|
|
|
198
|
-
|
|
180
|
+
this._definitions.forEach((treeDefinition) => {
|
|
181
|
+
const tree = this._trees[treeDefinition.name];
|
|
182
|
+
const levelDefinitions = treeDefinition.definitions;
|
|
199
183
|
|
|
200
|
-
let
|
|
184
|
+
let portfolioRequiredGroup = null;
|
|
201
185
|
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
map[group.description] = index;
|
|
186
|
+
let portfolioLevelDefinition = null;
|
|
187
|
+
let portfolioLevelDefinitionIndex = null;
|
|
205
188
|
|
|
206
|
-
|
|
207
|
-
|
|
189
|
+
levelDefinitions.forEach((levelDefinition, i) => {
|
|
190
|
+
if (portfolioRequiredGroup === null) {
|
|
191
|
+
portfolioRequiredGroup = levelDefinition.generateRequiredGroup(portfolio);
|
|
208
192
|
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
} else {
|
|
213
|
-
return Number.MAX_VALUE;
|
|
193
|
+
if (portfolioRequiredGroup !== null) {
|
|
194
|
+
portfolioLevelDefinition = levelDefinition;
|
|
195
|
+
portfolioLevelDefinitionIndex = i;
|
|
214
196
|
}
|
|
215
|
-
}
|
|
197
|
+
}
|
|
198
|
+
});
|
|
216
199
|
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
}).thenBy((a, b) => {
|
|
220
|
-
return comparators.compareStrings(a.description, b.description);
|
|
221
|
-
});
|
|
222
|
-
} else {
|
|
223
|
-
builder = ComparatorBuilder.startWith((a, b) => {
|
|
224
|
-
return comparators.compareStrings(a.description, b.description);
|
|
225
|
-
});
|
|
226
|
-
}
|
|
200
|
+
if (portfolioRequiredGroup !== null) {
|
|
201
|
+
let parentTrees = [ ];
|
|
227
202
|
|
|
228
|
-
|
|
203
|
+
if (portfolioLevelDefinitionIndex === 0) {
|
|
204
|
+
parentTrees.push(tree);
|
|
205
|
+
} else {
|
|
206
|
+
const parentLevelDefinition = levelDefinitions[ portfolioLevelDefinitionIndex - 1 ];
|
|
229
207
|
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
208
|
+
tree.walk((group, groupTree) => {
|
|
209
|
+
if (group.definition === parentLevelDefinition) {
|
|
210
|
+
parentTrees.push(groupTree);
|
|
211
|
+
}
|
|
212
|
+
});
|
|
213
|
+
}
|
|
235
214
|
|
|
236
|
-
|
|
237
|
-
if (childGroup.excluded) {
|
|
238
|
-
excludedItems = excludedItems.concat(childGroup.items);
|
|
239
|
-
}
|
|
240
|
-
}, false, false);
|
|
215
|
+
const overrideRequiredGroups = [ portfolioRequiredGroup ];
|
|
241
216
|
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
trees.push(this._trees[name]);
|
|
250
|
-
}
|
|
251
|
-
|
|
252
|
-
return trees;
|
|
253
|
-
}, [ ]);
|
|
254
|
-
|
|
255
|
-
if (dependantTrees.length > 0) {
|
|
256
|
-
let excludedItems = [ ];
|
|
257
|
-
|
|
258
|
-
tree.walk((childGroup) => {
|
|
259
|
-
if (childGroup.excluded) {
|
|
260
|
-
excludedItems = excludedItems.concat(childGroup.items);
|
|
261
|
-
}
|
|
262
|
-
}, false, false);
|
|
263
|
-
|
|
264
|
-
dependantTrees.forEach((dependantTrees) => {
|
|
265
|
-
dependantTrees.walk((childGroup) => {
|
|
266
|
-
childGroup.setExcludedItems(excludedItems);
|
|
267
|
-
}, false, false);
|
|
268
|
-
});
|
|
269
|
-
}
|
|
270
|
-
}
|
|
271
|
-
}));
|
|
272
|
-
};
|
|
217
|
+
parentTrees.forEach((t) => {
|
|
218
|
+
createGroups.call(this, tree, t, [ ], treeDefinition, levelDefinitions.slice(portfolioLevelDefinitionIndex), overrideRequiredGroups);
|
|
219
|
+
});
|
|
220
|
+
}
|
|
221
|
+
});
|
|
222
|
+
}
|
|
223
|
+
}
|
|
273
224
|
|
|
274
|
-
|
|
275
|
-
const childTree = currentTree.addChild(group);
|
|
225
|
+
removePortfolio(portfolio) {
|
|
276
226
|
|
|
277
|
-
|
|
227
|
+
}
|
|
278
228
|
|
|
279
|
-
|
|
280
|
-
currentTree.walk((childGroup) => childGroup.refreshMarketPercent());
|
|
281
|
-
}));
|
|
229
|
+
mutatePosition(position, summary) {
|
|
282
230
|
|
|
283
|
-
|
|
284
|
-
});
|
|
285
|
-
};
|
|
231
|
+
}
|
|
286
232
|
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
map[treeDefinition.name] = tree;
|
|
233
|
+
removePosition(position) {
|
|
290
234
|
|
|
291
|
-
return map;
|
|
292
|
-
}, { });
|
|
293
235
|
}
|
|
294
236
|
|
|
295
237
|
/**
|
|
@@ -466,6 +408,16 @@ module.exports = (() => {
|
|
|
466
408
|
return findNode(this._trees[name], keys).getChildren().map(node => node.getValue());
|
|
467
409
|
}
|
|
468
410
|
|
|
411
|
+
/**
|
|
412
|
+
* Returns all portfolios in the container
|
|
413
|
+
*
|
|
414
|
+
* @public
|
|
415
|
+
* @return {Array.<Object>}
|
|
416
|
+
*/
|
|
417
|
+
getPortfolios() {
|
|
418
|
+
return this._portfolios;
|
|
419
|
+
}
|
|
420
|
+
|
|
469
421
|
/**
|
|
470
422
|
* Returns all positions for the given portfolio.
|
|
471
423
|
*
|
|
@@ -523,5 +475,134 @@ module.exports = (() => {
|
|
|
523
475
|
}
|
|
524
476
|
}
|
|
525
477
|
|
|
478
|
+
function addGroupBinding(group, dispoable) {
|
|
479
|
+
const id = group.id;
|
|
480
|
+
|
|
481
|
+
if (!this._groupBindings.hasOwnProperty(id)) {
|
|
482
|
+
this._groupBindings[id] = new DisposableStack();
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
this._groupBindings[id].push(dispoable);
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
function createGroups(parentTree, currentTree, items, treeDefinition, levelDefinitions, overrideRequiredGroups) {
|
|
489
|
+
if (levelDefinitions.length === 0) {
|
|
490
|
+
return;
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
const parent = currentTree.getValue() || null;
|
|
494
|
+
|
|
495
|
+
const levelDefinition = levelDefinitions[0];
|
|
496
|
+
|
|
497
|
+
const populatedObjects = array.groupBy(items, levelDefinition.keySelector);
|
|
498
|
+
const populatedGroups = Object.keys(populatedObjects).reduce((list, key) => {
|
|
499
|
+
const items = populatedObjects[key];
|
|
500
|
+
const first = items[0];
|
|
501
|
+
|
|
502
|
+
list.push(new PositionGroup(this, parent, levelDefinition, items, levelDefinition.currencySelector(first), key, levelDefinition.descriptionSelector(first), levelDefinition.single && items.length === 1, levelDefinition.aggregateCash));
|
|
503
|
+
|
|
504
|
+
return list;
|
|
505
|
+
}, [ ]);
|
|
506
|
+
|
|
507
|
+
const requiredGroupsToUse = overrideRequiredGroups || levelDefinition.requiredGroups;
|
|
508
|
+
|
|
509
|
+
const missingGroups = array.difference(requiredGroupsToUse.map(group => group.key), populatedGroups.map(group => group.key))
|
|
510
|
+
.map((key) => {
|
|
511
|
+
return requiredGroupsToUse.find(g => g.key === key);
|
|
512
|
+
});
|
|
513
|
+
|
|
514
|
+
const empty = missingGroups.map((group) => {
|
|
515
|
+
return new PositionGroup(this, parent, levelDefinition, [ ], group.currency, group.key, group.description);
|
|
516
|
+
});
|
|
517
|
+
|
|
518
|
+
const compositeGroups = populatedGroups.concat(empty);
|
|
519
|
+
|
|
520
|
+
let builder;
|
|
521
|
+
|
|
522
|
+
if (requiredGroupsToUse.length !== 0) {
|
|
523
|
+
const ordering = requiredGroupsToUse.reduce((map, group, index) => {
|
|
524
|
+
map[group.description] = index;
|
|
525
|
+
|
|
526
|
+
return map;
|
|
527
|
+
}, { });
|
|
528
|
+
|
|
529
|
+
const getIndex = (description) => {
|
|
530
|
+
if (ordering.hasOwnProperty(description)) {
|
|
531
|
+
return ordering[description];
|
|
532
|
+
} else {
|
|
533
|
+
return Number.MAX_VALUE;
|
|
534
|
+
}
|
|
535
|
+
};
|
|
536
|
+
|
|
537
|
+
builder = ComparatorBuilder.startWith((a, b) => {
|
|
538
|
+
return comparators.compareNumbers(getIndex(a.description), getIndex(b.description));
|
|
539
|
+
}).thenBy((a, b) => {
|
|
540
|
+
return comparators.compareStrings(a.description, b.description);
|
|
541
|
+
});
|
|
542
|
+
} else {
|
|
543
|
+
builder = ComparatorBuilder.startWith((a, b) => {
|
|
544
|
+
return comparators.compareStrings(a.description, b.description);
|
|
545
|
+
});
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
compositeGroups.sort(builder.toComparator());
|
|
549
|
+
|
|
550
|
+
const initializeGroupObservers = (group, groupTree) => {
|
|
551
|
+
addGroupBinding.call(this, group, group.registerGroupExcludedChangeHandler((excluded, sender) => {
|
|
552
|
+
groupTree.climb((parentGroup) => {
|
|
553
|
+
if (parentGroup) {
|
|
554
|
+
let excludedItems = [];
|
|
555
|
+
|
|
556
|
+
currentTree.walk((childGroup) => {
|
|
557
|
+
if (childGroup.excluded) {
|
|
558
|
+
excludedItems = excludedItems.concat(childGroup.items);
|
|
559
|
+
}
|
|
560
|
+
}, false, false);
|
|
561
|
+
|
|
562
|
+
parentGroup.setExcludedItems(array.unique(excludedItems));
|
|
563
|
+
}
|
|
564
|
+
}, false);
|
|
565
|
+
|
|
566
|
+
if (treeDefinition.exclusionDependencies.length > 0) {
|
|
567
|
+
const dependantTrees = treeDefinition.exclusionDependencies.reduce((trees, name) => {
|
|
568
|
+
if (this._trees.hasOwnProperty(name)) {
|
|
569
|
+
trees.push(this._trees[name]);
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
return trees;
|
|
573
|
+
}, [ ]);
|
|
574
|
+
|
|
575
|
+
if (dependantTrees.length > 0) {
|
|
576
|
+
let excludedItems = [ ];
|
|
577
|
+
|
|
578
|
+
parentTree.walk((childGroup) => {
|
|
579
|
+
if (childGroup.excluded) {
|
|
580
|
+
excludedItems = excludedItems.concat(childGroup.items);
|
|
581
|
+
}
|
|
582
|
+
}, false, false);
|
|
583
|
+
|
|
584
|
+
dependantTrees.forEach((dependantTrees) => {
|
|
585
|
+
dependantTrees.walk((childGroup) => {
|
|
586
|
+
childGroup.setExcludedItems(excludedItems);
|
|
587
|
+
}, false, false);
|
|
588
|
+
});
|
|
589
|
+
}
|
|
590
|
+
}
|
|
591
|
+
}));
|
|
592
|
+
};
|
|
593
|
+
|
|
594
|
+
compositeGroups.forEach((group) => {
|
|
595
|
+
const childTree = currentTree.addChild(group);
|
|
596
|
+
|
|
597
|
+
initializeGroupObservers(group, childTree);
|
|
598
|
+
|
|
599
|
+
addGroupBinding.call(this, group, group.registerMarketPercentChangeHandler(() => {
|
|
600
|
+
currentTree.walk((childGroup) => childGroup.refreshMarketPercent());
|
|
601
|
+
}));
|
|
602
|
+
|
|
603
|
+
createGroups.call(this, parentTree, childTree, group.items, treeDefinition, array.dropLeft(levelDefinitions));
|
|
604
|
+
});
|
|
605
|
+
}
|
|
606
|
+
|
|
526
607
|
return PositionContainer;
|
|
527
608
|
})();
|
|
@@ -22,6 +22,7 @@ module.exports = (() => {
|
|
|
22
22
|
* @public
|
|
23
23
|
* @param {PositionContainer} container
|
|
24
24
|
* @param {PositionGroup|null} parent
|
|
25
|
+
* @param {LevelDefinition} definition
|
|
25
26
|
* @param {Array.<PositionItem>} items
|
|
26
27
|
* @param {Currency} currency
|
|
27
28
|
* @param {String} key
|
|
@@ -30,8 +31,10 @@ module.exports = (() => {
|
|
|
30
31
|
* @param {Boolean=} aggregateCash
|
|
31
32
|
*/
|
|
32
33
|
class PositionGroup {
|
|
33
|
-
constructor(container, parent, items, currency, key, description, single, aggregateCash) {
|
|
34
|
+
constructor(container, parent, definition, items, currency, key, description, single, aggregateCash) {
|
|
34
35
|
this._id = counter++;
|
|
36
|
+
|
|
37
|
+
this._definition = definition;
|
|
35
38
|
this._container = container;
|
|
36
39
|
this._parent = parent || null;
|
|
37
40
|
|
|
@@ -209,6 +212,16 @@ module.exports = (() => {
|
|
|
209
212
|
return this._id;
|
|
210
213
|
}
|
|
211
214
|
|
|
215
|
+
/**
|
|
216
|
+
* The {@link LevelDefinition} which was used to generate this group.
|
|
217
|
+
*
|
|
218
|
+
* @public
|
|
219
|
+
* @returns {LevelDefinition}
|
|
220
|
+
*/
|
|
221
|
+
get definition() {
|
|
222
|
+
return this._definition;
|
|
223
|
+
}
|
|
224
|
+
|
|
212
225
|
/**
|
|
213
226
|
* The key of the group.
|
|
214
227
|
*
|
|
@@ -294,6 +307,16 @@ module.exports = (() => {
|
|
|
294
307
|
return this._excluded;
|
|
295
308
|
}
|
|
296
309
|
|
|
310
|
+
addItems(items) {
|
|
311
|
+
|
|
312
|
+
this.refresh();
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
removeItems(items) {
|
|
316
|
+
|
|
317
|
+
this.refresh();
|
|
318
|
+
}
|
|
319
|
+
|
|
297
320
|
/**
|
|
298
321
|
* Sets the list of items which are excluded from group aggregation calculations.
|
|
299
322
|
*
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
const assert = require('@barchart/common-js/lang/assert'),
|
|
2
|
+
Currency = require('@barchart/common-js/lang/Currency'),
|
|
2
3
|
is = require('@barchart/common-js/lang/is');
|
|
3
4
|
|
|
5
|
+
const InstrumentType = require('./../../data/InstrumentType');
|
|
6
|
+
|
|
4
7
|
module.exports = (() => {
|
|
5
8
|
'use strict';
|
|
6
9
|
|
|
@@ -15,12 +18,12 @@ module.exports = (() => {
|
|
|
15
18
|
* @param {PositionLevelDefinition~descriptionSelector} descriptionSelector
|
|
16
19
|
* @param {PositionLevelDefinition~currencySelector} currencySelector
|
|
17
20
|
* @param {Array.<PositionLevelDefinition~RequiredGroup>=} requiredGroups
|
|
18
|
-
* @param {Array.<PositionLevelDefinition~RequiredGroup>=} requiredGroups
|
|
19
21
|
* @param {Boolean=} single
|
|
20
22
|
* @param {Boolean=} aggregateCash
|
|
23
|
+
* @param {Function=} injectPositions
|
|
21
24
|
*/
|
|
22
25
|
class PositionLevelDefinition {
|
|
23
|
-
constructor(name, keySelector, descriptionSelector, currencySelector, requiredGroups, single, aggregateCash) {
|
|
26
|
+
constructor(name, keySelector, descriptionSelector, currencySelector, requiredGroups, single, aggregateCash, requiredGroupGenerator) {
|
|
24
27
|
assert.argumentIsRequired(name, 'name', String);
|
|
25
28
|
assert.argumentIsRequired(keySelector, 'keySelector', Function);
|
|
26
29
|
assert.argumentIsRequired(descriptionSelector, 'descriptionSelector', Function);
|
|
@@ -32,6 +35,7 @@ module.exports = (() => {
|
|
|
32
35
|
|
|
33
36
|
assert.argumentIsOptional(single, 'single', Boolean);
|
|
34
37
|
assert.argumentIsOptional(aggregateCash, 'aggregateCash', Boolean);
|
|
38
|
+
assert.argumentIsOptional(requiredGroupGenerator, 'requiredGroupGenerator', Function);
|
|
35
39
|
|
|
36
40
|
this._name = name;
|
|
37
41
|
|
|
@@ -40,8 +44,11 @@ module.exports = (() => {
|
|
|
40
44
|
this._currencySelector = currencySelector;
|
|
41
45
|
|
|
42
46
|
this._requiredGroups = requiredGroups || [ ];
|
|
47
|
+
|
|
43
48
|
this._single = is.boolean(single) && single;
|
|
44
49
|
this._aggregateCash = is.boolean(aggregateCash) && aggregateCash;
|
|
50
|
+
|
|
51
|
+
this._requiredGroupGenerator = requiredGroupGenerator || (input => null);
|
|
45
52
|
}
|
|
46
53
|
|
|
47
54
|
/**
|
|
@@ -118,6 +125,96 @@ module.exports = (() => {
|
|
|
118
125
|
return this._aggregateCash;
|
|
119
126
|
}
|
|
120
127
|
|
|
128
|
+
/**
|
|
129
|
+
* Given an input, potentially creates a new {@link PositionLevelDefinition~RequiredGroup}.
|
|
130
|
+
*
|
|
131
|
+
* @public
|
|
132
|
+
* @param {*} input
|
|
133
|
+
* @returns {PositionLevelDefinition~RequiredGroup|null}
|
|
134
|
+
*/
|
|
135
|
+
generateRequiredGroup(input) {
|
|
136
|
+
const requiredGroup = this._requiredGroupGenerator(input);
|
|
137
|
+
|
|
138
|
+
if (requiredGroup !== null) {
|
|
139
|
+
this._requiredGroups.push(requiredGroup);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
return requiredGroup;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* Builds a {@link PositionLevelDefinition~RequiredGroup} for a portfolio.
|
|
147
|
+
*
|
|
148
|
+
* @public
|
|
149
|
+
* @static
|
|
150
|
+
* @param {Object} portfolio
|
|
151
|
+
* @return {PositionLevelDefinition~RequiredGroup}
|
|
152
|
+
*/
|
|
153
|
+
static buildRequiredGroupForPortfolio(portfolio) {
|
|
154
|
+
return {
|
|
155
|
+
key: PositionLevelDefinition.getKeyForPortfolioGroup(portfolio),
|
|
156
|
+
description: PositionLevelDefinition.getDescriptionForPortfolioGroup(portfolio),
|
|
157
|
+
currency: Currency.CAD
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
static getKeyForPortfolioGroup(portfolio) {
|
|
162
|
+
assert.argumentIsRequired(portfolio, 'portfolio', Object);
|
|
163
|
+
|
|
164
|
+
return portfolio.portfolio;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
static getDescriptionForPortfolioGroup(portfolio) {
|
|
168
|
+
assert.argumentIsRequired(portfolio, 'portfolio', Object);
|
|
169
|
+
|
|
170
|
+
return portfolio.name;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
static getRequiredGroupGeneratorForPortfolio() {
|
|
174
|
+
return (portfolio) => {
|
|
175
|
+
let requiredGroup;
|
|
176
|
+
|
|
177
|
+
if (is.object(portfolio) && is.string(portfolio.portfolio) && is.string(portfolio.name)) {
|
|
178
|
+
requiredGroup = PositionLevelDefinition.buildRequiredGroupForPortfolio(portfolio);
|
|
179
|
+
} else {
|
|
180
|
+
requiredGroup = null;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
return requiredGroup;
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* Builds a {@link PositionLevelDefinition~RequiredGroup} for an asset class.
|
|
189
|
+
*
|
|
190
|
+
* @public
|
|
191
|
+
* @static
|
|
192
|
+
* @param {InstrumentType} type
|
|
193
|
+
* @param {Currency} currency
|
|
194
|
+
* @return {PositionLevelDefinition~RequiredGroup}
|
|
195
|
+
*/
|
|
196
|
+
static buildRequiredGroupForAssetClass(type, currency) {
|
|
197
|
+
return {
|
|
198
|
+
key: PositionLevelDefinition.getKeyForAssetClassGroup(type, currency),
|
|
199
|
+
description: PositionLevelDefinition.getDescriptionForAssetClassGroup(type, currency),
|
|
200
|
+
currency: currency
|
|
201
|
+
};
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
static getKeyForAssetClassGroup(type, currency) {
|
|
205
|
+
assert.argumentIsRequired(type, 'type', InstrumentType, 'InstrumentType');
|
|
206
|
+
assert.argumentIsRequired(currency, 'currency', Currency, 'Currency');
|
|
207
|
+
|
|
208
|
+
return `${type.code}|${currency.code}`;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
static getDescriptionForAssetClassGroup(type, currency) {
|
|
212
|
+
assert.argumentIsRequired(type, 'type', InstrumentType, 'InstrumentType');
|
|
213
|
+
assert.argumentIsRequired(currency, 'currency', Currency, 'Currency');
|
|
214
|
+
|
|
215
|
+
return `${type.alternateDescription}${currency.code === 'CAD' ? '' : ` (${currency.alternateDescription})`}`;
|
|
216
|
+
}
|
|
217
|
+
|
|
121
218
|
toString() {
|
|
122
219
|
return '[PositionLevelDefinition]';
|
|
123
220
|
}
|
package/package.json
CHANGED
package/test/SpecRunner.js
CHANGED
|
@@ -764,17 +764,9 @@ module.exports = (() => {
|
|
|
764
764
|
const currentSummaryFrame = PositionSummaryFrame.YTD;
|
|
765
765
|
const currentSummaryRange = array.last(currentSummaryFrame.getRecentRanges(0));
|
|
766
766
|
|
|
767
|
-
this.
|
|
768
|
-
|
|
769
|
-
const addGroupBinding = (group, dispoable) => {
|
|
770
|
-
const id = group.id;
|
|
771
|
-
|
|
772
|
-
if (!this._groupBindings.hasOwnProperty(id)) {
|
|
773
|
-
this._groupBindings[id] = new DisposableStack();
|
|
774
|
-
}
|
|
767
|
+
this._definitions = definitions;
|
|
775
768
|
|
|
776
|
-
|
|
777
|
-
};
|
|
769
|
+
this._groupBindings = { };
|
|
778
770
|
|
|
779
771
|
this._portfolios = portfolios.reduce((map, portfolio) => {
|
|
780
772
|
map[portfolio.portfolio] = portfolio;
|
|
@@ -880,132 +872,82 @@ module.exports = (() => {
|
|
|
880
872
|
return Rate.fromPair(Decimal.ONE, symbol);
|
|
881
873
|
});
|
|
882
874
|
|
|
883
|
-
this._trees =
|
|
875
|
+
this._trees = this._definitions.reduce((map, treeDefinition) => {
|
|
884
876
|
const tree = new Tree();
|
|
885
877
|
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
}
|
|
890
|
-
|
|
891
|
-
const parent = currentTree.getValue() || null;
|
|
892
|
-
|
|
893
|
-
const levelDefinition = levelDefinitions[0];
|
|
894
|
-
|
|
895
|
-
const populatedObjects = array.groupBy(items, levelDefinition.keySelector);
|
|
896
|
-
const populatedGroups = Object.keys(populatedObjects).reduce((list, key) => {
|
|
897
|
-
const items = populatedObjects[key];
|
|
898
|
-
const first = items[0];
|
|
878
|
+
createGroups.call(this, tree, tree, this._items, treeDefinition, treeDefinition.definitions);
|
|
879
|
+
|
|
880
|
+
map[treeDefinition.name] = tree;
|
|
899
881
|
|
|
900
|
-
|
|
882
|
+
return map;
|
|
883
|
+
}, { });
|
|
884
|
+
}
|
|
901
885
|
|
|
902
|
-
|
|
903
|
-
|
|
886
|
+
addPortfolio(portfolio) {
|
|
887
|
+
assert.argumentIsRequired(portfolio, 'portfolio', Object);
|
|
888
|
+
assert.argumentIsRequired(portfolio.portfolio, 'portfolio.portfolio', String);
|
|
889
|
+
assert.argumentIsRequired(portfolio.name, 'portfolio.name', String);
|
|
904
890
|
|
|
905
|
-
|
|
906
|
-
.map((key) => {
|
|
907
|
-
return levelDefinition.requiredGroups.find(g => g.key === key);
|
|
908
|
-
});
|
|
891
|
+
const key = portfolio.portfolio;
|
|
909
892
|
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
});
|
|
893
|
+
if (!this._portfolios.hasOwnProperty(key)) {
|
|
894
|
+
this._portfolios[key] = portfolio;
|
|
913
895
|
|
|
914
|
-
|
|
896
|
+
this._definitions.forEach((treeDefinition) => {
|
|
897
|
+
const tree = this._trees[treeDefinition.name];
|
|
898
|
+
const levelDefinitions = treeDefinition.definitions;
|
|
915
899
|
|
|
916
|
-
let
|
|
900
|
+
let portfolioRequiredGroup = null;
|
|
917
901
|
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
map[group.description] = index;
|
|
902
|
+
let portfolioLevelDefinition = null;
|
|
903
|
+
let portfolioLevelDefinitionIndex = null;
|
|
921
904
|
|
|
922
|
-
|
|
923
|
-
|
|
905
|
+
levelDefinitions.forEach((levelDefinition, i) => {
|
|
906
|
+
if (portfolioRequiredGroup === null) {
|
|
907
|
+
portfolioRequiredGroup = levelDefinition.generateRequiredGroup(portfolio);
|
|
924
908
|
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
} else {
|
|
929
|
-
return Number.MAX_VALUE;
|
|
909
|
+
if (portfolioRequiredGroup !== null) {
|
|
910
|
+
portfolioLevelDefinition = levelDefinition;
|
|
911
|
+
portfolioLevelDefinitionIndex = i;
|
|
930
912
|
}
|
|
931
|
-
}
|
|
913
|
+
}
|
|
914
|
+
});
|
|
932
915
|
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
}).thenBy((a, b) => {
|
|
936
|
-
return comparators.compareStrings(a.description, b.description);
|
|
937
|
-
});
|
|
938
|
-
} else {
|
|
939
|
-
builder = ComparatorBuilder.startWith((a, b) => {
|
|
940
|
-
return comparators.compareStrings(a.description, b.description);
|
|
941
|
-
});
|
|
942
|
-
}
|
|
916
|
+
if (portfolioRequiredGroup !== null) {
|
|
917
|
+
let parentTrees = [ ];
|
|
943
918
|
|
|
944
|
-
|
|
919
|
+
if (portfolioLevelDefinitionIndex === 0) {
|
|
920
|
+
parentTrees.push(tree);
|
|
921
|
+
} else {
|
|
922
|
+
const parentLevelDefinition = levelDefinitions[ portfolioLevelDefinitionIndex - 1 ];
|
|
945
923
|
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
924
|
+
tree.walk((group, groupTree) => {
|
|
925
|
+
if (group.definition === parentLevelDefinition) {
|
|
926
|
+
parentTrees.push(groupTree);
|
|
927
|
+
}
|
|
928
|
+
});
|
|
929
|
+
}
|
|
951
930
|
|
|
952
|
-
|
|
953
|
-
if (childGroup.excluded) {
|
|
954
|
-
excludedItems = excludedItems.concat(childGroup.items);
|
|
955
|
-
}
|
|
956
|
-
}, false, false);
|
|
931
|
+
const overrideRequiredGroups = [ portfolioRequiredGroup ];
|
|
957
932
|
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
trees.push(this._trees[name]);
|
|
966
|
-
}
|
|
967
|
-
|
|
968
|
-
return trees;
|
|
969
|
-
}, [ ]);
|
|
970
|
-
|
|
971
|
-
if (dependantTrees.length > 0) {
|
|
972
|
-
let excludedItems = [ ];
|
|
973
|
-
|
|
974
|
-
tree.walk((childGroup) => {
|
|
975
|
-
if (childGroup.excluded) {
|
|
976
|
-
excludedItems = excludedItems.concat(childGroup.items);
|
|
977
|
-
}
|
|
978
|
-
}, false, false);
|
|
979
|
-
|
|
980
|
-
dependantTrees.forEach((dependantTrees) => {
|
|
981
|
-
dependantTrees.walk((childGroup) => {
|
|
982
|
-
childGroup.setExcludedItems(excludedItems);
|
|
983
|
-
}, false, false);
|
|
984
|
-
});
|
|
985
|
-
}
|
|
986
|
-
}
|
|
987
|
-
}));
|
|
988
|
-
};
|
|
933
|
+
parentTrees.forEach((t) => {
|
|
934
|
+
createGroups.call(this, tree, t, [ ], treeDefinition, levelDefinitions.slice(portfolioLevelDefinitionIndex), overrideRequiredGroups);
|
|
935
|
+
});
|
|
936
|
+
}
|
|
937
|
+
});
|
|
938
|
+
}
|
|
939
|
+
}
|
|
989
940
|
|
|
990
|
-
|
|
991
|
-
const childTree = currentTree.addChild(group);
|
|
941
|
+
removePortfolio(portfolio) {
|
|
992
942
|
|
|
993
|
-
|
|
943
|
+
}
|
|
994
944
|
|
|
995
|
-
|
|
996
|
-
currentTree.walk((childGroup) => childGroup.refreshMarketPercent());
|
|
997
|
-
}));
|
|
945
|
+
mutatePosition(position, summary) {
|
|
998
946
|
|
|
999
|
-
|
|
1000
|
-
});
|
|
1001
|
-
};
|
|
947
|
+
}
|
|
1002
948
|
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
map[treeDefinition.name] = tree;
|
|
949
|
+
removePosition(position) {
|
|
1006
950
|
|
|
1007
|
-
return map;
|
|
1008
|
-
}, { });
|
|
1009
951
|
}
|
|
1010
952
|
|
|
1011
953
|
/**
|
|
@@ -1182,6 +1124,16 @@ module.exports = (() => {
|
|
|
1182
1124
|
return findNode(this._trees[name], keys).getChildren().map(node => node.getValue());
|
|
1183
1125
|
}
|
|
1184
1126
|
|
|
1127
|
+
/**
|
|
1128
|
+
* Returns all portfolios in the container
|
|
1129
|
+
*
|
|
1130
|
+
* @public
|
|
1131
|
+
* @return {Array.<Object>}
|
|
1132
|
+
*/
|
|
1133
|
+
getPortfolios() {
|
|
1134
|
+
return this._portfolios;
|
|
1135
|
+
}
|
|
1136
|
+
|
|
1185
1137
|
/**
|
|
1186
1138
|
* Returns all positions for the given portfolio.
|
|
1187
1139
|
*
|
|
@@ -1239,6 +1191,135 @@ module.exports = (() => {
|
|
|
1239
1191
|
}
|
|
1240
1192
|
}
|
|
1241
1193
|
|
|
1194
|
+
function addGroupBinding(group, dispoable) {
|
|
1195
|
+
const id = group.id;
|
|
1196
|
+
|
|
1197
|
+
if (!this._groupBindings.hasOwnProperty(id)) {
|
|
1198
|
+
this._groupBindings[id] = new DisposableStack();
|
|
1199
|
+
}
|
|
1200
|
+
|
|
1201
|
+
this._groupBindings[id].push(dispoable);
|
|
1202
|
+
}
|
|
1203
|
+
|
|
1204
|
+
function createGroups(parentTree, currentTree, items, treeDefinition, levelDefinitions, overrideRequiredGroups) {
|
|
1205
|
+
if (levelDefinitions.length === 0) {
|
|
1206
|
+
return;
|
|
1207
|
+
}
|
|
1208
|
+
|
|
1209
|
+
const parent = currentTree.getValue() || null;
|
|
1210
|
+
|
|
1211
|
+
const levelDefinition = levelDefinitions[0];
|
|
1212
|
+
|
|
1213
|
+
const populatedObjects = array.groupBy(items, levelDefinition.keySelector);
|
|
1214
|
+
const populatedGroups = Object.keys(populatedObjects).reduce((list, key) => {
|
|
1215
|
+
const items = populatedObjects[key];
|
|
1216
|
+
const first = items[0];
|
|
1217
|
+
|
|
1218
|
+
list.push(new PositionGroup(this, parent, levelDefinition, items, levelDefinition.currencySelector(first), key, levelDefinition.descriptionSelector(first), levelDefinition.single && items.length === 1, levelDefinition.aggregateCash));
|
|
1219
|
+
|
|
1220
|
+
return list;
|
|
1221
|
+
}, [ ]);
|
|
1222
|
+
|
|
1223
|
+
const requiredGroupsToUse = overrideRequiredGroups || levelDefinition.requiredGroups;
|
|
1224
|
+
|
|
1225
|
+
const missingGroups = array.difference(requiredGroupsToUse.map(group => group.key), populatedGroups.map(group => group.key))
|
|
1226
|
+
.map((key) => {
|
|
1227
|
+
return requiredGroupsToUse.find(g => g.key === key);
|
|
1228
|
+
});
|
|
1229
|
+
|
|
1230
|
+
const empty = missingGroups.map((group) => {
|
|
1231
|
+
return new PositionGroup(this, parent, levelDefinition, [ ], group.currency, group.key, group.description);
|
|
1232
|
+
});
|
|
1233
|
+
|
|
1234
|
+
const compositeGroups = populatedGroups.concat(empty);
|
|
1235
|
+
|
|
1236
|
+
let builder;
|
|
1237
|
+
|
|
1238
|
+
if (requiredGroupsToUse.length !== 0) {
|
|
1239
|
+
const ordering = requiredGroupsToUse.reduce((map, group, index) => {
|
|
1240
|
+
map[group.description] = index;
|
|
1241
|
+
|
|
1242
|
+
return map;
|
|
1243
|
+
}, { });
|
|
1244
|
+
|
|
1245
|
+
const getIndex = (description) => {
|
|
1246
|
+
if (ordering.hasOwnProperty(description)) {
|
|
1247
|
+
return ordering[description];
|
|
1248
|
+
} else {
|
|
1249
|
+
return Number.MAX_VALUE;
|
|
1250
|
+
}
|
|
1251
|
+
};
|
|
1252
|
+
|
|
1253
|
+
builder = ComparatorBuilder.startWith((a, b) => {
|
|
1254
|
+
return comparators.compareNumbers(getIndex(a.description), getIndex(b.description));
|
|
1255
|
+
}).thenBy((a, b) => {
|
|
1256
|
+
return comparators.compareStrings(a.description, b.description);
|
|
1257
|
+
});
|
|
1258
|
+
} else {
|
|
1259
|
+
builder = ComparatorBuilder.startWith((a, b) => {
|
|
1260
|
+
return comparators.compareStrings(a.description, b.description);
|
|
1261
|
+
});
|
|
1262
|
+
}
|
|
1263
|
+
|
|
1264
|
+
compositeGroups.sort(builder.toComparator());
|
|
1265
|
+
|
|
1266
|
+
const initializeGroupObservers = (group, groupTree) => {
|
|
1267
|
+
addGroupBinding.call(this, group, group.registerGroupExcludedChangeHandler((excluded, sender) => {
|
|
1268
|
+
groupTree.climb((parentGroup) => {
|
|
1269
|
+
if (parentGroup) {
|
|
1270
|
+
let excludedItems = [];
|
|
1271
|
+
|
|
1272
|
+
currentTree.walk((childGroup) => {
|
|
1273
|
+
if (childGroup.excluded) {
|
|
1274
|
+
excludedItems = excludedItems.concat(childGroup.items);
|
|
1275
|
+
}
|
|
1276
|
+
}, false, false);
|
|
1277
|
+
|
|
1278
|
+
parentGroup.setExcludedItems(array.unique(excludedItems));
|
|
1279
|
+
}
|
|
1280
|
+
}, false);
|
|
1281
|
+
|
|
1282
|
+
if (treeDefinition.exclusionDependencies.length > 0) {
|
|
1283
|
+
const dependantTrees = treeDefinition.exclusionDependencies.reduce((trees, name) => {
|
|
1284
|
+
if (this._trees.hasOwnProperty(name)) {
|
|
1285
|
+
trees.push(this._trees[name]);
|
|
1286
|
+
}
|
|
1287
|
+
|
|
1288
|
+
return trees;
|
|
1289
|
+
}, [ ]);
|
|
1290
|
+
|
|
1291
|
+
if (dependantTrees.length > 0) {
|
|
1292
|
+
let excludedItems = [ ];
|
|
1293
|
+
|
|
1294
|
+
parentTree.walk((childGroup) => {
|
|
1295
|
+
if (childGroup.excluded) {
|
|
1296
|
+
excludedItems = excludedItems.concat(childGroup.items);
|
|
1297
|
+
}
|
|
1298
|
+
}, false, false);
|
|
1299
|
+
|
|
1300
|
+
dependantTrees.forEach((dependantTrees) => {
|
|
1301
|
+
dependantTrees.walk((childGroup) => {
|
|
1302
|
+
childGroup.setExcludedItems(excludedItems);
|
|
1303
|
+
}, false, false);
|
|
1304
|
+
});
|
|
1305
|
+
}
|
|
1306
|
+
}
|
|
1307
|
+
}));
|
|
1308
|
+
};
|
|
1309
|
+
|
|
1310
|
+
compositeGroups.forEach((group) => {
|
|
1311
|
+
const childTree = currentTree.addChild(group);
|
|
1312
|
+
|
|
1313
|
+
initializeGroupObservers(group, childTree);
|
|
1314
|
+
|
|
1315
|
+
addGroupBinding.call(this, group, group.registerMarketPercentChangeHandler(() => {
|
|
1316
|
+
currentTree.walk((childGroup) => childGroup.refreshMarketPercent());
|
|
1317
|
+
}));
|
|
1318
|
+
|
|
1319
|
+
createGroups.call(this, parentTree, childTree, group.items, treeDefinition, array.dropLeft(levelDefinitions));
|
|
1320
|
+
});
|
|
1321
|
+
}
|
|
1322
|
+
|
|
1242
1323
|
return PositionContainer;
|
|
1243
1324
|
})();
|
|
1244
1325
|
|
|
@@ -1267,6 +1348,7 @@ module.exports = (() => {
|
|
|
1267
1348
|
* @public
|
|
1268
1349
|
* @param {PositionContainer} container
|
|
1269
1350
|
* @param {PositionGroup|null} parent
|
|
1351
|
+
* @param {LevelDefinition} definition
|
|
1270
1352
|
* @param {Array.<PositionItem>} items
|
|
1271
1353
|
* @param {Currency} currency
|
|
1272
1354
|
* @param {String} key
|
|
@@ -1275,8 +1357,10 @@ module.exports = (() => {
|
|
|
1275
1357
|
* @param {Boolean=} aggregateCash
|
|
1276
1358
|
*/
|
|
1277
1359
|
class PositionGroup {
|
|
1278
|
-
constructor(container, parent, items, currency, key, description, single, aggregateCash) {
|
|
1360
|
+
constructor(container, parent, definition, items, currency, key, description, single, aggregateCash) {
|
|
1279
1361
|
this._id = counter++;
|
|
1362
|
+
|
|
1363
|
+
this._definition = definition;
|
|
1280
1364
|
this._container = container;
|
|
1281
1365
|
this._parent = parent || null;
|
|
1282
1366
|
|
|
@@ -1454,6 +1538,16 @@ module.exports = (() => {
|
|
|
1454
1538
|
return this._id;
|
|
1455
1539
|
}
|
|
1456
1540
|
|
|
1541
|
+
/**
|
|
1542
|
+
* The {@link LevelDefinition} which was used to generate this group.
|
|
1543
|
+
*
|
|
1544
|
+
* @public
|
|
1545
|
+
* @returns {LevelDefinition}
|
|
1546
|
+
*/
|
|
1547
|
+
get definition() {
|
|
1548
|
+
return this._definition;
|
|
1549
|
+
}
|
|
1550
|
+
|
|
1457
1551
|
/**
|
|
1458
1552
|
* The key of the group.
|
|
1459
1553
|
*
|
|
@@ -1539,6 +1633,16 @@ module.exports = (() => {
|
|
|
1539
1633
|
return this._excluded;
|
|
1540
1634
|
}
|
|
1541
1635
|
|
|
1636
|
+
addItems(items) {
|
|
1637
|
+
|
|
1638
|
+
this.refresh();
|
|
1639
|
+
}
|
|
1640
|
+
|
|
1641
|
+
removeItems(items) {
|
|
1642
|
+
|
|
1643
|
+
this.refresh();
|
|
1644
|
+
}
|
|
1645
|
+
|
|
1542
1646
|
/**
|
|
1543
1647
|
* Sets the list of items which are excluded from group aggregation calculations.
|
|
1544
1648
|
*
|
|
@@ -2295,8 +2399,11 @@ module.exports = (() => {
|
|
|
2295
2399
|
|
|
2296
2400
|
},{"./../data/InstrumentType":1,"@barchart/common-js/lang/Currency":14,"@barchart/common-js/lang/Decimal":16,"@barchart/common-js/lang/array":20,"@barchart/common-js/lang/assert":21,"@barchart/common-js/lang/is":23,"@barchart/common-js/messaging/Event":25}],7:[function(require,module,exports){
|
|
2297
2401
|
const assert = require('@barchart/common-js/lang/assert'),
|
|
2402
|
+
Currency = require('@barchart/common-js/lang/Currency'),
|
|
2298
2403
|
is = require('@barchart/common-js/lang/is');
|
|
2299
2404
|
|
|
2405
|
+
const InstrumentType = require('./../../data/InstrumentType');
|
|
2406
|
+
|
|
2300
2407
|
module.exports = (() => {
|
|
2301
2408
|
'use strict';
|
|
2302
2409
|
|
|
@@ -2311,12 +2418,12 @@ module.exports = (() => {
|
|
|
2311
2418
|
* @param {PositionLevelDefinition~descriptionSelector} descriptionSelector
|
|
2312
2419
|
* @param {PositionLevelDefinition~currencySelector} currencySelector
|
|
2313
2420
|
* @param {Array.<PositionLevelDefinition~RequiredGroup>=} requiredGroups
|
|
2314
|
-
* @param {Array.<PositionLevelDefinition~RequiredGroup>=} requiredGroups
|
|
2315
2421
|
* @param {Boolean=} single
|
|
2316
2422
|
* @param {Boolean=} aggregateCash
|
|
2423
|
+
* @param {Function=} injectPositions
|
|
2317
2424
|
*/
|
|
2318
2425
|
class PositionLevelDefinition {
|
|
2319
|
-
constructor(name, keySelector, descriptionSelector, currencySelector, requiredGroups, single, aggregateCash) {
|
|
2426
|
+
constructor(name, keySelector, descriptionSelector, currencySelector, requiredGroups, single, aggregateCash, requiredGroupGenerator) {
|
|
2320
2427
|
assert.argumentIsRequired(name, 'name', String);
|
|
2321
2428
|
assert.argumentIsRequired(keySelector, 'keySelector', Function);
|
|
2322
2429
|
assert.argumentIsRequired(descriptionSelector, 'descriptionSelector', Function);
|
|
@@ -2328,6 +2435,7 @@ module.exports = (() => {
|
|
|
2328
2435
|
|
|
2329
2436
|
assert.argumentIsOptional(single, 'single', Boolean);
|
|
2330
2437
|
assert.argumentIsOptional(aggregateCash, 'aggregateCash', Boolean);
|
|
2438
|
+
assert.argumentIsOptional(requiredGroupGenerator, 'requiredGroupGenerator', Function);
|
|
2331
2439
|
|
|
2332
2440
|
this._name = name;
|
|
2333
2441
|
|
|
@@ -2336,8 +2444,11 @@ module.exports = (() => {
|
|
|
2336
2444
|
this._currencySelector = currencySelector;
|
|
2337
2445
|
|
|
2338
2446
|
this._requiredGroups = requiredGroups || [ ];
|
|
2447
|
+
|
|
2339
2448
|
this._single = is.boolean(single) && single;
|
|
2340
2449
|
this._aggregateCash = is.boolean(aggregateCash) && aggregateCash;
|
|
2450
|
+
|
|
2451
|
+
this._requiredGroupGenerator = requiredGroupGenerator || (input => null);
|
|
2341
2452
|
}
|
|
2342
2453
|
|
|
2343
2454
|
/**
|
|
@@ -2414,6 +2525,96 @@ module.exports = (() => {
|
|
|
2414
2525
|
return this._aggregateCash;
|
|
2415
2526
|
}
|
|
2416
2527
|
|
|
2528
|
+
/**
|
|
2529
|
+
* Given an input, potentially creates a new {@link PositionLevelDefinition~RequiredGroup}.
|
|
2530
|
+
*
|
|
2531
|
+
* @public
|
|
2532
|
+
* @param {*} input
|
|
2533
|
+
* @returns {PositionLevelDefinition~RequiredGroup|null}
|
|
2534
|
+
*/
|
|
2535
|
+
generateRequiredGroup(input) {
|
|
2536
|
+
const requiredGroup = this._requiredGroupGenerator(input);
|
|
2537
|
+
|
|
2538
|
+
if (requiredGroup !== null) {
|
|
2539
|
+
this._requiredGroups.push(requiredGroup);
|
|
2540
|
+
}
|
|
2541
|
+
|
|
2542
|
+
return requiredGroup;
|
|
2543
|
+
}
|
|
2544
|
+
|
|
2545
|
+
/**
|
|
2546
|
+
* Builds a {@link PositionLevelDefinition~RequiredGroup} for a portfolio.
|
|
2547
|
+
*
|
|
2548
|
+
* @public
|
|
2549
|
+
* @static
|
|
2550
|
+
* @param {Object} portfolio
|
|
2551
|
+
* @return {PositionLevelDefinition~RequiredGroup}
|
|
2552
|
+
*/
|
|
2553
|
+
static buildRequiredGroupForPortfolio(portfolio) {
|
|
2554
|
+
return {
|
|
2555
|
+
key: PositionLevelDefinition.getKeyForPortfolioGroup(portfolio),
|
|
2556
|
+
description: PositionLevelDefinition.getDescriptionForPortfolioGroup(portfolio),
|
|
2557
|
+
currency: Currency.CAD
|
|
2558
|
+
};
|
|
2559
|
+
}
|
|
2560
|
+
|
|
2561
|
+
static getKeyForPortfolioGroup(portfolio) {
|
|
2562
|
+
assert.argumentIsRequired(portfolio, 'portfolio', Object);
|
|
2563
|
+
|
|
2564
|
+
return portfolio.portfolio;
|
|
2565
|
+
}
|
|
2566
|
+
|
|
2567
|
+
static getDescriptionForPortfolioGroup(portfolio) {
|
|
2568
|
+
assert.argumentIsRequired(portfolio, 'portfolio', Object);
|
|
2569
|
+
|
|
2570
|
+
return portfolio.name;
|
|
2571
|
+
}
|
|
2572
|
+
|
|
2573
|
+
static getRequiredGroupGeneratorForPortfolio() {
|
|
2574
|
+
return (portfolio) => {
|
|
2575
|
+
let requiredGroup;
|
|
2576
|
+
|
|
2577
|
+
if (is.object(portfolio) && is.string(portfolio.portfolio) && is.string(portfolio.name)) {
|
|
2578
|
+
requiredGroup = PositionLevelDefinition.buildRequiredGroupForPortfolio(portfolio);
|
|
2579
|
+
} else {
|
|
2580
|
+
requiredGroup = null;
|
|
2581
|
+
}
|
|
2582
|
+
|
|
2583
|
+
return requiredGroup;
|
|
2584
|
+
};
|
|
2585
|
+
}
|
|
2586
|
+
|
|
2587
|
+
/**
|
|
2588
|
+
* Builds a {@link PositionLevelDefinition~RequiredGroup} for an asset class.
|
|
2589
|
+
*
|
|
2590
|
+
* @public
|
|
2591
|
+
* @static
|
|
2592
|
+
* @param {InstrumentType} type
|
|
2593
|
+
* @param {Currency} currency
|
|
2594
|
+
* @return {PositionLevelDefinition~RequiredGroup}
|
|
2595
|
+
*/
|
|
2596
|
+
static buildRequiredGroupForAssetClass(type, currency) {
|
|
2597
|
+
return {
|
|
2598
|
+
key: PositionLevelDefinition.getKeyForAssetClassGroup(type, currency),
|
|
2599
|
+
description: PositionLevelDefinition.getDescriptionForAssetClassGroup(type, currency),
|
|
2600
|
+
currency: currency
|
|
2601
|
+
};
|
|
2602
|
+
}
|
|
2603
|
+
|
|
2604
|
+
static getKeyForAssetClassGroup(type, currency) {
|
|
2605
|
+
assert.argumentIsRequired(type, 'type', InstrumentType, 'InstrumentType');
|
|
2606
|
+
assert.argumentIsRequired(currency, 'currency', Currency, 'Currency');
|
|
2607
|
+
|
|
2608
|
+
return `${type.code}|${currency.code}`;
|
|
2609
|
+
}
|
|
2610
|
+
|
|
2611
|
+
static getDescriptionForAssetClassGroup(type, currency) {
|
|
2612
|
+
assert.argumentIsRequired(type, 'type', InstrumentType, 'InstrumentType');
|
|
2613
|
+
assert.argumentIsRequired(currency, 'currency', Currency, 'Currency');
|
|
2614
|
+
|
|
2615
|
+
return `${type.alternateDescription}${currency.code === 'CAD' ? '' : ` (${currency.alternateDescription})`}`;
|
|
2616
|
+
}
|
|
2617
|
+
|
|
2417
2618
|
toString() {
|
|
2418
2619
|
return '[PositionLevelDefinition]';
|
|
2419
2620
|
}
|
|
@@ -2463,7 +2664,7 @@ module.exports = (() => {
|
|
|
2463
2664
|
return PositionLevelDefinition;
|
|
2464
2665
|
})();
|
|
2465
2666
|
|
|
2466
|
-
},{"@barchart/common-js/lang/assert":21,"@barchart/common-js/lang/is":23}],8:[function(require,module,exports){
|
|
2667
|
+
},{"./../../data/InstrumentType":1,"@barchart/common-js/lang/Currency":14,"@barchart/common-js/lang/assert":21,"@barchart/common-js/lang/is":23}],8:[function(require,module,exports){
|
|
2467
2668
|
const assert = require('@barchart/common-js/lang/assert');
|
|
2468
2669
|
|
|
2469
2670
|
const PositionLevelDefinition = require('./PositionLevelDefinition');
|
|
@@ -2509,7 +2710,7 @@ module.exports = (() => {
|
|
|
2509
2710
|
* bottom-most level of the tree (i.e. leaf nodes).
|
|
2510
2711
|
*
|
|
2511
2712
|
* @public
|
|
2512
|
-
* @returns {Array.<
|
|
2713
|
+
* @returns {Array.<PositionLevelDefinitions>}
|
|
2513
2714
|
*/
|
|
2514
2715
|
get definitions() {
|
|
2515
2716
|
return this._definitions;
|
|
@@ -3333,7 +3534,7 @@ module.exports = function () {
|
|
|
3333
3534
|
var Currency = function (_Enum) {
|
|
3334
3535
|
_inherits(Currency, _Enum);
|
|
3335
3536
|
|
|
3336
|
-
function Currency(code, description, precision
|
|
3537
|
+
function Currency(code, description, precision) {
|
|
3337
3538
|
_classCallCheck(this, Currency);
|
|
3338
3539
|
|
|
3339
3540
|
var _this = _possibleConstructorReturn(this, (Currency.__proto__ || Object.getPrototypeOf(Currency)).call(this, code, description));
|
|
@@ -3341,11 +3542,7 @@ module.exports = function () {
|
|
|
3341
3542
|
assert.argumentIsRequired(precision, 'precision', Number);
|
|
3342
3543
|
assert.argumentIsValid(precision, 'precision', is.integer, 'is an integer');
|
|
3343
3544
|
|
|
3344
|
-
assert.argumentIsOptional(alternateDescription, 'alternateDescription', String);
|
|
3345
|
-
|
|
3346
3545
|
_this._precision = precision;
|
|
3347
|
-
|
|
3348
|
-
_this._alternateDescription = alternateDescription || description;
|
|
3349
3546
|
return _this;
|
|
3350
3547
|
}
|
|
3351
3548
|
|
|
@@ -3368,19 +3565,6 @@ module.exports = function () {
|
|
|
3368
3565
|
return this._precision;
|
|
3369
3566
|
}
|
|
3370
3567
|
|
|
3371
|
-
/**
|
|
3372
|
-
* An alternate human-readable description.
|
|
3373
|
-
*
|
|
3374
|
-
* @public
|
|
3375
|
-
* @returns {String}
|
|
3376
|
-
*/
|
|
3377
|
-
|
|
3378
|
-
}, {
|
|
3379
|
-
key: 'alternateDescription',
|
|
3380
|
-
get: function get() {
|
|
3381
|
-
return this._alternateDescription;
|
|
3382
|
-
}
|
|
3383
|
-
|
|
3384
3568
|
/**
|
|
3385
3569
|
* Given a code, returns the enumeration item.
|
|
3386
3570
|
*
|
|
@@ -3438,9 +3622,9 @@ module.exports = function () {
|
|
|
3438
3622
|
return Currency;
|
|
3439
3623
|
}(Enum);
|
|
3440
3624
|
|
|
3441
|
-
var cad = new Currency('CAD', 'Canadian Dollar', 2
|
|
3442
|
-
var eur = new Currency('EUR', 'Euro', 2
|
|
3443
|
-
var usd = new Currency('USD', 'US Dollar', 2
|
|
3625
|
+
var cad = new Currency('CAD', 'Canadian Dollar', 2);
|
|
3626
|
+
var eur = new Currency('EUR', 'Euro', 2);
|
|
3627
|
+
var usd = new Currency('USD', 'US Dollar', 2);
|
|
3444
3628
|
|
|
3445
3629
|
return Currency;
|
|
3446
3630
|
}();
|
|
@@ -4414,9 +4598,9 @@ module.exports = function () {
|
|
|
4414
4598
|
assert.argumentIsRequired(a, 'a', Decimal, 'Decimal');
|
|
4415
4599
|
assert.argumentIsRequired(b, 'b', Decimal, 'Decimal');
|
|
4416
4600
|
|
|
4417
|
-
if (a._big.gt(b
|
|
4601
|
+
if (a._big.gt(b)) {
|
|
4418
4602
|
return 1;
|
|
4419
|
-
} else if (a._big.lt(b
|
|
4603
|
+
} else if (a._big.lt(b)) {
|
|
4420
4604
|
return -1;
|
|
4421
4605
|
} else {
|
|
4422
4606
|
return 0;
|
|
@@ -4877,10 +5061,12 @@ var _createClass = function () { function defineProperties(target, props) { for
|
|
|
4877
5061
|
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
|
|
4878
5062
|
|
|
4879
5063
|
var assert = require('./assert'),
|
|
5064
|
+
is = require('./is'),
|
|
4880
5065
|
memoize = require('./memoize');
|
|
4881
5066
|
|
|
4882
5067
|
var Currency = require('./Currency'),
|
|
4883
|
-
Decimal = require('./Decimal')
|
|
5068
|
+
Decimal = require('./Decimal'),
|
|
5069
|
+
Enum = require('./Enum');
|
|
4884
5070
|
|
|
4885
5071
|
module.exports = function () {
|
|
4886
5072
|
'use strict';
|
|
@@ -5060,7 +5246,12 @@ module.exports = function () {
|
|
|
5060
5246
|
assert.argumentIsRequired(amount, 'amount', Decimal, 'Decimal');
|
|
5061
5247
|
assert.argumentIsRequired(currency, 'currency', Currency, 'Currency');
|
|
5062
5248
|
assert.argumentIsRequired(desiredCurrency, 'desiredCurrency', Currency, 'Currency');
|
|
5063
|
-
|
|
5249
|
+
|
|
5250
|
+
for (var _len = arguments.length, rates = Array(_len > 3 ? _len - 3 : 0), _key = 3; _key < _len; _key++) {
|
|
5251
|
+
rates[_key - 3] = arguments[_key];
|
|
5252
|
+
}
|
|
5253
|
+
|
|
5254
|
+
assert.argumentIsArray(rates, 'rates', Rate, 'Rate');
|
|
5064
5255
|
|
|
5065
5256
|
var converted = void 0;
|
|
5066
5257
|
|
|
@@ -5070,10 +5261,6 @@ module.exports = function () {
|
|
|
5070
5261
|
var numerator = desiredCurrency;
|
|
5071
5262
|
var denominator = currency;
|
|
5072
5263
|
|
|
5073
|
-
for (var _len = arguments.length, rates = Array(_len > 3 ? _len - 3 : 0), _key = 3; _key < _len; _key++) {
|
|
5074
|
-
rates[_key - 3] = arguments[_key];
|
|
5075
|
-
}
|
|
5076
|
-
|
|
5077
5264
|
var rate = rates.find(function (r) {
|
|
5078
5265
|
return r.numerator === numerator && r.denominator === denominator || r.numerator === denominator && r.denominator === numerator;
|
|
5079
5266
|
});
|
|
@@ -5124,7 +5311,7 @@ module.exports = function () {
|
|
|
5124
5311
|
return Rate;
|
|
5125
5312
|
}();
|
|
5126
5313
|
|
|
5127
|
-
},{"./Currency":14,"./Decimal":16,"./assert":21,"./memoize":24}],20:[function(require,module,exports){
|
|
5314
|
+
},{"./Currency":14,"./Decimal":16,"./Enum":18,"./assert":21,"./is":23,"./memoize":24}],20:[function(require,module,exports){
|
|
5128
5315
|
'use strict';
|
|
5129
5316
|
|
|
5130
5317
|
var assert = require('./assert'),
|