@barchart/portfolio-api-common 1.19.0 → 1.21.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,99 @@
|
|
|
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 value of a position.
|
|
11
|
+
*
|
|
12
|
+
* @public
|
|
13
|
+
*/
|
|
14
|
+
class ValuationCalculator {
|
|
15
|
+
constructor() {
|
|
16
|
+
|
|
17
|
+
}
|
|
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
|
+
*/
|
|
29
|
+
static calculate(instrument, price, quantity) {
|
|
30
|
+
let priceToUse = null;
|
|
31
|
+
|
|
32
|
+
if (is.number(price)) {
|
|
33
|
+
priceToUse = new Decimal(price);
|
|
34
|
+
} else if (price instanceof Decimal) {
|
|
35
|
+
priceToUse = price;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
if (priceToUse === null) {
|
|
39
|
+
return null;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const calculator = calculators.get(instrument.type);
|
|
43
|
+
|
|
44
|
+
return calculator(instrument, priceToUse, quantity);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
toString() {
|
|
48
|
+
return `[ValuationCalculator]`;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function calculateForCash(instrument, price, quantity) {
|
|
53
|
+
return new Decimal(quantity);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function calculateForEquity(instrument, price, quantity) {
|
|
57
|
+
return price.multiply(quantity);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function calculateForEquityOption(instrument, price, quantity) {
|
|
61
|
+
const priceMultiplier = instrument.option.multiplier;
|
|
62
|
+
|
|
63
|
+
return price.multiply(priceMultiplier).multiply(quantity);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function calculateForFund(instrument, price, quantity) {
|
|
67
|
+
return price.multiply(quantity);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function calculateForFuture(instrument, price, quantity) {
|
|
71
|
+
const minimumTick = instrument.future.tick;
|
|
72
|
+
const minimumTickValue = instrument.future.value;
|
|
73
|
+
|
|
74
|
+
return price.divide(minimumTick).multiply(minimumTickValue).multiply(quantity);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function calculateForFutureOption(instrument, price, quantity) {
|
|
78
|
+
const minimumTick = instrument.option.tick;
|
|
79
|
+
const minimumTickValue = instrument.option.value;
|
|
80
|
+
|
|
81
|
+
return price.divide(minimumTick).multiply(minimumTickValue).multiply(quantity);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function calculateForOther(instrument, price, quantity) {
|
|
85
|
+
return price.multiply(quantity);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
const calculators = new Map();
|
|
89
|
+
|
|
90
|
+
calculators.set(InstrumentType.CASH, calculateForCash);
|
|
91
|
+
calculators.set(InstrumentType.EQUITY, calculateForEquity);
|
|
92
|
+
calculators.set(InstrumentType.EQUITY_OPTION, calculateForEquityOption);
|
|
93
|
+
calculators.set(InstrumentType.FUND, calculateForFund);
|
|
94
|
+
calculators.set(InstrumentType.FUTURE, calculateForFuture);
|
|
95
|
+
calculators.set(InstrumentType.FUTURE_OPTION, calculateForFutureOption);
|
|
96
|
+
calculators.set(InstrumentType.OTHER, calculateForOther);
|
|
97
|
+
|
|
98
|
+
return ValuationCalculator;
|
|
99
|
+
})();
|
|
@@ -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;
|
|
@@ -8,6 +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 ValuationCalculator = require('./../calculators/ValuationCalculator');
|
|
12
|
+
|
|
11
13
|
module.exports = (() => {
|
|
12
14
|
'use strict';
|
|
13
15
|
|
|
@@ -514,18 +516,8 @@ module.exports = (() => {
|
|
|
514
516
|
market = snapshot.value;
|
|
515
517
|
} else if (position.instrument.type === InstrumentType.CASH) {
|
|
516
518
|
market = snapshot.open;
|
|
517
|
-
} else if (position.instrument.type === InstrumentType.FUTURE) {
|
|
518
|
-
market = getFuturesValue(position.instrument, snapshot.open, price) || snapshot.value;
|
|
519
|
-
} else if (position.instrument.type === InstrumentType.FUTURE_OPTION) {
|
|
520
|
-
market = getFuturesOptionValue(position.instrument, snapshot.open, price) || snapshot.value;
|
|
521
|
-
} else if (position.instrument.type === InstrumentType.EQUITY_OPTION) {
|
|
522
|
-
market = getEquityOptionValue(position.instrument, snapshot.open, price) || snapshot.value;
|
|
523
519
|
} else {
|
|
524
|
-
|
|
525
|
-
market = snapshot.open.multiply(price);
|
|
526
|
-
} else {
|
|
527
|
-
market = snapshot.value;
|
|
528
|
-
}
|
|
520
|
+
market = ValuationCalculator.calculate(position.instrument, price, snapshot.open) || snapshot.value;
|
|
529
521
|
}
|
|
530
522
|
|
|
531
523
|
let marketChange;
|
|
@@ -555,17 +547,7 @@ module.exports = (() => {
|
|
|
555
547
|
let unrealizedTodayChange;
|
|
556
548
|
|
|
557
549
|
if (data.previousPrice && price) {
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
if (position.instrument.type === InstrumentType.FUTURE) {
|
|
561
|
-
unrealizedTodayBase = getFuturesValue(position.instrument, snapshot.open, data.previousPrice);
|
|
562
|
-
} else if (position.instrument.type === InstrumentType.FUTURE_OPTION) {
|
|
563
|
-
unrealizedTodayBase = getFuturesOptionValue(position.instrument, snapshot.open, data.previousPrice);
|
|
564
|
-
} else if (position.instrument.type === InstrumentType.EQUITY_OPTION) {
|
|
565
|
-
unrealizedTodayBase = getEquityOptionValue(position.instrument, snapshot.open, data.previousPrice);
|
|
566
|
-
} else {
|
|
567
|
-
unrealizedTodayBase = snapshot.open.multiply(data.previousPrice);
|
|
568
|
-
}
|
|
550
|
+
const unrealizedTodayBase = ValuationCalculator.calculate(position.instrument, data.previousPrice, snapshot.open);
|
|
569
551
|
|
|
570
552
|
unrealizedToday = market.subtract(unrealizedTodayBase);
|
|
571
553
|
|
|
@@ -599,17 +581,7 @@ module.exports = (() => {
|
|
|
599
581
|
}
|
|
600
582
|
|
|
601
583
|
if (priceToUse !== null) {
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
if (position.instrument.type === InstrumentType.FUTURE) {
|
|
605
|
-
unrealized = getFuturesValue(position.instrument, currentSummary.end.open, priceToUse).add(currentSummary.end.basis);
|
|
606
|
-
} else if (position.instrument.type === InstrumentType.FUTURE_OPTION) {
|
|
607
|
-
unrealized = getFuturesOptionValue(position.instrument, currentSummary.end.open, priceToUse).add(currentSummary.end.basis);
|
|
608
|
-
} else if (position.instrument.type === InstrumentType.EQUITY_OPTION) {
|
|
609
|
-
unrealized = getEquityOptionValue(position.instrument, currentSummary.end.open, priceToUse).add(currentSummary.end.basis);
|
|
610
|
-
} else {
|
|
611
|
-
unrealized = currentSummary.end.open.multiply(priceToUse).add(currentSummary.end.basis);
|
|
612
|
-
}
|
|
584
|
+
const unrealized = ValuationCalculator.calculate(position.instrument, priceToUse, currentSummary.end.open).add(currentSummary.end.basis);
|
|
613
585
|
|
|
614
586
|
let unrealizedChange;
|
|
615
587
|
|
|
@@ -694,15 +666,7 @@ module.exports = (() => {
|
|
|
694
666
|
let endValue;
|
|
695
667
|
|
|
696
668
|
if (overridePrice) {
|
|
697
|
-
|
|
698
|
-
endValue = getFuturesValue(instrument, currentSummary.end.open, overridePrice);
|
|
699
|
-
} else if (type === InstrumentType.FUTURE_OPTION) {
|
|
700
|
-
endValue = getFuturesOptionValue(instrument, currentSummary.end.open, overridePrice);
|
|
701
|
-
} else if (type === InstrumentType.EQUITY_OPTION) {
|
|
702
|
-
endValue = getEquityOptionValue(instrument, currentSummary.end.open, overridePrice);
|
|
703
|
-
} else {
|
|
704
|
-
endValue = currentSummary.end.open.multiply(overridePrice);
|
|
705
|
-
}
|
|
669
|
+
endValue = ValuationCalculator.calculate(instrument, overridePrice, currentSummary.end.open);
|
|
706
670
|
} else {
|
|
707
671
|
endValue = currentSummary.end.value;
|
|
708
672
|
}
|
|
@@ -823,44 +787,5 @@ module.exports = (() => {
|
|
|
823
787
|
return snapshot;
|
|
824
788
|
}
|
|
825
789
|
|
|
826
|
-
function getFuturesValue(instrument, contracts, price) {
|
|
827
|
-
if (price || price === 0) {
|
|
828
|
-
const priceDecimal = new Decimal(price);
|
|
829
|
-
|
|
830
|
-
const minimumTick = instrument.future.tick;
|
|
831
|
-
const minimumTickValue = instrument.future.value;
|
|
832
|
-
|
|
833
|
-
return priceDecimal.divide(minimumTick).multiply(minimumTickValue).multiply(contracts);
|
|
834
|
-
} else {
|
|
835
|
-
return null;
|
|
836
|
-
}
|
|
837
|
-
}
|
|
838
|
-
|
|
839
|
-
function getFuturesOptionValue(instrument, contracts, price) {
|
|
840
|
-
if (price || price === 0) {
|
|
841
|
-
const priceDecimal = new Decimal(price);
|
|
842
|
-
|
|
843
|
-
const minimumTick = instrument.option.tick;
|
|
844
|
-
const minimumTickValue = instrument.option.value;
|
|
845
|
-
|
|
846
|
-
const multiplier = instrument.option.multiplier;
|
|
847
|
-
|
|
848
|
-
return priceDecimal.divide(minimumTick).multiply(minimumTickValue).multiply(multiplier).multiply(contracts);
|
|
849
|
-
} else {
|
|
850
|
-
return null;
|
|
851
|
-
}
|
|
852
|
-
}
|
|
853
|
-
|
|
854
|
-
function getEquityOptionValue(instrument, contracts, price) {
|
|
855
|
-
if (price || price === 0) {
|
|
856
|
-
const priceDecimal = new Decimal(price);
|
|
857
|
-
const multiplier = instrument.option.multiplier;
|
|
858
|
-
|
|
859
|
-
return priceDecimal.multiply(contracts).multiply(multiplier);
|
|
860
|
-
} else {
|
|
861
|
-
return null;
|
|
862
|
-
}
|
|
863
|
-
}
|
|
864
|
-
|
|
865
790
|
return PositionItem;
|
|
866
791
|
})();
|