@barchart/portfolio-api-common 1.0.268 → 1.1.0

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.
@@ -23,6 +23,17 @@ module.exports = (() => {
23
23
  return portfolioUpdateFailedNoPortfolio;
24
24
  }
25
25
 
26
+ /**
27
+ * The portfolio does not exist.
28
+ *
29
+ * @public
30
+ * @static
31
+ * @returns {FailureType}
32
+ */
33
+ static get PORTFOLIO_DELETE_FAILED_NO_PORTFOLIO() {
34
+ return portfolioDeleteFailedNoPortfolio;
35
+ }
36
+
26
37
  /**
27
38
  * The portfolio does not exist.
28
39
  *
@@ -136,7 +147,8 @@ module.exports = (() => {
136
147
  }
137
148
  }
138
149
 
139
- const portfolioUpdateFailedNoPortfolio = new FailureType('PORTFOLIO_UPDATED_FAILED_NO_PORTFOLIO', 'Unable to update portfolio. The portfolio does not exist, has it been deleted?');
150
+ const portfolioUpdateFailedNoPortfolio = new FailureType('PORTFOLIO_UPDATE_FAILED_NO_PORTFOLIO', 'Unable to update portfolio. The portfolio does not exist, has it been deleted?');
151
+ const portfolioDeleteFailedNoPortfolio = new FailureType('PORTFOLIO_DELETE_FAILED_NO_PORTFOLIO', 'Unable to delete portfolio. The portfolio does not exist, has it already been deleted?');
140
152
 
141
153
  const positionCreateFailedNoPortfolio = new FailureType('POSITION_CREATE_FAILED_NO_PORTFOLIO', 'Unable to create transaction. The portfolio does not exist, has it been deleted?');
142
154
  const positionUpdateFailedNoPosition = new FailureType('POSITION_UPDATE_FAILED_NO_POSITION', 'Unable to update preferences for position. The position does not exist, has it been deleted?');
@@ -1,5 +1,5 @@
1
1
  const assert = require('@barchart/common-js/lang/assert'),
2
- array = require('@barchart/common-js/lang/array')
2
+ array = require('@barchart/common-js/lang/array');
3
3
 
4
4
  const InstrumentType = require('./InstrumentType'),
5
5
  PositionDirection = require('./PositionDirection'),
@@ -25,22 +25,12 @@ module.exports = (() => {
25
25
  * @public
26
26
  * @static
27
27
  * @param {Array.<Object>} transactions
28
- * @param {Boolean=} partial - If true, sequence validation starts with the array's first transaction.
29
28
  * @return {boolean}
30
29
  */
31
- static validateOrder(transactions, partial) {
30
+ static validateOrder(transactions) {
32
31
  assert.argumentIsArray(transactions, 'transactions');
33
- assert.argumentIsOptional(partial, 'partial', Boolean);
34
32
 
35
- let startSequence;
36
-
37
- if (partial && transactions.length !== 0) {
38
- startSequence = array.first(transactions).sequence;
39
- } else {
40
- startSequence = 1;
41
- }
42
-
43
- return transactions.every((t, i) => t.sequence === (i + startSequence) && (i === 0 || !t.date.getIsBefore(transactions[i - 1].date)));
33
+ return transactions.every((t, i) => t.sequence === (i + 1) && (i === 0 || !t.date.getIsBefore(transactions[i - 1].date)));
44
34
  }
45
35
 
46
36
  /**
@@ -224,11 +224,9 @@ module.exports = (() => {
224
224
  assert.argumentIsRequired(portfolio, 'portfolio', Object);
225
225
  assert.argumentIsRequired(portfolio.portfolio, 'portfolio.portfolio', String);
226
226
 
227
- this.startTransaction(() => {
228
- getPositionItemsForPortfolio(this._items, portfolio.portfolio).forEach(item => item.updatePortfolio(portfolio));
227
+ getPositionItemsForPortfolio(this._items, portfolio.portfolio).forEach(item => item.updatePortfolio(portfolio));
229
228
 
230
- updateEmptyPortfolioGroups.call(this, portfolio);
231
- });
229
+ updateEmptyPortfolioGroups.call(this, portfolio);
232
230
  }
233
231
 
234
232
  /**
@@ -243,19 +241,19 @@ module.exports = (() => {
243
241
  assert.argumentIsRequired(portfolio, 'portfolio', Object);
244
242
  assert.argumentIsRequired(portfolio.portfolio, 'portfolio.portfolio', String);
245
243
 
246
- this.startTransaction(() => {
247
- getPositionItemsForPortfolio(this._items, portfolio.portfolio).forEach(item => removePositionItem.call(this, item));
244
+ getPositionItemsForPortfolio(this._items, portfolio.portfolio).forEach(item => removePositionItem.call(this, item));
248
245
 
249
- delete this._portfolios[portfolio.portfolio];
246
+ delete this._portfolios[portfolio.portfolio];
250
247
 
251
- Object.keys(this._trees).forEach((key) => {
252
- this._trees[key].walk((group, groupNode) => {
253
- if (group.definition.type === PositionLevelType.PORTFOLIO && group.key === PositionLevelDefinition.getKeyForPortfolioGroup(portfolio)) {
254
- severGroupNode.call(this, groupNode);
255
- }
256
- }, true, false);
257
- });
248
+ Object.keys(this._trees).forEach((key) => {
249
+ this._trees[key].walk((group, groupNode) => {
250
+ if (group.definition.type === PositionLevelType.PORTFOLIO && group.key === PositionLevelDefinition.getKeyForPortfolioGroup(portfolio)) {
251
+ severGroupNode.call(this, groupNode);
252
+ }
253
+ }, true, false);
258
254
  });
255
+
256
+ recalculatePercentages.call(this);
259
257
  }
260
258
 
261
259
  /**
@@ -276,56 +274,54 @@ module.exports = (() => {
276
274
  return;
277
275
  }
278
276
 
279
- this.startTransaction(() => {
280
- const existingBarchartSymbols = this.getPositionSymbols(false);
277
+ const existingBarchartSymbols = this.getPositionSymbols(false);
281
278
 
282
- removePositionItem.call(this, this._items.find((item) => item.position.position === position.position));
279
+ removePositionItem.call(this, this._items.find((item) => item.position.position === position.position));
283
280
 
284
- summaries.forEach((summary) => {
285
- addSummaryCurrent(this._summariesCurrent, summary, this._currentSummaryFrame, this._currentSummaryRange);
286
- addSummaryPrevious(this._summariesPrevious, summary, this._previousSummaryFrame, this._previousSummaryRanges);
287
- });
281
+ summaries.forEach((summary) => {
282
+ addSummaryCurrent(this._summariesCurrent, summary, this._currentSummaryFrame, this._currentSummaryRange);
283
+ addSummaryPrevious(this._summariesPrevious, summary, this._previousSummaryFrame, this._previousSummaryRanges);
284
+ });
288
285
 
289
- const item = createPositionItem.call(this, position);
286
+ const item = createPositionItem.call(this, position);
290
287
 
291
- addBarchartSymbol(this._symbols, item);
292
- addDisplaySymbol(this._symbolsDisplay, item);
288
+ addBarchartSymbol(this._symbols, item);
289
+ addDisplaySymbol(this._symbolsDisplay, item);
293
290
 
294
- this._items.push(item);
291
+ this._items.push(item);
295
292
 
296
- const createGroupOrInjectItem = (parentTree, treeDefinition, levelDefinitions) => {
297
- if (levelDefinitions.length === 0) {
298
- return;
299
- }
293
+ const createGroupOrInjectItem = (parentTree, treeDefinition, levelDefinitions) => {
294
+ if (levelDefinitions.length === 0) {
295
+ return;
296
+ }
300
297
 
301
- const levelDefinition = levelDefinitions[0];
302
- const levelKey = levelDefinition.keySelector(item);
298
+ const levelDefinition = levelDefinitions[0];
299
+ const levelKey = levelDefinition.keySelector(item);
303
300
 
304
- let groupTree;
301
+ let groupTree;
305
302
 
306
- if (parentTree.getChildren().length > 0) {
307
- groupTree = parentTree.findChild(childGroup => childGroup.key === levelKey) || null;
308
- } else {
309
- groupTree = null;
310
- }
303
+ if (parentTree.getChildren().length > 0) {
304
+ groupTree = parentTree.findChild(childGroup => childGroup.key === levelKey) || null;
305
+ } else {
306
+ groupTree = null;
307
+ }
311
308
 
312
- if (groupTree !== null) {
313
- groupTree.getValue().addItem(item);
309
+ if (groupTree !== null) {
310
+ groupTree.getValue().addItem(item);
314
311
 
315
- createGroupOrInjectItem(groupTree, treeDefinition, array.dropLeft(levelDefinitions));
316
- } else {
317
- createGroups.call(this, parentTree, [ item ], treeDefinition, levelDefinitions, [ ]);
318
- }
319
- };
312
+ createGroupOrInjectItem(groupTree, treeDefinition, array.dropLeft(levelDefinitions));
313
+ } else {
314
+ createGroups.call(this, parentTree, [ item ], treeDefinition, levelDefinitions, [ ]);
315
+ }
316
+ };
320
317
 
321
- this._definitions.forEach(definition => createGroupOrInjectItem(this._trees[definition.name], definition, definition.definitions));
318
+ this._definitions.forEach(definition => createGroupOrInjectItem(this._trees[definition.name], definition, definition.definitions));
322
319
 
323
- const addedBarchartSymbol = extractSymbolForBarchart(item.position);
320
+ const addedBarchartSymbol = extractSymbolForBarchart(item.position);
324
321
 
325
- if (addedBarchartSymbol !== null && !existingBarchartSymbols.some(existingBarchartSymbol => existingBarchartSymbol === addedBarchartSymbol)) {
326
- this._positionSymbolAddedEvent.fire(addedBarchartSymbol);
327
- }
328
- });
322
+ if (addedBarchartSymbol !== null && !existingBarchartSymbols.some(existingBarchartSymbol => existingBarchartSymbol === addedBarchartSymbol)) {
323
+ this._positionSymbolAddedEvent.fire(addedBarchartSymbol);
324
+ }
329
325
 
330
326
  recalculatePercentages.call(this);
331
327
  }
@@ -376,49 +372,55 @@ module.exports = (() => {
376
372
  }
377
373
 
378
374
  /**
379
- * Updates the quote for a single symbol; causing updates to any grouping
380
- * level that contains the position(s) for the symbol.
375
+ * Performs a batch update of both position quotes and forex quotes,
376
+ * triggering updates to position(s) and data aggregation(s).
381
377
  *
382
378
  * @public
383
- * @param {Object} quote
379
+ * @param {Array.<Object>} positionQuotes
380
+ * @param {Array.<Object>} forexQuotes
384
381
  */
385
- setPositionQuote(quote) {
386
- assert.argumentIsRequired(quote, 'quote', Object);
382
+ setQuotes(positionQuotes, forexQuotes) {
383
+ assert.argumentIsArray(positionQuotes, 'positionQuotes');
384
+ assert.argumentIsArray(forexQuotes, 'forexQuotes');
387
385
 
388
- const symbol = quote.symbol;
389
-
390
- if (symbol) {
391
- if (this._symbols.hasOwnProperty(symbol)) {
392
- this._symbols[symbol].forEach(item => item.setQuote(quote));
393
- }
386
+ if (positionQuotes.length !== 0) {
387
+ positionQuotes.forEach((quote) => {
388
+ const symbol = quote.symbol;
394
389
 
395
- recalculatePercentages.call(this);
390
+ if (symbol) {
391
+ if (this._symbols.hasOwnProperty(symbol)) {
392
+ this._symbols[ symbol ].forEach(item => item.setQuote(quote));
393
+ }
394
+ }
395
+ });
396
396
  }
397
- }
398
-
399
- /**
400
- * Performs a batch update of quotes; causing updates to any grouping
401
- * level that contains the position(s) for the symbol(s).
402
- *
403
- * @public
404
- * @param {Object} quote
405
- */
406
- setPositionQuotes(quotes) {
407
- assert.argumentIsArray(quotes, 'quotes');
408
397
 
409
- this.startTransaction(() => {
410
- quotes.forEach((quote) => {
398
+ if (forexQuotes.length !== 0) {
399
+ forexQuotes.forEach((quote) => {
411
400
  const symbol = quote.symbol;
412
401
 
413
402
  if (symbol) {
414
- if (this._symbols.hasOwnProperty(symbol)) {
415
- this._symbols[symbol].forEach(item => item.setQuote(quote));
403
+ const rate = Rate.fromPair(quote.lastPrice, symbol);
404
+ const index = this._forexQuotes.findIndex(existing => existing.formatPair() === rate.formatPair());
405
+
406
+ if (index < 0) {
407
+ this._forexQuotes.push(rate);
408
+ } else {
409
+ this._forexQuotes[index] = rate;
416
410
  }
411
+
412
+ Object.keys(this._trees).forEach((key) => {
413
+ this._trees[key].walk(group => group.setForexRates(this._forexQuotes), true, false);
414
+ });
415
+
416
+ recalculatePercentages.call(this);
417
417
  }
418
418
  });
419
+ }
419
420
 
421
+ if (positionQuotes.length !== 0 || forexQuotes.length !== 0) {
420
422
  recalculatePercentages.call(this);
421
- });
423
+ }
422
424
  }
423
425
 
424
426
  /**
@@ -441,34 +443,6 @@ module.exports = (() => {
441
443
  return this._forexQuotes;
442
444
  }
443
445
 
444
- /**
445
- * Updates the forex quote for a single currency pair; causing updates to
446
- * any grouping level that contains that requires translation.
447
- *
448
- * @public
449
- * @param {Object} quote
450
- */
451
- setForexQuote(quote) {
452
- assert.argumentIsRequired(quote, 'quote', Object);
453
-
454
- const symbol = quote.symbol;
455
-
456
- if (symbol) {
457
- const rate = Rate.fromPair(quote.lastPrice, symbol);
458
- const index = this._forexQuotes.findIndex(existing => existing.formatPair() === rate.formatPair());
459
-
460
- if (index < 0) {
461
- this._forexQuotes.push(rate);
462
- } else {
463
- this._forexQuotes[ index ] = rate;
464
- }
465
-
466
- Object.keys(this._trees).forEach(key => this._trees[ key ].walk(group => group.setForexRates(this._forexQuotes), true, false));
467
-
468
- recalculatePercentages.call(this);
469
- }
470
- }
471
-
472
446
  /**
473
447
  * Updates fundamental data for a single symbol.
474
448
  *
@@ -617,39 +591,6 @@ module.exports = (() => {
617
591
  return this.getPositions(portfolio).find(p => p.position === position) || null;
618
592
  }
619
593
 
620
- /**
621
- * Pauses aggregation calculations during the processing of an action.
622
- *
623
- * @public
624
- * @param {Function} executor
625
- * @param {String=|Array.<String>=} names
626
- */
627
- startTransaction(executor, names) {
628
- let namesToUse;
629
-
630
- if (is.array(names)) {
631
- assert.argumentIsArray(names, 'names', String);
632
-
633
- namesToUse = names;
634
- } else {
635
- assert.argumentIsOptional(names, 'names', String);
636
-
637
- if (names) {
638
- namesToUse = [ names ];
639
- } else {
640
- namesToUse = Object.keys(this._trees);
641
- }
642
- }
643
-
644
- assert.argumentIsRequired(executor, 'executor', Function);
645
-
646
- namesToUse.forEach((name) => this._trees[name].walk(group => group.setSuspended(true), false, false));
647
-
648
- executor(this);
649
-
650
- namesToUse.forEach((name) => this._trees[name].walk(group => group.setSuspended(false), false, false));
651
- }
652
-
653
594
  /**
654
595
  * Registers an observer for symbol addition (this occurs when a new position is added
655
596
  * for a symbol that does not already exist in the container). This event only fires
@@ -54,7 +54,6 @@ module.exports = (() => {
54
54
  this._aggregateCash = is.boolean(aggregateCash) && aggregateCash;
55
55
 
56
56
  this._excluded = false;
57
- this._suspended = false;
58
57
  this._showClosedPositions = false;
59
58
 
60
59
  this._groupExcludedChangeEvent = new Event(this);
@@ -255,10 +254,6 @@ module.exports = (() => {
255
254
  return this._single;
256
255
  }
257
256
 
258
- get suspended() {
259
- return this._suspended;
260
- }
261
-
262
257
  /**
263
258
  * Indicates if the group should be excluded from higher-level aggregations.
264
259
  *
@@ -381,24 +376,6 @@ module.exports = (() => {
381
376
  }
382
377
  }
383
378
 
384
- /**
385
- * Stops (or starts) group-level aggregation calculations.
386
- *
387
- * @public
388
- * @param {Boolean} value
389
- */
390
- setSuspended(value) {
391
- assert.argumentIsRequired(value, 'value', Boolean);
392
-
393
- if (this._suspended !== value) {
394
- this._suspended = value;
395
-
396
- if (!this._suspended) {
397
- this.refresh();
398
- }
399
- }
400
- }
401
-
402
379
  /**
403
380
  * Updates the portfolio data. For example, a portfolio's name might change. This
404
381
  * function only affects {@link PositionLevelType.PORTFOLIO} groups.
@@ -430,16 +407,11 @@ module.exports = (() => {
430
407
  }
431
408
 
432
409
  /**
433
- * Causes all aggregated data to be recalculated (assuming the group has not
434
- * been suspended).
410
+ * Causes all aggregated data to be recalculated.
435
411
  *
436
412
  * @public
437
413
  */
438
414
  refresh() {
439
- if (this._suspended) {
440
- return;
441
- }
442
-
443
415
  calculateStaticData(this, this._rates);
444
416
  calculatePriceData(this, this._rates, null, true);
445
417
  }
@@ -643,10 +615,6 @@ module.exports = (() => {
643
615
  }
644
616
 
645
617
  function calculateStaticData(group, rates) {
646
- if (group.suspended) {
647
- return;
648
- }
649
-
650
618
  const actual = group._dataActual;
651
619
  const format = group._dataFormat;
652
620
 
@@ -743,10 +711,6 @@ module.exports = (() => {
743
711
  }
744
712
 
745
713
  function calculatePriceData(group, rates, item, forceRefresh) {
746
- if (group.suspended) {
747
- return;
748
- }
749
-
750
714
  const currency = group.currency;
751
715
 
752
716
  const actual = group._dataActual;
@@ -832,10 +796,6 @@ module.exports = (() => {
832
796
  }
833
797
 
834
798
  function calculateMarketPercent(group, rates, parentGroup, portfolioGroup) {
835
- if (group.suspended) {
836
- return;
837
- }
838
-
839
799
  const actual = group._dataActual;
840
800
  const format = group._dataFormat;
841
801
  const excluded = group._excluded;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@barchart/portfolio-api-common",
3
- "version": "1.0.268",
3
+ "version": "1.1.0",
4
4
  "description": "Common classes used by the Portfolio system",
5
5
  "author": {
6
6
  "name": "Bryan Ingle",
@@ -1,4 +1,4 @@
1
- (function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i<t.length;i++)o(t[i]);return o}return r})()({1:[function(require,module,exports){
1
+ (function(){function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s}return e})()({1:[function(require,module,exports){
2
2
  const uuid = require('uuid');
3
3
 
4
4
  const assert = require('@barchart/common-js/lang/assert'),
@@ -957,7 +957,7 @@ module.exports = (() => {
957
957
 
958
958
  },{"@barchart/common-js/lang/Enum":21,"@barchart/common-js/lang/assert":24}],5:[function(require,module,exports){
959
959
  const assert = require('@barchart/common-js/lang/assert'),
960
- array = require('@barchart/common-js/lang/array')
960
+ array = require('@barchart/common-js/lang/array');
961
961
 
962
962
  const InstrumentType = require('./InstrumentType'),
963
963
  PositionDirection = require('./PositionDirection'),
@@ -983,22 +983,12 @@ module.exports = (() => {
983
983
  * @public
984
984
  * @static
985
985
  * @param {Array.<Object>} transactions
986
- * @param {Boolean=} partial - If true, sequence validation starts with the array's first transaction.
987
986
  * @return {boolean}
988
987
  */
989
- static validateOrder(transactions, partial) {
988
+ static validateOrder(transactions) {
990
989
  assert.argumentIsArray(transactions, 'transactions');
991
- assert.argumentIsOptional(partial, 'partial', Boolean);
992
990
 
993
- let startSequence;
994
-
995
- if (partial && transactions.length !== 0) {
996
- startSequence = array.first(transactions).sequence;
997
- } else {
998
- startSequence = 1;
999
- }
1000
-
1001
- return transactions.every((t, i) => t.sequence === (i + startSequence) && (i === 0 || !t.date.getIsBefore(transactions[i - 1].date)));
991
+ return transactions.every((t, i) => t.sequence === (i + 1) && (i === 0 || !t.date.getIsBefore(transactions[i - 1].date)));
1002
992
  }
1003
993
 
1004
994
  /**
@@ -1380,11 +1370,9 @@ module.exports = (() => {
1380
1370
  assert.argumentIsRequired(portfolio, 'portfolio', Object);
1381
1371
  assert.argumentIsRequired(portfolio.portfolio, 'portfolio.portfolio', String);
1382
1372
 
1383
- this.startTransaction(() => {
1384
- getPositionItemsForPortfolio(this._items, portfolio.portfolio).forEach(item => item.updatePortfolio(portfolio));
1373
+ getPositionItemsForPortfolio(this._items, portfolio.portfolio).forEach(item => item.updatePortfolio(portfolio));
1385
1374
 
1386
- updateEmptyPortfolioGroups.call(this, portfolio);
1387
- });
1375
+ updateEmptyPortfolioGroups.call(this, portfolio);
1388
1376
  }
1389
1377
 
1390
1378
  /**
@@ -1399,19 +1387,19 @@ module.exports = (() => {
1399
1387
  assert.argumentIsRequired(portfolio, 'portfolio', Object);
1400
1388
  assert.argumentIsRequired(portfolio.portfolio, 'portfolio.portfolio', String);
1401
1389
 
1402
- this.startTransaction(() => {
1403
- getPositionItemsForPortfolio(this._items, portfolio.portfolio).forEach(item => removePositionItem.call(this, item));
1390
+ getPositionItemsForPortfolio(this._items, portfolio.portfolio).forEach(item => removePositionItem.call(this, item));
1404
1391
 
1405
- delete this._portfolios[portfolio.portfolio];
1392
+ delete this._portfolios[portfolio.portfolio];
1406
1393
 
1407
- Object.keys(this._trees).forEach((key) => {
1408
- this._trees[key].walk((group, groupNode) => {
1409
- if (group.definition.type === PositionLevelType.PORTFOLIO && group.key === PositionLevelDefinition.getKeyForPortfolioGroup(portfolio)) {
1410
- severGroupNode.call(this, groupNode);
1411
- }
1412
- }, true, false);
1413
- });
1394
+ Object.keys(this._trees).forEach((key) => {
1395
+ this._trees[key].walk((group, groupNode) => {
1396
+ if (group.definition.type === PositionLevelType.PORTFOLIO && group.key === PositionLevelDefinition.getKeyForPortfolioGroup(portfolio)) {
1397
+ severGroupNode.call(this, groupNode);
1398
+ }
1399
+ }, true, false);
1414
1400
  });
1401
+
1402
+ recalculatePercentages.call(this);
1415
1403
  }
1416
1404
 
1417
1405
  /**
@@ -1432,56 +1420,54 @@ module.exports = (() => {
1432
1420
  return;
1433
1421
  }
1434
1422
 
1435
- this.startTransaction(() => {
1436
- const existingBarchartSymbols = this.getPositionSymbols(false);
1423
+ const existingBarchartSymbols = this.getPositionSymbols(false);
1437
1424
 
1438
- removePositionItem.call(this, this._items.find((item) => item.position.position === position.position));
1425
+ removePositionItem.call(this, this._items.find((item) => item.position.position === position.position));
1439
1426
 
1440
- summaries.forEach((summary) => {
1441
- addSummaryCurrent(this._summariesCurrent, summary, this._currentSummaryFrame, this._currentSummaryRange);
1442
- addSummaryPrevious(this._summariesPrevious, summary, this._previousSummaryFrame, this._previousSummaryRanges);
1443
- });
1427
+ summaries.forEach((summary) => {
1428
+ addSummaryCurrent(this._summariesCurrent, summary, this._currentSummaryFrame, this._currentSummaryRange);
1429
+ addSummaryPrevious(this._summariesPrevious, summary, this._previousSummaryFrame, this._previousSummaryRanges);
1430
+ });
1444
1431
 
1445
- const item = createPositionItem.call(this, position);
1432
+ const item = createPositionItem.call(this, position);
1446
1433
 
1447
- addBarchartSymbol(this._symbols, item);
1448
- addDisplaySymbol(this._symbolsDisplay, item);
1434
+ addBarchartSymbol(this._symbols, item);
1435
+ addDisplaySymbol(this._symbolsDisplay, item);
1449
1436
 
1450
- this._items.push(item);
1437
+ this._items.push(item);
1451
1438
 
1452
- const createGroupOrInjectItem = (parentTree, treeDefinition, levelDefinitions) => {
1453
- if (levelDefinitions.length === 0) {
1454
- return;
1455
- }
1439
+ const createGroupOrInjectItem = (parentTree, treeDefinition, levelDefinitions) => {
1440
+ if (levelDefinitions.length === 0) {
1441
+ return;
1442
+ }
1456
1443
 
1457
- const levelDefinition = levelDefinitions[0];
1458
- const levelKey = levelDefinition.keySelector(item);
1444
+ const levelDefinition = levelDefinitions[0];
1445
+ const levelKey = levelDefinition.keySelector(item);
1459
1446
 
1460
- let groupTree;
1447
+ let groupTree;
1461
1448
 
1462
- if (parentTree.getChildren().length > 0) {
1463
- groupTree = parentTree.findChild(childGroup => childGroup.key === levelKey) || null;
1464
- } else {
1465
- groupTree = null;
1466
- }
1449
+ if (parentTree.getChildren().length > 0) {
1450
+ groupTree = parentTree.findChild(childGroup => childGroup.key === levelKey) || null;
1451
+ } else {
1452
+ groupTree = null;
1453
+ }
1467
1454
 
1468
- if (groupTree !== null) {
1469
- groupTree.getValue().addItem(item);
1455
+ if (groupTree !== null) {
1456
+ groupTree.getValue().addItem(item);
1470
1457
 
1471
- createGroupOrInjectItem(groupTree, treeDefinition, array.dropLeft(levelDefinitions));
1472
- } else {
1473
- createGroups.call(this, parentTree, [ item ], treeDefinition, levelDefinitions, [ ]);
1474
- }
1475
- };
1458
+ createGroupOrInjectItem(groupTree, treeDefinition, array.dropLeft(levelDefinitions));
1459
+ } else {
1460
+ createGroups.call(this, parentTree, [ item ], treeDefinition, levelDefinitions, [ ]);
1461
+ }
1462
+ };
1476
1463
 
1477
- this._definitions.forEach(definition => createGroupOrInjectItem(this._trees[definition.name], definition, definition.definitions));
1464
+ this._definitions.forEach(definition => createGroupOrInjectItem(this._trees[definition.name], definition, definition.definitions));
1478
1465
 
1479
- const addedBarchartSymbol = extractSymbolForBarchart(item.position);
1466
+ const addedBarchartSymbol = extractSymbolForBarchart(item.position);
1480
1467
 
1481
- if (addedBarchartSymbol !== null && !existingBarchartSymbols.some(existingBarchartSymbol => existingBarchartSymbol === addedBarchartSymbol)) {
1482
- this._positionSymbolAddedEvent.fire(addedBarchartSymbol);
1483
- }
1484
- });
1468
+ if (addedBarchartSymbol !== null && !existingBarchartSymbols.some(existingBarchartSymbol => existingBarchartSymbol === addedBarchartSymbol)) {
1469
+ this._positionSymbolAddedEvent.fire(addedBarchartSymbol);
1470
+ }
1485
1471
 
1486
1472
  recalculatePercentages.call(this);
1487
1473
  }
@@ -1532,49 +1518,55 @@ module.exports = (() => {
1532
1518
  }
1533
1519
 
1534
1520
  /**
1535
- * Updates the quote for a single symbol; causing updates to any grouping
1536
- * level that contains the position(s) for the symbol.
1521
+ * Performs a batch update of both position quotes and forex quotes,
1522
+ * triggering updates to position(s) and data aggregation(s).
1537
1523
  *
1538
1524
  * @public
1539
- * @param {Object} quote
1525
+ * @param {Array.<Object>} positionQuotes
1526
+ * @param {Array.<Object>} forexQuotes
1540
1527
  */
1541
- setPositionQuote(quote) {
1542
- assert.argumentIsRequired(quote, 'quote', Object);
1543
-
1544
- const symbol = quote.symbol;
1528
+ setQuotes(positionQuotes, forexQuotes) {
1529
+ assert.argumentIsArray(positionQuotes, 'positionQuotes');
1530
+ assert.argumentIsArray(forexQuotes, 'forexQuotes');
1545
1531
 
1546
- if (symbol) {
1547
- if (this._symbols.hasOwnProperty(symbol)) {
1548
- this._symbols[symbol].forEach(item => item.setQuote(quote));
1549
- }
1532
+ if (positionQuotes.length !== 0) {
1533
+ positionQuotes.forEach((quote) => {
1534
+ const symbol = quote.symbol;
1550
1535
 
1551
- recalculatePercentages.call(this);
1536
+ if (symbol) {
1537
+ if (this._symbols.hasOwnProperty(symbol)) {
1538
+ this._symbols[ symbol ].forEach(item => item.setQuote(quote));
1539
+ }
1540
+ }
1541
+ });
1552
1542
  }
1553
- }
1554
-
1555
- /**
1556
- * Performs a batch update of quotes; causing updates to any grouping
1557
- * level that contains the position(s) for the symbol(s).
1558
- *
1559
- * @public
1560
- * @param {Object} quote
1561
- */
1562
- setPositionQuotes(quotes) {
1563
- assert.argumentIsArray(quotes, 'quotes');
1564
1543
 
1565
- this.startTransaction(() => {
1566
- quotes.forEach((quote) => {
1544
+ if (forexQuotes.length !== 0) {
1545
+ forexQuotes.forEach((quote) => {
1567
1546
  const symbol = quote.symbol;
1568
1547
 
1569
1548
  if (symbol) {
1570
- if (this._symbols.hasOwnProperty(symbol)) {
1571
- this._symbols[symbol].forEach(item => item.setQuote(quote));
1549
+ const rate = Rate.fromPair(quote.lastPrice, symbol);
1550
+ const index = this._forexQuotes.findIndex(existing => existing.formatPair() === rate.formatPair());
1551
+
1552
+ if (index < 0) {
1553
+ this._forexQuotes.push(rate);
1554
+ } else {
1555
+ this._forexQuotes[index] = rate;
1572
1556
  }
1557
+
1558
+ Object.keys(this._trees).forEach((key) => {
1559
+ this._trees[key].walk(group => group.setForexRates(this._forexQuotes), true, false);
1560
+ });
1561
+
1562
+ recalculatePercentages.call(this);
1573
1563
  }
1574
1564
  });
1565
+ }
1575
1566
 
1567
+ if (positionQuotes.length !== 0 || forexQuotes.length !== 0) {
1576
1568
  recalculatePercentages.call(this);
1577
- });
1569
+ }
1578
1570
  }
1579
1571
 
1580
1572
  /**
@@ -1597,34 +1589,6 @@ module.exports = (() => {
1597
1589
  return this._forexQuotes;
1598
1590
  }
1599
1591
 
1600
- /**
1601
- * Updates the forex quote for a single currency pair; causing updates to
1602
- * any grouping level that contains that requires translation.
1603
- *
1604
- * @public
1605
- * @param {Object} quote
1606
- */
1607
- setForexQuote(quote) {
1608
- assert.argumentIsRequired(quote, 'quote', Object);
1609
-
1610
- const symbol = quote.symbol;
1611
-
1612
- if (symbol) {
1613
- const rate = Rate.fromPair(quote.lastPrice, symbol);
1614
- const index = this._forexQuotes.findIndex(existing => existing.formatPair() === rate.formatPair());
1615
-
1616
- if (index < 0) {
1617
- this._forexQuotes.push(rate);
1618
- } else {
1619
- this._forexQuotes[ index ] = rate;
1620
- }
1621
-
1622
- Object.keys(this._trees).forEach(key => this._trees[ key ].walk(group => group.setForexRates(this._forexQuotes), true, false));
1623
-
1624
- recalculatePercentages.call(this);
1625
- }
1626
- }
1627
-
1628
1592
  /**
1629
1593
  * Updates fundamental data for a single symbol.
1630
1594
  *
@@ -1773,39 +1737,6 @@ module.exports = (() => {
1773
1737
  return this.getPositions(portfolio).find(p => p.position === position) || null;
1774
1738
  }
1775
1739
 
1776
- /**
1777
- * Pauses aggregation calculations during the processing of an action.
1778
- *
1779
- * @public
1780
- * @param {Function} executor
1781
- * @param {String=|Array.<String>=} names
1782
- */
1783
- startTransaction(executor, names) {
1784
- let namesToUse;
1785
-
1786
- if (is.array(names)) {
1787
- assert.argumentIsArray(names, 'names', String);
1788
-
1789
- namesToUse = names;
1790
- } else {
1791
- assert.argumentIsOptional(names, 'names', String);
1792
-
1793
- if (names) {
1794
- namesToUse = [ names ];
1795
- } else {
1796
- namesToUse = Object.keys(this._trees);
1797
- }
1798
- }
1799
-
1800
- assert.argumentIsRequired(executor, 'executor', Function);
1801
-
1802
- namesToUse.forEach((name) => this._trees[name].walk(group => group.setSuspended(true), false, false));
1803
-
1804
- executor(this);
1805
-
1806
- namesToUse.forEach((name) => this._trees[name].walk(group => group.setSuspended(false), false, false));
1807
- }
1808
-
1809
1740
  /**
1810
1741
  * Registers an observer for symbol addition (this occurs when a new position is added
1811
1742
  * for a symbol that does not already exist in the container). This event only fires
@@ -2212,7 +2143,6 @@ module.exports = (() => {
2212
2143
  this._aggregateCash = is.boolean(aggregateCash) && aggregateCash;
2213
2144
 
2214
2145
  this._excluded = false;
2215
- this._suspended = false;
2216
2146
  this._showClosedPositions = false;
2217
2147
 
2218
2148
  this._groupExcludedChangeEvent = new Event(this);
@@ -2413,10 +2343,6 @@ module.exports = (() => {
2413
2343
  return this._single;
2414
2344
  }
2415
2345
 
2416
- get suspended() {
2417
- return this._suspended;
2418
- }
2419
-
2420
2346
  /**
2421
2347
  * Indicates if the group should be excluded from higher-level aggregations.
2422
2348
  *
@@ -2539,24 +2465,6 @@ module.exports = (() => {
2539
2465
  }
2540
2466
  }
2541
2467
 
2542
- /**
2543
- * Stops (or starts) group-level aggregation calculations.
2544
- *
2545
- * @public
2546
- * @param {Boolean} value
2547
- */
2548
- setSuspended(value) {
2549
- assert.argumentIsRequired(value, 'value', Boolean);
2550
-
2551
- if (this._suspended !== value) {
2552
- this._suspended = value;
2553
-
2554
- if (!this._suspended) {
2555
- this.refresh();
2556
- }
2557
- }
2558
- }
2559
-
2560
2468
  /**
2561
2469
  * Updates the portfolio data. For example, a portfolio's name might change. This
2562
2470
  * function only affects {@link PositionLevelType.PORTFOLIO} groups.
@@ -2588,16 +2496,11 @@ module.exports = (() => {
2588
2496
  }
2589
2497
 
2590
2498
  /**
2591
- * Causes all aggregated data to be recalculated (assuming the group has not
2592
- * been suspended).
2499
+ * Causes all aggregated data to be recalculated.
2593
2500
  *
2594
2501
  * @public
2595
2502
  */
2596
2503
  refresh() {
2597
- if (this._suspended) {
2598
- return;
2599
- }
2600
-
2601
2504
  calculateStaticData(this, this._rates);
2602
2505
  calculatePriceData(this, this._rates, null, true);
2603
2506
  }
@@ -2801,10 +2704,6 @@ module.exports = (() => {
2801
2704
  }
2802
2705
 
2803
2706
  function calculateStaticData(group, rates) {
2804
- if (group.suspended) {
2805
- return;
2806
- }
2807
-
2808
2707
  const actual = group._dataActual;
2809
2708
  const format = group._dataFormat;
2810
2709
 
@@ -2901,10 +2800,6 @@ module.exports = (() => {
2901
2800
  }
2902
2801
 
2903
2802
  function calculatePriceData(group, rates, item, forceRefresh) {
2904
- if (group.suspended) {
2905
- return;
2906
- }
2907
-
2908
2803
  const currency = group.currency;
2909
2804
 
2910
2805
  const actual = group._dataActual;
@@ -2990,10 +2885,6 @@ module.exports = (() => {
2990
2885
  }
2991
2886
 
2992
2887
  function calculateMarketPercent(group, rates, parentGroup, portfolioGroup) {
2993
- if (group.suspended) {
2994
- return;
2995
- }
2996
-
2997
2888
  const actual = group._dataActual;
2998
2889
  const format = group._dataFormat;
2999
2890
  const excluded = group._excluded;
@@ -4060,31 +3951,14 @@ module.exports = function () {
4060
3951
  }
4061
3952
 
4062
3953
  /**
4063
- * Gets the root node.
3954
+ * Returns the parent node. If this is the root node, a null value is returned.
4064
3955
  *
4065
3956
  * @public
4066
- * @returns {Tree}
3957
+ * @returns {Tree|null}
4067
3958
  */
4068
3959
 
4069
3960
 
4070
3961
  _createClass(Tree, [{
4071
- key: 'getRoot',
4072
- value: function getRoot() {
4073
- if (this.getIsRoot()) {
4074
- return this;
4075
- } else {
4076
- return this._parent.getRoot();
4077
- }
4078
- }
4079
-
4080
- /**
4081
- * Returns the parent node. If this is the root node, a null value is returned.
4082
- *
4083
- * @public
4084
- * @returns {Tree|null}
4085
- */
4086
-
4087
- }, {
4088
3962
  key: 'getParent',
4089
3963
  value: function getParent() {
4090
3964
  return this._parent;
@@ -4185,23 +4059,6 @@ module.exports = function () {
4185
4059
  }
4186
4060
  }
4187
4061
 
4188
- /**
4189
- * Removes the current node from the parent tree. Use on a root node
4190
- * has no effect.
4191
- *
4192
- * @public
4193
- */
4194
-
4195
- }, {
4196
- key: 'sever',
4197
- value: function sever() {
4198
- if (this.getIsRoot()) {
4199
- return;
4200
- }
4201
-
4202
- this.getParent().removeChild(this);
4203
- }
4204
-
4205
4062
  /**
4206
4063
  * Searches the children nodes for the first child node that matches the
4207
4064
  * predicate.
@@ -4306,33 +4163,6 @@ module.exports = function () {
4306
4163
  }
4307
4164
  }
4308
4165
 
4309
- /**
4310
- * Climbs the tree, evaluating each parent until a predicate is matched. Once matched,
4311
- * the {@link Tree} node is returned. Otherwise, if the predicate cannot be matched,
4312
- * a null value is returned.
4313
- *
4314
- * @public
4315
- * @param {Tree~nodePredicate} predicate - A predicate that tests each child node. The predicate takes two arguments -- the node's value, and the node itself.
4316
- * @param {boolean=} includeCurrentNode - If true, the predicate will be applied to the current node.
4317
- * @returns {Tree|null}
4318
- */
4319
-
4320
- }, {
4321
- key: 'findParent',
4322
- value: function findParent(predicate, includeCurrentNode) {
4323
- var returnRef = void 0;
4324
-
4325
- if (is.boolean(includeCurrentNode) && includeCurrentNode && predicate(this.getValue(), this)) {
4326
- returnRef = this;
4327
- } else if (this._parent !== null) {
4328
- returnRef = this._parent.findParent(predicate, true);
4329
- } else {
4330
- returnRef = null;
4331
- }
4332
-
4333
- return returnRef;
4334
- }
4335
-
4336
4166
  /**
4337
4167
  * Creates a representation of the tree using JavaScript objects and arrays.
4338
4168
  *
@@ -5623,20 +5453,6 @@ module.exports = function () {
5623
5453
  return this._big.gt(getBig(other));
5624
5454
  }
5625
5455
 
5626
- /**
5627
- * Returns true if the current instance is greater than or equal to the value.
5628
- *
5629
- * @public
5630
- * @param {Decimal|Number|String} other - The value to compare.
5631
- * @returns {Boolean}
5632
- */
5633
-
5634
- }, {
5635
- key: 'getIsGreaterThanOrEqual',
5636
- value: function getIsGreaterThanOrEqual(other) {
5637
- return this._big.gte(getBig(other));
5638
- }
5639
-
5640
5456
  /**
5641
5457
  * Returns true if the current instance is less than the value.
5642
5458
  *
@@ -5651,20 +5467,6 @@ module.exports = function () {
5651
5467
  return this._big.lt(getBig(other));
5652
5468
  }
5653
5469
 
5654
- /**
5655
- * Returns true if the current instance is less than or equal to the value.
5656
- *
5657
- * @public
5658
- * @param {Decimal|Number|String} other - The value to compare.
5659
- * @returns {Boolean}
5660
- */
5661
-
5662
- }, {
5663
- key: 'getIsLessThanOrEqual',
5664
- value: function getIsLessThanOrEqual(other) {
5665
- return this._big.lte(getBig(other));
5666
- }
5667
-
5668
5470
  /**
5669
5471
  * Returns true if the current instance is equal to the value.
5670
5472
  *
@@ -5864,9 +5666,9 @@ module.exports = function () {
5864
5666
  assert.argumentIsRequired(a, 'a', Decimal, 'Decimal');
5865
5667
  assert.argumentIsRequired(b, 'b', Decimal, 'Decimal');
5866
5668
 
5867
- if (a._big.gt(b._big)) {
5669
+ if (a._big.gt(b)) {
5868
5670
  return 1;
5869
- } else if (a._big.lt(b._big)) {
5671
+ } else if (a._big.lt(b)) {
5870
5672
  return -1;
5871
5673
  } else {
5872
5674
  return 0;
@@ -6327,10 +6129,12 @@ var _createClass = function () { function defineProperties(target, props) { for
6327
6129
  function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
6328
6130
 
6329
6131
  var assert = require('./assert'),
6132
+ is = require('./is'),
6330
6133
  memoize = require('./memoize');
6331
6134
 
6332
6135
  var Currency = require('./Currency'),
6333
- Decimal = require('./Decimal');
6136
+ Decimal = require('./Decimal'),
6137
+ Enum = require('./Enum');
6334
6138
 
6335
6139
  module.exports = function () {
6336
6140
  'use strict';
@@ -6510,7 +6314,12 @@ module.exports = function () {
6510
6314
  assert.argumentIsRequired(amount, 'amount', Decimal, 'Decimal');
6511
6315
  assert.argumentIsRequired(currency, 'currency', Currency, 'Currency');
6512
6316
  assert.argumentIsRequired(desiredCurrency, 'desiredCurrency', Currency, 'Currency');
6513
- //assert.argumentIsArray(rates, 'rates', Rate, 'Rate');
6317
+
6318
+ for (var _len = arguments.length, rates = Array(_len > 3 ? _len - 3 : 0), _key = 3; _key < _len; _key++) {
6319
+ rates[_key - 3] = arguments[_key];
6320
+ }
6321
+
6322
+ assert.argumentIsArray(rates, 'rates', Rate, 'Rate');
6514
6323
 
6515
6324
  var converted = void 0;
6516
6325
 
@@ -6520,10 +6329,6 @@ module.exports = function () {
6520
6329
  var numerator = desiredCurrency;
6521
6330
  var denominator = currency;
6522
6331
 
6523
- for (var _len = arguments.length, rates = Array(_len > 3 ? _len - 3 : 0), _key = 3; _key < _len; _key++) {
6524
- rates[_key - 3] = arguments[_key];
6525
- }
6526
-
6527
6332
  var rate = rates.find(function (r) {
6528
6333
  return r.numerator === numerator && r.denominator === denominator || r.numerator === denominator && r.denominator === numerator;
6529
6334
  });
@@ -6574,7 +6379,7 @@ module.exports = function () {
6574
6379
  return Rate;
6575
6380
  }();
6576
6381
 
6577
- },{"./Currency":17,"./Decimal":19,"./assert":24,"./memoize":27}],23:[function(require,module,exports){
6382
+ },{"./Currency":17,"./Decimal":19,"./Enum":21,"./assert":24,"./is":26,"./memoize":27}],23:[function(require,module,exports){
6578
6383
  'use strict';
6579
6384
 
6580
6385
  var assert = require('./assert'),
@@ -6951,26 +6756,6 @@ module.exports = function () {
6951
6756
  });
6952
6757
 
6953
6758
  return returnRef;
6954
- },
6955
-
6956
-
6957
- /**
6958
- * Removes the first item from an array which matches a predicate.
6959
- *
6960
- * @static
6961
- * @public
6962
- * @param {Array} a
6963
- * @param {Function} predicate
6964
- */
6965
- remove: function remove(a, predicate) {
6966
- assert.argumentIsArray(a, 'a');
6967
- assert.argumentIsRequired(predicate, 'predicate', Function);
6968
-
6969
- var index = a.findIndex(predicate);
6970
-
6971
- if (!(index < 0)) {
6972
- a.splice(index, 1);
6973
- }
6974
6759
  }
6975
6760
  };
6976
6761
  }();
@@ -9202,14 +8987,6 @@ describe('When validating transaction order', () => {
9202
8987
  it('An array of transactions with ordered sequences, on the reversed days should not be valid', () => {
9203
8988
  expect(TransactionValidator.validateOrder([ build(1, '2018-05-02'), build(2, '2018-05-01'), build(3, '2018-04-30') ])).toEqual(false);
9204
8989
  });
9205
-
9206
- it('A partial array of transactions with ordered sequences (starting after one), on the same day should be valid', () => {
9207
- expect(TransactionValidator.validateOrder([ build(3, '2018-04-30'), build(4, '2018-04-30'), build(5, '2018-04-30') ], true)).toEqual(true);
9208
- });
9209
-
9210
- it('A partial array of transactions with gap in sequences (starting after one), on the same day should be not valid', () => {
9211
- expect(TransactionValidator.validateOrder([ build(3, '2018-04-30'), build(5, '2018-04-30'), build(6, '2018-04-30') ], true)).toEqual(false);
9212
- });
9213
8990
  });
9214
8991
 
9215
8992
  },{"./../../../lib/data/TransactionValidator":5,"@barchart/common-js/lang/Day":18}],37:[function(require,module,exports){
@@ -40,12 +40,4 @@ describe('When validating transaction order', () => {
40
40
  it('An array of transactions with ordered sequences, on the reversed days should not be valid', () => {
41
41
  expect(TransactionValidator.validateOrder([ build(1, '2018-05-02'), build(2, '2018-05-01'), build(3, '2018-04-30') ])).toEqual(false);
42
42
  });
43
-
44
- it('A partial array of transactions with ordered sequences (starting after one), on the same day should be valid', () => {
45
- expect(TransactionValidator.validateOrder([ build(3, '2018-04-30'), build(4, '2018-04-30'), build(5, '2018-04-30') ], true)).toEqual(true);
46
- });
47
-
48
- it('A partial array of transactions with gap in sequences (starting after one), on the same day should be not valid', () => {
49
- expect(TransactionValidator.validateOrder([ build(3, '2018-04-30'), build(5, '2018-04-30'), build(6, '2018-04-30') ], true)).toEqual(false);
50
- });
51
43
  });