@barchart/portfolio-api-common 1.2.84 → 1.2.88

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.
@@ -39,16 +39,18 @@ module.exports = (() => {
39
39
  *
40
40
  * @public
41
41
  * @param {Array.<PositionTreeDefinition>} definitions
42
- * @param {Array.<Object>} portfolios
43
- * @param {Array.<Object>} positions
44
- * @param {Array.<Object>} summaries
42
+ * @param {Array.<Object>} portfolios - The portfolios.
43
+ * @param {Array.<Object>} positions - The positions (for all of the portfolios).
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
46
  */
46
47
  class PositionContainer {
47
- constructor(definitions, portfolios, positions, summaries) {
48
+ constructor(definitions, portfolios, positions, summaries, frame) {
48
49
  assert.argumentIsArray(definitions, 'definitions', PositionTreeDefinition, 'PositionTreeDefinition');
49
50
  assert.argumentIsArray(portfolios, 'portfolios');
50
51
  assert.argumentIsArray(positions, 'positions');
51
52
  assert.argumentIsArray(summaries, 'summaries');
53
+ assert.argumentIsOptional(frame, 'frame', PositionSummaryFrame, 'PositionSummaryFrame');
52
54
 
53
55
  this._definitions = definitions;
54
56
 
@@ -63,18 +65,24 @@ module.exports = (() => {
63
65
  return map;
64
66
  }, { });
65
67
 
66
- this._currentSummaryFrame = PositionSummaryFrame.YTD;
68
+ this._currentSummaryFrame = frame || PositionSummaryFrame.YTD;
67
69
  this._currentSummaryRange = array.last(this._currentSummaryFrame.getRecentRanges(0));
68
70
 
71
+ this._previousSummaryFrame = frame || PositionSummaryFrame.YEARLY;
72
+ this._previousSummaryRanges = this._previousSummaryFrame.getRecentRanges(3);
73
+
74
+ if (this._currentSummaryFrame === this._previousSummaryFrame) {
75
+ this._previousSummaryRanges.pop();
76
+ } else {
77
+ this._previousSummaryRanges.shift();
78
+ }
79
+
69
80
  this._summariesCurrent = summaries.reduce((map, summary) => {
70
81
  addSummaryCurrent(map, summary, this._currentSummaryFrame, this._currentSummaryRange);
71
82
 
72
83
  return map;
73
84
  }, { });
74
85
 
75
- this._previousSummaryFrame = PositionSummaryFrame.YEARLY;
76
- this._previousSummaryRanges = this._previousSummaryFrame.getRecentRanges(1);
77
-
78
86
  this._summariesPrevious = summaries.reduce((map, summary) => {
79
87
  addSummaryPrevious(map, summary, this._previousSummaryFrame, this._previousSummaryRanges);
80
88
 
@@ -276,6 +284,14 @@ module.exports = (() => {
276
284
 
277
285
  const existingBarchartSymbols = this.getPositionSymbols(false);
278
286
 
287
+ let similiarPositionItem;
288
+
289
+ if (is.object(position.instrument.symbol) && is.string(position.instrument.symbol.barchart)) {
290
+ similiarPositionItem = this._items.find(item => is.object(item.position.instrument.symbol) && item.position.instrument.symbol.barchart === position.instrument.symbol.barchart) || null;
291
+ } else {
292
+ similiarPositionItem = null;
293
+ }
294
+
279
295
  removePositionItem.call(this, this._items.find(item => item.position.position === position.position));
280
296
 
281
297
  summaries.forEach((summary) => {
@@ -323,6 +339,16 @@ module.exports = (() => {
323
339
  this._positionSymbolAddedEvent.fire(addedBarchartSymbol);
324
340
  }
325
341
 
342
+ if (similiarPositionItem !== null) {
343
+ if (similiarPositionItem.previousQuote) {
344
+ item.setQuote(similiarPositionItem.previousQuote);
345
+ }
346
+
347
+ if (similiarPositionItem.quote) {
348
+ item.setQuote(similiarPositionItem.quote);
349
+ }
350
+ }
351
+
326
352
  recalculatePercentages.call(this);
327
353
  }
328
354
 
@@ -403,7 +429,7 @@ module.exports = (() => {
403
429
 
404
430
  const item = this._items.find(i => i.position.position === position.position);
405
431
 
406
- return is.object(item) && item.locked;
432
+ return is.object(item) && item.data.locked;
407
433
  }
408
434
 
409
435
  /**
@@ -907,7 +933,7 @@ module.exports = (() => {
907
933
  }
908
934
  }
909
935
 
910
- function createPositionItem(position) {
936
+ function createPositionItem(position, currentQuote, previousQuote) {
911
937
  const portfolio = this._portfolios[position.portfolio];
912
938
 
913
939
  let returnRef;
@@ -11,8 +11,8 @@ module.exports = (() => {
11
11
  'use strict';
12
12
 
13
13
  /**
14
- * A container for a single position, which handles quote changes and
15
- * notifies observers -- which are typically parent-level {@link PositionGroup}
14
+ * A container for a single position, which handles quote changes and notifies
15
+ * observers -- which are typically parent-level {@link PositionGroup}
16
16
  * instances.
17
17
  *
18
18
  * @public
@@ -41,6 +41,7 @@ module.exports = (() => {
41
41
  this._data.basis = null;
42
42
 
43
43
  this._currentQuote = null;
44
+ this._previousQuote = null;
44
45
  this._currentPrice = null;
45
46
 
46
47
  this._data.currentPrice = null;
@@ -124,7 +125,7 @@ module.exports = (() => {
124
125
  }
125
126
 
126
127
  /**
127
- * The year-to-date summary of the encapsulated position.
128
+ * The current summary of the encapsulated position.
128
129
  *
129
130
  * @public
130
131
  * @returns {Object}
@@ -134,7 +135,7 @@ module.exports = (() => {
134
135
  }
135
136
 
136
137
  /**
137
- * Previous year's summaries for the encapsulated position.
138
+ * Previous summaries for the encapsulated position.
138
139
  *
139
140
  * @public
140
141
  * @returns {Object}
@@ -147,22 +148,32 @@ module.exports = (() => {
147
148
  * Various data regarding the encapsulated position.
148
149
  *
149
150
  * @public
150
- * @returns {*}
151
+ * @returns {Object}
151
152
  */
152
153
  get data() {
153
154
  return this._data;
154
155
  }
155
156
 
156
157
  /**
157
- * The current quote for the symbol of the encapsulated position.
158
+ * The most recent quote for the symbol of the encapsulated position.
158
159
  *
159
160
  * @public
160
- * @returns {null|{Object}}
161
+ * @returns {null|Object}
161
162
  */
162
163
  get quote() {
163
164
  return this._currentQuote;
164
165
  }
165
166
 
167
+ /**
168
+ * The second most recent quote for the symbol of the encapsulated position.
169
+ *
170
+ * @public
171
+ * @returns {null|Object}
172
+ */
173
+ get previousQuote() {
174
+ return this._previousQuote;
175
+ }
176
+
166
177
  updatePortfolio(portfolio) {
167
178
  assert.argumentIsRequired(portfolio, 'portfolio', Object);
168
179
  assert.argumentIsRequired(portfolio.portfolio, 'portfolio.portfolio', String);
@@ -200,6 +211,7 @@ module.exports = (() => {
200
211
  this._currentPricePrevious = this._currentPrice;
201
212
  this._currentPrice = quote.lastPrice;
202
213
 
214
+ this._previousQuote = this._currentQuote;
203
215
  this._currentQuote = quote;
204
216
 
205
217
  this._quoteChangedEvent.fire(this._currentQuote);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@barchart/portfolio-api-common",
3
- "version": "1.2.84",
3
+ "version": "1.2.88",
4
4
  "description": "Common classes used by the Portfolio system",
5
5
  "author": {
6
6
  "name": "Bryan Ingle",
@@ -1418,16 +1418,18 @@ module.exports = (() => {
1418
1418
  *
1419
1419
  * @public
1420
1420
  * @param {Array.<PositionTreeDefinition>} definitions
1421
- * @param {Array.<Object>} portfolios
1422
- * @param {Array.<Object>} positions
1423
- * @param {Array.<Object>} summaries
1421
+ * @param {Array.<Object>} portfolios - The portfolios.
1422
+ * @param {Array.<Object>} positions - The positions (for all of the portfolios).
1423
+ * @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.
1424
1425
  */
1425
1426
  class PositionContainer {
1426
- constructor(definitions, portfolios, positions, summaries) {
1427
+ constructor(definitions, portfolios, positions, summaries, frame) {
1427
1428
  assert.argumentIsArray(definitions, 'definitions', PositionTreeDefinition, 'PositionTreeDefinition');
1428
1429
  assert.argumentIsArray(portfolios, 'portfolios');
1429
1430
  assert.argumentIsArray(positions, 'positions');
1430
1431
  assert.argumentIsArray(summaries, 'summaries');
1432
+ assert.argumentIsOptional(frame, 'frame', PositionSummaryFrame, 'PositionSummaryFrame');
1431
1433
 
1432
1434
  this._definitions = definitions;
1433
1435
 
@@ -1442,18 +1444,24 @@ module.exports = (() => {
1442
1444
  return map;
1443
1445
  }, { });
1444
1446
 
1445
- this._currentSummaryFrame = PositionSummaryFrame.YTD;
1447
+ this._currentSummaryFrame = frame || PositionSummaryFrame.YTD;
1446
1448
  this._currentSummaryRange = array.last(this._currentSummaryFrame.getRecentRanges(0));
1447
1449
 
1450
+ this._previousSummaryFrame = frame || PositionSummaryFrame.YEARLY;
1451
+ this._previousSummaryRanges = this._previousSummaryFrame.getRecentRanges(3);
1452
+
1453
+ if (this._currentSummaryFrame === this._previousSummaryFrame) {
1454
+ this._previousSummaryRanges.pop();
1455
+ } else {
1456
+ this._previousSummaryRanges.shift();
1457
+ }
1458
+
1448
1459
  this._summariesCurrent = summaries.reduce((map, summary) => {
1449
1460
  addSummaryCurrent(map, summary, this._currentSummaryFrame, this._currentSummaryRange);
1450
1461
 
1451
1462
  return map;
1452
1463
  }, { });
1453
1464
 
1454
- this._previousSummaryFrame = PositionSummaryFrame.YEARLY;
1455
- this._previousSummaryRanges = this._previousSummaryFrame.getRecentRanges(1);
1456
-
1457
1465
  this._summariesPrevious = summaries.reduce((map, summary) => {
1458
1466
  addSummaryPrevious(map, summary, this._previousSummaryFrame, this._previousSummaryRanges);
1459
1467
 
@@ -1655,6 +1663,14 @@ module.exports = (() => {
1655
1663
 
1656
1664
  const existingBarchartSymbols = this.getPositionSymbols(false);
1657
1665
 
1666
+ let similiarPositionItem;
1667
+
1668
+ if (is.object(position.instrument.symbol) && is.string(position.instrument.symbol.barchart)) {
1669
+ similiarPositionItem = this._items.find(item => is.object(item.position.instrument.symbol) && item.position.instrument.symbol.barchart === position.instrument.symbol.barchart) || null;
1670
+ } else {
1671
+ similiarPositionItem = null;
1672
+ }
1673
+
1658
1674
  removePositionItem.call(this, this._items.find(item => item.position.position === position.position));
1659
1675
 
1660
1676
  summaries.forEach((summary) => {
@@ -1702,6 +1718,16 @@ module.exports = (() => {
1702
1718
  this._positionSymbolAddedEvent.fire(addedBarchartSymbol);
1703
1719
  }
1704
1720
 
1721
+ if (similiarPositionItem !== null) {
1722
+ if (similiarPositionItem.previousQuote) {
1723
+ item.setQuote(similiarPositionItem.previousQuote);
1724
+ }
1725
+
1726
+ if (similiarPositionItem.quote) {
1727
+ item.setQuote(similiarPositionItem.quote);
1728
+ }
1729
+ }
1730
+
1705
1731
  recalculatePercentages.call(this);
1706
1732
  }
1707
1733
 
@@ -1782,7 +1808,7 @@ module.exports = (() => {
1782
1808
 
1783
1809
  const item = this._items.find(i => i.position.position === position.position);
1784
1810
 
1785
- return is.object(item) && item.locked;
1811
+ return is.object(item) && item.data.locked;
1786
1812
  }
1787
1813
 
1788
1814
  /**
@@ -2286,7 +2312,7 @@ module.exports = (() => {
2286
2312
  }
2287
2313
  }
2288
2314
 
2289
- function createPositionItem(position) {
2315
+ function createPositionItem(position, currentQuote, previousQuote) {
2290
2316
  const portfolio = this._portfolios[position.portfolio];
2291
2317
 
2292
2318
  let returnRef;
@@ -3239,8 +3265,8 @@ module.exports = (() => {
3239
3265
  'use strict';
3240
3266
 
3241
3267
  /**
3242
- * A container for a single position, which handles quote changes and
3243
- * notifies observers -- which are typically parent-level {@link PositionGroup}
3268
+ * A container for a single position, which handles quote changes and notifies
3269
+ * observers -- which are typically parent-level {@link PositionGroup}
3244
3270
  * instances.
3245
3271
  *
3246
3272
  * @public
@@ -3269,6 +3295,7 @@ module.exports = (() => {
3269
3295
  this._data.basis = null;
3270
3296
 
3271
3297
  this._currentQuote = null;
3298
+ this._previousQuote = null;
3272
3299
  this._currentPrice = null;
3273
3300
 
3274
3301
  this._data.currentPrice = null;
@@ -3352,7 +3379,7 @@ module.exports = (() => {
3352
3379
  }
3353
3380
 
3354
3381
  /**
3355
- * The year-to-date summary of the encapsulated position.
3382
+ * The current summary of the encapsulated position.
3356
3383
  *
3357
3384
  * @public
3358
3385
  * @returns {Object}
@@ -3362,7 +3389,7 @@ module.exports = (() => {
3362
3389
  }
3363
3390
 
3364
3391
  /**
3365
- * Previous year's summaries for the encapsulated position.
3392
+ * Previous summaries for the encapsulated position.
3366
3393
  *
3367
3394
  * @public
3368
3395
  * @returns {Object}
@@ -3375,22 +3402,32 @@ module.exports = (() => {
3375
3402
  * Various data regarding the encapsulated position.
3376
3403
  *
3377
3404
  * @public
3378
- * @returns {*}
3405
+ * @returns {Object}
3379
3406
  */
3380
3407
  get data() {
3381
3408
  return this._data;
3382
3409
  }
3383
3410
 
3384
3411
  /**
3385
- * The current quote for the symbol of the encapsulated position.
3412
+ * The most recent quote for the symbol of the encapsulated position.
3386
3413
  *
3387
3414
  * @public
3388
- * @returns {null|{Object}}
3415
+ * @returns {null|Object}
3389
3416
  */
3390
3417
  get quote() {
3391
3418
  return this._currentQuote;
3392
3419
  }
3393
3420
 
3421
+ /**
3422
+ * The second most recent quote for the symbol of the encapsulated position.
3423
+ *
3424
+ * @public
3425
+ * @returns {null|Object}
3426
+ */
3427
+ get previousQuote() {
3428
+ return this._previousQuote;
3429
+ }
3430
+
3394
3431
  updatePortfolio(portfolio) {
3395
3432
  assert.argumentIsRequired(portfolio, 'portfolio', Object);
3396
3433
  assert.argumentIsRequired(portfolio.portfolio, 'portfolio.portfolio', String);
@@ -3428,6 +3465,7 @@ module.exports = (() => {
3428
3465
  this._currentPricePrevious = this._currentPrice;
3429
3466
  this._currentPrice = quote.lastPrice;
3430
3467
 
3468
+ this._previousQuote = this._currentQuote;
3431
3469
  this._currentQuote = quote;
3432
3470
 
3433
3471
  this._quoteChangedEvent.fire(this._currentQuote);
@@ -17456,6 +17494,76 @@ describe('After the PositionSummaryFrame enumeration is initialized', () => {
17456
17494
  });
17457
17495
  });
17458
17496
  });
17497
+
17498
+ describe('and recent ranges are calculated', () => {
17499
+ let todayYear;
17500
+ let todayMonth;
17501
+ let todayDay;
17502
+
17503
+ beforeEach(() => {
17504
+ const today = new Date();
17505
+
17506
+ todayYear = today.getFullYear();
17507
+ todayMonth = today.getMonth() + 1;
17508
+ todayDay = today.getDate();
17509
+ });
17510
+
17511
+ describe('the most recent YTD frame', () => {
17512
+ let ranges;
17513
+
17514
+ beforeEach(() => {
17515
+ ranges = PositionSummaryFrame.YTD.getRecentRanges(0);
17516
+ });
17517
+
17518
+ it('should contain one range', () => {
17519
+ expect(ranges.length).toEqual(1);
17520
+ });
17521
+
17522
+ it('the range should begin at the end of last year', () => {
17523
+ expect(ranges[0].start.format()).toEqual(`${todayYear - 1}-12-31`);
17524
+ });
17525
+
17526
+ it('the range should end at the end of this year', () => {
17527
+ expect(ranges[0].end.format()).toEqual(`${todayYear}-12-31`);
17528
+ });
17529
+ });
17530
+
17531
+ describe('the three most recent YEARLY frames', () => {
17532
+ let ranges;
17533
+
17534
+ beforeEach(() => {
17535
+ ranges = PositionSummaryFrame.YEARLY.getRecentRanges(2);
17536
+ });
17537
+
17538
+ it('should contain three range', () => {
17539
+ expect(ranges.length).toEqual(3);
17540
+ });
17541
+
17542
+ it('the first range should begin at the end of this year (minus three years)', () => {
17543
+ expect(ranges[0].start.format()).toEqual(`${todayYear - 4}-12-31`);
17544
+ });
17545
+
17546
+ it('the first range should end at the end of this year (minus two years)', () => {
17547
+ expect(ranges[0].end.format()).toEqual(`${todayYear - 3}-12-31`);
17548
+ });
17549
+
17550
+ it('the second range should begin at the end of this year (minus two years)', () => {
17551
+ expect(ranges[1].start.format()).toEqual(`${todayYear - 3}-12-31`);
17552
+ });
17553
+
17554
+ it('the second range should end at the end of this year (minus one years)', () => {
17555
+ expect(ranges[1].end.format()).toEqual(`${todayYear - 2}-12-31`);
17556
+ });
17557
+
17558
+ it('the third range should begin at the end of the year before last', () => {
17559
+ expect(ranges[2].start.format()).toEqual(`${todayYear - 2}-12-31`);
17560
+ });
17561
+
17562
+ it('the third range should end at the end of last year', () => {
17563
+ expect(ranges[2].end.format()).toEqual(`${todayYear - 1}-12-31`);
17564
+ });
17565
+ });
17566
+ });
17459
17567
  });
17460
17568
 
17461
17569
  },{"./../../../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){
@@ -17557,7 +17665,8 @@ describe('When requesting all the user-initiated transaction types', () => {
17557
17665
  const Currency = require('@barchart/common-js/lang/Currency'),
17558
17666
  Decimal = require('@barchart/common-js/lang/Decimal');
17559
17667
 
17560
- const InstrumentType = require('./../../../lib/data/InstrumentType');
17668
+ const InstrumentType = require('./../../../lib/data/InstrumentType'),
17669
+ PositionSummaryFrame = require('./../../../lib/data/PositionSummaryFrame');
17561
17670
 
17562
17671
  const PositionContainer = require('./../../../lib/processing/PositionContainer'),
17563
17672
  PositionLevelDefinition = require('./../../../lib/processing/definitions/PositionLevelDefinition'),
@@ -17590,6 +17699,37 @@ describe('When a position container data is gathered', () => {
17590
17699
  };
17591
17700
  }
17592
17701
 
17702
+ function getSummaries(position, frame, count) {
17703
+ const ranges = frame.getRecentRanges(count - 1);
17704
+
17705
+ return ranges.map((range) => {
17706
+ return {
17707
+ portfolio: position.portfolio,
17708
+ position: position.position,
17709
+ frame: frame,
17710
+ start: {
17711
+ date: range.start,
17712
+ open: position.snapshot.open,
17713
+ value: position.snapshot.value,
17714
+ basis: position.snapshot.basis
17715
+ },
17716
+ end: {
17717
+ date: range.end,
17718
+ open: position.snapshot.open,
17719
+ value: position.snapshot.value,
17720
+ basis: position.snapshot.basis
17721
+ },
17722
+ period: {
17723
+ buys: new Decimal(0),
17724
+ sells: new Decimal(0),
17725
+ income: new Decimal(0),
17726
+ realized: new Decimal(0),
17727
+ unrealized: new Decimal(0)
17728
+ }
17729
+ };
17730
+ });
17731
+ }
17732
+
17593
17733
  describe('for two portfolios, each with the same position, and the second portfolio with an addition position', () => {
17594
17734
  let portfolios;
17595
17735
  let positions;
@@ -17612,7 +17752,12 @@ describe('When a position container data is gathered', () => {
17612
17752
  getPosition('My Second Portfolio', 'TSLA')
17613
17753
  ];
17614
17754
 
17615
- summaries = [ ];
17755
+ summaries = positions.reduce((accumulator, position) => {
17756
+ accumulator = accumulator.concat(getSummaries(position, PositionSummaryFrame.YTD, 1));
17757
+ accumulator = accumulator.concat(getSummaries(position, PositionSummaryFrame.YEARLY, 3));
17758
+
17759
+ return accumulator;
17760
+ }, [ ]);
17616
17761
  });
17617
17762
 
17618
17763
  describe('and a container is created grouping by total, portfolio, and instrument', () => {
@@ -17659,11 +17804,49 @@ describe('When a position container data is gathered', () => {
17659
17804
  it('the "b" portfolio group should have two items', () => {
17660
17805
  expect(container.getGroup(name, [ 'totals', 'My Second Portfolio' ]).items.length).toEqual(2);
17661
17806
  });
17807
+
17808
+ describe('and an item is pulled for one of the positions', function() {
17809
+ let item;
17810
+
17811
+ let todayYear;
17812
+ let todayMonth;
17813
+ let todayDay;
17814
+
17815
+ beforeEach(() => {
17816
+ item = container.getGroup(name, [ 'totals', 'My First Portfolio' ]).items[0];
17817
+
17818
+ const today = new Date();
17819
+
17820
+ todayYear = today.getFullYear();
17821
+ todayMonth = today.getMonth() + 1;
17822
+ todayDay = today.getDate();
17823
+ });
17824
+
17825
+ it('the current summary should be a YTD summary for this year', () => {
17826
+ expect(item.currentSummary).toBe(summaries.find(s => s.position === item.position.position && s.frame === PositionSummaryFrame.YTD && s.start.date.format() === `${(todayYear - 1)}-12-31` && s.end.date.format() === `${(todayYear - 0)}-12-31`));
17827
+ });
17828
+
17829
+ it('should have two previous summaries', () => {
17830
+ expect(item.previousSummaries.length).toEqual(3);
17831
+ });
17832
+
17833
+ it('the previous (x1) summary should be a YEARLY summary for three years ago', () => {
17834
+ expect(item.previousSummaries[0]).toBe(summaries.find(s => s.position === item.position.position && s.frame === PositionSummaryFrame.YEARLY && s.start.date.format() === `${(todayYear - 4)}-12-31` && s.end.date.format() === `${(todayYear - 3)}-12-31`));
17835
+ });
17836
+
17837
+ it('the previous (x2) summary should be a YEARLY summary for the year before last', () => {
17838
+ expect(item.previousSummaries[1]).toBe(summaries.find(s => s.position === item.position.position && s.frame === PositionSummaryFrame.YEARLY && s.start.date.format() === `${(todayYear - 3)}-12-31` && s.end.date.format() === `${(todayYear - 2)}-12-31`));
17839
+ });
17840
+
17841
+ it('the previous (x3) summary should be a YEARLY summary for last year', () => {
17842
+ expect(item.previousSummaries[2]).toBe(summaries.find(s => s.position === item.position.position && s.frame === PositionSummaryFrame.YEARLY && s.start.date.format() === `${(todayYear - 2)}-12-31` && s.end.date.format() === `${(todayYear - 1)}-12-31`));
17843
+ });
17844
+ });
17662
17845
  });
17663
17846
  });
17664
17847
  });
17665
17848
 
17666
- },{"./../../../lib/data/InstrumentType":1,"./../../../lib/processing/PositionContainer":6,"./../../../lib/processing/definitions/PositionLevelDefinition":9,"./../../../lib/processing/definitions/PositionLevelType":10,"./../../../lib/processing/definitions/PositionTreeDefinition":11,"@barchart/common-js/lang/Currency":20,"@barchart/common-js/lang/Decimal":22}],55:[function(require,module,exports){
17849
+ },{"./../../../lib/data/InstrumentType":1,"./../../../lib/data/PositionSummaryFrame":3,"./../../../lib/processing/PositionContainer":6,"./../../../lib/processing/definitions/PositionLevelDefinition":9,"./../../../lib/processing/definitions/PositionLevelType":10,"./../../../lib/processing/definitions/PositionTreeDefinition":11,"@barchart/common-js/lang/Currency":20,"@barchart/common-js/lang/Decimal":22}],55:[function(require,module,exports){
17667
17850
  const Currency = require('@barchart/common-js/lang/Currency'),
17668
17851
  Day = require('@barchart/common-js/lang/Day'),
17669
17852
  Decimal = require('@barchart/common-js/lang/Decimal');
@@ -352,4 +352,74 @@ describe('After the PositionSummaryFrame enumeration is initialized', () => {
352
352
  });
353
353
  });
354
354
  });
355
+
356
+ describe('and recent ranges are calculated', () => {
357
+ let todayYear;
358
+ let todayMonth;
359
+ let todayDay;
360
+
361
+ beforeEach(() => {
362
+ const today = new Date();
363
+
364
+ todayYear = today.getFullYear();
365
+ todayMonth = today.getMonth() + 1;
366
+ todayDay = today.getDate();
367
+ });
368
+
369
+ describe('the most recent YTD frame', () => {
370
+ let ranges;
371
+
372
+ beforeEach(() => {
373
+ ranges = PositionSummaryFrame.YTD.getRecentRanges(0);
374
+ });
375
+
376
+ it('should contain one range', () => {
377
+ expect(ranges.length).toEqual(1);
378
+ });
379
+
380
+ it('the range should begin at the end of last year', () => {
381
+ expect(ranges[0].start.format()).toEqual(`${todayYear - 1}-12-31`);
382
+ });
383
+
384
+ it('the range should end at the end of this year', () => {
385
+ expect(ranges[0].end.format()).toEqual(`${todayYear}-12-31`);
386
+ });
387
+ });
388
+
389
+ describe('the three most recent YEARLY frames', () => {
390
+ let ranges;
391
+
392
+ beforeEach(() => {
393
+ ranges = PositionSummaryFrame.YEARLY.getRecentRanges(2);
394
+ });
395
+
396
+ it('should contain three range', () => {
397
+ expect(ranges.length).toEqual(3);
398
+ });
399
+
400
+ it('the first range should begin at the end of this year (minus three years)', () => {
401
+ expect(ranges[0].start.format()).toEqual(`${todayYear - 4}-12-31`);
402
+ });
403
+
404
+ it('the first range should end at the end of this year (minus two years)', () => {
405
+ expect(ranges[0].end.format()).toEqual(`${todayYear - 3}-12-31`);
406
+ });
407
+
408
+ it('the second range should begin at the end of this year (minus two years)', () => {
409
+ expect(ranges[1].start.format()).toEqual(`${todayYear - 3}-12-31`);
410
+ });
411
+
412
+ it('the second range should end at the end of this year (minus one years)', () => {
413
+ expect(ranges[1].end.format()).toEqual(`${todayYear - 2}-12-31`);
414
+ });
415
+
416
+ it('the third range should begin at the end of the year before last', () => {
417
+ expect(ranges[2].start.format()).toEqual(`${todayYear - 2}-12-31`);
418
+ });
419
+
420
+ it('the third range should end at the end of last year', () => {
421
+ expect(ranges[2].end.format()).toEqual(`${todayYear - 1}-12-31`);
422
+ });
423
+ });
424
+ });
355
425
  });
@@ -1,7 +1,8 @@
1
1
  const Currency = require('@barchart/common-js/lang/Currency'),
2
2
  Decimal = require('@barchart/common-js/lang/Decimal');
3
3
 
4
- const InstrumentType = require('./../../../lib/data/InstrumentType');
4
+ const InstrumentType = require('./../../../lib/data/InstrumentType'),
5
+ PositionSummaryFrame = require('./../../../lib/data/PositionSummaryFrame');
5
6
 
6
7
  const PositionContainer = require('./../../../lib/processing/PositionContainer'),
7
8
  PositionLevelDefinition = require('./../../../lib/processing/definitions/PositionLevelDefinition'),
@@ -34,6 +35,37 @@ describe('When a position container data is gathered', () => {
34
35
  };
35
36
  }
36
37
 
38
+ function getSummaries(position, frame, count) {
39
+ const ranges = frame.getRecentRanges(count - 1);
40
+
41
+ return ranges.map((range) => {
42
+ return {
43
+ portfolio: position.portfolio,
44
+ position: position.position,
45
+ frame: frame,
46
+ start: {
47
+ date: range.start,
48
+ open: position.snapshot.open,
49
+ value: position.snapshot.value,
50
+ basis: position.snapshot.basis
51
+ },
52
+ end: {
53
+ date: range.end,
54
+ open: position.snapshot.open,
55
+ value: position.snapshot.value,
56
+ basis: position.snapshot.basis
57
+ },
58
+ period: {
59
+ buys: new Decimal(0),
60
+ sells: new Decimal(0),
61
+ income: new Decimal(0),
62
+ realized: new Decimal(0),
63
+ unrealized: new Decimal(0)
64
+ }
65
+ };
66
+ });
67
+ }
68
+
37
69
  describe('for two portfolios, each with the same position, and the second portfolio with an addition position', () => {
38
70
  let portfolios;
39
71
  let positions;
@@ -56,7 +88,12 @@ describe('When a position container data is gathered', () => {
56
88
  getPosition('My Second Portfolio', 'TSLA')
57
89
  ];
58
90
 
59
- summaries = [ ];
91
+ summaries = positions.reduce((accumulator, position) => {
92
+ accumulator = accumulator.concat(getSummaries(position, PositionSummaryFrame.YTD, 1));
93
+ accumulator = accumulator.concat(getSummaries(position, PositionSummaryFrame.YEARLY, 3));
94
+
95
+ return accumulator;
96
+ }, [ ]);
60
97
  });
61
98
 
62
99
  describe('and a container is created grouping by total, portfolio, and instrument', () => {
@@ -103,6 +140,44 @@ describe('When a position container data is gathered', () => {
103
140
  it('the "b" portfolio group should have two items', () => {
104
141
  expect(container.getGroup(name, [ 'totals', 'My Second Portfolio' ]).items.length).toEqual(2);
105
142
  });
143
+
144
+ describe('and an item is pulled for one of the positions', function() {
145
+ let item;
146
+
147
+ let todayYear;
148
+ let todayMonth;
149
+ let todayDay;
150
+
151
+ beforeEach(() => {
152
+ item = container.getGroup(name, [ 'totals', 'My First Portfolio' ]).items[0];
153
+
154
+ const today = new Date();
155
+
156
+ todayYear = today.getFullYear();
157
+ todayMonth = today.getMonth() + 1;
158
+ todayDay = today.getDate();
159
+ });
160
+
161
+ it('the current summary should be a YTD summary for this year', () => {
162
+ expect(item.currentSummary).toBe(summaries.find(s => s.position === item.position.position && s.frame === PositionSummaryFrame.YTD && s.start.date.format() === `${(todayYear - 1)}-12-31` && s.end.date.format() === `${(todayYear - 0)}-12-31`));
163
+ });
164
+
165
+ it('should have two previous summaries', () => {
166
+ expect(item.previousSummaries.length).toEqual(3);
167
+ });
168
+
169
+ it('the previous (x1) summary should be a YEARLY summary for three years ago', () => {
170
+ expect(item.previousSummaries[0]).toBe(summaries.find(s => s.position === item.position.position && s.frame === PositionSummaryFrame.YEARLY && s.start.date.format() === `${(todayYear - 4)}-12-31` && s.end.date.format() === `${(todayYear - 3)}-12-31`));
171
+ });
172
+
173
+ it('the previous (x2) summary should be a YEARLY summary for the year before last', () => {
174
+ expect(item.previousSummaries[1]).toBe(summaries.find(s => s.position === item.position.position && s.frame === PositionSummaryFrame.YEARLY && s.start.date.format() === `${(todayYear - 3)}-12-31` && s.end.date.format() === `${(todayYear - 2)}-12-31`));
175
+ });
176
+
177
+ it('the previous (x3) summary should be a YEARLY summary for last year', () => {
178
+ expect(item.previousSummaries[2]).toBe(summaries.find(s => s.position === item.position.position && s.frame === PositionSummaryFrame.YEARLY && s.start.date.format() === `${(todayYear - 2)}-12-31` && s.end.date.format() === `${(todayYear - 1)}-12-31`));
179
+ });
180
+ });
106
181
  });
107
182
  });
108
183
  });