@barchart/portfolio-api-common 1.0.65 → 1.0.69

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,8 @@ 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 InstrumentType = require('./../data/InstrumentType'),
10
+ PositionSummaryFrame = require('./../data/PositionSummaryFrame');
10
11
 
11
12
  const PositionGroup = require('./PositionGroup'),
12
13
  PositionItem = require('./PositionItem');
@@ -18,10 +19,13 @@ module.exports = (() => {
18
19
  * @public
19
20
  */
20
21
  class PositionContainer {
21
- constructor(portfolios, positions, summaries, definitions, defaultCurrency) {
22
+ constructor(portfolios, positions, summaries, definitions, defaultCurrency, summaryFrameType) {
22
23
  this._definitions = definitions;
23
24
  this._defaultCurrency = defaultCurrency || Currency.CAD;
24
25
 
26
+ this._summaryFrame = summaryFrameType || PositionSummaryFrame.YEARLY;
27
+ this._summaryRanges = this._summaryFrame.getRecentRanges(2);
28
+
25
29
  this._portfolios = portfolios.reduce((map, portfolio) => {
26
30
  map[portfolio.portfolio] = portfolio;
27
31
 
@@ -29,13 +33,19 @@ module.exports = (() => {
29
33
  }, { });
30
34
 
31
35
  this._summaries = summaries.reduce((map, summary) => {
32
- const key = summary.position;
36
+ if (this._summaryFrame === summary.frame) {
37
+ const key = summary.position;
33
38
 
34
- if (!map.hasOwnProperty(key)) {
35
- map[key] = [ ];
36
- }
39
+ if (!map.hasOwnProperty(key)) {
40
+ map[key] = getSummaryArray(this._summaryRanges);
41
+ }
42
+
43
+ const index = this._summaryRanges.findIndex(r => r.start === summary.start.date && r.end === summary.end.date);
37
44
 
38
- map[key].push(summary);
45
+ if (!(index < 0)) {
46
+ map[key][index] = summary;
47
+ }
48
+ }
39
49
 
40
50
  return map;
41
51
  }, { });
@@ -44,7 +54,7 @@ module.exports = (() => {
44
54
  const portfolio = this._portfolios[position.portfolio];
45
55
 
46
56
  if (position) {
47
- const summaries = this._summaries[position.position] || [ ];
57
+ const summaries = this._summaries[position.position] || getSummaryArray(this._summaryRanges);
48
58
 
49
59
  items.push(new PositionItem(portfolio, position, summaries));
50
60
  }
@@ -206,5 +216,9 @@ module.exports = (() => {
206
216
  }
207
217
  }
208
218
 
219
+ function getSummaryArray(ranges) {
220
+ return ranges.map(range => null);
221
+ }
222
+
209
223
  return PositionContainer;
210
224
  })();
@@ -25,22 +25,32 @@ 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
- this._dataFormat.unrealizedTodayPositive = true;
53
+ this._dataFormat.unrealizedTodayNegative = false;
44
54
 
45
55
  this._items.forEach((item) => {
46
56
  item.registerPriceChangeHandler((data, sender) => {
@@ -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);
173
- format.unrealizedTodayPositive = actual.unrealizedToday.getIsPositive();
201
+ format.market = formatCurrency(actual.market, currency);
202
+ format.marketPercent = formatPercent(actual.marketPercent, 2);
203
+ format.unrealizedToday = formatCurrency(actual.unrealizedToday, currency);
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.65",
3
+ "version": "1.0.69",
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,8 @@ 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 InstrumentType = require('./../data/InstrumentType'),
687
+ PositionSummaryFrame = require('./../data/PositionSummaryFrame');
616
688
 
617
689
  const PositionGroup = require('./PositionGroup'),
618
690
  PositionItem = require('./PositionItem');
@@ -624,10 +696,13 @@ module.exports = (() => {
624
696
  * @public
625
697
  */
626
698
  class PositionContainer {
627
- constructor(portfolios, positions, summaries, definitions, defaultCurrency) {
699
+ constructor(portfolios, positions, summaries, definitions, defaultCurrency, summaryFrameType) {
628
700
  this._definitions = definitions;
629
701
  this._defaultCurrency = defaultCurrency || Currency.CAD;
630
702
 
703
+ this._summaryFrame = summaryFrameType || PositionSummaryFrame.YEARLY;
704
+ this._summaryRanges = this._summaryFrame.getRecentRanges(2);
705
+
631
706
  this._portfolios = portfolios.reduce((map, portfolio) => {
632
707
  map[portfolio.portfolio] = portfolio;
633
708
 
@@ -635,13 +710,19 @@ module.exports = (() => {
635
710
  }, { });
636
711
 
637
712
  this._summaries = summaries.reduce((map, summary) => {
638
- const key = summary.position;
713
+ if (this._summaryFrame === summary.frame) {
714
+ const key = summary.position;
639
715
 
640
- if (!map.hasOwnProperty(key)) {
641
- map[key] = [ ];
642
- }
716
+ if (!map.hasOwnProperty(key)) {
717
+ map[key] = getSummaryArray(this._summaryRanges);
718
+ }
719
+
720
+ const index = this._summaryRanges.findIndex(r => r.start === summary.start.date && r.end === summary.end.date);
643
721
 
644
- map[key].push(summary);
722
+ if (!(index < 0)) {
723
+ map[key][index] = summary;
724
+ }
725
+ }
645
726
 
646
727
  return map;
647
728
  }, { });
@@ -650,7 +731,7 @@ module.exports = (() => {
650
731
  const portfolio = this._portfolios[position.portfolio];
651
732
 
652
733
  if (position) {
653
- const summaries = this._summaries[position.position] || [ ];
734
+ const summaries = this._summaries[position.position] || getSummaryArray(this._summaryRanges);
654
735
 
655
736
  items.push(new PositionItem(portfolio, position, summaries));
656
737
  }
@@ -812,10 +893,14 @@ module.exports = (() => {
812
893
  }
813
894
  }
814
895
 
896
+ function getSummaryArray(ranges) {
897
+ return ranges.map(range => null);
898
+ }
899
+
815
900
  return PositionContainer;
816
901
  })();
817
902
 
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){
903
+ },{"./../data/InstrumentType":1,"./../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
904
  const assert = require('@barchart/common-js/lang/assert'),
820
905
  Currency = require('@barchart/common-js/lang/Currency'),
821
906
  Decimal = require('@barchart/common-js/lang/Decimal'),
@@ -843,22 +928,32 @@ module.exports = (() => {
843
928
  this._dataActual = { };
844
929
 
845
930
  this._dataFormat.description = this._description;
846
-
931
+
847
932
  this._dataActual.currentPrice = null;
848
933
  this._dataActual.previousPrice = null;
849
934
  this._dataActual.basis = null;
935
+ this._dataActual.realized = null;
936
+ this._dataActual.income = null;
850
937
  this._dataActual.market = null;
851
938
  this._dataActual.marketPercent = null;
852
939
  this._dataActual.unrealizedToday = null;
940
+ this._dataActual.total = null;
941
+ this._dataActual.summaryOneTotal = null;
942
+ this._dataActual.summaryTwoTotal = null;
853
943
 
854
944
  this._dataFormat.currentPrice = null;
855
945
  this._dataFormat.previousPrice = null;
856
946
  this._dataFormat.basis = null;
947
+ this._dataFormat.realized = null;
948
+ this._dataFormat.income = null;
857
949
  this._dataFormat.market = null;
858
950
  this._dataFormat.marketPercent = null;
859
951
  this._dataFormat.unrealizedToday = null;
952
+ this._dataFormat.total = null;
953
+ this._dataFormat.summaryOneTotal = null;
954
+ this._dataFormat.summaryTwoTotal = null;
860
955
 
861
- this._dataFormat.unrealizedTodayPositive = true;
956
+ this._dataFormat.unrealizedTodayNegative = false;
862
957
 
863
958
  this._items.forEach((item) => {
864
959
  item.registerPriceChangeHandler((data, sender) => {
@@ -907,15 +1002,15 @@ module.exports = (() => {
907
1002
  if (decimal !== null) {
908
1003
  return formatter.numberToString(decimal.toFloat(), precision, ',', false);
909
1004
  } else {
910
- return '--';
1005
+ return '';
911
1006
  }
912
1007
  }
913
1008
 
914
1009
  function formatPercent(decimal, precision) {
915
1010
  if (decimal !== null) {
916
- return formatNumber(decimal.multiply(100));
1011
+ return formatNumber(decimal.multiply(100), precision);
917
1012
  } else {
918
- return '--';
1013
+ return '';
919
1014
  }
920
1015
  }
921
1016
 
@@ -933,15 +1028,31 @@ module.exports = (() => {
933
1028
 
934
1029
  let updates = items.reduce((updates, item) => {
935
1030
  updates.basis = updates.basis.add(item.data.basis);
1031
+ updates.realized = updates.realized.add(item.data.realized);
1032
+ updates.income = updates.income.add(item.data.income);
1033
+ updates.summaryOneTotal = updates.summaryOneTotal.add(item.data.summaryOneTotal);
1034
+ updates.summaryTwoTotal = updates.summaryTwoTotal.add(item.data.summaryTwoTotal);
936
1035
 
937
1036
  return updates;
938
1037
  }, {
939
- basis: Decimal.ZERO
1038
+ basis: Decimal.ZERO,
1039
+ realized: Decimal.ZERO,
1040
+ income: Decimal.ZERO,
1041
+ summaryOneTotal: Decimal.ZERO,
1042
+ summaryTwoTotal: Decimal.ZERO
940
1043
  });
941
1044
 
942
1045
  actual.basis = updates.basis;
943
-
944
- format.basis = formatCurrency(updates.basis, currency);
1046
+ actual.realized = updates.realized;
1047
+ actual.income = updates.income;
1048
+ actual.summaryOneTotal = updates.summaryOneTotal;
1049
+ actual.summaryTwoTotal = updates.summaryTwoTotal;
1050
+
1051
+ format.basis = formatCurrency(actual.basis, currency);
1052
+ format.realized = formatCurrency(actual.basis, currency);
1053
+ format.income = formatCurrency(actual.income, currency);
1054
+ format.summaryOneTotal = formatCurrency(updates.summaryOneTotal, currency);
1055
+ format.summaryTwoTotal = formatCurrency(updates.summaryTwoTotal, currency);
945
1056
  }
946
1057
 
947
1058
  function calculatePriceData(group, item) {
@@ -954,7 +1065,12 @@ module.exports = (() => {
954
1065
 
955
1066
  let updates;
956
1067
 
957
- if (actual.market === null || actual.unrealizedToday === null) {
1068
+ if (actual.market !== null && actual.unrealizedToday !== null && actual.total !== null) {
1069
+ updates = {
1070
+ market: actual.market.add(item.data.marketChange),
1071
+ unrealizedToday: actual.unrealizedToday.add(item.data.unrealizedTodayChange)
1072
+ };
1073
+ } else {
958
1074
  const items = group._items;
959
1075
 
960
1076
  updates = items.reduce((updates, item) => {
@@ -966,11 +1082,6 @@ module.exports = (() => {
966
1082
  market: Decimal.ZERO,
967
1083
  unrealizedToday: Decimal.ZERO
968
1084
  });
969
- } else {
970
- updates = {
971
- market: actual.market.add(item.data.marketChange),
972
- unrealizedToday: actual.unrealizedToday.add(item.data.unrealizedTodayChange)
973
- };
974
1085
  }
975
1086
 
976
1087
  if (parent !== null) {
@@ -978,17 +1089,23 @@ module.exports = (() => {
978
1089
 
979
1090
  if (parentData.market !== null && !parentData.market.getIsZero()) {
980
1091
  updates.marketPercent = updates.market.divide(parentData.market);
1092
+ } else {
1093
+ updates.marketPercent = null;
981
1094
  }
1095
+ } else {
1096
+ updates.marketPercent = null;
982
1097
  }
983
-
1098
+
984
1099
  actual.market = updates.market;
985
1100
  actual.marketPercent = updates.marketPercent;
986
1101
  actual.unrealizedToday = updates.unrealizedToday;
1102
+ actual.total = updates.unrealizedToday.add(actual.realized).add(actual.income);
987
1103
 
988
- format.market = formatCurrency(updates.market, currency);
989
- format.marketPercent = formatPercent(updates.unrealizedToday, 2);
990
- format.unrealizedToday = formatCurrency(updates.unrealizedToday, currency);
991
- format.unrealizedTodayPositive = actual.unrealizedToday.getIsPositive();
1104
+ format.market = formatCurrency(actual.market, currency);
1105
+ format.marketPercent = formatPercent(actual.marketPercent, 2);
1106
+ format.unrealizedToday = formatCurrency(actual.unrealizedToday, currency);
1107
+ format.unrealizedTodayNegative = actual.unrealizedToday.getIsNegative();
1108
+ format.total = formatCurrency(actual.total, currency);
992
1109
  }
993
1110
 
994
1111
  return PositionGroup;
@@ -1073,10 +1190,13 @@ module.exports = (() => {
1073
1190
 
1074
1191
  this._data.market = null;
1075
1192
  this._data.marketChange = null;
1076
-
1193
+
1077
1194
  this._data.unrealizedToday = null;
1078
1195
  this._data.unrealizedTodayChange = null;
1079
1196
 
1197
+ this._data.realized = null;
1198
+ this._data.income = null;
1199
+
1080
1200
  calculateStaticData(this);
1081
1201
  calculatePriceData(this, null);
1082
1202
 
@@ -1121,10 +1241,11 @@ module.exports = (() => {
1121
1241
  function calculateStaticData(item) {
1122
1242
  const position = item.position;
1123
1243
  const snapshot = item.position.snapshot;
1244
+ const summaries = item.summaries;
1124
1245
 
1125
1246
  const data = item._data;
1126
1247
 
1127
- data.previousPrice = position.previousPrice || null;
1248
+ data.previousPrice = position.previous || null;
1128
1249
 
1129
1250
  let basis;
1130
1251
 
@@ -1135,6 +1256,26 @@ module.exports = (() => {
1135
1256
  }
1136
1257
 
1137
1258
  data.basis = basis;
1259
+
1260
+ data.realized = snapshot.gain;
1261
+ data.income = snapshot.income;
1262
+
1263
+ const getSummaryTotal = (index) => {
1264
+ let summaryTotal;
1265
+
1266
+ if (summaries.length > (index + 1) && summaries[index] !== null) {
1267
+ const period = summaries[index].period;
1268
+
1269
+ summaryTotal = period.realized.add(period.unrealized).add(period.income);
1270
+ } else {
1271
+ summaryTotal = Decimal.ZERO;
1272
+ }
1273
+
1274
+ return summaryTotal;
1275
+ };
1276
+
1277
+ data.summaryOneTotal = getSummaryTotal(0);
1278
+ data.summaryTwoTotal = getSummaryTotal(1);
1138
1279
  }
1139
1280
 
1140
1281
  function calculatePriceData(item, price) {
@@ -5601,7 +5742,9 @@ describe('When a position container data is gathered', () => {
5601
5742
  snapshot: {
5602
5743
  basis: new Decimal(123),
5603
5744
  value: new Decimal(456),
5604
- open: new Decimal(1)
5745
+ open: new Decimal(1),
5746
+ income: new Decimal(0),
5747
+ gain: new Decimal(0)
5605
5748
  }
5606
5749
  }
5607
5750
  }
@@ -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
  }