@barchart/portfolio-api-common 1.31.1 → 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 +67 -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,10 +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,
|
|
32
|
+
Currency.CHF,
|
|
33
|
+
Currency.GBP,
|
|
34
|
+
Currency.GBX,
|
|
30
35
|
Currency.EUR,
|
|
31
36
|
Currency.HKD,
|
|
32
37
|
Currency.JPY,
|
|
@@ -76,6 +81,7 @@ module.exports = (() => {
|
|
|
76
81
|
this._groupBindings = { };
|
|
77
82
|
|
|
78
83
|
this._reporting = reportFrame instanceof PositionSummaryFrame;
|
|
84
|
+
this._useBarchartPriceFormattingRules = false;
|
|
79
85
|
|
|
80
86
|
this._positionSymbolAddedEvent = new Event(this);
|
|
81
87
|
this._positionSymbolRemovedEvent = new Event(this);
|
|
@@ -121,7 +127,7 @@ module.exports = (() => {
|
|
|
121
127
|
}, { });
|
|
122
128
|
|
|
123
129
|
this._items = positions.reduce((items, position) => {
|
|
124
|
-
const item = createPositionItem.call(this, position, reportFrame
|
|
130
|
+
const item = createPositionItem.call(this, position, !!reportFrame);
|
|
125
131
|
|
|
126
132
|
if (item) {
|
|
127
133
|
items.push(item);
|
|
@@ -142,22 +148,6 @@ module.exports = (() => {
|
|
|
142
148
|
return map;
|
|
143
149
|
}, { });
|
|
144
150
|
|
|
145
|
-
this._currencies = this._items.reduce((map, item) => {
|
|
146
|
-
const currency = extractCurrency(item.position);
|
|
147
|
-
|
|
148
|
-
if (currency) {
|
|
149
|
-
const code = currency.code;
|
|
150
|
-
|
|
151
|
-
if (!map.hasOwnProperty(code)) {
|
|
152
|
-
map[code] = [ ];
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
map[code].push(item);
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
return map;
|
|
159
|
-
}, { });
|
|
160
|
-
|
|
161
151
|
if (is.array(currencyPairs)) {
|
|
162
152
|
currencyPairs.forEach((currencyPair) => {
|
|
163
153
|
currencyPair.sort((a, b) => comparators.compareStrings(a.code, b.code));
|
|
@@ -167,21 +157,31 @@ module.exports = (() => {
|
|
|
167
157
|
return `^${currencyPair[0].code}${currencyPair[1].code}`;
|
|
168
158
|
}));
|
|
169
159
|
} else {
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
if (code !== DEFAULT_CURRENCY.code) {
|
|
174
|
-
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;
|
|
175
163
|
}
|
|
176
164
|
|
|
165
|
+
symbols.push(`^${DEFAULT_CURRENCY.code}${currency.code}`);
|
|
166
|
+
|
|
177
167
|
return symbols;
|
|
178
168
|
}, [ ]);
|
|
169
|
+
|
|
170
|
+
this._forexSymbols.push('^GBXGBP');
|
|
179
171
|
}
|
|
180
172
|
|
|
181
|
-
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
|
+
|
|
182
180
|
return Rate.fromPair(Decimal.ONE, symbol);
|
|
183
181
|
});
|
|
184
182
|
|
|
183
|
+
this._currencyTranslator.setRates(forexQuotes);
|
|
184
|
+
|
|
185
185
|
this._nodes = { };
|
|
186
186
|
|
|
187
187
|
this._trees = this._definitions.reduce((map, treeDefinition) => {
|
|
@@ -576,18 +576,6 @@ module.exports = (() => {
|
|
|
576
576
|
assert.argumentIsArray(positionQuotes, 'positionQuotes');
|
|
577
577
|
assert.argumentIsArray(forexQuotes, 'forexQuotes');
|
|
578
578
|
|
|
579
|
-
if (positionQuotes.length !== 0) {
|
|
580
|
-
positionQuotes.forEach((quote) => {
|
|
581
|
-
const symbol = quote.symbol;
|
|
582
|
-
|
|
583
|
-
if (symbol) {
|
|
584
|
-
if (this._symbols.hasOwnProperty(symbol)) {
|
|
585
|
-
this._symbols[ symbol ].forEach(item => item.setQuote(quote));
|
|
586
|
-
}
|
|
587
|
-
}
|
|
588
|
-
});
|
|
589
|
-
}
|
|
590
|
-
|
|
591
579
|
if (forexQuotes.length !== 0) {
|
|
592
580
|
forexQuotes.forEach((quote) => {
|
|
593
581
|
const symbol = quote.symbol;
|
|
@@ -595,27 +583,25 @@ module.exports = (() => {
|
|
|
595
583
|
if (symbol) {
|
|
596
584
|
const rate = Rate.fromPair(quote.lastPrice, symbol);
|
|
597
585
|
|
|
598
|
-
|
|
586
|
+
this._currencyTranslator.setRate(rate);
|
|
587
|
+
}
|
|
588
|
+
});
|
|
599
589
|
|
|
600
|
-
|
|
601
|
-
|
|
590
|
+
Object.keys(this._trees).forEach((key) => {
|
|
591
|
+
this._trees[key].walk(group => group.refreshTranslations(), true, false);
|
|
592
|
+
});
|
|
593
|
+
}
|
|
602
594
|
|
|
603
|
-
|
|
604
|
-
|
|
595
|
+
if (positionQuotes.length !== 0) {
|
|
596
|
+
positionQuotes.forEach((quote) => {
|
|
597
|
+
const symbol = quote.symbol;
|
|
605
598
|
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
this._forexQuotes[index] = rate;
|
|
599
|
+
if (symbol) {
|
|
600
|
+
if (this._symbols.hasOwnProperty(symbol)) {
|
|
601
|
+
this._symbols[ symbol ].forEach(item => item.setQuote(quote));
|
|
610
602
|
}
|
|
611
|
-
|
|
612
|
-
recalculatePercentages.call(this);
|
|
613
603
|
}
|
|
614
604
|
});
|
|
615
|
-
|
|
616
|
-
Object.keys(this._trees).forEach((key) => {
|
|
617
|
-
this._trees[key].walk(group => group.setForexRates(this._forexQuotes), true, false);
|
|
618
|
-
});
|
|
619
605
|
}
|
|
620
606
|
|
|
621
607
|
if (positionQuotes.length !== 0 || forexQuotes.length !== 0) {
|
|
@@ -644,18 +630,6 @@ module.exports = (() => {
|
|
|
644
630
|
return price;
|
|
645
631
|
}
|
|
646
632
|
|
|
647
|
-
/**
|
|
648
|
-
* Sets a historical forex quote.
|
|
649
|
-
*
|
|
650
|
-
* @public
|
|
651
|
-
* @param {Object} forexQuote
|
|
652
|
-
* @param {Day} date
|
|
653
|
-
*/
|
|
654
|
-
setHistoricalForexQuote(forexQuote, date) {
|
|
655
|
-
assert.argumentIsRequired(forexQuote, 'forexQuote', Object);
|
|
656
|
-
assert.argumentIsRequired(date, 'date', Day, 'Day');
|
|
657
|
-
}
|
|
658
|
-
|
|
659
633
|
/**
|
|
660
634
|
* Returns all forex symbols that are required to do currency translations.
|
|
661
635
|
*
|
|
@@ -666,16 +640,6 @@ module.exports = (() => {
|
|
|
666
640
|
return this._forexSymbols;
|
|
667
641
|
}
|
|
668
642
|
|
|
669
|
-
/**
|
|
670
|
-
* Returns all current forex quotes.
|
|
671
|
-
*
|
|
672
|
-
* @public
|
|
673
|
-
* @returns {Object[]}
|
|
674
|
-
*/
|
|
675
|
-
getForexQuotes() {
|
|
676
|
-
return this._forexQuotes;
|
|
677
|
-
}
|
|
678
|
-
|
|
679
643
|
/**
|
|
680
644
|
* Updates fundamental data for a single symbol.
|
|
681
645
|
*
|
|
@@ -850,6 +814,24 @@ module.exports = (() => {
|
|
|
850
814
|
return this._positionSymbolRemovedEvent.register(handler);
|
|
851
815
|
}
|
|
852
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
|
+
|
|
853
835
|
toString() {
|
|
854
836
|
return '[PositionContainer]';
|
|
855
837
|
}
|
|
@@ -891,14 +873,6 @@ module.exports = (() => {
|
|
|
891
873
|
}
|
|
892
874
|
}
|
|
893
875
|
|
|
894
|
-
function extractCurrency(position) {
|
|
895
|
-
if (position.instrument && position.instrument.currency) {
|
|
896
|
-
return position.instrument.currency;
|
|
897
|
-
} else {
|
|
898
|
-
return null;
|
|
899
|
-
}
|
|
900
|
-
}
|
|
901
|
-
|
|
902
876
|
function addGroupBinding(group, dispoable) {
|
|
903
877
|
const id = group.id;
|
|
904
878
|
|
|
@@ -962,7 +936,7 @@ module.exports = (() => {
|
|
|
962
936
|
return;
|
|
963
937
|
}
|
|
964
938
|
|
|
965
|
-
const
|
|
939
|
+
const currencyTranslator = this._currencyTranslator;
|
|
966
940
|
|
|
967
941
|
const levelDefinition = levelDefinitions[0];
|
|
968
942
|
|
|
@@ -971,7 +945,11 @@ module.exports = (() => {
|
|
|
971
945
|
const items = populatedObjects[key];
|
|
972
946
|
const first = items[0];
|
|
973
947
|
|
|
974
|
-
|
|
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);
|
|
975
953
|
|
|
976
954
|
return list;
|
|
977
955
|
}, [ ]);
|
|
@@ -984,7 +962,11 @@ module.exports = (() => {
|
|
|
984
962
|
});
|
|
985
963
|
|
|
986
964
|
const empty = missingGroups.map((group) => {
|
|
987
|
-
|
|
965
|
+
const eg = new PositionGroup(levelDefinition, [ ], group.currency, currencyTranslator, group.key, group.description);
|
|
966
|
+
|
|
967
|
+
eg.setBarchartPriceFormattingRules(this._useBarchartPriceFormattingRules);
|
|
968
|
+
|
|
969
|
+
return eg;
|
|
988
970
|
});
|
|
989
971
|
|
|
990
972
|
const compositeGroups = populatedGroups.concat(empty);
|
|
@@ -1148,12 +1130,6 @@ module.exports = (() => {
|
|
|
1148
1130
|
array.remove(this._symbolsDisplay[displaySymbol], i => i === positionItem);
|
|
1149
1131
|
}
|
|
1150
1132
|
|
|
1151
|
-
const currency = extractCurrency(positionItem.position);
|
|
1152
|
-
|
|
1153
|
-
if (currency && this._currencies.hasOwnProperty(currency.code)) {
|
|
1154
|
-
array.remove(this._currencies[currency.code], i => i === positionItem);
|
|
1155
|
-
}
|
|
1156
|
-
|
|
1157
1133
|
Object.keys(this._trees).forEach((key) => {
|
|
1158
1134
|
this._trees[key].walk((group, groupNode) => {
|
|
1159
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",
|