@barchart/portfolio-api-common 1.23.0 → 1.25.0
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.
|
@@ -24,7 +24,7 @@ module.exports = (() => {
|
|
|
24
24
|
* @param {Object} instrument
|
|
25
25
|
* @param {Decimal|Number} basis
|
|
26
26
|
* @param {Decimal|Number} quantity
|
|
27
|
-
* @returns {null
|
|
27
|
+
* @returns {Decimal|null}
|
|
28
28
|
*/
|
|
29
29
|
static calculate(instrument, basis, quantity) {
|
|
30
30
|
let basisToUse = null;
|
|
@@ -34,10 +34,18 @@ module.exports = (() => {
|
|
|
34
34
|
} else if (basis instanceof Decimal) {
|
|
35
35
|
basisToUse = basis;
|
|
36
36
|
}
|
|
37
|
+
|
|
38
|
+
let quantityToUse = null;
|
|
39
|
+
|
|
40
|
+
if (is.number(basis)) {
|
|
41
|
+
quantityToUse = new Decimal(quantity);
|
|
42
|
+
} else if (basis instanceof Decimal) {
|
|
43
|
+
quantityToUse = quantity;
|
|
44
|
+
}
|
|
37
45
|
|
|
38
46
|
const calculator = calculators.get(instrument.type);
|
|
39
47
|
|
|
40
|
-
return calculator(instrument, basisToUse,
|
|
48
|
+
return calculator(instrument, basisToUse, quantityToUse);
|
|
41
49
|
}
|
|
42
50
|
|
|
43
51
|
toString() {
|
|
@@ -50,11 +58,7 @@ module.exports = (() => {
|
|
|
50
58
|
}
|
|
51
59
|
|
|
52
60
|
function calculateForEquity(instrument, basis, quantity) {
|
|
53
|
-
if (basis === null) {
|
|
54
|
-
return null;
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
if (quantity === Decimal.ZERO || quantity === 0) {
|
|
61
|
+
if (basis === null || quantity === null || quantity.getIsZero()) {
|
|
58
62
|
return null;
|
|
59
63
|
}
|
|
60
64
|
|
|
@@ -62,11 +66,7 @@ module.exports = (() => {
|
|
|
62
66
|
}
|
|
63
67
|
|
|
64
68
|
function calculateForEquityOption(instrument, basis, quantity) {
|
|
65
|
-
if (basis === null) {
|
|
66
|
-
return null;
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
if (quantity === Decimal.ZERO || quantity === 0) {
|
|
69
|
+
if (basis === null || quantity === null || quantity.getIsZero()) {
|
|
70
70
|
return null;
|
|
71
71
|
}
|
|
72
72
|
|
|
@@ -76,11 +76,7 @@ module.exports = (() => {
|
|
|
76
76
|
}
|
|
77
77
|
|
|
78
78
|
function calculateForFund(instrument, basis, quantity) {
|
|
79
|
-
if (basis === null) {
|
|
80
|
-
return null;
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
if (quantity === Decimal.ZERO || quantity === 0) {
|
|
79
|
+
if (basis === null || quantity === null || quantity.getIsZero()) {
|
|
84
80
|
return null;
|
|
85
81
|
}
|
|
86
82
|
|
|
@@ -88,11 +84,7 @@ module.exports = (() => {
|
|
|
88
84
|
}
|
|
89
85
|
|
|
90
86
|
function calculateForFuture(instrument, basis, quantity) {
|
|
91
|
-
if (basis === null) {
|
|
92
|
-
return null;
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
if (quantity === Decimal.ZERO || quantity === 0) {
|
|
87
|
+
if (basis === null || quantity === null || quantity.getIsZero()) {
|
|
96
88
|
return null;
|
|
97
89
|
}
|
|
98
90
|
|
|
@@ -103,11 +95,7 @@ module.exports = (() => {
|
|
|
103
95
|
}
|
|
104
96
|
|
|
105
97
|
function calculateForFutureOption(instrument, basis, quantity) {
|
|
106
|
-
if (basis === null) {
|
|
107
|
-
return null;
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
if (quantity === Decimal.ZERO || quantity === 0) {
|
|
98
|
+
if (basis === null || quantity === null || quantity.getIsZero()) {
|
|
111
99
|
return null;
|
|
112
100
|
}
|
|
113
101
|
|
|
@@ -118,11 +106,7 @@ module.exports = (() => {
|
|
|
118
106
|
}
|
|
119
107
|
|
|
120
108
|
function calculateForOther(instrument, basis, quantity) {
|
|
121
|
-
if (basis === null) {
|
|
122
|
-
return null;
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
if (quantity === Decimal.ZERO || quantity === 0) {
|
|
109
|
+
if (basis === null || quantity === null || quantity.getIsZero()) {
|
|
126
110
|
return null;
|
|
127
111
|
}
|
|
128
112
|
|
|
@@ -6,6 +6,8 @@ const assert = require('@barchart/common-js/lang/assert'),
|
|
|
6
6
|
is = require('@barchart/common-js/lang/is'),
|
|
7
7
|
formatter = require('@barchart/common-js/lang/formatter');
|
|
8
8
|
|
|
9
|
+
formatter.numberToFraction = require('@barchart/marketdata-api-js/lib/utilities/format/fraction');
|
|
10
|
+
|
|
9
11
|
const InstrumentType = require('./../data/InstrumentType'),
|
|
10
12
|
TransactionType = require('./../data/TransactionType');
|
|
11
13
|
|
|
@@ -32,12 +34,14 @@ module.exports = (() => {
|
|
|
32
34
|
* @param {Object[]} transactions
|
|
33
35
|
* @param {Object[]} positions
|
|
34
36
|
* @param {Boolean=} descending
|
|
37
|
+
* @param {Boolean=} fractions
|
|
35
38
|
* @returns {Array}
|
|
36
39
|
*/
|
|
37
|
-
static format(transactions, positions, descending) {
|
|
40
|
+
static format(transactions, positions, descending, fractions) {
|
|
38
41
|
assert.argumentIsArray(transactions, 'transactions');
|
|
39
42
|
assert.argumentIsArray(positions, 'positions');
|
|
40
43
|
assert.argumentIsOptional(descending, 'descending', Boolean);
|
|
44
|
+
assert.argumentIsOptional(fractions, 'fractions', Boolean);
|
|
41
45
|
|
|
42
46
|
const instruments = positions.reduce((map, p) => {
|
|
43
47
|
const instrument = Object.assign({ }, p.instrument || { });
|
|
@@ -52,7 +56,7 @@ module.exports = (() => {
|
|
|
52
56
|
|
|
53
57
|
if (instruments.hasOwnProperty(position)) {
|
|
54
58
|
let instrument = instruments[position];
|
|
55
|
-
let formatted = { instrument, raw: {} };
|
|
59
|
+
let formatted = { instrument, raw: { } };
|
|
56
60
|
|
|
57
61
|
const formatterFunctions = formatters.get(transaction.type);
|
|
58
62
|
|
|
@@ -60,13 +64,21 @@ module.exports = (() => {
|
|
|
60
64
|
formatterFunction(transaction, formatted);
|
|
61
65
|
});
|
|
62
66
|
|
|
67
|
+
const code = instrument.code;
|
|
68
|
+
|
|
63
69
|
Object.keys(formatted).forEach((key) => {
|
|
64
70
|
const value = formatted[key];
|
|
65
71
|
|
|
66
72
|
if (value instanceof Decimal) {
|
|
67
|
-
|
|
73
|
+
if (fractions && code && code.supportsFractions && (instrument.type === InstrumentType.FUTURE || instrument.type === InstrumentType.FUTURE_OPTION) && keys.fractions.some(k => k === key)) {
|
|
74
|
+
const rounded = code.roundToNearestTick(value.toFloat(), instrument.future ? instrument.future.tick : instrument.option.tick, true);
|
|
75
|
+
|
|
76
|
+
formatted[key] = formatter.numberToFraction(rounded, code.fractionFactor, code.fractionDigits, '-', true);
|
|
77
|
+
} else {
|
|
78
|
+
const precision = instrument.currency.precision;
|
|
68
79
|
|
|
69
|
-
|
|
80
|
+
formatted[key] = formatter.numberToString(value.toFloat(), precision, ',');
|
|
81
|
+
}
|
|
70
82
|
}
|
|
71
83
|
});
|
|
72
84
|
|
|
@@ -122,6 +134,10 @@ module.exports = (() => {
|
|
|
122
134
|
}
|
|
123
135
|
}
|
|
124
136
|
|
|
137
|
+
const keys = { };
|
|
138
|
+
|
|
139
|
+
keys.fractions = [ 'average', 'price' ];
|
|
140
|
+
|
|
125
141
|
const basicFormatter = (t, f) => {
|
|
126
142
|
f.date = t.date;
|
|
127
143
|
f.type = t.type.display;
|
|
@@ -147,6 +163,7 @@ module.exports = (() => {
|
|
|
147
163
|
}
|
|
148
164
|
|
|
149
165
|
f.average = average;
|
|
166
|
+
f.raw.average = getRawForDecimal(average);
|
|
150
167
|
};
|
|
151
168
|
|
|
152
169
|
const buySellFormatter = (t, f) => {
|
|
@@ -9,6 +9,8 @@ const array = require('@barchart/common-js/lang/array'),
|
|
|
9
9
|
is = require('@barchart/common-js/lang/is'),
|
|
10
10
|
Rate = require('@barchart/common-js/lang/Rate');
|
|
11
11
|
|
|
12
|
+
const fractionFormatter = require('@barchart/marketdata-api-js/lib/utilities/format/fraction');
|
|
13
|
+
|
|
12
14
|
const InstrumentType = require('./../data/InstrumentType');
|
|
13
15
|
|
|
14
16
|
const PositionLevelDefinition = require('./definitions/PositionLevelDefinition'),
|
|
@@ -24,9 +26,9 @@ module.exports = (() => {
|
|
|
24
26
|
* all the positions and performs currency translation, as necessary.
|
|
25
27
|
*
|
|
26
28
|
* @public
|
|
27
|
-
* @param {PositionContainer} container
|
|
28
29
|
* @param {PositionLevelDefinition} definition
|
|
29
30
|
* @param {PositionItem[]} items
|
|
31
|
+
* @param {Rate[]} rates
|
|
30
32
|
* @param {Currency} currency
|
|
31
33
|
* @param {String} key
|
|
32
34
|
* @param {String} description
|
|
@@ -78,6 +80,7 @@ module.exports = (() => {
|
|
|
78
80
|
this._dataFormat.quantity = null;
|
|
79
81
|
this._dataFormat.quantityPrevious = null;
|
|
80
82
|
this._dataFormat.basisPrice = null;
|
|
83
|
+
this._dataFormat.unrealizedPrice = null;
|
|
81
84
|
|
|
82
85
|
this._dataActual.key = this._key;
|
|
83
86
|
this._dataActual.description = this._description;
|
|
@@ -85,6 +88,7 @@ module.exports = (() => {
|
|
|
85
88
|
this._dataActual.quantity = null;
|
|
86
89
|
this._dataActual.quantityPrevious = null;
|
|
87
90
|
this._dataActual.basisPrice = null;
|
|
91
|
+
this._dataActual.unrealizedPrice = null;
|
|
88
92
|
|
|
89
93
|
if (this._single && items.length === 1) {
|
|
90
94
|
const item = items[0];
|
|
@@ -218,10 +222,10 @@ module.exports = (() => {
|
|
|
218
222
|
}
|
|
219
223
|
|
|
220
224
|
/**
|
|
221
|
-
* The {@link
|
|
225
|
+
* The {@link PositionLevelDefinition} which was used to generate this group.
|
|
222
226
|
*
|
|
223
227
|
* @public
|
|
224
|
-
* @returns {
|
|
228
|
+
* @returns {PositionLevelDefinition}
|
|
225
229
|
*/
|
|
226
230
|
get definition() {
|
|
227
231
|
return this._definition;
|
|
@@ -516,10 +520,12 @@ module.exports = (() => {
|
|
|
516
520
|
function bindItem(item) {
|
|
517
521
|
const quoteBinding = item.registerQuoteChangeHandler((quote, sender) => {
|
|
518
522
|
if (this._single) {
|
|
519
|
-
const
|
|
523
|
+
const instrument = sender.position.instrument;
|
|
524
|
+
const currency = instrument.currency;
|
|
525
|
+
const precision = currency.precision;
|
|
520
526
|
|
|
521
527
|
this._dataActual.currentPrice = quote.lastPrice;
|
|
522
|
-
this._dataFormat.currentPrice =
|
|
528
|
+
this._dataFormat.currentPrice = formatFraction(this._dataActual.currentPrice, currency, instrument);
|
|
523
529
|
|
|
524
530
|
this._dataActual.quoteLast = quote.previousPrice;
|
|
525
531
|
this._dataActual.quoteOpen = quote.openPrice;
|
|
@@ -534,7 +540,8 @@ module.exports = (() => {
|
|
|
534
540
|
this._dataFormat.quoteOpen = formatNumber(this._dataActual.quoteOpen, precision);
|
|
535
541
|
this._dataFormat.quoteHigh = formatNumber(this._dataActual.quoteHigh, precision);
|
|
536
542
|
this._dataFormat.quoteLow = formatNumber(this._dataActual.quoteLow, precision);
|
|
537
|
-
this._dataFormat.quoteChange =
|
|
543
|
+
this._dataFormat.quoteChange = formatFraction(this._dataActual.quoteChange, currency, instrument);
|
|
544
|
+
|
|
538
545
|
this._dataFormat.quoteChangePercent = formatPercent(new Decimal(this._dataActual.quoteChangePercent || 0), 2);
|
|
539
546
|
this._dataFormat.quoteTime = this._dataActual.quoteTime;
|
|
540
547
|
this._dataFormat.quoteVolume = formatNumber(this._dataActual.quoteVolume, 0);
|
|
@@ -660,6 +667,27 @@ module.exports = (() => {
|
|
|
660
667
|
}));
|
|
661
668
|
}
|
|
662
669
|
|
|
670
|
+
function formatFraction(value, currency, instrument) {
|
|
671
|
+
let decimal = value instanceof Decimal;
|
|
672
|
+
|
|
673
|
+
if (instrument && value !== null) {
|
|
674
|
+
const type = instrument.type;
|
|
675
|
+
const code = instrument.code;
|
|
676
|
+
|
|
677
|
+
if (code && code.supportsFractions && (type === InstrumentType.FUTURE || type === InstrumentType.FUTURE_OPTION)) {
|
|
678
|
+
const rounded = code.roundToNearestTick(decimal ? value.toFloat() : value, instrument.future ? instrument.future.tick : instrument.option.tick, true);
|
|
679
|
+
|
|
680
|
+
return fractionFormatter(rounded, code.fractionFactor, code.fractionDigits, '-', true);
|
|
681
|
+
}
|
|
682
|
+
}
|
|
683
|
+
|
|
684
|
+
if (decimal) {
|
|
685
|
+
return formatDecimal(value, currency.precision);
|
|
686
|
+
} else {
|
|
687
|
+
return formatNumber(value, currency.precision);
|
|
688
|
+
}
|
|
689
|
+
}
|
|
690
|
+
|
|
663
691
|
function formatNumber(number, precision) {
|
|
664
692
|
if (is.number(number)) {
|
|
665
693
|
return formatter.numberToString(number, precision, ',', false);
|
|
@@ -825,6 +853,7 @@ module.exports = (() => {
|
|
|
825
853
|
|
|
826
854
|
if (group.single && groupItems.length === 1) {
|
|
827
855
|
const item = group._items[0];
|
|
856
|
+
const instrument = item.position.instrument;
|
|
828
857
|
|
|
829
858
|
actual.quantity = item.data.quantity;
|
|
830
859
|
actual.quantityPrevious = item.data.quantityPrevious;
|
|
@@ -833,8 +862,7 @@ module.exports = (() => {
|
|
|
833
862
|
format.quantityPrevious = formatDecimal(actual.quantityPrevious, 2);
|
|
834
863
|
|
|
835
864
|
actual.basisPrice = item.data.basisPrice;
|
|
836
|
-
|
|
837
|
-
format.basisPrice = formatCurrency(actual.basisPrice, currency);
|
|
865
|
+
format.basisPrice = formatFraction(actual.basisPrice, currency, instrument);
|
|
838
866
|
|
|
839
867
|
actual.periodPrice = item.data.periodPrice;
|
|
840
868
|
actual.periodPricePrevious = item.data.periodPricePrevious;
|
|
@@ -842,6 +870,9 @@ module.exports = (() => {
|
|
|
842
870
|
format.periodPrice = formatCurrency(actual.periodPrice, currency);
|
|
843
871
|
format.periodPricePrevious = formatCurrency(actual.periodPricePrevious, currency);
|
|
844
872
|
|
|
873
|
+
actual.unrealizedPrice = item.data.unrealizedPrice;
|
|
874
|
+
format.unrealizedPrice = formatFraction(actual.unrealizedPrice, currency, instrument);
|
|
875
|
+
|
|
845
876
|
format.invalid = definition.type === PositionLevelType.POSITION && item.invalid;
|
|
846
877
|
format.locked = definition.type === PositionLevelType.POSITION && item.data.locked;
|
|
847
878
|
format.calculating = definition.type === PositionLevelType.POSITION && item.data.calculating;
|
|
@@ -996,6 +1027,11 @@ module.exports = (() => {
|
|
|
996
1027
|
|
|
997
1028
|
actual.periodPercent = calculateGainPercent(actual.summaryTotalCurrent, actual.periodDivisorCurrent);
|
|
998
1029
|
format.periodPercent = formatPercent(actual.periodPercent, 2);
|
|
1030
|
+
|
|
1031
|
+
if (group.single && item) {
|
|
1032
|
+
actual.unrealizedPrice = item.data.unrealizedPrice;
|
|
1033
|
+
format.unrealizedPrice = formatFraction(actual.unrealizedPrice, currency, item.position.instrument);
|
|
1034
|
+
}
|
|
999
1035
|
}
|
|
1000
1036
|
|
|
1001
1037
|
function calculateMarketPercent(group, rates, parentGroup, portfolioGroup) {
|
|
@@ -8,7 +8,8 @@ const assert = require('@barchart/common-js/lang/assert'),
|
|
|
8
8
|
const InstrumentType = require('./../data/InstrumentType'),
|
|
9
9
|
PositionDirection = require('./../data/PositionDirection');
|
|
10
10
|
|
|
11
|
-
const
|
|
11
|
+
const AveragePriceCalculator = require('./../calculators/AveragePriceCalculator'),
|
|
12
|
+
ValuationCalculator = require('./../calculators/ValuationCalculator');
|
|
12
13
|
|
|
13
14
|
module.exports = (() => {
|
|
14
15
|
'use strict';
|
|
@@ -73,7 +74,9 @@ module.exports = (() => {
|
|
|
73
74
|
|
|
74
75
|
this._data.realized = null;
|
|
75
76
|
this._data.income = null;
|
|
77
|
+
|
|
76
78
|
this._data.basisPrice = null;
|
|
79
|
+
this._data.unrealizedPrice = null;
|
|
77
80
|
|
|
78
81
|
this._data.periodIncome = null;
|
|
79
82
|
this._data.periodRealized = null;
|
|
@@ -478,16 +481,8 @@ module.exports = (() => {
|
|
|
478
481
|
data.periodDivisorPrevious = calculatePeriodDivisor(position.instrument.type, data.initiate, previousSummary1, previousSummary2);
|
|
479
482
|
data.periodDivisorPrevious2 = calculatePeriodDivisor(position.instrument.type, data.initiate, previousSummary2, previousSummary3);
|
|
480
483
|
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
} else if (position.instrument.type === InstrumentType.FUTURE) {
|
|
484
|
-
const minimumTick = position.instrument.future.tick;
|
|
485
|
-
const minimumTickValue = position.instrument.future.value;
|
|
486
|
-
|
|
487
|
-
data.basisPrice = basis.divide(snapshot.open).divide(minimumTickValue).multiply(minimumTick);
|
|
488
|
-
} else {
|
|
489
|
-
data.basisPrice = basis.divide(snapshot.open);
|
|
490
|
-
}
|
|
484
|
+
data.basisPrice = AveragePriceCalculator.calculate(position.instrument, data.basis, snapshot.open) || Decimal.ZERO;
|
|
485
|
+
data.basisPrice = data.basisPrice.opposite();
|
|
491
486
|
|
|
492
487
|
if (currentSummary && !currentSummary.end.open.getIsZero()) {
|
|
493
488
|
data.periodPrice = currentSummary.end.value.divide(currentSummary.end.open);
|
|
@@ -617,6 +612,12 @@ module.exports = (() => {
|
|
|
617
612
|
|
|
618
613
|
data.periodUnrealized = periodUnrealized;
|
|
619
614
|
data.periodUnrealizedChange = periodUnrealizedChange;
|
|
615
|
+
|
|
616
|
+
if (snapshot.open.getIsZero()) {
|
|
617
|
+
data.unrealizedPrice = null;
|
|
618
|
+
} else {
|
|
619
|
+
data.unrealizedPrice = data.basisPrice.opposite().add(priceToUse);
|
|
620
|
+
}
|
|
620
621
|
} else {
|
|
621
622
|
data.unrealizedChange = Decimal.ZERO;
|
|
622
623
|
data.periodUnrealizedChange = Decimal.ZERO;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@barchart/portfolio-api-common",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.25.0",
|
|
4
4
|
"description": "Common JavaScript code used by Barchart's Portfolio Service",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Bryan Ingle",
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
},
|
|
17
17
|
"dependencies": {
|
|
18
18
|
"@barchart/common-js": "^4.27.0",
|
|
19
|
-
"@barchart/marketdata-api-js": "^6.2.
|
|
19
|
+
"@barchart/marketdata-api-js": "^6.2.1",
|
|
20
20
|
"uuid": "^8.3.2"
|
|
21
21
|
},
|
|
22
22
|
"devDependencies": {
|