@barchart/portfolio-api-common 1.2.89 → 1.2.93

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.
@@ -86,17 +86,52 @@ module.exports = (() => {
86
86
  return this._rangeCalculator(getFilteredTransactions(transactions));
87
87
  }
88
88
 
89
+ /**
90
+ * Returns the range which contains a given date and all subsequent ranges.
91
+ *
92
+ * @public
93
+ * @param {Day} date
94
+ * @return {Array.<PositionSummaryRange>}
95
+ */
96
+ getRangesFromDate(date) {
97
+ assert.argumentIsRequired(date, 'date', Day, 'Day');
98
+
99
+ const transaction = { date: date, snapshot: { open: Decimal.ONE } };
100
+
101
+ return this.getRanges([ transaction ]);
102
+ }
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
+
89
122
  /**
90
123
  * Returns the start date for a frame, a given number of periods ago.
91
124
  *
92
125
  * @public
93
126
  * @param {Number} periods
127
+ * @param {Day=} start
94
128
  * @returns {Day}
95
129
  */
96
- getStartDate(periods) {
130
+ getStartDate(periods, start) {
97
131
  assert.argumentIsRequired(periods, 'periods', Number);
132
+ assert.argumentIsOptional(start, 'start', Day, 'Day');
98
133
 
99
- return this._startDateCalculator(periods);
134
+ return this._startDateCalculator(periods, start);
100
135
  }
101
136
 
102
137
  /**
@@ -158,6 +193,16 @@ module.exports = (() => {
158
193
  * @property {Day} end
159
194
  */
160
195
 
196
+ /**
197
+ * The start and and date for a {@link PositionSummaryFrame} along with the frame type.
198
+ *
199
+ * @typedef PositionSummaryDefinition
200
+ * @type {Object}
201
+ * @property {Day} start
202
+ * @property {Day} end
203
+ * @property {PositionSummaryFrame} frame
204
+ */
205
+
161
206
  function getRange(start, end) {
162
207
  return {
163
208
  start: start,
@@ -219,24 +264,24 @@ module.exports = (() => {
219
264
  return ranges;
220
265
  }
221
266
 
222
- function getYearlyStartDate(periods) {
223
- const today = Day.getToday();
267
+ function getYearlyStartDate(periods, date) {
268
+ const today = date || Day.getToday();
224
269
 
225
- return Day.getToday()
270
+ return today
226
271
  .subtractMonths(today.month - 1)
227
272
  .subtractDays(today.day)
228
273
  .subtractYears(periods);
229
274
  }
230
275
 
231
- function getQuarterlyStartDate(periods) {
276
+ function getQuarterlyStartDate(periods, date) {
232
277
  return null;
233
278
  }
234
279
 
235
- function getMonthlyStartDate(periods) {
280
+ function getMonthlyStartDate(periods, date) {
236
281
  return null;
237
282
  }
238
283
 
239
- function getYearToDateStartDate(periods) {
284
+ function getYearToDateStartDate(periods, date) {
240
285
  return null;
241
286
  }
242
287
 
@@ -42,7 +42,7 @@ 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=} - If specified, locks the current (and previous) periods to a specific frame, use for reporting.
46
46
  */
47
47
  class PositionContainer {
48
48
  constructor(definitions, portfolios, positions, summaries, frame) {
@@ -130,6 +130,10 @@ module.exports = (() => {
130
130
  this._dataActual.summaryTotalCurrent = null;
131
131
  this._dataActual.summaryTotalPrevious = null;
132
132
  this._dataActual.summaryTotalPrevious2 = null;
133
+ this._dataActual.endingPrevious = null;
134
+ this._dataActual.endingPrevious2 = null;
135
+ this._dataActual.endingChange = null;
136
+ this._dataActual.endingChangePercent = null;
133
137
  this._dataActual.cashTotal = null;
134
138
 
135
139
  this._dataFormat.currentPrice = null;
@@ -153,6 +157,10 @@ module.exports = (() => {
153
157
  this._dataFormat.summaryTotalPreviousNegative = false;
154
158
  this._dataFormat.summaryTotalPrevious2 = null;
155
159
  this._dataFormat.summaryTotalPrevious2Negative = false;
160
+ this._dataFormat.endingPrevious = null;
161
+ this._dataFormat.endingPrevious2 = null;
162
+ this._dataFormat.endingChange = null;
163
+ this._dataFormat.endingChangePercent = null;
156
164
  this._dataFormat.cashTotal = null;
157
165
  this._dataFormat.portfolioType = null;
158
166
 
@@ -388,8 +396,6 @@ module.exports = (() => {
388
396
  return;
389
397
  }
390
398
 
391
- const descriptionSelector = this._definition.descriptionSelector;
392
-
393
399
  this._description = PositionLevelDefinition.getDescriptionForPortfolioGroup(portfolio);
394
400
 
395
401
  this._dataActual.description = this._description;
@@ -634,7 +640,7 @@ module.exports = (() => {
634
640
  const translate = (item, value) => {
635
641
  let translated;
636
642
 
637
- if (item.currency !== currency) {
643
+ if (item.currency !== currency && !value.getIsZero()) {
638
644
  translated = Rate.convert(value, item.currency, currency, ...rates);
639
645
  } else {
640
646
  translated = value;
@@ -651,6 +657,8 @@ module.exports = (() => {
651
657
  updates.summaryTotalCurrent = updates.summaryTotalCurrent.add(translate(item, item.data.summaryTotalCurrent));
652
658
  updates.summaryTotalPrevious = updates.summaryTotalPrevious.add(translate(item, item.data.summaryTotalPrevious));
653
659
  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));
654
662
 
655
663
  if (item.position.instrument.type === InstrumentType.CASH) {
656
664
  updates.cashTotal = updates.cashTotal.add(translate(item, item.data.market));
@@ -665,6 +673,8 @@ module.exports = (() => {
665
673
  summaryTotalCurrent: Decimal.ZERO,
666
674
  summaryTotalPrevious: Decimal.ZERO,
667
675
  summaryTotalPrevious2: Decimal.ZERO,
676
+ endingPrevious: Decimal.ZERO,
677
+ endingPrevious2: Decimal.ZERO,
668
678
  cashTotal: Decimal.ZERO
669
679
  });
670
680
 
@@ -675,6 +685,8 @@ module.exports = (() => {
675
685
  actual.summaryTotalCurrent = updates.summaryTotalCurrent;
676
686
  actual.summaryTotalPrevious = updates.summaryTotalPrevious;
677
687
  actual.summaryTotalPrevious2 = updates.summaryTotalPrevious2;
688
+ actual.endingPrevious = updates.endingPrevious;
689
+ actual.endingPrevious2 = updates.endingPrevious2;
678
690
  actual.cashTotal = updates.cashTotal;
679
691
 
680
692
  format.basis = formatCurrency(actual.basis, currency);
@@ -686,6 +698,8 @@ module.exports = (() => {
686
698
  format.summaryTotalPreviousNegative = updates.summaryTotalPrevious.getIsNegative();
687
699
  format.summaryTotalPrevious2 = formatCurrency(updates.summaryTotalPrevious2, currency);
688
700
  format.summaryTotalPrevious2Negative = updates.summaryTotalPrevious2.getIsNegative();
701
+ format.endingPrevious = formatCurrency(updates.endingPrevious, currency);
702
+ format.endingPrevious2 = formatCurrency(updates.endingPrevious2, currency);
689
703
  format.cashTotal = formatCurrency(updates.cashTotal, currency);
690
704
 
691
705
  calculateUnrealizedPercent(group);
@@ -735,7 +749,7 @@ module.exports = (() => {
735
749
  const translate = (item, value) => {
736
750
  let translated;
737
751
 
738
- if (item.currency !== currency) {
752
+ if (item.currency !== currency && !value.getIsZero()) {
739
753
  translated = Rate.convert(value, item.currency, currency, ...rates);
740
754
  } else {
741
755
  translated = value;
@@ -782,7 +796,25 @@ module.exports = (() => {
782
796
  actual.unrealizedToday = updates.unrealizedToday;
783
797
  actual.summaryTotalCurrent = updates.summaryTotalCurrent;
784
798
  actual.total = updates.unrealized.add(actual.realized).add(actual.income);
785
-
799
+
800
+ let endingChange = updates.market.subtract(actual.endingPrevious);
801
+ let endingChangePercent;
802
+
803
+ if (actual.endingPrevious.getIsZero()) {
804
+ if (endingChange.getIsPositive()) {
805
+ endingChangePercent = Decimal.ONE;
806
+ } else if (endingChange.getIsNegative()) {
807
+ endingChangePercent = Decimal.NEGATIVE_ONE;
808
+ } else {
809
+ endingChangePercent = Decimal.ZERO;
810
+ }
811
+ } else {
812
+ endingChangePercent = endingChange.divide(actual.endingPrevious);
813
+ }
814
+
815
+ actual.endingChange = endingChange;
816
+ actual.endingChangePercent = endingChangePercent;
817
+
786
818
  format.market = formatCurrency(actual.market, currency);
787
819
 
788
820
  if (updates.marketDirection.up || updates.marketDirection.down) {
@@ -802,6 +834,9 @@ module.exports = (() => {
802
834
  format.total = formatCurrency(actual.total, currency);
803
835
  format.totalNegative = actual.total.getIsNegative();
804
836
 
837
+ format.endingChange = formatCurrency(actual.endingChange, currency);
838
+ format.endingChangePercent = formatPercent(actual.endingChangePercent, 2);
839
+
805
840
  calculateUnrealizedPercent(group);
806
841
  }
807
842
 
@@ -65,6 +65,9 @@ module.exports = (() => {
65
65
  this._data.summaryTotalPrevious = null;
66
66
  this._data.summaryTotalPrevious2 = null;
67
67
 
68
+ this._data.endingPrevious = null;
69
+ this._data.endingPrevious2 = null;
70
+
68
71
  this._data.realized = null;
69
72
  this._data.income = null;
70
73
  this._data.basisPrice = null;
@@ -380,9 +383,16 @@ module.exports = (() => {
380
383
 
381
384
  data.income = snapshot.income;
382
385
 
383
- data.summaryTotalCurrent = calculateSummaryTotal(item.currentSummary, getPreviousSummary(previousSummaries, 1));
384
- data.summaryTotalPrevious = calculateSummaryTotal(getPreviousSummary(previousSummaries, 1), getPreviousSummary(previousSummaries, 2));
385
- data.summaryTotalPrevious2 = calculateSummaryTotal(getPreviousSummary(previousSummaries, 2), getPreviousSummary(previousSummaries, 3));
386
+ const previousSummary1 = getPreviousSummary(previousSummaries, 1);
387
+ const previousSummary2 = getPreviousSummary(previousSummaries, 2);
388
+ const previousSummary3 = getPreviousSummary(previousSummaries, 3);
389
+
390
+ data.summaryTotalCurrent = calculateSummaryTotal(item.currentSummary, previousSummary1);
391
+ data.summaryTotalPrevious = calculateSummaryTotal(previousSummary1, previousSummary2);
392
+ data.summaryTotalPrevious2 = calculateSummaryTotal(previousSummary2, previousSummary3);
393
+
394
+ data.endingPrevious = previousSummary1 === null ? Decimal.ZERO : previousSummary1.end.value;
395
+ data.endingPrevious2 = previousSummary2 === null ? Decimal.ZERO : previousSummary2.end.value;
386
396
 
387
397
  if (snapshot.open.getIsZero()) {
388
398
  data.basisPrice = Decimal.ZERO;
@@ -0,0 +1,58 @@
1
+ const DataType = require('@barchart/common-js/serialization/json/DataType'),
2
+ Enum = require('@barchart/common-js/lang/Enum'),
3
+ Schema = require('@barchart/common-js/serialization/json/Schema'),
4
+ SchemaBuilder = require('@barchart/common-js/serialization/json/builders/SchemaBuilder');
5
+
6
+ const PositionSummaryFrame = require('./../data/PositionSummaryFrame');
7
+
8
+ module.exports = (() => {
9
+ 'use strict';
10
+
11
+ /**
12
+ * The schemas which can be used to represent position summary objects.
13
+ *
14
+ * @public
15
+ * @extends {Enum}
16
+ */
17
+ class PositionSummaryDefinitionSchema extends Enum {
18
+ constructor(schema) {
19
+ super(schema.name, schema.name);
20
+
21
+ this._schema = schema;
22
+ }
23
+
24
+ /**
25
+ * The actual {@link Schema}.
26
+ *
27
+ * @public
28
+ * @returns {Schema}
29
+ */
30
+ get schema() {
31
+ return this._schema;
32
+ }
33
+
34
+ /**
35
+ * The complete position summary definition schema.
36
+ *
37
+ * @static
38
+ * @public
39
+ * @returns {PositionSummaryDefinitionSchema}
40
+ */
41
+ static get COMPLETE() {
42
+ return complete;
43
+ }
44
+
45
+ toString() {
46
+ return '[PositionSummaryDefinitionSchema]';
47
+ }
48
+ }
49
+
50
+ const complete = new PositionSummaryDefinitionSchema(SchemaBuilder.withName('complete')
51
+ .withField('start', DataType.DAY)
52
+ .withField('end', DataType.DAY)
53
+ .withField('frame', DataType.forEnum(PositionSummaryFrame, 'PositionSummaryFrame'))
54
+ .schema
55
+ );
56
+
57
+ return PositionSummaryDefinitionSchema;
58
+ })();
@@ -1,5 +1,4 @@
1
- const Currency = require('@barchart/common-js/lang/Currency'),
2
- DataType = require('@barchart/common-js/serialization/json/DataType'),
1
+ const DataType = require('@barchart/common-js/serialization/json/DataType'),
3
2
  Enum = require('@barchart/common-js/lang/Enum'),
4
3
  Schema = require('@barchart/common-js/serialization/json/Schema'),
5
4
  SchemaBuilder = require('@barchart/common-js/serialization/json/builders/SchemaBuilder');
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@barchart/portfolio-api-common",
3
- "version": "1.2.89",
3
+ "version": "1.2.93",
4
4
  "description": "Common classes used by the Portfolio system",
5
5
  "author": {
6
6
  "name": "Bryan Ingle",
@@ -477,17 +477,52 @@ module.exports = (() => {
477
477
  return this._rangeCalculator(getFilteredTransactions(transactions));
478
478
  }
479
479
 
480
+ /**
481
+ * Returns the range which contains a given date and all subsequent ranges.
482
+ *
483
+ * @public
484
+ * @param {Day} date
485
+ * @return {Array.<PositionSummaryRange>}
486
+ */
487
+ getRangesFromDate(date) {
488
+ assert.argumentIsRequired(date, 'date', Day, 'Day');
489
+
490
+ const transaction = { date: date, snapshot: { open: Decimal.ONE } };
491
+
492
+ return this.getRanges([ transaction ]);
493
+ }
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
+
480
513
  /**
481
514
  * Returns the start date for a frame, a given number of periods ago.
482
515
  *
483
516
  * @public
484
517
  * @param {Number} periods
518
+ * @param {Day=} start
485
519
  * @returns {Day}
486
520
  */
487
- getStartDate(periods) {
521
+ getStartDate(periods, start) {
488
522
  assert.argumentIsRequired(periods, 'periods', Number);
523
+ assert.argumentIsOptional(start, 'start', Day, 'Day');
489
524
 
490
- return this._startDateCalculator(periods);
525
+ return this._startDateCalculator(periods, start);
491
526
  }
492
527
 
493
528
  /**
@@ -549,6 +584,16 @@ module.exports = (() => {
549
584
  * @property {Day} end
550
585
  */
551
586
 
587
+ /**
588
+ * The start and and date for a {@link PositionSummaryFrame} along with the frame type.
589
+ *
590
+ * @typedef PositionSummaryDefinition
591
+ * @type {Object}
592
+ * @property {Day} start
593
+ * @property {Day} end
594
+ * @property {PositionSummaryFrame} frame
595
+ */
596
+
552
597
  function getRange(start, end) {
553
598
  return {
554
599
  start: start,
@@ -610,24 +655,24 @@ module.exports = (() => {
610
655
  return ranges;
611
656
  }
612
657
 
613
- function getYearlyStartDate(periods) {
614
- const today = Day.getToday();
658
+ function getYearlyStartDate(periods, date) {
659
+ const today = date || Day.getToday();
615
660
 
616
- return Day.getToday()
661
+ return today
617
662
  .subtractMonths(today.month - 1)
618
663
  .subtractDays(today.day)
619
664
  .subtractYears(periods);
620
665
  }
621
666
 
622
- function getQuarterlyStartDate(periods) {
667
+ function getQuarterlyStartDate(periods, date) {
623
668
  return null;
624
669
  }
625
670
 
626
- function getMonthlyStartDate(periods) {
671
+ function getMonthlyStartDate(periods, date) {
627
672
  return null;
628
673
  }
629
674
 
630
- function getYearToDateStartDate(periods) {
675
+ function getYearToDateStartDate(periods, date) {
631
676
  return null;
632
677
  }
633
678
 
@@ -1421,7 +1466,7 @@ module.exports = (() => {
1421
1466
  * @param {Array.<Object>} portfolios - The portfolios.
1422
1467
  * @param {Array.<Object>} positions - The positions (for all of the portfolios).
1423
1468
  * @param {Array.<Object>} summaries - The positions summaries (for all of the positions).
1424
- * @param {PositionSummaryFrame} - If specified, locks the current (and previous) periods to a specific frame, use for reporting.
1469
+ * @param {PositionSummaryFrame=} - If specified, locks the current (and previous) periods to a specific frame, use for reporting.
1425
1470
  */
1426
1471
  class PositionContainer {
1427
1472
  constructor(definitions, portfolios, positions, summaries, frame) {
@@ -2515,6 +2560,10 @@ module.exports = (() => {
2515
2560
  this._dataActual.summaryTotalCurrent = null;
2516
2561
  this._dataActual.summaryTotalPrevious = null;
2517
2562
  this._dataActual.summaryTotalPrevious2 = null;
2563
+ this._dataActual.endingPrevious = null;
2564
+ this._dataActual.endingPrevious2 = null;
2565
+ this._dataActual.endingChange = null;
2566
+ this._dataActual.endingChangePercent = null;
2518
2567
  this._dataActual.cashTotal = null;
2519
2568
 
2520
2569
  this._dataFormat.currentPrice = null;
@@ -2538,6 +2587,10 @@ module.exports = (() => {
2538
2587
  this._dataFormat.summaryTotalPreviousNegative = false;
2539
2588
  this._dataFormat.summaryTotalPrevious2 = null;
2540
2589
  this._dataFormat.summaryTotalPrevious2Negative = false;
2590
+ this._dataFormat.endingPrevious = null;
2591
+ this._dataFormat.endingPrevious2 = null;
2592
+ this._dataFormat.endingChange = null;
2593
+ this._dataFormat.endingChangePercent = null;
2541
2594
  this._dataFormat.cashTotal = null;
2542
2595
  this._dataFormat.portfolioType = null;
2543
2596
 
@@ -2773,8 +2826,6 @@ module.exports = (() => {
2773
2826
  return;
2774
2827
  }
2775
2828
 
2776
- const descriptionSelector = this._definition.descriptionSelector;
2777
-
2778
2829
  this._description = PositionLevelDefinition.getDescriptionForPortfolioGroup(portfolio);
2779
2830
 
2780
2831
  this._dataActual.description = this._description;
@@ -3019,7 +3070,7 @@ module.exports = (() => {
3019
3070
  const translate = (item, value) => {
3020
3071
  let translated;
3021
3072
 
3022
- if (item.currency !== currency) {
3073
+ if (item.currency !== currency && !value.getIsZero()) {
3023
3074
  translated = Rate.convert(value, item.currency, currency, ...rates);
3024
3075
  } else {
3025
3076
  translated = value;
@@ -3036,6 +3087,8 @@ module.exports = (() => {
3036
3087
  updates.summaryTotalCurrent = updates.summaryTotalCurrent.add(translate(item, item.data.summaryTotalCurrent));
3037
3088
  updates.summaryTotalPrevious = updates.summaryTotalPrevious.add(translate(item, item.data.summaryTotalPrevious));
3038
3089
  updates.summaryTotalPrevious2 = updates.summaryTotalPrevious2.add(translate(item, item.data.summaryTotalPrevious2));
3090
+ updates.endingPrevious = updates.endingPrevious.add(translate(item, item.data.endingPrevious));
3091
+ updates.endingPrevious2 = updates.endingPrevious2.add(translate(item, item.data.endingPrevious2));
3039
3092
 
3040
3093
  if (item.position.instrument.type === InstrumentType.CASH) {
3041
3094
  updates.cashTotal = updates.cashTotal.add(translate(item, item.data.market));
@@ -3050,6 +3103,8 @@ module.exports = (() => {
3050
3103
  summaryTotalCurrent: Decimal.ZERO,
3051
3104
  summaryTotalPrevious: Decimal.ZERO,
3052
3105
  summaryTotalPrevious2: Decimal.ZERO,
3106
+ endingPrevious: Decimal.ZERO,
3107
+ endingPrevious2: Decimal.ZERO,
3053
3108
  cashTotal: Decimal.ZERO
3054
3109
  });
3055
3110
 
@@ -3060,6 +3115,8 @@ module.exports = (() => {
3060
3115
  actual.summaryTotalCurrent = updates.summaryTotalCurrent;
3061
3116
  actual.summaryTotalPrevious = updates.summaryTotalPrevious;
3062
3117
  actual.summaryTotalPrevious2 = updates.summaryTotalPrevious2;
3118
+ actual.endingPrevious = updates.endingPrevious;
3119
+ actual.endingPrevious2 = updates.endingPrevious2;
3063
3120
  actual.cashTotal = updates.cashTotal;
3064
3121
 
3065
3122
  format.basis = formatCurrency(actual.basis, currency);
@@ -3071,6 +3128,8 @@ module.exports = (() => {
3071
3128
  format.summaryTotalPreviousNegative = updates.summaryTotalPrevious.getIsNegative();
3072
3129
  format.summaryTotalPrevious2 = formatCurrency(updates.summaryTotalPrevious2, currency);
3073
3130
  format.summaryTotalPrevious2Negative = updates.summaryTotalPrevious2.getIsNegative();
3131
+ format.endingPrevious = formatCurrency(updates.endingPrevious, currency);
3132
+ format.endingPrevious2 = formatCurrency(updates.endingPrevious2, currency);
3074
3133
  format.cashTotal = formatCurrency(updates.cashTotal, currency);
3075
3134
 
3076
3135
  calculateUnrealizedPercent(group);
@@ -3120,7 +3179,7 @@ module.exports = (() => {
3120
3179
  const translate = (item, value) => {
3121
3180
  let translated;
3122
3181
 
3123
- if (item.currency !== currency) {
3182
+ if (item.currency !== currency && !value.getIsZero()) {
3124
3183
  translated = Rate.convert(value, item.currency, currency, ...rates);
3125
3184
  } else {
3126
3185
  translated = value;
@@ -3167,7 +3226,25 @@ module.exports = (() => {
3167
3226
  actual.unrealizedToday = updates.unrealizedToday;
3168
3227
  actual.summaryTotalCurrent = updates.summaryTotalCurrent;
3169
3228
  actual.total = updates.unrealized.add(actual.realized).add(actual.income);
3170
-
3229
+
3230
+ let endingChange = updates.market.subtract(actual.endingPrevious);
3231
+ let endingChangePercent;
3232
+
3233
+ if (actual.endingPrevious.getIsZero()) {
3234
+ if (endingChange.getIsPositive()) {
3235
+ endingChangePercent = Decimal.ONE;
3236
+ } else if (endingChange.getIsNegative()) {
3237
+ endingChangePercent = Decimal.NEGATIVE_ONE;
3238
+ } else {
3239
+ endingChangePercent = Decimal.ZERO;
3240
+ }
3241
+ } else {
3242
+ endingChangePercent = endingChange.divide(actual.endingPrevious);
3243
+ }
3244
+
3245
+ actual.endingChange = endingChange;
3246
+ actual.endingChangePercent = endingChangePercent;
3247
+
3171
3248
  format.market = formatCurrency(actual.market, currency);
3172
3249
 
3173
3250
  if (updates.marketDirection.up || updates.marketDirection.down) {
@@ -3187,6 +3264,9 @@ module.exports = (() => {
3187
3264
  format.total = formatCurrency(actual.total, currency);
3188
3265
  format.totalNegative = actual.total.getIsNegative();
3189
3266
 
3267
+ format.endingChange = formatCurrency(actual.endingChange, currency);
3268
+ format.endingChangePercent = formatPercent(actual.endingChangePercent, 2);
3269
+
3190
3270
  calculateUnrealizedPercent(group);
3191
3271
  }
3192
3272
 
@@ -3319,6 +3399,9 @@ module.exports = (() => {
3319
3399
  this._data.summaryTotalPrevious = null;
3320
3400
  this._data.summaryTotalPrevious2 = null;
3321
3401
 
3402
+ this._data.endingPrevious = null;
3403
+ this._data.endingPrevious2 = null;
3404
+
3322
3405
  this._data.realized = null;
3323
3406
  this._data.income = null;
3324
3407
  this._data.basisPrice = null;
@@ -3634,9 +3717,16 @@ module.exports = (() => {
3634
3717
 
3635
3718
  data.income = snapshot.income;
3636
3719
 
3637
- data.summaryTotalCurrent = calculateSummaryTotal(item.currentSummary, getPreviousSummary(previousSummaries, 1));
3638
- data.summaryTotalPrevious = calculateSummaryTotal(getPreviousSummary(previousSummaries, 1), getPreviousSummary(previousSummaries, 2));
3639
- data.summaryTotalPrevious2 = calculateSummaryTotal(getPreviousSummary(previousSummaries, 2), getPreviousSummary(previousSummaries, 3));
3720
+ const previousSummary1 = getPreviousSummary(previousSummaries, 1);
3721
+ const previousSummary2 = getPreviousSummary(previousSummaries, 2);
3722
+ const previousSummary3 = getPreviousSummary(previousSummaries, 3);
3723
+
3724
+ data.summaryTotalCurrent = calculateSummaryTotal(item.currentSummary, previousSummary1);
3725
+ data.summaryTotalPrevious = calculateSummaryTotal(previousSummary1, previousSummary2);
3726
+ data.summaryTotalPrevious2 = calculateSummaryTotal(previousSummary2, previousSummary3);
3727
+
3728
+ data.endingPrevious = previousSummary1 === null ? Decimal.ZERO : previousSummary1.end.value;
3729
+ data.endingPrevious2 = previousSummary2 === null ? Decimal.ZERO : previousSummary2.end.value;
3640
3730
 
3641
3731
  if (snapshot.open.getIsZero()) {
3642
3732
  data.basisPrice = Decimal.ZERO;
@@ -17564,6 +17654,38 @@ describe('After the PositionSummaryFrame enumeration is initialized', () => {
17564
17654
  });
17565
17655
  });
17566
17656
  });
17657
+
17658
+ describe('and prior ranges are calculated', () => {
17659
+ describe('for YEARLY ranges', () => {
17660
+ describe('from 2017-10-10, including one previous ranges', () => {
17661
+ let ranges;
17662
+
17663
+ beforeEach(() => {
17664
+ ranges = PositionSummaryFrame.YEARLY.getPriorRanges(new Day(2015, 4, 20), 1);
17665
+ });
17666
+
17667
+ it('should return two ranges', () => {
17668
+ expect(ranges.length).toEqual(2);
17669
+ });
17670
+
17671
+ it('the first range should begin on 2013-12-31', () => {
17672
+ expect(ranges[0].start.getIsEqual(new Day(2013, 12, 31))).toEqual(true);
17673
+ });
17674
+
17675
+ it('the first range should end on 2014-12-31', () => {
17676
+ expect(ranges[0].end.getIsEqual(new Day(2014, 12, 31))).toEqual(true);
17677
+ });
17678
+
17679
+ it('the second range should begin on 2014-12-31', () => {
17680
+ expect(ranges[1].start.getIsEqual(new Day(2014, 12, 31))).toEqual(true);
17681
+ });
17682
+
17683
+ it('the second range should end on 2015-12-31', () => {
17684
+ expect(ranges[1].end.getIsEqual(new Day(2015, 12, 31))).toEqual(true);
17685
+ });
17686
+ });
17687
+ });
17688
+ });
17567
17689
  });
17568
17690
 
17569
17691
  },{"./../../../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
  });