@barchart/portfolio-api-common 1.2.117 → 1.2.122
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/lib/api/failures/PortfolioFailureType.js +41 -1
- package/lib/data/CorporateActionType.js +5 -8
- package/lib/data/TransactionType.js +2 -3
- package/lib/data/TransactionValidator.js +2 -1
- package/lib/formatters/TransactionFormatter.js +137 -153
- package/package.json +1 -1
- package/test/SpecRunner.js +37 -121
- package/test/specs/data/PositionSummaryFrameSpec.js +31 -115
- package/test/specs/data/TransactionValidatorSpec.js +1 -1
|
@@ -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
|
+
})();
|
|
@@ -11,13 +11,10 @@ module.exports = (() => {
|
|
|
11
11
|
* @extends {Enum}
|
|
12
12
|
* @param {String} code
|
|
13
13
|
* @param {String} description
|
|
14
|
-
* @param {Boolean} internal
|
|
15
14
|
*/
|
|
16
15
|
class CorporateActionType extends Enum {
|
|
17
|
-
constructor(code, description
|
|
16
|
+
constructor(code, description) {
|
|
18
17
|
super(code, description);
|
|
19
|
-
|
|
20
|
-
this._internal = is.boolean(internal) && internal;
|
|
21
18
|
}
|
|
22
19
|
|
|
23
20
|
/**
|
|
@@ -76,14 +73,14 @@ module.exports = (() => {
|
|
|
76
73
|
}
|
|
77
74
|
|
|
78
75
|
/**
|
|
79
|
-
* A
|
|
76
|
+
* A delisting.
|
|
80
77
|
*
|
|
81
78
|
* @public
|
|
82
79
|
* @static
|
|
83
80
|
* @returns {CorporateActionType}
|
|
84
81
|
*/
|
|
85
|
-
static get
|
|
86
|
-
return
|
|
82
|
+
static get DELIST() {
|
|
83
|
+
return delist;
|
|
87
84
|
}
|
|
88
85
|
}
|
|
89
86
|
|
|
@@ -91,7 +88,7 @@ module.exports = (() => {
|
|
|
91
88
|
const nameChange = new CorporateActionType('NAME_CHANGE', 'Name Change', false);
|
|
92
89
|
const dividend = new CorporateActionType('DIVIDEND', 'Dividend', false);
|
|
93
90
|
const split = new CorporateActionType('SPLIT', 'Split', false);
|
|
94
|
-
const
|
|
91
|
+
const delist = new CorporateActionType('DELIST', 'Delist', false);
|
|
95
92
|
|
|
96
93
|
return CorporateActionType;
|
|
97
94
|
})();
|
|
@@ -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,7 +351,7 @@ module.exports = (() => {
|
|
|
352
351
|
static get DEBIT() {
|
|
353
352
|
return debit;
|
|
354
353
|
}
|
|
355
|
-
|
|
354
|
+
|
|
356
355
|
/**
|
|
357
356
|
* A system-generated transaction, indicating the security has stopped active trading.
|
|
358
357
|
*
|
|
@@ -412,7 +411,7 @@ module.exports = (() => {
|
|
|
412
411
|
const split = new TransactionType('SP', 'Split', 'Split', 1, false, false, false, true, false, false, true, false, false);
|
|
413
412
|
const fee = new TransactionType('F', 'Fee', 'Fee', 0, false, false, false, false, false, true, false, false, false);
|
|
414
413
|
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',
|
|
414
|
+
const delist = new TransactionType('DL', 'Delist', 'Delist', 1, false, false, false, false, false, false, true, false, false);
|
|
416
415
|
|
|
417
416
|
const distributionCash = new TransactionType('DC', 'Distribution (Cash)', 'Cash Distribution', 1, false, false, true, false, false, false, true, false, false);
|
|
418
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'),
|
|
@@ -46,32 +46,33 @@ module.exports = (() => {
|
|
|
46
46
|
return map;
|
|
47
47
|
}, { });
|
|
48
48
|
|
|
49
|
-
const
|
|
49
|
+
const list = transactions.reduce((accumulator, transaction) => {
|
|
50
50
|
const position = transaction.position;
|
|
51
51
|
|
|
52
52
|
if (instruments.hasOwnProperty(position)) {
|
|
53
53
|
let instrument = instruments[position];
|
|
54
|
-
let formatted =
|
|
54
|
+
let formatted = { instrument: instrument };
|
|
55
55
|
|
|
56
|
-
|
|
57
|
-
const formatterFunction = formatters.get(transaction.type);
|
|
58
|
-
const formattedTransaction = formatterFunction(transaction);
|
|
56
|
+
const formatterFunctions = formatters.get(transaction.type);
|
|
59
57
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
58
|
+
formatterFunctions.forEach((formatterFunction) => {
|
|
59
|
+
formatterFunction(transaction, formatted);
|
|
60
|
+
});
|
|
63
61
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
});
|
|
62
|
+
Object.keys(formatted).forEach((key) => {
|
|
63
|
+
const value = formatted[key];
|
|
67
64
|
|
|
68
|
-
|
|
69
|
-
|
|
65
|
+
if (value instanceof Decimal) {
|
|
66
|
+
const precision = instrument.currency.precision;
|
|
70
67
|
|
|
71
|
-
|
|
68
|
+
formatted[key] = formatter.numberToString(value.toFloat(), precision, ',');
|
|
69
|
+
}
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
accumulator.push(formatted);
|
|
72
73
|
}
|
|
73
74
|
|
|
74
|
-
return
|
|
75
|
+
return accumulator;
|
|
75
76
|
}, [ ]);
|
|
76
77
|
|
|
77
78
|
let comparator;
|
|
@@ -82,13 +83,13 @@ module.exports = (() => {
|
|
|
82
83
|
comparator = comparatorAscending;
|
|
83
84
|
}
|
|
84
85
|
|
|
85
|
-
|
|
86
|
+
list.sort(comparator);
|
|
86
87
|
|
|
87
|
-
|
|
88
|
+
list.forEach((t) => {
|
|
88
89
|
delete t.instrument.id;
|
|
89
90
|
});
|
|
90
91
|
|
|
91
|
-
return
|
|
92
|
+
return list;
|
|
92
93
|
}
|
|
93
94
|
|
|
94
95
|
/**
|
|
@@ -120,126 +121,105 @@ module.exports = (() => {
|
|
|
120
121
|
}
|
|
121
122
|
}
|
|
122
123
|
|
|
123
|
-
const
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
instrument: i,
|
|
130
|
-
position: t.position
|
|
131
|
-
};
|
|
124
|
+
const basicFormatter = (t, f) => {
|
|
125
|
+
f.date = t.date;
|
|
126
|
+
f.type = t.type.display;
|
|
127
|
+
f.code = t.type.code;
|
|
128
|
+
f.sequence = t.sequence;
|
|
129
|
+
f.position = t.position;
|
|
132
130
|
};
|
|
133
131
|
|
|
134
|
-
const
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
}
|
|
132
|
+
const averageCostFormatter = (t, f) => {
|
|
133
|
+
const basis = t.snapshot.basis;
|
|
134
|
+
const open = t.snapshot.open;
|
|
135
|
+
|
|
136
|
+
let average;
|
|
137
|
+
|
|
138
|
+
if (basis && open && !open.getIsZero()) {
|
|
139
|
+
average = basis.divide(open);
|
|
140
|
+
} else {
|
|
141
|
+
average = '';
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
f.average = average;
|
|
143
145
|
};
|
|
144
146
|
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
fee: t.fee
|
|
162
|
-
};
|
|
147
|
+
const buySellFormatter = (t, f) => {
|
|
148
|
+
f.boughtSold = t.quantity;
|
|
149
|
+
f.price = t.trade.price;
|
|
150
|
+
f.fee = t.fee;
|
|
151
|
+
f.total = t.amount;
|
|
152
|
+
};
|
|
153
|
+
|
|
154
|
+
const dividendFormatter = (t, f) => {
|
|
155
|
+
f.shares = t.snapshot.open;
|
|
156
|
+
f.total = t.dividend.amount;
|
|
157
|
+
f.rate = t.dividend.rate;
|
|
158
|
+
};
|
|
159
|
+
|
|
160
|
+
const dividendStockFormatter = (t, f) => {
|
|
161
|
+
f.boughtSold = t.quantity;
|
|
162
|
+
f.fee = t.fee;
|
|
163
163
|
|
|
164
164
|
if (t.dividend && t.dividend.rate && t.dividend.price) {
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
165
|
+
f.shares = t.snapshot.open.subtract(t.quantity);
|
|
166
|
+
f.price = t.dividend.price;
|
|
167
|
+
f.rate = t.dividend.rate;
|
|
168
168
|
}
|
|
169
|
+
};
|
|
170
|
+
|
|
171
|
+
const dividendReinvestFormatter = (t, f) => {
|
|
172
|
+
f.boughtSold = t.quantity;
|
|
173
|
+
f.shares = t.snapshot.open.subtract(t.quantity);
|
|
174
|
+
f.price = t.dividend.price;
|
|
175
|
+
f.fee = t.fee;
|
|
176
|
+
f.rate = t.dividend.rate;
|
|
177
|
+
};
|
|
178
|
+
|
|
179
|
+
const distributionCashFormatter = (t, f) => {
|
|
180
|
+
f.shares = t.snapshot.open;
|
|
181
|
+
f.total = t.dividend.amount;
|
|
182
|
+
f.rate = t.dividend.rate;
|
|
183
|
+
};
|
|
169
184
|
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
formatters.set(TransactionType.DIVIDEND_REINVEST, (t) => {
|
|
174
|
-
return {
|
|
175
|
-
boughtSold: t.quantity,
|
|
176
|
-
shares: t.snapshot.open.subtract(t.quantity),
|
|
177
|
-
price: t.dividend.price,
|
|
178
|
-
fee: t.fee,
|
|
179
|
-
rate: t.dividend.rate
|
|
180
|
-
};
|
|
181
|
-
});
|
|
182
|
-
|
|
183
|
-
formatters.set(TransactionType.DISTRIBUTION_CASH, (t) => {
|
|
184
|
-
return {
|
|
185
|
-
shares: t.snapshot.open,
|
|
186
|
-
total: t.dividend.amount,
|
|
187
|
-
rate: t.dividend.rate
|
|
188
|
-
};
|
|
189
|
-
});
|
|
190
|
-
|
|
191
|
-
formatters.set(TransactionType.DISTRIBUTION_FUND, (t) => {
|
|
192
|
-
const data = {
|
|
193
|
-
boughtSold: t.quantity,
|
|
194
|
-
fee: t.fee
|
|
195
|
-
};
|
|
185
|
+
const distributionFundFormatter = (t, f) => {
|
|
186
|
+
f.boughtSold =t.quantity;
|
|
187
|
+
f.fee = t.fee;
|
|
196
188
|
|
|
197
189
|
if (t.dividend && t.dividend.rate && t.dividend.price) {
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
190
|
+
f.shares = t.snapshot.open.subtract(t.quantity);
|
|
191
|
+
f.price = t.dividend.price;
|
|
192
|
+
f.rate = t.dividend.rate;
|
|
201
193
|
}
|
|
194
|
+
};
|
|
202
195
|
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
return {
|
|
231
|
-
boughtSold: t.quantity
|
|
232
|
-
};
|
|
233
|
-
});
|
|
234
|
-
|
|
235
|
-
formatters.set(TransactionType.SPLIT, (t) => {
|
|
236
|
-
return {
|
|
237
|
-
shares: t.quantity,
|
|
238
|
-
rate: t.split.numerator.divide(t.split.denominator)
|
|
239
|
-
};
|
|
240
|
-
});
|
|
241
|
-
|
|
242
|
-
formatters.set(TransactionType.VALUATION, (t) => {
|
|
196
|
+
const distributionReinvestFormatter = (t, f) => {
|
|
197
|
+
f.boughtSold = t.quantity;
|
|
198
|
+
f.shares = t.snapshot.open.subtract(t.quantity);
|
|
199
|
+
f.price = t.dividend.price;
|
|
200
|
+
f.fee = t.fee;
|
|
201
|
+
f.rate = t.dividend.rate;
|
|
202
|
+
};
|
|
203
|
+
|
|
204
|
+
const incomeFormatter = (t, f) => {
|
|
205
|
+
f.total = t.income.amount;
|
|
206
|
+
};
|
|
207
|
+
|
|
208
|
+
const feeFormatter = (t, f) => {
|
|
209
|
+
f.fee = t.charge.amount;
|
|
210
|
+
f.total = t.charge.amount;
|
|
211
|
+
};
|
|
212
|
+
|
|
213
|
+
const feeUnitsFormatter = (t, f) => {
|
|
214
|
+
f.boughtSold = t.quantity;
|
|
215
|
+
};
|
|
216
|
+
|
|
217
|
+
const splitFormatter = (t, f) => {
|
|
218
|
+
f.shares = t.quantity;
|
|
219
|
+
f.rate = t.split.numerator.divide(t.split.denominator);
|
|
220
|
+
};
|
|
221
|
+
|
|
222
|
+
const valuationFormatter = (t, f) => {
|
|
243
223
|
let rate;
|
|
244
224
|
|
|
245
225
|
if (t.valuation.rate) {
|
|
@@ -250,39 +230,43 @@ module.exports = (() => {
|
|
|
250
230
|
rate = t.valuation.value.divide(t.snapshot.open);
|
|
251
231
|
}
|
|
252
232
|
|
|
253
|
-
|
|
254
|
-
price: rate
|
|
255
|
-
};
|
|
256
|
-
});
|
|
257
|
-
|
|
258
|
-
formatters.set(TransactionType.DELIST, () => {
|
|
259
|
-
return { };
|
|
260
|
-
});
|
|
261
|
-
|
|
262
|
-
const cashFormatter = (t) => {
|
|
263
|
-
return {
|
|
264
|
-
total: t.quantity
|
|
265
|
-
};
|
|
233
|
+
f.price = rate;
|
|
266
234
|
};
|
|
267
235
|
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
formatters.set(TransactionType.DEBIT, (t) => {
|
|
272
|
-
const formatted = cashFormatter(t);
|
|
273
|
-
|
|
274
|
-
formatted.description = t.description;
|
|
236
|
+
const cashFormatter = (t, f) => {
|
|
237
|
+
f.total = t.quantity;
|
|
238
|
+
};
|
|
275
239
|
|
|
276
|
-
|
|
277
|
-
|
|
240
|
+
const debitFormatter = (t, f) => {
|
|
241
|
+
f.description = t.description;
|
|
242
|
+
};
|
|
278
243
|
|
|
279
|
-
|
|
280
|
-
|
|
244
|
+
const creditFormatter = (t, f) => {
|
|
245
|
+
f.description = t.description;
|
|
246
|
+
};
|
|
281
247
|
|
|
282
|
-
|
|
248
|
+
const formatters = new Map();
|
|
283
249
|
|
|
284
|
-
|
|
285
|
-
|
|
250
|
+
formatters.set(TransactionType.BUY, [ basicFormatter, buySellFormatter, averageCostFormatter ]);
|
|
251
|
+
formatters.set(TransactionType.SELL, [ basicFormatter, buySellFormatter, averageCostFormatter ]);
|
|
252
|
+
formatters.set(TransactionType.BUY_SHORT, [ basicFormatter, buySellFormatter, averageCostFormatter ]);
|
|
253
|
+
formatters.set(TransactionType.SELL_SHORT, [ basicFormatter, buySellFormatter, averageCostFormatter ]);
|
|
254
|
+
formatters.set(TransactionType.DIVIDEND, [ basicFormatter, dividendFormatter, averageCostFormatter ]);
|
|
255
|
+
formatters.set(TransactionType.DIVIDEND_STOCK, [ basicFormatter, dividendStockFormatter, averageCostFormatter ]);
|
|
256
|
+
formatters.set(TransactionType.DIVIDEND_REINVEST, [ basicFormatter, dividendReinvestFormatter, averageCostFormatter ]);
|
|
257
|
+
formatters.set(TransactionType.DISTRIBUTION_CASH, [ basicFormatter, distributionCashFormatter, averageCostFormatter ]);
|
|
258
|
+
formatters.set(TransactionType.DISTRIBUTION_FUND, [ basicFormatter, distributionFundFormatter, averageCostFormatter ]);
|
|
259
|
+
formatters.set(TransactionType.DISTRIBUTION_REINVEST, [ basicFormatter, distributionReinvestFormatter, averageCostFormatter ]);
|
|
260
|
+
formatters.set(TransactionType.INCOME, [ basicFormatter, incomeFormatter, averageCostFormatter ]);
|
|
261
|
+
formatters.set(TransactionType.FEE, [ basicFormatter, feeFormatter, averageCostFormatter ]);
|
|
262
|
+
formatters.set(TransactionType.FEE_UNITS, [ basicFormatter, feeUnitsFormatter, averageCostFormatter ]);
|
|
263
|
+
formatters.set(TransactionType.SPLIT, [ basicFormatter, splitFormatter, averageCostFormatter ]);
|
|
264
|
+
formatters.set(TransactionType.VALUATION, [ basicFormatter, valuationFormatter, averageCostFormatter ]);
|
|
265
|
+
formatters.set(TransactionType.DELIST, [ basicFormatter, averageCostFormatter ]);
|
|
266
|
+
formatters.set(TransactionType.DEPOSIT, [ basicFormatter, cashFormatter ]);
|
|
267
|
+
formatters.set(TransactionType.WITHDRAWAL, [ basicFormatter, cashFormatter ]);
|
|
268
|
+
formatters.set(TransactionType.DEBIT, [ basicFormatter, cashFormatter, debitFormatter ]);
|
|
269
|
+
formatters.set(TransactionType.CREDIT, [ basicFormatter, cashFormatter, creditFormatter ]);
|
|
286
270
|
|
|
287
271
|
function getInstrumentTypePriority(type) {
|
|
288
272
|
if (type === InstrumentType.CASH) {
|
package/package.json
CHANGED
package/test/SpecRunner.js
CHANGED
|
@@ -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,7 +1088,7 @@ module.exports = (() => {
|
|
|
1089
1088
|
static get DEBIT() {
|
|
1090
1089
|
return debit;
|
|
1091
1090
|
}
|
|
1092
|
-
|
|
1091
|
+
|
|
1093
1092
|
/**
|
|
1094
1093
|
* A system-generated transaction, indicating the security has stopped active trading.
|
|
1095
1094
|
*
|
|
@@ -1149,7 +1148,7 @@ module.exports = (() => {
|
|
|
1149
1148
|
const split = new TransactionType('SP', 'Split', 'Split', 1, false, false, false, true, false, false, true, false, false);
|
|
1150
1149
|
const fee = new TransactionType('F', 'Fee', 'Fee', 0, false, false, false, false, false, true, false, false, false);
|
|
1151
1150
|
const feeUnits = new TransactionType('FU', 'Fee Units', 'Fee', 0, false, false, false, false, true, false, false, false, false);
|
|
1152
|
-
const delist = new TransactionType('DL', 'Delist', 'Delist',
|
|
1151
|
+
const delist = new TransactionType('DL', 'Delist', 'Delist', 1, false, false, false, false, false, false, true, false, false);
|
|
1153
1152
|
|
|
1154
1153
|
const distributionCash = new TransactionType('DC', 'Distribution (Cash)', 'Cash Distribution', 1, false, false, true, false, false, false, true, false, false);
|
|
1155
1154
|
const distributionReinvest = new TransactionType('DY', 'Distribution (Reinvested)', 'Distribution Reinvest', 1, false, false, false, true, false, false, true, false, false);
|
|
@@ -1169,7 +1168,8 @@ module.exports = (() => {
|
|
|
1169
1168
|
},{"@barchart/common-js/lang/Enum":24,"@barchart/common-js/lang/assert":29}],5:[function(require,module,exports){
|
|
1170
1169
|
const assert = require('@barchart/common-js/lang/assert'),
|
|
1171
1170
|
array = require('@barchart/common-js/lang/array'),
|
|
1172
|
-
is = require('@barchart/common-js/lang/is')
|
|
1171
|
+
is = require('@barchart/common-js/lang/is'),
|
|
1172
|
+
Day = require('@barchart/common-js/lang/Day');
|
|
1173
1173
|
|
|
1174
1174
|
const InstrumentType = require('./InstrumentType'),
|
|
1175
1175
|
PositionDirection = require('./PositionDirection'),
|
|
@@ -1464,7 +1464,7 @@ module.exports = (() => {
|
|
|
1464
1464
|
return TransactionValidator;
|
|
1465
1465
|
})();
|
|
1466
1466
|
|
|
1467
|
-
},{"./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){
|
|
1467
|
+
},{"./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){
|
|
1468
1468
|
const array = require('@barchart/common-js/lang/array'),
|
|
1469
1469
|
assert = require('@barchart/common-js/lang/assert'),
|
|
1470
1470
|
ComparatorBuilder = require('@barchart/common-js/collections/sorting/ComparatorBuilder'),
|
|
@@ -17622,8 +17622,8 @@ describe('After the PositionSummaryFrame enumeration is initialized', () => {
|
|
|
17622
17622
|
ranges = PositionSummaryFrame.YEARLY.getRanges(transactions);
|
|
17623
17623
|
});
|
|
17624
17624
|
|
|
17625
|
-
it('should have
|
|
17626
|
-
expect(ranges.length).toEqual(
|
|
17625
|
+
it('should have four ranges (assuming the current year is 2019)', () => {
|
|
17626
|
+
expect(ranges.length).toEqual(4);
|
|
17627
17627
|
});
|
|
17628
17628
|
|
|
17629
17629
|
it('the first range should be from 12-31-2014 to 12-31-2015', () => {
|
|
@@ -17640,6 +17640,11 @@ describe('After the PositionSummaryFrame enumeration is initialized', () => {
|
|
|
17640
17640
|
expect(ranges[2].start.format()).toEqual('2016-12-31');
|
|
17641
17641
|
expect(ranges[2].end.format()).toEqual('2017-12-31');
|
|
17642
17642
|
});
|
|
17643
|
+
|
|
17644
|
+
it('the fourth range should be from 12-31-2017 to 12-31-2018', () => {
|
|
17645
|
+
expect(ranges[3].start.format()).toEqual('2017-12-31');
|
|
17646
|
+
expect(ranges[3].end.format()).toEqual('2018-12-31');
|
|
17647
|
+
});
|
|
17643
17648
|
});
|
|
17644
17649
|
|
|
17645
17650
|
describe('and yearly position summary ranges are processed for a transaction set closes the same year', () => {
|
|
@@ -17715,7 +17720,7 @@ describe('After the PositionSummaryFrame enumeration is initialized', () => {
|
|
|
17715
17720
|
});
|
|
17716
17721
|
});
|
|
17717
17722
|
|
|
17718
|
-
describe('and yearly position summary ranges are processed for a transaction set
|
|
17723
|
+
describe('and yearly position summary ranges are processed for a transaction set that opens in 2015 and closes in 2017', () => {
|
|
17719
17724
|
let ranges;
|
|
17720
17725
|
|
|
17721
17726
|
beforeEach(() => {
|
|
@@ -17739,7 +17744,7 @@ describe('After the PositionSummaryFrame enumeration is initialized', () => {
|
|
|
17739
17744
|
ranges = PositionSummaryFrame.YEARLY.getRanges(transactions);
|
|
17740
17745
|
});
|
|
17741
17746
|
|
|
17742
|
-
it('should have
|
|
17747
|
+
it('should have three ranges', () => {
|
|
17743
17748
|
expect(ranges.length).toEqual(3);
|
|
17744
17749
|
});
|
|
17745
17750
|
|
|
@@ -17759,7 +17764,7 @@ describe('After the PositionSummaryFrame enumeration is initialized', () => {
|
|
|
17759
17764
|
});
|
|
17760
17765
|
});
|
|
17761
17766
|
|
|
17762
|
-
describe('and yearly position summary ranges are processed for a transaction set
|
|
17767
|
+
describe('and yearly position summary ranges are processed for a transaction set that opens in 2019 and closes in 2016, but has after-the-fact superfluous valuations in 2017 and 2018', () => {
|
|
17763
17768
|
let ranges;
|
|
17764
17769
|
|
|
17765
17770
|
beforeEach(() => {
|
|
@@ -17812,7 +17817,7 @@ describe('After the PositionSummaryFrame enumeration is initialized', () => {
|
|
|
17812
17817
|
});
|
|
17813
17818
|
});
|
|
17814
17819
|
|
|
17815
|
-
describe('and a year-to-date position summary ranges are processed for a transaction set that closed
|
|
17820
|
+
describe('and a year-to-date position summary ranges are processed for a transaction set that closed in 2017', () => {
|
|
17816
17821
|
let ranges;
|
|
17817
17822
|
|
|
17818
17823
|
beforeEach(() => {
|
|
@@ -17841,13 +17846,13 @@ describe('After the PositionSummaryFrame enumeration is initialized', () => {
|
|
|
17841
17846
|
});
|
|
17842
17847
|
});
|
|
17843
17848
|
|
|
17844
|
-
describe('and a year-to-date position summary ranges are processed for a transaction set that opened this year and has not yet closed', () => {
|
|
17849
|
+
describe('and a year-to-date position summary ranges are processed for a transaction set that opened this year and has not yet closed (assuming its 2019)', () => {
|
|
17845
17850
|
let ranges;
|
|
17846
17851
|
|
|
17847
17852
|
beforeEach(() => {
|
|
17848
17853
|
const transactions = [
|
|
17849
17854
|
{
|
|
17850
|
-
date: new Day(
|
|
17855
|
+
date: new Day(2019, 1, 1),
|
|
17851
17856
|
snapshot: {
|
|
17852
17857
|
open: new Decimal(100)
|
|
17853
17858
|
},
|
|
@@ -17862,26 +17867,26 @@ describe('After the PositionSummaryFrame enumeration is initialized', () => {
|
|
|
17862
17867
|
expect(ranges.length).toEqual(1);
|
|
17863
17868
|
});
|
|
17864
17869
|
|
|
17865
|
-
it('the first range should be from 12-31-
|
|
17866
|
-
expect(ranges[0].start.format()).toEqual('
|
|
17867
|
-
expect(ranges[0].end.format()).toEqual('
|
|
17870
|
+
it('the first range should be from 12-31-2018 to 12-31-2019', () => {
|
|
17871
|
+
expect(ranges[0].start.format()).toEqual('2018-12-31');
|
|
17872
|
+
expect(ranges[0].end.format()).toEqual('2019-12-31');
|
|
17868
17873
|
});
|
|
17869
17874
|
});
|
|
17870
17875
|
|
|
17871
|
-
describe('and a year-to-date position summary ranges are processed for a transaction set that opened and closed
|
|
17876
|
+
describe('and a year-to-date position summary ranges are processed for a transaction set that that opened and closed in 2019', () => {
|
|
17872
17877
|
let ranges;
|
|
17873
17878
|
|
|
17874
17879
|
beforeEach(() => {
|
|
17875
17880
|
const transactions = [
|
|
17876
17881
|
{
|
|
17877
|
-
date: new Day(
|
|
17882
|
+
date: new Day(2019, 1, 1),
|
|
17878
17883
|
snapshot: {
|
|
17879
17884
|
open: new Decimal(1)
|
|
17880
17885
|
},
|
|
17881
17886
|
type: TransactionType.BUY
|
|
17882
17887
|
},
|
|
17883
17888
|
{
|
|
17884
|
-
date: new Day(
|
|
17889
|
+
date: new Day(2019, 1, 2),
|
|
17885
17890
|
snapshot: {
|
|
17886
17891
|
open: new Decimal(0)
|
|
17887
17892
|
},
|
|
@@ -17896,62 +17901,20 @@ describe('After the PositionSummaryFrame enumeration is initialized', () => {
|
|
|
17896
17901
|
expect(ranges.length).toEqual(1);
|
|
17897
17902
|
});
|
|
17898
17903
|
|
|
17899
|
-
it('the first range should be from 12-31-
|
|
17900
|
-
expect(ranges[0].start.format()).toEqual('
|
|
17901
|
-
expect(ranges[0].end.format()).toEqual('
|
|
17902
|
-
});
|
|
17903
|
-
});
|
|
17904
|
-
|
|
17905
|
-
describe('and month position summary ranges are processed for a transaction set that does not close', () => {
|
|
17906
|
-
let ranges;
|
|
17907
|
-
|
|
17908
|
-
beforeEach(() => {
|
|
17909
|
-
const transactions = [
|
|
17910
|
-
{
|
|
17911
|
-
date: new Day(2018, 10, 20),
|
|
17912
|
-
snapshot: {
|
|
17913
|
-
open: new Decimal(1)
|
|
17914
|
-
},
|
|
17915
|
-
type: TransactionType.BUY
|
|
17916
|
-
},
|
|
17917
|
-
{
|
|
17918
|
-
date: new Day(2018, 11, 21),
|
|
17919
|
-
snapshot: {
|
|
17920
|
-
open: new Decimal(1)
|
|
17921
|
-
},
|
|
17922
|
-
type: TransactionType.BUY
|
|
17923
|
-
}
|
|
17924
|
-
];
|
|
17925
|
-
|
|
17926
|
-
ranges = PositionSummaryFrame.MONTHLY.getRanges(transactions);
|
|
17927
|
-
});
|
|
17928
|
-
|
|
17929
|
-
it('should have three ranges (assuming the current year is 2018 and the current month is December)', () => {
|
|
17930
|
-
expect(ranges.length).toEqual(3);
|
|
17931
|
-
});
|
|
17932
|
-
|
|
17933
|
-
it('the first range should be from 2018-09-30 to 2018-10-31', () => {
|
|
17934
|
-
expect(ranges[0].start.format()).toEqual('2018-09-30');
|
|
17935
|
-
expect(ranges[0].end.format()).toEqual('2018-10-31');
|
|
17936
|
-
});
|
|
17937
|
-
|
|
17938
|
-
it('the second range should be from 2018-10-31 to 2018-11-30', () => {
|
|
17939
|
-
expect(ranges[1].start.format()).toEqual('2018-10-31');
|
|
17940
|
-
expect(ranges[1].end.format()).toEqual('2018-11-30');
|
|
17941
|
-
});
|
|
17942
|
-
|
|
17943
|
-
it('the third range should be from 2018-10-31 to 2018-11-30', () => {
|
|
17944
|
-
expect(ranges[2].start.format()).toEqual('2018-11-30');
|
|
17945
|
-
expect(ranges[2].end.format()).toEqual('2018-12-31');
|
|
17904
|
+
it('the first range should be from 12-31-2018 to 12-31-2019', () => {
|
|
17905
|
+
expect(ranges[0].start.format()).toEqual('2018-12-31');
|
|
17906
|
+
expect(ranges[0].end.format()).toEqual('2019-12-31');
|
|
17946
17907
|
});
|
|
17947
17908
|
});
|
|
17948
17909
|
|
|
17949
17910
|
describe('and getting the start date for yearly frames', () => {
|
|
17950
|
-
describe('for one year ago',
|
|
17911
|
+
describe('for one year ago', () => {
|
|
17951
17912
|
let start;
|
|
17913
|
+
let today;
|
|
17952
17914
|
|
|
17953
17915
|
beforeEach(() => {
|
|
17954
17916
|
start = PositionSummaryFrame.YEARLY.getStartDate(1);
|
|
17917
|
+
today = new Date();
|
|
17955
17918
|
});
|
|
17956
17919
|
|
|
17957
17920
|
it('should be in December', () => {
|
|
@@ -17963,15 +17926,17 @@ describe('After the PositionSummaryFrame enumeration is initialized', () => {
|
|
|
17963
17926
|
});
|
|
17964
17927
|
|
|
17965
17928
|
it('should be two years ago', () => {
|
|
17966
|
-
expect(start.year).toEqual(
|
|
17929
|
+
expect(start.year).toEqual(today.getFullYear() - 2);
|
|
17967
17930
|
});
|
|
17968
17931
|
});
|
|
17969
17932
|
|
|
17970
|
-
describe('for two years ago',
|
|
17933
|
+
describe('for two years ago', () => {
|
|
17971
17934
|
let start;
|
|
17935
|
+
let today;
|
|
17972
17936
|
|
|
17973
17937
|
beforeEach(() => {
|
|
17974
17938
|
start = PositionSummaryFrame.YEARLY.getStartDate(2);
|
|
17939
|
+
today = new Date();
|
|
17975
17940
|
});
|
|
17976
17941
|
|
|
17977
17942
|
it('should be in December', () => {
|
|
@@ -17982,61 +17947,12 @@ describe('After the PositionSummaryFrame enumeration is initialized', () => {
|
|
|
17982
17947
|
expect(start.day).toEqual(31);
|
|
17983
17948
|
});
|
|
17984
17949
|
|
|
17985
|
-
it('should be
|
|
17986
|
-
expect(start.year).toEqual(
|
|
17950
|
+
it('should be three years ago', () => {
|
|
17951
|
+
expect(start.year).toEqual(today.getFullYear() - 3);
|
|
17987
17952
|
});
|
|
17988
17953
|
});
|
|
17989
17954
|
});
|
|
17990
17955
|
|
|
17991
|
-
|
|
17992
|
-
|
|
17993
|
-
|
|
17994
|
-
////
|
|
17995
|
-
|
|
17996
|
-
describe('and getting the start date for monthly frames', () => {
|
|
17997
|
-
describe('for one month ago', function () {
|
|
17998
|
-
let start;
|
|
17999
|
-
|
|
18000
|
-
beforeEach(() => {
|
|
18001
|
-
start = PositionSummaryFrame.MONTHLY.getStartDate(1);
|
|
18002
|
-
});
|
|
18003
|
-
|
|
18004
|
-
it('should be on the last day of month', () => {
|
|
18005
|
-
const today = Day.getToday();
|
|
18006
|
-
|
|
18007
|
-
expect(start.day).toEqual(Day.getDaysInMonth(today.year, today.month - 2));
|
|
18008
|
-
});
|
|
18009
|
-
|
|
18010
|
-
it('should be month ago', () => {
|
|
18011
|
-
expect(start.month).toEqual(Day.getToday().month - 2);
|
|
18012
|
-
});
|
|
18013
|
-
});
|
|
18014
|
-
|
|
18015
|
-
describe('for three months ago', function () {
|
|
18016
|
-
let start;
|
|
18017
|
-
|
|
18018
|
-
beforeEach(() => {
|
|
18019
|
-
start = PositionSummaryFrame.MONTHLY.getStartDate(3);
|
|
18020
|
-
});
|
|
18021
|
-
|
|
18022
|
-
it('should be on the last day of month', () => {
|
|
18023
|
-
const today = Day.getToday();
|
|
18024
|
-
|
|
18025
|
-
expect(start.day).toEqual(Day.getDaysInMonth(today.year, today.month - 4));
|
|
18026
|
-
});
|
|
18027
|
-
|
|
18028
|
-
it('should be 3 month ago', () => {
|
|
18029
|
-
expect(start.month).toEqual(Day.getToday().month - 4);
|
|
18030
|
-
});
|
|
18031
|
-
});
|
|
18032
|
-
});
|
|
18033
|
-
|
|
18034
|
-
////
|
|
18035
|
-
|
|
18036
|
-
|
|
18037
|
-
|
|
18038
|
-
|
|
18039
|
-
|
|
18040
17956
|
describe('and recent ranges are calculated', () => {
|
|
18041
17957
|
let todayYear;
|
|
18042
17958
|
let todayMonth;
|
|
@@ -18150,7 +18066,7 @@ describe('When validating transaction order', () => {
|
|
|
18150
18066
|
'use strict';
|
|
18151
18067
|
|
|
18152
18068
|
const build = (sequence, day, type) => {
|
|
18153
|
-
return { sequence: sequence, date: Day.parse(day), type: (type || TransactionType.BUY
|
|
18069
|
+
return { sequence: sequence, date: Day.parse(day), type: (type || TransactionType.BUY) };
|
|
18154
18070
|
};
|
|
18155
18071
|
|
|
18156
18072
|
it('An array of zero transactions should be valid', () => {
|
|
@@ -31,8 +31,8 @@ describe('After the PositionSummaryFrame enumeration is initialized', () => {
|
|
|
31
31
|
ranges = PositionSummaryFrame.YEARLY.getRanges(transactions);
|
|
32
32
|
});
|
|
33
33
|
|
|
34
|
-
it('should have
|
|
35
|
-
expect(ranges.length).toEqual(
|
|
34
|
+
it('should have four ranges (assuming the current year is 2019)', () => {
|
|
35
|
+
expect(ranges.length).toEqual(4);
|
|
36
36
|
});
|
|
37
37
|
|
|
38
38
|
it('the first range should be from 12-31-2014 to 12-31-2015', () => {
|
|
@@ -49,6 +49,11 @@ describe('After the PositionSummaryFrame enumeration is initialized', () => {
|
|
|
49
49
|
expect(ranges[2].start.format()).toEqual('2016-12-31');
|
|
50
50
|
expect(ranges[2].end.format()).toEqual('2017-12-31');
|
|
51
51
|
});
|
|
52
|
+
|
|
53
|
+
it('the fourth range should be from 12-31-2017 to 12-31-2018', () => {
|
|
54
|
+
expect(ranges[3].start.format()).toEqual('2017-12-31');
|
|
55
|
+
expect(ranges[3].end.format()).toEqual('2018-12-31');
|
|
56
|
+
});
|
|
52
57
|
});
|
|
53
58
|
|
|
54
59
|
describe('and yearly position summary ranges are processed for a transaction set closes the same year', () => {
|
|
@@ -124,7 +129,7 @@ describe('After the PositionSummaryFrame enumeration is initialized', () => {
|
|
|
124
129
|
});
|
|
125
130
|
});
|
|
126
131
|
|
|
127
|
-
describe('and yearly position summary ranges are processed for a transaction set
|
|
132
|
+
describe('and yearly position summary ranges are processed for a transaction set that opens in 2015 and closes in 2017', () => {
|
|
128
133
|
let ranges;
|
|
129
134
|
|
|
130
135
|
beforeEach(() => {
|
|
@@ -148,7 +153,7 @@ describe('After the PositionSummaryFrame enumeration is initialized', () => {
|
|
|
148
153
|
ranges = PositionSummaryFrame.YEARLY.getRanges(transactions);
|
|
149
154
|
});
|
|
150
155
|
|
|
151
|
-
it('should have
|
|
156
|
+
it('should have three ranges', () => {
|
|
152
157
|
expect(ranges.length).toEqual(3);
|
|
153
158
|
});
|
|
154
159
|
|
|
@@ -168,7 +173,7 @@ describe('After the PositionSummaryFrame enumeration is initialized', () => {
|
|
|
168
173
|
});
|
|
169
174
|
});
|
|
170
175
|
|
|
171
|
-
describe('and yearly position summary ranges are processed for a transaction set
|
|
176
|
+
describe('and yearly position summary ranges are processed for a transaction set that opens in 2019 and closes in 2016, but has after-the-fact superfluous valuations in 2017 and 2018', () => {
|
|
172
177
|
let ranges;
|
|
173
178
|
|
|
174
179
|
beforeEach(() => {
|
|
@@ -221,7 +226,7 @@ describe('After the PositionSummaryFrame enumeration is initialized', () => {
|
|
|
221
226
|
});
|
|
222
227
|
});
|
|
223
228
|
|
|
224
|
-
describe('and a year-to-date position summary ranges are processed for a transaction set that closed
|
|
229
|
+
describe('and a year-to-date position summary ranges are processed for a transaction set that closed in 2017', () => {
|
|
225
230
|
let ranges;
|
|
226
231
|
|
|
227
232
|
beforeEach(() => {
|
|
@@ -250,13 +255,13 @@ describe('After the PositionSummaryFrame enumeration is initialized', () => {
|
|
|
250
255
|
});
|
|
251
256
|
});
|
|
252
257
|
|
|
253
|
-
describe('and a year-to-date position summary ranges are processed for a transaction set that opened this year and has not yet closed', () => {
|
|
258
|
+
describe('and a year-to-date position summary ranges are processed for a transaction set that opened this year and has not yet closed (assuming its 2019)', () => {
|
|
254
259
|
let ranges;
|
|
255
260
|
|
|
256
261
|
beforeEach(() => {
|
|
257
262
|
const transactions = [
|
|
258
263
|
{
|
|
259
|
-
date: new Day(
|
|
264
|
+
date: new Day(2019, 1, 1),
|
|
260
265
|
snapshot: {
|
|
261
266
|
open: new Decimal(100)
|
|
262
267
|
},
|
|
@@ -271,26 +276,26 @@ describe('After the PositionSummaryFrame enumeration is initialized', () => {
|
|
|
271
276
|
expect(ranges.length).toEqual(1);
|
|
272
277
|
});
|
|
273
278
|
|
|
274
|
-
it('the first range should be from 12-31-
|
|
275
|
-
expect(ranges[0].start.format()).toEqual('
|
|
276
|
-
expect(ranges[0].end.format()).toEqual('
|
|
279
|
+
it('the first range should be from 12-31-2018 to 12-31-2019', () => {
|
|
280
|
+
expect(ranges[0].start.format()).toEqual('2018-12-31');
|
|
281
|
+
expect(ranges[0].end.format()).toEqual('2019-12-31');
|
|
277
282
|
});
|
|
278
283
|
});
|
|
279
284
|
|
|
280
|
-
describe('and a year-to-date position summary ranges are processed for a transaction set that opened and closed
|
|
285
|
+
describe('and a year-to-date position summary ranges are processed for a transaction set that that opened and closed in 2019', () => {
|
|
281
286
|
let ranges;
|
|
282
287
|
|
|
283
288
|
beforeEach(() => {
|
|
284
289
|
const transactions = [
|
|
285
290
|
{
|
|
286
|
-
date: new Day(
|
|
291
|
+
date: new Day(2019, 1, 1),
|
|
287
292
|
snapshot: {
|
|
288
293
|
open: new Decimal(1)
|
|
289
294
|
},
|
|
290
295
|
type: TransactionType.BUY
|
|
291
296
|
},
|
|
292
297
|
{
|
|
293
|
-
date: new Day(
|
|
298
|
+
date: new Day(2019, 1, 2),
|
|
294
299
|
snapshot: {
|
|
295
300
|
open: new Decimal(0)
|
|
296
301
|
},
|
|
@@ -305,62 +310,20 @@ describe('After the PositionSummaryFrame enumeration is initialized', () => {
|
|
|
305
310
|
expect(ranges.length).toEqual(1);
|
|
306
311
|
});
|
|
307
312
|
|
|
308
|
-
it('the first range should be from 12-31-
|
|
309
|
-
expect(ranges[0].start.format()).toEqual('
|
|
310
|
-
expect(ranges[0].end.format()).toEqual('
|
|
311
|
-
});
|
|
312
|
-
});
|
|
313
|
-
|
|
314
|
-
describe('and month position summary ranges are processed for a transaction set that does not close', () => {
|
|
315
|
-
let ranges;
|
|
316
|
-
|
|
317
|
-
beforeEach(() => {
|
|
318
|
-
const transactions = [
|
|
319
|
-
{
|
|
320
|
-
date: new Day(2018, 10, 20),
|
|
321
|
-
snapshot: {
|
|
322
|
-
open: new Decimal(1)
|
|
323
|
-
},
|
|
324
|
-
type: TransactionType.BUY
|
|
325
|
-
},
|
|
326
|
-
{
|
|
327
|
-
date: new Day(2018, 11, 21),
|
|
328
|
-
snapshot: {
|
|
329
|
-
open: new Decimal(1)
|
|
330
|
-
},
|
|
331
|
-
type: TransactionType.BUY
|
|
332
|
-
}
|
|
333
|
-
];
|
|
334
|
-
|
|
335
|
-
ranges = PositionSummaryFrame.MONTHLY.getRanges(transactions);
|
|
336
|
-
});
|
|
337
|
-
|
|
338
|
-
it('should have three ranges (assuming the current year is 2018 and the current month is December)', () => {
|
|
339
|
-
expect(ranges.length).toEqual(3);
|
|
340
|
-
});
|
|
341
|
-
|
|
342
|
-
it('the first range should be from 2018-09-30 to 2018-10-31', () => {
|
|
343
|
-
expect(ranges[0].start.format()).toEqual('2018-09-30');
|
|
344
|
-
expect(ranges[0].end.format()).toEqual('2018-10-31');
|
|
345
|
-
});
|
|
346
|
-
|
|
347
|
-
it('the second range should be from 2018-10-31 to 2018-11-30', () => {
|
|
348
|
-
expect(ranges[1].start.format()).toEqual('2018-10-31');
|
|
349
|
-
expect(ranges[1].end.format()).toEqual('2018-11-30');
|
|
350
|
-
});
|
|
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');
|
|
313
|
+
it('the first range should be from 12-31-2018 to 12-31-2019', () => {
|
|
314
|
+
expect(ranges[0].start.format()).toEqual('2018-12-31');
|
|
315
|
+
expect(ranges[0].end.format()).toEqual('2019-12-31');
|
|
355
316
|
});
|
|
356
317
|
});
|
|
357
318
|
|
|
358
319
|
describe('and getting the start date for yearly frames', () => {
|
|
359
|
-
describe('for one year ago',
|
|
320
|
+
describe('for one year ago', () => {
|
|
360
321
|
let start;
|
|
322
|
+
let today;
|
|
361
323
|
|
|
362
324
|
beforeEach(() => {
|
|
363
325
|
start = PositionSummaryFrame.YEARLY.getStartDate(1);
|
|
326
|
+
today = new Date();
|
|
364
327
|
});
|
|
365
328
|
|
|
366
329
|
it('should be in December', () => {
|
|
@@ -372,15 +335,17 @@ describe('After the PositionSummaryFrame enumeration is initialized', () => {
|
|
|
372
335
|
});
|
|
373
336
|
|
|
374
337
|
it('should be two years ago', () => {
|
|
375
|
-
expect(start.year).toEqual(
|
|
338
|
+
expect(start.year).toEqual(today.getFullYear() - 2);
|
|
376
339
|
});
|
|
377
340
|
});
|
|
378
341
|
|
|
379
|
-
describe('for two years ago',
|
|
342
|
+
describe('for two years ago', () => {
|
|
380
343
|
let start;
|
|
344
|
+
let today;
|
|
381
345
|
|
|
382
346
|
beforeEach(() => {
|
|
383
347
|
start = PositionSummaryFrame.YEARLY.getStartDate(2);
|
|
348
|
+
today = new Date();
|
|
384
349
|
});
|
|
385
350
|
|
|
386
351
|
it('should be in December', () => {
|
|
@@ -391,61 +356,12 @@ describe('After the PositionSummaryFrame enumeration is initialized', () => {
|
|
|
391
356
|
expect(start.day).toEqual(31);
|
|
392
357
|
});
|
|
393
358
|
|
|
394
|
-
it('should be
|
|
395
|
-
expect(start.year).toEqual(
|
|
359
|
+
it('should be three years ago', () => {
|
|
360
|
+
expect(start.year).toEqual(today.getFullYear() - 3);
|
|
396
361
|
});
|
|
397
362
|
});
|
|
398
363
|
});
|
|
399
364
|
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
////
|
|
404
|
-
|
|
405
|
-
describe('and getting the start date for monthly frames', () => {
|
|
406
|
-
describe('for one month ago', function () {
|
|
407
|
-
let start;
|
|
408
|
-
|
|
409
|
-
beforeEach(() => {
|
|
410
|
-
start = PositionSummaryFrame.MONTHLY.getStartDate(1);
|
|
411
|
-
});
|
|
412
|
-
|
|
413
|
-
it('should be on the last day of month', () => {
|
|
414
|
-
const today = Day.getToday();
|
|
415
|
-
|
|
416
|
-
expect(start.day).toEqual(Day.getDaysInMonth(today.year, today.month - 2));
|
|
417
|
-
});
|
|
418
|
-
|
|
419
|
-
it('should be month ago', () => {
|
|
420
|
-
expect(start.month).toEqual(Day.getToday().month - 2);
|
|
421
|
-
});
|
|
422
|
-
});
|
|
423
|
-
|
|
424
|
-
describe('for three months ago', function () {
|
|
425
|
-
let start;
|
|
426
|
-
|
|
427
|
-
beforeEach(() => {
|
|
428
|
-
start = PositionSummaryFrame.MONTHLY.getStartDate(3);
|
|
429
|
-
});
|
|
430
|
-
|
|
431
|
-
it('should be on the last day of month', () => {
|
|
432
|
-
const today = Day.getToday();
|
|
433
|
-
|
|
434
|
-
expect(start.day).toEqual(Day.getDaysInMonth(today.year, today.month - 4));
|
|
435
|
-
});
|
|
436
|
-
|
|
437
|
-
it('should be 3 month ago', () => {
|
|
438
|
-
expect(start.month).toEqual(Day.getToday().month - 4);
|
|
439
|
-
});
|
|
440
|
-
});
|
|
441
|
-
});
|
|
442
|
-
|
|
443
|
-
////
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
365
|
describe('and recent ranges are calculated', () => {
|
|
450
366
|
let todayYear;
|
|
451
367
|
let todayMonth;
|
|
@@ -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', () => {
|