@barchart/portfolio-api-common 1.0.162 → 1.0.166
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 +187 -122
- package/lib/processing/PositionGroup.js +14 -1
- package/lib/processing/definitions/PositionLevelDefinition.js +38 -4
- package/lib/processing/definitions/PositionTreeDefinition.js +1 -1
- package/package.json +1 -1
- package/test/SpecRunner.js +240 -128
|
@@ -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,136 +156,70 @@ 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
|
-
}
|
|
216
|
-
|
|
217
|
-
builder = ComparatorBuilder.startWith((a, b) => {
|
|
218
|
-
return comparators.compareNumbers(getIndex(a.description), getIndex(b.description));
|
|
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
|
-
}
|
|
227
|
-
|
|
228
|
-
compositeGroups.sort(builder.toComparator());
|
|
197
|
+
}
|
|
198
|
+
});
|
|
229
199
|
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
groupTree.climb((parentGroup) => {
|
|
233
|
-
if (parentGroup) {
|
|
234
|
-
let excludedItems = [];
|
|
200
|
+
if (portfolioRequiredGroup !== null) {
|
|
201
|
+
let parentTrees = [ ];
|
|
235
202
|
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
}, false, false);
|
|
203
|
+
if (portfolioLevelDefinitionIndex === 0) {
|
|
204
|
+
parentTrees.push(tree);
|
|
205
|
+
} else {
|
|
206
|
+
const parentLevelDefinition = levelDefinitions[ portfolioLevelDefinitionIndex - 1 ];
|
|
241
207
|
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
if (treeDefinition.exclusionDependencies.length > 0) {
|
|
247
|
-
const dependantTrees = treeDefinition.exclusionDependencies.reduce((trees, name) => {
|
|
248
|
-
if (this._trees.hasOwnProperty(name)) {
|
|
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
|
-
});
|
|
208
|
+
tree.walk((group, groupTree) => {
|
|
209
|
+
if (group.definition === parentLevelDefinition) {
|
|
210
|
+
parentTrees.push(groupTree);
|
|
269
211
|
}
|
|
270
|
-
}
|
|
271
|
-
}
|
|
272
|
-
};
|
|
273
|
-
|
|
274
|
-
compositeGroups.forEach((group) => {
|
|
275
|
-
const childTree = currentTree.addChild(group);
|
|
212
|
+
}, false, false);
|
|
213
|
+
}
|
|
276
214
|
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
addGroupBinding(group, group.registerMarketPercentChangeHandler(() => {
|
|
280
|
-
currentTree.walk((childGroup) => childGroup.refreshMarketPercent());
|
|
281
|
-
}));
|
|
282
|
-
|
|
283
|
-
createGroups(childTree, group.items, array.dropLeft(levelDefinitions));
|
|
284
|
-
});
|
|
285
|
-
};
|
|
286
|
-
|
|
287
|
-
createGroups(tree, this._items, treeDefinition.definitions);
|
|
288
|
-
|
|
289
|
-
map[treeDefinition.name] = tree;
|
|
290
|
-
|
|
291
|
-
return map;
|
|
292
|
-
}, { });
|
|
293
|
-
}
|
|
294
|
-
|
|
295
|
-
addPortfolio(portfolio) {
|
|
215
|
+
const overrideRequiredGroups = [ portfolioRequiredGroup ];
|
|
296
216
|
|
|
217
|
+
parentTrees.forEach((t) => {
|
|
218
|
+
createGroups.call(this, tree, t, [ ], treeDefinition, levelDefinitions.slice(portfolioLevelDefinitionIndex), overrideRequiredGroups);
|
|
219
|
+
});
|
|
220
|
+
}
|
|
221
|
+
});
|
|
222
|
+
}
|
|
297
223
|
}
|
|
298
224
|
|
|
299
225
|
removePortfolio(portfolio) {
|
|
@@ -482,6 +408,16 @@ module.exports = (() => {
|
|
|
482
408
|
return findNode(this._trees[name], keys).getChildren().map(node => node.getValue());
|
|
483
409
|
}
|
|
484
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
|
+
|
|
485
421
|
/**
|
|
486
422
|
* Returns all positions for the given portfolio.
|
|
487
423
|
*
|
|
@@ -539,5 +475,134 @@ module.exports = (() => {
|
|
|
539
475
|
}
|
|
540
476
|
}
|
|
541
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
|
+
|
|
542
607
|
return PositionContainer;
|
|
543
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
|
*
|
|
@@ -20,9 +20,10 @@ module.exports = (() => {
|
|
|
20
20
|
* @param {Array.<PositionLevelDefinition~RequiredGroup>=} requiredGroups
|
|
21
21
|
* @param {Boolean=} single
|
|
22
22
|
* @param {Boolean=} aggregateCash
|
|
23
|
+
* @param {Function=} requiredGroupGenerator
|
|
23
24
|
*/
|
|
24
25
|
class PositionLevelDefinition {
|
|
25
|
-
constructor(name, keySelector, descriptionSelector, currencySelector, requiredGroups, single, aggregateCash) {
|
|
26
|
+
constructor(name, keySelector, descriptionSelector, currencySelector, requiredGroups, single, aggregateCash, requiredGroupGenerator) {
|
|
26
27
|
assert.argumentIsRequired(name, 'name', String);
|
|
27
28
|
assert.argumentIsRequired(keySelector, 'keySelector', Function);
|
|
28
29
|
assert.argumentIsRequired(descriptionSelector, 'descriptionSelector', Function);
|
|
@@ -34,6 +35,7 @@ module.exports = (() => {
|
|
|
34
35
|
|
|
35
36
|
assert.argumentIsOptional(single, 'single', Boolean);
|
|
36
37
|
assert.argumentIsOptional(aggregateCash, 'aggregateCash', Boolean);
|
|
38
|
+
assert.argumentIsOptional(requiredGroupGenerator, 'requiredGroupGenerator', Function);
|
|
37
39
|
|
|
38
40
|
this._name = name;
|
|
39
41
|
|
|
@@ -42,8 +44,11 @@ module.exports = (() => {
|
|
|
42
44
|
this._currencySelector = currencySelector;
|
|
43
45
|
|
|
44
46
|
this._requiredGroups = requiredGroups || [ ];
|
|
47
|
+
|
|
45
48
|
this._single = is.boolean(single) && single;
|
|
46
49
|
this._aggregateCash = is.boolean(aggregateCash) && aggregateCash;
|
|
50
|
+
|
|
51
|
+
this._requiredGroupGenerator = requiredGroupGenerator || (input => null);
|
|
47
52
|
}
|
|
48
53
|
|
|
49
54
|
/**
|
|
@@ -120,6 +125,23 @@ module.exports = (() => {
|
|
|
120
125
|
return this._aggregateCash;
|
|
121
126
|
}
|
|
122
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
|
+
|
|
123
145
|
/**
|
|
124
146
|
* Builds a {@link PositionLevelDefinition~RequiredGroup} for a portfolio.
|
|
125
147
|
*
|
|
@@ -136,7 +158,6 @@ module.exports = (() => {
|
|
|
136
158
|
};
|
|
137
159
|
}
|
|
138
160
|
|
|
139
|
-
|
|
140
161
|
static getKeyForPortfolioGroup(portfolio) {
|
|
141
162
|
assert.argumentIsRequired(portfolio, 'portfolio', Object);
|
|
142
163
|
|
|
@@ -149,6 +170,20 @@ module.exports = (() => {
|
|
|
149
170
|
return portfolio.name;
|
|
150
171
|
}
|
|
151
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
|
+
|
|
152
187
|
/**
|
|
153
188
|
* Builds a {@link PositionLevelDefinition~RequiredGroup} for an asset class.
|
|
154
189
|
*
|
|
@@ -163,10 +198,9 @@ module.exports = (() => {
|
|
|
163
198
|
key: PositionLevelDefinition.getKeyForAssetClassGroup(type, currency),
|
|
164
199
|
description: PositionLevelDefinition.getDescriptionForAssetClassGroup(type, currency),
|
|
165
200
|
currency: currency
|
|
166
|
-
}
|
|
201
|
+
};
|
|
167
202
|
}
|
|
168
203
|
|
|
169
|
-
|
|
170
204
|
static getKeyForAssetClassGroup(type, currency) {
|
|
171
205
|
assert.argumentIsRequired(type, 'type', InstrumentType, 'InstrumentType');
|
|
172
206
|
assert.argumentIsRequired(currency, 'currency', Currency, 'Currency');
|
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,136 +872,70 @@ 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
|
-
}
|
|
932
|
-
|
|
933
|
-
builder = ComparatorBuilder.startWith((a, b) => {
|
|
934
|
-
return comparators.compareNumbers(getIndex(a.description), getIndex(b.description));
|
|
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
|
-
}
|
|
943
|
-
|
|
944
|
-
compositeGroups.sort(builder.toComparator());
|
|
913
|
+
}
|
|
914
|
+
});
|
|
945
915
|
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
groupTree.climb((parentGroup) => {
|
|
949
|
-
if (parentGroup) {
|
|
950
|
-
let excludedItems = [];
|
|
916
|
+
if (portfolioRequiredGroup !== null) {
|
|
917
|
+
let parentTrees = [ ];
|
|
951
918
|
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
}, false, false);
|
|
919
|
+
if (portfolioLevelDefinitionIndex === 0) {
|
|
920
|
+
parentTrees.push(tree);
|
|
921
|
+
} else {
|
|
922
|
+
const parentLevelDefinition = levelDefinitions[ portfolioLevelDefinitionIndex - 1 ];
|
|
957
923
|
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
if (treeDefinition.exclusionDependencies.length > 0) {
|
|
963
|
-
const dependantTrees = treeDefinition.exclusionDependencies.reduce((trees, name) => {
|
|
964
|
-
if (this._trees.hasOwnProperty(name)) {
|
|
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
|
-
});
|
|
924
|
+
tree.walk((group, groupTree) => {
|
|
925
|
+
if (group.definition === parentLevelDefinition) {
|
|
926
|
+
parentTrees.push(groupTree);
|
|
985
927
|
}
|
|
986
|
-
}
|
|
987
|
-
}
|
|
988
|
-
};
|
|
989
|
-
|
|
990
|
-
compositeGroups.forEach((group) => {
|
|
991
|
-
const childTree = currentTree.addChild(group);
|
|
992
|
-
|
|
993
|
-
initializeGroupObservers(group, childTree);
|
|
994
|
-
|
|
995
|
-
addGroupBinding(group, group.registerMarketPercentChangeHandler(() => {
|
|
996
|
-
currentTree.walk((childGroup) => childGroup.refreshMarketPercent());
|
|
997
|
-
}));
|
|
998
|
-
|
|
999
|
-
createGroups(childTree, group.items, array.dropLeft(levelDefinitions));
|
|
1000
|
-
});
|
|
1001
|
-
};
|
|
1002
|
-
|
|
1003
|
-
createGroups(tree, this._items, treeDefinition.definitions);
|
|
1004
|
-
|
|
1005
|
-
map[treeDefinition.name] = tree;
|
|
1006
|
-
|
|
1007
|
-
return map;
|
|
1008
|
-
}, { });
|
|
1009
|
-
}
|
|
928
|
+
}, false, false);
|
|
929
|
+
}
|
|
1010
930
|
|
|
1011
|
-
|
|
931
|
+
const overrideRequiredGroups = [ portfolioRequiredGroup ];
|
|
1012
932
|
|
|
933
|
+
parentTrees.forEach((t) => {
|
|
934
|
+
createGroups.call(this, tree, t, [ ], treeDefinition, levelDefinitions.slice(portfolioLevelDefinitionIndex), overrideRequiredGroups);
|
|
935
|
+
});
|
|
936
|
+
}
|
|
937
|
+
});
|
|
938
|
+
}
|
|
1013
939
|
}
|
|
1014
940
|
|
|
1015
941
|
removePortfolio(portfolio) {
|
|
@@ -1198,6 +1124,16 @@ module.exports = (() => {
|
|
|
1198
1124
|
return findNode(this._trees[name], keys).getChildren().map(node => node.getValue());
|
|
1199
1125
|
}
|
|
1200
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
|
+
|
|
1201
1137
|
/**
|
|
1202
1138
|
* Returns all positions for the given portfolio.
|
|
1203
1139
|
*
|
|
@@ -1255,6 +1191,135 @@ module.exports = (() => {
|
|
|
1255
1191
|
}
|
|
1256
1192
|
}
|
|
1257
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
|
+
|
|
1258
1323
|
return PositionContainer;
|
|
1259
1324
|
})();
|
|
1260
1325
|
|
|
@@ -1283,6 +1348,7 @@ module.exports = (() => {
|
|
|
1283
1348
|
* @public
|
|
1284
1349
|
* @param {PositionContainer} container
|
|
1285
1350
|
* @param {PositionGroup|null} parent
|
|
1351
|
+
* @param {LevelDefinition} definition
|
|
1286
1352
|
* @param {Array.<PositionItem>} items
|
|
1287
1353
|
* @param {Currency} currency
|
|
1288
1354
|
* @param {String} key
|
|
@@ -1291,8 +1357,10 @@ module.exports = (() => {
|
|
|
1291
1357
|
* @param {Boolean=} aggregateCash
|
|
1292
1358
|
*/
|
|
1293
1359
|
class PositionGroup {
|
|
1294
|
-
constructor(container, parent, items, currency, key, description, single, aggregateCash) {
|
|
1360
|
+
constructor(container, parent, definition, items, currency, key, description, single, aggregateCash) {
|
|
1295
1361
|
this._id = counter++;
|
|
1362
|
+
|
|
1363
|
+
this._definition = definition;
|
|
1296
1364
|
this._container = container;
|
|
1297
1365
|
this._parent = parent || null;
|
|
1298
1366
|
|
|
@@ -1470,6 +1538,16 @@ module.exports = (() => {
|
|
|
1470
1538
|
return this._id;
|
|
1471
1539
|
}
|
|
1472
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
|
+
|
|
1473
1551
|
/**
|
|
1474
1552
|
* The key of the group.
|
|
1475
1553
|
*
|
|
@@ -2342,9 +2420,10 @@ module.exports = (() => {
|
|
|
2342
2420
|
* @param {Array.<PositionLevelDefinition~RequiredGroup>=} requiredGroups
|
|
2343
2421
|
* @param {Boolean=} single
|
|
2344
2422
|
* @param {Boolean=} aggregateCash
|
|
2423
|
+
* @param {Function=} requiredGroupGenerator
|
|
2345
2424
|
*/
|
|
2346
2425
|
class PositionLevelDefinition {
|
|
2347
|
-
constructor(name, keySelector, descriptionSelector, currencySelector, requiredGroups, single, aggregateCash) {
|
|
2426
|
+
constructor(name, keySelector, descriptionSelector, currencySelector, requiredGroups, single, aggregateCash, requiredGroupGenerator) {
|
|
2348
2427
|
assert.argumentIsRequired(name, 'name', String);
|
|
2349
2428
|
assert.argumentIsRequired(keySelector, 'keySelector', Function);
|
|
2350
2429
|
assert.argumentIsRequired(descriptionSelector, 'descriptionSelector', Function);
|
|
@@ -2356,6 +2435,7 @@ module.exports = (() => {
|
|
|
2356
2435
|
|
|
2357
2436
|
assert.argumentIsOptional(single, 'single', Boolean);
|
|
2358
2437
|
assert.argumentIsOptional(aggregateCash, 'aggregateCash', Boolean);
|
|
2438
|
+
assert.argumentIsOptional(requiredGroupGenerator, 'requiredGroupGenerator', Function);
|
|
2359
2439
|
|
|
2360
2440
|
this._name = name;
|
|
2361
2441
|
|
|
@@ -2364,8 +2444,11 @@ module.exports = (() => {
|
|
|
2364
2444
|
this._currencySelector = currencySelector;
|
|
2365
2445
|
|
|
2366
2446
|
this._requiredGroups = requiredGroups || [ ];
|
|
2447
|
+
|
|
2367
2448
|
this._single = is.boolean(single) && single;
|
|
2368
2449
|
this._aggregateCash = is.boolean(aggregateCash) && aggregateCash;
|
|
2450
|
+
|
|
2451
|
+
this._requiredGroupGenerator = requiredGroupGenerator || (input => null);
|
|
2369
2452
|
}
|
|
2370
2453
|
|
|
2371
2454
|
/**
|
|
@@ -2442,6 +2525,23 @@ module.exports = (() => {
|
|
|
2442
2525
|
return this._aggregateCash;
|
|
2443
2526
|
}
|
|
2444
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
|
+
|
|
2445
2545
|
/**
|
|
2446
2546
|
* Builds a {@link PositionLevelDefinition~RequiredGroup} for a portfolio.
|
|
2447
2547
|
*
|
|
@@ -2458,7 +2558,6 @@ module.exports = (() => {
|
|
|
2458
2558
|
};
|
|
2459
2559
|
}
|
|
2460
2560
|
|
|
2461
|
-
|
|
2462
2561
|
static getKeyForPortfolioGroup(portfolio) {
|
|
2463
2562
|
assert.argumentIsRequired(portfolio, 'portfolio', Object);
|
|
2464
2563
|
|
|
@@ -2471,6 +2570,20 @@ module.exports = (() => {
|
|
|
2471
2570
|
return portfolio.name;
|
|
2472
2571
|
}
|
|
2473
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
|
+
|
|
2474
2587
|
/**
|
|
2475
2588
|
* Builds a {@link PositionLevelDefinition~RequiredGroup} for an asset class.
|
|
2476
2589
|
*
|
|
@@ -2485,10 +2598,9 @@ module.exports = (() => {
|
|
|
2485
2598
|
key: PositionLevelDefinition.getKeyForAssetClassGroup(type, currency),
|
|
2486
2599
|
description: PositionLevelDefinition.getDescriptionForAssetClassGroup(type, currency),
|
|
2487
2600
|
currency: currency
|
|
2488
|
-
}
|
|
2601
|
+
};
|
|
2489
2602
|
}
|
|
2490
2603
|
|
|
2491
|
-
|
|
2492
2604
|
static getKeyForAssetClassGroup(type, currency) {
|
|
2493
2605
|
assert.argumentIsRequired(type, 'type', InstrumentType, 'InstrumentType');
|
|
2494
2606
|
assert.argumentIsRequired(currency, 'currency', Currency, 'Currency');
|
|
@@ -2598,7 +2710,7 @@ module.exports = (() => {
|
|
|
2598
2710
|
* bottom-most level of the tree (i.e. leaf nodes).
|
|
2599
2711
|
*
|
|
2600
2712
|
* @public
|
|
2601
|
-
* @returns {Array.<
|
|
2713
|
+
* @returns {Array.<PositionLevelDefinitions>}
|
|
2602
2714
|
*/
|
|
2603
2715
|
get definitions() {
|
|
2604
2716
|
return this._definitions;
|