@barchart/portfolio-api-common 1.0.71 → 1.0.72
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.
|
@@ -109,13 +109,13 @@ module.exports = (() => {
|
|
|
109
109
|
const populatedGroups = Object.keys(populatedObjects).map(key => populatedObjects[key]).map((items) => {
|
|
110
110
|
const first = items[0];
|
|
111
111
|
|
|
112
|
-
return new PositionGroup(parent, items, currentDefinition.currencySelector(first), currentDefinition.descriptionSelector(first), currentDefinition.single && items.length === 1);
|
|
112
|
+
return new PositionGroup(this, parent, items, currentDefinition.currencySelector(first), currentDefinition.descriptionSelector(first), currentDefinition.single && items.length === 1);
|
|
113
113
|
});
|
|
114
114
|
|
|
115
115
|
const missingGroups = array.difference(currentDefinition.requiredGroups.map(group => group.description), populatedGroups.map(group => group.description));
|
|
116
116
|
|
|
117
117
|
const empty = missingGroups.map((description) => {
|
|
118
|
-
return new PositionGroup(parent, [ ], currentDefinition.requiredGroups.find(group => group.description === description).currency, description);
|
|
118
|
+
return new PositionGroup(this, parent, [ ], currentDefinition.requiredGroups.find(group => group.description === description).currency, description);
|
|
119
119
|
});
|
|
120
120
|
|
|
121
121
|
const compositeGroups = populatedGroups.concat(empty);
|
|
@@ -186,10 +186,20 @@ module.exports = (() => {
|
|
|
186
186
|
}, [ ]);
|
|
187
187
|
}
|
|
188
188
|
|
|
189
|
-
|
|
189
|
+
setExchangeRate(symbol, price) {
|
|
190
190
|
|
|
191
191
|
}
|
|
192
192
|
|
|
193
|
+
startTransaction(executor) {
|
|
194
|
+
assert.argumentIsRequired(executor, 'executor', Function);
|
|
195
|
+
|
|
196
|
+
this._tree.walk(group => group.setSuspended(true), false, false);
|
|
197
|
+
|
|
198
|
+
executor(this);
|
|
199
|
+
|
|
200
|
+
this._tree.walk(group => group.setSuspended(false), false, false);
|
|
201
|
+
}
|
|
202
|
+
|
|
193
203
|
getGroup(keys) {
|
|
194
204
|
const node = keys.reduce((tree, key) => {
|
|
195
205
|
tree = tree.findChild(group => group.description === key);
|
|
@@ -11,7 +11,8 @@ module.exports = (() => {
|
|
|
11
11
|
* @public
|
|
12
12
|
*/
|
|
13
13
|
class PositionGroup {
|
|
14
|
-
constructor(parent, items, currency, description, single) {
|
|
14
|
+
constructor(container, parent, items, currency, description, single) {
|
|
15
|
+
this._container = container;
|
|
15
16
|
this._parent = parent || null;
|
|
16
17
|
|
|
17
18
|
this._items = items;
|
|
@@ -21,6 +22,9 @@ module.exports = (() => {
|
|
|
21
22
|
|
|
22
23
|
this._single = is.boolean(single) && single;
|
|
23
24
|
|
|
25
|
+
this._excluded = false;
|
|
26
|
+
this._suspended = false;
|
|
27
|
+
|
|
24
28
|
this._dataFormat = { };
|
|
25
29
|
this._dataActual = { };
|
|
26
30
|
|
|
@@ -62,12 +66,11 @@ module.exports = (() => {
|
|
|
62
66
|
this._dataFormat.currentPrice = null;
|
|
63
67
|
}
|
|
64
68
|
|
|
65
|
-
calculatePriceData(this, sender);
|
|
69
|
+
calculatePriceData(this, sender, false);
|
|
66
70
|
});
|
|
67
71
|
});
|
|
68
72
|
|
|
69
|
-
|
|
70
|
-
calculatePriceData(this);
|
|
73
|
+
this.refresh();
|
|
71
74
|
}
|
|
72
75
|
|
|
73
76
|
get items() {
|
|
@@ -90,6 +93,41 @@ module.exports = (() => {
|
|
|
90
93
|
return this._single;
|
|
91
94
|
}
|
|
92
95
|
|
|
96
|
+
get suspended() {
|
|
97
|
+
return this._suspended;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
get excluded() {
|
|
101
|
+
return this._excluded;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
setExcluded(value) {
|
|
105
|
+
assert.argumentIsRequired(value, 'value', Boolean);
|
|
106
|
+
|
|
107
|
+
if (this._excluded !== value) {
|
|
108
|
+
this._container.startTransaction(() => {
|
|
109
|
+
this._items.forEach((item) => {
|
|
110
|
+
item.setExcluded(value);
|
|
111
|
+
});
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
setSuspended(value) {
|
|
117
|
+
assert.argumentIsRequired(value, 'value', Boolean);
|
|
118
|
+
|
|
119
|
+
if (this._suspended !== value) {
|
|
120
|
+
if (this._suspended = value) {
|
|
121
|
+
this.refresh();
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
refresh() {
|
|
127
|
+
calculateStaticData(this);
|
|
128
|
+
calculatePriceData(this, null, true);
|
|
129
|
+
}
|
|
130
|
+
|
|
93
131
|
toString() {
|
|
94
132
|
return '[PositionGroup]';
|
|
95
133
|
}
|
|
@@ -116,6 +154,10 @@ module.exports = (() => {
|
|
|
116
154
|
}
|
|
117
155
|
|
|
118
156
|
function calculateStaticData(group) {
|
|
157
|
+
if (group.suspended) {
|
|
158
|
+
return;
|
|
159
|
+
}
|
|
160
|
+
|
|
119
161
|
const actual = group._dataActual;
|
|
120
162
|
const format = group._dataFormat;
|
|
121
163
|
|
|
@@ -152,7 +194,11 @@ module.exports = (() => {
|
|
|
152
194
|
format.summaryTwoTotal = formatCurrency(updates.summaryTwoTotal, currency);
|
|
153
195
|
}
|
|
154
196
|
|
|
155
|
-
function calculatePriceData(group, item) {
|
|
197
|
+
function calculatePriceData(group, item, forceRefresh) {
|
|
198
|
+
if (group.suspended) {
|
|
199
|
+
return;
|
|
200
|
+
}
|
|
201
|
+
|
|
156
202
|
const parent = group._parent;
|
|
157
203
|
|
|
158
204
|
const actual = group._dataActual;
|
|
@@ -160,14 +206,11 @@ module.exports = (() => {
|
|
|
160
206
|
|
|
161
207
|
const currency = group.currency;
|
|
162
208
|
|
|
209
|
+
const refresh = (is.boolean(forceRefresh) && forceRefresh) || (actual.market === null || actual.unrealizedToday === null || actual.total === null);
|
|
210
|
+
|
|
163
211
|
let updates;
|
|
164
212
|
|
|
165
|
-
if (
|
|
166
|
-
updates = {
|
|
167
|
-
market: actual.market.add(item.data.marketChange),
|
|
168
|
-
unrealizedToday: actual.unrealizedToday.add(item.data.unrealizedTodayChange)
|
|
169
|
-
};
|
|
170
|
-
} else {
|
|
213
|
+
if (refresh) {
|
|
171
214
|
const items = group._items;
|
|
172
215
|
|
|
173
216
|
updates = items.reduce((updates, item) => {
|
|
@@ -177,8 +220,14 @@ module.exports = (() => {
|
|
|
177
220
|
return updates;
|
|
178
221
|
}, {
|
|
179
222
|
market: Decimal.ZERO,
|
|
223
|
+
|
|
180
224
|
unrealizedToday: Decimal.ZERO
|
|
181
225
|
});
|
|
226
|
+
} else {
|
|
227
|
+
updates = {
|
|
228
|
+
market: actual.market.add(item.data.marketChange),
|
|
229
|
+
unrealizedToday: actual.unrealizedToday.add(item.data.unrealizedTodayChange)
|
|
230
|
+
};
|
|
182
231
|
}
|
|
183
232
|
|
|
184
233
|
if (parent !== null) {
|
|
@@ -33,10 +33,13 @@ module.exports = (() => {
|
|
|
33
33
|
this._data.realized = null;
|
|
34
34
|
this._data.income = null;
|
|
35
35
|
|
|
36
|
+
this._excluded = false;
|
|
37
|
+
|
|
36
38
|
calculateStaticData(this);
|
|
37
39
|
calculatePriceData(this, null);
|
|
38
40
|
|
|
39
41
|
this._priceChangeEvent = new Event(this);
|
|
42
|
+
this._excludedChangeEvent = new Event(this);
|
|
40
43
|
}
|
|
41
44
|
|
|
42
45
|
get portfolio() {
|
|
@@ -55,7 +58,13 @@ module.exports = (() => {
|
|
|
55
58
|
return this._data;
|
|
56
59
|
}
|
|
57
60
|
|
|
61
|
+
get excluded() {
|
|
62
|
+
return this._excluded;
|
|
63
|
+
}
|
|
64
|
+
|
|
58
65
|
setPrice(price) {
|
|
66
|
+
assert.argumentIsRequired(price, 'price', Number);
|
|
67
|
+
|
|
59
68
|
if (this._data.price !== price) {
|
|
60
69
|
calculatePriceData(this, this._data.currentPrice = price);
|
|
61
70
|
|
|
@@ -63,12 +72,22 @@ module.exports = (() => {
|
|
|
63
72
|
}
|
|
64
73
|
}
|
|
65
74
|
|
|
66
|
-
|
|
67
|
-
assert.argumentIsRequired(
|
|
75
|
+
setExcluded(value) {
|
|
76
|
+
assert.argumentIsRequired(value, 'value', Boolean);
|
|
68
77
|
|
|
78
|
+
if (this._excluded !== value) {
|
|
79
|
+
this._excludedChangeEvent.fire(this, this._excluded = value);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
registerPriceChangeHandler(handler) {
|
|
69
84
|
this._priceChangeEvent.register(handler);
|
|
70
85
|
}
|
|
71
86
|
|
|
87
|
+
registerExcludedChangeHandler(handler) {
|
|
88
|
+
this._excludedChangeEvent.register(handler);
|
|
89
|
+
}
|
|
90
|
+
|
|
72
91
|
toString() {
|
|
73
92
|
return '[PositionItem]';
|
|
74
93
|
}
|
|
@@ -155,6 +155,7 @@ module.exports = (() => {
|
|
|
155
155
|
);
|
|
156
156
|
|
|
157
157
|
const update = new PortfolioSchema(SchemaBuilder.withName('update')
|
|
158
|
+
.withField('portfolio', DataType.STRING)
|
|
158
159
|
.withField('name', DataType.STRING)
|
|
159
160
|
.withField('timezone', DataType.forEnum(Timezones, 'Timezone'), true)
|
|
160
161
|
.withField('defaults.currency', DataType.forEnum(Currency, 'Currency'), true)
|
package/package.json
CHANGED
package/test/SpecRunner.js
CHANGED
|
@@ -786,13 +786,13 @@ module.exports = (() => {
|
|
|
786
786
|
const populatedGroups = Object.keys(populatedObjects).map(key => populatedObjects[key]).map((items) => {
|
|
787
787
|
const first = items[0];
|
|
788
788
|
|
|
789
|
-
return new PositionGroup(parent, items, currentDefinition.currencySelector(first), currentDefinition.descriptionSelector(first), currentDefinition.single && items.length === 1);
|
|
789
|
+
return new PositionGroup(this, parent, items, currentDefinition.currencySelector(first), currentDefinition.descriptionSelector(first), currentDefinition.single && items.length === 1);
|
|
790
790
|
});
|
|
791
791
|
|
|
792
792
|
const missingGroups = array.difference(currentDefinition.requiredGroups.map(group => group.description), populatedGroups.map(group => group.description));
|
|
793
793
|
|
|
794
794
|
const empty = missingGroups.map((description) => {
|
|
795
|
-
return new PositionGroup(parent, [ ], currentDefinition.requiredGroups.find(group => group.description === description).currency, description);
|
|
795
|
+
return new PositionGroup(this, parent, [ ], currentDefinition.requiredGroups.find(group => group.description === description).currency, description);
|
|
796
796
|
});
|
|
797
797
|
|
|
798
798
|
const compositeGroups = populatedGroups.concat(empty);
|
|
@@ -863,10 +863,20 @@ module.exports = (() => {
|
|
|
863
863
|
}, [ ]);
|
|
864
864
|
}
|
|
865
865
|
|
|
866
|
-
|
|
866
|
+
setExchangeRate(symbol, price) {
|
|
867
867
|
|
|
868
868
|
}
|
|
869
869
|
|
|
870
|
+
startTransaction(executor) {
|
|
871
|
+
assert.argumentIsRequired(executor, 'executor', Function);
|
|
872
|
+
|
|
873
|
+
this._tree.walk(group => group.setSuspended(true), false, false);
|
|
874
|
+
|
|
875
|
+
executor(this);
|
|
876
|
+
|
|
877
|
+
this._tree.walk(group => group.setSuspended(false), false, false);
|
|
878
|
+
}
|
|
879
|
+
|
|
870
880
|
getGroup(keys) {
|
|
871
881
|
const node = keys.reduce((tree, key) => {
|
|
872
882
|
tree = tree.findChild(group => group.description === key);
|
|
@@ -913,7 +923,8 @@ module.exports = (() => {
|
|
|
913
923
|
* @public
|
|
914
924
|
*/
|
|
915
925
|
class PositionGroup {
|
|
916
|
-
constructor(parent, items, currency, description, single) {
|
|
926
|
+
constructor(container, parent, items, currency, description, single) {
|
|
927
|
+
this._container = container;
|
|
917
928
|
this._parent = parent || null;
|
|
918
929
|
|
|
919
930
|
this._items = items;
|
|
@@ -923,6 +934,9 @@ module.exports = (() => {
|
|
|
923
934
|
|
|
924
935
|
this._single = is.boolean(single) && single;
|
|
925
936
|
|
|
937
|
+
this._excluded = false;
|
|
938
|
+
this._suspended = false;
|
|
939
|
+
|
|
926
940
|
this._dataFormat = { };
|
|
927
941
|
this._dataActual = { };
|
|
928
942
|
|
|
@@ -964,12 +978,11 @@ module.exports = (() => {
|
|
|
964
978
|
this._dataFormat.currentPrice = null;
|
|
965
979
|
}
|
|
966
980
|
|
|
967
|
-
calculatePriceData(this, sender);
|
|
981
|
+
calculatePriceData(this, sender, false);
|
|
968
982
|
});
|
|
969
983
|
});
|
|
970
984
|
|
|
971
|
-
|
|
972
|
-
calculatePriceData(this);
|
|
985
|
+
this.refresh();
|
|
973
986
|
}
|
|
974
987
|
|
|
975
988
|
get items() {
|
|
@@ -992,6 +1005,41 @@ module.exports = (() => {
|
|
|
992
1005
|
return this._single;
|
|
993
1006
|
}
|
|
994
1007
|
|
|
1008
|
+
get suspended() {
|
|
1009
|
+
return this._suspended;
|
|
1010
|
+
}
|
|
1011
|
+
|
|
1012
|
+
get excluded() {
|
|
1013
|
+
return this._excluded;
|
|
1014
|
+
}
|
|
1015
|
+
|
|
1016
|
+
setExcluded(value) {
|
|
1017
|
+
assert.argumentIsRequired(value, 'value', Boolean);
|
|
1018
|
+
|
|
1019
|
+
if (this._excluded !== value) {
|
|
1020
|
+
this._container.startTransaction(() => {
|
|
1021
|
+
this._items.forEach((item) => {
|
|
1022
|
+
item.setExcluded(value);
|
|
1023
|
+
});
|
|
1024
|
+
});
|
|
1025
|
+
}
|
|
1026
|
+
}
|
|
1027
|
+
|
|
1028
|
+
setSuspended(value) {
|
|
1029
|
+
assert.argumentIsRequired(value, 'value', Boolean);
|
|
1030
|
+
|
|
1031
|
+
if (this._suspended !== value) {
|
|
1032
|
+
if (this._suspended = value) {
|
|
1033
|
+
this.refresh();
|
|
1034
|
+
}
|
|
1035
|
+
}
|
|
1036
|
+
}
|
|
1037
|
+
|
|
1038
|
+
refresh() {
|
|
1039
|
+
calculateStaticData(this);
|
|
1040
|
+
calculatePriceData(this, null, true);
|
|
1041
|
+
}
|
|
1042
|
+
|
|
995
1043
|
toString() {
|
|
996
1044
|
return '[PositionGroup]';
|
|
997
1045
|
}
|
|
@@ -1018,6 +1066,10 @@ module.exports = (() => {
|
|
|
1018
1066
|
}
|
|
1019
1067
|
|
|
1020
1068
|
function calculateStaticData(group) {
|
|
1069
|
+
if (group.suspended) {
|
|
1070
|
+
return;
|
|
1071
|
+
}
|
|
1072
|
+
|
|
1021
1073
|
const actual = group._dataActual;
|
|
1022
1074
|
const format = group._dataFormat;
|
|
1023
1075
|
|
|
@@ -1054,7 +1106,11 @@ module.exports = (() => {
|
|
|
1054
1106
|
format.summaryTwoTotal = formatCurrency(updates.summaryTwoTotal, currency);
|
|
1055
1107
|
}
|
|
1056
1108
|
|
|
1057
|
-
function calculatePriceData(group, item) {
|
|
1109
|
+
function calculatePriceData(group, item, forceRefresh) {
|
|
1110
|
+
if (group.suspended) {
|
|
1111
|
+
return;
|
|
1112
|
+
}
|
|
1113
|
+
|
|
1058
1114
|
const parent = group._parent;
|
|
1059
1115
|
|
|
1060
1116
|
const actual = group._dataActual;
|
|
@@ -1062,14 +1118,11 @@ module.exports = (() => {
|
|
|
1062
1118
|
|
|
1063
1119
|
const currency = group.currency;
|
|
1064
1120
|
|
|
1121
|
+
const refresh = (is.boolean(forceRefresh) && forceRefresh) || (actual.market === null || actual.unrealizedToday === null || actual.total === null);
|
|
1122
|
+
|
|
1065
1123
|
let updates;
|
|
1066
1124
|
|
|
1067
|
-
if (
|
|
1068
|
-
updates = {
|
|
1069
|
-
market: actual.market.add(item.data.marketChange),
|
|
1070
|
-
unrealizedToday: actual.unrealizedToday.add(item.data.unrealizedTodayChange)
|
|
1071
|
-
};
|
|
1072
|
-
} else {
|
|
1125
|
+
if (refresh) {
|
|
1073
1126
|
const items = group._items;
|
|
1074
1127
|
|
|
1075
1128
|
updates = items.reduce((updates, item) => {
|
|
@@ -1079,8 +1132,14 @@ module.exports = (() => {
|
|
|
1079
1132
|
return updates;
|
|
1080
1133
|
}, {
|
|
1081
1134
|
market: Decimal.ZERO,
|
|
1135
|
+
|
|
1082
1136
|
unrealizedToday: Decimal.ZERO
|
|
1083
1137
|
});
|
|
1138
|
+
} else {
|
|
1139
|
+
updates = {
|
|
1140
|
+
market: actual.market.add(item.data.marketChange),
|
|
1141
|
+
unrealizedToday: actual.unrealizedToday.add(item.data.unrealizedTodayChange)
|
|
1142
|
+
};
|
|
1084
1143
|
}
|
|
1085
1144
|
|
|
1086
1145
|
if (parent !== null) {
|
|
@@ -1196,10 +1255,13 @@ module.exports = (() => {
|
|
|
1196
1255
|
this._data.realized = null;
|
|
1197
1256
|
this._data.income = null;
|
|
1198
1257
|
|
|
1258
|
+
this._excluded = false;
|
|
1259
|
+
|
|
1199
1260
|
calculateStaticData(this);
|
|
1200
1261
|
calculatePriceData(this, null);
|
|
1201
1262
|
|
|
1202
1263
|
this._priceChangeEvent = new Event(this);
|
|
1264
|
+
this._excludedChangeEvent = new Event(this);
|
|
1203
1265
|
}
|
|
1204
1266
|
|
|
1205
1267
|
get portfolio() {
|
|
@@ -1218,7 +1280,13 @@ module.exports = (() => {
|
|
|
1218
1280
|
return this._data;
|
|
1219
1281
|
}
|
|
1220
1282
|
|
|
1283
|
+
get excluded() {
|
|
1284
|
+
return this._excluded;
|
|
1285
|
+
}
|
|
1286
|
+
|
|
1221
1287
|
setPrice(price) {
|
|
1288
|
+
assert.argumentIsRequired(price, 'price', Number);
|
|
1289
|
+
|
|
1222
1290
|
if (this._data.price !== price) {
|
|
1223
1291
|
calculatePriceData(this, this._data.currentPrice = price);
|
|
1224
1292
|
|
|
@@ -1226,12 +1294,22 @@ module.exports = (() => {
|
|
|
1226
1294
|
}
|
|
1227
1295
|
}
|
|
1228
1296
|
|
|
1229
|
-
|
|
1230
|
-
assert.argumentIsRequired(
|
|
1297
|
+
setExcluded(value) {
|
|
1298
|
+
assert.argumentIsRequired(value, 'value', Boolean);
|
|
1231
1299
|
|
|
1300
|
+
if (this._excluded !== value) {
|
|
1301
|
+
this._excludedChangeEvent.fire(this, this._excluded = value);
|
|
1302
|
+
}
|
|
1303
|
+
}
|
|
1304
|
+
|
|
1305
|
+
registerPriceChangeHandler(handler) {
|
|
1232
1306
|
this._priceChangeEvent.register(handler);
|
|
1233
1307
|
}
|
|
1234
1308
|
|
|
1309
|
+
registerExcludedChangeHandler(handler) {
|
|
1310
|
+
this._excludedChangeEvent.register(handler);
|
|
1311
|
+
}
|
|
1312
|
+
|
|
1235
1313
|
toString() {
|
|
1236
1314
|
return '[PositionItem]';
|
|
1237
1315
|
}
|