@barchart/portfolio-api-common 1.2.92 → 1.2.96

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.
@@ -8,7 +8,7 @@ module.exports = (() => {
8
8
  'use strict';
9
9
 
10
10
  /**
11
- * An enumeration used to define timeframes for position summaries.
11
+ * An enumeration used to define time frames for position summaries.
12
12
  *
13
13
  * @public
14
14
  * @extends {Enum}
@@ -94,22 +94,44 @@ module.exports = (() => {
94
94
  * @return {Array.<PositionSummaryRange>}
95
95
  */
96
96
  getRangesFromDate(date) {
97
+ assert.argumentIsRequired(date, 'date', Day, 'Day');
98
+
97
99
  const transaction = { date: date, snapshot: { open: Decimal.ONE } };
98
100
 
99
101
  return this.getRanges([ transaction ]);
100
102
  }
101
103
 
104
+ /**
105
+ * Returns the range immediately prior to the range containing the
106
+ * date supplied.
107
+ *
108
+ * @public
109
+ * @param {Day} date
110
+ * @param {Number} periods
111
+ */
112
+ getPriorRanges(date, periods) {
113
+ assert.argumentIsRequired(date, 'date', Day, 'Day');
114
+ assert.argumentIsRequired(periods, 'periods', Number, 'Number');
115
+
116
+ const transactionOne = { date: this.getStartDate((periods - 1), date), snapshot: { open: Decimal.ONE } };
117
+ const transactionTwo = { date: date, snapshot: { open: Decimal.ZERO } };
118
+
119
+ return this._rangeCalculator([ transactionOne, transactionTwo ]);
120
+ }
121
+
102
122
  /**
103
123
  * Returns the start date for a frame, a given number of periods ago.
104
124
  *
105
125
  * @public
106
126
  * @param {Number} periods
127
+ * @param {Day=} start
107
128
  * @returns {Day}
108
129
  */
109
- getStartDate(periods) {
130
+ getStartDate(periods, start) {
110
131
  assert.argumentIsRequired(periods, 'periods', Number);
132
+ assert.argumentIsOptional(start, 'start', Day, 'Day');
111
133
 
112
- return this._startDateCalculator(periods);
134
+ return this._startDateCalculator(periods, start);
113
135
  }
114
136
 
115
137
  /**
@@ -242,29 +264,29 @@ module.exports = (() => {
242
264
  return ranges;
243
265
  }
244
266
 
245
- function getYearlyStartDate(periods) {
246
- const today = Day.getToday();
267
+ function getYearlyStartDate(periods, date) {
268
+ const today = date || Day.getToday();
247
269
 
248
- return Day.getToday()
270
+ return today
249
271
  .subtractMonths(today.month - 1)
250
272
  .subtractDays(today.day)
251
273
  .subtractYears(periods);
252
274
  }
253
275
 
254
- function getQuarterlyStartDate(periods) {
276
+ function getQuarterlyStartDate(periods, date) {
255
277
  return null;
256
278
  }
257
279
 
258
- function getMonthlyStartDate(periods) {
280
+ function getMonthlyStartDate(periods, date) {
259
281
  return null;
260
282
  }
261
283
 
262
- function getYearToDateStartDate(periods) {
284
+ function getYearToDateStartDate(periods, date) {
263
285
  return null;
264
286
  }
265
287
 
266
288
  function getYearlyRangeDescription(start, end) {
267
- return end.year.toString();
289
+ return `Year ended ${end.year.toString()}`;
268
290
  }
269
291
 
270
292
  function getQuarterlyRangeDescription(start, end) {
@@ -42,20 +42,22 @@ module.exports = (() => {
42
42
  * @param {Array.<Object>} portfolios - The portfolios.
43
43
  * @param {Array.<Object>} positions - The positions (for all of the portfolios).
44
44
  * @param {Array.<Object>} summaries - The positions summaries (for all of the positions).
45
- * @param {PositionSummaryFrame=} - If specified, locks the current (and previous) periods to a specific frame, use for reporting.
45
+ * @param {PositionSummaryFrame=} reportFrame - If specified, locks the current (and previous) periods to a specific frame, use for reporting.
46
46
  */
47
47
  class PositionContainer {
48
- constructor(definitions, portfolios, positions, summaries, frame) {
48
+ constructor(definitions, portfolios, positions, summaries, reportFrame) {
49
49
  assert.argumentIsArray(definitions, 'definitions', PositionTreeDefinition, 'PositionTreeDefinition');
50
50
  assert.argumentIsArray(portfolios, 'portfolios');
51
51
  assert.argumentIsArray(positions, 'positions');
52
52
  assert.argumentIsArray(summaries, 'summaries');
53
- assert.argumentIsOptional(frame, 'frame', PositionSummaryFrame, 'PositionSummaryFrame');
53
+ assert.argumentIsOptional(reportFrame, 'reportFrame', PositionSummaryFrame, 'PositionSummaryFrame');
54
54
 
55
55
  this._definitions = definitions;
56
56
 
57
57
  this._groupBindings = { };
58
58
 
59
+ this._reporting = reportFrame instanceof PositionSummaryFrame;
60
+
59
61
  this._positionSymbolAddedEvent = new Event(this);
60
62
  this._positionSymbolRemovedEvent = new Event(this);
61
63
 
@@ -65,10 +67,10 @@ module.exports = (() => {
65
67
  return map;
66
68
  }, { });
67
69
 
68
- this._currentSummaryFrame = frame || PositionSummaryFrame.YTD;
70
+ this._currentSummaryFrame = reportFrame || PositionSummaryFrame.YTD;
69
71
  this._currentSummaryRange = array.last(this._currentSummaryFrame.getRecentRanges(0));
70
72
 
71
- this._previousSummaryFrame = frame || PositionSummaryFrame.YEARLY;
73
+ this._previousSummaryFrame = reportFrame || PositionSummaryFrame.YEARLY;
72
74
  this._previousSummaryRanges = this._previousSummaryFrame.getRecentRanges(3);
73
75
 
74
76
  if (this._currentSummaryFrame === this._previousSummaryFrame) {
@@ -942,7 +944,7 @@ module.exports = (() => {
942
944
  const currentSummary = this._summariesCurrent[ position.position ] || null;
943
945
  const previousSummaries = this._summariesPrevious[ position.position ] || getSummaryArray(this._previousSummaryRanges);
944
946
 
945
- returnRef = new PositionItem(portfolio, position, currentSummary, previousSummaries);
947
+ returnRef = new PositionItem(portfolio, position, currentSummary, previousSummaries, this._reporting);
946
948
  } else {
947
949
  returnRef = null;
948
950
  }
@@ -75,12 +75,14 @@ module.exports = (() => {
75
75
  this._dataFormat.locked = false;
76
76
  this._dataFormat.newsExists = false;
77
77
  this._dataFormat.quantity = null;
78
+ this._dataFormat.quantityPrevious = null;
78
79
  this._dataFormat.basisPrice = null;
79
80
 
80
81
  this._dataActual.key = this._key;
81
82
  this._dataActual.description = this._description;
82
83
  this._dataActual.newsExists = false;
83
84
  this._dataActual.quantity = null;
85
+ this._dataActual.quantityPrevious = null;
84
86
  this._dataActual.basisPrice = null;
85
87
 
86
88
  if (this._single && items.length === 1) {
@@ -130,10 +132,10 @@ module.exports = (() => {
130
132
  this._dataActual.summaryTotalCurrent = null;
131
133
  this._dataActual.summaryTotalPrevious = null;
132
134
  this._dataActual.summaryTotalPrevious2 = null;
133
- this._dataActual.endingPrevious = null;
134
- this._dataActual.endingPrevious2 = null;
135
- this._dataActual.endingChange = null;
136
- this._dataActual.endingChangePercent = null;
135
+ this._dataActual.marketPrevious = null;
136
+ this._dataActual.marketPrevious2 = null;
137
+ this._dataActual.marketChange = null;
138
+ this._dataActual.marketChangePercent = null;
137
139
  this._dataActual.cashTotal = null;
138
140
 
139
141
  this._dataFormat.currentPrice = null;
@@ -157,10 +159,10 @@ module.exports = (() => {
157
159
  this._dataFormat.summaryTotalPreviousNegative = false;
158
160
  this._dataFormat.summaryTotalPrevious2 = null;
159
161
  this._dataFormat.summaryTotalPrevious2Negative = false;
160
- this._dataFormat.endingPrevious = null;
161
- this._dataFormat.endingPrevious2 = null;
162
- this._dataFormat.endingChange = null;
163
- this._dataFormat.endingChangePercent = null;
162
+ this._dataFormat.marketPrevious = null;
163
+ this._dataFormat.marketPrevious2 = null;
164
+ this._dataFormat.marketChange = null;
165
+ this._dataFormat.marketChangePercent = null;
164
166
  this._dataFormat.cashTotal = null;
165
167
  this._dataFormat.portfolioType = null;
166
168
 
@@ -657,8 +659,8 @@ module.exports = (() => {
657
659
  updates.summaryTotalCurrent = updates.summaryTotalCurrent.add(translate(item, item.data.summaryTotalCurrent));
658
660
  updates.summaryTotalPrevious = updates.summaryTotalPrevious.add(translate(item, item.data.summaryTotalPrevious));
659
661
  updates.summaryTotalPrevious2 = updates.summaryTotalPrevious2.add(translate(item, item.data.summaryTotalPrevious2));
660
- updates.endingPrevious = updates.endingPrevious.add(translate(item, item.data.endingPrevious));
661
- updates.endingPrevious2 = updates.endingPrevious2.add(translate(item, item.data.endingPrevious2));
662
+ updates.marketPrevious = updates.marketPrevious.add(translate(item, item.data.marketPrevious));
663
+ updates.marketPrevious2 = updates.marketPrevious2.add(translate(item, item.data.marketPrevious2));
662
664
 
663
665
  if (item.position.instrument.type === InstrumentType.CASH) {
664
666
  updates.cashTotal = updates.cashTotal.add(translate(item, item.data.market));
@@ -673,8 +675,8 @@ module.exports = (() => {
673
675
  summaryTotalCurrent: Decimal.ZERO,
674
676
  summaryTotalPrevious: Decimal.ZERO,
675
677
  summaryTotalPrevious2: Decimal.ZERO,
676
- endingPrevious: Decimal.ZERO,
677
- endingPrevious2: Decimal.ZERO,
678
+ marketPrevious: Decimal.ZERO,
679
+ marketPrevious2: Decimal.ZERO,
678
680
  cashTotal: Decimal.ZERO
679
681
  });
680
682
 
@@ -685,8 +687,8 @@ module.exports = (() => {
685
687
  actual.summaryTotalCurrent = updates.summaryTotalCurrent;
686
688
  actual.summaryTotalPrevious = updates.summaryTotalPrevious;
687
689
  actual.summaryTotalPrevious2 = updates.summaryTotalPrevious2;
688
- actual.endingPrevious = updates.endingPrevious;
689
- actual.endingPrevious2 = updates.endingPrevious2;
690
+ actual.marketPrevious = updates.marketPrevious;
691
+ actual.marketPrevious2 = updates.marketPrevious2;
690
692
  actual.cashTotal = updates.cashTotal;
691
693
 
692
694
  format.basis = formatCurrency(actual.basis, currency);
@@ -698,8 +700,8 @@ module.exports = (() => {
698
700
  format.summaryTotalPreviousNegative = updates.summaryTotalPrevious.getIsNegative();
699
701
  format.summaryTotalPrevious2 = formatCurrency(updates.summaryTotalPrevious2, currency);
700
702
  format.summaryTotalPrevious2Negative = updates.summaryTotalPrevious2.getIsNegative();
701
- format.endingPrevious = formatCurrency(updates.endingPrevious, currency);
702
- format.endingPrevious2 = formatCurrency(updates.endingPrevious2, currency);
703
+ format.marketPrevious = formatCurrency(updates.marketPrevious, currency);
704
+ format.marketPrevious2 = formatCurrency(updates.marketPrevious2, currency);
703
705
  format.cashTotal = formatCurrency(updates.cashTotal, currency);
704
706
 
705
707
  calculateUnrealizedPercent(group);
@@ -708,9 +710,13 @@ module.exports = (() => {
708
710
  const item = group._items[0];
709
711
 
710
712
  actual.quantity = item.position.snapshot.open;
713
+ actual.quantityPrevious = item.data.quantityPrevious;
714
+
711
715
  actual.basisPrice = item.data.basisPrice;
712
716
 
713
717
  format.quantity = formatDecimal(actual.quantity, 2);
718
+ format.quantityPrevious = formatDecimal(actual.quantityPrevious, 2);
719
+
714
720
  format.basisPrice = formatCurrency(actual.basisPrice, currency);
715
721
 
716
722
  format.invalid = definition.type === PositionLevelType.POSITION && item.invalid;
@@ -797,23 +803,23 @@ module.exports = (() => {
797
803
  actual.summaryTotalCurrent = updates.summaryTotalCurrent;
798
804
  actual.total = updates.unrealized.add(actual.realized).add(actual.income);
799
805
 
800
- let endingChange = updates.market.subtract(actual.endingPrevious);
801
- let endingChangePercent;
806
+ let marketChange = updates.market.subtract(actual.marketPrevious);
807
+ let marketChangePercent;
802
808
 
803
- if (actual.endingPrevious.getIsZero()) {
804
- if (endingChange.getIsPositive()) {
805
- endingChangePercent = Decimal.ONE;
806
- } else if (endingChange.getIsNegative()) {
807
- endingChangePercent = Decimal.NEGATIVE_ONE;
809
+ if (actual.marketPrevious.getIsZero()) {
810
+ if (marketChange.getIsPositive()) {
811
+ marketChangePercent = Decimal.ONE;
812
+ } else if (marketChange.getIsNegative()) {
813
+ marketChangePercent = Decimal.NEGATIVE_ONE;
808
814
  } else {
809
- endingChangePercent = Decimal.ZERO;
815
+ marketChangePercent = Decimal.ZERO;
810
816
  }
811
817
  } else {
812
- endingChangePercent = endingChange.divide(actual.endingPrevious);
818
+ marketChangePercent = marketChange.divide(actual.marketPrevious);
813
819
  }
814
820
 
815
- actual.endingChange = endingChange;
816
- actual.endingChangePercent = endingChangePercent;
821
+ actual.marketChange = marketChange;
822
+ actual.marketChangePercent = marketChangePercent;
817
823
 
818
824
  format.market = formatCurrency(actual.market, currency);
819
825
 
@@ -834,8 +840,8 @@ module.exports = (() => {
834
840
  format.total = formatCurrency(actual.total, currency);
835
841
  format.totalNegative = actual.total.getIsNegative();
836
842
 
837
- format.endingChange = formatCurrency(actual.endingChange, currency);
838
- format.endingChangePercent = formatPercent(actual.endingChangePercent, 2);
843
+ format.marketChange = formatCurrency(actual.marketChange, currency);
844
+ format.marketChangePercent = formatPercent(actual.marketChangePercent, 2);
839
845
 
840
846
  calculateUnrealizedPercent(group);
841
847
  }
@@ -20,9 +20,10 @@ module.exports = (() => {
20
20
  * @param {Object} position
21
21
  * @param {Object} currentSummary
22
22
  * @param {Array.<Object>} previousSummaries
23
+ * @param {Boolean} reporting
23
24
  */
24
25
  class PositionItem extends Disposable {
25
- constructor(portfolio, position, currentSummary, previousSummaries) {
26
+ constructor(portfolio, position, currentSummary, previousSummaries, reporting) {
26
27
  super();
27
28
 
28
29
  this._portfolio = portfolio;
@@ -36,6 +37,8 @@ module.exports = (() => {
36
37
  this._currentSummary = currentSummary || null;
37
38
  this._previousSummaries = previousSummaries || [ ];
38
39
 
40
+ this._reporting = reporting;
41
+
39
42
  this._data = { };
40
43
 
41
44
  this._data.basis = null;
@@ -65,9 +68,12 @@ module.exports = (() => {
65
68
  this._data.summaryTotalPrevious = null;
66
69
  this._data.summaryTotalPrevious2 = null;
67
70
 
68
- this._data.endingPrevious = null;
69
- this._data.endingPrevious2 = null;
71
+ this._data.marketPrevious = null;
72
+ this._data.marketPrevious2 = null;
70
73
 
74
+ this._data.quantityPrevious = null;
75
+ this._data.quantityPrevious2 = null;
76
+
71
77
  this._data.realized = null;
72
78
  this._data.income = null;
73
79
  this._data.basisPrice = null;
@@ -361,7 +367,7 @@ module.exports = (() => {
361
367
 
362
368
  function calculateStaticData(item) {
363
369
  const position = item.position;
364
- const snapshot = item.position.snapshot;
370
+ const snapshot = getSnapshot(position, item.currentSummary, item._reporting);
365
371
  const previousSummaries = item.previousSummaries;
366
372
 
367
373
  const data = item._data;
@@ -391,8 +397,10 @@ module.exports = (() => {
391
397
  data.summaryTotalPrevious = calculateSummaryTotal(previousSummary1, previousSummary2);
392
398
  data.summaryTotalPrevious2 = calculateSummaryTotal(previousSummary2, previousSummary3);
393
399
 
394
- data.endingPrevious = previousSummary1 === null ? Decimal.ZERO : previousSummary1.end.value;
395
- data.endingPrevious2 = previousSummary2 === null ? Decimal.ZERO : previousSummary2.end.value;
400
+ data.marketPrevious = previousSummary1 === null ? Decimal.ZERO : previousSummary1.end.value;
401
+ data.marketPrevious2 = previousSummary2 === null ? Decimal.ZERO : previousSummary2.end.value;
402
+
403
+ data.quantityPrevious = previousSummary1 === null ? Decimal.ZERO : previousSummary1.end.open;
396
404
 
397
405
  if (snapshot.open.getIsZero()) {
398
406
  data.basisPrice = Decimal.ZERO;
@@ -403,7 +411,7 @@ module.exports = (() => {
403
411
 
404
412
  function calculatePriceData(item, price) {
405
413
  const position = item.position;
406
- const snapshot = item.position.snapshot;
414
+ const snapshot = getSnapshot(position, item.currentSummary, item._reporting);
407
415
  const previousSummaries = item.previousSummaries;
408
416
 
409
417
  const data = item._data;
@@ -555,5 +563,27 @@ module.exports = (() => {
555
563
  return is.object(position.system) && is.boolean(position.system.locked) && position.system.locked;
556
564
  }
557
565
 
566
+ function getSnapshot(position, currentSummary, reporting) {
567
+ let snapshot;
568
+
569
+ if (reporting) {
570
+ snapshot = { };
571
+
572
+ snapshot.date = currentSummary.end.date;
573
+ snapshot.open = currentSummary.end.open;
574
+ snapshot.direction = currentSummary.end.direction;
575
+ snapshot.buys = currentSummary.period.buys;
576
+ snapshot.sells = currentSummary.period.sells;
577
+ snapshot.gain = currentSummary.period.realized;
578
+ snapshot.basis = currentSummary.end.basis;
579
+ snapshot.income = currentSummary.period.income;
580
+ snapshot.value = currentSummary.end.value;
581
+ } else {
582
+ snapshot = position.snapshot;
583
+ }
584
+
585
+ return snapshot;
586
+ }
587
+
558
588
  return PositionItem;
559
589
  })();
@@ -11,6 +11,7 @@ module.exports = (() => {
11
11
  * @public
12
12
  * @param {String} name
13
13
  * @param {Array.<PositionLevelDefinition>} definitions
14
+ * @oaram {Array.<String>=} exclusionDependencies
14
15
  */
15
16
  class PositionTreeDefinitions {
16
17
  constructor(name, definitions, exclusionDependencies) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@barchart/portfolio-api-common",
3
- "version": "1.2.92",
3
+ "version": "1.2.96",
4
4
  "description": "Common classes used by the Portfolio system",
5
5
  "author": {
6
6
  "name": "Bryan Ingle",
@@ -399,7 +399,7 @@ module.exports = (() => {
399
399
  'use strict';
400
400
 
401
401
  /**
402
- * An enumeration used to define timeframes for position summaries.
402
+ * An enumeration used to define time frames for position summaries.
403
403
  *
404
404
  * @public
405
405
  * @extends {Enum}
@@ -485,22 +485,44 @@ module.exports = (() => {
485
485
  * @return {Array.<PositionSummaryRange>}
486
486
  */
487
487
  getRangesFromDate(date) {
488
+ assert.argumentIsRequired(date, 'date', Day, 'Day');
489
+
488
490
  const transaction = { date: date, snapshot: { open: Decimal.ONE } };
489
491
 
490
492
  return this.getRanges([ transaction ]);
491
493
  }
492
494
 
495
+ /**
496
+ * Returns the range immediately prior to the range containing the
497
+ * date supplied.
498
+ *
499
+ * @public
500
+ * @param {Day} date
501
+ * @param {Number} periods
502
+ */
503
+ getPriorRanges(date, periods) {
504
+ assert.argumentIsRequired(date, 'date', Day, 'Day');
505
+ assert.argumentIsRequired(periods, 'periods', Number, 'Number');
506
+
507
+ const transactionOne = { date: this.getStartDate((periods - 1), date), snapshot: { open: Decimal.ONE } };
508
+ const transactionTwo = { date: date, snapshot: { open: Decimal.ZERO } };
509
+
510
+ return this._rangeCalculator([ transactionOne, transactionTwo ]);
511
+ }
512
+
493
513
  /**
494
514
  * Returns the start date for a frame, a given number of periods ago.
495
515
  *
496
516
  * @public
497
517
  * @param {Number} periods
518
+ * @param {Day=} start
498
519
  * @returns {Day}
499
520
  */
500
- getStartDate(periods) {
521
+ getStartDate(periods, start) {
501
522
  assert.argumentIsRequired(periods, 'periods', Number);
523
+ assert.argumentIsOptional(start, 'start', Day, 'Day');
502
524
 
503
- return this._startDateCalculator(periods);
525
+ return this._startDateCalculator(periods, start);
504
526
  }
505
527
 
506
528
  /**
@@ -633,29 +655,29 @@ module.exports = (() => {
633
655
  return ranges;
634
656
  }
635
657
 
636
- function getYearlyStartDate(periods) {
637
- const today = Day.getToday();
658
+ function getYearlyStartDate(periods, date) {
659
+ const today = date || Day.getToday();
638
660
 
639
- return Day.getToday()
661
+ return today
640
662
  .subtractMonths(today.month - 1)
641
663
  .subtractDays(today.day)
642
664
  .subtractYears(periods);
643
665
  }
644
666
 
645
- function getQuarterlyStartDate(periods) {
667
+ function getQuarterlyStartDate(periods, date) {
646
668
  return null;
647
669
  }
648
670
 
649
- function getMonthlyStartDate(periods) {
671
+ function getMonthlyStartDate(periods, date) {
650
672
  return null;
651
673
  }
652
674
 
653
- function getYearToDateStartDate(periods) {
675
+ function getYearToDateStartDate(periods, date) {
654
676
  return null;
655
677
  }
656
678
 
657
679
  function getYearlyRangeDescription(start, end) {
658
- return end.year.toString();
680
+ return `Year ended ${end.year.toString()}`;
659
681
  }
660
682
 
661
683
  function getQuarterlyRangeDescription(start, end) {
@@ -1444,20 +1466,22 @@ module.exports = (() => {
1444
1466
  * @param {Array.<Object>} portfolios - The portfolios.
1445
1467
  * @param {Array.<Object>} positions - The positions (for all of the portfolios).
1446
1468
  * @param {Array.<Object>} summaries - The positions summaries (for all of the positions).
1447
- * @param {PositionSummaryFrame=} - If specified, locks the current (and previous) periods to a specific frame, use for reporting.
1469
+ * @param {PositionSummaryFrame=} reportFrame - If specified, locks the current (and previous) periods to a specific frame, use for reporting.
1448
1470
  */
1449
1471
  class PositionContainer {
1450
- constructor(definitions, portfolios, positions, summaries, frame) {
1472
+ constructor(definitions, portfolios, positions, summaries, reportFrame) {
1451
1473
  assert.argumentIsArray(definitions, 'definitions', PositionTreeDefinition, 'PositionTreeDefinition');
1452
1474
  assert.argumentIsArray(portfolios, 'portfolios');
1453
1475
  assert.argumentIsArray(positions, 'positions');
1454
1476
  assert.argumentIsArray(summaries, 'summaries');
1455
- assert.argumentIsOptional(frame, 'frame', PositionSummaryFrame, 'PositionSummaryFrame');
1477
+ assert.argumentIsOptional(reportFrame, 'reportFrame', PositionSummaryFrame, 'PositionSummaryFrame');
1456
1478
 
1457
1479
  this._definitions = definitions;
1458
1480
 
1459
1481
  this._groupBindings = { };
1460
1482
 
1483
+ this._reporting = reportFrame instanceof PositionSummaryFrame;
1484
+
1461
1485
  this._positionSymbolAddedEvent = new Event(this);
1462
1486
  this._positionSymbolRemovedEvent = new Event(this);
1463
1487
 
@@ -1467,10 +1491,10 @@ module.exports = (() => {
1467
1491
  return map;
1468
1492
  }, { });
1469
1493
 
1470
- this._currentSummaryFrame = frame || PositionSummaryFrame.YTD;
1494
+ this._currentSummaryFrame = reportFrame || PositionSummaryFrame.YTD;
1471
1495
  this._currentSummaryRange = array.last(this._currentSummaryFrame.getRecentRanges(0));
1472
1496
 
1473
- this._previousSummaryFrame = frame || PositionSummaryFrame.YEARLY;
1497
+ this._previousSummaryFrame = reportFrame || PositionSummaryFrame.YEARLY;
1474
1498
  this._previousSummaryRanges = this._previousSummaryFrame.getRecentRanges(3);
1475
1499
 
1476
1500
  if (this._currentSummaryFrame === this._previousSummaryFrame) {
@@ -2344,7 +2368,7 @@ module.exports = (() => {
2344
2368
  const currentSummary = this._summariesCurrent[ position.position ] || null;
2345
2369
  const previousSummaries = this._summariesPrevious[ position.position ] || getSummaryArray(this._previousSummaryRanges);
2346
2370
 
2347
- returnRef = new PositionItem(portfolio, position, currentSummary, previousSummaries);
2371
+ returnRef = new PositionItem(portfolio, position, currentSummary, previousSummaries, this._reporting);
2348
2372
  } else {
2349
2373
  returnRef = null;
2350
2374
  }
@@ -2483,12 +2507,14 @@ module.exports = (() => {
2483
2507
  this._dataFormat.locked = false;
2484
2508
  this._dataFormat.newsExists = false;
2485
2509
  this._dataFormat.quantity = null;
2510
+ this._dataFormat.quantityPrevious = null;
2486
2511
  this._dataFormat.basisPrice = null;
2487
2512
 
2488
2513
  this._dataActual.key = this._key;
2489
2514
  this._dataActual.description = this._description;
2490
2515
  this._dataActual.newsExists = false;
2491
2516
  this._dataActual.quantity = null;
2517
+ this._dataActual.quantityPrevious = null;
2492
2518
  this._dataActual.basisPrice = null;
2493
2519
 
2494
2520
  if (this._single && items.length === 1) {
@@ -2538,10 +2564,10 @@ module.exports = (() => {
2538
2564
  this._dataActual.summaryTotalCurrent = null;
2539
2565
  this._dataActual.summaryTotalPrevious = null;
2540
2566
  this._dataActual.summaryTotalPrevious2 = null;
2541
- this._dataActual.endingPrevious = null;
2542
- this._dataActual.endingPrevious2 = null;
2543
- this._dataActual.endingChange = null;
2544
- this._dataActual.endingChangePercent = null;
2567
+ this._dataActual.marketPrevious = null;
2568
+ this._dataActual.marketPrevious2 = null;
2569
+ this._dataActual.marketChange = null;
2570
+ this._dataActual.marketChangePercent = null;
2545
2571
  this._dataActual.cashTotal = null;
2546
2572
 
2547
2573
  this._dataFormat.currentPrice = null;
@@ -2565,10 +2591,10 @@ module.exports = (() => {
2565
2591
  this._dataFormat.summaryTotalPreviousNegative = false;
2566
2592
  this._dataFormat.summaryTotalPrevious2 = null;
2567
2593
  this._dataFormat.summaryTotalPrevious2Negative = false;
2568
- this._dataFormat.endingPrevious = null;
2569
- this._dataFormat.endingPrevious2 = null;
2570
- this._dataFormat.endingChange = null;
2571
- this._dataFormat.endingChangePercent = null;
2594
+ this._dataFormat.marketPrevious = null;
2595
+ this._dataFormat.marketPrevious2 = null;
2596
+ this._dataFormat.marketChange = null;
2597
+ this._dataFormat.marketChangePercent = null;
2572
2598
  this._dataFormat.cashTotal = null;
2573
2599
  this._dataFormat.portfolioType = null;
2574
2600
 
@@ -3065,8 +3091,8 @@ module.exports = (() => {
3065
3091
  updates.summaryTotalCurrent = updates.summaryTotalCurrent.add(translate(item, item.data.summaryTotalCurrent));
3066
3092
  updates.summaryTotalPrevious = updates.summaryTotalPrevious.add(translate(item, item.data.summaryTotalPrevious));
3067
3093
  updates.summaryTotalPrevious2 = updates.summaryTotalPrevious2.add(translate(item, item.data.summaryTotalPrevious2));
3068
- updates.endingPrevious = updates.endingPrevious.add(translate(item, item.data.endingPrevious));
3069
- updates.endingPrevious2 = updates.endingPrevious2.add(translate(item, item.data.endingPrevious2));
3094
+ updates.marketPrevious = updates.marketPrevious.add(translate(item, item.data.marketPrevious));
3095
+ updates.marketPrevious2 = updates.marketPrevious2.add(translate(item, item.data.marketPrevious2));
3070
3096
 
3071
3097
  if (item.position.instrument.type === InstrumentType.CASH) {
3072
3098
  updates.cashTotal = updates.cashTotal.add(translate(item, item.data.market));
@@ -3081,8 +3107,8 @@ module.exports = (() => {
3081
3107
  summaryTotalCurrent: Decimal.ZERO,
3082
3108
  summaryTotalPrevious: Decimal.ZERO,
3083
3109
  summaryTotalPrevious2: Decimal.ZERO,
3084
- endingPrevious: Decimal.ZERO,
3085
- endingPrevious2: Decimal.ZERO,
3110
+ marketPrevious: Decimal.ZERO,
3111
+ marketPrevious2: Decimal.ZERO,
3086
3112
  cashTotal: Decimal.ZERO
3087
3113
  });
3088
3114
 
@@ -3093,8 +3119,8 @@ module.exports = (() => {
3093
3119
  actual.summaryTotalCurrent = updates.summaryTotalCurrent;
3094
3120
  actual.summaryTotalPrevious = updates.summaryTotalPrevious;
3095
3121
  actual.summaryTotalPrevious2 = updates.summaryTotalPrevious2;
3096
- actual.endingPrevious = updates.endingPrevious;
3097
- actual.endingPrevious2 = updates.endingPrevious2;
3122
+ actual.marketPrevious = updates.marketPrevious;
3123
+ actual.marketPrevious2 = updates.marketPrevious2;
3098
3124
  actual.cashTotal = updates.cashTotal;
3099
3125
 
3100
3126
  format.basis = formatCurrency(actual.basis, currency);
@@ -3106,8 +3132,8 @@ module.exports = (() => {
3106
3132
  format.summaryTotalPreviousNegative = updates.summaryTotalPrevious.getIsNegative();
3107
3133
  format.summaryTotalPrevious2 = formatCurrency(updates.summaryTotalPrevious2, currency);
3108
3134
  format.summaryTotalPrevious2Negative = updates.summaryTotalPrevious2.getIsNegative();
3109
- format.endingPrevious = formatCurrency(updates.endingPrevious, currency);
3110
- format.endingPrevious2 = formatCurrency(updates.endingPrevious2, currency);
3135
+ format.marketPrevious = formatCurrency(updates.marketPrevious, currency);
3136
+ format.marketPrevious2 = formatCurrency(updates.marketPrevious2, currency);
3111
3137
  format.cashTotal = formatCurrency(updates.cashTotal, currency);
3112
3138
 
3113
3139
  calculateUnrealizedPercent(group);
@@ -3116,9 +3142,13 @@ module.exports = (() => {
3116
3142
  const item = group._items[0];
3117
3143
 
3118
3144
  actual.quantity = item.position.snapshot.open;
3145
+ actual.quantityPrevious = item.data.quantityPrevious;
3146
+
3119
3147
  actual.basisPrice = item.data.basisPrice;
3120
3148
 
3121
3149
  format.quantity = formatDecimal(actual.quantity, 2);
3150
+ format.quantityPrevious = formatDecimal(actual.quantityPrevious, 2);
3151
+
3122
3152
  format.basisPrice = formatCurrency(actual.basisPrice, currency);
3123
3153
 
3124
3154
  format.invalid = definition.type === PositionLevelType.POSITION && item.invalid;
@@ -3205,23 +3235,23 @@ module.exports = (() => {
3205
3235
  actual.summaryTotalCurrent = updates.summaryTotalCurrent;
3206
3236
  actual.total = updates.unrealized.add(actual.realized).add(actual.income);
3207
3237
 
3208
- let endingChange = updates.market.subtract(actual.endingPrevious);
3209
- let endingChangePercent;
3238
+ let marketChange = updates.market.subtract(actual.marketPrevious);
3239
+ let marketChangePercent;
3210
3240
 
3211
- if (actual.endingPrevious.getIsZero()) {
3212
- if (endingChange.getIsPositive()) {
3213
- endingChangePercent = Decimal.ONE;
3214
- } else if (endingChange.getIsNegative()) {
3215
- endingChangePercent = Decimal.NEGATIVE_ONE;
3241
+ if (actual.marketPrevious.getIsZero()) {
3242
+ if (marketChange.getIsPositive()) {
3243
+ marketChangePercent = Decimal.ONE;
3244
+ } else if (marketChange.getIsNegative()) {
3245
+ marketChangePercent = Decimal.NEGATIVE_ONE;
3216
3246
  } else {
3217
- endingChangePercent = Decimal.ZERO;
3247
+ marketChangePercent = Decimal.ZERO;
3218
3248
  }
3219
3249
  } else {
3220
- endingChangePercent = endingChange.divide(actual.endingPrevious);
3250
+ marketChangePercent = marketChange.divide(actual.marketPrevious);
3221
3251
  }
3222
3252
 
3223
- actual.endingChange = endingChange;
3224
- actual.endingChangePercent = endingChangePercent;
3253
+ actual.marketChange = marketChange;
3254
+ actual.marketChangePercent = marketChangePercent;
3225
3255
 
3226
3256
  format.market = formatCurrency(actual.market, currency);
3227
3257
 
@@ -3242,8 +3272,8 @@ module.exports = (() => {
3242
3272
  format.total = formatCurrency(actual.total, currency);
3243
3273
  format.totalNegative = actual.total.getIsNegative();
3244
3274
 
3245
- format.endingChange = formatCurrency(actual.endingChange, currency);
3246
- format.endingChangePercent = formatPercent(actual.endingChangePercent, 2);
3275
+ format.marketChange = formatCurrency(actual.marketChange, currency);
3276
+ format.marketChangePercent = formatPercent(actual.marketChangePercent, 2);
3247
3277
 
3248
3278
  calculateUnrealizedPercent(group);
3249
3279
  }
@@ -3332,9 +3362,10 @@ module.exports = (() => {
3332
3362
  * @param {Object} position
3333
3363
  * @param {Object} currentSummary
3334
3364
  * @param {Array.<Object>} previousSummaries
3365
+ * @param {Boolean} reporting
3335
3366
  */
3336
3367
  class PositionItem extends Disposable {
3337
- constructor(portfolio, position, currentSummary, previousSummaries) {
3368
+ constructor(portfolio, position, currentSummary, previousSummaries, reporting) {
3338
3369
  super();
3339
3370
 
3340
3371
  this._portfolio = portfolio;
@@ -3348,6 +3379,8 @@ module.exports = (() => {
3348
3379
  this._currentSummary = currentSummary || null;
3349
3380
  this._previousSummaries = previousSummaries || [ ];
3350
3381
 
3382
+ this._reporting = reporting;
3383
+
3351
3384
  this._data = { };
3352
3385
 
3353
3386
  this._data.basis = null;
@@ -3377,9 +3410,12 @@ module.exports = (() => {
3377
3410
  this._data.summaryTotalPrevious = null;
3378
3411
  this._data.summaryTotalPrevious2 = null;
3379
3412
 
3380
- this._data.endingPrevious = null;
3381
- this._data.endingPrevious2 = null;
3413
+ this._data.marketPrevious = null;
3414
+ this._data.marketPrevious2 = null;
3382
3415
 
3416
+ this._data.quantityPrevious = null;
3417
+ this._data.quantityPrevious2 = null;
3418
+
3383
3419
  this._data.realized = null;
3384
3420
  this._data.income = null;
3385
3421
  this._data.basisPrice = null;
@@ -3673,7 +3709,7 @@ module.exports = (() => {
3673
3709
 
3674
3710
  function calculateStaticData(item) {
3675
3711
  const position = item.position;
3676
- const snapshot = item.position.snapshot;
3712
+ const snapshot = getSnapshot(position, item.currentSummary, item._reporting);
3677
3713
  const previousSummaries = item.previousSummaries;
3678
3714
 
3679
3715
  const data = item._data;
@@ -3703,8 +3739,10 @@ module.exports = (() => {
3703
3739
  data.summaryTotalPrevious = calculateSummaryTotal(previousSummary1, previousSummary2);
3704
3740
  data.summaryTotalPrevious2 = calculateSummaryTotal(previousSummary2, previousSummary3);
3705
3741
 
3706
- data.endingPrevious = previousSummary1 === null ? Decimal.ZERO : previousSummary1.end.value;
3707
- data.endingPrevious2 = previousSummary2 === null ? Decimal.ZERO : previousSummary2.end.value;
3742
+ data.marketPrevious = previousSummary1 === null ? Decimal.ZERO : previousSummary1.end.value;
3743
+ data.marketPrevious2 = previousSummary2 === null ? Decimal.ZERO : previousSummary2.end.value;
3744
+
3745
+ data.quantityPrevious = previousSummary1 === null ? Decimal.ZERO : previousSummary1.end.open;
3708
3746
 
3709
3747
  if (snapshot.open.getIsZero()) {
3710
3748
  data.basisPrice = Decimal.ZERO;
@@ -3715,7 +3753,7 @@ module.exports = (() => {
3715
3753
 
3716
3754
  function calculatePriceData(item, price) {
3717
3755
  const position = item.position;
3718
- const snapshot = item.position.snapshot;
3756
+ const snapshot = getSnapshot(position, item.currentSummary, item._reporting);
3719
3757
  const previousSummaries = item.previousSummaries;
3720
3758
 
3721
3759
  const data = item._data;
@@ -3867,6 +3905,28 @@ module.exports = (() => {
3867
3905
  return is.object(position.system) && is.boolean(position.system.locked) && position.system.locked;
3868
3906
  }
3869
3907
 
3908
+ function getSnapshot(position, currentSummary, reporting) {
3909
+ let snapshot;
3910
+
3911
+ if (reporting) {
3912
+ snapshot = { };
3913
+
3914
+ snapshot.date = currentSummary.end.date;
3915
+ snapshot.open = currentSummary.end.open;
3916
+ snapshot.direction = currentSummary.end.direction;
3917
+ snapshot.buys = currentSummary.period.buys;
3918
+ snapshot.sells = currentSummary.period.sells;
3919
+ snapshot.gain = currentSummary.period.realized;
3920
+ snapshot.basis = currentSummary.end.basis;
3921
+ snapshot.income = currentSummary.period.income;
3922
+ snapshot.value = currentSummary.end.value;
3923
+ } else {
3924
+ snapshot = position.snapshot;
3925
+ }
3926
+
3927
+ return snapshot;
3928
+ }
3929
+
3870
3930
  return PositionItem;
3871
3931
  })();
3872
3932
 
@@ -4194,6 +4254,7 @@ module.exports = (() => {
4194
4254
  * @public
4195
4255
  * @param {String} name
4196
4256
  * @param {Array.<PositionLevelDefinition>} definitions
4257
+ * @oaram {Array.<String>=} exclusionDependencies
4197
4258
  */
4198
4259
  class PositionTreeDefinitions {
4199
4260
  constructor(name, definitions, exclusionDependencies) {
@@ -17632,6 +17693,38 @@ describe('After the PositionSummaryFrame enumeration is initialized', () => {
17632
17693
  });
17633
17694
  });
17634
17695
  });
17696
+
17697
+ describe('and prior ranges are calculated', () => {
17698
+ describe('for YEARLY ranges', () => {
17699
+ describe('from 2017-10-10, including one previous ranges', () => {
17700
+ let ranges;
17701
+
17702
+ beforeEach(() => {
17703
+ ranges = PositionSummaryFrame.YEARLY.getPriorRanges(new Day(2015, 4, 20), 1);
17704
+ });
17705
+
17706
+ it('should return two ranges', () => {
17707
+ expect(ranges.length).toEqual(2);
17708
+ });
17709
+
17710
+ it('the first range should begin on 2013-12-31', () => {
17711
+ expect(ranges[0].start.getIsEqual(new Day(2013, 12, 31))).toEqual(true);
17712
+ });
17713
+
17714
+ it('the first range should end on 2014-12-31', () => {
17715
+ expect(ranges[0].end.getIsEqual(new Day(2014, 12, 31))).toEqual(true);
17716
+ });
17717
+
17718
+ it('the second range should begin on 2014-12-31', () => {
17719
+ expect(ranges[1].start.getIsEqual(new Day(2014, 12, 31))).toEqual(true);
17720
+ });
17721
+
17722
+ it('the second range should end on 2015-12-31', () => {
17723
+ expect(ranges[1].end.getIsEqual(new Day(2015, 12, 31))).toEqual(true);
17724
+ });
17725
+ });
17726
+ });
17727
+ });
17635
17728
  });
17636
17729
 
17637
17730
  },{"./../../../lib/data/PositionSummaryFrame":3,"./../../../lib/data/TransactionType":4,"@barchart/common-js/lang/Day":21,"@barchart/common-js/lang/Decimal":22}],53:[function(require,module,exports){
@@ -422,4 +422,36 @@ describe('After the PositionSummaryFrame enumeration is initialized', () => {
422
422
  });
423
423
  });
424
424
  });
425
+
426
+ describe('and prior ranges are calculated', () => {
427
+ describe('for YEARLY ranges', () => {
428
+ describe('from 2017-10-10, including one previous ranges', () => {
429
+ let ranges;
430
+
431
+ beforeEach(() => {
432
+ ranges = PositionSummaryFrame.YEARLY.getPriorRanges(new Day(2015, 4, 20), 1);
433
+ });
434
+
435
+ it('should return two ranges', () => {
436
+ expect(ranges.length).toEqual(2);
437
+ });
438
+
439
+ it('the first range should begin on 2013-12-31', () => {
440
+ expect(ranges[0].start.getIsEqual(new Day(2013, 12, 31))).toEqual(true);
441
+ });
442
+
443
+ it('the first range should end on 2014-12-31', () => {
444
+ expect(ranges[0].end.getIsEqual(new Day(2014, 12, 31))).toEqual(true);
445
+ });
446
+
447
+ it('the second range should begin on 2014-12-31', () => {
448
+ expect(ranges[1].start.getIsEqual(new Day(2014, 12, 31))).toEqual(true);
449
+ });
450
+
451
+ it('the second range should end on 2015-12-31', () => {
452
+ expect(ranges[1].end.getIsEqual(new Day(2015, 12, 31))).toEqual(true);
453
+ });
454
+ });
455
+ });
456
+ });
425
457
  });