@barchart/portfolio-api-common 1.32.0 → 2.0.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/processing/PositionContainer.js +66 -91
- package/lib/processing/PositionGroup.js +158 -130
- package/package.json +3 -3
|
@@ -3,6 +3,7 @@ const array = require('@barchart/common-js/lang/array'),
|
|
|
3
3
|
ComparatorBuilder = require('@barchart/common-js/collections/sorting/ComparatorBuilder'),
|
|
4
4
|
comparators = require('@barchart/common-js/collections/sorting/comparators'),
|
|
5
5
|
Currency = require('@barchart/common-js/lang/Currency'),
|
|
6
|
+
CurrencyTranslator = require('@barchart/common-js/lang/CurrencyTranslator'),
|
|
6
7
|
Day = require('@barchart/common-js/lang/Day'),
|
|
7
8
|
Decimal = require('@barchart/common-js/lang/Decimal'),
|
|
8
9
|
DisposableStack = require('@barchart/common-js/collections/specialized/DisposableStack'),
|
|
@@ -23,11 +24,14 @@ const PositionGroup = require('./PositionGroup'),
|
|
|
23
24
|
module.exports = (() => {
|
|
24
25
|
'use strict';
|
|
25
26
|
|
|
26
|
-
const DEFAULT_CURRENCY = Currency.
|
|
27
|
+
const DEFAULT_CURRENCY = Currency.USD;
|
|
27
28
|
|
|
28
|
-
const
|
|
29
|
+
const SUPPORTED_CURRENCIES = [
|
|
30
|
+
Currency.AUD,
|
|
29
31
|
Currency.CAD,
|
|
30
32
|
Currency.CHF,
|
|
33
|
+
Currency.GBP,
|
|
34
|
+
Currency.GBX,
|
|
31
35
|
Currency.EUR,
|
|
32
36
|
Currency.HKD,
|
|
33
37
|
Currency.JPY,
|
|
@@ -77,6 +81,7 @@ module.exports = (() => {
|
|
|
77
81
|
this._groupBindings = { };
|
|
78
82
|
|
|
79
83
|
this._reporting = reportFrame instanceof PositionSummaryFrame;
|
|
84
|
+
this._useBarchartPriceFormattingRules = false;
|
|
80
85
|
|
|
81
86
|
this._positionSymbolAddedEvent = new Event(this);
|
|
82
87
|
this._positionSymbolRemovedEvent = new Event(this);
|
|
@@ -122,7 +127,7 @@ module.exports = (() => {
|
|
|
122
127
|
}, { });
|
|
123
128
|
|
|
124
129
|
this._items = positions.reduce((items, position) => {
|
|
125
|
-
const item = createPositionItem.call(this, position, reportFrame
|
|
130
|
+
const item = createPositionItem.call(this, position, !!reportFrame);
|
|
126
131
|
|
|
127
132
|
if (item) {
|
|
128
133
|
items.push(item);
|
|
@@ -143,22 +148,6 @@ module.exports = (() => {
|
|
|
143
148
|
return map;
|
|
144
149
|
}, { });
|
|
145
150
|
|
|
146
|
-
this._currencies = this._items.reduce((map, item) => {
|
|
147
|
-
const currency = extractCurrency(item.position);
|
|
148
|
-
|
|
149
|
-
if (currency) {
|
|
150
|
-
const code = currency.code;
|
|
151
|
-
|
|
152
|
-
if (!map.hasOwnProperty(code)) {
|
|
153
|
-
map[code] = [ ];
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
map[code].push(item);
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
return map;
|
|
160
|
-
}, { });
|
|
161
|
-
|
|
162
151
|
if (is.array(currencyPairs)) {
|
|
163
152
|
currencyPairs.forEach((currencyPair) => {
|
|
164
153
|
currencyPair.sort((a, b) => comparators.compareStrings(a.code, b.code));
|
|
@@ -168,21 +157,31 @@ module.exports = (() => {
|
|
|
168
157
|
return `^${currencyPair[0].code}${currencyPair[1].code}`;
|
|
169
158
|
}));
|
|
170
159
|
} else {
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
if (code !== DEFAULT_CURRENCY.code) {
|
|
175
|
-
symbols.push(`^${code}${DEFAULT_CURRENCY.code}`);
|
|
160
|
+
this._forexSymbols = SUPPORTED_CURRENCIES.reduce((symbols, currency) => {
|
|
161
|
+
if (currency === DEFAULT_CURRENCY || currency === Currency.GBX) {
|
|
162
|
+
return symbols;
|
|
176
163
|
}
|
|
177
164
|
|
|
165
|
+
symbols.push(`^${DEFAULT_CURRENCY.code}${currency.code}`);
|
|
166
|
+
|
|
178
167
|
return symbols;
|
|
179
168
|
}, [ ]);
|
|
169
|
+
|
|
170
|
+
this._forexSymbols.push('^GBXGBP');
|
|
180
171
|
}
|
|
181
172
|
|
|
182
|
-
this.
|
|
173
|
+
this._currencyTranslator = new CurrencyTranslator(this._forexSymbols);
|
|
174
|
+
|
|
175
|
+
const forexQuotes = this._forexSymbols.map((symbol) => {
|
|
176
|
+
if (symbol === '^GBXGBP') {
|
|
177
|
+
return Rate.fromPair(0.01, '^GBXGBP');
|
|
178
|
+
}
|
|
179
|
+
|
|
183
180
|
return Rate.fromPair(Decimal.ONE, symbol);
|
|
184
181
|
});
|
|
185
182
|
|
|
183
|
+
this._currencyTranslator.setRates(forexQuotes);
|
|
184
|
+
|
|
186
185
|
this._nodes = { };
|
|
187
186
|
|
|
188
187
|
this._trees = this._definitions.reduce((map, treeDefinition) => {
|
|
@@ -577,18 +576,6 @@ module.exports = (() => {
|
|
|
577
576
|
assert.argumentIsArray(positionQuotes, 'positionQuotes');
|
|
578
577
|
assert.argumentIsArray(forexQuotes, 'forexQuotes');
|
|
579
578
|
|
|
580
|
-
if (positionQuotes.length !== 0) {
|
|
581
|
-
positionQuotes.forEach((quote) => {
|
|
582
|
-
const symbol = quote.symbol;
|
|
583
|
-
|
|
584
|
-
if (symbol) {
|
|
585
|
-
if (this._symbols.hasOwnProperty(symbol)) {
|
|
586
|
-
this._symbols[ symbol ].forEach(item => item.setQuote(quote));
|
|
587
|
-
}
|
|
588
|
-
}
|
|
589
|
-
});
|
|
590
|
-
}
|
|
591
|
-
|
|
592
579
|
if (forexQuotes.length !== 0) {
|
|
593
580
|
forexQuotes.forEach((quote) => {
|
|
594
581
|
const symbol = quote.symbol;
|
|
@@ -596,27 +583,25 @@ module.exports = (() => {
|
|
|
596
583
|
if (symbol) {
|
|
597
584
|
const rate = Rate.fromPair(quote.lastPrice, symbol);
|
|
598
585
|
|
|
599
|
-
|
|
586
|
+
this._currencyTranslator.setRate(rate);
|
|
587
|
+
}
|
|
588
|
+
});
|
|
600
589
|
|
|
601
|
-
|
|
602
|
-
|
|
590
|
+
Object.keys(this._trees).forEach((key) => {
|
|
591
|
+
this._trees[key].walk(group => group.refreshTranslations(), true, false);
|
|
592
|
+
});
|
|
593
|
+
}
|
|
603
594
|
|
|
604
|
-
|
|
605
|
-
|
|
595
|
+
if (positionQuotes.length !== 0) {
|
|
596
|
+
positionQuotes.forEach((quote) => {
|
|
597
|
+
const symbol = quote.symbol;
|
|
606
598
|
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
this._forexQuotes[index] = rate;
|
|
599
|
+
if (symbol) {
|
|
600
|
+
if (this._symbols.hasOwnProperty(symbol)) {
|
|
601
|
+
this._symbols[ symbol ].forEach(item => item.setQuote(quote));
|
|
611
602
|
}
|
|
612
|
-
|
|
613
|
-
recalculatePercentages.call(this);
|
|
614
603
|
}
|
|
615
604
|
});
|
|
616
|
-
|
|
617
|
-
Object.keys(this._trees).forEach((key) => {
|
|
618
|
-
this._trees[key].walk(group => group.setForexRates(this._forexQuotes), true, false);
|
|
619
|
-
});
|
|
620
605
|
}
|
|
621
606
|
|
|
622
607
|
if (positionQuotes.length !== 0 || forexQuotes.length !== 0) {
|
|
@@ -645,18 +630,6 @@ module.exports = (() => {
|
|
|
645
630
|
return price;
|
|
646
631
|
}
|
|
647
632
|
|
|
648
|
-
/**
|
|
649
|
-
* Sets a historical forex quote.
|
|
650
|
-
*
|
|
651
|
-
* @public
|
|
652
|
-
* @param {Object} forexQuote
|
|
653
|
-
* @param {Day} date
|
|
654
|
-
*/
|
|
655
|
-
setHistoricalForexQuote(forexQuote, date) {
|
|
656
|
-
assert.argumentIsRequired(forexQuote, 'forexQuote', Object);
|
|
657
|
-
assert.argumentIsRequired(date, 'date', Day, 'Day');
|
|
658
|
-
}
|
|
659
|
-
|
|
660
633
|
/**
|
|
661
634
|
* Returns all forex symbols that are required to do currency translations.
|
|
662
635
|
*
|
|
@@ -667,16 +640,6 @@ module.exports = (() => {
|
|
|
667
640
|
return this._forexSymbols;
|
|
668
641
|
}
|
|
669
642
|
|
|
670
|
-
/**
|
|
671
|
-
* Returns all current forex quotes.
|
|
672
|
-
*
|
|
673
|
-
* @public
|
|
674
|
-
* @returns {Object[]}
|
|
675
|
-
*/
|
|
676
|
-
getForexQuotes() {
|
|
677
|
-
return this._forexQuotes;
|
|
678
|
-
}
|
|
679
|
-
|
|
680
643
|
/**
|
|
681
644
|
* Updates fundamental data for a single symbol.
|
|
682
645
|
*
|
|
@@ -851,6 +814,24 @@ module.exports = (() => {
|
|
|
851
814
|
return this._positionSymbolRemovedEvent.register(handler);
|
|
852
815
|
}
|
|
853
816
|
|
|
817
|
+
/**
|
|
818
|
+
* Changes rules for price formatting.
|
|
819
|
+
*
|
|
820
|
+
* @public
|
|
821
|
+
* @param {boolean} value
|
|
822
|
+
*/
|
|
823
|
+
setBarchartPriceFormattingRules(value) {
|
|
824
|
+
assert.argumentIsRequired(value, 'value', Boolean);
|
|
825
|
+
|
|
826
|
+
if (this._useBarchartPriceFormattingRules !== value) {
|
|
827
|
+
this._useBarchartPriceFormattingRules = value;
|
|
828
|
+
|
|
829
|
+
Object.keys(this._trees).forEach((key) => {
|
|
830
|
+
this._trees[key].walk(group => group.setBarchartPriceFormattingRules(this._useBarchartPriceFormattingRules));
|
|
831
|
+
});
|
|
832
|
+
}
|
|
833
|
+
}
|
|
834
|
+
|
|
854
835
|
toString() {
|
|
855
836
|
return '[PositionContainer]';
|
|
856
837
|
}
|
|
@@ -892,14 +873,6 @@ module.exports = (() => {
|
|
|
892
873
|
}
|
|
893
874
|
}
|
|
894
875
|
|
|
895
|
-
function extractCurrency(position) {
|
|
896
|
-
if (position.instrument && position.instrument.currency) {
|
|
897
|
-
return position.instrument.currency;
|
|
898
|
-
} else {
|
|
899
|
-
return null;
|
|
900
|
-
}
|
|
901
|
-
}
|
|
902
|
-
|
|
903
876
|
function addGroupBinding(group, dispoable) {
|
|
904
877
|
const id = group.id;
|
|
905
878
|
|
|
@@ -963,7 +936,7 @@ module.exports = (() => {
|
|
|
963
936
|
return;
|
|
964
937
|
}
|
|
965
938
|
|
|
966
|
-
const
|
|
939
|
+
const currencyTranslator = this._currencyTranslator;
|
|
967
940
|
|
|
968
941
|
const levelDefinition = levelDefinitions[0];
|
|
969
942
|
|
|
@@ -972,7 +945,11 @@ module.exports = (() => {
|
|
|
972
945
|
const items = populatedObjects[key];
|
|
973
946
|
const first = items[0];
|
|
974
947
|
|
|
975
|
-
|
|
948
|
+
const group = new PositionGroup(levelDefinition, items, levelDefinition.currencySelector(first), currencyTranslator, key, levelDefinition.descriptionSelector(first), levelDefinition.aggregateCash);
|
|
949
|
+
|
|
950
|
+
group.setBarchartPriceFormattingRules(this._useBarchartPriceFormattingRules);
|
|
951
|
+
|
|
952
|
+
list.push(group);
|
|
976
953
|
|
|
977
954
|
return list;
|
|
978
955
|
}, [ ]);
|
|
@@ -985,7 +962,11 @@ module.exports = (() => {
|
|
|
985
962
|
});
|
|
986
963
|
|
|
987
964
|
const empty = missingGroups.map((group) => {
|
|
988
|
-
|
|
965
|
+
const eg = new PositionGroup(levelDefinition, [ ], group.currency, currencyTranslator, group.key, group.description);
|
|
966
|
+
|
|
967
|
+
eg.setBarchartPriceFormattingRules(this._useBarchartPriceFormattingRules);
|
|
968
|
+
|
|
969
|
+
return eg;
|
|
989
970
|
});
|
|
990
971
|
|
|
991
972
|
const compositeGroups = populatedGroups.concat(empty);
|
|
@@ -1149,12 +1130,6 @@ module.exports = (() => {
|
|
|
1149
1130
|
array.remove(this._symbolsDisplay[displaySymbol], i => i === positionItem);
|
|
1150
1131
|
}
|
|
1151
1132
|
|
|
1152
|
-
const currency = extractCurrency(positionItem.position);
|
|
1153
|
-
|
|
1154
|
-
if (currency && this._currencies.hasOwnProperty(currency.code)) {
|
|
1155
|
-
array.remove(this._currencies[currency.code], i => i === positionItem);
|
|
1156
|
-
}
|
|
1157
|
-
|
|
1158
1133
|
Object.keys(this._trees).forEach((key) => {
|
|
1159
1134
|
this._trees[key].walk((group, groupNode) => {
|
|
1160
1135
|
if (group.definition.type === PositionLevelType.POSITION && group.key === positionItem.position.position) {
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
const array = require('@barchart/common-js/lang/array'),
|
|
2
2
|
assert = require('@barchart/common-js/lang/assert'),
|
|
3
3
|
Currency = require('@barchart/common-js/lang/Currency'),
|
|
4
|
+
CurrencyTranslator = require('@barchart/common-js/lang/CurrencyTranslator'),
|
|
4
5
|
Decimal = require('@barchart/common-js/lang/Decimal'),
|
|
5
6
|
Disposable = require('@barchart/common-js/lang/Disposable'),
|
|
6
7
|
DisposableStack = require('@barchart/common-js/collections/specialized/DisposableStack'),
|
|
7
8
|
Event = require('@barchart/common-js/messaging/Event'),
|
|
8
9
|
formatter = require('@barchart/common-js/lang/formatter'),
|
|
9
|
-
is = require('@barchart/common-js/lang/is')
|
|
10
|
-
Rate = require('@barchart/common-js/lang/Rate');
|
|
10
|
+
is = require('@barchart/common-js/lang/is');
|
|
11
11
|
|
|
12
12
|
const fractionFormatter = require('@barchart/marketdata-api-js/lib/utilities/format/fraction');
|
|
13
13
|
|
|
@@ -28,27 +28,29 @@ module.exports = (() => {
|
|
|
28
28
|
* @public
|
|
29
29
|
* @param {PositionLevelDefinition} definition
|
|
30
30
|
* @param {PositionItem[]} items
|
|
31
|
-
* @param {Rate[]} rates
|
|
32
31
|
* @param {Currency} currency
|
|
32
|
+
* @param {CurrencyTranslator} currencyTranslator
|
|
33
33
|
* @param {String} key
|
|
34
34
|
* @param {String} description
|
|
35
35
|
* @param {Boolean=} aggregateCash
|
|
36
36
|
*/
|
|
37
37
|
class PositionGroup {
|
|
38
|
-
constructor(definition, items,
|
|
38
|
+
constructor(definition, items, currency, currencyTranslator, key, description, aggregateCash) {
|
|
39
39
|
this._id = counter++;
|
|
40
40
|
|
|
41
41
|
this._definition = definition;
|
|
42
42
|
|
|
43
43
|
this._items = items;
|
|
44
|
-
this._rates = rates;
|
|
45
44
|
|
|
46
45
|
this._parentGroup = null;
|
|
47
46
|
this._portfolioGroup = null;
|
|
48
47
|
|
|
49
48
|
this._currency = currency || Currency.CAD;
|
|
49
|
+
this._currencyTranslator = currencyTranslator;
|
|
50
50
|
this._bypassCurrencyTranslation = false;
|
|
51
51
|
|
|
52
|
+
this._useBarchartPriceFormattingRules = false;
|
|
53
|
+
|
|
52
54
|
this._key = key;
|
|
53
55
|
this._description = description;
|
|
54
56
|
|
|
@@ -404,20 +406,6 @@ module.exports = (() => {
|
|
|
404
406
|
this.refresh();
|
|
405
407
|
}
|
|
406
408
|
|
|
407
|
-
/**
|
|
408
|
-
* Causes aggregated data to be recalculated using a new exchange rate.
|
|
409
|
-
*
|
|
410
|
-
* @public
|
|
411
|
-
* @param {Rate[]} rates
|
|
412
|
-
*/
|
|
413
|
-
setForexRates(rates) {
|
|
414
|
-
this._rates = rates;
|
|
415
|
-
|
|
416
|
-
if (!this._bypassCurrencyTranslation) {
|
|
417
|
-
this.refresh();
|
|
418
|
-
}
|
|
419
|
-
}
|
|
420
|
-
|
|
421
409
|
/**
|
|
422
410
|
* Set a flag to indicate if parent groups should exclude this group's
|
|
423
411
|
* items from their calculations.
|
|
@@ -477,8 +465,8 @@ module.exports = (() => {
|
|
|
477
465
|
* @public
|
|
478
466
|
*/
|
|
479
467
|
refresh() {
|
|
480
|
-
calculateStaticData(this, this.
|
|
481
|
-
calculatePriceData(this,
|
|
468
|
+
calculateStaticData(this, this._definition);
|
|
469
|
+
calculatePriceData(this,null, true);
|
|
482
470
|
}
|
|
483
471
|
|
|
484
472
|
/**
|
|
@@ -488,7 +476,20 @@ module.exports = (() => {
|
|
|
488
476
|
* @public
|
|
489
477
|
*/
|
|
490
478
|
refreshMarketPercent() {
|
|
491
|
-
calculateMarketPercent(this, this.
|
|
479
|
+
calculateMarketPercent(this, this._parentGroup, this._portfolioGroup);
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
/**
|
|
483
|
+
* Causes aggregated data to be recalculated using a new exchange rate.
|
|
484
|
+
*
|
|
485
|
+
* @public
|
|
486
|
+
*/
|
|
487
|
+
refreshTranslations() {
|
|
488
|
+
if (this._bypassCurrencyTranslation) {
|
|
489
|
+
return;
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
this.refresh();
|
|
492
493
|
}
|
|
493
494
|
|
|
494
495
|
/**
|
|
@@ -513,6 +514,37 @@ module.exports = (() => {
|
|
|
513
514
|
return this._groupExcludedChangeEvent.register(handler);
|
|
514
515
|
}
|
|
515
516
|
|
|
517
|
+
/**
|
|
518
|
+
* Changes rules for price formatting.
|
|
519
|
+
*
|
|
520
|
+
* @public
|
|
521
|
+
* @param {boolean} value
|
|
522
|
+
*/
|
|
523
|
+
setBarchartPriceFormattingRules(value) {
|
|
524
|
+
assert.argumentIsRequired(value, 'value', Boolean);
|
|
525
|
+
|
|
526
|
+
if (this._useBarchartPriceFormattingRules !== value) {
|
|
527
|
+
this._useBarchartPriceFormattingRules = value;
|
|
528
|
+
|
|
529
|
+
if (this._single && this._dataActual.currentPrice) {
|
|
530
|
+
const item = this._items[0];
|
|
531
|
+
|
|
532
|
+
const instrument = item.position.instrument;
|
|
533
|
+
const currency = instrument.currency;
|
|
534
|
+
|
|
535
|
+
this._dataFormat.currentPrice = formatFraction(this._dataActual.currentPrice, currency, instrument, this._useBarchartPriceFormattingRules);
|
|
536
|
+
|
|
537
|
+
this._dataFormat.quoteLast = formatFraction(this._dataActual.quoteLast, currency, instrument, this._useBarchartPriceFormattingRules);
|
|
538
|
+
this._dataFormat.quoteOpen = formatFraction(this._dataActual.quoteOpen, currency, instrument, this._useBarchartPriceFormattingRules);
|
|
539
|
+
this._dataFormat.quoteHigh = formatFraction(this._dataActual.quoteHigh, currency, instrument, this._useBarchartPriceFormattingRules);
|
|
540
|
+
this._dataFormat.quoteLow = formatFraction(this._dataActual.quoteLow, currency, instrument, this._useBarchartPriceFormattingRules);
|
|
541
|
+
|
|
542
|
+
this._dataFormat.quoteChange = formatFraction(this._dataActual.quoteChange, currency, instrument, this._useBarchartPriceFormattingRules);
|
|
543
|
+
|
|
544
|
+
}
|
|
545
|
+
}
|
|
546
|
+
}
|
|
547
|
+
|
|
516
548
|
toString() {
|
|
517
549
|
return '[PositionGroup]';
|
|
518
550
|
}
|
|
@@ -523,27 +555,28 @@ module.exports = (() => {
|
|
|
523
555
|
if (this._single) {
|
|
524
556
|
const instrument = sender.position.instrument;
|
|
525
557
|
const currency = instrument.currency;
|
|
526
|
-
const precision = currency.precision;
|
|
527
558
|
|
|
528
|
-
this._dataActual.currentPrice = quote.lastPrice;
|
|
529
|
-
this.
|
|
559
|
+
this._dataActual.currentPrice = is.number(quote.lastPrice) ? quote.lastPrice : null;
|
|
560
|
+
this._dataActual.quoteLast = is.number(quote.previousPrice) ? quote.previousPrice : null;
|
|
561
|
+
this._dataActual.quoteOpen = is.number(quote.openPrice) ? quote.openPrice : null;
|
|
562
|
+
this._dataActual.quoteHigh = is.number(quote.highPrice) ? quote.highPrice : null;
|
|
563
|
+
this._dataActual.quoteLow = is.number(quote.lowPrice) ? quote.lowPrice : null;
|
|
530
564
|
|
|
531
|
-
this.
|
|
532
|
-
this.
|
|
533
|
-
this.
|
|
534
|
-
this.
|
|
535
|
-
this.
|
|
536
|
-
this._dataActual.quoteChangePercent = quote.percentChange;
|
|
537
|
-
this._dataActual.quoteTime = quote.timeDisplay;
|
|
538
|
-
this._dataActual.quoteVolume = quote.volume;
|
|
565
|
+
this._dataFormat.currentPrice = formatFraction(this._dataActual.currentPrice, currency, instrument, this._useBarchartPriceFormattingRules);
|
|
566
|
+
this._dataFormat.quoteLast = formatFraction(this._dataActual.quoteLast, currency, instrument, this._useBarchartPriceFormattingRules);
|
|
567
|
+
this._dataFormat.quoteOpen = formatFraction(this._dataActual.quoteOpen, currency, instrument, this._useBarchartPriceFormattingRules);
|
|
568
|
+
this._dataFormat.quoteHigh = formatFraction(this._dataActual.quoteHigh, currency, instrument, this._useBarchartPriceFormattingRules);
|
|
569
|
+
this._dataFormat.quoteLow = formatFraction(this._dataActual.quoteLow, currency, instrument, this._useBarchartPriceFormattingRules);
|
|
539
570
|
|
|
540
|
-
this.
|
|
541
|
-
this.
|
|
542
|
-
this._dataFormat.quoteHigh = formatNumber(this._dataActual.quoteHigh, precision);
|
|
543
|
-
this._dataFormat.quoteLow = formatNumber(this._dataActual.quoteLow, precision);
|
|
544
|
-
this._dataFormat.quoteChange = formatFraction(this._dataActual.quoteChange, currency, instrument);
|
|
571
|
+
this._dataActual.quoteChange = is.number(quote.priceChange) ? quote.priceChange : null;
|
|
572
|
+
this._dataActual.quoteChangePercent = is.number(quote.percentChange) ? quote.percentChange : null;
|
|
545
573
|
|
|
574
|
+
this._dataFormat.quoteChange = formatFraction(this._dataActual.quoteChange, currency, instrument, this._useBarchartPriceFormattingRules);
|
|
546
575
|
this._dataFormat.quoteChangePercent = formatPercent(new Decimal(this._dataActual.quoteChangePercent || 0), 2);
|
|
576
|
+
|
|
577
|
+
this._dataActual.quoteTime = quote.timeDisplay;
|
|
578
|
+
this._dataActual.quoteVolume = is.number(quote.volume) ? quote.volume : null;
|
|
579
|
+
|
|
547
580
|
this._dataFormat.quoteTime = this._dataActual.quoteTime;
|
|
548
581
|
this._dataFormat.quoteVolume = formatNumber(this._dataActual.quoteVolume, 0);
|
|
549
582
|
|
|
@@ -558,7 +591,7 @@ module.exports = (() => {
|
|
|
558
591
|
this._dataFormat.currentPrice = null;
|
|
559
592
|
}
|
|
560
593
|
|
|
561
|
-
calculatePriceData(this,
|
|
594
|
+
calculatePriceData(this, sender, false);
|
|
562
595
|
});
|
|
563
596
|
|
|
564
597
|
let fundamentalBinding = item.registerFundamentalDataChangeHandler((data) => {
|
|
@@ -668,9 +701,43 @@ module.exports = (() => {
|
|
|
668
701
|
}));
|
|
669
702
|
}
|
|
670
703
|
|
|
671
|
-
function
|
|
704
|
+
function formatNumber(number, precision) {
|
|
705
|
+
if (!is.number(number)) {
|
|
706
|
+
return '—';
|
|
707
|
+
}
|
|
708
|
+
|
|
709
|
+
return formatter.numberToString(number, precision, ',', false);
|
|
710
|
+
}
|
|
711
|
+
|
|
712
|
+
function formatDecimal(decimal, precision) {
|
|
713
|
+
if (decimal === null) {
|
|
714
|
+
return '—';
|
|
715
|
+
}
|
|
716
|
+
|
|
717
|
+
return formatNumber(decimal.toFloat(), precision);
|
|
718
|
+
}
|
|
719
|
+
|
|
720
|
+
function formatPercent(decimal, precision, plus) {
|
|
721
|
+
if (decimal === null) {
|
|
722
|
+
return '—';
|
|
723
|
+
}
|
|
724
|
+
|
|
725
|
+
let prefix;
|
|
726
|
+
|
|
727
|
+
if (is.boolean(plus) && plus && !Decimal.getIsNegative(decimal)) {
|
|
728
|
+
prefix = '+';
|
|
729
|
+
} else {
|
|
730
|
+
prefix = '';
|
|
731
|
+
}
|
|
732
|
+
|
|
733
|
+
return `${prefix}${formatDecimal(decimal.multiply(100), precision)}%`;
|
|
734
|
+
}
|
|
735
|
+
|
|
736
|
+
function formatFraction(value, currency, instrument, useBarchartPriceFormattingRules) {
|
|
672
737
|
let decimal = value instanceof Decimal;
|
|
673
738
|
|
|
739
|
+
let precision = currency.precision;
|
|
740
|
+
|
|
674
741
|
if (instrument && value !== null) {
|
|
675
742
|
const type = instrument.type;
|
|
676
743
|
const code = instrument.code;
|
|
@@ -680,101 +747,66 @@ module.exports = (() => {
|
|
|
680
747
|
|
|
681
748
|
return fractionFormatter(rounded, code.fractionFactor, code.fractionDigits, '-', true);
|
|
682
749
|
}
|
|
750
|
+
|
|
751
|
+
if (code && useBarchartPriceFormattingRules) {
|
|
752
|
+
precision = code.decimalDigits;
|
|
753
|
+
}
|
|
683
754
|
}
|
|
684
755
|
|
|
685
756
|
if (decimal) {
|
|
686
|
-
return formatDecimal(value,
|
|
757
|
+
return formatDecimal(value, precision);
|
|
687
758
|
} else {
|
|
688
|
-
return formatNumber(value,
|
|
759
|
+
return formatNumber(value, precision);
|
|
689
760
|
}
|
|
690
761
|
}
|
|
691
762
|
|
|
692
|
-
function
|
|
693
|
-
let
|
|
694
|
-
let
|
|
763
|
+
function formatCurrency(decimal, currency) {
|
|
764
|
+
let translated = decimal;
|
|
765
|
+
let desired = currency;
|
|
695
766
|
|
|
696
|
-
if (
|
|
697
|
-
|
|
767
|
+
if (desired === Currency.GBX) {
|
|
768
|
+
desired = Currency.GBP;
|
|
698
769
|
|
|
699
|
-
if (
|
|
700
|
-
|
|
701
|
-
} else if (is.number(value)) {
|
|
702
|
-
translatedValue = Rate.convert(new Decimal(value), Currency.GBX, Currency.GBP).toFloat();
|
|
703
|
-
} else {
|
|
704
|
-
translatedValue = value;
|
|
770
|
+
if (translated !== null) {
|
|
771
|
+
translated = translated.multiply(0.01);
|
|
705
772
|
}
|
|
706
|
-
} else {
|
|
707
|
-
translatedCurrency = currency;
|
|
708
|
-
translatedValue = value;
|
|
709
773
|
}
|
|
710
774
|
|
|
711
|
-
return
|
|
775
|
+
return formatDecimal(translated, desired.precision);
|
|
712
776
|
}
|
|
713
777
|
|
|
714
|
-
function
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
} else {
|
|
718
|
-
return '—';
|
|
719
|
-
}
|
|
720
|
-
}
|
|
778
|
+
function formatFractionSpecial(value, currency, instrument) {
|
|
779
|
+
let translated = value;
|
|
780
|
+
let desired = currency;
|
|
721
781
|
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
return formatNumber(decimal.toFloat(), precision);
|
|
725
|
-
} else {
|
|
726
|
-
return '—';
|
|
727
|
-
}
|
|
728
|
-
}
|
|
729
|
-
|
|
730
|
-
function formatPercent(decimal, precision, plus) {
|
|
731
|
-
if (decimal !== null) {
|
|
732
|
-
let prefix;
|
|
782
|
+
if (desired === Currency.GBX) {
|
|
783
|
+
desired = Currency.GBP;
|
|
733
784
|
|
|
734
|
-
if (
|
|
735
|
-
|
|
736
|
-
} else {
|
|
737
|
-
prefix = '';
|
|
785
|
+
if (translated !== null) {
|
|
786
|
+
translated = translated.multiply(0.01);
|
|
738
787
|
}
|
|
739
|
-
|
|
740
|
-
return `${prefix}${formatDecimal(decimal.multiply(100), precision)}%`;
|
|
741
|
-
} else {
|
|
742
|
-
return '—';
|
|
743
788
|
}
|
|
744
|
-
}
|
|
745
|
-
|
|
746
|
-
function formatCurrency(decimal, currency) {
|
|
747
|
-
let formatted;
|
|
748
789
|
|
|
749
|
-
|
|
750
|
-
formatted = formatDecimal(decimal, currency.precision);
|
|
751
|
-
} else {
|
|
752
|
-
formatted = formatDecimal(Rate.convert(decimal, Currency.GBX, Currency.GBP), Currency.GBP.precision);
|
|
753
|
-
}
|
|
754
|
-
|
|
755
|
-
return formatted;
|
|
790
|
+
return formatFraction(translated, desired, instrument);
|
|
756
791
|
}
|
|
757
792
|
|
|
758
|
-
function calculateStaticData(group,
|
|
793
|
+
function calculateStaticData(group, definition) {
|
|
759
794
|
const actual = group._dataActual;
|
|
760
795
|
const format = group._dataFormat;
|
|
761
796
|
|
|
762
797
|
const currency = group.currency;
|
|
798
|
+
const currencyTranslator = group._currencyTranslator;
|
|
763
799
|
|
|
764
800
|
const items = group._consideredItems;
|
|
765
801
|
|
|
766
802
|
group._bypassCurrencyTranslation = items.every(item => item.currency === currency);
|
|
767
803
|
|
|
768
804
|
const translate = (item, value) => {
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
if (item.currency !== currency && !value.getIsZero()) {
|
|
772
|
-
translated = Rate.convert(value, item.currency, currency, ...rates);
|
|
773
|
-
} else {
|
|
774
|
-
translated = value;
|
|
805
|
+
if (item.currency === currency || value.getIsZero()) {
|
|
806
|
+
return value;
|
|
775
807
|
}
|
|
776
808
|
|
|
777
|
-
return
|
|
809
|
+
return currencyTranslator.translate(value, item.currency, currency);
|
|
778
810
|
};
|
|
779
811
|
|
|
780
812
|
let updates = items.reduce((updates, item) => {
|
|
@@ -893,7 +925,7 @@ module.exports = (() => {
|
|
|
893
925
|
format.quantityPrevious = formatDecimal(actual.quantityPrevious, 2);
|
|
894
926
|
|
|
895
927
|
actual.basisPrice = item.data.basisPrice;
|
|
896
|
-
format.basisPrice =
|
|
928
|
+
format.basisPrice = formatFractionSpecial(actual.basisPrice, currency, instrument);
|
|
897
929
|
|
|
898
930
|
actual.periodPrice = item.data.periodPrice;
|
|
899
931
|
actual.periodPricePrevious = item.data.periodPricePrevious;
|
|
@@ -902,7 +934,7 @@ module.exports = (() => {
|
|
|
902
934
|
format.periodPricePrevious = formatCurrency(actual.periodPricePrevious, currency);
|
|
903
935
|
|
|
904
936
|
actual.unrealizedPrice = item.data.unrealizedPrice;
|
|
905
|
-
format.unrealizedPrice =
|
|
937
|
+
format.unrealizedPrice = formatFractionSpecial(actual.unrealizedPrice, currency, instrument);
|
|
906
938
|
|
|
907
939
|
format.invalid = definition.type === PositionLevelType.POSITION && item.invalid;
|
|
908
940
|
format.locked = definition.type === PositionLevelType.POSITION && item.data.locked;
|
|
@@ -925,7 +957,7 @@ module.exports = (() => {
|
|
|
925
957
|
format.portfolioType = portfolioType;
|
|
926
958
|
}
|
|
927
959
|
|
|
928
|
-
function calculatePriceData(group,
|
|
960
|
+
function calculatePriceData(group, item, forceRefresh) {
|
|
929
961
|
const currency = group.currency;
|
|
930
962
|
|
|
931
963
|
const actual = group._dataActual;
|
|
@@ -937,16 +969,14 @@ module.exports = (() => {
|
|
|
937
969
|
return;
|
|
938
970
|
}
|
|
939
971
|
|
|
940
|
-
const
|
|
941
|
-
let translated;
|
|
972
|
+
const currencyTranslator = group._currencyTranslator;
|
|
942
973
|
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
translated = value;
|
|
974
|
+
const translate = (item, value) => {
|
|
975
|
+
if (item.currency === currency || value.getIsZero()) {
|
|
976
|
+
return value;
|
|
947
977
|
}
|
|
948
978
|
|
|
949
|
-
return
|
|
979
|
+
return currencyTranslator.translate(value, item.currency, currency);
|
|
950
980
|
};
|
|
951
981
|
|
|
952
982
|
let updates;
|
|
@@ -1062,39 +1092,37 @@ module.exports = (() => {
|
|
|
1062
1092
|
|
|
1063
1093
|
if (group.single && item) {
|
|
1064
1094
|
actual.unrealizedPrice = item.data.unrealizedPrice;
|
|
1065
|
-
format.unrealizedPrice =
|
|
1095
|
+
format.unrealizedPrice = formatFractionSpecial(actual.unrealizedPrice, currency, item.position.instrument);
|
|
1066
1096
|
}
|
|
1067
1097
|
}
|
|
1068
1098
|
|
|
1069
|
-
function calculateMarketPercent(group,
|
|
1099
|
+
function calculateMarketPercent(group, parentGroup, portfolioGroup) {
|
|
1070
1100
|
const actual = group._dataActual;
|
|
1071
1101
|
const format = group._dataFormat;
|
|
1072
1102
|
const excluded = group._excluded;
|
|
1073
1103
|
|
|
1104
|
+
const currencyTranslator = group._currencyTranslator;
|
|
1105
|
+
|
|
1074
1106
|
const calculatePercent = (parent) => {
|
|
1075
|
-
|
|
1107
|
+
if (!parent || excluded) {
|
|
1108
|
+
return null;
|
|
1109
|
+
}
|
|
1076
1110
|
|
|
1077
|
-
|
|
1078
|
-
const parentData = parent._dataActual;
|
|
1111
|
+
const parentData = parent._dataActual;
|
|
1079
1112
|
|
|
1080
|
-
|
|
1081
|
-
|
|
1113
|
+
if (parentData.marketAbsolute === null || parentData.marketAbsolute.getIsApproximate(Decimal.ZERO, 4)) {
|
|
1114
|
+
return null;
|
|
1115
|
+
}
|
|
1082
1116
|
|
|
1083
|
-
|
|
1084
|
-
numerator = Rate.convert(actual.marketAbsolute, group.currency, parent.currency, ...rates);
|
|
1085
|
-
} else {
|
|
1086
|
-
numerator = actual.marketAbsolute;
|
|
1087
|
-
}
|
|
1117
|
+
let numerator;
|
|
1088
1118
|
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
marketPercent = null;
|
|
1092
|
-
}
|
|
1119
|
+
if (group.currency === parent.currency) {
|
|
1120
|
+
numerator = actual.marketAbsolute;
|
|
1093
1121
|
} else {
|
|
1094
|
-
|
|
1122
|
+
numerator = currencyTranslator.translate(actual.marketAbsolute, group.currency, parent.currency);
|
|
1095
1123
|
}
|
|
1096
1124
|
|
|
1097
|
-
return
|
|
1125
|
+
return numerator.divide(parentData.marketAbsolute);
|
|
1098
1126
|
};
|
|
1099
1127
|
|
|
1100
1128
|
actual.marketPercent = calculatePercent(parentGroup);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@barchart/portfolio-api-common",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.0",
|
|
4
4
|
"description": "Common JavaScript code used by Barchart's Portfolio Service",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Bryan Ingle",
|
|
@@ -15,9 +15,9 @@
|
|
|
15
15
|
"url": "git+ssh://git@github.com/barchart/portfolio-api-common.git"
|
|
16
16
|
},
|
|
17
17
|
"dependencies": {
|
|
18
|
-
"@barchart/common-js": "^4.
|
|
18
|
+
"@barchart/common-js": "^4.46.1",
|
|
19
19
|
"@barchart/marketdata-api-js": "^6.2.1",
|
|
20
|
-
"uuid": "
|
|
20
|
+
"uuid": "9.0.1"
|
|
21
21
|
},
|
|
22
22
|
"devDependencies": {
|
|
23
23
|
"@babel/core": "^7.6.2",
|