@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
- if (f.instrument.type === InstrumentType.FUTURE) {
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
- market: actual.market.add(translate(item, item.data.marketChange)),
899
- marketAbsolute: actual.marketAbsolute.add(translate(item, item.data.marketAbsoluteChange)),
900
- marketDirection: { up: item.data.marketChange.getIsPositive(), down: item.data.marketChange.getIsNegative() },
901
- unrealized: actual.unrealized.add(translate(item, item.data.unrealizedChange)),
902
- unrealizedToday: actual.unrealizedToday.add(translate(item, item.data.unrealizedTodayChange)),
903
- summaryTotalCurrent: actual.summaryTotalCurrent.add(translate(item, item.data.periodGainChange)),
904
- periodUnrealized: actual.periodUnrealized.add(translate(item, item.data.periodUnrealizedChange))
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;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@barchart/portfolio-api-common",
3
- "version": "1.20.0",
3
+ "version": "1.22.0",
4
4
  "description": "Common JavaScript code used by Barchart's Portfolio Service",
5
5
  "author": {
6
6
  "name": "Bryan Ingle",