@barchart/portfolio-api-common 1.20.0 → 1.22.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.
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
const Decimal = require('@barchart/common-js/lang/Decimal'),
|
|
2
|
+
is = require('@barchart/common-js/lang/is');
|
|
3
|
+
|
|
4
|
+
const InstrumentType = require('./../data/InstrumentType');
|
|
5
|
+
|
|
6
|
+
module.exports = (() => {
|
|
7
|
+
'use strict';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Static utilities for calculating the average price of a position.
|
|
11
|
+
*
|
|
12
|
+
* @public
|
|
13
|
+
*/
|
|
14
|
+
class AveragePriceCalculator {
|
|
15
|
+
constructor() {
|
|
16
|
+
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Calculates the average price of a position.
|
|
21
|
+
*
|
|
22
|
+
* @public
|
|
23
|
+
* @static
|
|
24
|
+
* @param {Object} instrument
|
|
25
|
+
* @param {Decimal|Number} basis
|
|
26
|
+
* @param {Decimal|Number} quantity
|
|
27
|
+
* @returns {null|Decimal}
|
|
28
|
+
*/
|
|
29
|
+
static calculate(instrument, basis, quantity) {
|
|
30
|
+
let basisToUse = null;
|
|
31
|
+
|
|
32
|
+
if (is.number(basis)) {
|
|
33
|
+
basisToUse = new Decimal(basis);
|
|
34
|
+
} else if (basis instanceof Decimal) {
|
|
35
|
+
basisToUse = basis;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const calculator = calculators.get(instrument.type);
|
|
39
|
+
|
|
40
|
+
return calculator(instrument, basisToUse, quantity);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
toString() {
|
|
44
|
+
return `[AveragePriceCalculator]`;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function calculateForCash(instrument, basis, quantity) {
|
|
49
|
+
return Decimal.ONE;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function calculateForEquity(instrument, basis, quantity) {
|
|
53
|
+
if (basis === null) {
|
|
54
|
+
return null;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
if (quantity === Decimal.ZERO || quantity === 0) {
|
|
58
|
+
return null;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
return basis.divide(quantity).opposite();
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function calculateForEquityOption(instrument, basis, quantity) {
|
|
65
|
+
if (basis === null) {
|
|
66
|
+
return null;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
if (quantity === Decimal.ZERO || quantity === 0) {
|
|
70
|
+
return null;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
const multiplier = instrument.option.multiplier;
|
|
74
|
+
|
|
75
|
+
return basis.divide(quantity).divide(multiplier).opposite();
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
function calculateForFund(instrument, basis, quantity) {
|
|
79
|
+
if (basis === null) {
|
|
80
|
+
return null;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
if (quantity === Decimal.ZERO || quantity === 0) {
|
|
84
|
+
return null;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
return basis.divide(quantity).opposite();
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
function calculateForFuture(instrument, basis, quantity) {
|
|
91
|
+
if (basis === null) {
|
|
92
|
+
return null;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
if (quantity === Decimal.ZERO || quantity === 0) {
|
|
96
|
+
return null;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
const minimumTick = instrument.future.tick;
|
|
100
|
+
const minimumTickValue = instrument.future.value;
|
|
101
|
+
|
|
102
|
+
return basis.divide(quantity).multiply(minimumTick).divide(minimumTickValue).opposite();
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
function calculateForFutureOption(instrument, basis, quantity) {
|
|
106
|
+
if (basis === null) {
|
|
107
|
+
return null;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
if (quantity === Decimal.ZERO || quantity === 0) {
|
|
111
|
+
return null;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
const minimumTick = instrument.option.tick;
|
|
115
|
+
const minimumTickValue = instrument.option.value;
|
|
116
|
+
|
|
117
|
+
return basis.divide(quantity).multiply(minimumTick).divide(minimumTickValue).opposite();
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
function calculateForOther(instrument, basis, quantity) {
|
|
121
|
+
if (basis === null) {
|
|
122
|
+
return null;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
if (quantity === Decimal.ZERO || quantity === 0) {
|
|
126
|
+
return null;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
return basis.divide(quantity).opposite();
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
const calculators = new Map();
|
|
133
|
+
|
|
134
|
+
calculators.set(InstrumentType.CASH, calculateForCash);
|
|
135
|
+
calculators.set(InstrumentType.EQUITY, calculateForEquity);
|
|
136
|
+
calculators.set(InstrumentType.EQUITY_OPTION, calculateForEquityOption);
|
|
137
|
+
calculators.set(InstrumentType.FUND, calculateForFund);
|
|
138
|
+
calculators.set(InstrumentType.FUTURE, calculateForFuture);
|
|
139
|
+
calculators.set(InstrumentType.FUTURE_OPTION, calculateForFutureOption);
|
|
140
|
+
calculators.set(InstrumentType.OTHER, calculateForOther);
|
|
141
|
+
|
|
142
|
+
return AveragePriceCalculator;
|
|
143
|
+
})();
|
|
@@ -5,12 +5,27 @@ const InstrumentType = require('./../data/InstrumentType');
|
|
|
5
5
|
|
|
6
6
|
module.exports = (() => {
|
|
7
7
|
'use strict';
|
|
8
|
-
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Static utilities for calculating the value of a position.
|
|
11
|
+
*
|
|
12
|
+
* @public
|
|
13
|
+
*/
|
|
9
14
|
class ValuationCalculator {
|
|
10
15
|
constructor() {
|
|
11
16
|
|
|
12
17
|
}
|
|
13
18
|
|
|
19
|
+
/**
|
|
20
|
+
* Calculates the value of a position.
|
|
21
|
+
*
|
|
22
|
+
* @public
|
|
23
|
+
* @static
|
|
24
|
+
* @param {Object} instrument
|
|
25
|
+
* @param {Decimal|Number} price
|
|
26
|
+
* @param {Decimal|Number} quantity
|
|
27
|
+
* @returns {null|Decimal}
|
|
28
|
+
*/
|
|
14
29
|
static calculate(instrument, price, quantity) {
|
|
15
30
|
let priceToUse = null;
|
|
16
31
|
|
|
@@ -9,6 +9,8 @@ const assert = require('@barchart/common-js/lang/assert'),
|
|
|
9
9
|
const InstrumentType = require('./../data/InstrumentType'),
|
|
10
10
|
TransactionType = require('./../data/TransactionType');
|
|
11
11
|
|
|
12
|
+
const AveragePriceCalculator = require('./../calculators/AveragePriceCalculator');
|
|
13
|
+
|
|
12
14
|
module.exports = (() => {
|
|
13
15
|
'use strict';
|
|
14
16
|
|
|
@@ -139,14 +141,7 @@ module.exports = (() => {
|
|
|
139
141
|
let average;
|
|
140
142
|
|
|
141
143
|
if (basis && open && !open.getIsZero()) {
|
|
142
|
-
|
|
143
|
-
const minimumTick = f.instrument.future.tick;
|
|
144
|
-
const minimumTickValue = f.instrument.future.value;
|
|
145
|
-
|
|
146
|
-
average = basis.divide(open).multiply(minimumTick).divide(minimumTickValue).absolute();
|
|
147
|
-
} else {
|
|
148
|
-
average = basis.divide(open).absolute();
|
|
149
|
-
}
|
|
144
|
+
average = AveragePriceCalculator.calculate(f.instrument, basis, open);
|
|
150
145
|
} else {
|
|
151
146
|
average = '';
|
|
152
147
|
}
|
|
@@ -122,9 +122,11 @@ module.exports = (() => {
|
|
|
122
122
|
|
|
123
123
|
this._dataActual.currentPrice = null;
|
|
124
124
|
this._dataActual.basis = null;
|
|
125
|
+
this._dataActual.basis2 = null;
|
|
125
126
|
this._dataActual.realized = null;
|
|
126
127
|
this._dataActual.income = null;
|
|
127
128
|
this._dataActual.market = null;
|
|
129
|
+
this._dataActual.market2 = null;
|
|
128
130
|
this._dataActual.marketPercent = null;
|
|
129
131
|
this._dataActual.marketPercentPortfolio = null;
|
|
130
132
|
this._dataActual.unrealized = null;
|
|
@@ -145,10 +147,12 @@ module.exports = (() => {
|
|
|
145
147
|
|
|
146
148
|
this._dataFormat.currentPrice = null;
|
|
147
149
|
this._dataFormat.basis = null;
|
|
150
|
+
this._dataFormat.basis2 = null;
|
|
148
151
|
this._dataFormat.realized = null;
|
|
149
152
|
this._dataFormat.realizedPercent = null;
|
|
150
153
|
this._dataFormat.income = null;
|
|
151
154
|
this._dataFormat.market = null;
|
|
155
|
+
this._dataFormat.market2 = null;
|
|
152
156
|
this._dataFormat.marketPercent = null;
|
|
153
157
|
this._dataFormat.marketPercentPortfolio = null;
|
|
154
158
|
this._dataFormat.marketDirection = null;
|
|
@@ -716,6 +720,15 @@ module.exports = (() => {
|
|
|
716
720
|
|
|
717
721
|
let updates = items.reduce((updates, item) => {
|
|
718
722
|
updates.basis = updates.basis.add(translate(item, item.data.basis));
|
|
723
|
+
|
|
724
|
+
if (item.position.instrument.type === InstrumentType.FUTURE) {
|
|
725
|
+
if (group.single) {
|
|
726
|
+
updates.basis2 = null;
|
|
727
|
+
}
|
|
728
|
+
} else {
|
|
729
|
+
updates.basis2 = updates.basis2.add(translate(item, item.data.basis));
|
|
730
|
+
}
|
|
731
|
+
|
|
719
732
|
updates.realized = updates.realized.add(translate(item, item.data.realized));
|
|
720
733
|
updates.unrealized = updates.unrealized.add(translate(item, item.data.unrealized));
|
|
721
734
|
updates.income = updates.income.add(translate(item, item.data.income));
|
|
@@ -741,6 +754,7 @@ module.exports = (() => {
|
|
|
741
754
|
return updates;
|
|
742
755
|
}, {
|
|
743
756
|
basis: Decimal.ZERO,
|
|
757
|
+
basis2: Decimal.ZERO,
|
|
744
758
|
realized: Decimal.ZERO,
|
|
745
759
|
unrealized: Decimal.ZERO,
|
|
746
760
|
income: Decimal.ZERO,
|
|
@@ -760,6 +774,7 @@ module.exports = (() => {
|
|
|
760
774
|
});
|
|
761
775
|
|
|
762
776
|
actual.basis = updates.basis;
|
|
777
|
+
actual.basis2 = updates.basis2;
|
|
763
778
|
actual.realized = updates.realized;
|
|
764
779
|
actual.unrealized = updates.unrealized;
|
|
765
780
|
actual.income = updates.income;
|
|
@@ -778,6 +793,7 @@ module.exports = (() => {
|
|
|
778
793
|
actual.periodDivisorPrevious2 = updates.periodDivisorPrevious2;
|
|
779
794
|
|
|
780
795
|
format.basis = formatCurrency(actual.basis, currency);
|
|
796
|
+
format.basis2 = formatCurrency(actual.basis2, currency);
|
|
781
797
|
format.realized = formatCurrency(actual.realized, currency);
|
|
782
798
|
format.unrealized = formatCurrency(actual.unrealized, currency);
|
|
783
799
|
format.income = formatCurrency(actual.income, currency);
|
|
@@ -877,6 +893,13 @@ module.exports = (() => {
|
|
|
877
893
|
|
|
878
894
|
updates = items.reduce((updates, item) => {
|
|
879
895
|
updates.market = updates.market.add(translate(item, item.data.market));
|
|
896
|
+
|
|
897
|
+
if (item.position.instrument.type === InstrumentType.FUTURE) {
|
|
898
|
+
updates.market2 = updates.market2.add(translate(item, item.data.unrealized));
|
|
899
|
+
} else {
|
|
900
|
+
updates.market2 = updates.market2.add(translate(item, item.data.market));
|
|
901
|
+
}
|
|
902
|
+
|
|
880
903
|
updates.marketAbsolute = updates.marketAbsolute.add(translate(item, item.data.marketAbsolute));
|
|
881
904
|
updates.unrealized = updates.unrealized.add(translate(item, item.data.unrealized));
|
|
882
905
|
updates.unrealizedToday = updates.unrealizedToday.add(translate(item, item.data.unrealizedToday));
|
|
@@ -886,6 +909,7 @@ module.exports = (() => {
|
|
|
886
909
|
return updates;
|
|
887
910
|
}, {
|
|
888
911
|
market: Decimal.ZERO,
|
|
912
|
+
market2: Decimal.ZERO,
|
|
889
913
|
marketAbsolute: Decimal.ZERO,
|
|
890
914
|
marketDirection: unchanged,
|
|
891
915
|
unrealized: Decimal.ZERO,
|
|
@@ -894,18 +918,26 @@ module.exports = (() => {
|
|
|
894
918
|
periodUnrealized: Decimal.ZERO
|
|
895
919
|
});
|
|
896
920
|
} else {
|
|
897
|
-
updates = {
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
}
|
|
921
|
+
updates = { };
|
|
922
|
+
|
|
923
|
+
updates.market = actual.market.add(translate(item, item.data.marketChange));
|
|
924
|
+
|
|
925
|
+
if (item.position.instrument.type === InstrumentType.FUTURE) {
|
|
926
|
+
updates.market2 = actual.market2.add(translate(item, item.data.unrealizedChange));
|
|
927
|
+
} else {
|
|
928
|
+
updates.market2 = actual.market2.add(translate(item, item.data.marketChange));
|
|
929
|
+
}
|
|
930
|
+
|
|
931
|
+
updates.marketAbsolute = actual.marketAbsolute.add(translate(item, item.data.marketAbsoluteChange));
|
|
932
|
+
updates.marketDirection = { up: item.data.marketChange.getIsPositive(), down: item.data.marketChange.getIsNegative() };
|
|
933
|
+
updates.unrealized = actual.unrealized.add(translate(item, item.data.unrealizedChange));
|
|
934
|
+
updates.unrealizedToday = actual.unrealizedToday.add(translate(item, item.data.unrealizedTodayChange));
|
|
935
|
+
updates.summaryTotalCurrent = actual.summaryTotalCurrent.add(translate(item, item.data.periodGainChange));
|
|
936
|
+
updates.periodUnrealized = actual.periodUnrealized.add(translate(item, item.data.periodUnrealizedChange));
|
|
906
937
|
}
|
|
907
938
|
|
|
908
939
|
actual.market = updates.market;
|
|
940
|
+
actual.market2 = updates.market2;
|
|
909
941
|
actual.marketAbsolute = updates.marketAbsolute;
|
|
910
942
|
actual.unrealized = updates.unrealized;
|
|
911
943
|
actual.unrealizedToday = updates.unrealizedToday;
|
|
@@ -934,6 +966,7 @@ module.exports = (() => {
|
|
|
934
966
|
actual.marketChangePercent = marketChangePercent;
|
|
935
967
|
|
|
936
968
|
format.market = formatCurrency(actual.market, currency);
|
|
969
|
+
format.market2 = formatCurrency(actual.market2, currency);
|
|
937
970
|
|
|
938
971
|
if (updates.marketDirection.up || updates.marketDirection.down) {
|
|
939
972
|
format.marketDirection = unchanged;
|