@barchart/portfolio-api-common 1.3.20 → 1.3.24
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.
- package/.jshintrc +4 -1
- package/README.md +29 -4
- package/buildspec.yml +15 -0
- package/gulpfile.js +22 -33
- package/lib/api/failures/PortfolioFailureType.js +40 -2
- package/lib/data/CorporateActionType.js +24 -0
- package/lib/data/TransactionType.js +128 -26
- package/lib/data/TransactionValidator.js +14 -6
- package/lib/formatters/TransactionFormatter.js +36 -0
- package/lib/serialization/TransactionSchema.js +15 -5
- package/package.json +2 -4
- package/test/SpecRunner.js +164 -42
- package/test/specs/data/PositionSummaryFrameSpec.js +1 -1
- package/test/specs/data/TransactionValidatorSpec.js +4 -4
package/.jshintrc
CHANGED
package/README.md
CHANGED
|
@@ -1,7 +1,32 @@
|
|
|
1
1
|
# @barchart/portfolio-api-common
|
|
2
|
-
## Barchart Portfolio API Common Components
|
|
3
2
|
|
|
4
|
-
|
|
3
|
+
[](https://github.com/barchart/portfolio-api-common)
|
|
5
4
|
|
|
6
|
-
*
|
|
7
|
-
|
|
5
|
+
A *private* library of shared JavaScript code pertaining to the paper-trading portfolio system.
|
|
6
|
+
|
|
7
|
+
### Overview
|
|
8
|
+
|
|
9
|
+
Simply put, this project contains code that runs on both the servers (i.e. Serverless applications) and clients (e.g. browser, mobile, etc).
|
|
10
|
+
|
|
11
|
+
#### [lib/serialization](https://github.com/barchart/portfolio-api-common/tree/master/lib/serialization)
|
|
12
|
+
|
|
13
|
+
Data is passed between client and server in JSON format. However, the code works with more complex types. For example, [Decimal](https://github.com/barchart/barchart-common-js/blob/master/lang/Decimal.js) instances are used in place of [native JavaScript floats](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number). [Day](https://github.com/barchart/barchart-common-js/blob/master/lang/Day.js) instances are used instead of [native JavaScript Dates](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date).
|
|
14
|
+
|
|
15
|
+
So, before data is exchanged, it must be converted to pure JSON. Conversely, when data is received, as pure JSON, its translated into more complex types before use. This is facilitated by the [Schema](https://github.com/barchart/barchart-common-js/blob/master/serialization/json/Schema.js) definitions which build custom "reviver" functions for [JSON parsing](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/parse).
|
|
16
|
+
|
|
17
|
+
#### [lib/processing](https://github.com/barchart/portfolio-api-common/tree/master/lib/processing)
|
|
18
|
+
|
|
19
|
+
For reporting and display purposes, positions can be grouped together (by asset class, by portfolio, by user, etc). This code supports aggregation and gain/loss calculation. It is used by server-generated reports and dynamic user interfaces.
|
|
20
|
+
|
|
21
|
+
### Notable Consumers
|
|
22
|
+
|
|
23
|
+
* [aws-lambda-portfolio](https://github.com/barchart/aws-lambda-portfolio) - Serverless applications (i.e. the servers)
|
|
24
|
+
* [portfolio-client-js](https://github.com/barchart/portfolio-client-js) - JavaScript client SDK for communicating with server API's.
|
|
25
|
+
* [tgam-portfolio-ui-js](https://github.com/barchart/tgam-portfolio-ui-js) - A dynamic, single-page HTML UI.
|
|
26
|
+
|
|
27
|
+
### Package Managers
|
|
28
|
+
|
|
29
|
+
This library has been published as a *private* module to NPM as [@barchart/portfolio-api-common](https://www.npmjs.com/package/@barchart/portfolio-api-common).
|
|
30
|
+
|
|
31
|
+
> npm login
|
|
32
|
+
> npm install @barchart/portfolio-api-common -S
|
package/buildspec.yml
ADDED
package/gulpfile.js
CHANGED
|
@@ -5,17 +5,15 @@ const fs = require('fs');
|
|
|
5
5
|
const browserify = require('browserify'),
|
|
6
6
|
buffer = require('vinyl-buffer'),
|
|
7
7
|
bump = require('gulp-bump'),
|
|
8
|
-
exec = require('child_process').exec,
|
|
9
8
|
git = require('gulp-git'),
|
|
10
9
|
gitStatus = require('git-get-status'),
|
|
11
10
|
glob = require('glob'),
|
|
12
11
|
jasmine = require('gulp-jasmine'),
|
|
13
12
|
jshint = require('gulp-jshint'),
|
|
14
|
-
replace = require('gulp-replace'),
|
|
15
13
|
source = require('vinyl-source-stream');
|
|
16
14
|
|
|
17
15
|
function getVersionFromPackage() {
|
|
18
|
-
|
|
16
|
+
return JSON.parse(fs.readFileSync('./package.json', 'utf8')).version;
|
|
19
17
|
}
|
|
20
18
|
|
|
21
19
|
gulp.task('ensure-clean-working-directory', (cb) => {
|
|
@@ -30,39 +28,30 @@ gulp.task('ensure-clean-working-directory', (cb) => {
|
|
|
30
28
|
|
|
31
29
|
gulp.task('bump-version', () => {
|
|
32
30
|
return gulp.src([ './package.json' ])
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
});
|
|
36
|
-
|
|
37
|
-
gulp.task('document', (cb) => {
|
|
38
|
-
exec('jsdoc . -c jsdoc.json -r -d docs', (error, stdout, stderr) => {
|
|
39
|
-
console.log(stdout);
|
|
40
|
-
console.log(stderr);
|
|
41
|
-
|
|
42
|
-
cb();
|
|
43
|
-
});
|
|
31
|
+
.pipe(bump({ type: 'patch' }))
|
|
32
|
+
.pipe(gulp.dest('./'));
|
|
44
33
|
});
|
|
45
34
|
|
|
46
35
|
gulp.task('commit-changes', () => {
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
36
|
+
return gulp.src([ './', './test/', './package.json' ])
|
|
37
|
+
.pipe(git.add())
|
|
38
|
+
.pipe(git.commit('Release. Bump version number'));
|
|
50
39
|
});
|
|
51
40
|
|
|
52
41
|
gulp.task('push-changes', (cb) => {
|
|
53
|
-
|
|
42
|
+
git.push('origin', 'master', cb);
|
|
54
43
|
});
|
|
55
44
|
|
|
56
45
|
gulp.task('create-tag', (cb) => {
|
|
57
|
-
|
|
46
|
+
const version = getVersionFromPackage();
|
|
58
47
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
48
|
+
git.tag(version, 'Release ' + version, (error) => {
|
|
49
|
+
if (error) {
|
|
50
|
+
return cb(error);
|
|
51
|
+
}
|
|
63
52
|
|
|
64
|
-
|
|
65
|
-
|
|
53
|
+
git.push('origin', 'master', { args: '--tags' }, cb);
|
|
54
|
+
});
|
|
66
55
|
});
|
|
67
56
|
|
|
68
57
|
gulp.task('build-test-bundle', () => {
|
|
@@ -74,13 +63,13 @@ gulp.task('build-test-bundle', () => {
|
|
|
74
63
|
});
|
|
75
64
|
|
|
76
65
|
gulp.task('execute-browser-tests', () => {
|
|
77
|
-
|
|
78
|
-
|
|
66
|
+
return gulp.src('test/SpecRunner.js')
|
|
67
|
+
.pipe(jasmine());
|
|
79
68
|
});
|
|
80
69
|
|
|
81
70
|
gulp.task('execute-node-tests', () => {
|
|
82
|
-
|
|
83
|
-
|
|
71
|
+
return gulp.src(['test/specs/**/*.js'])
|
|
72
|
+
.pipe(jasmine());
|
|
84
73
|
});
|
|
85
74
|
|
|
86
75
|
gulp.task('execute-tests', gulp.series(
|
|
@@ -92,7 +81,6 @@ gulp.task('execute-tests', gulp.series(
|
|
|
92
81
|
gulp.task('release', gulp.series(
|
|
93
82
|
'ensure-clean-working-directory',
|
|
94
83
|
'execute-tests',
|
|
95
|
-
'document',
|
|
96
84
|
'bump-version',
|
|
97
85
|
'commit-changes',
|
|
98
86
|
'push-changes',
|
|
@@ -100,9 +88,10 @@ gulp.task('release', gulp.series(
|
|
|
100
88
|
));
|
|
101
89
|
|
|
102
90
|
gulp.task('lint', () => {
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
91
|
+
return gulp.src([ './**/*.js', './test/specs/**/*.js', '!./node_modules/**', '!./docs/**', '!./test/SpecRunner.js' ])
|
|
92
|
+
.pipe(jshint({'esversion': 6}))
|
|
93
|
+
.pipe(jshint.reporter('default'))
|
|
94
|
+
.pipe(jshint.reporter('fail'));
|
|
106
95
|
});
|
|
107
96
|
|
|
108
97
|
gulp.task('test', gulp.series('execute-tests'));
|
|
@@ -88,7 +88,7 @@ module.exports = (() => {
|
|
|
88
88
|
static get TRANSACTION_CREATE_FAILED_OUT_OF_SEQUENCE() {
|
|
89
89
|
return transactionCreateFailedOutOfSequence;
|
|
90
90
|
}
|
|
91
|
-
|
|
91
|
+
|
|
92
92
|
/**
|
|
93
93
|
* The transaction date is invalid.
|
|
94
94
|
* For example create opening transaction after delist date.
|
|
@@ -101,6 +101,18 @@ module.exports = (() => {
|
|
|
101
101
|
return transactionCreateFailedInvalidDate;
|
|
102
102
|
}
|
|
103
103
|
|
|
104
|
+
/**
|
|
105
|
+
* The target instrument is invalid.
|
|
106
|
+
* Can be used in Merger and Acquisition.
|
|
107
|
+
*
|
|
108
|
+
* @public
|
|
109
|
+
* @static
|
|
110
|
+
* @returns {FailureType}
|
|
111
|
+
*/
|
|
112
|
+
static get TRANSACTION_CREATE_FAILED_TARGET_INSTRUMENT_MISSING() {
|
|
113
|
+
return transactionCreateFailedTargetInstrumentMissing;
|
|
114
|
+
}
|
|
115
|
+
|
|
104
116
|
/**
|
|
105
117
|
* @public
|
|
106
118
|
* @static
|
|
@@ -153,6 +165,29 @@ module.exports = (() => {
|
|
|
153
165
|
return transactionCreateFailedValuationNegative;
|
|
154
166
|
}
|
|
155
167
|
|
|
168
|
+
/**
|
|
169
|
+
* A "terminal" transaction must be the last transaction is the history.
|
|
170
|
+
*
|
|
171
|
+
* @public
|
|
172
|
+
* @static
|
|
173
|
+
* @returns {FailureType}
|
|
174
|
+
*/
|
|
175
|
+
static get TRANSACTION_CREATE_FAILED_INVALID_TERMINATION() {
|
|
176
|
+
return transactionCreateFailedInvalidTermination;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
/**
|
|
180
|
+
* A transaction cannot be created after the termination date of
|
|
181
|
+
* the instrument.
|
|
182
|
+
*
|
|
183
|
+
* @public
|
|
184
|
+
* @static
|
|
185
|
+
* @returns {FailureType}
|
|
186
|
+
*/
|
|
187
|
+
static get TRANSACTION_CREATE_FAILED_AFTER_TERMINATION() {
|
|
188
|
+
return transactionCreateFailedAfterTermination;
|
|
189
|
+
}
|
|
190
|
+
|
|
156
191
|
/**
|
|
157
192
|
* The transaction (of this type) cannot be created by a user, instead,
|
|
158
193
|
* it is created and managed by the system (e.g. dividends).
|
|
@@ -255,7 +290,7 @@ module.exports = (() => {
|
|
|
255
290
|
static get TRANSACTION_DELETE_FAILED_POSITION_LOCKED() {
|
|
256
291
|
return transactionDeleteFailedPositionLocked;
|
|
257
292
|
}
|
|
258
|
-
|
|
293
|
+
|
|
259
294
|
/**
|
|
260
295
|
* The transaction date is invalid.
|
|
261
296
|
* For example edit opening transaction after delist date.
|
|
@@ -306,11 +341,14 @@ module.exports = (() => {
|
|
|
306
341
|
const transactionCreateFailedNoPosition = new FailureType('TRANSACTION_CREATE_FAILED_NO_POSITION', 'Unable to create transaction. The referenced position does not exist. Has it been deleted?', false);
|
|
307
342
|
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).');
|
|
308
343
|
const transactionCreateFailedInvalidDate = new FailureType('TRANSACTION_CREATE_FAILED_INVALID_DATE', 'Unable to process transaction with given date.');
|
|
344
|
+
const transactionCreateFailedTargetInstrumentMissing = new FailureType('TRANSACTION_CREATE_FAILED_TARGET_INSTRUMENT_MISSING', 'Unable to create transaction. The target instrument does not exist.');
|
|
309
345
|
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.');
|
|
310
346
|
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.', false);
|
|
311
347
|
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.', false);
|
|
312
348
|
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.', false);
|
|
313
349
|
const transactionCreateFailedValuationNegative = new FailureType('TRANSACTION_CREATE_FAILED_VALUATION_NEGATIVE', 'Unable to process operation, valuations cannot be negative.', false);
|
|
350
|
+
const transactionCreateFailedInvalidTermination = new FailureType('TRANSACTION_CREATE_FAILED_INVALID_TERMINATION', 'Unable to process operation, a {U|transactionType.description} must be the final transaction in the position history.', false);
|
|
351
|
+
const transactionCreateFailedAfterTermination = new FailureType('TRANSACTION_CREATE_FAILED_AFTER_TERMINATION', 'Unable to process operation, one or more transactions would exist after {L|termination}, the final day of trading for this instrument', false);
|
|
314
352
|
|
|
315
353
|
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.');
|
|
316
354
|
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.');
|
|
@@ -82,6 +82,28 @@ module.exports = (() => {
|
|
|
82
82
|
static get DELIST() {
|
|
83
83
|
return delist;
|
|
84
84
|
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* A merging.
|
|
88
|
+
*
|
|
89
|
+
* @public
|
|
90
|
+
* @static
|
|
91
|
+
* @returns {CorporateActionType}
|
|
92
|
+
*/
|
|
93
|
+
static get MERGER() {
|
|
94
|
+
return merger;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* A spinoff.
|
|
99
|
+
*
|
|
100
|
+
* @public
|
|
101
|
+
* @static
|
|
102
|
+
* @returns {CorporateActionType}
|
|
103
|
+
*/
|
|
104
|
+
static get SPINOFF() {
|
|
105
|
+
return spinoff;
|
|
106
|
+
}
|
|
85
107
|
}
|
|
86
108
|
|
|
87
109
|
const split = new CorporateActionType('SPLIT', 'Split', false);
|
|
@@ -90,6 +112,8 @@ module.exports = (() => {
|
|
|
90
112
|
const symbolChange = new CorporateActionType('SYMBOL_CHANGE', 'Symbol Change', false);
|
|
91
113
|
const nameChange = new CorporateActionType('NAME_CHANGE', 'Name Change', false);
|
|
92
114
|
const delist = new CorporateActionType('DELIST', 'Delist', false);
|
|
115
|
+
const merger = new CorporateActionType('MERGER', 'Merger', false);
|
|
116
|
+
const spinoff = new CorporateActionType('SPINOFF', 'Spinoff', false);
|
|
93
117
|
|
|
94
118
|
return CorporateActionType;
|
|
95
119
|
})();
|
|
@@ -21,11 +21,14 @@ module.exports = (() => {
|
|
|
21
21
|
* @param {Boolean} fee
|
|
22
22
|
* @param {Boolean} corporateAction
|
|
23
23
|
* @param {Boolean} initial
|
|
24
|
+
* @param {Boolean} terminal
|
|
24
25
|
* @param {Boolean} significant
|
|
25
|
-
* @param {Boolean}
|
|
26
|
+
* @param {Boolean} chaining
|
|
27
|
+
* @param {Boolean} chained
|
|
28
|
+
* @param {Boolean} transfer
|
|
26
29
|
*/
|
|
27
30
|
class TransactionType extends Enum {
|
|
28
|
-
constructor(code, description, display, sequence, purchase, sale, income, opening, closing, fee, corporateAction, initial, significant) {
|
|
31
|
+
constructor(code, description, display, sequence, purchase, sale, income, opening, closing, fee, corporateAction, initial, terminal, significant, chaining, chained, transfer) {
|
|
29
32
|
super(code, description);
|
|
30
33
|
|
|
31
34
|
assert.argumentIsRequired(display, 'display', String);
|
|
@@ -38,7 +41,11 @@ module.exports = (() => {
|
|
|
38
41
|
assert.argumentIsRequired(fee, 'fee', Boolean);
|
|
39
42
|
assert.argumentIsRequired(corporateAction, 'corporateAction', Boolean);
|
|
40
43
|
assert.argumentIsRequired(initial, 'initial', Boolean);
|
|
44
|
+
assert.argumentIsRequired(terminal, 'terminal', Boolean);
|
|
41
45
|
assert.argumentIsRequired(significant, 'significant', Boolean);
|
|
46
|
+
assert.argumentIsRequired(chaining, 'chaining', Boolean);
|
|
47
|
+
assert.argumentIsRequired(chained, 'chained', Boolean);
|
|
48
|
+
assert.argumentIsRequired(transfer, 'transfer', Boolean);
|
|
42
49
|
|
|
43
50
|
this._display = display;
|
|
44
51
|
this._sequence = sequence;
|
|
@@ -50,7 +57,11 @@ module.exports = (() => {
|
|
|
50
57
|
this._fee = fee;
|
|
51
58
|
this._corporateAction = corporateAction;
|
|
52
59
|
this._initial = initial;
|
|
60
|
+
this._terminal = terminal;
|
|
53
61
|
this._significant = significant;
|
|
62
|
+
this._chaining = chaining;
|
|
63
|
+
this._chained = chained;
|
|
64
|
+
this._transfer = transfer;
|
|
54
65
|
}
|
|
55
66
|
|
|
56
67
|
/**
|
|
@@ -167,6 +178,16 @@ module.exports = (() => {
|
|
|
167
178
|
return this._initial;
|
|
168
179
|
}
|
|
169
180
|
|
|
181
|
+
/**
|
|
182
|
+
* Indicates if the transaction must be the last
|
|
183
|
+
*
|
|
184
|
+
* @public
|
|
185
|
+
* @returns {Boolean}
|
|
186
|
+
*/
|
|
187
|
+
get terminal() {
|
|
188
|
+
return this._terminal;
|
|
189
|
+
}
|
|
190
|
+
|
|
170
191
|
/**
|
|
171
192
|
* Significant transactions cannot be discarded during transaction re-write.
|
|
172
193
|
*
|
|
@@ -177,6 +198,37 @@ module.exports = (() => {
|
|
|
177
198
|
return this._significant;
|
|
178
199
|
}
|
|
179
200
|
|
|
201
|
+
/**
|
|
202
|
+
* Chain transactions cause another position to be created.
|
|
203
|
+
*
|
|
204
|
+
* @public
|
|
205
|
+
* @returns {Boolean}
|
|
206
|
+
*/
|
|
207
|
+
get chaining() {
|
|
208
|
+
return this._chaining;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
/**
|
|
212
|
+
* Chained transactions are created from another position.
|
|
213
|
+
*
|
|
214
|
+
* @public
|
|
215
|
+
* @returns {Boolean}
|
|
216
|
+
*/
|
|
217
|
+
get chained() {
|
|
218
|
+
return this._chained;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
/**
|
|
222
|
+
* Indicates if the transaction should cause gains and losses to be
|
|
223
|
+
* transferred from the original (chaining) position.
|
|
224
|
+
*
|
|
225
|
+
* @public
|
|
226
|
+
* @returns {Boolean}
|
|
227
|
+
*/
|
|
228
|
+
get transfer() {
|
|
229
|
+
return this._transfer;
|
|
230
|
+
}
|
|
231
|
+
|
|
180
232
|
/**
|
|
181
233
|
* A purchase.
|
|
182
234
|
*
|
|
@@ -352,7 +404,7 @@ module.exports = (() => {
|
|
|
352
404
|
static get DEBIT() {
|
|
353
405
|
return debit;
|
|
354
406
|
}
|
|
355
|
-
|
|
407
|
+
|
|
356
408
|
/**
|
|
357
409
|
* A system-generated transaction, indicating the security has stopped active trading.
|
|
358
410
|
*
|
|
@@ -397,34 +449,84 @@ module.exports = (() => {
|
|
|
397
449
|
return income;
|
|
398
450
|
}
|
|
399
451
|
|
|
452
|
+
/**
|
|
453
|
+
* A merger opening.
|
|
454
|
+
*
|
|
455
|
+
* @public
|
|
456
|
+
* @static
|
|
457
|
+
* @returns {TransactionType}
|
|
458
|
+
*/
|
|
459
|
+
static get MERGER_OPEN() {
|
|
460
|
+
return mergerOpen;
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
/**
|
|
464
|
+
* A merger closing.
|
|
465
|
+
*
|
|
466
|
+
* @public
|
|
467
|
+
* @static
|
|
468
|
+
* @returns {TransactionType}
|
|
469
|
+
*/
|
|
470
|
+
static get MERGER_CLOSE() {
|
|
471
|
+
return mergerClose;
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
/**
|
|
475
|
+
* A spin-off.
|
|
476
|
+
*
|
|
477
|
+
* @public
|
|
478
|
+
* @static
|
|
479
|
+
* @returns {TransactionType}
|
|
480
|
+
*/
|
|
481
|
+
static get SPINOFF() {
|
|
482
|
+
return spinoff;
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
/**
|
|
486
|
+
* A spin-off opening.
|
|
487
|
+
*
|
|
488
|
+
* @public
|
|
489
|
+
* @static
|
|
490
|
+
* @returns {TransactionType}
|
|
491
|
+
*/
|
|
492
|
+
static get SPINOFF_OPEN() {
|
|
493
|
+
return spinoffOpen;
|
|
494
|
+
}
|
|
495
|
+
|
|
400
496
|
toString() {
|
|
401
497
|
return '[TransactionType]';
|
|
402
498
|
}
|
|
403
499
|
}
|
|
404
500
|
|
|
405
|
-
const buy = new TransactionType('B', 'Buy', 'Buy', 0, true, false, false, true, false, false, false, true, true);
|
|
406
|
-
const sell = new TransactionType('S', 'Sell', 'Sell', 0, false, true, false, false, true, false, false, false, true);
|
|
407
|
-
const buyShort = new TransactionType('BS', 'Buy To Cover', 'Buy To Cover', 0, true, false, false, false, true, false, false, false, true);
|
|
408
|
-
const sellShort = new TransactionType('SS', 'Sell Short', 'Sell Short', 0, false, true, false, true, false, false, false, true, true);
|
|
409
|
-
const dividend = new TransactionType('DV', 'Dividend', 'Dividend', 1, false, false, true, false, false, false, true, false, false);
|
|
410
|
-
const dividendReinvest = new TransactionType('DX', 'Dividend (Reinvested)', 'Dividend Reinvest', 1, false, false, false, true, false, false, true, false, false);
|
|
411
|
-
const dividendStock = new TransactionType('DS', 'Dividend (Stock)', 'Dividend Stock', 1, false, false, false, true, false, false, true, false, false);
|
|
412
|
-
const split = new TransactionType('SP', 'Split', 'Split', 1, false, false, false, true, false, false, true, false, false);
|
|
413
|
-
const fee = new TransactionType('F', 'Fee', 'Fee', 0, false, false, false, false, false, true, false, false, false);
|
|
414
|
-
const feeUnits = new TransactionType('FU', 'Fee Units', 'Fee', 0, false, false, false, false, true, false, false, false, false);
|
|
415
|
-
const delist = new TransactionType('DL', 'Delist', 'Delist', 1, false, false, false, false, false, false, true, false, false);
|
|
416
|
-
|
|
417
|
-
const
|
|
418
|
-
const
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
const
|
|
422
|
-
|
|
423
|
-
const
|
|
424
|
-
const
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
const
|
|
501
|
+
const buy = new TransactionType('B', 'Buy', 'Buy', 0, true, false, false, true, false, false, false, true, false, true, false, false, false);
|
|
502
|
+
const sell = new TransactionType('S', 'Sell', 'Sell', 0, false, true, false, false, true, false, false, false, false, true, false, false, false);
|
|
503
|
+
const buyShort = new TransactionType('BS', 'Buy To Cover', 'Buy To Cover', 0, true, false, false, false, true, false, false, false, false, true, false, false, false);
|
|
504
|
+
const sellShort = new TransactionType('SS', 'Sell Short', 'Sell Short', 0, false, true, false, true, false, false, false, true, false, true, false, false, false);
|
|
505
|
+
const dividend = new TransactionType('DV', 'Dividend', 'Dividend', 1, false, false, true, false, false, false, true, false, false, false, false, false, false);
|
|
506
|
+
const dividendReinvest = new TransactionType('DX', 'Dividend (Reinvested)', 'Dividend Reinvest', 1, false, false, false, true, false, false, true, false, false, false, false, false, false);
|
|
507
|
+
const dividendStock = new TransactionType('DS', 'Dividend (Stock)', 'Dividend Stock', 1, false, false, false, true, false, false, true, false, false, false, false, false, false);
|
|
508
|
+
const split = new TransactionType('SP', 'Split', 'Split', 1, false, false, false, true, false, false, true, false, false, false, false, false, false);
|
|
509
|
+
const fee = new TransactionType('F', 'Fee', 'Fee', 0, false, false, false, false, false, true, false, false, false, false, false, false, false);
|
|
510
|
+
const feeUnits = new TransactionType('FU', 'Fee Units', 'Fee', 0, false, false, false, false, true, false, false, false, false, false, false, false, false);
|
|
511
|
+
const delist = new TransactionType('DL', 'Delist', 'Delist', 1, false, false, false, false, false, false, true, false, true, false, false, false, false);
|
|
512
|
+
|
|
513
|
+
const mergerOpen = new TransactionType('MO', 'Merger Open', 'Merger Open', 1, false, false, false, true, false, false, true, true, false, true, false, true, true);
|
|
514
|
+
const mergerClose = new TransactionType('MC', 'Merger Close', 'Merger Close', 1, false, false, false, false, true, false, true, false, true, false, true, false, false);
|
|
515
|
+
|
|
516
|
+
const spinoff = new TransactionType('SPF', 'Spinoff', 'Spinoff', 1, false, false, false, false, false, false, true, false, false, false, true, false, false);
|
|
517
|
+
const spinoffOpen = new TransactionType('SPFO', 'Spinoff Open', 'Spinoff Open', 1, false, false, false, true, false, false, true, true, false, true, false, false, false);
|
|
518
|
+
|
|
519
|
+
const distributionCash = new TransactionType('DC', 'Distribution (Cash)', 'Cash Distribution', 1, false, false, true, false, false, false, true, false, false, false, false, false, false);
|
|
520
|
+
const distributionReinvest = new TransactionType('DY', 'Distribution (Reinvested)', 'Distribution Reinvest', 1, false, false, false, true, false, false, true, false, false, false, false, false, false);
|
|
521
|
+
const distributionFund = new TransactionType('DF', 'Distribution (Units)', 'Unit Distribution', 1, false, false, false, true, false, false, true, false, false, false, false, false, false);
|
|
522
|
+
|
|
523
|
+
const deposit = new TransactionType('D', 'Deposit', 'Deposit', 0, false, false, false, false, false, false, false, true, false, true, false, false, false);
|
|
524
|
+
const withdrawal = new TransactionType('W', 'Withdrawal', 'Withdrawal', 0, false, false, false, false, false, false, false, true, false, true, false, false, false);
|
|
525
|
+
const debit = new TransactionType('DR', 'Debit', 'Debit', 0, false, false, false, false, false, false, false, true, false, true, false, false, false);
|
|
526
|
+
const credit = new TransactionType('CR', 'Credit', 'Credit', 0, false, false, false, false, false, false, false, true, false, true, false, false, false);
|
|
527
|
+
|
|
528
|
+
const valuation = new TransactionType('V', 'Valuation', 'Valuation', 0, false, false, false, false, false, false, false, false, false, false, false, false, false);
|
|
529
|
+
const income = new TransactionType('I', 'Income', 'Income', 0, false, false, true, false, false, false, false, false, false, false, false, false, false);
|
|
428
530
|
|
|
429
531
|
return TransactionType;
|
|
430
532
|
})();
|
|
@@ -70,20 +70,20 @@ module.exports = (() => {
|
|
|
70
70
|
return transactions.every((t) => {
|
|
71
71
|
let valid = true;
|
|
72
72
|
|
|
73
|
-
if (is.object(t.reference) && is.string(t.reference.root) && is.
|
|
73
|
+
if (is.object(t.reference) && is.string(t.reference.root) && is.string(t.reference.transaction)) {
|
|
74
74
|
const root = t.reference.root;
|
|
75
|
-
const
|
|
75
|
+
const transaction = t.reference.transaction;
|
|
76
76
|
|
|
77
77
|
if (!references.hasOwnProperty(root)) {
|
|
78
78
|
references[root] = [ ];
|
|
79
79
|
}
|
|
80
80
|
|
|
81
|
-
const
|
|
81
|
+
const transactions = references[root];
|
|
82
82
|
|
|
83
|
-
if (
|
|
83
|
+
if (transactions.some(t => t === transaction)) {
|
|
84
84
|
valid = false;
|
|
85
85
|
} else {
|
|
86
|
-
|
|
86
|
+
transactions.push(transaction);
|
|
87
87
|
}
|
|
88
88
|
}
|
|
89
89
|
|
|
@@ -186,7 +186,7 @@ module.exports = (() => {
|
|
|
186
186
|
static validateInitialTransactionType(transactionType) {
|
|
187
187
|
return transactionType.initial;
|
|
188
188
|
}
|
|
189
|
-
|
|
189
|
+
|
|
190
190
|
/**
|
|
191
191
|
* Determines if a position for a given instrument type can exist in
|
|
192
192
|
* the given direction.
|
|
@@ -246,6 +246,10 @@ module.exports = (() => {
|
|
|
246
246
|
associateTypes(InstrumentType.EQUITY, TransactionType.DIVIDEND_STOCK, false);
|
|
247
247
|
associateTypes(InstrumentType.EQUITY, TransactionType.SPLIT, false);
|
|
248
248
|
associateTypes(InstrumentType.EQUITY, TransactionType.DELIST, false);
|
|
249
|
+
associateTypes(InstrumentType.EQUITY, TransactionType.MERGER_OPEN, false);
|
|
250
|
+
associateTypes(InstrumentType.EQUITY, TransactionType.MERGER_CLOSE, false);
|
|
251
|
+
associateTypes(InstrumentType.EQUITY, TransactionType.SPINOFF, false);
|
|
252
|
+
associateTypes(InstrumentType.EQUITY, TransactionType.SPINOFF_OPEN, false);
|
|
249
253
|
|
|
250
254
|
associateTypes(InstrumentType.FUND, TransactionType.BUY, true, [ PositionDirection.LONG, PositionDirection.EVEN ]);
|
|
251
255
|
associateTypes(InstrumentType.FUND, TransactionType.SELL, true, [ PositionDirection.LONG ]);
|
|
@@ -255,6 +259,10 @@ module.exports = (() => {
|
|
|
255
259
|
associateTypes(InstrumentType.FUND, TransactionType.DISTRIBUTION_REINVEST, false);
|
|
256
260
|
associateTypes(InstrumentType.FUND, TransactionType.DISTRIBUTION_FUND, false);
|
|
257
261
|
associateTypes(InstrumentType.FUND, TransactionType.DELIST, false);
|
|
262
|
+
associateTypes(InstrumentType.FUND, TransactionType.MERGER_OPEN, false);
|
|
263
|
+
associateTypes(InstrumentType.FUND, TransactionType.MERGER_CLOSE, false);
|
|
264
|
+
associateTypes(InstrumentType.FUND, TransactionType.SPINOFF, false);
|
|
265
|
+
associateTypes(InstrumentType.FUND, TransactionType.SPINOFF_OPEN, false);
|
|
258
266
|
|
|
259
267
|
associateTypes(InstrumentType.OTHER, TransactionType.BUY, true, [ PositionDirection.LONG, PositionDirection.EVEN ]);
|
|
260
268
|
associateTypes(InstrumentType.OTHER, TransactionType.SELL, true, [ PositionDirection.LONG ]);
|
|
@@ -326,6 +326,38 @@ module.exports = (() => {
|
|
|
326
326
|
f.description = t.description;
|
|
327
327
|
};
|
|
328
328
|
|
|
329
|
+
const mergerFormatter = (t, f) => {
|
|
330
|
+
f.boughtSold = t.quantity;
|
|
331
|
+
|
|
332
|
+
let rate;
|
|
333
|
+
|
|
334
|
+
if (!t.merger.denominator.getIsZero()) {
|
|
335
|
+
rate = t.merger.numerator.divide(t.merger.denominator);
|
|
336
|
+
} else {
|
|
337
|
+
rate = '';
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
f.rate = rate;
|
|
341
|
+
|
|
342
|
+
f.shares = t.snapshot.open.subtract(t.quantity);
|
|
343
|
+
};
|
|
344
|
+
|
|
345
|
+
const spinoffFormatter = (t, f) => {
|
|
346
|
+
f.boughtSold = t.quantity;
|
|
347
|
+
|
|
348
|
+
let rate;
|
|
349
|
+
|
|
350
|
+
if (!t.spinoff.denominator.getIsZero()) {
|
|
351
|
+
rate = t.spinoff.numerator.divide(t.spinoff.denominator);
|
|
352
|
+
} else {
|
|
353
|
+
rate = '';
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
f.rate = rate;
|
|
357
|
+
|
|
358
|
+
f.shares = t.snapshot.open.subtract(t.quantity);
|
|
359
|
+
};
|
|
360
|
+
|
|
329
361
|
const formatters = new Map();
|
|
330
362
|
|
|
331
363
|
formatters.set(TransactionType.BUY, [ basicFormatter, buySellFormatter, averageCostFormatter ]);
|
|
@@ -348,6 +380,10 @@ module.exports = (() => {
|
|
|
348
380
|
formatters.set(TransactionType.WITHDRAWAL, [ basicFormatter, cashFormatter ]);
|
|
349
381
|
formatters.set(TransactionType.DEBIT, [ basicFormatter, cashFormatter, debitFormatter ]);
|
|
350
382
|
formatters.set(TransactionType.CREDIT, [ basicFormatter, cashFormatter, creditFormatter ]);
|
|
383
|
+
formatters.set(TransactionType.MERGER_OPEN, [ basicFormatter ]);
|
|
384
|
+
formatters.set(TransactionType.MERGER_CLOSE, [ basicFormatter, mergerFormatter ]);
|
|
385
|
+
formatters.set(TransactionType.SPINOFF, [ basicFormatter, spinoffFormatter ]);
|
|
386
|
+
formatters.set(TransactionType.SPINOFF_OPEN, [ basicFormatter ]);
|
|
351
387
|
|
|
352
388
|
function getInstrumentTypePriority(type) {
|
|
353
389
|
if (type === InstrumentType.CASH) {
|
|
@@ -113,7 +113,7 @@ module.exports = (() => {
|
|
|
113
113
|
static get VALUATION() {
|
|
114
114
|
return valuation;
|
|
115
115
|
}
|
|
116
|
-
|
|
116
|
+
|
|
117
117
|
static get DELIST() {
|
|
118
118
|
return delist;
|
|
119
119
|
}
|
|
@@ -130,6 +130,7 @@ module.exports = (() => {
|
|
|
130
130
|
const complete = new TransactionSchema(SchemaBuilder.withName('complete')
|
|
131
131
|
.withField('portfolio', DataType.STRING)
|
|
132
132
|
.withField('position', DataType.STRING)
|
|
133
|
+
.withField('transaction', DataType.STRING)
|
|
133
134
|
.withField('sequence', DataType.NUMBER)
|
|
134
135
|
.withField('type', DataType.forEnum(TransactionType, 'TransactionType'))
|
|
135
136
|
.withField('date', DataType.DAY)
|
|
@@ -138,7 +139,7 @@ module.exports = (() => {
|
|
|
138
139
|
.withField('quantity', DataType.DECIMAL)
|
|
139
140
|
.withField('fee', DataType.DECIMAL, true)
|
|
140
141
|
.withField('reference.position', DataType.STRING, true)
|
|
141
|
-
.withField('reference.
|
|
142
|
+
.withField('reference.transaction', DataType.STRING, true)
|
|
142
143
|
.withField('snapshot.open', DataType.DECIMAL)
|
|
143
144
|
.withField('snapshot.direction', DataType.forEnum(PositionDirection, 'PositionDirection'))
|
|
144
145
|
.withField('snapshot.buys', DataType.DECIMAL)
|
|
@@ -162,6 +163,10 @@ module.exports = (() => {
|
|
|
162
163
|
.withField('split.denominator', DataType.DECIMAL, true)
|
|
163
164
|
.withField('split.effective', DataType.DAY, true)
|
|
164
165
|
.withField('split.reference', DataType.STRING, true)
|
|
166
|
+
.withField('merger.numerator', DataType.DECIMAL, true)
|
|
167
|
+
.withField('merger.denominator', DataType.DECIMAL, true)
|
|
168
|
+
.withField('spinoff.numerator', DataType.DECIMAL, true)
|
|
169
|
+
.withField('spinoff.denominator', DataType.DECIMAL, true)
|
|
165
170
|
.withField('charge.amount', DataType.DECIMAL, true)
|
|
166
171
|
.withField('income.amount', DataType.DECIMAL, true)
|
|
167
172
|
.withField('valuation.rate', DataType.DECIMAL, true)
|
|
@@ -175,6 +180,7 @@ module.exports = (() => {
|
|
|
175
180
|
const client = new TransactionSchema(SchemaBuilder.withName('client')
|
|
176
181
|
.withField('portfolio', DataType.STRING)
|
|
177
182
|
.withField('position', DataType.STRING)
|
|
183
|
+
.withField('transaction', DataType.STRING)
|
|
178
184
|
.withField('sequence', DataType.NUMBER)
|
|
179
185
|
.withField('type', DataType.forEnum(TransactionType, 'TransactionType'))
|
|
180
186
|
.withField('date', DataType.DAY)
|
|
@@ -183,7 +189,7 @@ module.exports = (() => {
|
|
|
183
189
|
.withField('quantity', DataType.DECIMAL)
|
|
184
190
|
.withField('fee', DataType.DECIMAL, true)
|
|
185
191
|
.withField('reference.position', DataType.STRING, true)
|
|
186
|
-
.withField('reference.
|
|
192
|
+
.withField('reference.transaction', DataType.NUMBER, true)
|
|
187
193
|
.withField('snapshot.open', DataType.DECIMAL)
|
|
188
194
|
.withField('snapshot.direction', DataType.forEnum(PositionDirection, 'PositionDirection'))
|
|
189
195
|
.withField('snapshot.buys', DataType.DECIMAL)
|
|
@@ -201,6 +207,10 @@ module.exports = (() => {
|
|
|
201
207
|
.withField('split.denominator', DataType.DECIMAL, true)
|
|
202
208
|
.withField('split.effective', DataType.DAY, true)
|
|
203
209
|
.withField('split.reference', DataType.STRING, true)
|
|
210
|
+
.withField('merger.numerator', DataType.DECIMAL, true)
|
|
211
|
+
.withField('merger.denominator', DataType.DECIMAL, true)
|
|
212
|
+
.withField('spinoff.numerator', DataType.DECIMAL, true)
|
|
213
|
+
.withField('spinoff.denominator', DataType.DECIMAL, true)
|
|
204
214
|
.withField('charge.amount', DataType.DECIMAL, true)
|
|
205
215
|
.withField('income.amount', DataType.DECIMAL, true)
|
|
206
216
|
.withField('valuation.rate', DataType.DECIMAL, true)
|
|
@@ -326,7 +336,7 @@ module.exports = (() => {
|
|
|
326
336
|
.withField('force', DataType.BOOLEAN, true)
|
|
327
337
|
.schema
|
|
328
338
|
);
|
|
329
|
-
|
|
339
|
+
|
|
330
340
|
const delist = new TransactionSchema(SchemaBuilder.withName(TransactionType.DELIST.code)
|
|
331
341
|
.withField('portfolio', DataType.STRING)
|
|
332
342
|
.withField('position', DataType.STRING)
|
|
@@ -336,7 +346,7 @@ module.exports = (() => {
|
|
|
336
346
|
.withField('force', DataType.BOOLEAN, true)
|
|
337
347
|
.schema
|
|
338
348
|
);
|
|
339
|
-
|
|
349
|
+
|
|
340
350
|
const income = new TransactionSchema(SchemaBuilder.withName(TransactionType.INCOME.code)
|
|
341
351
|
.withField('portfolio', DataType.STRING)
|
|
342
352
|
.withField('position', DataType.STRING)
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@barchart/portfolio-api-common",
|
|
3
|
-
"version": "1.3.
|
|
4
|
-
"description": "Common
|
|
3
|
+
"version": "1.3.24",
|
|
4
|
+
"description": "Common code used by the Portfolio system",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Bryan Ingle",
|
|
7
7
|
"email": "bryan.ingle@barchart.com",
|
|
@@ -22,9 +22,7 @@
|
|
|
22
22
|
"gulp-bump": "~1.0.0",
|
|
23
23
|
"gulp-git": "^2.9.0",
|
|
24
24
|
"gulp-jasmine": "^2.2.1",
|
|
25
|
-
"gulp-jsdoc3": "^1.0.1",
|
|
26
25
|
"gulp-jshint": "~2.1.0",
|
|
27
|
-
"gulp-replace": "^0.5.4",
|
|
28
26
|
"jsdoc": "^3.5.5",
|
|
29
27
|
"jshint": "2.9.5",
|
|
30
28
|
"vinyl-buffer": "^1.0.1",
|
package/test/SpecRunner.js
CHANGED
|
@@ -774,11 +774,14 @@ module.exports = (() => {
|
|
|
774
774
|
* @param {Boolean} fee
|
|
775
775
|
* @param {Boolean} corporateAction
|
|
776
776
|
* @param {Boolean} initial
|
|
777
|
+
* @param {Boolean} terminal
|
|
777
778
|
* @param {Boolean} significant
|
|
778
|
-
* @param {Boolean}
|
|
779
|
+
* @param {Boolean} chaining
|
|
780
|
+
* @param {Boolean} chained
|
|
781
|
+
* @param {Boolean} transfer
|
|
779
782
|
*/
|
|
780
783
|
class TransactionType extends Enum {
|
|
781
|
-
constructor(code, description, display, sequence, purchase, sale, income, opening, closing, fee, corporateAction, initial, significant) {
|
|
784
|
+
constructor(code, description, display, sequence, purchase, sale, income, opening, closing, fee, corporateAction, initial, terminal, significant, chaining, chained, transfer) {
|
|
782
785
|
super(code, description);
|
|
783
786
|
|
|
784
787
|
assert.argumentIsRequired(display, 'display', String);
|
|
@@ -791,7 +794,11 @@ module.exports = (() => {
|
|
|
791
794
|
assert.argumentIsRequired(fee, 'fee', Boolean);
|
|
792
795
|
assert.argumentIsRequired(corporateAction, 'corporateAction', Boolean);
|
|
793
796
|
assert.argumentIsRequired(initial, 'initial', Boolean);
|
|
797
|
+
assert.argumentIsRequired(terminal, 'terminal', Boolean);
|
|
794
798
|
assert.argumentIsRequired(significant, 'significant', Boolean);
|
|
799
|
+
assert.argumentIsRequired(chaining, 'chaining', Boolean);
|
|
800
|
+
assert.argumentIsRequired(chained, 'chained', Boolean);
|
|
801
|
+
assert.argumentIsRequired(transfer, 'transfer', Boolean);
|
|
795
802
|
|
|
796
803
|
this._display = display;
|
|
797
804
|
this._sequence = sequence;
|
|
@@ -803,7 +810,11 @@ module.exports = (() => {
|
|
|
803
810
|
this._fee = fee;
|
|
804
811
|
this._corporateAction = corporateAction;
|
|
805
812
|
this._initial = initial;
|
|
813
|
+
this._terminal = terminal;
|
|
806
814
|
this._significant = significant;
|
|
815
|
+
this._chaining = chaining;
|
|
816
|
+
this._chained = chained;
|
|
817
|
+
this._transfer = transfer;
|
|
807
818
|
}
|
|
808
819
|
|
|
809
820
|
/**
|
|
@@ -920,6 +931,16 @@ module.exports = (() => {
|
|
|
920
931
|
return this._initial;
|
|
921
932
|
}
|
|
922
933
|
|
|
934
|
+
/**
|
|
935
|
+
* Indicates if the transaction must be the last
|
|
936
|
+
*
|
|
937
|
+
* @public
|
|
938
|
+
* @returns {Boolean}
|
|
939
|
+
*/
|
|
940
|
+
get terminal() {
|
|
941
|
+
return this._terminal;
|
|
942
|
+
}
|
|
943
|
+
|
|
923
944
|
/**
|
|
924
945
|
* Significant transactions cannot be discarded during transaction re-write.
|
|
925
946
|
*
|
|
@@ -930,6 +951,37 @@ module.exports = (() => {
|
|
|
930
951
|
return this._significant;
|
|
931
952
|
}
|
|
932
953
|
|
|
954
|
+
/**
|
|
955
|
+
* Chain transactions cause another position to be created.
|
|
956
|
+
*
|
|
957
|
+
* @public
|
|
958
|
+
* @returns {Boolean}
|
|
959
|
+
*/
|
|
960
|
+
get chaining() {
|
|
961
|
+
return this._chaining;
|
|
962
|
+
}
|
|
963
|
+
|
|
964
|
+
/**
|
|
965
|
+
* Chained transactions are created from another position.
|
|
966
|
+
*
|
|
967
|
+
* @public
|
|
968
|
+
* @returns {Boolean}
|
|
969
|
+
*/
|
|
970
|
+
get chained() {
|
|
971
|
+
return this._chained;
|
|
972
|
+
}
|
|
973
|
+
|
|
974
|
+
/**
|
|
975
|
+
* Indicates if the transaction should cause gains and losses to be
|
|
976
|
+
* transferred from the original (chaining) position.
|
|
977
|
+
*
|
|
978
|
+
* @public
|
|
979
|
+
* @returns {Boolean}
|
|
980
|
+
*/
|
|
981
|
+
get transfer() {
|
|
982
|
+
return this._transfer;
|
|
983
|
+
}
|
|
984
|
+
|
|
933
985
|
/**
|
|
934
986
|
* A purchase.
|
|
935
987
|
*
|
|
@@ -1105,7 +1157,7 @@ module.exports = (() => {
|
|
|
1105
1157
|
static get DEBIT() {
|
|
1106
1158
|
return debit;
|
|
1107
1159
|
}
|
|
1108
|
-
|
|
1160
|
+
|
|
1109
1161
|
/**
|
|
1110
1162
|
* A system-generated transaction, indicating the security has stopped active trading.
|
|
1111
1163
|
*
|
|
@@ -1150,34 +1202,84 @@ module.exports = (() => {
|
|
|
1150
1202
|
return income;
|
|
1151
1203
|
}
|
|
1152
1204
|
|
|
1205
|
+
/**
|
|
1206
|
+
* A merger opening.
|
|
1207
|
+
*
|
|
1208
|
+
* @public
|
|
1209
|
+
* @static
|
|
1210
|
+
* @returns {TransactionType}
|
|
1211
|
+
*/
|
|
1212
|
+
static get MERGER_OPEN() {
|
|
1213
|
+
return mergerOpen;
|
|
1214
|
+
}
|
|
1215
|
+
|
|
1216
|
+
/**
|
|
1217
|
+
* A merger closing.
|
|
1218
|
+
*
|
|
1219
|
+
* @public
|
|
1220
|
+
* @static
|
|
1221
|
+
* @returns {TransactionType}
|
|
1222
|
+
*/
|
|
1223
|
+
static get MERGER_CLOSE() {
|
|
1224
|
+
return mergerClose;
|
|
1225
|
+
}
|
|
1226
|
+
|
|
1227
|
+
/**
|
|
1228
|
+
* A spin-off.
|
|
1229
|
+
*
|
|
1230
|
+
* @public
|
|
1231
|
+
* @static
|
|
1232
|
+
* @returns {TransactionType}
|
|
1233
|
+
*/
|
|
1234
|
+
static get SPINOFF() {
|
|
1235
|
+
return spinoff;
|
|
1236
|
+
}
|
|
1237
|
+
|
|
1238
|
+
/**
|
|
1239
|
+
* A spin-off opening.
|
|
1240
|
+
*
|
|
1241
|
+
* @public
|
|
1242
|
+
* @static
|
|
1243
|
+
* @returns {TransactionType}
|
|
1244
|
+
*/
|
|
1245
|
+
static get SPINOFF_OPEN() {
|
|
1246
|
+
return spinoffOpen;
|
|
1247
|
+
}
|
|
1248
|
+
|
|
1153
1249
|
toString() {
|
|
1154
1250
|
return '[TransactionType]';
|
|
1155
1251
|
}
|
|
1156
1252
|
}
|
|
1157
1253
|
|
|
1158
|
-
const buy = new TransactionType('B', 'Buy', 'Buy', 0, true, false, false, true, false, false, false, true, true);
|
|
1159
|
-
const sell = new TransactionType('S', 'Sell', 'Sell', 0, false, true, false, false, true, false, false, false, true);
|
|
1160
|
-
const buyShort = new TransactionType('BS', 'Buy To Cover', 'Buy To Cover', 0, true, false, false, false, true, false, false, false, true);
|
|
1161
|
-
const sellShort = new TransactionType('SS', 'Sell Short', 'Sell Short', 0, false, true, false, true, false, false, false, true, true);
|
|
1162
|
-
const dividend = new TransactionType('DV', 'Dividend', 'Dividend', 1, false, false, true, false, false, false, true, false, false);
|
|
1163
|
-
const dividendReinvest = new TransactionType('DX', 'Dividend (Reinvested)', 'Dividend Reinvest', 1, false, false, false, true, false, false, true, false, false);
|
|
1164
|
-
const dividendStock = new TransactionType('DS', 'Dividend (Stock)', 'Dividend Stock', 1, false, false, false, true, false, false, true, false, false);
|
|
1165
|
-
const split = new TransactionType('SP', 'Split', 'Split', 1, false, false, false, true, false, false, true, false, false);
|
|
1166
|
-
const fee = new TransactionType('F', 'Fee', 'Fee', 0, false, false, false, false, false, true, false, false, false);
|
|
1167
|
-
const feeUnits = new TransactionType('FU', 'Fee Units', 'Fee', 0, false, false, false, false, true, false, false, false, false);
|
|
1168
|
-
const delist = new TransactionType('DL', 'Delist', 'Delist', 1, false, false, false, false, false, false, true, false, false);
|
|
1169
|
-
|
|
1170
|
-
const
|
|
1171
|
-
const
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
const
|
|
1175
|
-
|
|
1176
|
-
const
|
|
1177
|
-
const
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
const
|
|
1254
|
+
const buy = new TransactionType('B', 'Buy', 'Buy', 0, true, false, false, true, false, false, false, true, false, true, false, false, false);
|
|
1255
|
+
const sell = new TransactionType('S', 'Sell', 'Sell', 0, false, true, false, false, true, false, false, false, false, true, false, false, false);
|
|
1256
|
+
const buyShort = new TransactionType('BS', 'Buy To Cover', 'Buy To Cover', 0, true, false, false, false, true, false, false, false, false, true, false, false, false);
|
|
1257
|
+
const sellShort = new TransactionType('SS', 'Sell Short', 'Sell Short', 0, false, true, false, true, false, false, false, true, false, true, false, false, false);
|
|
1258
|
+
const dividend = new TransactionType('DV', 'Dividend', 'Dividend', 1, false, false, true, false, false, false, true, false, false, false, false, false, false);
|
|
1259
|
+
const dividendReinvest = new TransactionType('DX', 'Dividend (Reinvested)', 'Dividend Reinvest', 1, false, false, false, true, false, false, true, false, false, false, false, false, false);
|
|
1260
|
+
const dividendStock = new TransactionType('DS', 'Dividend (Stock)', 'Dividend Stock', 1, false, false, false, true, false, false, true, false, false, false, false, false, false);
|
|
1261
|
+
const split = new TransactionType('SP', 'Split', 'Split', 1, false, false, false, true, false, false, true, false, false, false, false, false, false);
|
|
1262
|
+
const fee = new TransactionType('F', 'Fee', 'Fee', 0, false, false, false, false, false, true, false, false, false, false, false, false, false);
|
|
1263
|
+
const feeUnits = new TransactionType('FU', 'Fee Units', 'Fee', 0, false, false, false, false, true, false, false, false, false, false, false, false, false);
|
|
1264
|
+
const delist = new TransactionType('DL', 'Delist', 'Delist', 1, false, false, false, false, false, false, true, false, true, false, false, false, false);
|
|
1265
|
+
|
|
1266
|
+
const mergerOpen = new TransactionType('MO', 'Merger Open', 'Merger Open', 1, false, false, false, true, false, false, true, true, false, true, false, true, true);
|
|
1267
|
+
const mergerClose = new TransactionType('MC', 'Merger Close', 'Merger Close', 1, false, false, false, false, true, false, true, false, true, false, true, false, false);
|
|
1268
|
+
|
|
1269
|
+
const spinoff = new TransactionType('SPF', 'Spinoff', 'Spinoff', 1, false, false, false, false, false, false, true, false, false, false, true, false, false);
|
|
1270
|
+
const spinoffOpen = new TransactionType('SPFO', 'Spinoff Open', 'Spinoff Open', 1, false, false, false, true, false, false, true, true, false, true, false, false, false);
|
|
1271
|
+
|
|
1272
|
+
const distributionCash = new TransactionType('DC', 'Distribution (Cash)', 'Cash Distribution', 1, false, false, true, false, false, false, true, false, false, false, false, false, false);
|
|
1273
|
+
const distributionReinvest = new TransactionType('DY', 'Distribution (Reinvested)', 'Distribution Reinvest', 1, false, false, false, true, false, false, true, false, false, false, false, false, false);
|
|
1274
|
+
const distributionFund = new TransactionType('DF', 'Distribution (Units)', 'Unit Distribution', 1, false, false, false, true, false, false, true, false, false, false, false, false, false);
|
|
1275
|
+
|
|
1276
|
+
const deposit = new TransactionType('D', 'Deposit', 'Deposit', 0, false, false, false, false, false, false, false, true, false, true, false, false, false);
|
|
1277
|
+
const withdrawal = new TransactionType('W', 'Withdrawal', 'Withdrawal', 0, false, false, false, false, false, false, false, true, false, true, false, false, false);
|
|
1278
|
+
const debit = new TransactionType('DR', 'Debit', 'Debit', 0, false, false, false, false, false, false, false, true, false, true, false, false, false);
|
|
1279
|
+
const credit = new TransactionType('CR', 'Credit', 'Credit', 0, false, false, false, false, false, false, false, true, false, true, false, false, false);
|
|
1280
|
+
|
|
1281
|
+
const valuation = new TransactionType('V', 'Valuation', 'Valuation', 0, false, false, false, false, false, false, false, false, false, false, false, false, false);
|
|
1282
|
+
const income = new TransactionType('I', 'Income', 'Income', 0, false, false, true, false, false, false, false, false, false, false, false, false, false);
|
|
1181
1283
|
|
|
1182
1284
|
return TransactionType;
|
|
1183
1285
|
})();
|
|
@@ -1255,20 +1357,20 @@ module.exports = (() => {
|
|
|
1255
1357
|
return transactions.every((t) => {
|
|
1256
1358
|
let valid = true;
|
|
1257
1359
|
|
|
1258
|
-
if (is.object(t.reference) && is.string(t.reference.root) && is.
|
|
1360
|
+
if (is.object(t.reference) && is.string(t.reference.root) && is.string(t.reference.transaction)) {
|
|
1259
1361
|
const root = t.reference.root;
|
|
1260
|
-
const
|
|
1362
|
+
const transaction = t.reference.transaction;
|
|
1261
1363
|
|
|
1262
1364
|
if (!references.hasOwnProperty(root)) {
|
|
1263
1365
|
references[root] = [ ];
|
|
1264
1366
|
}
|
|
1265
1367
|
|
|
1266
|
-
const
|
|
1368
|
+
const transactions = references[root];
|
|
1267
1369
|
|
|
1268
|
-
if (
|
|
1370
|
+
if (transactions.some(t => t === transaction)) {
|
|
1269
1371
|
valid = false;
|
|
1270
1372
|
} else {
|
|
1271
|
-
|
|
1373
|
+
transactions.push(transaction);
|
|
1272
1374
|
}
|
|
1273
1375
|
}
|
|
1274
1376
|
|
|
@@ -1371,7 +1473,7 @@ module.exports = (() => {
|
|
|
1371
1473
|
static validateInitialTransactionType(transactionType) {
|
|
1372
1474
|
return transactionType.initial;
|
|
1373
1475
|
}
|
|
1374
|
-
|
|
1476
|
+
|
|
1375
1477
|
/**
|
|
1376
1478
|
* Determines if a position for a given instrument type can exist in
|
|
1377
1479
|
* the given direction.
|
|
@@ -1431,6 +1533,10 @@ module.exports = (() => {
|
|
|
1431
1533
|
associateTypes(InstrumentType.EQUITY, TransactionType.DIVIDEND_STOCK, false);
|
|
1432
1534
|
associateTypes(InstrumentType.EQUITY, TransactionType.SPLIT, false);
|
|
1433
1535
|
associateTypes(InstrumentType.EQUITY, TransactionType.DELIST, false);
|
|
1536
|
+
associateTypes(InstrumentType.EQUITY, TransactionType.MERGER_OPEN, false);
|
|
1537
|
+
associateTypes(InstrumentType.EQUITY, TransactionType.MERGER_CLOSE, false);
|
|
1538
|
+
associateTypes(InstrumentType.EQUITY, TransactionType.SPINOFF, false);
|
|
1539
|
+
associateTypes(InstrumentType.EQUITY, TransactionType.SPINOFF_OPEN, false);
|
|
1434
1540
|
|
|
1435
1541
|
associateTypes(InstrumentType.FUND, TransactionType.BUY, true, [ PositionDirection.LONG, PositionDirection.EVEN ]);
|
|
1436
1542
|
associateTypes(InstrumentType.FUND, TransactionType.SELL, true, [ PositionDirection.LONG ]);
|
|
@@ -1440,6 +1546,10 @@ module.exports = (() => {
|
|
|
1440
1546
|
associateTypes(InstrumentType.FUND, TransactionType.DISTRIBUTION_REINVEST, false);
|
|
1441
1547
|
associateTypes(InstrumentType.FUND, TransactionType.DISTRIBUTION_FUND, false);
|
|
1442
1548
|
associateTypes(InstrumentType.FUND, TransactionType.DELIST, false);
|
|
1549
|
+
associateTypes(InstrumentType.FUND, TransactionType.MERGER_OPEN, false);
|
|
1550
|
+
associateTypes(InstrumentType.FUND, TransactionType.MERGER_CLOSE, false);
|
|
1551
|
+
associateTypes(InstrumentType.FUND, TransactionType.SPINOFF, false);
|
|
1552
|
+
associateTypes(InstrumentType.FUND, TransactionType.SPINOFF_OPEN, false);
|
|
1443
1553
|
|
|
1444
1554
|
associateTypes(InstrumentType.OTHER, TransactionType.BUY, true, [ PositionDirection.LONG, PositionDirection.EVEN ]);
|
|
1445
1555
|
associateTypes(InstrumentType.OTHER, TransactionType.SELL, true, [ PositionDirection.LONG ]);
|
|
@@ -4853,7 +4963,7 @@ module.exports = (() => {
|
|
|
4853
4963
|
static get VALUATION() {
|
|
4854
4964
|
return valuation;
|
|
4855
4965
|
}
|
|
4856
|
-
|
|
4966
|
+
|
|
4857
4967
|
static get DELIST() {
|
|
4858
4968
|
return delist;
|
|
4859
4969
|
}
|
|
@@ -4870,6 +4980,7 @@ module.exports = (() => {
|
|
|
4870
4980
|
const complete = new TransactionSchema(SchemaBuilder.withName('complete')
|
|
4871
4981
|
.withField('portfolio', DataType.STRING)
|
|
4872
4982
|
.withField('position', DataType.STRING)
|
|
4983
|
+
.withField('transaction', DataType.STRING)
|
|
4873
4984
|
.withField('sequence', DataType.NUMBER)
|
|
4874
4985
|
.withField('type', DataType.forEnum(TransactionType, 'TransactionType'))
|
|
4875
4986
|
.withField('date', DataType.DAY)
|
|
@@ -4878,7 +4989,7 @@ module.exports = (() => {
|
|
|
4878
4989
|
.withField('quantity', DataType.DECIMAL)
|
|
4879
4990
|
.withField('fee', DataType.DECIMAL, true)
|
|
4880
4991
|
.withField('reference.position', DataType.STRING, true)
|
|
4881
|
-
.withField('reference.
|
|
4992
|
+
.withField('reference.transaction', DataType.STRING, true)
|
|
4882
4993
|
.withField('snapshot.open', DataType.DECIMAL)
|
|
4883
4994
|
.withField('snapshot.direction', DataType.forEnum(PositionDirection, 'PositionDirection'))
|
|
4884
4995
|
.withField('snapshot.buys', DataType.DECIMAL)
|
|
@@ -4902,6 +5013,10 @@ module.exports = (() => {
|
|
|
4902
5013
|
.withField('split.denominator', DataType.DECIMAL, true)
|
|
4903
5014
|
.withField('split.effective', DataType.DAY, true)
|
|
4904
5015
|
.withField('split.reference', DataType.STRING, true)
|
|
5016
|
+
.withField('merger.numerator', DataType.DECIMAL, true)
|
|
5017
|
+
.withField('merger.denominator', DataType.DECIMAL, true)
|
|
5018
|
+
.withField('spinoff.numerator', DataType.DECIMAL, true)
|
|
5019
|
+
.withField('spinoff.denominator', DataType.DECIMAL, true)
|
|
4905
5020
|
.withField('charge.amount', DataType.DECIMAL, true)
|
|
4906
5021
|
.withField('income.amount', DataType.DECIMAL, true)
|
|
4907
5022
|
.withField('valuation.rate', DataType.DECIMAL, true)
|
|
@@ -4915,6 +5030,7 @@ module.exports = (() => {
|
|
|
4915
5030
|
const client = new TransactionSchema(SchemaBuilder.withName('client')
|
|
4916
5031
|
.withField('portfolio', DataType.STRING)
|
|
4917
5032
|
.withField('position', DataType.STRING)
|
|
5033
|
+
.withField('transaction', DataType.STRING)
|
|
4918
5034
|
.withField('sequence', DataType.NUMBER)
|
|
4919
5035
|
.withField('type', DataType.forEnum(TransactionType, 'TransactionType'))
|
|
4920
5036
|
.withField('date', DataType.DAY)
|
|
@@ -4923,7 +5039,7 @@ module.exports = (() => {
|
|
|
4923
5039
|
.withField('quantity', DataType.DECIMAL)
|
|
4924
5040
|
.withField('fee', DataType.DECIMAL, true)
|
|
4925
5041
|
.withField('reference.position', DataType.STRING, true)
|
|
4926
|
-
.withField('reference.
|
|
5042
|
+
.withField('reference.transaction', DataType.NUMBER, true)
|
|
4927
5043
|
.withField('snapshot.open', DataType.DECIMAL)
|
|
4928
5044
|
.withField('snapshot.direction', DataType.forEnum(PositionDirection, 'PositionDirection'))
|
|
4929
5045
|
.withField('snapshot.buys', DataType.DECIMAL)
|
|
@@ -4941,6 +5057,10 @@ module.exports = (() => {
|
|
|
4941
5057
|
.withField('split.denominator', DataType.DECIMAL, true)
|
|
4942
5058
|
.withField('split.effective', DataType.DAY, true)
|
|
4943
5059
|
.withField('split.reference', DataType.STRING, true)
|
|
5060
|
+
.withField('merger.numerator', DataType.DECIMAL, true)
|
|
5061
|
+
.withField('merger.denominator', DataType.DECIMAL, true)
|
|
5062
|
+
.withField('spinoff.numerator', DataType.DECIMAL, true)
|
|
5063
|
+
.withField('spinoff.denominator', DataType.DECIMAL, true)
|
|
4944
5064
|
.withField('charge.amount', DataType.DECIMAL, true)
|
|
4945
5065
|
.withField('income.amount', DataType.DECIMAL, true)
|
|
4946
5066
|
.withField('valuation.rate', DataType.DECIMAL, true)
|
|
@@ -5066,7 +5186,7 @@ module.exports = (() => {
|
|
|
5066
5186
|
.withField('force', DataType.BOOLEAN, true)
|
|
5067
5187
|
.schema
|
|
5068
5188
|
);
|
|
5069
|
-
|
|
5189
|
+
|
|
5070
5190
|
const delist = new TransactionSchema(SchemaBuilder.withName(TransactionType.DELIST.code)
|
|
5071
5191
|
.withField('portfolio', DataType.STRING)
|
|
5072
5192
|
.withField('position', DataType.STRING)
|
|
@@ -5076,7 +5196,7 @@ module.exports = (() => {
|
|
|
5076
5196
|
.withField('force', DataType.BOOLEAN, true)
|
|
5077
5197
|
.schema
|
|
5078
5198
|
);
|
|
5079
|
-
|
|
5199
|
+
|
|
5080
5200
|
const income = new TransactionSchema(SchemaBuilder.withName(TransactionType.INCOME.code)
|
|
5081
5201
|
.withField('portfolio', DataType.STRING)
|
|
5082
5202
|
.withField('position', DataType.STRING)
|
|
@@ -7370,6 +7490,7 @@ module.exports = (() => {
|
|
|
7370
7490
|
* item's value. If no matching item can be found, a null value is returned.
|
|
7371
7491
|
*
|
|
7372
7492
|
* @public
|
|
7493
|
+
* @static
|
|
7373
7494
|
* @param {Function} type - The enumeration type.
|
|
7374
7495
|
* @param {String} code - The enumeration item's code.
|
|
7375
7496
|
* @returns {*|null}
|
|
@@ -7383,6 +7504,7 @@ module.exports = (() => {
|
|
|
7383
7504
|
* Returns all of the enumeration's items (given an enumeration type).
|
|
7384
7505
|
*
|
|
7385
7506
|
* @public
|
|
7507
|
+
* @static
|
|
7386
7508
|
* @param {Function} type - The enumeration to list.
|
|
7387
7509
|
* @returns {Array}
|
|
7388
7510
|
*/
|
|
@@ -17467,7 +17589,7 @@ describe('After the PositionSummaryFrame enumeration is initialized', () => {
|
|
|
17467
17589
|
}
|
|
17468
17590
|
];
|
|
17469
17591
|
|
|
17470
|
-
ranges = PositionSummaryFrame.YTD.getRanges(transactions)
|
|
17592
|
+
ranges = PositionSummaryFrame.YTD.getRanges(transactions);
|
|
17471
17593
|
});
|
|
17472
17594
|
|
|
17473
17595
|
it('should have one range', () => {
|
|
@@ -17724,8 +17846,8 @@ describe('When validating transaction order', () => {
|
|
|
17724
17846
|
describe('When validating transaction references', () => {
|
|
17725
17847
|
'use strict';
|
|
17726
17848
|
|
|
17727
|
-
const build = (root,
|
|
17728
|
-
return { reference: { root: root,
|
|
17849
|
+
const build = (root, transaction) => {
|
|
17850
|
+
return { reference: { root: root, transaction: transaction } };
|
|
17729
17851
|
};
|
|
17730
17852
|
|
|
17731
17853
|
it('An array of zero transactions should be valid', () => {
|
|
@@ -17737,11 +17859,11 @@ describe('When validating transaction references', () => {
|
|
|
17737
17859
|
});
|
|
17738
17860
|
|
|
17739
17861
|
it('An array with distinct references should be valid', () => {
|
|
17740
|
-
expect(TransactionValidator.validateReferences([ build('a',
|
|
17862
|
+
expect(TransactionValidator.validateReferences([ build('a', 'x'), build('a', 'y'), build('b', 'y') ])).toEqual(true);
|
|
17741
17863
|
});
|
|
17742
17864
|
|
|
17743
17865
|
it('An array with non-distinct references should be not valid', () => {
|
|
17744
|
-
expect(TransactionValidator.validateReferences([ build('a',
|
|
17866
|
+
expect(TransactionValidator.validateReferences([ build('a', 'x'), build('a', 'y'), build('b', 'x'), build('a', 'y') ])).toEqual(false);
|
|
17745
17867
|
});
|
|
17746
17868
|
});
|
|
17747
17869
|
|
|
@@ -432,7 +432,7 @@ describe('After the PositionSummaryFrame enumeration is initialized', () => {
|
|
|
432
432
|
}
|
|
433
433
|
];
|
|
434
434
|
|
|
435
|
-
ranges = PositionSummaryFrame.YTD.getRanges(transactions)
|
|
435
|
+
ranges = PositionSummaryFrame.YTD.getRanges(transactions);
|
|
436
436
|
});
|
|
437
437
|
|
|
438
438
|
it('should have one range', () => {
|
|
@@ -58,8 +58,8 @@ describe('When validating transaction order', () => {
|
|
|
58
58
|
describe('When validating transaction references', () => {
|
|
59
59
|
'use strict';
|
|
60
60
|
|
|
61
|
-
const build = (root,
|
|
62
|
-
return { reference: { root: root,
|
|
61
|
+
const build = (root, transaction) => {
|
|
62
|
+
return { reference: { root: root, transaction: transaction } };
|
|
63
63
|
};
|
|
64
64
|
|
|
65
65
|
it('An array of zero transactions should be valid', () => {
|
|
@@ -71,11 +71,11 @@ describe('When validating transaction references', () => {
|
|
|
71
71
|
});
|
|
72
72
|
|
|
73
73
|
it('An array with distinct references should be valid', () => {
|
|
74
|
-
expect(TransactionValidator.validateReferences([ build('a',
|
|
74
|
+
expect(TransactionValidator.validateReferences([ build('a', 'x'), build('a', 'y'), build('b', 'y') ])).toEqual(true);
|
|
75
75
|
});
|
|
76
76
|
|
|
77
77
|
it('An array with non-distinct references should be not valid', () => {
|
|
78
|
-
expect(TransactionValidator.validateReferences([ build('a',
|
|
78
|
+
expect(TransactionValidator.validateReferences([ build('a', 'x'), build('a', 'y'), build('b', 'x'), build('a', 'y') ])).toEqual(false);
|
|
79
79
|
});
|
|
80
80
|
});
|
|
81
81
|
|