@barchart/portfolio-api-common 1.2.114 → 1.2.118

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.
@@ -88,6 +88,18 @@ module.exports = (() => {
88
88
  static get TRANSACTION_CREATE_FAILED_OUT_OF_SEQUENCE() {
89
89
  return transactionCreateFailedOutOfSequence;
90
90
  }
91
+
92
+ /**
93
+ * The transaction date is invalid.
94
+ * For example create opening transaction after delist date.
95
+ *
96
+ * @public
97
+ * @static
98
+ * @returns {FailureType}
99
+ */
100
+ static get TRANSACTION_CREATE_FAILED_INVALID_DATE() {
101
+ return transactionCreateFailedInvalidDate;
102
+ }
91
103
 
92
104
  /**
93
105
  * @public
@@ -164,6 +176,18 @@ module.exports = (() => {
164
176
  static get TRANSACTION_CREATE_FAILED_POSITION_LOCKED() {
165
177
  return transactionCreateFailedPositionLocked;
166
178
  }
179
+
180
+ /**
181
+ * The transaction (of this type) cannot be deleted by a user, instead,
182
+ * it is created and managed by the system (e.g. dividends).
183
+ *
184
+ * @public
185
+ * @static
186
+ * @returns {FailureType}
187
+ */
188
+ static get TRANSACTION_DELETE_FAILED_TYPE_RESERVED() {
189
+ return transactionDeleteFailedTypeReserved;
190
+ }
167
191
 
168
192
  /**
169
193
  * Deleting any transaction except for the most recent requires
@@ -209,6 +233,18 @@ module.exports = (() => {
209
233
  static get TRANSACTION_DELETE_FAILED_POSITION_LOCKED() {
210
234
  return transactionDeleteFailedPositionLocked;
211
235
  }
236
+
237
+ /**
238
+ * The transaction date is invalid.
239
+ * For example edit opening transaction after delist date.
240
+ *
241
+ * @public
242
+ * @static
243
+ * @returns {FailureType}
244
+ */
245
+ static get TRANSACTION_EDIT_FAILED_INVALID_DATE() {
246
+ return transactionEditFailedInvalidDate;
247
+ }
212
248
 
213
249
  /**
214
250
  * Unable to edit, the transaction doesn't exist.
@@ -247,10 +283,12 @@ module.exports = (() => {
247
283
 
248
284
  const transactionCreateFailedNoPosition = new FailureType('TRANSACTION_CREATE_FAILED_NO_POSITION', 'Unable to create transaction. The referenced position does not exist. Has it been deleted?');
249
285
  const transactionCreateFailedOutOfSequence = new FailureType('TRANSACTION_CREATE_FAILED_OUT_OF_SEQUENCE', 'Unable to process transaction, because the transaction date is out-of-sequence. In other words, it would occur before an existing transaction. Please confirm your intent to re-write transaction history (which could take some time and alter the historical results for this position).');
286
+ const transactionCreateFailedInvalidDate = new FailureType('TRANSACTION_CREATE_FAILED_INVALID_DATE', 'Unable to process transaction with given date.');
250
287
  const transactionCreateFailedTypeInvalidForInstrument = new FailureType('TRANSACTION_CREATE_FAILED_TYPE_INVALID_FOR_INSTRUMENT', 'Unable to process transaction, {L|transactionType.description} transactions cannot be used with {L|instrumentType.description} positions.');
251
288
  const transactionCreateFailedTypeInvalidForDirection = new FailureType('TRANSACTION_CREATE_FAILED_TYPE_INVALID_FOR_DIRECTION', 'Unable to process transaction, a {L|positionDirection.description} position would be created (i.e. you would have {L|positionDirection.sign} shares/units). {u|instrumentType.description} positions cannot have {L|positionDirection.description} positions.');
252
289
  const transactionCreateFailedInvalidDirectionSwitch = new FailureType('TRANSACTION_CREATE_FAILED_INVALID_DIRECTION_SWITCH', 'Unable to process transaction, the transaction would switch the position from {L|currentDirection.description} to {L|proposedDirection.description} (i.e. {L|currentDirection.sign} to {L|proposedDirection.sign} shares/units). This is not allowed. Please close the current position (i.e. zero it out) and then enter a second transaction.');
253
290
  const transactionCreateFailedInvalidInitialType = new FailureType('TRANSACTION_CREATE_FAILED_INVALID_INITIAL_TYPE', 'Unable to process operation because the first transaction would to be a {U|transactionType.description}, which is not allowed -- since {U|transactionType.description} transactions cannot open a position.');
291
+
254
292
  const transactionCreateFailedTypeReserved = new FailureType('TRANSACTION_CREATE_FAILED_TYPE_RESERVED', 'Unable to create {U|type.description} transaction, this type of transaction is managed by the system.');
255
293
  const transactionCreateFailedReinvestPriceUnavailable = new FailureType('TRANSACTION_CREATE_FAILED_REINVEST_PRICE_UNAVAILABLE', 'Unable to create transaction, a dividend was paid on {L|day}; however no historical price is available for this day. To successfully create this transaction, please turn off dividend reinvestment for this position.');
256
294
  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.');
@@ -259,9 +297,11 @@ module.exports = (() => {
259
297
  const transactionDeleteFailedNoTransaction = new FailureType('TRANSACTION_DELETE_FAILED_NO_TRANSACTION', 'Unable to delete transaction. The referenced transaction does not exist.');
260
298
  const transactionDeleteFailedDirectionSwitchOnRewrite = new FailureType('TRANSACTION_DELETE_FAILED_DIRECTION_SWITCH_ON_REWRITE', 'Deleting this transaction would cause your history to be re-written and the position to switch from long to short (i.e. positive to negative) or vice versa.');
261
299
  const transactionDeleteFailedPositionLocked = new FailureType('TRANSACTION_DELETE_FAILED_POSITION_LOCKED', 'Unable to delete transaction, your {L|description} history is being recalculated. Please wait a minute or two and retry.');
300
+ const transactionDeleteFailedTypeReserved = new FailureType('TRANSACTION_DELETE_FAILED_TYPE_RESERVED', 'Unable to delete {U|type.description} transaction, this type of transaction is managed by the system.');
262
301
 
302
+ const transactionEditFailedInvalidDate = new FailureType('TRANSACTION_EDIT_FAILED_INVALID_DATE', 'Unable to edit transaction with given date.');
263
303
  const transactionEditFailedNoTransaction = new FailureType('TRANSACTION_EDIT_FAILED_NO_TRANSACTION', 'Unable to edit transaction. The referenced transaction does not exist.');
264
304
  const transactionEditFailedTypeReserved = new FailureType('TRANSACTION_EDIT_FAILED_TYPE_RESERVED', 'Unable to edit {U|type.description} transaction, this type of transaction is managed by the system.');
265
305
 
266
306
  return PortfolioFailureType;
267
- })();
307
+ })();
@@ -22,7 +22,6 @@ module.exports = (() => {
22
22
  * @param {Boolean} corporateAction
23
23
  * @param {Boolean} initial
24
24
  * @param {Boolean} significant
25
- * @param {Boolean} eod
26
25
  */
27
26
  class TransactionType extends Enum {
28
27
  constructor(code, description, display, sequence, purchase, sale, income, opening, closing, fee, corporateAction, initial, significant) {
@@ -352,6 +351,17 @@ module.exports = (() => {
352
351
  static get DEBIT() {
353
352
  return debit;
354
353
  }
354
+
355
+ /**
356
+ * A system-generated transaction, indicating the security has stopped active trading.
357
+ *
358
+ * @public
359
+ * @static
360
+ * @returns {TransactionType}
361
+ */
362
+ static get DELIST() {
363
+ return delist;
364
+ }
355
365
 
356
366
  /**
357
367
  * A system-generated deposit, arising from another transaction.
@@ -401,6 +411,7 @@ module.exports = (() => {
401
411
  const split = new TransactionType('SP', 'Split', 'Split', 1, false, false, false, true, false, false, true, false, false);
402
412
  const fee = new TransactionType('F', 'Fee', 'Fee', 0, false, false, false, false, false, true, false, false, false);
403
413
  const feeUnits = new TransactionType('FU', 'Fee Units', 'Fee', 0, false, false, false, false, true, false, false, false, false);
414
+ const delist = new TransactionType('DL', 'Delist', 'Delist', 1, false, false, false, false, false, false, true, false, false);
404
415
 
405
416
  const distributionCash = new TransactionType('DC', 'Distribution (Cash)', 'Cash Distribution', 1, false, false, true, false, false, false, true, false, false);
406
417
  const distributionReinvest = new TransactionType('DY', 'Distribution (Reinvested)', 'Distribution Reinvest', 1, false, false, false, true, false, false, true, false, false);
@@ -1,6 +1,7 @@
1
1
  const assert = require('@barchart/common-js/lang/assert'),
2
2
  array = require('@barchart/common-js/lang/array'),
3
- is = require('@barchart/common-js/lang/is');
3
+ is = require('@barchart/common-js/lang/is'),
4
+ Day = require('@barchart/common-js/lang/Day');
4
5
 
5
6
  const InstrumentType = require('./InstrumentType'),
6
7
  PositionDirection = require('./PositionDirection'),
@@ -217,6 +218,23 @@ module.exports = (() => {
217
218
  static validateDirectionSwitch(instrumentType, currentDirection, proposedDirection) {
218
219
  return currentDirection === null || instrumentType.canSwitchDirection || (currentDirection.closed || proposedDirection.closed || currentDirection.positive === proposedDirection.positive);
219
220
  }
221
+
222
+ /**
223
+ * Assuming the transaction list is ordered by sequence, validates that
224
+ * no opening transactions exist after delisting date.
225
+ *
226
+ * @static
227
+ * @public
228
+ * @param {Array.<Object>} transactions
229
+ * @returns {Boolean}
230
+ */
231
+ static validateDelisting(transactions) {
232
+ assert.argumentIsArray(transactions, 'transactions');
233
+
234
+ const delistIndex = transactions.findIndex(t => t.type === TransactionType.DELIST);
235
+
236
+ return delistIndex < 0 || !transactions.some((t, i) => delistIndex < i && t.type.opening);
237
+ }
220
238
 
221
239
  toString() {
222
240
  return '[TransactionValidator]';
@@ -244,6 +262,7 @@ module.exports = (() => {
244
262
  associateTypes(InstrumentType.EQUITY, TransactionType.DIVIDEND_REINVEST, false);
245
263
  associateTypes(InstrumentType.EQUITY, TransactionType.DIVIDEND_STOCK, false);
246
264
  associateTypes(InstrumentType.EQUITY, TransactionType.SPLIT, false);
265
+ associateTypes(InstrumentType.EQUITY, TransactionType.DELIST, false);
247
266
 
248
267
  associateTypes(InstrumentType.FUND, TransactionType.BUY, true, [ PositionDirection.LONG, PositionDirection.EVEN ]);
249
268
  associateTypes(InstrumentType.FUND, TransactionType.SELL, true, [ PositionDirection.LONG ]);
@@ -252,6 +271,7 @@ module.exports = (() => {
252
271
  associateTypes(InstrumentType.FUND, TransactionType.DISTRIBUTION_CASH, false);
253
272
  associateTypes(InstrumentType.FUND, TransactionType.DISTRIBUTION_REINVEST, false);
254
273
  associateTypes(InstrumentType.FUND, TransactionType.DISTRIBUTION_FUND, false);
274
+ associateTypes(InstrumentType.FUND, TransactionType.DELIST, false);
255
275
 
256
276
  associateTypes(InstrumentType.OTHER, TransactionType.BUY, true, [ PositionDirection.LONG, PositionDirection.EVEN ]);
257
277
  associateTypes(InstrumentType.OTHER, TransactionType.SELL, true, [ PositionDirection.LONG ]);
@@ -216,7 +216,7 @@ module.exports = (() => {
216
216
  formatters.set(TransactionType.INCOME, (t) => {
217
217
  return {
218
218
  total: t.income.amount
219
- };
219
+ };
220
220
  });
221
221
 
222
222
  formatters.set(TransactionType.FEE, (t) => {
@@ -254,6 +254,10 @@ module.exports = (() => {
254
254
  price: rate
255
255
  };
256
256
  });
257
+
258
+ formatters.set(TransactionType.DELIST, () => {
259
+ return { };
260
+ });
257
261
 
258
262
  const cashFormatter = (t) => {
259
263
  return {
@@ -298,4 +302,4 @@ module.exports = (() => {
298
302
  .toComparator();
299
303
 
300
304
  return TransactionFormatter;
301
- })();
305
+ })();
@@ -786,9 +786,9 @@ module.exports = (() => {
786
786
  actual.periodUnrealizedBasisPrevious = item.data.periodUnrealizedBasisPrevious;
787
787
  actual.periodUnrealizedBasisPrevious2 = item.data.periodUnrealizedBasisPrevious2;
788
788
 
789
- actual.periodPercent = calculatePeriodPercent(actual.periodRealized, actual.periodRealizedBasis, actual.periodUnrealized, actual.periodUnrealizedBasis);
790
- actual.periodPercentPrevious = calculatePeriodPercent(actual.periodRealizedPrevious, actual.periodRealizedBasisPrevious, actual.periodUnrealizedPrevious, actual.periodUnrealizedBasisPrevious);
791
- actual.periodPercentPrevious2 = calculatePeriodPercent(actual.periodRealizedPrevious2, actual.periodRealizedBasisPrevious2, actual.periodUnrealizedPrevious2, actual.periodUnrealizedBasisPrevious2);
789
+ actual.periodPercent = calculatePeriodPercent(actual.summaryTotalCurrent, actual.periodRealizedBasis, actual.periodUnrealizedBasis);
790
+ actual.periodPercentPrevious = calculatePeriodPercent(actual.summaryTotalPrevious, actual.periodRealizedBasisPrevious, actual.periodUnrealizedBasisPrevious);
791
+ actual.periodPercentPrevious2 = calculatePeriodPercent(actual.summaryTotalPrevious2, actual.periodRealizedBasisPrevious2, actual.periodUnrealizedBasisPrevious2);
792
792
 
793
793
  format.periodPercent = formatPercent(actual.periodPercent, 2);
794
794
  format.periodPercentPrevious = formatPercent(actual.periodPercentPrevious, 2);
@@ -921,7 +921,7 @@ module.exports = (() => {
921
921
  if (group.single && item) {
922
922
  actual.periodUnrealized = item.data.periodUnrealized;
923
923
 
924
- actual.periodPercent = calculatePeriodPercent(actual.periodRealized, actual.periodRealizedBasis, actual.periodUnrealized, actual.periodUnrealizedBasis);
924
+ actual.periodPercent = calculatePeriodPercent(actual.summaryTotalCurrent, actual.periodRealizedBasis, actual.periodUnrealizedBasis);
925
925
  format.periodPercent = formatPercent(actual.periodPercent, 2);
926
926
  }
927
927
  }
@@ -982,8 +982,8 @@ module.exports = (() => {
982
982
  }
983
983
  }
984
984
 
985
- function calculatePeriodPercent(realized, realizedBasis, unrealized, unrealizedBasis) {
986
- const numerator = realized.add(unrealized);
985
+ function calculatePeriodPercent(periodSummaryTotal, realizedBasis, unrealizedBasis) {
986
+ const numerator = periodSummaryTotal;
987
987
  const denominator = realizedBasis.add(unrealizedBasis);
988
988
 
989
989
  return denominator.getIsZero() ? Decimal.ZERO : numerator.divide(denominator);
@@ -648,8 +648,6 @@ module.exports = (() => {
648
648
  let returnRef;
649
649
 
650
650
  if (currentSummary) {
651
- const period = currentSummary.period;
652
-
653
651
  returnRef = currentSummary.end.basis.absolute();
654
652
  } else {
655
653
  returnRef = Decimal.ZERO;
@@ -113,6 +113,10 @@ module.exports = (() => {
113
113
  static get VALUATION() {
114
114
  return valuation;
115
115
  }
116
+
117
+ static get DELIST() {
118
+ return delist;
119
+ }
116
120
 
117
121
  static get INCOME() {
118
122
  return income;
@@ -322,8 +326,18 @@ module.exports = (() => {
322
326
  .withField('force', DataType.BOOLEAN, true)
323
327
  .schema
324
328
  );
325
-
326
- const income = new TransactionSchema(SchemaBuilder.withName(TransactionType.INCOME.code)
329
+
330
+ const delist = new TransactionSchema(SchemaBuilder.withName(TransactionType.DELIST.code)
331
+ .withField('portfolio', DataType.STRING)
332
+ .withField('position', DataType.STRING)
333
+ .withField('sequence', DataType.NUMBER, true)
334
+ .withField('type', DataType.forEnum(TransactionType, 'TransactionType'))
335
+ .withField('date', DataType.DAY)
336
+ .withField('force', DataType.BOOLEAN, true)
337
+ .schema
338
+ );
339
+
340
+ const income = new TransactionSchema(SchemaBuilder.withName(TransactionType.INCOME.code)
327
341
  .withField('portfolio', DataType.STRING)
328
342
  .withField('position', DataType.STRING)
329
343
  .withField('sequence', DataType.NUMBER, true)
@@ -349,6 +363,7 @@ module.exports = (() => {
349
363
  addSchemaToMap(TransactionType.DEPOSIT, deposit);
350
364
  addSchemaToMap(TransactionType.WITHDRAWAL, withdrawal);
351
365
  addSchemaToMap(TransactionType.VALUATION, valuation);
366
+ addSchemaToMap(TransactionType.DELIST, delist);
352
367
  addSchemaToMap(TransactionType.INCOME, income);
353
368
 
354
369
  return TransactionSchema;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@barchart/portfolio-api-common",
3
- "version": "1.2.114",
3
+ "version": "1.2.118",
4
4
  "description": "Common classes used by the Portfolio system",
5
5
  "author": {
6
6
  "name": "Bryan Ingle",
@@ -759,7 +759,6 @@ module.exports = (() => {
759
759
  * @param {Boolean} corporateAction
760
760
  * @param {Boolean} initial
761
761
  * @param {Boolean} significant
762
- * @param {Boolean} eod
763
762
  */
764
763
  class TransactionType extends Enum {
765
764
  constructor(code, description, display, sequence, purchase, sale, income, opening, closing, fee, corporateAction, initial, significant) {
@@ -1089,6 +1088,17 @@ module.exports = (() => {
1089
1088
  static get DEBIT() {
1090
1089
  return debit;
1091
1090
  }
1091
+
1092
+ /**
1093
+ * A system-generated transaction, indicating the security has stopped active trading.
1094
+ *
1095
+ * @public
1096
+ * @static
1097
+ * @returns {TransactionType}
1098
+ */
1099
+ static get DELIST() {
1100
+ return delist;
1101
+ }
1092
1102
 
1093
1103
  /**
1094
1104
  * A system-generated deposit, arising from another transaction.
@@ -1138,6 +1148,7 @@ module.exports = (() => {
1138
1148
  const split = new TransactionType('SP', 'Split', 'Split', 1, false, false, false, true, false, false, true, false, false);
1139
1149
  const fee = new TransactionType('F', 'Fee', 'Fee', 0, false, false, false, false, false, true, false, false, false);
1140
1150
  const feeUnits = new TransactionType('FU', 'Fee Units', 'Fee', 0, false, false, false, false, true, false, false, false, false);
1151
+ const delist = new TransactionType('DL', 'Delist', 'Delist', 1, false, false, false, false, false, false, true, false, false);
1141
1152
 
1142
1153
  const distributionCash = new TransactionType('DC', 'Distribution (Cash)', 'Cash Distribution', 1, false, false, true, false, false, false, true, false, false);
1143
1154
  const distributionReinvest = new TransactionType('DY', 'Distribution (Reinvested)', 'Distribution Reinvest', 1, false, false, false, true, false, false, true, false, false);
@@ -1157,7 +1168,8 @@ module.exports = (() => {
1157
1168
  },{"@barchart/common-js/lang/Enum":24,"@barchart/common-js/lang/assert":29}],5:[function(require,module,exports){
1158
1169
  const assert = require('@barchart/common-js/lang/assert'),
1159
1170
  array = require('@barchart/common-js/lang/array'),
1160
- is = require('@barchart/common-js/lang/is');
1171
+ is = require('@barchart/common-js/lang/is'),
1172
+ Day = require('@barchart/common-js/lang/Day');
1161
1173
 
1162
1174
  const InstrumentType = require('./InstrumentType'),
1163
1175
  PositionDirection = require('./PositionDirection'),
@@ -1374,6 +1386,23 @@ module.exports = (() => {
1374
1386
  static validateDirectionSwitch(instrumentType, currentDirection, proposedDirection) {
1375
1387
  return currentDirection === null || instrumentType.canSwitchDirection || (currentDirection.closed || proposedDirection.closed || currentDirection.positive === proposedDirection.positive);
1376
1388
  }
1389
+
1390
+ /**
1391
+ * Assuming the transaction list is ordered by sequence, validates that
1392
+ * no opening transactions exist after delisting date.
1393
+ *
1394
+ * @static
1395
+ * @public
1396
+ * @param {Array.<Object>} transactions
1397
+ * @returns {Boolean}
1398
+ */
1399
+ static validateDelisting(transactions) {
1400
+ assert.argumentIsArray(transactions, 'transactions');
1401
+
1402
+ const delistIndex = transactions.findIndex(t => t.type === TransactionType.DELIST);
1403
+
1404
+ return delistIndex < 0 || !transactions.some((t, i) => delistIndex < i && t.type.opening);
1405
+ }
1377
1406
 
1378
1407
  toString() {
1379
1408
  return '[TransactionValidator]';
@@ -1401,6 +1430,7 @@ module.exports = (() => {
1401
1430
  associateTypes(InstrumentType.EQUITY, TransactionType.DIVIDEND_REINVEST, false);
1402
1431
  associateTypes(InstrumentType.EQUITY, TransactionType.DIVIDEND_STOCK, false);
1403
1432
  associateTypes(InstrumentType.EQUITY, TransactionType.SPLIT, false);
1433
+ associateTypes(InstrumentType.EQUITY, TransactionType.DELIST, false);
1404
1434
 
1405
1435
  associateTypes(InstrumentType.FUND, TransactionType.BUY, true, [ PositionDirection.LONG, PositionDirection.EVEN ]);
1406
1436
  associateTypes(InstrumentType.FUND, TransactionType.SELL, true, [ PositionDirection.LONG ]);
@@ -1409,6 +1439,7 @@ module.exports = (() => {
1409
1439
  associateTypes(InstrumentType.FUND, TransactionType.DISTRIBUTION_CASH, false);
1410
1440
  associateTypes(InstrumentType.FUND, TransactionType.DISTRIBUTION_REINVEST, false);
1411
1441
  associateTypes(InstrumentType.FUND, TransactionType.DISTRIBUTION_FUND, false);
1442
+ associateTypes(InstrumentType.FUND, TransactionType.DELIST, false);
1412
1443
 
1413
1444
  associateTypes(InstrumentType.OTHER, TransactionType.BUY, true, [ PositionDirection.LONG, PositionDirection.EVEN ]);
1414
1445
  associateTypes(InstrumentType.OTHER, TransactionType.SELL, true, [ PositionDirection.LONG ]);
@@ -1450,7 +1481,7 @@ module.exports = (() => {
1450
1481
  return TransactionValidator;
1451
1482
  })();
1452
1483
 
1453
- },{"./InstrumentType":1,"./PositionDirection":2,"./TransactionType":4,"@barchart/common-js/lang/array":28,"@barchart/common-js/lang/assert":29,"@barchart/common-js/lang/is":33}],6:[function(require,module,exports){
1484
+ },{"./InstrumentType":1,"./PositionDirection":2,"./TransactionType":4,"@barchart/common-js/lang/Day":21,"@barchart/common-js/lang/array":28,"@barchart/common-js/lang/assert":29,"@barchart/common-js/lang/is":33}],6:[function(require,module,exports){
1454
1485
  const array = require('@barchart/common-js/lang/array'),
1455
1486
  assert = require('@barchart/common-js/lang/assert'),
1456
1487
  ComparatorBuilder = require('@barchart/common-js/collections/sorting/ComparatorBuilder'),
@@ -3275,9 +3306,9 @@ module.exports = (() => {
3275
3306
  actual.periodUnrealizedBasisPrevious = item.data.periodUnrealizedBasisPrevious;
3276
3307
  actual.periodUnrealizedBasisPrevious2 = item.data.periodUnrealizedBasisPrevious2;
3277
3308
 
3278
- actual.periodPercent = calculatePeriodPercent(actual.periodRealized, actual.periodRealizedBasis, actual.periodUnrealized, actual.periodUnrealizedBasis);
3279
- actual.periodPercentPrevious = calculatePeriodPercent(actual.periodRealizedPrevious, actual.periodRealizedBasisPrevious, actual.periodUnrealizedPrevious, actual.periodUnrealizedBasisPrevious);
3280
- actual.periodPercentPrevious2 = calculatePeriodPercent(actual.periodRealizedPrevious2, actual.periodRealizedBasisPrevious2, actual.periodUnrealizedPrevious2, actual.periodUnrealizedBasisPrevious2);
3309
+ actual.periodPercent = calculatePeriodPercent(actual.summaryTotalCurrent, actual.periodRealizedBasis, actual.periodUnrealizedBasis);
3310
+ actual.periodPercentPrevious = calculatePeriodPercent(actual.summaryTotalPrevious, actual.periodRealizedBasisPrevious, actual.periodUnrealizedBasisPrevious);
3311
+ actual.periodPercentPrevious2 = calculatePeriodPercent(actual.summaryTotalPrevious2, actual.periodRealizedBasisPrevious2, actual.periodUnrealizedBasisPrevious2);
3281
3312
 
3282
3313
  format.periodPercent = formatPercent(actual.periodPercent, 2);
3283
3314
  format.periodPercentPrevious = formatPercent(actual.periodPercentPrevious, 2);
@@ -3410,7 +3441,7 @@ module.exports = (() => {
3410
3441
  if (group.single && item) {
3411
3442
  actual.periodUnrealized = item.data.periodUnrealized;
3412
3443
 
3413
- actual.periodPercent = calculatePeriodPercent(actual.periodRealized, actual.periodRealizedBasis, actual.periodUnrealized, actual.periodUnrealizedBasis);
3444
+ actual.periodPercent = calculatePeriodPercent(actual.summaryTotalCurrent, actual.periodRealizedBasis, actual.periodUnrealizedBasis);
3414
3445
  format.periodPercent = formatPercent(actual.periodPercent, 2);
3415
3446
  }
3416
3447
  }
@@ -3471,8 +3502,8 @@ module.exports = (() => {
3471
3502
  }
3472
3503
  }
3473
3504
 
3474
- function calculatePeriodPercent(realized, realizedBasis, unrealized, unrealizedBasis) {
3475
- const numerator = realized.add(unrealized);
3505
+ function calculatePeriodPercent(periodSummaryTotal, realizedBasis, unrealizedBasis) {
3506
+ const numerator = periodSummaryTotal;
3476
3507
  const denominator = realizedBasis.add(unrealizedBasis);
3477
3508
 
3478
3509
  return denominator.getIsZero() ? Decimal.ZERO : numerator.divide(denominator);
@@ -4134,8 +4165,6 @@ module.exports = (() => {
4134
4165
  let returnRef;
4135
4166
 
4136
4167
  if (currentSummary) {
4137
- const period = currentSummary.period;
4138
-
4139
4168
  returnRef = currentSummary.end.basis.absolute();
4140
4169
  } else {
4141
4170
  returnRef = Decimal.ZERO;
@@ -4701,6 +4730,10 @@ module.exports = (() => {
4701
4730
  static get VALUATION() {
4702
4731
  return valuation;
4703
4732
  }
4733
+
4734
+ static get DELIST() {
4735
+ return delist;
4736
+ }
4704
4737
 
4705
4738
  static get INCOME() {
4706
4739
  return income;
@@ -4910,8 +4943,18 @@ module.exports = (() => {
4910
4943
  .withField('force', DataType.BOOLEAN, true)
4911
4944
  .schema
4912
4945
  );
4913
-
4914
- const income = new TransactionSchema(SchemaBuilder.withName(TransactionType.INCOME.code)
4946
+
4947
+ const delist = new TransactionSchema(SchemaBuilder.withName(TransactionType.DELIST.code)
4948
+ .withField('portfolio', DataType.STRING)
4949
+ .withField('position', DataType.STRING)
4950
+ .withField('sequence', DataType.NUMBER, true)
4951
+ .withField('type', DataType.forEnum(TransactionType, 'TransactionType'))
4952
+ .withField('date', DataType.DAY)
4953
+ .withField('force', DataType.BOOLEAN, true)
4954
+ .schema
4955
+ );
4956
+
4957
+ const income = new TransactionSchema(SchemaBuilder.withName(TransactionType.INCOME.code)
4915
4958
  .withField('portfolio', DataType.STRING)
4916
4959
  .withField('position', DataType.STRING)
4917
4960
  .withField('sequence', DataType.NUMBER, true)
@@ -4937,6 +4980,7 @@ module.exports = (() => {
4937
4980
  addSchemaToMap(TransactionType.DEPOSIT, deposit);
4938
4981
  addSchemaToMap(TransactionType.WITHDRAWAL, withdrawal);
4939
4982
  addSchemaToMap(TransactionType.VALUATION, valuation);
4983
+ addSchemaToMap(TransactionType.DELIST, delist);
4940
4984
  addSchemaToMap(TransactionType.INCOME, income);
4941
4985
 
4942
4986
  return TransactionSchema;
@@ -17875,10 +17919,6 @@ describe('After the PositionSummaryFrame enumeration is initialized', () => {
17875
17919
  });
17876
17920
  });
17877
17921
 
17878
-
17879
-
17880
- /////
17881
-
17882
17922
  describe('and month position summary ranges are processed for a transaction set that does not close', () => {
17883
17923
  let ranges;
17884
17924
 
@@ -17903,8 +17943,8 @@ describe('After the PositionSummaryFrame enumeration is initialized', () => {
17903
17943
  ranges = PositionSummaryFrame.MONTHLY.getRanges(transactions);
17904
17944
  });
17905
17945
 
17906
- it('should have 2 ranges (assuming the current year is 2018 and the current month is November)', () => {
17907
- expect(ranges.length).toEqual(2);
17946
+ it('should have three ranges (assuming the current year is 2018 and the current month is December)', () => {
17947
+ expect(ranges.length).toEqual(3);
17908
17948
  });
17909
17949
 
17910
17950
  it('the first range should be from 2018-09-30 to 2018-10-31', () => {
@@ -17913,14 +17953,15 @@ describe('After the PositionSummaryFrame enumeration is initialized', () => {
17913
17953
  });
17914
17954
 
17915
17955
  it('the second range should be from 2018-10-31 to 2018-11-30', () => {
17916
- expect(ranges[1].start.format()).toEqual('2018-10-31');
17917
- expect(ranges[1].end.format()).toEqual('2018-11-30');
17956
+ expect(ranges[1].start.format()).toEqual('2018-10-31');
17957
+ expect(ranges[1].end.format()).toEqual('2018-11-30');
17918
17958
  });
17919
- });
17920
-
17921
- ///////
17922
-
17923
17959
 
17960
+ it('the third range should be from 2018-10-31 to 2018-11-30', () => {
17961
+ expect(ranges[2].start.format()).toEqual('2018-11-30');
17962
+ expect(ranges[2].end.format()).toEqual('2018-12-31');
17963
+ });
17964
+ });
17924
17965
 
17925
17966
  describe('and getting the start date for yearly frames', () => {
17926
17967
  describe('for one year ago', function() {
@@ -18126,7 +18167,7 @@ describe('When validating transaction order', () => {
18126
18167
  'use strict';
18127
18168
 
18128
18169
  const build = (sequence, day, type) => {
18129
- return { sequence: sequence, date: Day.parse(day), type: (type || TransactionType.BUY ) };
18170
+ return { sequence: sequence, date: Day.parse(day), type: (type || TransactionType.BUY) };
18130
18171
  };
18131
18172
 
18132
18173
  it('An array of zero transactions should be valid', () => {
@@ -18198,6 +18239,28 @@ describe('When validating transaction references', () => {
18198
18239
  });
18199
18240
  });
18200
18241
 
18242
+ describe('When validating transactions which could include instrument delisting', () => {
18243
+ const build = (type) => {
18244
+ return { type: type };
18245
+ };
18246
+
18247
+ it('An array without a DELSIT transaction should be valid', () => {
18248
+ expect(TransactionValidator.validateDelisting([ build(TransactionType.BUY), build(TransactionType.SELL) ])).toEqual(true);
18249
+ });
18250
+
18251
+ it('An array with a final DELSIT transaction should be valid', () => {
18252
+ expect(TransactionValidator.validateDelisting([ build(TransactionType.BUY), build(TransactionType.SELL), build(TransactionType.DELIST) ])).toEqual(true);
18253
+ });
18254
+
18255
+ it('An array with a closing transaction after a DELIST transaction should be valid', () => {
18256
+ expect(TransactionValidator.validateDelisting([ build(TransactionType.BUY), build(TransactionType.SELL), build(TransactionType.DELIST), build(TransactionType.SELL) ])).toEqual(true);
18257
+ });
18258
+
18259
+ it('An array with an opening transaction after a DELIST transaction should not be valid', () => {
18260
+ expect(TransactionValidator.validateDelisting([ build(TransactionType.BUY), build(TransactionType.SELL), build(TransactionType.DELIST), build(TransactionType.BUY) ])).toEqual(false);
18261
+ });
18262
+ });
18263
+
18201
18264
  describe('When requesting all the user-initiated transaction types', () => {
18202
18265
  'use strict';
18203
18266
 
@@ -311,10 +311,6 @@ describe('After the PositionSummaryFrame enumeration is initialized', () => {
311
311
  });
312
312
  });
313
313
 
314
-
315
-
316
- /////
317
-
318
314
  describe('and month position summary ranges are processed for a transaction set that does not close', () => {
319
315
  let ranges;
320
316
 
@@ -339,8 +335,8 @@ describe('After the PositionSummaryFrame enumeration is initialized', () => {
339
335
  ranges = PositionSummaryFrame.MONTHLY.getRanges(transactions);
340
336
  });
341
337
 
342
- it('should have 2 ranges (assuming the current year is 2018 and the current month is November)', () => {
343
- expect(ranges.length).toEqual(2);
338
+ it('should have three ranges (assuming the current year is 2018 and the current month is December)', () => {
339
+ expect(ranges.length).toEqual(3);
344
340
  });
345
341
 
346
342
  it('the first range should be from 2018-09-30 to 2018-10-31', () => {
@@ -349,14 +345,15 @@ describe('After the PositionSummaryFrame enumeration is initialized', () => {
349
345
  });
350
346
 
351
347
  it('the second range should be from 2018-10-31 to 2018-11-30', () => {
352
- expect(ranges[1].start.format()).toEqual('2018-10-31');
353
- expect(ranges[1].end.format()).toEqual('2018-11-30');
348
+ expect(ranges[1].start.format()).toEqual('2018-10-31');
349
+ expect(ranges[1].end.format()).toEqual('2018-11-30');
354
350
  });
355
- });
356
-
357
- ///////
358
-
359
351
 
352
+ it('the third range should be from 2018-10-31 to 2018-11-30', () => {
353
+ expect(ranges[2].start.format()).toEqual('2018-11-30');
354
+ expect(ranges[2].end.format()).toEqual('2018-12-31');
355
+ });
356
+ });
360
357
 
361
358
  describe('and getting the start date for yearly frames', () => {
362
359
  describe('for one year ago', function() {
@@ -7,7 +7,7 @@ describe('When validating transaction order', () => {
7
7
  'use strict';
8
8
 
9
9
  const build = (sequence, day, type) => {
10
- return { sequence: sequence, date: Day.parse(day), type: (type || TransactionType.BUY ) };
10
+ return { sequence: sequence, date: Day.parse(day), type: (type || TransactionType.BUY) };
11
11
  };
12
12
 
13
13
  it('An array of zero transactions should be valid', () => {
@@ -79,6 +79,28 @@ describe('When validating transaction references', () => {
79
79
  });
80
80
  });
81
81
 
82
+ describe('When validating transactions which could include instrument delisting', () => {
83
+ const build = (type) => {
84
+ return { type: type };
85
+ };
86
+
87
+ it('An array without a DELSIT transaction should be valid', () => {
88
+ expect(TransactionValidator.validateDelisting([ build(TransactionType.BUY), build(TransactionType.SELL) ])).toEqual(true);
89
+ });
90
+
91
+ it('An array with a final DELSIT transaction should be valid', () => {
92
+ expect(TransactionValidator.validateDelisting([ build(TransactionType.BUY), build(TransactionType.SELL), build(TransactionType.DELIST) ])).toEqual(true);
93
+ });
94
+
95
+ it('An array with a closing transaction after a DELIST transaction should be valid', () => {
96
+ expect(TransactionValidator.validateDelisting([ build(TransactionType.BUY), build(TransactionType.SELL), build(TransactionType.DELIST), build(TransactionType.SELL) ])).toEqual(true);
97
+ });
98
+
99
+ it('An array with an opening transaction after a DELIST transaction should not be valid', () => {
100
+ expect(TransactionValidator.validateDelisting([ build(TransactionType.BUY), build(TransactionType.SELL), build(TransactionType.DELIST), build(TransactionType.BUY) ])).toEqual(false);
101
+ });
102
+ });
103
+
82
104
  describe('When requesting all the user-initiated transaction types', () => {
83
105
  'use strict';
84
106