@barchart/portfolio-api-common 1.26.0 → 1.27.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/api/failures/PortfolioFailureType.js +0 -13
- package/lib/processing/PositionContainer.js +6 -5
- package/lib/processing/PositionGroup.js +3 -3
- package/lib/processing/definitions/PositionLevelDefinition.js +20 -0
- package/lib/providers/InstrumentProvider.js +98 -0
- package/lib/providers/InstrumentProviderCache.js +66 -0
- package/package.json +1 -1
|
@@ -416,17 +416,6 @@ module.exports = (() => {
|
|
|
416
416
|
static get TRANSACTION_SWITCH_FAILED_INVALID_REINVEST() {
|
|
417
417
|
return transactionSwitchFailedInvalidReinvest;
|
|
418
418
|
}
|
|
419
|
-
|
|
420
|
-
/**
|
|
421
|
-
* Unable to generate analytics report. The portfolio does not exist.
|
|
422
|
-
*
|
|
423
|
-
* @public
|
|
424
|
-
* @static
|
|
425
|
-
* @returns {FailureType}
|
|
426
|
-
*/
|
|
427
|
-
static get WEALTHSCOPE_TOKEN_CREATE_FAIL_NO_PORTFOLIO() {
|
|
428
|
-
return wealthscopeTokenCreateFailNoPortfolio;
|
|
429
|
-
}
|
|
430
419
|
|
|
431
420
|
toString() {
|
|
432
421
|
return '[PortfolioFailureType]';
|
|
@@ -476,7 +465,5 @@ module.exports = (() => {
|
|
|
476
465
|
const transactionSwitchFailedInvalidConversion = new FailureType('TRANSACTION_SWITCH_FAILED_INVALID_CONVERSION', 'Unable to convert transaction from {U|existing.description} to {U|desired.description}. This conversion is not supported.');
|
|
477
466
|
const transactionSwitchFailedInvalidReinvest = new FailureType('TRANSACTION_SWITCH_FAILED_INVALID_REINVEST', 'Unable to convert transaction from {U|existing.description} to {U|desired.description}. Reinvestment is not supported for short positions.');
|
|
478
467
|
|
|
479
|
-
const wealthscopeTokenCreateFailNoPortfolio = new FailureType('WEALTHSCOPE_TOKEN_CREATE_FAIL_NO_PORTFOLIO', 'Unable to generate analytics report. The portfolio does not exist, has it been deleted?', false);
|
|
480
|
-
|
|
481
468
|
return PortfolioFailureType;
|
|
482
469
|
})();
|
|
@@ -356,7 +356,7 @@ module.exports = (() => {
|
|
|
356
356
|
*
|
|
357
357
|
* @public
|
|
358
358
|
* @param {Object} position
|
|
359
|
-
* @param {Object
|
|
359
|
+
* @param {Object[]} summaries
|
|
360
360
|
*/
|
|
361
361
|
updatePosition(position, summaries) {
|
|
362
362
|
assert.argumentIsRequired(position, 'position', Object);
|
|
@@ -662,6 +662,7 @@ module.exports = (() => {
|
|
|
662
662
|
*
|
|
663
663
|
* @public
|
|
664
664
|
* @param {String} symbol
|
|
665
|
+
* @param {Boolean} display
|
|
665
666
|
* @param {Object} data
|
|
666
667
|
*/
|
|
667
668
|
setPositionFundamentalData(symbol, display, data) {
|
|
@@ -718,7 +719,7 @@ module.exports = (() => {
|
|
|
718
719
|
*/
|
|
719
720
|
getGroup(name, keys) {
|
|
720
721
|
assert.argumentIsRequired(name, 'name', String);
|
|
721
|
-
assert.argumentIsArray(keys, 'keys',
|
|
722
|
+
assert.argumentIsArray(keys, 'keys', String);
|
|
722
723
|
|
|
723
724
|
return findNode(this._trees[name], keys).getValue();
|
|
724
725
|
}
|
|
@@ -734,7 +735,7 @@ module.exports = (() => {
|
|
|
734
735
|
*/
|
|
735
736
|
getGroups(name, keys) {
|
|
736
737
|
assert.argumentIsRequired(name, 'name', String);
|
|
737
|
-
assert.argumentIsArray(keys, 'keys',
|
|
738
|
+
assert.argumentIsArray(keys, 'keys', String);
|
|
738
739
|
|
|
739
740
|
return findNode(this._trees[name], keys).getChildren().map(node => node.getValue());
|
|
740
741
|
}
|
|
@@ -743,7 +744,7 @@ module.exports = (() => {
|
|
|
743
744
|
* Returns the immediate parent {@link PositionGroup} of a {@link PositionGroup}.
|
|
744
745
|
*
|
|
745
746
|
* @public
|
|
746
|
-
* @param {PositionGroup}
|
|
747
|
+
* @param {PositionGroup} group
|
|
747
748
|
* @returns {PositionGroup|null}
|
|
748
749
|
*/
|
|
749
750
|
getParentGroup(group) {
|
|
@@ -756,7 +757,7 @@ module.exports = (() => {
|
|
|
756
757
|
* Returns the a parent {@link PositionGroup} which represents a portfolio.
|
|
757
758
|
*
|
|
758
759
|
* @public
|
|
759
|
-
* @param {PositionGroup}
|
|
760
|
+
* @param {PositionGroup} group
|
|
760
761
|
* @returns {PositionGroup|null}
|
|
761
762
|
*/
|
|
762
763
|
getParentGroupForPortfolio(group) {
|
|
@@ -265,7 +265,7 @@ module.exports = (() => {
|
|
|
265
265
|
* The {@link PositionItem} instances which for which aggregated data is compiled.
|
|
266
266
|
*
|
|
267
267
|
* @public
|
|
268
|
-
* @returns {
|
|
268
|
+
* @returns {PositionItem[]}
|
|
269
269
|
*/
|
|
270
270
|
get items() {
|
|
271
271
|
return this._items;
|
|
@@ -333,7 +333,7 @@ module.exports = (() => {
|
|
|
333
333
|
* percentages).
|
|
334
334
|
*
|
|
335
335
|
* @public
|
|
336
|
-
* @param {
|
|
336
|
+
* @param {PositionGroup} group
|
|
337
337
|
*/
|
|
338
338
|
setParentGroup(group) {
|
|
339
339
|
assert.argumentIsOptional(group, 'group', PositionGroup, 'PositionGroup');
|
|
@@ -350,7 +350,7 @@ module.exports = (() => {
|
|
|
350
350
|
* of relative percentages).
|
|
351
351
|
*
|
|
352
352
|
* @public
|
|
353
|
-
* @param {
|
|
353
|
+
* @param {PositionGroup} group
|
|
354
354
|
*/
|
|
355
355
|
setPortfolioGroup(group) {
|
|
356
356
|
assert.argumentIsOptional(group, 'group', PositionGroup, 'PositionGroup');
|
|
@@ -16,6 +16,7 @@ module.exports = (() => {
|
|
|
16
16
|
*
|
|
17
17
|
* @public
|
|
18
18
|
* @param {String} name
|
|
19
|
+
* @param {PositionLevelType} type
|
|
19
20
|
* @param {PositionLevelDefinition~keySelector} keySelector
|
|
20
21
|
* @param {PositionLevelDefinition~descriptionSelector} descriptionSelector
|
|
21
22
|
* @param {PositionLevelDefinition~currencySelector} currencySelector
|
|
@@ -173,6 +174,15 @@ module.exports = (() => {
|
|
|
173
174
|
};
|
|
174
175
|
}
|
|
175
176
|
|
|
177
|
+
/**
|
|
178
|
+
* Generates the key for a {@link PositionGroup}, representing a portfolio, held
|
|
179
|
+
* within a {@link PositionContainer}.
|
|
180
|
+
*
|
|
181
|
+
* @public
|
|
182
|
+
* @static
|
|
183
|
+
* @param {Object} portfolio
|
|
184
|
+
* @returns {String}
|
|
185
|
+
*/
|
|
176
186
|
static getKeyForPortfolioGroup(portfolio) {
|
|
177
187
|
assert.argumentIsRequired(portfolio, 'portfolio', Object);
|
|
178
188
|
|
|
@@ -217,6 +227,16 @@ module.exports = (() => {
|
|
|
217
227
|
};
|
|
218
228
|
}
|
|
219
229
|
|
|
230
|
+
/**
|
|
231
|
+
* Generates the key for a {@link PositionGroup}, representing a grouping of positions
|
|
232
|
+
* by asset class, held within a {@link PositionContainer}.
|
|
233
|
+
*
|
|
234
|
+
* @public
|
|
235
|
+
* @static
|
|
236
|
+
* @param {InstrumentType} type
|
|
237
|
+
* @param {Currency} currency
|
|
238
|
+
* @returns {String}
|
|
239
|
+
*/
|
|
220
240
|
static getKeyForAssetClassGroup(type, currency) {
|
|
221
241
|
assert.argumentIsRequired(type, 'type', InstrumentType, 'InstrumentType');
|
|
222
242
|
assert.argumentIsRequired(currency, 'currency', Currency, 'Currency');
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
const assert = require('@barchart/common-js/lang/assert'),
|
|
2
|
+
is = require('@barchart/common-js/lang/is'),
|
|
3
|
+
promise = require('@barchart/common-js/lang/promise');
|
|
4
|
+
|
|
5
|
+
const EndpointBuilder = require('@barchart/common-js/api/http/builders/EndpointBuilder'),
|
|
6
|
+
ErrorInterceptor = require('@barchart/common-js/api/http/interceptors/ErrorInterceptor'),
|
|
7
|
+
Gateway = require('@barchart/common-js/api/http/Gateway'),
|
|
8
|
+
ProtocolType = require('@barchart/common-js/api/http/definitions/ProtocolType'),
|
|
9
|
+
ResponseInterceptor = require('@barchart/common-js/api/http/interceptors/ResponseInterceptor'),
|
|
10
|
+
VerbType = require('@barchart/common-js/api/http/definitions/VerbType');
|
|
11
|
+
|
|
12
|
+
module.exports = (() => {
|
|
13
|
+
'use strict';
|
|
14
|
+
|
|
15
|
+
const MAXIMUM_WAIT_BEFORE_TIMEOUT_IN_MILLISECONDS = 3 * 1000;
|
|
16
|
+
|
|
17
|
+
const cache = { };
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* A utility that downloads instrument metadata (i.e. instrument "profile" data).
|
|
21
|
+
*
|
|
22
|
+
* @public
|
|
23
|
+
*/
|
|
24
|
+
class InstrumentProvider {
|
|
25
|
+
constructor() {
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Returns a promise for instrument metadata (i.e. "profile" data). If no instrument
|
|
30
|
+
* can be found with a matching symbol, the promise is rejected.
|
|
31
|
+
*
|
|
32
|
+
* @public
|
|
33
|
+
* @async
|
|
34
|
+
* @param {String} symbol
|
|
35
|
+
* @returns {Promise<Object>}
|
|
36
|
+
*/
|
|
37
|
+
async getInstrument(symbol) {
|
|
38
|
+
return Promise.resolve()
|
|
39
|
+
.then(() => {
|
|
40
|
+
assert.argumentIsRequired(symbol, 'symbol', String);
|
|
41
|
+
|
|
42
|
+
return promise.timeout(Gateway.invoke(getInstrumentLookupEndpoint(), {symbol}), MAXIMUM_WAIT_BEFORE_TIMEOUT_IN_MILLISECONDS, 'instrument lookup')
|
|
43
|
+
.catch((e) => {
|
|
44
|
+
delete cache[symbol];
|
|
45
|
+
|
|
46
|
+
let message;
|
|
47
|
+
|
|
48
|
+
if (is.string(e) && e === 'timeout') {
|
|
49
|
+
message = `Instrument lookup for [ ${symbol} ] failed due to timed out`;
|
|
50
|
+
} else {
|
|
51
|
+
message = `Instrument lookup for [ ${symbol} ] failed due to an unspecified error`;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
return Promise.reject(message);
|
|
55
|
+
}).then((result) => {
|
|
56
|
+
if (result.instrument === null) {
|
|
57
|
+
return Promise.reject(`Instrument lookup for [ ${symbol} ] failed, the instrument does not exist`);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
return result;
|
|
61
|
+
});
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
toString() {
|
|
66
|
+
return '[InstrumentProvider]';
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function buildInstrumentLookupEndpoint(host) {
|
|
71
|
+
return EndpointBuilder.for('query-instrument', 'query instrument')
|
|
72
|
+
.withVerb(VerbType.GET)
|
|
73
|
+
.withProtocol(ProtocolType.HTTPS)
|
|
74
|
+
.withHost(host)
|
|
75
|
+
.withPort(443)
|
|
76
|
+
.withPathBuilder((pb) => {
|
|
77
|
+
pb.withLiteralParameter('instruments', 'instruments')
|
|
78
|
+
.withVariableParameter('symbol', 'symbol', 'symbol');
|
|
79
|
+
})
|
|
80
|
+
.withResponseInterceptor(ResponseInterceptor.DATA)
|
|
81
|
+
.withErrorInterceptor(ErrorInterceptor.GENERAL)
|
|
82
|
+
.endpoint;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
const instrumentLookupEndpoints = new Map();
|
|
86
|
+
|
|
87
|
+
function getInstrumentLookupEndpoint() {
|
|
88
|
+
const host = 'instruments-prod.aws.barchart.com';
|
|
89
|
+
|
|
90
|
+
if (!instrumentLookupEndpoints.has(host)) {
|
|
91
|
+
instrumentLookupEndpoints.set(host, buildInstrumentLookupEndpoint(host));
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
return instrumentLookupEndpoints.get(host);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
return InstrumentProvider;
|
|
98
|
+
})();
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
const assert = require('@barchart/common-js/lang/assert'),
|
|
2
|
+
TimeMap = require('@barchart/common-js/collections/specialized/TimeMap');
|
|
3
|
+
|
|
4
|
+
const InstrumentProvider = require('./InstrumentProvider');
|
|
5
|
+
|
|
6
|
+
module.exports = (() => {
|
|
7
|
+
'use strict';
|
|
8
|
+
|
|
9
|
+
const MAXIMUM_CACHE_AGE_IN_MILLISECONDS = 15 * 60 * 1000;
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* A caching layer on top of the {@link InstrumentProvider}.
|
|
13
|
+
*
|
|
14
|
+
* @public
|
|
15
|
+
* @param {InstrumentProvider} provider
|
|
16
|
+
* @param {Number} cacheDuration - The maximum number of milliseconds to cache an instrument.
|
|
17
|
+
*/
|
|
18
|
+
class InstrumentProviderCache {
|
|
19
|
+
constructor(provider, cacheDuration) {
|
|
20
|
+
assert.argumentIsRequired(provider, 'provider', InstrumentProvider, 'InstrumentProvider');
|
|
21
|
+
|
|
22
|
+
this._provider = provider;
|
|
23
|
+
this._cache = new TimeMap(cacheDuration || MAXIMUM_CACHE_AGE_IN_MILLISECONDS);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Returns a promise for instrument metadata from an internal cache. If the instrument
|
|
28
|
+
* does not exist in the cache, or the data has expired, then a new request for the
|
|
29
|
+
* instrument is made using the {@link InstrumentProvider}.
|
|
30
|
+
*
|
|
31
|
+
* @public
|
|
32
|
+
* @async
|
|
33
|
+
* @param {String} symbol
|
|
34
|
+
* @returns {Promise<Object>}
|
|
35
|
+
*/
|
|
36
|
+
async getInstrument(symbol) {
|
|
37
|
+
return Promise.resolve()
|
|
38
|
+
.then(() => {
|
|
39
|
+
assert.argumentIsRequired(symbol, 'symbol', String);
|
|
40
|
+
|
|
41
|
+
let promise = this._cache.get(symbol);
|
|
42
|
+
|
|
43
|
+
if (promise !== null) {
|
|
44
|
+
return promise;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
promise = this._provider.getInstrument(symbol)
|
|
48
|
+
.then((profile) => {
|
|
49
|
+
if (profile) {
|
|
50
|
+
this._cache.put(symbol, promise);
|
|
51
|
+
|
|
52
|
+
return profile;
|
|
53
|
+
}
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
return promise;
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
toString() {
|
|
61
|
+
return '[InstrumentProviderCache]';
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
return InstrumentProviderCache;
|
|
66
|
+
})();
|