@barchart/portfolio-api-common 1.2.55 → 1.2.59
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/InstrumentType.js +1 -2
- package/lib/data/TransactionValidator.js +7 -4
- package/lib/processing/PositionContainer.js +0 -1
- package/lib/processing/PositionItem.js +17 -15
- package/package.json +1 -1
- package/test/SpecRunner.js +32 -25
- package/test/specs/data/TransactionValidatorSpec.js +6 -2
|
@@ -109,7 +109,7 @@ module.exports = (() => {
|
|
|
109
109
|
|
|
110
110
|
/**
|
|
111
111
|
* Indicates if fractional shares should be closed when the position
|
|
112
|
-
* size is less than one.
|
|
112
|
+
* size is less than one (or some of the fractional shares are closed).
|
|
113
113
|
*
|
|
114
114
|
* @public
|
|
115
115
|
* @returns {Boolean}
|
|
@@ -118,7 +118,6 @@ module.exports = (() => {
|
|
|
118
118
|
return this._closeFractional;
|
|
119
119
|
}
|
|
120
120
|
|
|
121
|
-
|
|
122
121
|
/**
|
|
123
122
|
* Generates an identifier for the instrument.
|
|
124
123
|
*
|
|
@@ -26,10 +26,11 @@ module.exports = (() => {
|
|
|
26
26
|
* @public
|
|
27
27
|
* @static
|
|
28
28
|
* @param {Array.<Object>} transactions
|
|
29
|
+
* @param {Boolean=} strict
|
|
29
30
|
* @returns {Boolean}
|
|
30
31
|
*/
|
|
31
|
-
static validateOrder(transactions) {
|
|
32
|
-
return TransactionValidator.getInvalidIndex(transactions) < 0;
|
|
32
|
+
static validateOrder(transactions, strict) {
|
|
33
|
+
return TransactionValidator.getInvalidIndex(transactions, strict) < 0;
|
|
33
34
|
}
|
|
34
35
|
|
|
35
36
|
/**
|
|
@@ -77,12 +78,14 @@ module.exports = (() => {
|
|
|
77
78
|
* @public
|
|
78
79
|
* @static
|
|
79
80
|
* @param {Array.<Object>} transactions
|
|
81
|
+
* @param {Boolean=} strict
|
|
80
82
|
* @returns {Number}
|
|
81
83
|
*/
|
|
82
|
-
static getInvalidIndex(transactions) {
|
|
84
|
+
static getInvalidIndex(transactions, strict) {
|
|
83
85
|
assert.argumentIsArray(transactions, 'transactions');
|
|
86
|
+
assert.argumentIsOptional(strict, 'strict', Boolean);
|
|
84
87
|
|
|
85
|
-
return transactions.findIndex((t, i, a) => t.sequence !== (i + 1) || (i !== 0 && t.date.getIsBefore(a[ i - 1 ].date)) || (i !== 0 && t.date.getIsEqual(a[i - 1].date) && t.type.sequence < a[i - 1].type.sequence));
|
|
88
|
+
return transactions.findIndex((t, i, a) => t.sequence !== (i + 1) || (i !== 0 && t.date.getIsBefore(a[ i - 1 ].date)) || (i !== 0 && is.boolean(strict) && strict && t.date.getIsEqual(a[i - 1].date) && t.type.sequence < a[i - 1].type.sequence));
|
|
86
89
|
}
|
|
87
90
|
|
|
88
91
|
/**
|
|
@@ -6,7 +6,6 @@ const array = require('@barchart/common-js/lang/array'),
|
|
|
6
6
|
Decimal = require('@barchart/common-js/lang/Decimal'),
|
|
7
7
|
DisposableStack = require('@barchart/common-js/collections/specialized/DisposableStack'),
|
|
8
8
|
Event = require('@barchart/common-js/messaging/Event'),
|
|
9
|
-
is = require('@barchart/common-js/lang/is'),
|
|
10
9
|
Rate = require('@barchart/common-js/lang/Rate'),
|
|
11
10
|
Tree = require('@barchart/common-js/collections/Tree');
|
|
12
11
|
|
|
@@ -311,7 +311,6 @@ module.exports = (() => {
|
|
|
311
311
|
}
|
|
312
312
|
|
|
313
313
|
function calculateStaticData(item) {
|
|
314
|
-
const portfolio = item.portfolio;
|
|
315
314
|
const position = item.position;
|
|
316
315
|
const snapshot = item.position.snapshot;
|
|
317
316
|
const previousSummaries = item.previousSummaries;
|
|
@@ -335,9 +334,9 @@ module.exports = (() => {
|
|
|
335
334
|
|
|
336
335
|
data.income = snapshot.income;
|
|
337
336
|
|
|
338
|
-
data.summaryTotalCurrent = calculateSummaryTotal(item.currentSummary);
|
|
339
|
-
data.summaryTotalPrevious = calculateSummaryTotal(getPreviousSummary(previousSummaries, 1));
|
|
340
|
-
data.summaryTotalPrevious2 = calculateSummaryTotal(getPreviousSummary(previousSummaries, 2));
|
|
337
|
+
data.summaryTotalCurrent = calculateSummaryTotal(item.currentSummary, getPreviousSummary(previousSummaries, 1));
|
|
338
|
+
data.summaryTotalPrevious = calculateSummaryTotal(getPreviousSummary(previousSummaries, 1), getPreviousSummary(previousSummaries, 2));
|
|
339
|
+
data.summaryTotalPrevious2 = calculateSummaryTotal(getPreviousSummary(previousSummaries, 2), getPreviousSummary(previousSummaries, 3));
|
|
341
340
|
|
|
342
341
|
if (snapshot.open.getIsZero()) {
|
|
343
342
|
data.basisPrice = Decimal.ZERO;
|
|
@@ -349,6 +348,7 @@ module.exports = (() => {
|
|
|
349
348
|
function calculatePriceData(item, price) {
|
|
350
349
|
const position = item.position;
|
|
351
350
|
const snapshot = item.position.snapshot;
|
|
351
|
+
const previousSummaries = item.previousSummaries;
|
|
352
352
|
|
|
353
353
|
const data = item._data;
|
|
354
354
|
|
|
@@ -408,25 +408,27 @@ module.exports = (() => {
|
|
|
408
408
|
data.unrealizedToday = unrealizedToday;
|
|
409
409
|
data.unrealizedTodayChange = unrealizedTodayChange;
|
|
410
410
|
|
|
411
|
-
const
|
|
411
|
+
const currentSummary = item.currentSummary;
|
|
412
|
+
|
|
413
|
+
if (currentSummary && position.instrument.type !== InstrumentType.CASH) {
|
|
414
|
+
const previousSummary = getPreviousSummary(previousSummaries, 1);
|
|
412
415
|
|
|
413
|
-
if (summary && position.instrument.type !== InstrumentType.CASH) {
|
|
414
416
|
let priceToUse;
|
|
415
417
|
|
|
416
418
|
if (price) {
|
|
417
419
|
priceToUse = price;
|
|
418
420
|
} else if (data.previousPrice) {
|
|
419
421
|
priceToUse = new Decimal(data.previousPrice);
|
|
420
|
-
} else if (!
|
|
421
|
-
priceToUse =
|
|
422
|
+
} else if (!currentSummary.end.open.getIsZero()) {
|
|
423
|
+
priceToUse = currentSummary.end.value.divide(summary.end.open);
|
|
422
424
|
} else {
|
|
423
425
|
priceToUse = null;
|
|
424
426
|
}
|
|
425
427
|
|
|
426
428
|
if (priceToUse !== null) {
|
|
427
|
-
const period =
|
|
429
|
+
const period = currentSummary.period;
|
|
428
430
|
|
|
429
|
-
let unrealized =
|
|
431
|
+
let unrealized = currentSummary.end.open.multiply(priceToUse).add(currentSummary.end.basis);
|
|
430
432
|
let unrealizedChange;
|
|
431
433
|
|
|
432
434
|
if (data.unrealized !== null) {
|
|
@@ -435,7 +437,7 @@ module.exports = (() => {
|
|
|
435
437
|
unrealizedChange = Decimal.ZERO;
|
|
436
438
|
}
|
|
437
439
|
|
|
438
|
-
let summaryTotalCurrent = period.realized.add(period.income).add(unrealized);
|
|
440
|
+
let summaryTotalCurrent = period.realized.add(period.income).add(unrealized).subtract(previousSummary !== null ? previousSummary.period.unrealized : Decimal.ZERO);
|
|
439
441
|
let summaryTotalCurrentChange;
|
|
440
442
|
|
|
441
443
|
if (data.summaryTotalCurrent !== null) {
|
|
@@ -463,13 +465,13 @@ module.exports = (() => {
|
|
|
463
465
|
}
|
|
464
466
|
}
|
|
465
467
|
|
|
466
|
-
function calculateSummaryTotal(
|
|
468
|
+
function calculateSummaryTotal(currentSummary, previousSummary) {
|
|
467
469
|
let returnRef;
|
|
468
470
|
|
|
469
|
-
if (
|
|
470
|
-
const period =
|
|
471
|
+
if (currentSummary) {
|
|
472
|
+
const period = currentSummary.period;
|
|
471
473
|
|
|
472
|
-
returnRef = period.realized.add(period.income).add(period.unrealized);
|
|
474
|
+
returnRef = period.realized.add(period.income).add(period.unrealized).subtract(previousSummary !== null ? previousSummary.period.unrealized : Decimal.ZERO);
|
|
473
475
|
} else {
|
|
474
476
|
returnRef = Decimal.ZERO;
|
|
475
477
|
}
|
package/package.json
CHANGED
package/test/SpecRunner.js
CHANGED
|
@@ -110,7 +110,7 @@ module.exports = (() => {
|
|
|
110
110
|
|
|
111
111
|
/**
|
|
112
112
|
* Indicates if fractional shares should be closed when the position
|
|
113
|
-
* size is less than one.
|
|
113
|
+
* size is less than one (or some of the fractional shares are closed).
|
|
114
114
|
*
|
|
115
115
|
* @public
|
|
116
116
|
* @returns {Boolean}
|
|
@@ -119,7 +119,6 @@ module.exports = (() => {
|
|
|
119
119
|
return this._closeFractional;
|
|
120
120
|
}
|
|
121
121
|
|
|
122
|
-
|
|
123
122
|
/**
|
|
124
123
|
* Generates an identifier for the instrument.
|
|
125
124
|
*
|
|
@@ -1084,10 +1083,11 @@ module.exports = (() => {
|
|
|
1084
1083
|
* @public
|
|
1085
1084
|
* @static
|
|
1086
1085
|
* @param {Array.<Object>} transactions
|
|
1086
|
+
* @param {Boolean=} strict
|
|
1087
1087
|
* @returns {Boolean}
|
|
1088
1088
|
*/
|
|
1089
|
-
static validateOrder(transactions) {
|
|
1090
|
-
return TransactionValidator.getInvalidIndex(transactions) < 0;
|
|
1089
|
+
static validateOrder(transactions, strict) {
|
|
1090
|
+
return TransactionValidator.getInvalidIndex(transactions, strict) < 0;
|
|
1091
1091
|
}
|
|
1092
1092
|
|
|
1093
1093
|
/**
|
|
@@ -1135,12 +1135,14 @@ module.exports = (() => {
|
|
|
1135
1135
|
* @public
|
|
1136
1136
|
* @static
|
|
1137
1137
|
* @param {Array.<Object>} transactions
|
|
1138
|
+
* @param {Boolean=} strict
|
|
1138
1139
|
* @returns {Number}
|
|
1139
1140
|
*/
|
|
1140
|
-
static getInvalidIndex(transactions) {
|
|
1141
|
+
static getInvalidIndex(transactions, strict) {
|
|
1141
1142
|
assert.argumentIsArray(transactions, 'transactions');
|
|
1143
|
+
assert.argumentIsOptional(strict, 'strict', Boolean);
|
|
1142
1144
|
|
|
1143
|
-
return transactions.findIndex((t, i, a) => t.sequence !== (i + 1) || (i !== 0 && t.date.getIsBefore(a[ i - 1 ].date)) || (i !== 0 && t.date.getIsEqual(a[i - 1].date) && t.type.sequence < a[i - 1].type.sequence));
|
|
1145
|
+
return transactions.findIndex((t, i, a) => t.sequence !== (i + 1) || (i !== 0 && t.date.getIsBefore(a[ i - 1 ].date)) || (i !== 0 && is.boolean(strict) && strict && t.date.getIsEqual(a[i - 1].date) && t.type.sequence < a[i - 1].type.sequence));
|
|
1144
1146
|
}
|
|
1145
1147
|
|
|
1146
1148
|
/**
|
|
@@ -1338,7 +1340,6 @@ const array = require('@barchart/common-js/lang/array'),
|
|
|
1338
1340
|
Decimal = require('@barchart/common-js/lang/Decimal'),
|
|
1339
1341
|
DisposableStack = require('@barchart/common-js/collections/specialized/DisposableStack'),
|
|
1340
1342
|
Event = require('@barchart/common-js/messaging/Event'),
|
|
1341
|
-
is = require('@barchart/common-js/lang/is'),
|
|
1342
1343
|
Rate = require('@barchart/common-js/lang/Rate'),
|
|
1343
1344
|
Tree = require('@barchart/common-js/collections/Tree');
|
|
1344
1345
|
|
|
@@ -2272,7 +2273,7 @@ module.exports = (() => {
|
|
|
2272
2273
|
return PositionContainer;
|
|
2273
2274
|
})();
|
|
2274
2275
|
|
|
2275
|
-
},{"./../data/PositionSummaryFrame":3,"./PositionGroup":7,"./PositionItem":8,"./definitions/PositionLevelDefinition":9,"./definitions/PositionLevelType":10,"./definitions/PositionTreeDefinition":11,"@barchart/common-js/collections/Tree":15,"@barchart/common-js/collections/sorting/ComparatorBuilder":16,"@barchart/common-js/collections/sorting/comparators":17,"@barchart/common-js/collections/specialized/DisposableStack":18,"@barchart/common-js/lang/Currency":20,"@barchart/common-js/lang/Decimal":22,"@barchart/common-js/lang/Rate":26,"@barchart/common-js/lang/array":28,"@barchart/common-js/lang/assert":29,"@barchart/common-js/
|
|
2276
|
+
},{"./../data/PositionSummaryFrame":3,"./PositionGroup":7,"./PositionItem":8,"./definitions/PositionLevelDefinition":9,"./definitions/PositionLevelType":10,"./definitions/PositionTreeDefinition":11,"@barchart/common-js/collections/Tree":15,"@barchart/common-js/collections/sorting/ComparatorBuilder":16,"@barchart/common-js/collections/sorting/comparators":17,"@barchart/common-js/collections/specialized/DisposableStack":18,"@barchart/common-js/lang/Currency":20,"@barchart/common-js/lang/Decimal":22,"@barchart/common-js/lang/Rate":26,"@barchart/common-js/lang/array":28,"@barchart/common-js/lang/assert":29,"@barchart/common-js/messaging/Event":35}],7:[function(require,module,exports){
|
|
2276
2277
|
const array = require('@barchart/common-js/lang/array'),
|
|
2277
2278
|
assert = require('@barchart/common-js/lang/assert'),
|
|
2278
2279
|
Currency = require('@barchart/common-js/lang/Currency'),
|
|
@@ -3446,7 +3447,6 @@ module.exports = (() => {
|
|
|
3446
3447
|
}
|
|
3447
3448
|
|
|
3448
3449
|
function calculateStaticData(item) {
|
|
3449
|
-
const portfolio = item.portfolio;
|
|
3450
3450
|
const position = item.position;
|
|
3451
3451
|
const snapshot = item.position.snapshot;
|
|
3452
3452
|
const previousSummaries = item.previousSummaries;
|
|
@@ -3470,9 +3470,9 @@ module.exports = (() => {
|
|
|
3470
3470
|
|
|
3471
3471
|
data.income = snapshot.income;
|
|
3472
3472
|
|
|
3473
|
-
data.summaryTotalCurrent = calculateSummaryTotal(item.currentSummary);
|
|
3474
|
-
data.summaryTotalPrevious = calculateSummaryTotal(getPreviousSummary(previousSummaries, 1));
|
|
3475
|
-
data.summaryTotalPrevious2 = calculateSummaryTotal(getPreviousSummary(previousSummaries, 2));
|
|
3473
|
+
data.summaryTotalCurrent = calculateSummaryTotal(item.currentSummary, getPreviousSummary(previousSummaries, 1));
|
|
3474
|
+
data.summaryTotalPrevious = calculateSummaryTotal(getPreviousSummary(previousSummaries, 1), getPreviousSummary(previousSummaries, 2));
|
|
3475
|
+
data.summaryTotalPrevious2 = calculateSummaryTotal(getPreviousSummary(previousSummaries, 2), getPreviousSummary(previousSummaries, 3));
|
|
3476
3476
|
|
|
3477
3477
|
if (snapshot.open.getIsZero()) {
|
|
3478
3478
|
data.basisPrice = Decimal.ZERO;
|
|
@@ -3484,6 +3484,7 @@ module.exports = (() => {
|
|
|
3484
3484
|
function calculatePriceData(item, price) {
|
|
3485
3485
|
const position = item.position;
|
|
3486
3486
|
const snapshot = item.position.snapshot;
|
|
3487
|
+
const previousSummaries = item.previousSummaries;
|
|
3487
3488
|
|
|
3488
3489
|
const data = item._data;
|
|
3489
3490
|
|
|
@@ -3543,25 +3544,27 @@ module.exports = (() => {
|
|
|
3543
3544
|
data.unrealizedToday = unrealizedToday;
|
|
3544
3545
|
data.unrealizedTodayChange = unrealizedTodayChange;
|
|
3545
3546
|
|
|
3546
|
-
const
|
|
3547
|
+
const currentSummary = item.currentSummary;
|
|
3548
|
+
|
|
3549
|
+
if (currentSummary && position.instrument.type !== InstrumentType.CASH) {
|
|
3550
|
+
const previousSummary = getPreviousSummary(previousSummaries, 1);
|
|
3547
3551
|
|
|
3548
|
-
if (summary && position.instrument.type !== InstrumentType.CASH) {
|
|
3549
3552
|
let priceToUse;
|
|
3550
3553
|
|
|
3551
3554
|
if (price) {
|
|
3552
3555
|
priceToUse = price;
|
|
3553
3556
|
} else if (data.previousPrice) {
|
|
3554
3557
|
priceToUse = new Decimal(data.previousPrice);
|
|
3555
|
-
} else if (!
|
|
3556
|
-
priceToUse =
|
|
3558
|
+
} else if (!currentSummary.end.open.getIsZero()) {
|
|
3559
|
+
priceToUse = currentSummary.end.value.divide(summary.end.open);
|
|
3557
3560
|
} else {
|
|
3558
3561
|
priceToUse = null;
|
|
3559
3562
|
}
|
|
3560
3563
|
|
|
3561
3564
|
if (priceToUse !== null) {
|
|
3562
|
-
const period =
|
|
3565
|
+
const period = currentSummary.period;
|
|
3563
3566
|
|
|
3564
|
-
let unrealized =
|
|
3567
|
+
let unrealized = currentSummary.end.open.multiply(priceToUse).add(currentSummary.end.basis);
|
|
3565
3568
|
let unrealizedChange;
|
|
3566
3569
|
|
|
3567
3570
|
if (data.unrealized !== null) {
|
|
@@ -3570,7 +3573,7 @@ module.exports = (() => {
|
|
|
3570
3573
|
unrealizedChange = Decimal.ZERO;
|
|
3571
3574
|
}
|
|
3572
3575
|
|
|
3573
|
-
let summaryTotalCurrent = period.realized.add(period.income).add(unrealized);
|
|
3576
|
+
let summaryTotalCurrent = period.realized.add(period.income).add(unrealized).subtract(previousSummary !== null ? previousSummary.period.unrealized : Decimal.ZERO);
|
|
3574
3577
|
let summaryTotalCurrentChange;
|
|
3575
3578
|
|
|
3576
3579
|
if (data.summaryTotalCurrent !== null) {
|
|
@@ -3598,13 +3601,13 @@ module.exports = (() => {
|
|
|
3598
3601
|
}
|
|
3599
3602
|
}
|
|
3600
3603
|
|
|
3601
|
-
function calculateSummaryTotal(
|
|
3604
|
+
function calculateSummaryTotal(currentSummary, previousSummary) {
|
|
3602
3605
|
let returnRef;
|
|
3603
3606
|
|
|
3604
|
-
if (
|
|
3605
|
-
const period =
|
|
3607
|
+
if (currentSummary) {
|
|
3608
|
+
const period = currentSummary.period;
|
|
3606
3609
|
|
|
3607
|
-
returnRef = period.realized.add(period.income).add(period.unrealized);
|
|
3610
|
+
returnRef = period.realized.add(period.income).add(period.unrealized).subtract(previousSummary !== null ? previousSummary.period.unrealized : Decimal.ZERO);
|
|
3608
3611
|
} else {
|
|
3609
3612
|
returnRef = Decimal.ZERO;
|
|
3610
3613
|
}
|
|
@@ -17249,8 +17252,12 @@ describe('When validating transaction order', () => {
|
|
|
17249
17252
|
expect(TransactionValidator.validateOrder([ build(1, '2018-04-30'), build(2, '2018-04-30', TransactionType.DIVIDEND) ])).toEqual(true);
|
|
17250
17253
|
});
|
|
17251
17254
|
|
|
17252
|
-
it('An array of transactions with ordered sequences, on the same day should be valid, where a dividend occurs first, should not be valid', () => {
|
|
17253
|
-
expect(TransactionValidator.validateOrder([ build(1, '2018-04-30', TransactionType.DIVIDEND), build(2, '2018-04-30') ])).toEqual(false);
|
|
17255
|
+
it('An array of transactions with ordered sequences, on the same day should be valid, where a dividend occurs first, in strict mode, should not be valid', () => {
|
|
17256
|
+
expect(TransactionValidator.validateOrder([ build(1, '2018-04-30', TransactionType.DIVIDEND), build(2, '2018-04-30') ], true)).toEqual(false);
|
|
17257
|
+
});
|
|
17258
|
+
|
|
17259
|
+
it('An array of transactions with ordered sequences, on the same day should be valid, where a dividend occurs first, in non-strict mode, should be valid', () => {
|
|
17260
|
+
expect(TransactionValidator.validateOrder([ build(1, '2018-04-30', TransactionType.DIVIDEND), build(2, '2018-04-30') ], false)).toEqual(true);
|
|
17254
17261
|
});
|
|
17255
17262
|
|
|
17256
17263
|
it('An array of transactions with ordered sequences, on the sequential days should be valid', () => {
|
|
@@ -22,8 +22,12 @@ describe('When validating transaction order', () => {
|
|
|
22
22
|
expect(TransactionValidator.validateOrder([ build(1, '2018-04-30'), build(2, '2018-04-30', TransactionType.DIVIDEND) ])).toEqual(true);
|
|
23
23
|
});
|
|
24
24
|
|
|
25
|
-
it('An array of transactions with ordered sequences, on the same day should be valid, where a dividend occurs first, should not be valid', () => {
|
|
26
|
-
expect(TransactionValidator.validateOrder([ build(1, '2018-04-30', TransactionType.DIVIDEND), build(2, '2018-04-30') ])).toEqual(false);
|
|
25
|
+
it('An array of transactions with ordered sequences, on the same day should be valid, where a dividend occurs first, in strict mode, should not be valid', () => {
|
|
26
|
+
expect(TransactionValidator.validateOrder([ build(1, '2018-04-30', TransactionType.DIVIDEND), build(2, '2018-04-30') ], true)).toEqual(false);
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
it('An array of transactions with ordered sequences, on the same day should be valid, where a dividend occurs first, in non-strict mode, should be valid', () => {
|
|
30
|
+
expect(TransactionValidator.validateOrder([ build(1, '2018-04-30', TransactionType.DIVIDEND), build(2, '2018-04-30') ], false)).toEqual(true);
|
|
27
31
|
});
|
|
28
32
|
|
|
29
33
|
it('An array of transactions with ordered sequences, on the sequential days should be valid', () => {
|