@barchart/portfolio-api-common 1.18.0 → 1.20.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.
@@ -280,6 +280,17 @@ module.exports = (() => {
280
280
  return transactionCreateFailedInstrumentCorrupt;
281
281
  }
282
282
 
283
+ /**
284
+ * The transaction failed because instrument metadata could not be resolved.
285
+ *
286
+ * @public
287
+ * @static
288
+ * @returns {FailureType}
289
+ */
290
+ static get TRANSACTION_CREATE_FAILED_INSTRUMENT_UNAVAILABLE() {
291
+ return transactionCreateFailedInstrumentUnavailable;
292
+ }
293
+
283
294
  /**
284
295
  * The transaction (of this type) cannot be deleted by a user, instead,
285
296
  * it is created and managed by the system (e.g. dividends).
@@ -449,6 +460,7 @@ module.exports = (() => {
449
460
  const transactionCreateFailedReinvestInvalid = new FailureType('TRANSACTION_CREATE_FAILED_REINVEST_INVALID', 'Unable to create transaction, short positions do not allow dividends to be reinvested.');
450
461
  const transactionCreateFailedPositionLocked = new FailureType('TRANSACTION_CREATE_FAILED_POSITION_LOCKED', 'Unable to create transaction, your {L|description} history is being recalculated. Please re-enter this transaction in a minute or two.');
451
462
  const transactionCreateFailedInstrumentCorrupt = new FailureType('TRANSACTION_CREATE_FAILED_INSTRUMENT_CORRUPT', 'Unable to create transaction, corporate action history for {U|symbol} cannot be located. The issue should be corrected within 24 to 48 hours.');
463
+ const transactionCreateFailedInstrumentUnavailable = new FailureType('TRANSACTION_CREATE_FAILED_INSTRUMENT_UNAVAILABLE', 'Unable to create transaction, no {L|description} instrument was found with the symbol {U|symbol}.');
452
464
 
453
465
  const transactionDeleteFailedOutOfSequence = new FailureType('TRANSACTION_DELETE_FAILED_OUT_OF_SEQUENCE', 'Deleting any transaction, except for the most recent, will cause transaction history to be re-written. Please confirm your intent to re-write transaction history (which could take some time and alter the historical results for this position).');
454
466
  const transactionDeleteFailedNoTransaction = new FailureType('TRANSACTION_DELETE_FAILED_NO_TRANSACTION', 'Unable to delete transaction. The referenced transaction does not exist.', false);
@@ -0,0 +1,84 @@
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
+ class ValuationCalculator {
10
+ constructor() {
11
+
12
+ }
13
+
14
+ static calculate(instrument, price, quantity) {
15
+ let priceToUse = null;
16
+
17
+ if (is.number(price)) {
18
+ priceToUse = new Decimal(price);
19
+ } else if (price instanceof Decimal) {
20
+ priceToUse = price;
21
+ }
22
+
23
+ if (priceToUse === null) {
24
+ return null;
25
+ }
26
+
27
+ const calculator = calculators.get(instrument.type);
28
+
29
+ return calculator(instrument, priceToUse, quantity);
30
+ }
31
+
32
+ toString() {
33
+ return `[ValuationCalculator]`;
34
+ }
35
+ }
36
+
37
+ function calculateForCash(instrument, price, quantity) {
38
+ return new Decimal(quantity);
39
+ }
40
+
41
+ function calculateForEquity(instrument, price, quantity) {
42
+ return price.multiply(quantity);
43
+ }
44
+
45
+ function calculateForEquityOption(instrument, price, quantity) {
46
+ const priceMultiplier = instrument.option.multiplier;
47
+
48
+ return price.multiply(priceMultiplier).multiply(quantity);
49
+ }
50
+
51
+ function calculateForFund(instrument, price, quantity) {
52
+ return price.multiply(quantity);
53
+ }
54
+
55
+ function calculateForFuture(instrument, price, quantity) {
56
+ const minimumTick = instrument.future.tick;
57
+ const minimumTickValue = instrument.future.value;
58
+
59
+ return price.divide(minimumTick).multiply(minimumTickValue).multiply(quantity);
60
+ }
61
+
62
+ function calculateForFutureOption(instrument, price, quantity) {
63
+ const minimumTick = instrument.option.tick;
64
+ const minimumTickValue = instrument.option.value;
65
+
66
+ return price.divide(minimumTick).multiply(minimumTickValue).multiply(quantity);
67
+ }
68
+
69
+ function calculateForOther(instrument, price, quantity) {
70
+ return price.multiply(quantity);
71
+ }
72
+
73
+ const calculators = new Map();
74
+
75
+ calculators.set(InstrumentType.CASH, calculateForCash);
76
+ calculators.set(InstrumentType.EQUITY, calculateForEquity);
77
+ calculators.set(InstrumentType.EQUITY_OPTION, calculateForEquityOption);
78
+ calculators.set(InstrumentType.FUND, calculateForFund);
79
+ calculators.set(InstrumentType.FUTURE, calculateForFuture);
80
+ calculators.set(InstrumentType.FUTURE_OPTION, calculateForFutureOption);
81
+ calculators.set(InstrumentType.OTHER, calculateForOther);
82
+
83
+ return ValuationCalculator;
84
+ })();
@@ -1,5 +1,4 @@
1
- const Enum = require('@barchart/common-js/lang/Enum'),
2
- is = require('@barchart/common-js/lang/is');
1
+ const Enum = require('@barchart/common-js/lang/Enum');
3
2
 
4
3
  module.exports = (() => {
5
4
  'use strict';
@@ -120,14 +119,14 @@ module.exports = (() => {
120
119
  }
121
120
  }
122
121
 
123
- const split = new CorporateActionType('SPLIT', 'Split', false);
124
- const dividend = new CorporateActionType('DIVIDEND', 'Dividend', false);
125
- const stockDividend = new CorporateActionType('STOCK_DIVIDEND', 'Stock Dividend', false);
126
- const symbolChange = new CorporateActionType('SYMBOL_CHANGE', 'Symbol Change', false);
127
- const nameChange = new CorporateActionType('NAME_CHANGE', 'Name Change', false);
128
- const delist = new CorporateActionType('DELIST', 'Delist', false);
129
- const merger = new CorporateActionType('MERGER', 'Merger', false);
130
- const spinoff = new CorporateActionType('SPINOFF', 'Spinoff', false);
122
+ const split = new CorporateActionType('SPLIT', 'Split');
123
+ const dividend = new CorporateActionType('DIVIDEND', 'Dividend');
124
+ const stockDividend = new CorporateActionType('STOCK_DIVIDEND', 'Stock Dividend');
125
+ const symbolChange = new CorporateActionType('SYMBOL_CHANGE', 'Symbol Change');
126
+ const nameChange = new CorporateActionType('NAME_CHANGE', 'Name Change');
127
+ const delist = new CorporateActionType('DELIST', 'Delist');
128
+ const merger = new CorporateActionType('MERGER', 'Merger');
129
+ const spinoff = new CorporateActionType('SPINOFF', 'Spinoff');
131
130
 
132
131
  return CorporateActionType;
133
132
  })();
@@ -173,6 +173,26 @@ module.exports = (() => {
173
173
  return this._roundQuantity;
174
174
  }
175
175
 
176
+ /**
177
+ * Indicates if the instrument is a futures contract.
178
+ *
179
+ * @public
180
+ * @returns {boolean}
181
+ */
182
+ get future() {
183
+ return this === future;
184
+ }
185
+
186
+ /**
187
+ * Indicates if the instrument is an option contract.
188
+ *
189
+ * @public
190
+ * @returns {boolean}
191
+ */
192
+ get option() {
193
+ return this === equityOption || this === futureOption;
194
+ }
195
+
176
196
  /**
177
197
  * Generates an identifier for the instrument.
178
198
  *
@@ -212,6 +232,17 @@ module.exports = (() => {
212
232
  return equity;
213
233
  }
214
234
 
235
+ /**
236
+ * An option on equity shares.
237
+ *
238
+ * @public
239
+ * @static
240
+ * @returns {InstrumentType}
241
+ */
242
+ static get EQUITY_OPTION() {
243
+ return equityOption;
244
+ }
245
+
215
246
  /**
216
247
  * A mutual fund.
217
248
  *
@@ -234,6 +265,17 @@ module.exports = (() => {
234
265
  return future;
235
266
  }
236
267
 
268
+ /**
269
+ * An option on a futures contract.
270
+ *
271
+ * @public
272
+ * @static
273
+ * @returns {InstrumentType}
274
+ */
275
+ static get FUTURE_OPTION() {
276
+ return futureOption;
277
+ }
278
+
237
279
  /**
238
280
  * An undefined asset (e.g. a house, or a collectible, or a salvaged alien spaceship).
239
281
  *
@@ -281,10 +323,14 @@ module.exports = (() => {
281
323
 
282
324
  if (code === 1 || code === 6 || code === 7 || code === 11) {
283
325
  return InstrumentType.EQUITY;
326
+ } else if (code === 34) {
327
+ return InstrumentType.EQUITY_OPTION;
284
328
  } else if (code === 5 || code == 15) {
285
329
  return InstrumentType.FUND;
286
330
  } else if (code === 2) {
287
331
  return InstrumentType.FUTURE;
332
+ } else if (code === 12) {
333
+ return InstrumentType.FUTURE_OPTION;
288
334
  } else {
289
335
  throw new Error(`Unable to determine InstrumentType for [ ${code} ]`);
290
336
  }
@@ -297,8 +343,10 @@ module.exports = (() => {
297
343
 
298
344
  const cash = new InstrumentType('CASH', 'cash', 'Cash', true, false, false, true, false, false, true, false, false, false, instrument => `BARCHART-${instrument.type.code}-${instrument.currency.code}`);
299
345
  const equity = new InstrumentType('EQUITY', 'equity', 'Equities', false, true, true, false, true, true, true, true, true, true, instrument => `BARCHART-${instrument.type.code}-${instrument.symbol.barchart}`);
346
+ const equityOption = new InstrumentType('EQUITY_OPTION', 'equity option', 'Equity Option', false, false, true, false, true, false, false, false, false, true, instrument => `BARCHART-${instrument.type.code}-${instrument.symbol.barchart}`);
300
347
  const fund = new InstrumentType('FUND', 'mutual fund', 'Funds', false, true, false, false, true, true, true,false, true, true, instrument => `BARCHART-${instrument.type.code}-${instrument.symbol.barchart}`);
301
348
  const future = new InstrumentType('FUTURE', 'futures contract', 'Futures', false, false, true, false, true, false, false, false, false, true, instrument => `BARCHART-${instrument.type.code}-${instrument.symbol.barchart}`);
349
+ const futureOption = new InstrumentType('FUTURE_OPTION', 'futures option', 'Futures Option', false, false, true, false, true, false, false, false, false, true, instrument => `BARCHART-${instrument.type.code}-${instrument.symbol.barchart}`);
302
350
  const other = new InstrumentType('OTHER', 'other', 'Other', false, false, false, false, false, false, true,false, true, true, instrument => `BARCHART-${instrument.type.code}-${uuid.v4()}`);
303
351
 
304
352
  return InstrumentType;
@@ -0,0 +1,61 @@
1
+ const Enum = require('@barchart/common-js/lang/Enum');
2
+
3
+ module.exports = (() => {
4
+ 'use strict';
5
+
6
+ /**
7
+ * Indicates whether an option conveys the right to buy or
8
+ * sell the underlying instrument.
9
+ *
10
+ * @public
11
+ * @extends {Enum}
12
+ * @param {String} code
13
+ * @param {String} description
14
+ */
15
+ class OptionSide extends Enum {
16
+ constructor(code, description) {
17
+ super(code, description);
18
+ }
19
+
20
+ /**
21
+ * The right to buy the underlying instrument.
22
+ *
23
+ * @public
24
+ * @static
25
+ * @returns {OptionSide}
26
+ */
27
+ static get CALL() {
28
+ return call;
29
+ }
30
+
31
+ /**
32
+ * The right to sell the underlying instrument.
33
+ *
34
+ * @public
35
+ * @static
36
+ * @returns {OptionSide}
37
+ */
38
+ static get PUT() {
39
+ return put;
40
+ }
41
+
42
+ /**
43
+ * @public
44
+ * @static
45
+ * @param {String} code
46
+ * @returns {OptionSide|null}
47
+ */
48
+ static parse(code) {
49
+ return Enum.fromCode(OptionSide, code);
50
+ }
51
+
52
+ toString() {
53
+ return `[OptionSide (code=${this.code})]`;
54
+ }
55
+ }
56
+
57
+ const put = new OptionSide('PUT', 'Put');
58
+ const call = new OptionSide('CALL', 'Call');
59
+
60
+ return OptionSide;
61
+ })();
@@ -250,6 +250,11 @@ module.exports = (() => {
250
250
  associateTypes(InstrumentType.EQUITY, TransactionType.SPINOFF, false);
251
251
  associateTypes(InstrumentType.EQUITY, TransactionType.SPINOFF_OPEN, false);
252
252
 
253
+ associateTypes(InstrumentType.EQUITY_OPTION, TransactionType.BUY, true, [ PositionDirection.LONG, PositionDirection.EVEN ]);
254
+ associateTypes(InstrumentType.EQUITY_OPTION, TransactionType.SELL, true, [ PositionDirection.LONG ]);
255
+ associateTypes(InstrumentType.EQUITY_OPTION, TransactionType.SELL_SHORT, true, [ PositionDirection.SHORT, PositionDirection.EVEN ]);
256
+ associateTypes(InstrumentType.EQUITY_OPTION, TransactionType.BUY_SHORT, true, [ PositionDirection.SHORT ]);
257
+
253
258
  associateTypes(InstrumentType.FUND, TransactionType.BUY, true, [ PositionDirection.LONG, PositionDirection.EVEN ]);
254
259
  associateTypes(InstrumentType.FUND, TransactionType.SELL, true, [ PositionDirection.LONG ]);
255
260
  associateTypes(InstrumentType.FUND, TransactionType.FEE, true, [ PositionDirection.LONG ]);
@@ -268,6 +273,11 @@ module.exports = (() => {
268
273
  associateTypes(InstrumentType.FUTURE, TransactionType.SELL_SHORT, true, [ PositionDirection.SHORT, PositionDirection.EVEN ]);
269
274
  associateTypes(InstrumentType.FUTURE, TransactionType.BUY_SHORT, true, [ PositionDirection.SHORT ]);
270
275
 
276
+ associateTypes(InstrumentType.FUTURE_OPTION, TransactionType.BUY, true, [ PositionDirection.LONG, PositionDirection.EVEN ]);
277
+ associateTypes(InstrumentType.FUTURE_OPTION, TransactionType.SELL, true, [ PositionDirection.LONG ]);
278
+ associateTypes(InstrumentType.FUTURE_OPTION, TransactionType.SELL_SHORT, true, [ PositionDirection.SHORT, PositionDirection.EVEN ]);
279
+ associateTypes(InstrumentType.FUTURE_OPTION, TransactionType.BUY_SHORT, true, [ PositionDirection.SHORT ]);
280
+
271
281
  associateTypes(InstrumentType.OTHER, TransactionType.BUY, true, [ PositionDirection.LONG, PositionDirection.EVEN ]);
272
282
  associateTypes(InstrumentType.OTHER, TransactionType.SELL, true, [ PositionDirection.LONG ]);
273
283
  associateTypes(InstrumentType.OTHER, TransactionType.INCOME, true, [ PositionDirection.LONG ]);
@@ -295,6 +305,10 @@ module.exports = (() => {
295
305
  associateDirections(InstrumentType.EQUITY, PositionDirection.LONG);
296
306
  associateDirections(InstrumentType.EQUITY, PositionDirection.SHORT);
297
307
 
308
+ associateDirections(InstrumentType.EQUITY_OPTION, PositionDirection.EVEN);
309
+ associateDirections(InstrumentType.EQUITY_OPTION, PositionDirection.LONG);
310
+ associateDirections(InstrumentType.EQUITY_OPTION, PositionDirection.SHORT);
311
+
298
312
  associateDirections(InstrumentType.FUND, PositionDirection.EVEN);
299
313
  associateDirections(InstrumentType.FUND, PositionDirection.LONG);
300
314
 
@@ -302,6 +316,10 @@ module.exports = (() => {
302
316
  associateDirections(InstrumentType.FUTURE, PositionDirection.LONG);
303
317
  associateDirections(InstrumentType.FUTURE, PositionDirection.SHORT);
304
318
 
319
+ associateDirections(InstrumentType.FUTURE_OPTION, PositionDirection.EVEN);
320
+ associateDirections(InstrumentType.FUTURE_OPTION, PositionDirection.LONG);
321
+ associateDirections(InstrumentType.FUTURE_OPTION, PositionDirection.SHORT);
322
+
305
323
  associateDirections(InstrumentType.OTHER, PositionDirection.EVEN);
306
324
  associateDirections(InstrumentType.OTHER, PositionDirection.LONG);
307
325
 
@@ -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,14 +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
519
  } else {
520
- if (price) {
521
- market = snapshot.open.multiply(price);
522
- } else {
523
- market = snapshot.value;
524
- }
520
+ market = ValuationCalculator.calculate(position.instrument, price, snapshot.open) || snapshot.value;
525
521
  }
526
522
 
527
523
  let marketChange;
@@ -551,13 +547,7 @@ module.exports = (() => {
551
547
  let unrealizedTodayChange;
552
548
 
553
549
  if (data.previousPrice && price) {
554
- let unrealizedTodayBase;
555
-
556
- if (position.instrument.type === InstrumentType.FUTURE) {
557
- unrealizedTodayBase = getFuturesValue(position.instrument, snapshot.open, data.previousPrice);
558
- } else {
559
- unrealizedTodayBase = snapshot.open.multiply(data.previousPrice);
560
- }
550
+ const unrealizedTodayBase = ValuationCalculator.calculate(position.instrument, data.previousPrice, snapshot.open);
561
551
 
562
552
  unrealizedToday = market.subtract(unrealizedTodayBase);
563
553
 
@@ -591,13 +581,7 @@ module.exports = (() => {
591
581
  }
592
582
 
593
583
  if (priceToUse !== null) {
594
- let unrealized;
595
-
596
- if (position.instrument.type === InstrumentType.FUTURE) {
597
- unrealized = getFuturesValue(position.instrument, currentSummary.end.open, priceToUse).add(currentSummary.end.basis);
598
- } else {
599
- unrealized = currentSummary.end.open.multiply(priceToUse).add(currentSummary.end.basis);
600
- }
584
+ const unrealized = ValuationCalculator.calculate(position.instrument, priceToUse, currentSummary.end.open).add(currentSummary.end.basis);
601
585
 
602
586
  let unrealizedChange;
603
587
 
@@ -682,11 +666,7 @@ module.exports = (() => {
682
666
  let endValue;
683
667
 
684
668
  if (overridePrice) {
685
- if (type === InstrumentType.FUTURE) {
686
- endValue = getFuturesValue(instrument, currentSummary.end.open, overridePrice);
687
- } else {
688
- endValue = currentSummary.end.open.multiply(overridePrice);
689
- }
669
+ endValue = ValuationCalculator.calculate(instrument, overridePrice, currentSummary.end.open);
690
670
  } else {
691
671
  endValue = currentSummary.end.value;
692
672
  }
@@ -807,18 +787,5 @@ module.exports = (() => {
807
787
  return snapshot;
808
788
  }
809
789
 
810
- function getFuturesValue(instrument, contracts, price) {
811
- if (price || price === 0) {
812
- const priceDecimal = new Decimal(price);
813
-
814
- const minimumTick = instrument.future.tick;
815
- const minimumTickValue = instrument.future.value;
816
-
817
- return priceDecimal.divide(minimumTick).multiply(minimumTickValue).multiply(contracts);
818
- } else {
819
- return null;
820
- }
821
- }
822
-
823
790
  return PositionItem;
824
791
  })();
@@ -5,6 +5,7 @@ const Currency = require('@barchart/common-js/lang/Currency'),
5
5
  SchemaBuilder = require('@barchart/common-js/serialization/json/builders/SchemaBuilder');
6
6
 
7
7
  const InstrumentType = require('./../data/InstrumentType'),
8
+ OptionSide = require('./../data/OptionSide'),
8
9
  PositionDirection = require('./../data/PositionDirection'),
9
10
  ValuationType = require('./../data/ValuationType');
10
11
 
@@ -95,7 +96,11 @@ module.exports = (() => {
95
96
  .withField('instrument.future.tick', DataType.DECIMAL, true)
96
97
  .withField('instrument.future.value', DataType.DECIMAL, true)
97
98
  .withField('instrument.option.expiration', DataType.DAY, true)
99
+ .withField('instrument.option.side', DataType.forEnum(OptionSide, 'OptionSide'), true)
98
100
  .withField('instrument.option.strike', DataType.DECIMAL, true)
101
+ .withField('instrument.option.multiplier', DataType.DECIMAL, true)
102
+ .withField('instrument.option.tick', DataType.DECIMAL, true)
103
+ .withField('instrument.option.value', DataType.DECIMAL, true)
99
104
  .withField('instrument.symbol.barchart', DataType.STRING, true)
100
105
  .withField('instrument.symbol.display', DataType.STRING, true)
101
106
  .withField('position', DataType.STRING)
@@ -136,7 +141,11 @@ module.exports = (() => {
136
141
  .withField('instrument.future.tick', DataType.DECIMAL, true)
137
142
  .withField('instrument.future.value', DataType.DECIMAL, true)
138
143
  .withField('instrument.option.expiration', DataType.DAY, true)
144
+ .withField('instrument.option.side', DataType.forEnum(OptionSide, 'OptionSide'), true)
139
145
  .withField('instrument.option.strike', DataType.DECIMAL, true)
146
+ .withField('instrument.option.multiplier', DataType.DECIMAL, true)
147
+ .withField('instrument.option.tick', DataType.DECIMAL, true)
148
+ .withField('instrument.option.value', DataType.DECIMAL, true)
140
149
  .withField('instrument.symbol.barchart', DataType.STRING, true)
141
150
  .withField('instrument.symbol.display', DataType.STRING, true)
142
151
  .withField('position', DataType.STRING)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@barchart/portfolio-api-common",
3
- "version": "1.18.0",
3
+ "version": "1.20.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.1.0",
19
+ "@barchart/marketdata-api-js": "^6.1.1",
20
20
  "uuid": "^8.3.2"
21
21
  },
22
22
  "devDependencies": {