@barchart/portfolio-api-common 1.0.66 → 1.0.70

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.
@@ -1,6 +1,7 @@
1
1
  const array = require('@barchart/common-js/lang/array'),
2
2
  assert = require('@barchart/common-js/lang/assert'),
3
3
  Day = require('@barchart/common-js/lang/Day'),
4
+ Decimal = require('@barchart/common-js/lang/Decimal'),
4
5
  Enum = require('@barchart/common-js/lang/Enum'),
5
6
  is = require('@barchart/common-js/lang/is');
6
7
 
@@ -16,23 +17,68 @@ module.exports = (() => {
16
17
  * @param {String} description
17
18
  * @param {Function} rangeCalculator
18
19
  * @param {Function} startDateCalculator
20
+ * @param {Function} descriptionCalculator
19
21
  */
20
22
  class PositionSummaryFrame extends Enum {
21
- constructor(code, description, rangeCalculator, startDateCalculator) {
23
+ constructor(code, description, rangeCalculator, startDateCalculator, descriptionCalculator) {
22
24
  super(code, description);
23
25
 
24
26
  assert.argumentIsRequired(rangeCalculator, 'rangeCalculator', Function);
27
+ assert.argumentIsRequired(startDateCalculator, 'startDateCalculator', Function);
28
+ assert.argumentIsRequired(descriptionCalculator, 'descriptionCalculator', Function);
25
29
 
26
30
  this._rangeCalculator = rangeCalculator;
27
31
  this._startDateCalculator = startDateCalculator;
32
+ this._descriptionCalculator = descriptionCalculator;
28
33
  }
29
34
 
35
+ /**
36
+ * Returns a human-readable description of the frame, given
37
+ * start and end dates.
38
+ *
39
+ * @public
40
+ * @param {Day} startDate
41
+ * @param {Day} endDate
42
+ * @return {String}
43
+ */
44
+ describeRange(startDate, endDate) {
45
+ return this._descriptionCalculator(startDate, endDate);
46
+ }
47
+
48
+ /**
49
+ * Returns the most recent ranges for the frame.
50
+ *
51
+ * @public
52
+ * @param {Number} periods
53
+ * @returns {Array.<PositionSummaryRange>}
54
+ */
55
+ getRecentRanges(periods) {
56
+ const startDate = this.getStartDate(periods);
57
+ const transaction = { date: startDate, snapshot: { open: Decimal.ONE } };
58
+
59
+ return this.getRanges([ transaction ]);
60
+ }
61
+
62
+ /**
63
+ * Returns the ranges for the set of {@link Transaction} objects.
64
+ *
65
+ * @public
66
+ * @param {Array.<Transaction>} transactions
67
+ * @returns {Array.<PositionSummaryRange>}
68
+ */
30
69
  getRanges(transactions) {
31
70
  assert.argumentIsArray(transactions, 'transactions');
32
71
 
33
72
  return this._rangeCalculator(getFilteredTransactions(transactions));
34
73
  }
35
74
 
75
+ /**
76
+ * Returns the start date for a frame, a given number of periods ago.
77
+ *
78
+ * @public
79
+ * @param {Number} periods
80
+ * @returns {Day}
81
+ */
36
82
  getStartDate(periods) {
37
83
  assert.argumentIsRequired(periods, 'periods', Number);
38
84
 
@@ -84,10 +130,19 @@ module.exports = (() => {
84
130
  }
85
131
  }
86
132
 
87
- const yearly = new PositionSummaryFrame('YEARLY', 'year', getYearlyRanges, getYearlyStartDate);
88
- const quarterly = new PositionSummaryFrame('QUARTER', 'quarter', getQuarterlyRanges, getQuarterlyStartDate);
89
- const monthly = new PositionSummaryFrame('MONTH', 'month', getMonthlyRanges, getMonthlyStartDate);
90
- const ytd = new PositionSummaryFrame('YTD', 'year-to-date', getYearToDateRanges, getYearToDateStartDate);
133
+ const yearly = new PositionSummaryFrame('YEARLY', 'year', getYearlyRanges, getYearlyStartDate, getYearlyRangeDescription);
134
+ const quarterly = new PositionSummaryFrame('QUARTER', 'quarter', getQuarterlyRanges, getQuarterlyStartDate, getQuarterlyRangeDescription);
135
+ const monthly = new PositionSummaryFrame('MONTH', 'month', getMonthlyRanges, getMonthlyStartDate, getMonthlyRangeDescription);
136
+ const ytd = new PositionSummaryFrame('YTD', 'year-to-date', getYearToDateRanges, getYearToDateStartDate, getYearToDateRangeDescription);
137
+
138
+ /**
139
+ * The start and and date for a {@link PositionSummaryFrame}
140
+ *
141
+ * @typedef PositionSummaryRange
142
+ * @type {Object}
143
+ * @property {Day} start
144
+ * @property {Day} end
145
+ */
91
146
 
92
147
  function getRange(start, end) {
93
148
  return {
@@ -171,6 +226,22 @@ module.exports = (() => {
171
226
  return null;
172
227
  }
173
228
 
229
+ function getYearlyRangeDescription(startDate, endDate) {
230
+ return endDate.year.toString();
231
+ }
232
+
233
+ function getQuarterlyRangeDescription(startDate, endDate) {
234
+ return '';
235
+ }
236
+
237
+ function getMonthlyRangeDescription(startDate, endDate) {
238
+ return '';
239
+ }
240
+
241
+ function getYearToDateRangeDescription(startDate, endDate) {
242
+ return '';
243
+ }
244
+
174
245
  function getFilteredTransactions(transactions) {
175
246
  return transactions.reduce((filtered, transaction) => {
176
247
  if (!transaction.snapshot.open.getIsZero() || transaction.type.closing) {
@@ -6,7 +6,7 @@ const array = require('@barchart/common-js/lang/array'),
6
6
  is = require('@barchart/common-js/lang/is'),
7
7
  Tree = require('@barchart/common-js/collections/Tree');
8
8
 
9
- const InstrumentType = require('./../data/InstrumentType');
9
+ const PositionSummaryFrame = require('./../data/PositionSummaryFrame');
10
10
 
11
11
  const PositionGroup = require('./PositionGroup'),
12
12
  PositionItem = require('./PositionItem');
@@ -18,10 +18,13 @@ module.exports = (() => {
18
18
  * @public
19
19
  */
20
20
  class PositionContainer {
21
- constructor(portfolios, positions, summaries, definitions, defaultCurrency) {
21
+ constructor(portfolios, positions, summaries, definitions, defaultCurrency, summaryFrameType) {
22
22
  this._definitions = definitions;
23
23
  this._defaultCurrency = defaultCurrency || Currency.CAD;
24
24
 
25
+ this._summaryFrame = summaryFrameType || PositionSummaryFrame.YEARLY;
26
+ this._summaryRanges = this._summaryFrame.getRecentRanges(1);
27
+
25
28
  this._portfolios = portfolios.reduce((map, portfolio) => {
26
29
  map[portfolio.portfolio] = portfolio;
27
30
 
@@ -29,13 +32,19 @@ module.exports = (() => {
29
32
  }, { });
30
33
 
31
34
  this._summaries = summaries.reduce((map, summary) => {
32
- const key = summary.position;
35
+ if (this._summaryFrame === summary.frame) {
36
+ const key = summary.position;
33
37
 
34
- if (!map.hasOwnProperty(key)) {
35
- map[key] = [ ];
36
- }
38
+ if (!map.hasOwnProperty(key)) {
39
+ map[key] = getSummaryArray(this._summaryRanges);
40
+ }
41
+
42
+ const index = this._summaryRanges.findIndex(r => r.start.getIsEqual(summary.start.date) && r.end.getIsEqual(summary.end.date));
37
43
 
38
- map[key].push(summary);
44
+ if (!(index < 0)) {
45
+ map[key][index] = summary;
46
+ }
47
+ }
39
48
 
40
49
  return map;
41
50
  }, { });
@@ -44,7 +53,7 @@ module.exports = (() => {
44
53
  const portfolio = this._portfolios[position.portfolio];
45
54
 
46
55
  if (position) {
47
- const summaries = this._summaries[position.position] || [ ];
56
+ const summaries = this._summaries[position.position] || getSummaryArray(this._summaryRanges);
48
57
 
49
58
  items.push(new PositionItem(portfolio, position, summaries));
50
59
  }
@@ -206,5 +215,9 @@ module.exports = (() => {
206
215
  }
207
216
  }
208
217
 
218
+ function getSummaryArray(ranges) {
219
+ return ranges.map(range => null);
220
+ }
221
+
209
222
  return PositionContainer;
210
223
  })();
@@ -25,20 +25,30 @@ module.exports = (() => {
25
25
  this._dataActual = { };
26
26
 
27
27
  this._dataFormat.description = this._description;
28
-
28
+
29
29
  this._dataActual.currentPrice = null;
30
30
  this._dataActual.previousPrice = null;
31
31
  this._dataActual.basis = null;
32
+ this._dataActual.realized = null;
33
+ this._dataActual.income = null;
32
34
  this._dataActual.market = null;
33
35
  this._dataActual.marketPercent = null;
34
36
  this._dataActual.unrealizedToday = null;
37
+ this._dataActual.total = null;
38
+ this._dataActual.summaryOneTotal = null;
39
+ this._dataActual.summaryTwoTotal = null;
35
40
 
36
41
  this._dataFormat.currentPrice = null;
37
42
  this._dataFormat.previousPrice = null;
38
43
  this._dataFormat.basis = null;
44
+ this._dataFormat.realized = null;
45
+ this._dataFormat.income = null;
39
46
  this._dataFormat.market = null;
40
47
  this._dataFormat.marketPercent = null;
41
48
  this._dataFormat.unrealizedToday = null;
49
+ this._dataFormat.total = null;
50
+ this._dataFormat.summaryOneTotal = null;
51
+ this._dataFormat.summaryTwoTotal = null;
42
52
 
43
53
  this._dataFormat.unrealizedTodayNegative = false;
44
54
 
@@ -89,15 +99,15 @@ module.exports = (() => {
89
99
  if (decimal !== null) {
90
100
  return formatter.numberToString(decimal.toFloat(), precision, ',', false);
91
101
  } else {
92
- return '--';
102
+ return '';
93
103
  }
94
104
  }
95
105
 
96
106
  function formatPercent(decimal, precision) {
97
107
  if (decimal !== null) {
98
- return formatNumber(decimal.multiply(100));
108
+ return formatNumber(decimal.multiply(100), precision);
99
109
  } else {
100
- return '--';
110
+ return '';
101
111
  }
102
112
  }
103
113
 
@@ -115,15 +125,31 @@ module.exports = (() => {
115
125
 
116
126
  let updates = items.reduce((updates, item) => {
117
127
  updates.basis = updates.basis.add(item.data.basis);
128
+ updates.realized = updates.realized.add(item.data.realized);
129
+ updates.income = updates.income.add(item.data.income);
130
+ updates.summaryOneTotal = updates.summaryOneTotal.add(item.data.summaryOneTotal);
131
+ updates.summaryTwoTotal = updates.summaryTwoTotal.add(item.data.summaryTwoTotal);
118
132
 
119
133
  return updates;
120
134
  }, {
121
- basis: Decimal.ZERO
135
+ basis: Decimal.ZERO,
136
+ realized: Decimal.ZERO,
137
+ income: Decimal.ZERO,
138
+ summaryOneTotal: Decimal.ZERO,
139
+ summaryTwoTotal: Decimal.ZERO
122
140
  });
123
141
 
124
142
  actual.basis = updates.basis;
125
-
126
- format.basis = formatCurrency(updates.basis, currency);
143
+ actual.realized = updates.realized;
144
+ actual.income = updates.income;
145
+ actual.summaryOneTotal = updates.summaryOneTotal;
146
+ actual.summaryTwoTotal = updates.summaryTwoTotal;
147
+
148
+ format.basis = formatCurrency(actual.basis, currency);
149
+ format.realized = formatCurrency(actual.basis, currency);
150
+ format.income = formatCurrency(actual.income, currency);
151
+ format.summaryOneTotal = formatCurrency(updates.summaryOneTotal, currency);
152
+ format.summaryTwoTotal = formatCurrency(updates.summaryTwoTotal, currency);
127
153
  }
128
154
 
129
155
  function calculatePriceData(group, item) {
@@ -136,7 +162,12 @@ module.exports = (() => {
136
162
 
137
163
  let updates;
138
164
 
139
- if (actual.market === null || actual.unrealizedToday === null) {
165
+ if (actual.market !== null && actual.unrealizedToday !== null && actual.total !== null) {
166
+ updates = {
167
+ market: actual.market.add(item.data.marketChange),
168
+ unrealizedToday: actual.unrealizedToday.add(item.data.unrealizedTodayChange)
169
+ };
170
+ } else {
140
171
  const items = group._items;
141
172
 
142
173
  updates = items.reduce((updates, item) => {
@@ -148,11 +179,6 @@ module.exports = (() => {
148
179
  market: Decimal.ZERO,
149
180
  unrealizedToday: Decimal.ZERO
150
181
  });
151
- } else {
152
- updates = {
153
- market: actual.market.add(item.data.marketChange),
154
- unrealizedToday: actual.unrealizedToday.add(item.data.unrealizedTodayChange)
155
- };
156
182
  }
157
183
 
158
184
  if (parent !== null) {
@@ -160,17 +186,23 @@ module.exports = (() => {
160
186
 
161
187
  if (parentData.market !== null && !parentData.market.getIsZero()) {
162
188
  updates.marketPercent = updates.market.divide(parentData.market);
189
+ } else {
190
+ updates.marketPercent = null;
163
191
  }
192
+ } else {
193
+ updates.marketPercent = null;
164
194
  }
165
-
195
+
166
196
  actual.market = updates.market;
167
197
  actual.marketPercent = updates.marketPercent;
168
198
  actual.unrealizedToday = updates.unrealizedToday;
199
+ actual.total = updates.unrealizedToday.add(actual.realized).add(actual.income);
169
200
 
170
- format.market = formatCurrency(updates.market, currency);
171
- format.marketPercent = formatPercent(updates.unrealizedToday, 2);
172
- format.unrealizedToday = formatCurrency(updates.unrealizedToday, currency);
201
+ format.market = formatCurrency(actual.market, currency);
202
+ format.marketPercent = formatPercent(actual.marketPercent, 2);
203
+ format.unrealizedToday = formatCurrency(actual.unrealizedToday, currency);
173
204
  format.unrealizedTodayNegative = actual.unrealizedToday.getIsNegative();
205
+ format.total = formatCurrency(actual.total, currency);
174
206
  }
175
207
 
176
208
  return PositionGroup;
@@ -26,10 +26,13 @@ module.exports = (() => {
26
26
 
27
27
  this._data.market = null;
28
28
  this._data.marketChange = null;
29
-
29
+
30
30
  this._data.unrealizedToday = null;
31
31
  this._data.unrealizedTodayChange = null;
32
32
 
33
+ this._data.realized = null;
34
+ this._data.income = null;
35
+
33
36
  calculateStaticData(this);
34
37
  calculatePriceData(this, null);
35
38
 
@@ -74,10 +77,11 @@ module.exports = (() => {
74
77
  function calculateStaticData(item) {
75
78
  const position = item.position;
76
79
  const snapshot = item.position.snapshot;
80
+ const summaries = item.summaries;
77
81
 
78
82
  const data = item._data;
79
83
 
80
- data.previousPrice = position.previousPrice || null;
84
+ data.previousPrice = position.previous || null;
81
85
 
82
86
  let basis;
83
87
 
@@ -88,6 +92,26 @@ module.exports = (() => {
88
92
  }
89
93
 
90
94
  data.basis = basis;
95
+
96
+ data.realized = snapshot.gain;
97
+ data.income = snapshot.income;
98
+
99
+ const getSummaryTotal = (index) => {
100
+ let summaryTotal;
101
+
102
+ if (summaries.length > (index + 1) && summaries[index] !== null) {
103
+ const period = summaries[index].period;
104
+
105
+ summaryTotal = period.realized.add(period.unrealized).add(period.income);
106
+ } else {
107
+ summaryTotal = Decimal.ZERO;
108
+ }
109
+
110
+ return summaryTotal;
111
+ };
112
+
113
+ data.summaryOneTotal = getSummaryTotal(0);
114
+ data.summaryTwoTotal = getSummaryTotal(1);
91
115
  }
92
116
 
93
117
  function calculatePriceData(item, price) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@barchart/portfolio-api-common",
3
- "version": "1.0.66",
3
+ "version": "1.0.70",
4
4
  "description": "Common classes used by the Portfolio system",
5
5
  "author": {
6
6
  "name": "Bryan Ingle",
@@ -93,6 +93,7 @@ module.exports = (() => {
93
93
  const array = require('@barchart/common-js/lang/array'),
94
94
  assert = require('@barchart/common-js/lang/assert'),
95
95
  Day = require('@barchart/common-js/lang/Day'),
96
+ Decimal = require('@barchart/common-js/lang/Decimal'),
96
97
  Enum = require('@barchart/common-js/lang/Enum'),
97
98
  is = require('@barchart/common-js/lang/is');
98
99
 
@@ -108,23 +109,68 @@ module.exports = (() => {
108
109
  * @param {String} description
109
110
  * @param {Function} rangeCalculator
110
111
  * @param {Function} startDateCalculator
112
+ * @param {Function} descriptionCalculator
111
113
  */
112
114
  class PositionSummaryFrame extends Enum {
113
- constructor(code, description, rangeCalculator, startDateCalculator) {
115
+ constructor(code, description, rangeCalculator, startDateCalculator, descriptionCalculator) {
114
116
  super(code, description);
115
117
 
116
118
  assert.argumentIsRequired(rangeCalculator, 'rangeCalculator', Function);
119
+ assert.argumentIsRequired(startDateCalculator, 'startDateCalculator', Function);
120
+ assert.argumentIsRequired(descriptionCalculator, 'descriptionCalculator', Function);
117
121
 
118
122
  this._rangeCalculator = rangeCalculator;
119
123
  this._startDateCalculator = startDateCalculator;
124
+ this._descriptionCalculator = descriptionCalculator;
125
+ }
126
+
127
+ /**
128
+ * Returns a human-readable description of the frame, given
129
+ * start and end dates.
130
+ *
131
+ * @public
132
+ * @param {Day} startDate
133
+ * @param {Day} endDate
134
+ * @return {String}
135
+ */
136
+ describeRange(startDate, endDate) {
137
+ return this._descriptionCalculator(startDate, endDate);
138
+ }
139
+
140
+ /**
141
+ * Returns the most recent ranges for the frame.
142
+ *
143
+ * @public
144
+ * @param {Number} periods
145
+ * @returns {Array.<PositionSummaryRange>}
146
+ */
147
+ getRecentRanges(periods) {
148
+ const startDate = this.getStartDate(periods);
149
+ const transaction = { date: startDate, snapshot: { open: Decimal.ONE } };
150
+
151
+ return this.getRanges([ transaction ]);
120
152
  }
121
153
 
154
+ /**
155
+ * Returns the ranges for the set of {@link Transaction} objects.
156
+ *
157
+ * @public
158
+ * @param {Array.<Transaction>} transactions
159
+ * @returns {Array.<PositionSummaryRange>}
160
+ */
122
161
  getRanges(transactions) {
123
162
  assert.argumentIsArray(transactions, 'transactions');
124
163
 
125
164
  return this._rangeCalculator(getFilteredTransactions(transactions));
126
165
  }
127
166
 
167
+ /**
168
+ * Returns the start date for a frame, a given number of periods ago.
169
+ *
170
+ * @public
171
+ * @param {Number} periods
172
+ * @returns {Day}
173
+ */
128
174
  getStartDate(periods) {
129
175
  assert.argumentIsRequired(periods, 'periods', Number);
130
176
 
@@ -176,10 +222,19 @@ module.exports = (() => {
176
222
  }
177
223
  }
178
224
 
179
- const yearly = new PositionSummaryFrame('YEARLY', 'year', getYearlyRanges, getYearlyStartDate);
180
- const quarterly = new PositionSummaryFrame('QUARTER', 'quarter', getQuarterlyRanges, getQuarterlyStartDate);
181
- const monthly = new PositionSummaryFrame('MONTH', 'month', getMonthlyRanges, getMonthlyStartDate);
182
- const ytd = new PositionSummaryFrame('YTD', 'year-to-date', getYearToDateRanges, getYearToDateStartDate);
225
+ const yearly = new PositionSummaryFrame('YEARLY', 'year', getYearlyRanges, getYearlyStartDate, getYearlyRangeDescription);
226
+ const quarterly = new PositionSummaryFrame('QUARTER', 'quarter', getQuarterlyRanges, getQuarterlyStartDate, getQuarterlyRangeDescription);
227
+ const monthly = new PositionSummaryFrame('MONTH', 'month', getMonthlyRanges, getMonthlyStartDate, getMonthlyRangeDescription);
228
+ const ytd = new PositionSummaryFrame('YTD', 'year-to-date', getYearToDateRanges, getYearToDateStartDate, getYearToDateRangeDescription);
229
+
230
+ /**
231
+ * The start and and date for a {@link PositionSummaryFrame}
232
+ *
233
+ * @typedef PositionSummaryRange
234
+ * @type {Object}
235
+ * @property {Day} start
236
+ * @property {Day} end
237
+ */
183
238
 
184
239
  function getRange(start, end) {
185
240
  return {
@@ -263,6 +318,22 @@ module.exports = (() => {
263
318
  return null;
264
319
  }
265
320
 
321
+ function getYearlyRangeDescription(startDate, endDate) {
322
+ return endDate.year.toString();
323
+ }
324
+
325
+ function getQuarterlyRangeDescription(startDate, endDate) {
326
+ return '';
327
+ }
328
+
329
+ function getMonthlyRangeDescription(startDate, endDate) {
330
+ return '';
331
+ }
332
+
333
+ function getYearToDateRangeDescription(startDate, endDate) {
334
+ return '';
335
+ }
336
+
266
337
  function getFilteredTransactions(transactions) {
267
338
  return transactions.reduce((filtered, transaction) => {
268
339
  if (!transaction.snapshot.open.getIsZero() || transaction.type.closing) {
@@ -276,7 +347,7 @@ module.exports = (() => {
276
347
  return PositionSummaryFrame;
277
348
  })();
278
349
 
279
- },{"@barchart/common-js/lang/Day":12,"@barchart/common-js/lang/Enum":15,"@barchart/common-js/lang/array":16,"@barchart/common-js/lang/assert":17,"@barchart/common-js/lang/is":19}],3:[function(require,module,exports){
350
+ },{"@barchart/common-js/lang/Day":12,"@barchart/common-js/lang/Decimal":13,"@barchart/common-js/lang/Enum":15,"@barchart/common-js/lang/array":16,"@barchart/common-js/lang/assert":17,"@barchart/common-js/lang/is":19}],3:[function(require,module,exports){
280
351
  const assert = require('@barchart/common-js/lang/assert'),
281
352
  Enum = require('@barchart/common-js/lang/Enum');
282
353
 
@@ -612,7 +683,7 @@ const array = require('@barchart/common-js/lang/array'),
612
683
  is = require('@barchart/common-js/lang/is'),
613
684
  Tree = require('@barchart/common-js/collections/Tree');
614
685
 
615
- const InstrumentType = require('./../data/InstrumentType');
686
+ const PositionSummaryFrame = require('./../data/PositionSummaryFrame');
616
687
 
617
688
  const PositionGroup = require('./PositionGroup'),
618
689
  PositionItem = require('./PositionItem');
@@ -624,10 +695,13 @@ module.exports = (() => {
624
695
  * @public
625
696
  */
626
697
  class PositionContainer {
627
- constructor(portfolios, positions, summaries, definitions, defaultCurrency) {
698
+ constructor(portfolios, positions, summaries, definitions, defaultCurrency, summaryFrameType) {
628
699
  this._definitions = definitions;
629
700
  this._defaultCurrency = defaultCurrency || Currency.CAD;
630
701
 
702
+ this._summaryFrame = summaryFrameType || PositionSummaryFrame.YEARLY;
703
+ this._summaryRanges = this._summaryFrame.getRecentRanges(1);
704
+
631
705
  this._portfolios = portfolios.reduce((map, portfolio) => {
632
706
  map[portfolio.portfolio] = portfolio;
633
707
 
@@ -635,13 +709,19 @@ module.exports = (() => {
635
709
  }, { });
636
710
 
637
711
  this._summaries = summaries.reduce((map, summary) => {
638
- const key = summary.position;
712
+ if (this._summaryFrame === summary.frame) {
713
+ const key = summary.position;
639
714
 
640
- if (!map.hasOwnProperty(key)) {
641
- map[key] = [ ];
642
- }
715
+ if (!map.hasOwnProperty(key)) {
716
+ map[key] = getSummaryArray(this._summaryRanges);
717
+ }
718
+
719
+ const index = this._summaryRanges.findIndex(r => r.start.getIsEqual(summary.start.date) && r.end.getIsEqual(summary.end.date));
643
720
 
644
- map[key].push(summary);
721
+ if (!(index < 0)) {
722
+ map[key][index] = summary;
723
+ }
724
+ }
645
725
 
646
726
  return map;
647
727
  }, { });
@@ -650,7 +730,7 @@ module.exports = (() => {
650
730
  const portfolio = this._portfolios[position.portfolio];
651
731
 
652
732
  if (position) {
653
- const summaries = this._summaries[position.position] || [ ];
733
+ const summaries = this._summaries[position.position] || getSummaryArray(this._summaryRanges);
654
734
 
655
735
  items.push(new PositionItem(portfolio, position, summaries));
656
736
  }
@@ -812,10 +892,14 @@ module.exports = (() => {
812
892
  }
813
893
  }
814
894
 
895
+ function getSummaryArray(ranges) {
896
+ return ranges.map(range => null);
897
+ }
898
+
815
899
  return PositionContainer;
816
900
  })();
817
901
 
818
- },{"./../data/InstrumentType":1,"./PositionGroup":5,"./PositionItem":7,"@barchart/common-js/collections/Tree":8,"@barchart/common-js/collections/sorting/ComparatorBuilder":9,"@barchart/common-js/collections/sorting/comparators":10,"@barchart/common-js/lang/Currency":11,"@barchart/common-js/lang/array":16,"@barchart/common-js/lang/assert":17,"@barchart/common-js/lang/is":19}],5:[function(require,module,exports){
902
+ },{"./../data/PositionSummaryFrame":2,"./PositionGroup":5,"./PositionItem":7,"@barchart/common-js/collections/Tree":8,"@barchart/common-js/collections/sorting/ComparatorBuilder":9,"@barchart/common-js/collections/sorting/comparators":10,"@barchart/common-js/lang/Currency":11,"@barchart/common-js/lang/array":16,"@barchart/common-js/lang/assert":17,"@barchart/common-js/lang/is":19}],5:[function(require,module,exports){
819
903
  const assert = require('@barchart/common-js/lang/assert'),
820
904
  Currency = require('@barchart/common-js/lang/Currency'),
821
905
  Decimal = require('@barchart/common-js/lang/Decimal'),
@@ -843,20 +927,30 @@ module.exports = (() => {
843
927
  this._dataActual = { };
844
928
 
845
929
  this._dataFormat.description = this._description;
846
-
930
+
847
931
  this._dataActual.currentPrice = null;
848
932
  this._dataActual.previousPrice = null;
849
933
  this._dataActual.basis = null;
934
+ this._dataActual.realized = null;
935
+ this._dataActual.income = null;
850
936
  this._dataActual.market = null;
851
937
  this._dataActual.marketPercent = null;
852
938
  this._dataActual.unrealizedToday = null;
939
+ this._dataActual.total = null;
940
+ this._dataActual.summaryOneTotal = null;
941
+ this._dataActual.summaryTwoTotal = null;
853
942
 
854
943
  this._dataFormat.currentPrice = null;
855
944
  this._dataFormat.previousPrice = null;
856
945
  this._dataFormat.basis = null;
946
+ this._dataFormat.realized = null;
947
+ this._dataFormat.income = null;
857
948
  this._dataFormat.market = null;
858
949
  this._dataFormat.marketPercent = null;
859
950
  this._dataFormat.unrealizedToday = null;
951
+ this._dataFormat.total = null;
952
+ this._dataFormat.summaryOneTotal = null;
953
+ this._dataFormat.summaryTwoTotal = null;
860
954
 
861
955
  this._dataFormat.unrealizedTodayNegative = false;
862
956
 
@@ -907,15 +1001,15 @@ module.exports = (() => {
907
1001
  if (decimal !== null) {
908
1002
  return formatter.numberToString(decimal.toFloat(), precision, ',', false);
909
1003
  } else {
910
- return '--';
1004
+ return '';
911
1005
  }
912
1006
  }
913
1007
 
914
1008
  function formatPercent(decimal, precision) {
915
1009
  if (decimal !== null) {
916
- return formatNumber(decimal.multiply(100));
1010
+ return formatNumber(decimal.multiply(100), precision);
917
1011
  } else {
918
- return '--';
1012
+ return '';
919
1013
  }
920
1014
  }
921
1015
 
@@ -933,15 +1027,31 @@ module.exports = (() => {
933
1027
 
934
1028
  let updates = items.reduce((updates, item) => {
935
1029
  updates.basis = updates.basis.add(item.data.basis);
1030
+ updates.realized = updates.realized.add(item.data.realized);
1031
+ updates.income = updates.income.add(item.data.income);
1032
+ updates.summaryOneTotal = updates.summaryOneTotal.add(item.data.summaryOneTotal);
1033
+ updates.summaryTwoTotal = updates.summaryTwoTotal.add(item.data.summaryTwoTotal);
936
1034
 
937
1035
  return updates;
938
1036
  }, {
939
- basis: Decimal.ZERO
1037
+ basis: Decimal.ZERO,
1038
+ realized: Decimal.ZERO,
1039
+ income: Decimal.ZERO,
1040
+ summaryOneTotal: Decimal.ZERO,
1041
+ summaryTwoTotal: Decimal.ZERO
940
1042
  });
941
1043
 
942
1044
  actual.basis = updates.basis;
943
-
944
- format.basis = formatCurrency(updates.basis, currency);
1045
+ actual.realized = updates.realized;
1046
+ actual.income = updates.income;
1047
+ actual.summaryOneTotal = updates.summaryOneTotal;
1048
+ actual.summaryTwoTotal = updates.summaryTwoTotal;
1049
+
1050
+ format.basis = formatCurrency(actual.basis, currency);
1051
+ format.realized = formatCurrency(actual.basis, currency);
1052
+ format.income = formatCurrency(actual.income, currency);
1053
+ format.summaryOneTotal = formatCurrency(updates.summaryOneTotal, currency);
1054
+ format.summaryTwoTotal = formatCurrency(updates.summaryTwoTotal, currency);
945
1055
  }
946
1056
 
947
1057
  function calculatePriceData(group, item) {
@@ -954,7 +1064,12 @@ module.exports = (() => {
954
1064
 
955
1065
  let updates;
956
1066
 
957
- if (actual.market === null || actual.unrealizedToday === null) {
1067
+ if (actual.market !== null && actual.unrealizedToday !== null && actual.total !== null) {
1068
+ updates = {
1069
+ market: actual.market.add(item.data.marketChange),
1070
+ unrealizedToday: actual.unrealizedToday.add(item.data.unrealizedTodayChange)
1071
+ };
1072
+ } else {
958
1073
  const items = group._items;
959
1074
 
960
1075
  updates = items.reduce((updates, item) => {
@@ -966,11 +1081,6 @@ module.exports = (() => {
966
1081
  market: Decimal.ZERO,
967
1082
  unrealizedToday: Decimal.ZERO
968
1083
  });
969
- } else {
970
- updates = {
971
- market: actual.market.add(item.data.marketChange),
972
- unrealizedToday: actual.unrealizedToday.add(item.data.unrealizedTodayChange)
973
- };
974
1084
  }
975
1085
 
976
1086
  if (parent !== null) {
@@ -978,17 +1088,23 @@ module.exports = (() => {
978
1088
 
979
1089
  if (parentData.market !== null && !parentData.market.getIsZero()) {
980
1090
  updates.marketPercent = updates.market.divide(parentData.market);
1091
+ } else {
1092
+ updates.marketPercent = null;
981
1093
  }
1094
+ } else {
1095
+ updates.marketPercent = null;
982
1096
  }
983
-
1097
+
984
1098
  actual.market = updates.market;
985
1099
  actual.marketPercent = updates.marketPercent;
986
1100
  actual.unrealizedToday = updates.unrealizedToday;
1101
+ actual.total = updates.unrealizedToday.add(actual.realized).add(actual.income);
987
1102
 
988
- format.market = formatCurrency(updates.market, currency);
989
- format.marketPercent = formatPercent(updates.unrealizedToday, 2);
990
- format.unrealizedToday = formatCurrency(updates.unrealizedToday, currency);
1103
+ format.market = formatCurrency(actual.market, currency);
1104
+ format.marketPercent = formatPercent(actual.marketPercent, 2);
1105
+ format.unrealizedToday = formatCurrency(actual.unrealizedToday, currency);
991
1106
  format.unrealizedTodayNegative = actual.unrealizedToday.getIsNegative();
1107
+ format.total = formatCurrency(actual.total, currency);
992
1108
  }
993
1109
 
994
1110
  return PositionGroup;
@@ -1073,10 +1189,13 @@ module.exports = (() => {
1073
1189
 
1074
1190
  this._data.market = null;
1075
1191
  this._data.marketChange = null;
1076
-
1192
+
1077
1193
  this._data.unrealizedToday = null;
1078
1194
  this._data.unrealizedTodayChange = null;
1079
1195
 
1196
+ this._data.realized = null;
1197
+ this._data.income = null;
1198
+
1080
1199
  calculateStaticData(this);
1081
1200
  calculatePriceData(this, null);
1082
1201
 
@@ -1121,10 +1240,11 @@ module.exports = (() => {
1121
1240
  function calculateStaticData(item) {
1122
1241
  const position = item.position;
1123
1242
  const snapshot = item.position.snapshot;
1243
+ const summaries = item.summaries;
1124
1244
 
1125
1245
  const data = item._data;
1126
1246
 
1127
- data.previousPrice = position.previousPrice || null;
1247
+ data.previousPrice = position.previous || null;
1128
1248
 
1129
1249
  let basis;
1130
1250
 
@@ -1135,6 +1255,26 @@ module.exports = (() => {
1135
1255
  }
1136
1256
 
1137
1257
  data.basis = basis;
1258
+
1259
+ data.realized = snapshot.gain;
1260
+ data.income = snapshot.income;
1261
+
1262
+ const getSummaryTotal = (index) => {
1263
+ let summaryTotal;
1264
+
1265
+ if (summaries.length > (index + 1) && summaries[index] !== null) {
1266
+ const period = summaries[index].period;
1267
+
1268
+ summaryTotal = period.realized.add(period.unrealized).add(period.income);
1269
+ } else {
1270
+ summaryTotal = Decimal.ZERO;
1271
+ }
1272
+
1273
+ return summaryTotal;
1274
+ };
1275
+
1276
+ data.summaryOneTotal = getSummaryTotal(0);
1277
+ data.summaryTwoTotal = getSummaryTotal(1);
1138
1278
  }
1139
1279
 
1140
1280
  function calculatePriceData(item, price) {
@@ -5601,7 +5741,9 @@ describe('When a position container data is gathered', () => {
5601
5741
  snapshot: {
5602
5742
  basis: new Decimal(123),
5603
5743
  value: new Decimal(456),
5604
- open: new Decimal(1)
5744
+ open: new Decimal(1),
5745
+ income: new Decimal(0),
5746
+ gain: new Decimal(0)
5605
5747
  }
5606
5748
  }
5607
5749
  }
@@ -25,7 +25,9 @@ describe('When a position container data is gathered', () => {
25
25
  snapshot: {
26
26
  basis: new Decimal(123),
27
27
  value: new Decimal(456),
28
- open: new Decimal(1)
28
+ open: new Decimal(1),
29
+ income: new Decimal(0),
30
+ gain: new Decimal(0)
29
31
  }
30
32
  }
31
33
  }