@barchart/portfolio-api-common 1.0.85 → 1.0.90
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.
- package/lib/data/PositionSummaryFrame.js +11 -10
- package/lib/data/TransactionType.js +35 -22
- package/lib/formatters/TransactionFormatter.js +4 -3
- package/lib/processing/PositionContainer.js +48 -19
- package/lib/processing/PositionGroup.js +57 -16
- package/lib/processing/PositionItem.js +32 -22
- package/package.json +1 -1
- package/test/SpecRunner.js +184 -90
- package/test/specs/processing/PositionContainerSpec.js +2 -2
|
@@ -37,12 +37,13 @@ module.exports = (() => {
|
|
|
37
37
|
* start and end dates.
|
|
38
38
|
*
|
|
39
39
|
* @public
|
|
40
|
-
* @
|
|
41
|
-
* @param {Day} endDate
|
|
40
|
+
* @return {PositionSummaryRange} range
|
|
42
41
|
* @return {String}
|
|
43
42
|
*/
|
|
44
|
-
describeRange(
|
|
45
|
-
|
|
43
|
+
describeRange(range) {
|
|
44
|
+
console.log('range: ', range);
|
|
45
|
+
|
|
46
|
+
return this._descriptionCalculator(range.start, range.end);
|
|
46
47
|
}
|
|
47
48
|
|
|
48
49
|
/**
|
|
@@ -226,20 +227,20 @@ module.exports = (() => {
|
|
|
226
227
|
return null;
|
|
227
228
|
}
|
|
228
229
|
|
|
229
|
-
function getYearlyRangeDescription(
|
|
230
|
-
return
|
|
230
|
+
function getYearlyRangeDescription(start, end) {
|
|
231
|
+
return end.year.toString();
|
|
231
232
|
}
|
|
232
233
|
|
|
233
|
-
function getQuarterlyRangeDescription(
|
|
234
|
+
function getQuarterlyRangeDescription(start, end) {
|
|
234
235
|
return '';
|
|
235
236
|
}
|
|
236
237
|
|
|
237
|
-
function getMonthlyRangeDescription(
|
|
238
|
+
function getMonthlyRangeDescription(start, end) {
|
|
238
239
|
return '';
|
|
239
240
|
}
|
|
240
241
|
|
|
241
|
-
function getYearToDateRangeDescription(
|
|
242
|
-
return `${
|
|
242
|
+
function getYearToDateRangeDescription(start, end) {
|
|
243
|
+
return `${end.year.toString()} YTD`;
|
|
243
244
|
}
|
|
244
245
|
|
|
245
246
|
function getFilteredTransactions(transactions) {
|
|
@@ -11,6 +11,7 @@ module.exports = (() => {
|
|
|
11
11
|
* @extends {Enum}
|
|
12
12
|
* @param {String} code
|
|
13
13
|
* @param {String} description
|
|
14
|
+
* @param {String} display
|
|
14
15
|
* @param {Boolean} purchase
|
|
15
16
|
* @param {Boolean} sale
|
|
16
17
|
* @param {Boolean} income
|
|
@@ -18,15 +19,17 @@ module.exports = (() => {
|
|
|
18
19
|
* @param {Boolean} closing
|
|
19
20
|
*/
|
|
20
21
|
class TransactionType extends Enum {
|
|
21
|
-
constructor(code, description, purchase, sale, income, opening, closing) {
|
|
22
|
+
constructor(code, description, display, purchase, sale, income, opening, closing) {
|
|
22
23
|
super(code, description);
|
|
23
24
|
|
|
25
|
+
assert.argumentIsRequired(display, 'display', String);
|
|
24
26
|
assert.argumentIsRequired(purchase, 'purchase', Boolean);
|
|
25
27
|
assert.argumentIsRequired(sale, 'sale', Boolean);
|
|
26
28
|
assert.argumentIsRequired(income, 'income', Boolean);
|
|
27
29
|
assert.argumentIsRequired(opening, 'opening', Boolean);
|
|
28
30
|
assert.argumentIsRequired(closing, 'closing', Boolean);
|
|
29
31
|
|
|
32
|
+
this._display = display;
|
|
30
33
|
this._purchase = purchase;
|
|
31
34
|
this._sale = sale;
|
|
32
35
|
this._income = income;
|
|
@@ -34,6 +37,16 @@ module.exports = (() => {
|
|
|
34
37
|
this._closing = closing;
|
|
35
38
|
}
|
|
36
39
|
|
|
40
|
+
/**
|
|
41
|
+
* A human-readable description of the transaction type.
|
|
42
|
+
*
|
|
43
|
+
* @public
|
|
44
|
+
* @returns {String}
|
|
45
|
+
*/
|
|
46
|
+
get display() {
|
|
47
|
+
return this._display;
|
|
48
|
+
}
|
|
49
|
+
|
|
37
50
|
/**
|
|
38
51
|
* Indicates if the transaction was a trade.
|
|
39
52
|
*
|
|
@@ -299,27 +312,27 @@ module.exports = (() => {
|
|
|
299
312
|
}
|
|
300
313
|
}
|
|
301
314
|
|
|
302
|
-
const buy = new TransactionType('B', 'Buy', true, false, false, true, false);
|
|
303
|
-
const sell = new TransactionType('S', 'Sell', false, true, false, false, true);
|
|
304
|
-
const buyShort = new TransactionType('BS', 'Buy To Cover', true, false, false, false, true);
|
|
305
|
-
const sellShort = new TransactionType('SS', 'Sell Short',
|
|
306
|
-
const dividend = new TransactionType('DV', 'Dividend', false, false, true, false, false);
|
|
307
|
-
const dividendReinvest = new TransactionType('DX', 'Dividend (Reinvested)', false, false, false, true, false);
|
|
308
|
-
const dividendStock = new TransactionType('DS', 'Dividend (Stock)', false, false, false, true, false);
|
|
309
|
-
const split = new TransactionType('SP', 'Split', false, false, false, true, false);
|
|
310
|
-
const fee = new TransactionType('F', 'Fee', false, false, false, true, false);
|
|
311
|
-
const feeUnits = new TransactionType('FU', 'Fee', false, false, false, false, false);
|
|
312
|
-
|
|
313
|
-
const distributionCash = new TransactionType('DC', 'Distribution (Cash)', false, false, true, false, false);
|
|
314
|
-
const distributionFund = new TransactionType('DF', 'Distribution (Units)', false, false, false, true, false);
|
|
315
|
-
|
|
316
|
-
const deposit = new TransactionType('D', 'Deposit', false, false, false, true, false);
|
|
317
|
-
const withdrawal = new TransactionType('W', 'Withdrawal', false, false, false, false, true);
|
|
318
|
-
const debit = new TransactionType('DR', 'Debit', false, false, false, false, true);
|
|
319
|
-
const credit = new TransactionType('CR', 'Credit', false, false, false, true, false);
|
|
320
|
-
|
|
321
|
-
const valuation = new TransactionType('V', 'Valuation', false, false, false, false, false);
|
|
322
|
-
const income = new TransactionType('I', 'Income', false, false, true, false, false);
|
|
315
|
+
const buy = new TransactionType('B', 'Buy', 'Buy', true, false, false, true, false);
|
|
316
|
+
const sell = new TransactionType('S', 'Sell', 'Sell', false, true, false, false, true);
|
|
317
|
+
const buyShort = new TransactionType('BS', 'Buy To Cover', 'Buy To Cover', true, false, false, false, true);
|
|
318
|
+
const sellShort = new TransactionType('SS', 'Sell Short', 'Sell Short', false, true, false, true, false);
|
|
319
|
+
const dividend = new TransactionType('DV', 'Dividend', 'Dividend', false, false, true, false, false);
|
|
320
|
+
const dividendReinvest = new TransactionType('DX', 'Dividend (Reinvested)', 'Dividend Reinvest', false, false, false, true, false);
|
|
321
|
+
const dividendStock = new TransactionType('DS', 'Dividend (Stock)', 'Dividend Stock', false, false, false, true, false);
|
|
322
|
+
const split = new TransactionType('SP', 'Split', 'Split', false, false, false, true, false);
|
|
323
|
+
const fee = new TransactionType('F', 'Fee', 'Fee', false, false, false, true, false);
|
|
324
|
+
const feeUnits = new TransactionType('FU', 'Fee Units', 'Fee', false, false, false, false, false);
|
|
325
|
+
|
|
326
|
+
const distributionCash = new TransactionType('DC', 'Distribution (Cash)', 'Cash Distribution', false, false, true, false, false);
|
|
327
|
+
const distributionFund = new TransactionType('DF', 'Distribution (Units)', 'Unit Distribution', false, false, false, true, false);
|
|
328
|
+
|
|
329
|
+
const deposit = new TransactionType('D', 'Deposit', 'Deposit', false, false, false, true, false);
|
|
330
|
+
const withdrawal = new TransactionType('W', 'Withdrawal', 'Withdrawal', false, false, false, false, true);
|
|
331
|
+
const debit = new TransactionType('DR', 'Debit', 'Debit', false, false, false, false, true);
|
|
332
|
+
const credit = new TransactionType('CR', 'Credit', 'Credit', false, false, false, true, false);
|
|
333
|
+
|
|
334
|
+
const valuation = new TransactionType('V', 'Valuation', 'Valuation', false, false, false, false, false);
|
|
335
|
+
const income = new TransactionType('I', 'Income', 'Income', false, false, true, false, false);
|
|
323
336
|
|
|
324
337
|
return TransactionType;
|
|
325
338
|
})();
|
|
@@ -35,9 +35,9 @@ module.exports = (() => {
|
|
|
35
35
|
|
|
36
36
|
const positionMap = {};
|
|
37
37
|
|
|
38
|
-
positions.map(
|
|
38
|
+
positions.map(p => positionMap[p.position] = p.instrument);
|
|
39
39
|
|
|
40
|
-
return transactions.filter(
|
|
40
|
+
return transactions.filter(t => positionMap[t.position]).map((transaction) => {
|
|
41
41
|
transaction.instrument = positionMap[transaction.position];
|
|
42
42
|
|
|
43
43
|
let formatted = getBasicTransaction(transaction);
|
|
@@ -76,7 +76,7 @@ module.exports = (() => {
|
|
|
76
76
|
const getBasicTransaction = (t) => {
|
|
77
77
|
const basic = {
|
|
78
78
|
date: t.date,
|
|
79
|
-
type: t.type,
|
|
79
|
+
type: t.type.display,
|
|
80
80
|
sequence: t.sequence,
|
|
81
81
|
instrument: t.instrument
|
|
82
82
|
};
|
|
@@ -98,6 +98,7 @@ module.exports = (() => {
|
|
|
98
98
|
total: t.amount
|
|
99
99
|
};
|
|
100
100
|
};
|
|
101
|
+
|
|
101
102
|
formatters.set(TransactionType.BUY, buySellFormatter);
|
|
102
103
|
formatters.set(TransactionType.SELL, buySellFormatter);
|
|
103
104
|
formatters.set(TransactionType.BUY_SHORT, buySellFormatter);
|
|
@@ -18,12 +18,18 @@ 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, summaryFrame) {
|
|
22
22
|
this._definitions = definitions;
|
|
23
23
|
this._defaultCurrency = defaultCurrency || Currency.CAD;
|
|
24
|
+
|
|
25
|
+
const previousSummaryFrame = summaryFrame || PositionSummaryFrame.YEARLY;
|
|
26
|
+
const previousSummaryRanges = previousSummaryFrame.getRecentRanges(0);
|
|
24
27
|
|
|
25
|
-
|
|
26
|
-
|
|
28
|
+
const currentSummaryFrame = PositionSummaryFrame.YTD;
|
|
29
|
+
const currentSummaryRange = array.last(currentSummaryFrame.getRecentRanges(0));
|
|
30
|
+
|
|
31
|
+
this._summaryDescriptionCurrent = previousSummaryFrame.describeRange(array.last(previousSummaryRanges));
|
|
32
|
+
this._summaryDescriptionPrevious = currentSummaryFrame.describeRange(currentSummaryRange);
|
|
27
33
|
|
|
28
34
|
this._portfolios = portfolios.reduce((map, portfolio) => {
|
|
29
35
|
map[portfolio.portfolio] = portfolio;
|
|
@@ -31,15 +37,25 @@ module.exports = (() => {
|
|
|
31
37
|
return map;
|
|
32
38
|
}, { });
|
|
33
39
|
|
|
34
|
-
this.
|
|
35
|
-
if (
|
|
40
|
+
this._summariesCurrent = summaries.reduce((map, summary) => {
|
|
41
|
+
if (summary.frame === currentSummaryFrame && currentSummaryRange.start.getIsEqual(summary.start.date) && currentSummaryRange.end.getIsEqual(summary.end.date)) {
|
|
42
|
+
const key = summary.position;
|
|
43
|
+
|
|
44
|
+
map[key] = summary;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
return map;
|
|
48
|
+
}, { });
|
|
49
|
+
|
|
50
|
+
this._summariesPrevious = summaries.reduce((map, summary) => {
|
|
51
|
+
if (summary.frame === previousSummaryFrame) {
|
|
36
52
|
const key = summary.position;
|
|
37
53
|
|
|
38
54
|
if (!map.hasOwnProperty(key)) {
|
|
39
|
-
map[key] = getSummaryArray(
|
|
55
|
+
map[key] = getSummaryArray(previousSummaryRanges);
|
|
40
56
|
}
|
|
41
57
|
|
|
42
|
-
const index =
|
|
58
|
+
const index = previousSummaryRanges.findIndex(r => r.start.getIsEqual(summary.start.date) && r.end.getIsEqual(summary.end.date));
|
|
43
59
|
|
|
44
60
|
if (!(index < 0)) {
|
|
45
61
|
map[key][index] = summary;
|
|
@@ -53,9 +69,10 @@ module.exports = (() => {
|
|
|
53
69
|
const portfolio = this._portfolios[position.portfolio];
|
|
54
70
|
|
|
55
71
|
if (position) {
|
|
56
|
-
const
|
|
72
|
+
const currentSummary = this._summariesCurrent[position.position] || null;
|
|
73
|
+
const previousSummaries = this._summariesPrevious[position.position] || getSummaryArray(previousSummaryRanges);
|
|
57
74
|
|
|
58
|
-
items.push(new PositionItem(portfolio, position,
|
|
75
|
+
items.push(new PositionItem(portfolio, position, currentSummary, previousSummaries));
|
|
59
76
|
}
|
|
60
77
|
|
|
61
78
|
return items;
|
|
@@ -153,6 +170,10 @@ module.exports = (() => {
|
|
|
153
170
|
compositeGroups.forEach((group) => {
|
|
154
171
|
const child = tree.addChild(group);
|
|
155
172
|
|
|
173
|
+
group.registerMarketPercentChangeHandler(() => {
|
|
174
|
+
this._tree.walk((childGroup) => childGroup.refreshMarketPercent());
|
|
175
|
+
});
|
|
176
|
+
|
|
156
177
|
createGroups(child, group.items, additionalDefinitions);
|
|
157
178
|
});
|
|
158
179
|
};
|
|
@@ -163,7 +184,25 @@ module.exports = (() => {
|
|
|
163
184
|
get defaultCurrency() {
|
|
164
185
|
return this._defaultCurrency;
|
|
165
186
|
}
|
|
187
|
+
|
|
188
|
+
getCurrentSummaryDescription() {
|
|
189
|
+
return this._summaryDescriptionCurrent;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
getPreviousSummaryDescription() {
|
|
193
|
+
return this._summaryDescriptionPrevious;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
startTransaction(executor) {
|
|
197
|
+
assert.argumentIsRequired(executor, 'executor', Function);
|
|
198
|
+
|
|
199
|
+
this._tree.walk(group => group.setSuspended(true), false, false);
|
|
200
|
+
|
|
201
|
+
executor(this);
|
|
166
202
|
|
|
203
|
+
this._tree.walk(group => group.setSuspended(false), false, false);
|
|
204
|
+
}
|
|
205
|
+
|
|
167
206
|
getSymbols() {
|
|
168
207
|
return Object.keys(this._symbols);
|
|
169
208
|
}
|
|
@@ -190,16 +229,6 @@ module.exports = (() => {
|
|
|
190
229
|
|
|
191
230
|
}
|
|
192
231
|
|
|
193
|
-
startTransaction(executor) {
|
|
194
|
-
assert.argumentIsRequired(executor, 'executor', Function);
|
|
195
|
-
|
|
196
|
-
this._tree.walk(group => group.setSuspended(true), false, false);
|
|
197
|
-
|
|
198
|
-
executor(this);
|
|
199
|
-
|
|
200
|
-
this._tree.walk(group => group.setSuspended(false), false, false);
|
|
201
|
-
}
|
|
202
|
-
|
|
203
232
|
getGroup(keys) {
|
|
204
233
|
const node = keys.reduce((tree, key) => {
|
|
205
234
|
tree = tree.findChild(group => group.description === key);
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
const assert = require('@barchart/common-js/lang/assert'),
|
|
2
2
|
Currency = require('@barchart/common-js/lang/Currency'),
|
|
3
3
|
Decimal = require('@barchart/common-js/lang/Decimal'),
|
|
4
|
+
Event = require('@barchart/common-js/messaging/Event'),
|
|
4
5
|
formatter = require('@barchart/common-js/lang/formatter'),
|
|
5
6
|
is = require('@barchart/common-js/lang/is');
|
|
6
7
|
|
|
@@ -25,6 +26,8 @@ module.exports = (() => {
|
|
|
25
26
|
this._excluded = false;
|
|
26
27
|
this._suspended = false;
|
|
27
28
|
|
|
29
|
+
this._marketPercentChangeEvent = new Event(this);
|
|
30
|
+
|
|
28
31
|
this._dataFormat = { };
|
|
29
32
|
this._dataActual = { };
|
|
30
33
|
|
|
@@ -39,8 +42,8 @@ module.exports = (() => {
|
|
|
39
42
|
this._dataActual.marketPercent = null;
|
|
40
43
|
this._dataActual.unrealizedToday = null;
|
|
41
44
|
this._dataActual.total = null;
|
|
42
|
-
this._dataActual.
|
|
43
|
-
this._dataActual.
|
|
45
|
+
this._dataActual.summaryTotalCurrent = null;
|
|
46
|
+
this._dataActual.summaryTotalPrevious = null;
|
|
44
47
|
|
|
45
48
|
this._dataFormat.currentPrice = null;
|
|
46
49
|
this._dataFormat.previousPrice = null;
|
|
@@ -54,8 +57,8 @@ module.exports = (() => {
|
|
|
54
57
|
this._dataFormat.unrealizedTodayNegative = false;
|
|
55
58
|
this._dataFormat.total = null;
|
|
56
59
|
this._dataFormat.totalNegative = false;
|
|
57
|
-
this._dataFormat.
|
|
58
|
-
this._dataFormat.
|
|
60
|
+
this._dataFormat.summaryTotalCurrent = null;
|
|
61
|
+
this._dataFormat.summaryTotalPrevious = null;
|
|
59
62
|
|
|
60
63
|
this._dataFormat.unrealizedTodayNegative = false;
|
|
61
64
|
|
|
@@ -135,6 +138,14 @@ module.exports = (() => {
|
|
|
135
138
|
calculatePriceData(this, null, true);
|
|
136
139
|
}
|
|
137
140
|
|
|
141
|
+
refreshMarketPercent() {
|
|
142
|
+
calculateMarketPercent(this, true);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
registerMarketPercentChangeHandler(handler) {
|
|
146
|
+
this._marketPercentChangeEvent.register(handler);
|
|
147
|
+
}
|
|
148
|
+
|
|
138
149
|
toString() {
|
|
139
150
|
return '[PositionGroup]';
|
|
140
151
|
}
|
|
@@ -176,29 +187,29 @@ module.exports = (() => {
|
|
|
176
187
|
updates.basis = updates.basis.add(item.data.basis);
|
|
177
188
|
updates.realized = updates.realized.add(item.data.realized);
|
|
178
189
|
updates.income = updates.income.add(item.data.income);
|
|
179
|
-
updates.
|
|
180
|
-
updates.
|
|
190
|
+
updates.summaryTotalCurrent = updates.summaryTotalCurrent.add(item.data.summaryTotalCurrent);
|
|
191
|
+
updates.summaryTotalPrevious = updates.summaryTotalPrevious.add(item.data.summaryTotalPrevious);
|
|
181
192
|
|
|
182
193
|
return updates;
|
|
183
194
|
}, {
|
|
184
195
|
basis: Decimal.ZERO,
|
|
185
196
|
realized: Decimal.ZERO,
|
|
186
197
|
income: Decimal.ZERO,
|
|
187
|
-
|
|
188
|
-
|
|
198
|
+
summaryTotalCurrent: Decimal.ZERO,
|
|
199
|
+
summaryTotalPrevious: Decimal.ZERO
|
|
189
200
|
});
|
|
190
201
|
|
|
191
202
|
actual.basis = updates.basis;
|
|
192
203
|
actual.realized = updates.realized;
|
|
193
204
|
actual.income = updates.income;
|
|
194
|
-
actual.
|
|
195
|
-
actual.
|
|
205
|
+
actual.summaryTotalCurrent = updates.summaryTotalCurrent;
|
|
206
|
+
actual.summaryTotalPrevious = updates.summaryTotalPrevious;
|
|
196
207
|
|
|
197
208
|
format.basis = formatCurrency(actual.basis, currency);
|
|
198
209
|
format.realized = formatCurrency(actual.basis, currency);
|
|
199
210
|
format.income = formatCurrency(actual.income, currency);
|
|
200
|
-
format.
|
|
201
|
-
format.
|
|
211
|
+
format.summaryTotalCurrent = formatCurrency(updates.summaryTotalCurrent, currency);
|
|
212
|
+
format.summaryTotalPrevious = formatCurrency(updates.summaryTotalPrevious, currency);
|
|
202
213
|
}
|
|
203
214
|
|
|
204
215
|
function calculatePriceData(group, item, forceRefresh) {
|
|
@@ -252,12 +263,11 @@ module.exports = (() => {
|
|
|
252
263
|
}
|
|
253
264
|
|
|
254
265
|
actual.market = updates.market;
|
|
255
|
-
actual.marketPercent = updates.marketPercent;
|
|
256
266
|
actual.unrealizedToday = updates.unrealizedToday;
|
|
257
267
|
actual.total = updates.unrealizedToday.add(actual.realized).add(actual.income);
|
|
268
|
+
|
|
258
269
|
format.market = formatCurrency(actual.market, currency);
|
|
259
|
-
|
|
260
|
-
|
|
270
|
+
|
|
261
271
|
if (updates.marketDirection.up || updates.marketDirection.down) {
|
|
262
272
|
format.marketDirection = unchanged;
|
|
263
273
|
setTimeout(() => format.marketDirection = updates.marketDirection, 0);
|
|
@@ -267,10 +277,41 @@ module.exports = (() => {
|
|
|
267
277
|
format.unrealizedTodayNegative = actual.unrealizedToday.getIsNegative();
|
|
268
278
|
format.total = formatCurrency(actual.total, currency);
|
|
269
279
|
format.totalNegative = actual.total.getIsNegative();
|
|
280
|
+
|
|
281
|
+
calculateMarketPercent(group, false);
|
|
270
282
|
}
|
|
271
283
|
|
|
272
|
-
function
|
|
284
|
+
function calculateMarketPercent(group, silent) {
|
|
285
|
+
if (group.suspended) {
|
|
286
|
+
return;
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
const parent = group._parent;
|
|
290
|
+
|
|
291
|
+
const actual = group._dataActual;
|
|
292
|
+
const format = group._dataFormat;
|
|
293
|
+
|
|
294
|
+
let marketPercent;
|
|
295
|
+
|
|
296
|
+
if (parent !== null) {
|
|
297
|
+
const parentData = parent._dataActual;
|
|
298
|
+
|
|
299
|
+
if (parentData.market !== null && !parentData.market.getIsZero()) {
|
|
300
|
+
marketPercent = actual.market.divide(parentData.market);
|
|
301
|
+
} else {
|
|
302
|
+
marketPercent = null;
|
|
303
|
+
}
|
|
304
|
+
} else {
|
|
305
|
+
marketPercent = null;
|
|
306
|
+
}
|
|
273
307
|
|
|
308
|
+
actual.marketPercent = marketPercent;
|
|
309
|
+
|
|
310
|
+
format.marketPercent = formatPercent(actual.marketPercent, 2);
|
|
311
|
+
|
|
312
|
+
if (!silent) {
|
|
313
|
+
group._marketPercentChangeEvent.fire(group);
|
|
314
|
+
}
|
|
274
315
|
}
|
|
275
316
|
|
|
276
317
|
const unchanged = { up: false, down: false };
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
const
|
|
1
|
+
const array = require('@barchart/common-js/lang/array'),
|
|
2
|
+
assert = require('@barchart/common-js/lang/assert'),
|
|
2
3
|
Decimal = require('@barchart/common-js/lang/Decimal'),
|
|
3
4
|
Event = require('@barchart/common-js/messaging/Event'),
|
|
4
5
|
is = require('@barchart/common-js/lang/is');
|
|
@@ -12,10 +13,12 @@ module.exports = (() => {
|
|
|
12
13
|
* @public
|
|
13
14
|
*/
|
|
14
15
|
class PositionItem {
|
|
15
|
-
constructor(portfolio, position,
|
|
16
|
+
constructor(portfolio, position, currentSummary, previousSummaries) {
|
|
16
17
|
this._portfolio = portfolio;
|
|
17
18
|
this._position = position;
|
|
18
|
-
|
|
19
|
+
|
|
20
|
+
this._currentSummary = currentSummary || null;
|
|
21
|
+
this._previousSummaries = previousSummaries || [ ];
|
|
19
22
|
|
|
20
23
|
this._data = { };
|
|
21
24
|
|
|
@@ -32,6 +35,9 @@ module.exports = (() => {
|
|
|
32
35
|
|
|
33
36
|
this._data.realized = null;
|
|
34
37
|
this._data.income = null;
|
|
38
|
+
|
|
39
|
+
this._data.summaryTotalCurrent = null;
|
|
40
|
+
this._data.summaryTotalPrevious = null;
|
|
35
41
|
|
|
36
42
|
this._excluded = false;
|
|
37
43
|
|
|
@@ -50,8 +56,12 @@ module.exports = (() => {
|
|
|
50
56
|
return this._position;
|
|
51
57
|
}
|
|
52
58
|
|
|
53
|
-
get
|
|
54
|
-
return this.
|
|
59
|
+
get currentSummary() {
|
|
60
|
+
return this._currentSummary;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
get previousSummaries() {
|
|
64
|
+
return this._previousSummaries;
|
|
55
65
|
}
|
|
56
66
|
|
|
57
67
|
get data() {
|
|
@@ -96,7 +106,7 @@ module.exports = (() => {
|
|
|
96
106
|
function calculateStaticData(item) {
|
|
97
107
|
const position = item.position;
|
|
98
108
|
const snapshot = item.position.snapshot;
|
|
99
|
-
const
|
|
109
|
+
const previousSummaries = item.previousSummaries;
|
|
100
110
|
|
|
101
111
|
const data = item._data;
|
|
102
112
|
|
|
@@ -115,22 +125,8 @@ module.exports = (() => {
|
|
|
115
125
|
data.realized = snapshot.gain;
|
|
116
126
|
data.income = snapshot.income;
|
|
117
127
|
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
if (summaries.length > index && summaries[index] !== null) {
|
|
122
|
-
const period = summaries[index].period;
|
|
123
|
-
|
|
124
|
-
summaryTotal = period.realized.add(period.unrealized).add(period.income);
|
|
125
|
-
} else {
|
|
126
|
-
summaryTotal = Decimal.ZERO;
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
return summaryTotal;
|
|
130
|
-
};
|
|
131
|
-
|
|
132
|
-
data.summaryOneTotal = getSummaryTotal(0);
|
|
133
|
-
data.summaryTwoTotal = getSummaryTotal(1);
|
|
128
|
+
data.summaryTotalCurrent = calculateSummaryTotal(item.currentSummary);
|
|
129
|
+
data.summaryTotalPrevious = calculateSummaryTotal(array.last(previousSummaries));
|
|
134
130
|
}
|
|
135
131
|
|
|
136
132
|
function calculatePriceData(item, price) {
|
|
@@ -183,6 +179,20 @@ module.exports = (() => {
|
|
|
183
179
|
data.unrealizedToday = unrealizedToday;
|
|
184
180
|
data.unrealizedTodayChange = unrealizedTodayChange;
|
|
185
181
|
}
|
|
182
|
+
|
|
183
|
+
function calculateSummaryTotal(summary) {
|
|
184
|
+
let returnRef;
|
|
185
|
+
|
|
186
|
+
if (summary) {
|
|
187
|
+
const period = summary.period;
|
|
188
|
+
|
|
189
|
+
returnRef = period.realized.add(period.unrealized).add(period.income);
|
|
190
|
+
} else {
|
|
191
|
+
returnRef = Decimal.ZERO;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
return returnRef;
|
|
195
|
+
}
|
|
186
196
|
|
|
187
197
|
return PositionItem;
|
|
188
198
|
})();
|
package/package.json
CHANGED
package/test/SpecRunner.js
CHANGED
|
@@ -156,12 +156,13 @@ module.exports = (() => {
|
|
|
156
156
|
* start and end dates.
|
|
157
157
|
*
|
|
158
158
|
* @public
|
|
159
|
-
* @
|
|
160
|
-
* @param {Day} endDate
|
|
159
|
+
* @return {PositionSummaryRange} range
|
|
161
160
|
* @return {String}
|
|
162
161
|
*/
|
|
163
|
-
describeRange(
|
|
164
|
-
|
|
162
|
+
describeRange(range) {
|
|
163
|
+
console.log('range: ', range);
|
|
164
|
+
|
|
165
|
+
return this._descriptionCalculator(range.start, range.end);
|
|
165
166
|
}
|
|
166
167
|
|
|
167
168
|
/**
|
|
@@ -345,20 +346,20 @@ module.exports = (() => {
|
|
|
345
346
|
return null;
|
|
346
347
|
}
|
|
347
348
|
|
|
348
|
-
function getYearlyRangeDescription(
|
|
349
|
-
return
|
|
349
|
+
function getYearlyRangeDescription(start, end) {
|
|
350
|
+
return end.year.toString();
|
|
350
351
|
}
|
|
351
352
|
|
|
352
|
-
function getQuarterlyRangeDescription(
|
|
353
|
+
function getQuarterlyRangeDescription(start, end) {
|
|
353
354
|
return '';
|
|
354
355
|
}
|
|
355
356
|
|
|
356
|
-
function getMonthlyRangeDescription(
|
|
357
|
+
function getMonthlyRangeDescription(start, end) {
|
|
357
358
|
return '';
|
|
358
359
|
}
|
|
359
360
|
|
|
360
|
-
function getYearToDateRangeDescription(
|
|
361
|
-
return `${
|
|
361
|
+
function getYearToDateRangeDescription(start, end) {
|
|
362
|
+
return `${end.year.toString()} YTD`;
|
|
362
363
|
}
|
|
363
364
|
|
|
364
365
|
function getFilteredTransactions(transactions) {
|
|
@@ -388,6 +389,7 @@ module.exports = (() => {
|
|
|
388
389
|
* @extends {Enum}
|
|
389
390
|
* @param {String} code
|
|
390
391
|
* @param {String} description
|
|
392
|
+
* @param {String} display
|
|
391
393
|
* @param {Boolean} purchase
|
|
392
394
|
* @param {Boolean} sale
|
|
393
395
|
* @param {Boolean} income
|
|
@@ -395,15 +397,17 @@ module.exports = (() => {
|
|
|
395
397
|
* @param {Boolean} closing
|
|
396
398
|
*/
|
|
397
399
|
class TransactionType extends Enum {
|
|
398
|
-
constructor(code, description, purchase, sale, income, opening, closing) {
|
|
400
|
+
constructor(code, description, display, purchase, sale, income, opening, closing) {
|
|
399
401
|
super(code, description);
|
|
400
402
|
|
|
403
|
+
assert.argumentIsRequired(display, 'display', String);
|
|
401
404
|
assert.argumentIsRequired(purchase, 'purchase', Boolean);
|
|
402
405
|
assert.argumentIsRequired(sale, 'sale', Boolean);
|
|
403
406
|
assert.argumentIsRequired(income, 'income', Boolean);
|
|
404
407
|
assert.argumentIsRequired(opening, 'opening', Boolean);
|
|
405
408
|
assert.argumentIsRequired(closing, 'closing', Boolean);
|
|
406
409
|
|
|
410
|
+
this._display = display;
|
|
407
411
|
this._purchase = purchase;
|
|
408
412
|
this._sale = sale;
|
|
409
413
|
this._income = income;
|
|
@@ -411,6 +415,16 @@ module.exports = (() => {
|
|
|
411
415
|
this._closing = closing;
|
|
412
416
|
}
|
|
413
417
|
|
|
418
|
+
/**
|
|
419
|
+
* A human-readable description of the transaction type.
|
|
420
|
+
*
|
|
421
|
+
* @public
|
|
422
|
+
* @returns {String}
|
|
423
|
+
*/
|
|
424
|
+
get display() {
|
|
425
|
+
return this._display;
|
|
426
|
+
}
|
|
427
|
+
|
|
414
428
|
/**
|
|
415
429
|
* Indicates if the transaction was a trade.
|
|
416
430
|
*
|
|
@@ -676,27 +690,27 @@ module.exports = (() => {
|
|
|
676
690
|
}
|
|
677
691
|
}
|
|
678
692
|
|
|
679
|
-
const buy = new TransactionType('B', 'Buy', true, false, false, true, false);
|
|
680
|
-
const sell = new TransactionType('S', 'Sell', false, true, false, false, true);
|
|
681
|
-
const buyShort = new TransactionType('BS', 'Buy To Cover', true, false, false, false, true);
|
|
682
|
-
const sellShort = new TransactionType('SS', 'Sell Short',
|
|
683
|
-
const dividend = new TransactionType('DV', 'Dividend', false, false, true, false, false);
|
|
684
|
-
const dividendReinvest = new TransactionType('DX', 'Dividend (Reinvested)', false, false, false, true, false);
|
|
685
|
-
const dividendStock = new TransactionType('DS', 'Dividend (Stock)', false, false, false, true, false);
|
|
686
|
-
const split = new TransactionType('SP', 'Split', false, false, false, true, false);
|
|
687
|
-
const fee = new TransactionType('F', 'Fee', false, false, false, true, false);
|
|
688
|
-
const feeUnits = new TransactionType('FU', 'Fee', false, false, false, false, false);
|
|
693
|
+
const buy = new TransactionType('B', 'Buy', 'Buy', true, false, false, true, false);
|
|
694
|
+
const sell = new TransactionType('S', 'Sell', 'Sell', false, true, false, false, true);
|
|
695
|
+
const buyShort = new TransactionType('BS', 'Buy To Cover', 'Buy To Cover', true, false, false, false, true);
|
|
696
|
+
const sellShort = new TransactionType('SS', 'Sell Short', 'Sell Short', false, true, false, true, false);
|
|
697
|
+
const dividend = new TransactionType('DV', 'Dividend', 'Dividend', false, false, true, false, false);
|
|
698
|
+
const dividendReinvest = new TransactionType('DX', 'Dividend (Reinvested)', 'Dividend Reinvest', false, false, false, true, false);
|
|
699
|
+
const dividendStock = new TransactionType('DS', 'Dividend (Stock)', 'Dividend Stock', false, false, false, true, false);
|
|
700
|
+
const split = new TransactionType('SP', 'Split', 'Split', false, false, false, true, false);
|
|
701
|
+
const fee = new TransactionType('F', 'Fee', 'Fee', false, false, false, true, false);
|
|
702
|
+
const feeUnits = new TransactionType('FU', 'Fee Units', 'Fee', false, false, false, false, false);
|
|
689
703
|
|
|
690
|
-
const distributionCash = new TransactionType('DC', 'Distribution (Cash)', false, false, true, false, false);
|
|
691
|
-
const distributionFund = new TransactionType('DF', 'Distribution (Units)', false, false, false, true, false);
|
|
704
|
+
const distributionCash = new TransactionType('DC', 'Distribution (Cash)', 'Cash Distribution', false, false, true, false, false);
|
|
705
|
+
const distributionFund = new TransactionType('DF', 'Distribution (Units)', 'Unit Distribution', false, false, false, true, false);
|
|
692
706
|
|
|
693
|
-
const deposit = new TransactionType('D', 'Deposit', false, false, false, true, false);
|
|
694
|
-
const withdrawal = new TransactionType('W', 'Withdrawal', false, false, false, false, true);
|
|
695
|
-
const debit = new TransactionType('DR', 'Debit', false, false, false, false, true);
|
|
696
|
-
const credit = new TransactionType('CR', 'Credit', false, false, false, true, false);
|
|
707
|
+
const deposit = new TransactionType('D', 'Deposit', 'Deposit', false, false, false, true, false);
|
|
708
|
+
const withdrawal = new TransactionType('W', 'Withdrawal', 'Withdrawal', false, false, false, false, true);
|
|
709
|
+
const debit = new TransactionType('DR', 'Debit', 'Debit', false, false, false, false, true);
|
|
710
|
+
const credit = new TransactionType('CR', 'Credit', 'Credit', false, false, false, true, false);
|
|
697
711
|
|
|
698
|
-
const valuation = new TransactionType('V', 'Valuation', false, false, false, false, false);
|
|
699
|
-
const income = new TransactionType('I', 'Income', false, false, true, false, false);
|
|
712
|
+
const valuation = new TransactionType('V', 'Valuation', 'Valuation', false, false, false, false, false);
|
|
713
|
+
const income = new TransactionType('I', 'Income', 'Income', false, false, true, false, false);
|
|
700
714
|
|
|
701
715
|
return TransactionType;
|
|
702
716
|
})();
|
|
@@ -722,12 +736,18 @@ module.exports = (() => {
|
|
|
722
736
|
* @public
|
|
723
737
|
*/
|
|
724
738
|
class PositionContainer {
|
|
725
|
-
constructor(portfolios, positions, summaries, definitions, defaultCurrency,
|
|
739
|
+
constructor(portfolios, positions, summaries, definitions, defaultCurrency, summaryFrame) {
|
|
726
740
|
this._definitions = definitions;
|
|
727
741
|
this._defaultCurrency = defaultCurrency || Currency.CAD;
|
|
742
|
+
|
|
743
|
+
const previousSummaryFrame = summaryFrame || PositionSummaryFrame.YEARLY;
|
|
744
|
+
const previousSummaryRanges = previousSummaryFrame.getRecentRanges(0);
|
|
745
|
+
|
|
746
|
+
const currentSummaryFrame = PositionSummaryFrame.YTD;
|
|
747
|
+
const currentSummaryRange = array.last(currentSummaryFrame.getRecentRanges(0));
|
|
728
748
|
|
|
729
|
-
this.
|
|
730
|
-
this.
|
|
749
|
+
this._summaryDescriptionCurrent = previousSummaryFrame.describeRange(array.last(previousSummaryRanges));
|
|
750
|
+
this._summaryDescriptionPrevious = currentSummaryFrame.describeRange(currentSummaryRange);
|
|
731
751
|
|
|
732
752
|
this._portfolios = portfolios.reduce((map, portfolio) => {
|
|
733
753
|
map[portfolio.portfolio] = portfolio;
|
|
@@ -735,15 +755,25 @@ module.exports = (() => {
|
|
|
735
755
|
return map;
|
|
736
756
|
}, { });
|
|
737
757
|
|
|
738
|
-
this.
|
|
739
|
-
if (
|
|
758
|
+
this._summariesCurrent = summaries.reduce((map, summary) => {
|
|
759
|
+
if (summary.frame === currentSummaryFrame && currentSummaryRange.start.getIsEqual(summary.start.date) && currentSummaryRange.end.getIsEqual(summary.end.date)) {
|
|
760
|
+
const key = summary.position;
|
|
761
|
+
|
|
762
|
+
map[key] = summary;
|
|
763
|
+
}
|
|
764
|
+
|
|
765
|
+
return map;
|
|
766
|
+
}, { });
|
|
767
|
+
|
|
768
|
+
this._summariesPrevious = summaries.reduce((map, summary) => {
|
|
769
|
+
if (summary.frame === previousSummaryFrame) {
|
|
740
770
|
const key = summary.position;
|
|
741
771
|
|
|
742
772
|
if (!map.hasOwnProperty(key)) {
|
|
743
|
-
map[key] = getSummaryArray(
|
|
773
|
+
map[key] = getSummaryArray(previousSummaryRanges);
|
|
744
774
|
}
|
|
745
775
|
|
|
746
|
-
const index =
|
|
776
|
+
const index = previousSummaryRanges.findIndex(r => r.start.getIsEqual(summary.start.date) && r.end.getIsEqual(summary.end.date));
|
|
747
777
|
|
|
748
778
|
if (!(index < 0)) {
|
|
749
779
|
map[key][index] = summary;
|
|
@@ -757,9 +787,10 @@ module.exports = (() => {
|
|
|
757
787
|
const portfolio = this._portfolios[position.portfolio];
|
|
758
788
|
|
|
759
789
|
if (position) {
|
|
760
|
-
const
|
|
790
|
+
const currentSummary = this._summariesCurrent[position.position] || null;
|
|
791
|
+
const previousSummaries = this._summariesPrevious[position.position] || getSummaryArray(previousSummaryRanges);
|
|
761
792
|
|
|
762
|
-
items.push(new PositionItem(portfolio, position,
|
|
793
|
+
items.push(new PositionItem(portfolio, position, currentSummary, previousSummaries));
|
|
763
794
|
}
|
|
764
795
|
|
|
765
796
|
return items;
|
|
@@ -857,6 +888,10 @@ module.exports = (() => {
|
|
|
857
888
|
compositeGroups.forEach((group) => {
|
|
858
889
|
const child = tree.addChild(group);
|
|
859
890
|
|
|
891
|
+
group.registerMarketPercentChangeHandler(() => {
|
|
892
|
+
this._tree.walk((childGroup) => childGroup.refreshMarketPercent());
|
|
893
|
+
});
|
|
894
|
+
|
|
860
895
|
createGroups(child, group.items, additionalDefinitions);
|
|
861
896
|
});
|
|
862
897
|
};
|
|
@@ -867,7 +902,25 @@ module.exports = (() => {
|
|
|
867
902
|
get defaultCurrency() {
|
|
868
903
|
return this._defaultCurrency;
|
|
869
904
|
}
|
|
905
|
+
|
|
906
|
+
getCurrentSummaryDescription() {
|
|
907
|
+
return this._summaryDescriptionCurrent;
|
|
908
|
+
}
|
|
909
|
+
|
|
910
|
+
getPreviousSummaryDescription() {
|
|
911
|
+
return this._summaryDescriptionPrevious;
|
|
912
|
+
}
|
|
913
|
+
|
|
914
|
+
startTransaction(executor) {
|
|
915
|
+
assert.argumentIsRequired(executor, 'executor', Function);
|
|
870
916
|
|
|
917
|
+
this._tree.walk(group => group.setSuspended(true), false, false);
|
|
918
|
+
|
|
919
|
+
executor(this);
|
|
920
|
+
|
|
921
|
+
this._tree.walk(group => group.setSuspended(false), false, false);
|
|
922
|
+
}
|
|
923
|
+
|
|
871
924
|
getSymbols() {
|
|
872
925
|
return Object.keys(this._symbols);
|
|
873
926
|
}
|
|
@@ -894,16 +947,6 @@ module.exports = (() => {
|
|
|
894
947
|
|
|
895
948
|
}
|
|
896
949
|
|
|
897
|
-
startTransaction(executor) {
|
|
898
|
-
assert.argumentIsRequired(executor, 'executor', Function);
|
|
899
|
-
|
|
900
|
-
this._tree.walk(group => group.setSuspended(true), false, false);
|
|
901
|
-
|
|
902
|
-
executor(this);
|
|
903
|
-
|
|
904
|
-
this._tree.walk(group => group.setSuspended(false), false, false);
|
|
905
|
-
}
|
|
906
|
-
|
|
907
950
|
getGroup(keys) {
|
|
908
951
|
const node = keys.reduce((tree, key) => {
|
|
909
952
|
tree = tree.findChild(group => group.description === key);
|
|
@@ -940,6 +983,7 @@ module.exports = (() => {
|
|
|
940
983
|
const assert = require('@barchart/common-js/lang/assert'),
|
|
941
984
|
Currency = require('@barchart/common-js/lang/Currency'),
|
|
942
985
|
Decimal = require('@barchart/common-js/lang/Decimal'),
|
|
986
|
+
Event = require('@barchart/common-js/messaging/Event'),
|
|
943
987
|
formatter = require('@barchart/common-js/lang/formatter'),
|
|
944
988
|
is = require('@barchart/common-js/lang/is');
|
|
945
989
|
|
|
@@ -964,6 +1008,8 @@ module.exports = (() => {
|
|
|
964
1008
|
this._excluded = false;
|
|
965
1009
|
this._suspended = false;
|
|
966
1010
|
|
|
1011
|
+
this._marketPercentChangeEvent = new Event(this);
|
|
1012
|
+
|
|
967
1013
|
this._dataFormat = { };
|
|
968
1014
|
this._dataActual = { };
|
|
969
1015
|
|
|
@@ -978,8 +1024,8 @@ module.exports = (() => {
|
|
|
978
1024
|
this._dataActual.marketPercent = null;
|
|
979
1025
|
this._dataActual.unrealizedToday = null;
|
|
980
1026
|
this._dataActual.total = null;
|
|
981
|
-
this._dataActual.
|
|
982
|
-
this._dataActual.
|
|
1027
|
+
this._dataActual.summaryTotalCurrent = null;
|
|
1028
|
+
this._dataActual.summaryTotalPrevious = null;
|
|
983
1029
|
|
|
984
1030
|
this._dataFormat.currentPrice = null;
|
|
985
1031
|
this._dataFormat.previousPrice = null;
|
|
@@ -993,8 +1039,8 @@ module.exports = (() => {
|
|
|
993
1039
|
this._dataFormat.unrealizedTodayNegative = false;
|
|
994
1040
|
this._dataFormat.total = null;
|
|
995
1041
|
this._dataFormat.totalNegative = false;
|
|
996
|
-
this._dataFormat.
|
|
997
|
-
this._dataFormat.
|
|
1042
|
+
this._dataFormat.summaryTotalCurrent = null;
|
|
1043
|
+
this._dataFormat.summaryTotalPrevious = null;
|
|
998
1044
|
|
|
999
1045
|
this._dataFormat.unrealizedTodayNegative = false;
|
|
1000
1046
|
|
|
@@ -1074,6 +1120,14 @@ module.exports = (() => {
|
|
|
1074
1120
|
calculatePriceData(this, null, true);
|
|
1075
1121
|
}
|
|
1076
1122
|
|
|
1123
|
+
refreshMarketPercent() {
|
|
1124
|
+
calculateMarketPercent(this, true);
|
|
1125
|
+
}
|
|
1126
|
+
|
|
1127
|
+
registerMarketPercentChangeHandler(handler) {
|
|
1128
|
+
this._marketPercentChangeEvent.register(handler);
|
|
1129
|
+
}
|
|
1130
|
+
|
|
1077
1131
|
toString() {
|
|
1078
1132
|
return '[PositionGroup]';
|
|
1079
1133
|
}
|
|
@@ -1115,29 +1169,29 @@ module.exports = (() => {
|
|
|
1115
1169
|
updates.basis = updates.basis.add(item.data.basis);
|
|
1116
1170
|
updates.realized = updates.realized.add(item.data.realized);
|
|
1117
1171
|
updates.income = updates.income.add(item.data.income);
|
|
1118
|
-
updates.
|
|
1119
|
-
updates.
|
|
1172
|
+
updates.summaryTotalCurrent = updates.summaryTotalCurrent.add(item.data.summaryTotalCurrent);
|
|
1173
|
+
updates.summaryTotalPrevious = updates.summaryTotalPrevious.add(item.data.summaryTotalPrevious);
|
|
1120
1174
|
|
|
1121
1175
|
return updates;
|
|
1122
1176
|
}, {
|
|
1123
1177
|
basis: Decimal.ZERO,
|
|
1124
1178
|
realized: Decimal.ZERO,
|
|
1125
1179
|
income: Decimal.ZERO,
|
|
1126
|
-
|
|
1127
|
-
|
|
1180
|
+
summaryTotalCurrent: Decimal.ZERO,
|
|
1181
|
+
summaryTotalPrevious: Decimal.ZERO
|
|
1128
1182
|
});
|
|
1129
1183
|
|
|
1130
1184
|
actual.basis = updates.basis;
|
|
1131
1185
|
actual.realized = updates.realized;
|
|
1132
1186
|
actual.income = updates.income;
|
|
1133
|
-
actual.
|
|
1134
|
-
actual.
|
|
1187
|
+
actual.summaryTotalCurrent = updates.summaryTotalCurrent;
|
|
1188
|
+
actual.summaryTotalPrevious = updates.summaryTotalPrevious;
|
|
1135
1189
|
|
|
1136
1190
|
format.basis = formatCurrency(actual.basis, currency);
|
|
1137
1191
|
format.realized = formatCurrency(actual.basis, currency);
|
|
1138
1192
|
format.income = formatCurrency(actual.income, currency);
|
|
1139
|
-
format.
|
|
1140
|
-
format.
|
|
1193
|
+
format.summaryTotalCurrent = formatCurrency(updates.summaryTotalCurrent, currency);
|
|
1194
|
+
format.summaryTotalPrevious = formatCurrency(updates.summaryTotalPrevious, currency);
|
|
1141
1195
|
}
|
|
1142
1196
|
|
|
1143
1197
|
function calculatePriceData(group, item, forceRefresh) {
|
|
@@ -1191,12 +1245,11 @@ module.exports = (() => {
|
|
|
1191
1245
|
}
|
|
1192
1246
|
|
|
1193
1247
|
actual.market = updates.market;
|
|
1194
|
-
actual.marketPercent = updates.marketPercent;
|
|
1195
1248
|
actual.unrealizedToday = updates.unrealizedToday;
|
|
1196
1249
|
actual.total = updates.unrealizedToday.add(actual.realized).add(actual.income);
|
|
1250
|
+
|
|
1197
1251
|
format.market = formatCurrency(actual.market, currency);
|
|
1198
|
-
|
|
1199
|
-
|
|
1252
|
+
|
|
1200
1253
|
if (updates.marketDirection.up || updates.marketDirection.down) {
|
|
1201
1254
|
format.marketDirection = unchanged;
|
|
1202
1255
|
setTimeout(() => format.marketDirection = updates.marketDirection, 0);
|
|
@@ -1206,10 +1259,41 @@ module.exports = (() => {
|
|
|
1206
1259
|
format.unrealizedTodayNegative = actual.unrealizedToday.getIsNegative();
|
|
1207
1260
|
format.total = formatCurrency(actual.total, currency);
|
|
1208
1261
|
format.totalNegative = actual.total.getIsNegative();
|
|
1262
|
+
|
|
1263
|
+
calculateMarketPercent(group, false);
|
|
1209
1264
|
}
|
|
1210
1265
|
|
|
1211
|
-
function
|
|
1266
|
+
function calculateMarketPercent(group, silent) {
|
|
1267
|
+
if (group.suspended) {
|
|
1268
|
+
return;
|
|
1269
|
+
}
|
|
1270
|
+
|
|
1271
|
+
const parent = group._parent;
|
|
1272
|
+
|
|
1273
|
+
const actual = group._dataActual;
|
|
1274
|
+
const format = group._dataFormat;
|
|
1275
|
+
|
|
1276
|
+
let marketPercent;
|
|
1277
|
+
|
|
1278
|
+
if (parent !== null) {
|
|
1279
|
+
const parentData = parent._dataActual;
|
|
1280
|
+
|
|
1281
|
+
if (parentData.market !== null && !parentData.market.getIsZero()) {
|
|
1282
|
+
marketPercent = actual.market.divide(parentData.market);
|
|
1283
|
+
} else {
|
|
1284
|
+
marketPercent = null;
|
|
1285
|
+
}
|
|
1286
|
+
} else {
|
|
1287
|
+
marketPercent = null;
|
|
1288
|
+
}
|
|
1212
1289
|
|
|
1290
|
+
actual.marketPercent = marketPercent;
|
|
1291
|
+
|
|
1292
|
+
format.marketPercent = formatPercent(actual.marketPercent, 2);
|
|
1293
|
+
|
|
1294
|
+
if (!silent) {
|
|
1295
|
+
group._marketPercentChangeEvent.fire(group);
|
|
1296
|
+
}
|
|
1213
1297
|
}
|
|
1214
1298
|
|
|
1215
1299
|
const unchanged = { up: false, down: false };
|
|
@@ -1217,7 +1301,7 @@ module.exports = (() => {
|
|
|
1217
1301
|
return PositionGroup;
|
|
1218
1302
|
})();
|
|
1219
1303
|
|
|
1220
|
-
},{"@barchart/common-js/lang/Currency":11,"@barchart/common-js/lang/Decimal":13,"@barchart/common-js/lang/assert":17,"@barchart/common-js/lang/formatter":18,"@barchart/common-js/lang/is":19}],6:[function(require,module,exports){
|
|
1304
|
+
},{"@barchart/common-js/lang/Currency":11,"@barchart/common-js/lang/Decimal":13,"@barchart/common-js/lang/assert":17,"@barchart/common-js/lang/formatter":18,"@barchart/common-js/lang/is":19,"@barchart/common-js/messaging/Event":20}],6:[function(require,module,exports){
|
|
1221
1305
|
const assert = require('@barchart/common-js/lang/assert'),
|
|
1222
1306
|
is = require('@barchart/common-js/lang/is');
|
|
1223
1307
|
|
|
@@ -1268,7 +1352,8 @@ module.exports = (() => {
|
|
|
1268
1352
|
})();
|
|
1269
1353
|
|
|
1270
1354
|
},{"@barchart/common-js/lang/assert":17,"@barchart/common-js/lang/is":19}],7:[function(require,module,exports){
|
|
1271
|
-
const
|
|
1355
|
+
const array = require('@barchart/common-js/lang/array'),
|
|
1356
|
+
assert = require('@barchart/common-js/lang/assert'),
|
|
1272
1357
|
Decimal = require('@barchart/common-js/lang/Decimal'),
|
|
1273
1358
|
Event = require('@barchart/common-js/messaging/Event'),
|
|
1274
1359
|
is = require('@barchart/common-js/lang/is');
|
|
@@ -1282,10 +1367,12 @@ module.exports = (() => {
|
|
|
1282
1367
|
* @public
|
|
1283
1368
|
*/
|
|
1284
1369
|
class PositionItem {
|
|
1285
|
-
constructor(portfolio, position,
|
|
1370
|
+
constructor(portfolio, position, currentSummary, previousSummaries) {
|
|
1286
1371
|
this._portfolio = portfolio;
|
|
1287
1372
|
this._position = position;
|
|
1288
|
-
|
|
1373
|
+
|
|
1374
|
+
this._currentSummary = currentSummary || null;
|
|
1375
|
+
this._previousSummaries = previousSummaries || [ ];
|
|
1289
1376
|
|
|
1290
1377
|
this._data = { };
|
|
1291
1378
|
|
|
@@ -1302,6 +1389,9 @@ module.exports = (() => {
|
|
|
1302
1389
|
|
|
1303
1390
|
this._data.realized = null;
|
|
1304
1391
|
this._data.income = null;
|
|
1392
|
+
|
|
1393
|
+
this._data.summaryTotalCurrent = null;
|
|
1394
|
+
this._data.summaryTotalPrevious = null;
|
|
1305
1395
|
|
|
1306
1396
|
this._excluded = false;
|
|
1307
1397
|
|
|
@@ -1320,8 +1410,12 @@ module.exports = (() => {
|
|
|
1320
1410
|
return this._position;
|
|
1321
1411
|
}
|
|
1322
1412
|
|
|
1323
|
-
get
|
|
1324
|
-
return this.
|
|
1413
|
+
get currentSummary() {
|
|
1414
|
+
return this._currentSummary;
|
|
1415
|
+
}
|
|
1416
|
+
|
|
1417
|
+
get previousSummaries() {
|
|
1418
|
+
return this._previousSummaries;
|
|
1325
1419
|
}
|
|
1326
1420
|
|
|
1327
1421
|
get data() {
|
|
@@ -1366,7 +1460,7 @@ module.exports = (() => {
|
|
|
1366
1460
|
function calculateStaticData(item) {
|
|
1367
1461
|
const position = item.position;
|
|
1368
1462
|
const snapshot = item.position.snapshot;
|
|
1369
|
-
const
|
|
1463
|
+
const previousSummaries = item.previousSummaries;
|
|
1370
1464
|
|
|
1371
1465
|
const data = item._data;
|
|
1372
1466
|
|
|
@@ -1385,22 +1479,8 @@ module.exports = (() => {
|
|
|
1385
1479
|
data.realized = snapshot.gain;
|
|
1386
1480
|
data.income = snapshot.income;
|
|
1387
1481
|
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
if (summaries.length > index && summaries[index] !== null) {
|
|
1392
|
-
const period = summaries[index].period;
|
|
1393
|
-
|
|
1394
|
-
summaryTotal = period.realized.add(period.unrealized).add(period.income);
|
|
1395
|
-
} else {
|
|
1396
|
-
summaryTotal = Decimal.ZERO;
|
|
1397
|
-
}
|
|
1398
|
-
|
|
1399
|
-
return summaryTotal;
|
|
1400
|
-
};
|
|
1401
|
-
|
|
1402
|
-
data.summaryOneTotal = getSummaryTotal(0);
|
|
1403
|
-
data.summaryTwoTotal = getSummaryTotal(1);
|
|
1482
|
+
data.summaryTotalCurrent = calculateSummaryTotal(item.currentSummary);
|
|
1483
|
+
data.summaryTotalPrevious = calculateSummaryTotal(array.last(previousSummaries));
|
|
1404
1484
|
}
|
|
1405
1485
|
|
|
1406
1486
|
function calculatePriceData(item, price) {
|
|
@@ -1453,11 +1533,25 @@ module.exports = (() => {
|
|
|
1453
1533
|
data.unrealizedToday = unrealizedToday;
|
|
1454
1534
|
data.unrealizedTodayChange = unrealizedTodayChange;
|
|
1455
1535
|
}
|
|
1536
|
+
|
|
1537
|
+
function calculateSummaryTotal(summary) {
|
|
1538
|
+
let returnRef;
|
|
1539
|
+
|
|
1540
|
+
if (summary) {
|
|
1541
|
+
const period = summary.period;
|
|
1542
|
+
|
|
1543
|
+
returnRef = period.realized.add(period.unrealized).add(period.income);
|
|
1544
|
+
} else {
|
|
1545
|
+
returnRef = Decimal.ZERO;
|
|
1546
|
+
}
|
|
1547
|
+
|
|
1548
|
+
return returnRef;
|
|
1549
|
+
}
|
|
1456
1550
|
|
|
1457
1551
|
return PositionItem;
|
|
1458
1552
|
})();
|
|
1459
1553
|
|
|
1460
|
-
},{"./../data/InstrumentType":1,"@barchart/common-js/lang/Decimal":13,"@barchart/common-js/lang/assert":17,"@barchart/common-js/lang/is":19,"@barchart/common-js/messaging/Event":20}],8:[function(require,module,exports){
|
|
1554
|
+
},{"./../data/InstrumentType":1,"@barchart/common-js/lang/Decimal":13,"@barchart/common-js/lang/array":16,"@barchart/common-js/lang/assert":17,"@barchart/common-js/lang/is":19,"@barchart/common-js/messaging/Event":20}],8:[function(require,module,exports){
|
|
1461
1555
|
'use strict';
|
|
1462
1556
|
|
|
1463
1557
|
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
|
|
@@ -5871,10 +5965,10 @@ describe('When a position container data is gathered', () => {
|
|
|
5871
5965
|
income: new Decimal(0),
|
|
5872
5966
|
gain: new Decimal(0)
|
|
5873
5967
|
}
|
|
5874
|
-
}
|
|
5968
|
+
};
|
|
5875
5969
|
}
|
|
5876
5970
|
|
|
5877
|
-
describe('for two portfolios, each with the same position, and the second portfolio with an
|
|
5971
|
+
describe('for two portfolios, each with the same position, and the second portfolio with an addition position', () => {
|
|
5878
5972
|
let portfolios;
|
|
5879
5973
|
let positions;
|
|
5880
5974
|
let summaries;
|
|
@@ -29,10 +29,10 @@ describe('When a position container data is gathered', () => {
|
|
|
29
29
|
income: new Decimal(0),
|
|
30
30
|
gain: new Decimal(0)
|
|
31
31
|
}
|
|
32
|
-
}
|
|
32
|
+
};
|
|
33
33
|
}
|
|
34
34
|
|
|
35
|
-
describe('for two portfolios, each with the same position, and the second portfolio with an
|
|
35
|
+
describe('for two portfolios, each with the same position, and the second portfolio with an addition position', () => {
|
|
36
36
|
let portfolios;
|
|
37
37
|
let positions;
|
|
38
38
|
let summaries;
|