@barchart/portfolio-api-common 1.0.61 → 1.0.65

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.
@@ -6,6 +6,8 @@ const array = require('@barchart/common-js/lang/array'),
6
6
  is = require('@barchart/common-js/lang/is'),
7
7
  Tree = require('@barchart/common-js/collections/Tree');
8
8
 
9
+ const InstrumentType = require('./../data/InstrumentType');
10
+
9
11
  const PositionGroup = require('./PositionGroup'),
10
12
  PositionItem = require('./PositionItem');
11
13
 
@@ -16,7 +18,10 @@ module.exports = (() => {
16
18
  * @public
17
19
  */
18
20
  class PositionContainer {
19
- constructor(portfolios, positions, summaries, definitions) {
21
+ constructor(portfolios, positions, summaries, definitions, defaultCurrency) {
22
+ this._definitions = definitions;
23
+ this._defaultCurrency = defaultCurrency || Currency.CAD;
24
+
20
25
  this._portfolios = portfolios.reduce((map, portfolio) => {
21
26
  map[portfolio.portfolio] = portfolio;
22
27
 
@@ -48,11 +53,10 @@ module.exports = (() => {
48
53
  }, [ ]);
49
54
 
50
55
  this._symbols = this._items.reduce((map, item) => {
51
- let position = item.position;
52
- let symbol = null;
56
+ const position = item.position;
53
57
 
54
58
  if (position.instrument && position.instrument.symbol && position.instrument.symbol.barchart) {
55
- symbol = position.instrument.symbol.barchart;
59
+ const symbol = position.instrument.symbol.barchart;
56
60
 
57
61
  if (!map.hasOwnProperty(symbol)) {
58
62
  map[symbol] = [ ];
@@ -64,7 +68,21 @@ module.exports = (() => {
64
68
  return map;
65
69
  }, { });
66
70
 
67
- this._definitions = definitions;
71
+ this._currencies = this._items.reduce((map, item) => {
72
+ const position = item.position;
73
+
74
+ if (position.instrument && position.instrument.currency) {
75
+ const currency = position.instrument.currency;
76
+
77
+ if (!map.hasOwnProperty(currency)) {
78
+ map[currency] = [ ];
79
+ }
80
+
81
+ map[currency].push(item);
82
+ }
83
+
84
+ return map;
85
+ }, { });
68
86
 
69
87
  this._tree = new Tree();
70
88
 
@@ -73,6 +91,8 @@ module.exports = (() => {
73
91
  return;
74
92
  }
75
93
 
94
+ const parent = tree.getValue() || null;
95
+
76
96
  const currentDefinition = definitions[0];
77
97
  const additionalDefinitions = array.dropLeft(definitions);
78
98
 
@@ -80,13 +100,13 @@ module.exports = (() => {
80
100
  const populatedGroups = Object.keys(populatedObjects).map(key => populatedObjects[key]).map((items) => {
81
101
  const first = items[0];
82
102
 
83
- return new PositionGroup(items, currentDefinition.currencySelector(first), currentDefinition.descriptionSelector(first), currentDefinition.single && items.length === 1);
103
+ return new PositionGroup(parent, items, currentDefinition.currencySelector(first), currentDefinition.descriptionSelector(first), currentDefinition.single && items.length === 1);
84
104
  });
85
105
 
86
106
  const missingGroups = array.difference(currentDefinition.requiredGroups.map(group => group.description), populatedGroups.map(group => group.description));
87
107
 
88
108
  const empty = missingGroups.map((description) => {
89
- return new PositionGroup([ ], currentDefinition.requiredGroups.find(group => group.description === description).currency, description);
109
+ return new PositionGroup(parent, [ ], currentDefinition.requiredGroups.find(group => group.description === description).currency, description);
90
110
  });
91
111
 
92
112
  const compositeGroups = populatedGroups.concat(empty);
@@ -131,6 +151,10 @@ module.exports = (() => {
131
151
  createGroups(this._tree, this._items, this._definitions);
132
152
  }
133
153
 
154
+ get defaultCurrency() {
155
+ return this._defaultCurrency;
156
+ }
157
+
134
158
  getSymbols() {
135
159
  return Object.keys(this._symbols);
136
160
  }
@@ -141,6 +165,22 @@ module.exports = (() => {
141
165
  }
142
166
  }
143
167
 
168
+ getCurrencySymbols() {
169
+ const codes = Object.keys(this._currencies);
170
+
171
+ return codes.reduce((symbols, code) => {
172
+ if (code !== this._defaultCurrency) {
173
+ symbols.push(`^${this._defaultCurrency}${code}`);
174
+ }
175
+
176
+ return symbols;
177
+ }, [ ]);
178
+ }
179
+
180
+ setExchangeRage(symbol, price) {
181
+
182
+ }
183
+
144
184
  getGroup(keys) {
145
185
  const node = keys.reduce((tree, key) => {
146
186
  tree = tree.findChild(group => group.description === key);
@@ -11,7 +11,9 @@ module.exports = (() => {
11
11
  * @public
12
12
  */
13
13
  class PositionGroup {
14
- constructor(items, currency, description, single) {
14
+ constructor(parent, items, currency, description, single) {
15
+ this._parent = parent || null;
16
+
15
17
  this._items = items;
16
18
  this._currency = currency;
17
19
 
@@ -20,37 +22,42 @@ module.exports = (() => {
20
22
  this._single = is.boolean(single) && single;
21
23
 
22
24
  this._dataFormat = { };
23
- this._dataRaw = { };
25
+ this._dataActual = { };
24
26
 
25
27
  this._dataFormat.description = this._description;
26
28
 
27
- this._dataRaw.current = null;
28
- this._dataRaw.previous = null;
29
-
30
- this._dataFormat.current = null;
31
- this._dataFormat.previous = null;
32
-
33
- this._dataRaw.basis = null;
34
- this._dataRaw.market = null;
29
+ this._dataActual.currentPrice = null;
30
+ this._dataActual.previousPrice = null;
31
+ this._dataActual.basis = null;
32
+ this._dataActual.market = null;
33
+ this._dataActual.marketPercent = null;
34
+ this._dataActual.unrealizedToday = null;
35
35
 
36
+ this._dataFormat.currentPrice = null;
37
+ this._dataFormat.previousPrice = null;
36
38
  this._dataFormat.basis = null;
37
39
  this._dataFormat.market = null;
40
+ this._dataFormat.marketPercent = null;
41
+ this._dataFormat.unrealizedToday = null;
42
+
43
+ this._dataFormat.unrealizedTodayPositive = true;
38
44
 
39
45
  this._items.forEach((item) => {
40
46
  item.registerPriceChangeHandler((data, sender) => {
41
47
  if (this._single) {
42
- this._dataRaw.current = data.current;
43
- this._dataFormat.current = format(data.current, sender.position.instrument.currency);
48
+ this._dataActual.currentPrice = data.currentPrice;
49
+ this._dataFormat.currentPrice = format(data.currentPrice, sender.position.instrument.currency);
44
50
  } else {
45
- this._dataRaw.current = null;
46
- this._dataFormat.current = null;
51
+ this._dataActual.currentPrice = null;
52
+ this._dataFormat.currentPrice = null;
47
53
  }
48
54
 
49
- calculatePriceData(this, item);
55
+ calculatePriceData(this, sender);
50
56
  });
51
57
  });
52
58
 
53
59
  calculateStaticData(this);
60
+ calculatePriceData(this);
54
61
  }
55
62
 
56
63
  get items() {
@@ -78,64 +85,92 @@ module.exports = (() => {
78
85
  }
79
86
  }
80
87
 
81
- function format(decimal, currency) {
82
- return formatter.numberToString(decimal.toFloat(), currency.precision, ',', false);
88
+ function formatNumber(decimal, precision) {
89
+ if (decimal !== null) {
90
+ return formatter.numberToString(decimal.toFloat(), precision, ',', false);
91
+ } else {
92
+ return '--';
93
+ }
83
94
  }
84
95
 
85
- function calculateStaticData(group) {
86
- const items = group._items;
87
-
88
- let updates;
96
+ function formatPercent(decimal, precision) {
97
+ if (decimal !== null) {
98
+ return formatNumber(decimal.multiply(100));
99
+ } else {
100
+ return '--';
101
+ }
102
+ }
89
103
 
90
- if (group.single) {
91
- const item = items[0];
104
+ function formatCurrency(decimal, currency) {
105
+ return formatNumber(decimal, currency.precision);
106
+ }
92
107
 
93
- updates = { };
108
+ function calculateStaticData(group) {
109
+ const actual = group._dataActual;
110
+ const format = group._dataFormat;
94
111
 
95
- updates.basis = item.basis;
96
- } else {
97
- updates = items.reduce(function(updates, item) {
98
- updates.basis = updates.basis.add(item.data.basis);
112
+ const currency = group.currency;
113
+
114
+ const items = group._items;
99
115
 
100
- return updates;
101
- }, {
102
- basis: Decimal.ZERO
103
- });
104
- }
116
+ let updates = items.reduce((updates, item) => {
117
+ updates.basis = updates.basis.add(item.data.basis);
105
118
 
106
- const raw = group._dataRaw;
107
- const formatted = group._dataFormat;
119
+ return updates;
120
+ }, {
121
+ basis: Decimal.ZERO
122
+ });
108
123
 
109
- raw.basis = updates.basis;
110
- formatted.basis = format(updates.basis, Currency.USD);
124
+ actual.basis = updates.basis;
125
+
126
+ format.basis = formatCurrency(updates.basis, currency);
111
127
  }
112
128
 
113
- function calculatePriceData(group) {
114
- const items = group._items;
129
+ function calculatePriceData(group, item) {
130
+ const parent = group._parent;
115
131
 
116
- let updates;
132
+ const actual = group._dataActual;
133
+ const format = group._dataFormat;
134
+
135
+ const currency = group.currency;
117
136
 
118
- if (group.single) {
119
- updates = { };
137
+ let updates;
120
138
 
121
- let item = items[0];
139
+ if (actual.market === null || actual.unrealizedToday === null) {
140
+ const items = group._items;
122
141
 
123
- updates.market = item.market;
124
- } else {
125
- updates = items.reduce(function(updates, item) {
142
+ updates = items.reduce((updates, item) => {
126
143
  updates.market = updates.market.add(item.data.market);
144
+ updates.unrealizedToday = updates.unrealizedToday.add(item.data.unrealizedToday);
127
145
 
128
146
  return updates;
129
147
  }, {
130
- market: Decimal.ZERO
148
+ market: Decimal.ZERO,
149
+ unrealizedToday: Decimal.ZERO
131
150
  });
151
+ } else {
152
+ updates = {
153
+ market: actual.market.add(item.data.marketChange),
154
+ unrealizedToday: actual.unrealizedToday.add(item.data.unrealizedTodayChange)
155
+ };
132
156
  }
157
+
158
+ if (parent !== null) {
159
+ const parentData = parent._dataActual;
133
160
 
134
- const raw = group._dataRaw;
135
- const formatted = group._dataFormat;
136
-
137
- raw.market = updates.market;
138
- formatted.market = format(updates.market, Currency.USD);
161
+ if (parentData.market !== null && !parentData.market.getIsZero()) {
162
+ updates.marketPercent = updates.market.divide(parentData.market);
163
+ }
164
+ }
165
+
166
+ actual.market = updates.market;
167
+ actual.marketPercent = updates.marketPercent;
168
+ actual.unrealizedToday = updates.unrealizedToday;
169
+
170
+ format.market = formatCurrency(updates.market, currency);
171
+ format.marketPercent = formatPercent(updates.unrealizedToday, 2);
172
+ format.unrealizedToday = formatCurrency(updates.unrealizedToday, currency);
173
+ format.unrealizedTodayPositive = actual.unrealizedToday.getIsPositive();
139
174
  }
140
175
 
141
176
  return PositionGroup;
@@ -19,10 +19,17 @@ module.exports = (() => {
19
19
 
20
20
  this._data = { };
21
21
 
22
- this._data.current = null;
23
- this._data.previous = null;
24
22
  this._data.basis = null;
25
23
 
24
+ this._data.currentPrice = null;
25
+ this._data.previousPrice = null;
26
+
27
+ this._data.market = null;
28
+ this._data.marketChange = null;
29
+
30
+ this._data.unrealizedToday = null;
31
+ this._data.unrealizedTodayChange = null;
32
+
26
33
  calculateStaticData(this);
27
34
  calculatePriceData(this, null);
28
35
 
@@ -47,7 +54,7 @@ module.exports = (() => {
47
54
 
48
55
  setPrice(price) {
49
56
  if (this._data.price !== price) {
50
- calculatePriceData(this, this._data.price = price);
57
+ calculatePriceData(this, this._data.currentPrice = price);
51
58
 
52
59
  this._priceChangeEvent.fire(this._data);
53
60
  }
@@ -70,7 +77,7 @@ module.exports = (() => {
70
77
 
71
78
  const data = item._data;
72
79
 
73
- data.previous = position.previous || null;
80
+ data.previousPrice = position.previousPrice || null;
74
81
 
75
82
  let basis;
76
83
 
@@ -103,7 +110,35 @@ module.exports = (() => {
103
110
  }
104
111
  }
105
112
 
113
+ let marketChange;
114
+
115
+ if (data.market === null) {
116
+ marketChange = market;
117
+ } else {
118
+ marketChange = market.subtract(data.market);
119
+ }
120
+
106
121
  data.market = market;
122
+ data.marketChange = marketChange;
123
+
124
+ let unrealizedToday;
125
+ let unrealizedTodayChange;
126
+
127
+ if (data.previousPrice && price) {
128
+ unrealizedToday = market.subtract(snapshot.open.multiply(data.previousPrice));
129
+
130
+ if (data.unrealizedToday !== null) {
131
+ unrealizedTodayChange = unrealizedToday.subtract(data.unrealizedToday);
132
+ } else {
133
+ unrealizedTodayChange = unrealizedToday;
134
+ }
135
+ } else {
136
+ unrealizedToday = Decimal.ZERO;
137
+ unrealizedTodayChange = Decimal.ZERO;
138
+ }
139
+
140
+ data.unrealizedToday = unrealizedToday;
141
+ data.unrealizedTodayChange = unrealizedTodayChange;
107
142
  }
108
143
 
109
144
  return PositionItem;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@barchart/portfolio-api-common",
3
- "version": "1.0.61",
3
+ "version": "1.0.65",
4
4
  "description": "Common classes used by the Portfolio system",
5
5
  "author": {
6
6
  "name": "Bryan Ingle",
@@ -612,6 +612,8 @@ const array = require('@barchart/common-js/lang/array'),
612
612
  is = require('@barchart/common-js/lang/is'),
613
613
  Tree = require('@barchart/common-js/collections/Tree');
614
614
 
615
+ const InstrumentType = require('./../data/InstrumentType');
616
+
615
617
  const PositionGroup = require('./PositionGroup'),
616
618
  PositionItem = require('./PositionItem');
617
619
 
@@ -622,7 +624,10 @@ module.exports = (() => {
622
624
  * @public
623
625
  */
624
626
  class PositionContainer {
625
- constructor(portfolios, positions, summaries, definitions) {
627
+ constructor(portfolios, positions, summaries, definitions, defaultCurrency) {
628
+ this._definitions = definitions;
629
+ this._defaultCurrency = defaultCurrency || Currency.CAD;
630
+
626
631
  this._portfolios = portfolios.reduce((map, portfolio) => {
627
632
  map[portfolio.portfolio] = portfolio;
628
633
 
@@ -654,11 +659,10 @@ module.exports = (() => {
654
659
  }, [ ]);
655
660
 
656
661
  this._symbols = this._items.reduce((map, item) => {
657
- let position = item.position;
658
- let symbol = null;
662
+ const position = item.position;
659
663
 
660
664
  if (position.instrument && position.instrument.symbol && position.instrument.symbol.barchart) {
661
- symbol = position.instrument.symbol.barchart;
665
+ const symbol = position.instrument.symbol.barchart;
662
666
 
663
667
  if (!map.hasOwnProperty(symbol)) {
664
668
  map[symbol] = [ ];
@@ -670,7 +674,21 @@ module.exports = (() => {
670
674
  return map;
671
675
  }, { });
672
676
 
673
- this._definitions = definitions;
677
+ this._currencies = this._items.reduce((map, item) => {
678
+ const position = item.position;
679
+
680
+ if (position.instrument && position.instrument.currency) {
681
+ const currency = position.instrument.currency;
682
+
683
+ if (!map.hasOwnProperty(currency)) {
684
+ map[currency] = [ ];
685
+ }
686
+
687
+ map[currency].push(item);
688
+ }
689
+
690
+ return map;
691
+ }, { });
674
692
 
675
693
  this._tree = new Tree();
676
694
 
@@ -679,6 +697,8 @@ module.exports = (() => {
679
697
  return;
680
698
  }
681
699
 
700
+ const parent = tree.getValue() || null;
701
+
682
702
  const currentDefinition = definitions[0];
683
703
  const additionalDefinitions = array.dropLeft(definitions);
684
704
 
@@ -686,13 +706,13 @@ module.exports = (() => {
686
706
  const populatedGroups = Object.keys(populatedObjects).map(key => populatedObjects[key]).map((items) => {
687
707
  const first = items[0];
688
708
 
689
- return new PositionGroup(items, currentDefinition.currencySelector(first), currentDefinition.descriptionSelector(first), currentDefinition.single && items.length === 1);
709
+ return new PositionGroup(parent, items, currentDefinition.currencySelector(first), currentDefinition.descriptionSelector(first), currentDefinition.single && items.length === 1);
690
710
  });
691
711
 
692
712
  const missingGroups = array.difference(currentDefinition.requiredGroups.map(group => group.description), populatedGroups.map(group => group.description));
693
713
 
694
714
  const empty = missingGroups.map((description) => {
695
- return new PositionGroup([ ], currentDefinition.requiredGroups.find(group => group.description === description).currency, description);
715
+ return new PositionGroup(parent, [ ], currentDefinition.requiredGroups.find(group => group.description === description).currency, description);
696
716
  });
697
717
 
698
718
  const compositeGroups = populatedGroups.concat(empty);
@@ -737,6 +757,10 @@ module.exports = (() => {
737
757
  createGroups(this._tree, this._items, this._definitions);
738
758
  }
739
759
 
760
+ get defaultCurrency() {
761
+ return this._defaultCurrency;
762
+ }
763
+
740
764
  getSymbols() {
741
765
  return Object.keys(this._symbols);
742
766
  }
@@ -747,6 +771,22 @@ module.exports = (() => {
747
771
  }
748
772
  }
749
773
 
774
+ getCurrencySymbols() {
775
+ const codes = Object.keys(this._currencies);
776
+
777
+ return codes.reduce((symbols, code) => {
778
+ if (code !== this._defaultCurrency) {
779
+ symbols.push(`^${this._defaultCurrency}${code}`);
780
+ }
781
+
782
+ return symbols;
783
+ }, [ ]);
784
+ }
785
+
786
+ setExchangeRage(symbol, price) {
787
+
788
+ }
789
+
750
790
  getGroup(keys) {
751
791
  const node = keys.reduce((tree, key) => {
752
792
  tree = tree.findChild(group => group.description === key);
@@ -775,7 +815,7 @@ module.exports = (() => {
775
815
  return PositionContainer;
776
816
  })();
777
817
 
778
- },{"./PositionGroup":5,"./PositionItem":7,"@barchart/common-js/collections/Tree":8,"@barchart/common-js/collections/sorting/ComparatorBuilder":9,"@barchart/common-js/collections/sorting/comparators":10,"@barchart/common-js/lang/Currency":11,"@barchart/common-js/lang/array":16,"@barchart/common-js/lang/assert":17,"@barchart/common-js/lang/is":19}],5:[function(require,module,exports){
818
+ },{"./../data/InstrumentType":1,"./PositionGroup":5,"./PositionItem":7,"@barchart/common-js/collections/Tree":8,"@barchart/common-js/collections/sorting/ComparatorBuilder":9,"@barchart/common-js/collections/sorting/comparators":10,"@barchart/common-js/lang/Currency":11,"@barchart/common-js/lang/array":16,"@barchart/common-js/lang/assert":17,"@barchart/common-js/lang/is":19}],5:[function(require,module,exports){
779
819
  const assert = require('@barchart/common-js/lang/assert'),
780
820
  Currency = require('@barchart/common-js/lang/Currency'),
781
821
  Decimal = require('@barchart/common-js/lang/Decimal'),
@@ -789,7 +829,9 @@ module.exports = (() => {
789
829
  * @public
790
830
  */
791
831
  class PositionGroup {
792
- constructor(items, currency, description, single) {
832
+ constructor(parent, items, currency, description, single) {
833
+ this._parent = parent || null;
834
+
793
835
  this._items = items;
794
836
  this._currency = currency;
795
837
 
@@ -798,37 +840,42 @@ module.exports = (() => {
798
840
  this._single = is.boolean(single) && single;
799
841
 
800
842
  this._dataFormat = { };
801
- this._dataRaw = { };
843
+ this._dataActual = { };
802
844
 
803
845
  this._dataFormat.description = this._description;
804
846
 
805
- this._dataRaw.current = null;
806
- this._dataRaw.previous = null;
807
-
808
- this._dataFormat.current = null;
809
- this._dataFormat.previous = null;
810
-
811
- this._dataRaw.basis = null;
812
- this._dataRaw.market = null;
847
+ this._dataActual.currentPrice = null;
848
+ this._dataActual.previousPrice = null;
849
+ this._dataActual.basis = null;
850
+ this._dataActual.market = null;
851
+ this._dataActual.marketPercent = null;
852
+ this._dataActual.unrealizedToday = null;
813
853
 
854
+ this._dataFormat.currentPrice = null;
855
+ this._dataFormat.previousPrice = null;
814
856
  this._dataFormat.basis = null;
815
857
  this._dataFormat.market = null;
858
+ this._dataFormat.marketPercent = null;
859
+ this._dataFormat.unrealizedToday = null;
860
+
861
+ this._dataFormat.unrealizedTodayPositive = true;
816
862
 
817
863
  this._items.forEach((item) => {
818
864
  item.registerPriceChangeHandler((data, sender) => {
819
865
  if (this._single) {
820
- this._dataRaw.current = data.current;
821
- this._dataFormat.current = format(data.current, sender.position.instrument.currency);
866
+ this._dataActual.currentPrice = data.currentPrice;
867
+ this._dataFormat.currentPrice = format(data.currentPrice, sender.position.instrument.currency);
822
868
  } else {
823
- this._dataRaw.current = null;
824
- this._dataFormat.current = null;
869
+ this._dataActual.currentPrice = null;
870
+ this._dataFormat.currentPrice = null;
825
871
  }
826
872
 
827
- calculatePriceData(this, item);
873
+ calculatePriceData(this, sender);
828
874
  });
829
875
  });
830
876
 
831
877
  calculateStaticData(this);
878
+ calculatePriceData(this);
832
879
  }
833
880
 
834
881
  get items() {
@@ -856,64 +903,92 @@ module.exports = (() => {
856
903
  }
857
904
  }
858
905
 
859
- function format(decimal, currency) {
860
- return formatter.numberToString(decimal.toFloat(), currency.precision, ',', false);
906
+ function formatNumber(decimal, precision) {
907
+ if (decimal !== null) {
908
+ return formatter.numberToString(decimal.toFloat(), precision, ',', false);
909
+ } else {
910
+ return '--';
911
+ }
861
912
  }
862
913
 
863
- function calculateStaticData(group) {
864
- const items = group._items;
865
-
866
- let updates;
914
+ function formatPercent(decimal, precision) {
915
+ if (decimal !== null) {
916
+ return formatNumber(decimal.multiply(100));
917
+ } else {
918
+ return '--';
919
+ }
920
+ }
867
921
 
868
- if (group.single) {
869
- const item = items[0];
922
+ function formatCurrency(decimal, currency) {
923
+ return formatNumber(decimal, currency.precision);
924
+ }
870
925
 
871
- updates = { };
926
+ function calculateStaticData(group) {
927
+ const actual = group._dataActual;
928
+ const format = group._dataFormat;
872
929
 
873
- updates.basis = item.basis;
874
- } else {
875
- updates = items.reduce(function(updates, item) {
876
- updates.basis = updates.basis.add(item.data.basis);
930
+ const currency = group.currency;
931
+
932
+ const items = group._items;
877
933
 
878
- return updates;
879
- }, {
880
- basis: Decimal.ZERO
881
- });
882
- }
934
+ let updates = items.reduce((updates, item) => {
935
+ updates.basis = updates.basis.add(item.data.basis);
883
936
 
884
- const raw = group._dataRaw;
885
- const formatted = group._dataFormat;
937
+ return updates;
938
+ }, {
939
+ basis: Decimal.ZERO
940
+ });
886
941
 
887
- raw.basis = updates.basis;
888
- formatted.basis = format(updates.basis, Currency.USD);
942
+ actual.basis = updates.basis;
943
+
944
+ format.basis = formatCurrency(updates.basis, currency);
889
945
  }
890
946
 
891
- function calculatePriceData(group) {
892
- const items = group._items;
947
+ function calculatePriceData(group, item) {
948
+ const parent = group._parent;
893
949
 
894
- let updates;
950
+ const actual = group._dataActual;
951
+ const format = group._dataFormat;
895
952
 
896
- if (group.single) {
897
- updates = { };
953
+ const currency = group.currency;
898
954
 
899
- let item = items[0];
955
+ let updates;
900
956
 
901
- updates.market = item.market;
902
- } else {
903
- updates = items.reduce(function(updates, item) {
957
+ if (actual.market === null || actual.unrealizedToday === null) {
958
+ const items = group._items;
959
+
960
+ updates = items.reduce((updates, item) => {
904
961
  updates.market = updates.market.add(item.data.market);
962
+ updates.unrealizedToday = updates.unrealizedToday.add(item.data.unrealizedToday);
905
963
 
906
964
  return updates;
907
965
  }, {
908
- market: Decimal.ZERO
966
+ market: Decimal.ZERO,
967
+ unrealizedToday: Decimal.ZERO
909
968
  });
969
+ } else {
970
+ updates = {
971
+ market: actual.market.add(item.data.marketChange),
972
+ unrealizedToday: actual.unrealizedToday.add(item.data.unrealizedTodayChange)
973
+ };
910
974
  }
975
+
976
+ if (parent !== null) {
977
+ const parentData = parent._dataActual;
911
978
 
912
- const raw = group._dataRaw;
913
- const formatted = group._dataFormat;
914
-
915
- raw.market = updates.market;
916
- formatted.market = format(updates.market, Currency.USD);
979
+ if (parentData.market !== null && !parentData.market.getIsZero()) {
980
+ updates.marketPercent = updates.market.divide(parentData.market);
981
+ }
982
+ }
983
+
984
+ actual.market = updates.market;
985
+ actual.marketPercent = updates.marketPercent;
986
+ actual.unrealizedToday = updates.unrealizedToday;
987
+
988
+ format.market = formatCurrency(updates.market, currency);
989
+ format.marketPercent = formatPercent(updates.unrealizedToday, 2);
990
+ format.unrealizedToday = formatCurrency(updates.unrealizedToday, currency);
991
+ format.unrealizedTodayPositive = actual.unrealizedToday.getIsPositive();
917
992
  }
918
993
 
919
994
  return PositionGroup;
@@ -991,10 +1066,17 @@ module.exports = (() => {
991
1066
 
992
1067
  this._data = { };
993
1068
 
994
- this._data.current = null;
995
- this._data.previous = null;
996
1069
  this._data.basis = null;
997
1070
 
1071
+ this._data.currentPrice = null;
1072
+ this._data.previousPrice = null;
1073
+
1074
+ this._data.market = null;
1075
+ this._data.marketChange = null;
1076
+
1077
+ this._data.unrealizedToday = null;
1078
+ this._data.unrealizedTodayChange = null;
1079
+
998
1080
  calculateStaticData(this);
999
1081
  calculatePriceData(this, null);
1000
1082
 
@@ -1019,7 +1101,7 @@ module.exports = (() => {
1019
1101
 
1020
1102
  setPrice(price) {
1021
1103
  if (this._data.price !== price) {
1022
- calculatePriceData(this, this._data.price = price);
1104
+ calculatePriceData(this, this._data.currentPrice = price);
1023
1105
 
1024
1106
  this._priceChangeEvent.fire(this._data);
1025
1107
  }
@@ -1042,7 +1124,7 @@ module.exports = (() => {
1042
1124
 
1043
1125
  const data = item._data;
1044
1126
 
1045
- data.previous = position.previous || null;
1127
+ data.previousPrice = position.previousPrice || null;
1046
1128
 
1047
1129
  let basis;
1048
1130
 
@@ -1075,7 +1157,35 @@ module.exports = (() => {
1075
1157
  }
1076
1158
  }
1077
1159
 
1160
+ let marketChange;
1161
+
1162
+ if (data.market === null) {
1163
+ marketChange = market;
1164
+ } else {
1165
+ marketChange = market.subtract(data.market);
1166
+ }
1167
+
1078
1168
  data.market = market;
1169
+ data.marketChange = marketChange;
1170
+
1171
+ let unrealizedToday;
1172
+ let unrealizedTodayChange;
1173
+
1174
+ if (data.previousPrice && price) {
1175
+ unrealizedToday = market.subtract(snapshot.open.multiply(data.previousPrice));
1176
+
1177
+ if (data.unrealizedToday !== null) {
1178
+ unrealizedTodayChange = unrealizedToday.subtract(data.unrealizedToday);
1179
+ } else {
1180
+ unrealizedTodayChange = unrealizedToday;
1181
+ }
1182
+ } else {
1183
+ unrealizedToday = Decimal.ZERO;
1184
+ unrealizedTodayChange = Decimal.ZERO;
1185
+ }
1186
+
1187
+ data.unrealizedToday = unrealizedToday;
1188
+ data.unrealizedTodayChange = unrealizedTodayChange;
1079
1189
  }
1080
1190
 
1081
1191
  return PositionItem;