@barchart/portfolio-api-common 1.2.65 → 1.2.69
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.
|
@@ -143,6 +143,17 @@ module.exports = (() => {
|
|
|
143
143
|
return transactionCreateFailedReinvestPriceUnavailable;
|
|
144
144
|
}
|
|
145
145
|
|
|
146
|
+
/**
|
|
147
|
+
* The transaction failed because the position has been locked.
|
|
148
|
+
*
|
|
149
|
+
* @public
|
|
150
|
+
* @static
|
|
151
|
+
* @returns {FailureType}
|
|
152
|
+
*/
|
|
153
|
+
static get TRANSACTION_CREATE_FAILED_POSITION_LOCKED() {
|
|
154
|
+
return transactionCreateFailedPositionLocked;
|
|
155
|
+
}
|
|
156
|
+
|
|
146
157
|
/**
|
|
147
158
|
* Deleting any transaction except for the most recent requires
|
|
148
159
|
* re-writing transaction history.
|
|
@@ -219,6 +230,7 @@ module.exports = (() => {
|
|
|
219
230
|
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.');
|
|
220
231
|
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.');
|
|
221
232
|
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.');
|
|
233
|
+
const transactionCreateFailedPositionLocked = new FailureType('TRANSACTION_CREATE_FAILED_POSITION_LOCKED', 'Unable to create transaction, are being recalculated for this position (or the linked cash position). Please re-enter the transaction in a minute or two.');
|
|
222
234
|
|
|
223
235
|
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).');
|
|
224
236
|
const transactionDeleteFailedNoTransaction = new FailureType('TRANSACTION_DELETE_FAILED_NO_TRANSACTION', 'Unable to delete transaction. The referenced transaction does not exist.');
|
|
@@ -21,10 +21,11 @@ module.exports = (() => {
|
|
|
21
21
|
* @param {Boolean} hasCorporateActions
|
|
22
22
|
* @param {Boolean} closeFractional
|
|
23
23
|
* @param {Boolean} roundQuantity
|
|
24
|
+
* @param {Boolean} strictOrdering
|
|
24
25
|
* @param {Function} generator
|
|
25
26
|
*/
|
|
26
27
|
class InstrumentType extends Enum {
|
|
27
|
-
constructor(code, description, alternateDescription, canReinvest, canShort, canSwitchDirection, usesSymbols, hasCorporateActions, closeFractional, roundQuantity, generator) {
|
|
28
|
+
constructor(code, description, alternateDescription, canReinvest, canShort, canSwitchDirection, usesSymbols, hasCorporateActions, closeFractional, roundQuantity, strictOrdering, generator) {
|
|
28
29
|
super(code, description);
|
|
29
30
|
|
|
30
31
|
assert.argumentIsRequired(alternateDescription, 'alternateDescription', String);
|
|
@@ -35,6 +36,7 @@ module.exports = (() => {
|
|
|
35
36
|
assert.argumentIsRequired(hasCorporateActions, 'hasCorporateActions', Boolean);
|
|
36
37
|
assert.argumentIsRequired(closeFractional, 'closeFractional', Boolean);
|
|
37
38
|
assert.argumentIsRequired(roundQuantity, 'roundQuantity', Boolean);
|
|
39
|
+
assert.argumentIsRequired(roundQuantity, 'strictOrdering', Boolean);
|
|
38
40
|
assert.argumentIsRequired(generator, 'generator', Function);
|
|
39
41
|
|
|
40
42
|
this._alternateDescription = alternateDescription;
|
|
@@ -45,6 +47,7 @@ module.exports = (() => {
|
|
|
45
47
|
this._hasCorporateActions = hasCorporateActions;
|
|
46
48
|
this._closeFractional = closeFractional;
|
|
47
49
|
this._roundQuantity = roundQuantity;
|
|
50
|
+
this._strictOrdering = strictOrdering;
|
|
48
51
|
|
|
49
52
|
this._generator = generator;
|
|
50
53
|
}
|
|
@@ -121,6 +124,17 @@ module.exports = (() => {
|
|
|
121
124
|
return this._closeFractional;
|
|
122
125
|
}
|
|
123
126
|
|
|
127
|
+
/**
|
|
128
|
+
* Indicates if transaction sequences must be honored before calculating position
|
|
129
|
+
* totals.
|
|
130
|
+
*
|
|
131
|
+
* @public
|
|
132
|
+
* @returns {Boolean}
|
|
133
|
+
*/
|
|
134
|
+
get strictOrdering() {
|
|
135
|
+
return this._strictOrdering;
|
|
136
|
+
}
|
|
137
|
+
|
|
124
138
|
/**
|
|
125
139
|
* Indicates transaction quantities should be rounded.
|
|
126
140
|
*
|
|
@@ -228,10 +242,10 @@ module.exports = (() => {
|
|
|
228
242
|
}
|
|
229
243
|
}
|
|
230
244
|
|
|
231
|
-
const cash = new InstrumentType('CASH', 'cash', 'Cash', false, false, true, false, false, false, false, (instrument) => `BARCHART-${instrument.type.code}-${instrument.currency.code}`);
|
|
232
|
-
const equity = new InstrumentType('EQUITY', 'equity', 'Equities', true, true, false, true, true, true, true,
|
|
233
|
-
const fund = new InstrumentType('FUND', 'mutual fund', 'Funds', true, false, false, true, true, false, true, (instrument) => `BARCHART-${instrument.type.code}-${instrument.symbol.barchart}`);
|
|
234
|
-
const other = new InstrumentType('OTHER', 'other', 'Other', false, false, false, false, false, false, true, (instrument) => `BARCHART-${instrument.type.code}-${uuid.v4()}`);
|
|
245
|
+
const cash = new InstrumentType('CASH', 'cash', 'Cash', false, false, true, false, false, false, false, false, (instrument) => `BARCHART-${instrument.type.code}-${instrument.currency.code}`);
|
|
246
|
+
const equity = new InstrumentType('EQUITY', 'equity', 'Equities', true, true, false, true, true, true, true, true, (instrument) => `BARCHART-${instrument.type.code}-${instrument.symbol.barchart}`);
|
|
247
|
+
const fund = new InstrumentType('FUND', 'mutual fund', 'Funds', true, false, false, true, true, false, true, true, (instrument) => `BARCHART-${instrument.type.code}-${instrument.symbol.barchart}`);
|
|
248
|
+
const other = new InstrumentType('OTHER', 'other', 'Other', false, false, false, false, false, false, true, true, (instrument) => `BARCHART-${instrument.type.code}-${uuid.v4()}`);
|
|
235
249
|
|
|
236
250
|
const map = { };
|
|
237
251
|
|
|
@@ -19,6 +19,25 @@ module.exports = (() => {
|
|
|
19
19
|
|
|
20
20
|
}
|
|
21
21
|
|
|
22
|
+
/**
|
|
23
|
+
* Determines the desired sequence number for a transaction.
|
|
24
|
+
*
|
|
25
|
+
* @public
|
|
26
|
+
* @param {Object} transaction
|
|
27
|
+
* @return {Number}
|
|
28
|
+
*/
|
|
29
|
+
static getSortSequence(transaction) {
|
|
30
|
+
let effective;
|
|
31
|
+
|
|
32
|
+
if (is.number(transaction.resequence)) {
|
|
33
|
+
effective = transaction.resequence;
|
|
34
|
+
} else {
|
|
35
|
+
effective = transaction.sequence;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
return effective;
|
|
39
|
+
}
|
|
40
|
+
|
|
22
41
|
/**
|
|
23
42
|
* Given an array of transactions, ensures that all sequence numbers and dates
|
|
24
43
|
* are properly ordered.
|
|
@@ -85,7 +104,7 @@ module.exports = (() => {
|
|
|
85
104
|
assert.argumentIsArray(transactions, 'transactions');
|
|
86
105
|
assert.argumentIsOptional(strict, 'strict', Boolean);
|
|
87
106
|
|
|
88
|
-
return transactions.findIndex((t, i, a) => t
|
|
107
|
+
return transactions.findIndex((t, i, a) => TransactionValidator.getSortSequence(t) !== (i + 1) || (i !== 0 && t.date.getIsBefore(a[ i - 1 ].date)) || (i !== 0 && is.boolean(strict) && strict && t.date.getIsEqual(a[i - 1].date) && t.type.sequence < a[i - 1].type.sequence));
|
|
89
108
|
}
|
|
90
109
|
|
|
91
110
|
/**
|
|
@@ -31,12 +31,14 @@ module.exports = (() => {
|
|
|
31
31
|
* @param {Array.<Object>} transactions
|
|
32
32
|
* @param {Array.<Object>} positions
|
|
33
33
|
* @param {Boolean=} mutate
|
|
34
|
+
* @param {Boolean=} descending
|
|
34
35
|
* @returns {Array}
|
|
35
36
|
*/
|
|
36
|
-
static format(transactions, positions, mutate) {
|
|
37
|
+
static format(transactions, positions, mutate, descending) {
|
|
37
38
|
assert.argumentIsArray(transactions, 'transactions');
|
|
38
39
|
assert.argumentIsArray(positions, 'positions');
|
|
39
40
|
assert.argumentIsOptional(mutate, 'mutate', Boolean);
|
|
41
|
+
assert.argumentIsOptional(descending, 'descending', Boolean);
|
|
40
42
|
|
|
41
43
|
const instruments = positions.reduce((map, p) => {
|
|
42
44
|
const instrument = Object.assign({ }, p.instrument || { });
|
|
@@ -84,6 +86,14 @@ module.exports = (() => {
|
|
|
84
86
|
return list;
|
|
85
87
|
}, [ ]);
|
|
86
88
|
|
|
89
|
+
let comparator;
|
|
90
|
+
|
|
91
|
+
if (is.boolean(descending) && descending) {
|
|
92
|
+
comparator = comparatorDescending;
|
|
93
|
+
} else {
|
|
94
|
+
comparator = comparatorAscending;
|
|
95
|
+
}
|
|
96
|
+
|
|
87
97
|
a.sort(comparator);
|
|
88
98
|
|
|
89
99
|
a.forEach((t) => {
|
|
@@ -99,9 +109,21 @@ module.exports = (() => {
|
|
|
99
109
|
* @public
|
|
100
110
|
* @static
|
|
101
111
|
* @param {Array.<Object>} transactions
|
|
112
|
+
* @param {Boolean=} descending
|
|
102
113
|
* @returns {Array}
|
|
103
114
|
*/
|
|
104
|
-
sort(transactions) {
|
|
115
|
+
sort(transactions, descending) {
|
|
116
|
+
assert.argumentIsArray(transactions, 'transactions');
|
|
117
|
+
assert.argumentIsOptional(descending, 'descending', Boolean);
|
|
118
|
+
|
|
119
|
+
let comparator;
|
|
120
|
+
|
|
121
|
+
if (is.boolean(descending) && descending) {
|
|
122
|
+
comparator = comparatorDescending;
|
|
123
|
+
} else {
|
|
124
|
+
comparator = comparatorAscending;
|
|
125
|
+
}
|
|
126
|
+
|
|
105
127
|
return transactions.sort(comparator);
|
|
106
128
|
}
|
|
107
129
|
|
|
@@ -277,15 +299,14 @@ module.exports = (() => {
|
|
|
277
299
|
}
|
|
278
300
|
}
|
|
279
301
|
|
|
280
|
-
const
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
}).toComparator();
|
|
302
|
+
const comparatorAscending = ComparatorBuilder.startWith((a, b) => Day.compareDays(a.date, b.date))
|
|
303
|
+
.thenBy((a, b) => comparators.compareNumbers(getInstrumentTypePriority(a.instrument.type), getInstrumentTypePriority(b.instrument.type))
|
|
304
|
+
.thenBy((a, b) => comparators.compareStrings(a.instrument.id, b.instrument.id))
|
|
305
|
+
.thenBy((a, b) => comparators.compareNumbers(a.sequence, b.sequence))
|
|
306
|
+
.toComparator();
|
|
307
|
+
|
|
308
|
+
const comparatorDescending = ComparatorBuilder.startWith((a, b) => comparatorAscending(b, a))
|
|
309
|
+
.toComparator();
|
|
289
310
|
|
|
290
311
|
return TransactionFormatter;
|
|
291
312
|
})();
|
package/package.json
CHANGED
package/test/SpecRunner.js
CHANGED
|
@@ -22,10 +22,11 @@ module.exports = (() => {
|
|
|
22
22
|
* @param {Boolean} hasCorporateActions
|
|
23
23
|
* @param {Boolean} closeFractional
|
|
24
24
|
* @param {Boolean} roundQuantity
|
|
25
|
+
* @param {Boolean} strictOrdering
|
|
25
26
|
* @param {Function} generator
|
|
26
27
|
*/
|
|
27
28
|
class InstrumentType extends Enum {
|
|
28
|
-
constructor(code, description, alternateDescription, canReinvest, canShort, canSwitchDirection, usesSymbols, hasCorporateActions, closeFractional, roundQuantity, generator) {
|
|
29
|
+
constructor(code, description, alternateDescription, canReinvest, canShort, canSwitchDirection, usesSymbols, hasCorporateActions, closeFractional, roundQuantity, strictOrdering, generator) {
|
|
29
30
|
super(code, description);
|
|
30
31
|
|
|
31
32
|
assert.argumentIsRequired(alternateDescription, 'alternateDescription', String);
|
|
@@ -36,6 +37,7 @@ module.exports = (() => {
|
|
|
36
37
|
assert.argumentIsRequired(hasCorporateActions, 'hasCorporateActions', Boolean);
|
|
37
38
|
assert.argumentIsRequired(closeFractional, 'closeFractional', Boolean);
|
|
38
39
|
assert.argumentIsRequired(roundQuantity, 'roundQuantity', Boolean);
|
|
40
|
+
assert.argumentIsRequired(roundQuantity, 'strictOrdering', Boolean);
|
|
39
41
|
assert.argumentIsRequired(generator, 'generator', Function);
|
|
40
42
|
|
|
41
43
|
this._alternateDescription = alternateDescription;
|
|
@@ -46,6 +48,7 @@ module.exports = (() => {
|
|
|
46
48
|
this._hasCorporateActions = hasCorporateActions;
|
|
47
49
|
this._closeFractional = closeFractional;
|
|
48
50
|
this._roundQuantity = roundQuantity;
|
|
51
|
+
this._strictOrdering = strictOrdering;
|
|
49
52
|
|
|
50
53
|
this._generator = generator;
|
|
51
54
|
}
|
|
@@ -122,6 +125,17 @@ module.exports = (() => {
|
|
|
122
125
|
return this._closeFractional;
|
|
123
126
|
}
|
|
124
127
|
|
|
128
|
+
/**
|
|
129
|
+
* Indicates if transaction sequences must be honored before calculating position
|
|
130
|
+
* totals.
|
|
131
|
+
*
|
|
132
|
+
* @public
|
|
133
|
+
* @returns {Boolean}
|
|
134
|
+
*/
|
|
135
|
+
get strictOrdering() {
|
|
136
|
+
return this._strictOrdering;
|
|
137
|
+
}
|
|
138
|
+
|
|
125
139
|
/**
|
|
126
140
|
* Indicates transaction quantities should be rounded.
|
|
127
141
|
*
|
|
@@ -229,10 +243,10 @@ module.exports = (() => {
|
|
|
229
243
|
}
|
|
230
244
|
}
|
|
231
245
|
|
|
232
|
-
const cash = new InstrumentType('CASH', 'cash', 'Cash', false, false, true, false, false, false, false, (instrument) => `BARCHART-${instrument.type.code}-${instrument.currency.code}`);
|
|
233
|
-
const equity = new InstrumentType('EQUITY', 'equity', 'Equities', true, true, false, true, true, true, true,
|
|
234
|
-
const fund = new InstrumentType('FUND', 'mutual fund', 'Funds', true, false, false, true, true, false, true, (instrument) => `BARCHART-${instrument.type.code}-${instrument.symbol.barchart}`);
|
|
235
|
-
const other = new InstrumentType('OTHER', 'other', 'Other', false, false, false, false, false, false, true, (instrument) => `BARCHART-${instrument.type.code}-${uuid.v4()}`);
|
|
246
|
+
const cash = new InstrumentType('CASH', 'cash', 'Cash', false, false, true, false, false, false, false, false, (instrument) => `BARCHART-${instrument.type.code}-${instrument.currency.code}`);
|
|
247
|
+
const equity = new InstrumentType('EQUITY', 'equity', 'Equities', true, true, false, true, true, true, true, true, (instrument) => `BARCHART-${instrument.type.code}-${instrument.symbol.barchart}`);
|
|
248
|
+
const fund = new InstrumentType('FUND', 'mutual fund', 'Funds', true, false, false, true, true, false, true, true, (instrument) => `BARCHART-${instrument.type.code}-${instrument.symbol.barchart}`);
|
|
249
|
+
const other = new InstrumentType('OTHER', 'other', 'Other', false, false, false, false, false, false, true, true, (instrument) => `BARCHART-${instrument.type.code}-${uuid.v4()}`);
|
|
236
250
|
|
|
237
251
|
const map = { };
|
|
238
252
|
|
|
@@ -1088,6 +1102,25 @@ module.exports = (() => {
|
|
|
1088
1102
|
|
|
1089
1103
|
}
|
|
1090
1104
|
|
|
1105
|
+
/**
|
|
1106
|
+
* Determines the desired sequence number for a transaction.
|
|
1107
|
+
*
|
|
1108
|
+
* @public
|
|
1109
|
+
* @param {Object} transaction
|
|
1110
|
+
* @return {Number}
|
|
1111
|
+
*/
|
|
1112
|
+
static getSortSequence(transaction) {
|
|
1113
|
+
let effective;
|
|
1114
|
+
|
|
1115
|
+
if (is.number(transaction.resequence)) {
|
|
1116
|
+
effective = transaction.resequence;
|
|
1117
|
+
} else {
|
|
1118
|
+
effective = transaction.sequence;
|
|
1119
|
+
}
|
|
1120
|
+
|
|
1121
|
+
return effective;
|
|
1122
|
+
}
|
|
1123
|
+
|
|
1091
1124
|
/**
|
|
1092
1125
|
* Given an array of transactions, ensures that all sequence numbers and dates
|
|
1093
1126
|
* are properly ordered.
|
|
@@ -1154,7 +1187,7 @@ module.exports = (() => {
|
|
|
1154
1187
|
assert.argumentIsArray(transactions, 'transactions');
|
|
1155
1188
|
assert.argumentIsOptional(strict, 'strict', Boolean);
|
|
1156
1189
|
|
|
1157
|
-
return transactions.findIndex((t, i, a) => t
|
|
1190
|
+
return transactions.findIndex((t, i, a) => TransactionValidator.getSortSequence(t) !== (i + 1) || (i !== 0 && t.date.getIsBefore(a[ i - 1 ].date)) || (i !== 0 && is.boolean(strict) && strict && t.date.getIsEqual(a[i - 1].date) && t.type.sequence < a[i - 1].type.sequence));
|
|
1158
1191
|
}
|
|
1159
1192
|
|
|
1160
1193
|
/**
|