@vuu-ui/vuu-data-test 2.1.19-beta.1 → 2.1.19-beta.2

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.
Files changed (61) hide show
  1. package/package.json +8 -9
  2. package/src/ArrayProxy.js +38 -0
  3. package/src/RuntimeVisualLink.js +45 -0
  4. package/src/SessionTable.js +49 -0
  5. package/src/Table.js +96 -0
  6. package/src/TickingArrayDataSource.js +208 -0
  7. package/src/UpdateGenerator.js +72 -0
  8. package/src/basket/BasketModule.js +272 -0
  9. package/src/basket/basket-schemas.js +355 -0
  10. package/src/basket/index.js +2 -0
  11. package/src/basket/reference-data/constituents.js +76 -0
  12. package/src/basket/reference-data/ftse100.js +686 -0
  13. package/src/basket/reference-data/hsi.js +1047 -0
  14. package/src/basket/reference-data/nasdaq100.js +812 -0
  15. package/src/basket/reference-data/prices.js +43 -0
  16. package/src/basket/reference-data/sp500.js +315 -0
  17. package/src/core/module/ModuleContainer.js +21 -0
  18. package/src/core/module/VuuModule.js +476 -0
  19. package/src/core/table/TableContainer.js +97 -0
  20. package/src/data-utils.js +53 -0
  21. package/src/index.js +13 -0
  22. package/src/local-datasource-provider/LocalDatasourceProvider.js +44 -0
  23. package/src/makeSuggestions.js +20 -0
  24. package/src/rowUpdates.js +0 -0
  25. package/src/schemas.js +19 -0
  26. package/src/session-table-utils.js +16 -0
  27. package/src/simul/SimulModule.js +175 -0
  28. package/src/simul/index.js +2 -0
  29. package/src/simul/reference-data/accounts.js +23 -0
  30. package/src/simul/reference-data/algos.js +9 -0
  31. package/src/simul/reference-data/currencies.js +8 -0
  32. package/src/simul/reference-data/index.js +5 -0
  33. package/src/simul/reference-data/instrument-prices.js +48 -0
  34. package/src/simul/reference-data/instruments-extended.js +12 -0
  35. package/src/simul/reference-data/instruments.js +67 -0
  36. package/src/simul/reference-data/isin-generator/convert-string-to-base-ten-number.js +2 -0
  37. package/src/simul/reference-data/isin-generator/fixtures/alphabet.js +27 -0
  38. package/src/simul/reference-data/isin-generator/fixtures/alphanumeric-values.js +7 -0
  39. package/src/simul/reference-data/isin-generator/fixtures/base-ten-numbers.js +13 -0
  40. package/src/simul/reference-data/isin-generator/generate-cusip-check-code.js +17 -0
  41. package/src/simul/reference-data/isin-generator/generate-cusip-without-check-code.js +8 -0
  42. package/src/simul/reference-data/isin-generator/generate-cusip.js +8 -0
  43. package/src/simul/reference-data/isin-generator/generate-random-alphanumeric.js +3 -0
  44. package/src/simul/reference-data/isin-generator/generate-random-base-ten-number.js +2 -0
  45. package/src/simul/reference-data/isin-generator/generate-random-string-of-alphanumeric-chars.js +7 -0
  46. package/src/simul/reference-data/isin-generator/generate-random-string-of-base-ten-chars.js +7 -0
  47. package/src/simul/reference-data/isin-generator/index.js +280 -0
  48. package/src/simul/reference-data/isin-generator/is-odd.js +2 -0
  49. package/src/simul/reference-data/locations.js +45 -0
  50. package/src/simul/reference-data/lotsizes.js +24 -0
  51. package/src/simul/reference-data/orderStatus.js +6 -0
  52. package/src/simul/reference-data/orders.js +64 -0
  53. package/src/simul/reference-data/parent-child-orders.js +117 -0
  54. package/src/simul/reference-data/priceStrategies.js +8 -0
  55. package/src/simul/reference-data/prices.js +78 -0
  56. package/src/simul/reference-data/sides.js +5 -0
  57. package/src/simul/simul-schemas.js +428 -0
  58. package/src/test/TestModule.js +95 -0
  59. package/src/test/index.js +1 -0
  60. package/src/test/test-schemas.js +74 -0
  61. package/src/vuu-row-generator.js +71 -0
package/package.json CHANGED
@@ -1,27 +1,26 @@
1
1
  {
2
- "version": "2.1.19-beta.1",
2
+ "version": "2.1.19-beta.2",
3
3
  "type": "module",
4
4
  "author": "heswell",
5
5
  "license": "Apache-2.0",
6
6
  "dependencies": {
7
- "@vuu-ui/vuu-data-local": "2.1.19-beta.1",
8
- "@vuu-ui/vuu-utils": "2.1.19-beta.1"
7
+ "@vuu-ui/vuu-data-local": "2.1.19-beta.2",
8
+ "@vuu-ui/vuu-utils": "2.1.19-beta.2"
9
9
  },
10
10
  "devDependencies": {
11
- "@vuu-ui/vuu-protocol-types": "2.1.19-beta.1",
12
- "@vuu-ui/vuu-data-types": "2.1.19-beta.1",
13
- "@vuu-ui/vuu-table-types": "2.1.19-beta.1"
11
+ "@vuu-ui/vuu-protocol-types": "2.1.19-beta.2",
12
+ "@vuu-ui/vuu-data-types": "2.1.19-beta.2",
13
+ "@vuu-ui/vuu-table-types": "2.1.19-beta.2"
14
14
  },
15
15
  "sideEffects": false,
16
16
  "files": [
17
17
  "README.md",
18
- "esm",
19
- "cjs",
18
+ "src",
20
19
  "/types"
21
20
  ],
22
21
  "exports": {
23
22
  ".": {
24
- "import": "./index.js",
23
+ "import": "./src/index.js",
25
24
  "types": "./types/index.d.ts"
26
25
  }
27
26
  },
@@ -0,0 +1,38 @@
1
+ class ArrayProxy {
2
+ #getItem;
3
+ length = 0;
4
+ constructor(size, getRow){
5
+ this.#getItem = getRow;
6
+ this.length = size;
7
+ const handler = {
8
+ get: (target, prop)=>{
9
+ if ("length" === prop) return target.length;
10
+ if ("slice" === prop) return target.slice;
11
+ if ("map" === prop) return target.map;
12
+ if ("toString" === prop) return "[ArrayProxy]";
13
+ if ("string" == typeof prop) {
14
+ const index = parseInt(prop, 10);
15
+ if (!isNaN(index)) if (index < this.length) return target.#getItem(index);
16
+ else return;
17
+ }
18
+ throw Error(`unsupported property ${String(prop)} on ArrayProxy`);
19
+ },
20
+ set: (target, prop, newVal)=>{
21
+ if ("length" === prop) {
22
+ target.length = newVal;
23
+ return true;
24
+ }
25
+ throw Error("ArrayProxy is immutable except for length");
26
+ }
27
+ };
28
+ return new Proxy(this, handler);
29
+ }
30
+ map = (func)=>new ArrayProxy(this.length, (i)=>func(this.#getItem(i), i));
31
+ slice = (from, to)=>{
32
+ const out = [];
33
+ const end = Math.min(this.length, to);
34
+ for(let i = from; i < end; i++)out.push(this.#getItem(i));
35
+ return out;
36
+ };
37
+ }
38
+ export { ArrayProxy };
@@ -0,0 +1,45 @@
1
+ import { buildColumnMap } from "@vuu-ui/vuu-utils";
2
+ class RuntimeVisualLink {
3
+ #childColumnName;
4
+ #childDataSource;
5
+ #parentColumnName;
6
+ #parentDataSource;
7
+ constructor(childDataSource, parentDataSource, childColumnName, parentColumnName){
8
+ this.#childColumnName = childColumnName;
9
+ this.#childDataSource = childDataSource;
10
+ this.#parentColumnName = parentColumnName;
11
+ this.#parentDataSource = parentDataSource;
12
+ parentDataSource.on("row-selection", this.handleParentSelectEvent);
13
+ }
14
+ destroy() {}
15
+ remove() {
16
+ this.#parentDataSource?.removeListener("row-selection", this.handleParentSelectEvent);
17
+ this.#childDataSource.baseFilter = {
18
+ filter: ""
19
+ };
20
+ }
21
+ handleParentSelectEvent = ()=>{
22
+ if (this.#childDataSource) {
23
+ const selectedValues = this.pickUniqueSelectedValues();
24
+ if (0 === selectedValues.length) this.#childDataSource.baseFilter = void 0;
25
+ else if (1 === selectedValues.length) this.#childDataSource.baseFilter = {
26
+ filter: `${this.#childColumnName} = "${selectedValues[0]}"`
27
+ };
28
+ else this.#childDataSource.baseFilter = {
29
+ filter: `${this.#childColumnName} in ["${selectedValues.join('","')}"]`
30
+ };
31
+ }
32
+ };
33
+ pickUniqueSelectedValues() {
34
+ const dataSource = this.#parentDataSource;
35
+ const map = buildColumnMap(dataSource.columns);
36
+ const colIndex = map[this.#parentColumnName];
37
+ const set = new Set();
38
+ for (const key of dataSource.getSelectedRowIds()){
39
+ const row = dataSource.getRowByKey(key);
40
+ if (row) set.add(row[colIndex]);
41
+ }
42
+ return Array.from(set);
43
+ }
44
+ }
45
+ export { RuntimeVisualLink };
@@ -0,0 +1,49 @@
1
+ import { EventEmitter } from "@vuu-ui/vuu-utils";
2
+ const isProxy = Symbol("proxy-session-table");
3
+ const isProxySessionTable = (table)=>table[isProxy];
4
+ const SessionTable = (table, sessionId)=>{
5
+ const updates = new Map();
6
+ const eventEmitter = new EventEmitter();
7
+ const getSessionUpdates = ()=>updates;
8
+ const addEventListener = (event, handler)=>{
9
+ eventEmitter.on(event, handler);
10
+ };
11
+ const update = (key, columnName, value)=>{
12
+ const row = table.findByKey(key);
13
+ if (row) {
14
+ const tsIndex = table.map.vuuUpdatedTimestamp;
15
+ let updatesForRow = updates.get(key);
16
+ if (void 0 === updatesForRow) {
17
+ updatesForRow = {
18
+ lastUpdateTimestamp: row[tsIndex],
19
+ cellUpdates: {}
20
+ };
21
+ updates.set(key, updatesForRow);
22
+ }
23
+ updatesForRow.cellUpdates[columnName] = value;
24
+ const newRow = row.slice();
25
+ for (const [columnName, value] of Object.entries(updatesForRow.cellUpdates)){
26
+ const colIndex = table.map[columnName];
27
+ newRow[colIndex] = value;
28
+ }
29
+ eventEmitter.emit("update", newRow, columnName, sessionId);
30
+ } else console.warn(`SessionTable update row ${key} not found`);
31
+ };
32
+ return new Proxy(table, {
33
+ get (_obj, prop) {
34
+ if ("symbol" == typeof prop) {
35
+ if (prop === isProxy) return true;
36
+ return;
37
+ }
38
+ if ("getSessionUpdates" === prop) return getSessionUpdates;
39
+ if ("on" === prop || "addEventListener" === prop) return addEventListener;
40
+ if ("update" === prop) return update;
41
+ if ("isProxy" === prop) return true;
42
+ return table[prop];
43
+ },
44
+ set () {
45
+ throw new TypeError("SessionTable is readonly");
46
+ }
47
+ });
48
+ };
49
+ export { SessionTable, isProxySessionTable };
package/src/Table.js ADDED
@@ -0,0 +1,96 @@
1
+ import { EventEmitter } from "@vuu-ui/vuu-utils";
2
+ class Table extends EventEmitter {
3
+ #data;
4
+ #dataMap;
5
+ #indexOfKey;
6
+ #index = new Map();
7
+ #schema;
8
+ constructor(schema, data, dataMap, updateGenerator){
9
+ super();
10
+ this.#data = data;
11
+ this.#dataMap = dataMap;
12
+ this.#schema = schema;
13
+ this.#indexOfKey = dataMap[schema.key];
14
+ this.buildIndex();
15
+ updateGenerator?.setTable(this);
16
+ updateGenerator?.setRange({
17
+ from: 0,
18
+ to: 100
19
+ });
20
+ }
21
+ buildIndex() {
22
+ for(let i = 0; i < this.#data.length; i++){
23
+ const key = this.#data[i][this.#indexOfKey];
24
+ this.#index.set(key, i);
25
+ }
26
+ }
27
+ get data() {
28
+ return this.#data;
29
+ }
30
+ get map() {
31
+ return this.#dataMap;
32
+ }
33
+ get schema() {
34
+ return this.#schema;
35
+ }
36
+ get name() {
37
+ return this.#schema.table.table;
38
+ }
39
+ delete(key, emitEvent = true) {
40
+ const index = this.#index.get(key) ?? -1;
41
+ if (-1 !== index) {
42
+ this.#index.delete(key);
43
+ this.#data.splice(index, 1);
44
+ for(let i = index; i < this.#data.length; i++)this.#index.set(this.#data[i][this.#indexOfKey], i);
45
+ if (emitEvent) this.emit("delete", key);
46
+ } else throw Error(`[Table] delete key ${key} not found`);
47
+ }
48
+ insert(row, emitEvent = true) {
49
+ const index = this.#data.length;
50
+ this.#data.push(row);
51
+ const key = row[this.#indexOfKey];
52
+ this.#index.set(key, index);
53
+ if (emitEvent) this.emit("insert", row);
54
+ }
55
+ findByKey(key) {
56
+ const index = this.#index.get(key) ?? -1;
57
+ return this.#data[index];
58
+ }
59
+ update(key, columnName, value) {
60
+ const rowIndex = this.#data.findIndex((row)=>row[this.#indexOfKey] === key);
61
+ const colIndex = this.#dataMap[columnName];
62
+ if (-1 !== rowIndex) {
63
+ const row = this.#data[rowIndex];
64
+ const newRow = row.slice();
65
+ newRow[colIndex] = value;
66
+ const tsIndex = this.#dataMap.vuuUpdatedTimestamp;
67
+ if ("number" == typeof tsIndex) {
68
+ const lastUpdated = Date.now();
69
+ newRow[tsIndex] = lastUpdated;
70
+ }
71
+ this.#data[rowIndex] = newRow;
72
+ this.emit("update", newRow, columnName);
73
+ }
74
+ }
75
+ updateRow(row) {
76
+ const key = row[this.#indexOfKey];
77
+ const rowIndex = this.#data.findIndex((row)=>row[this.#indexOfKey] === key);
78
+ if (-1 !== rowIndex) {
79
+ const tsIndex = this.#dataMap.vuuUpdatedTimestamp;
80
+ const lastUpdated = Date.now();
81
+ row[tsIndex] = lastUpdated;
82
+ this.#data[rowIndex] = row;
83
+ this.emit("update", row);
84
+ }
85
+ }
86
+ }
87
+ function buildDataColumnMapFromSchema(schema) {
88
+ return Object.values(schema.columns).reduce((map, col, index)=>({
89
+ ...map,
90
+ [col.name]: index
91
+ }), {});
92
+ }
93
+ function buildDataColumnMap(schemas, tableName) {
94
+ return buildDataColumnMapFromSchema(schemas[tableName]);
95
+ }
96
+ export { Table, buildDataColumnMap, buildDataColumnMapFromSchema };
@@ -0,0 +1,208 @@
1
+ import { ArrayDataSource } from "@vuu-ui/vuu-data-local";
2
+ import { isInlineEditingSession, isRpcSuccess, isTypeaheadRequest } from "@vuu-ui/vuu-utils";
3
+ import { makeSuggestions } from "./makeSuggestions.js";
4
+ class TickingArrayDataSource extends ArrayDataSource {
5
+ #menuRpcServices;
6
+ #pendingVisualLink;
7
+ #rpcMenuServices;
8
+ #rpcServices;
9
+ #sessionTables;
10
+ #sessionDataSource = void 0;
11
+ #table;
12
+ #selectionLinkSubscribers;
13
+ #visualLinkService;
14
+ #getVisualLinks;
15
+ #vuuModule;
16
+ constructor({ data, getVisualLinks, rpcServices, rpcMenuServices, sessionTables, table, menu, visualLink, visualLinkService, vuuModule, ...arrayDataSourceProps }){
17
+ if (void 0 === data && void 0 === table) throw Error("TickingArrayDataSource must be constructed with data");
18
+ super({
19
+ ...arrayDataSourceProps,
20
+ data: data ?? table?.data ?? [],
21
+ dataMap: table?.map
22
+ });
23
+ this._menu = menu;
24
+ this.#rpcMenuServices = rpcMenuServices;
25
+ this.#pendingVisualLink = visualLink;
26
+ this.#rpcServices = rpcServices;
27
+ this.#sessionTables = sessionTables;
28
+ this.#table = table;
29
+ this.#visualLinkService = visualLinkService;
30
+ this.#getVisualLinks = getVisualLinks;
31
+ this.#vuuModule = vuuModule;
32
+ if (table) {
33
+ this.tableSchema = table.schema;
34
+ table.on("insert", this.insert);
35
+ table.on("update", this.updateRowWithSessionCheck);
36
+ table.on("delete", this.deleteRow);
37
+ }
38
+ }
39
+ updateRowWithSessionCheck = (row, columnName, sessionId)=>{
40
+ if (sessionId && sessionId === this.viewport) this.updateRow(row, columnName);
41
+ else if (sessionId) console.warn("THIS IS NEVER EXPECTED TO HAPPEN");
42
+ else this.#sessionDataSource || this.updateRow(row, columnName);
43
+ };
44
+ async subscribe(subscribeProps, callback) {
45
+ const subscription = super.subscribe(subscribeProps, callback);
46
+ if (this.#pendingVisualLink) {
47
+ this.visualLink = this.#pendingVisualLink;
48
+ this.#pendingVisualLink = void 0;
49
+ }
50
+ return subscription;
51
+ }
52
+ unsubscribe() {
53
+ super.unsubscribe();
54
+ this.#table = void 0;
55
+ }
56
+ set range(range) {
57
+ super.range = range;
58
+ }
59
+ get range() {
60
+ return super.range;
61
+ }
62
+ set links(links) {
63
+ super.links = links;
64
+ }
65
+ get links() {
66
+ return this.#getVisualLinks?.(this.table.table);
67
+ }
68
+ getSelectedRowIds() {
69
+ return Array.from(this.selectedRows);
70
+ }
71
+ handleSessionMessage = (msg)=>{
72
+ if ("subscribed" === msg.type) ;
73
+ else if ("viewport-update" === msg.type) {
74
+ if (void 0 !== msg.size && msg.size !== this.size) this.emit("resize", msg.size);
75
+ this.clientCallback?.(msg);
76
+ }
77
+ };
78
+ createSessionDataSource(sessionTable) {
79
+ if (this.#vuuModule) return this.#vuuModule?.createDataSource(sessionTable.table, sessionTable.table);
80
+ throw Error("[TickingArrayDataSource] unable to createSessionDataSource, not constructed with VuuModule");
81
+ }
82
+ async beginEditSession(editSessionMode = "inline-all-rows") {
83
+ const rpcResponse = await this?.rpcRequest?.({
84
+ type: "RPC_REQUEST",
85
+ rpcName: "beginEditSession",
86
+ params: {
87
+ editSessionMode
88
+ }
89
+ });
90
+ if (isRpcSuccess(rpcResponse)) {
91
+ const { table: sessionTable } = rpcResponse.data;
92
+ if (!isInlineEditingSession(editSessionMode)) return this.#vuuModule?.createDataSource(sessionTable.table, sessionTable.table, this.config);
93
+ this.#sessionDataSource = this.#vuuModule?.createDataSource(sessionTable.table, sessionTable.table, this.config);
94
+ this.#sessionDataSource?.subscribe({
95
+ range: this.range
96
+ }, this.handleSessionMessage);
97
+ } else throw Error(`[VuuDataSource] beginEditSession ${rpcResponse.errorMessage}`);
98
+ }
99
+ async editCell(key, column, data) {
100
+ console.log(`[VuuDataSource] editCell ${this.#sessionDataSource?.viewport} rowKey ${key}, column ${column}, value ${data}`);
101
+ const rpcHost = this.#sessionDataSource ?? this;
102
+ return rpcHost.rpcRequest?.({
103
+ type: "RPC_REQUEST",
104
+ rpcName: "editCell",
105
+ params: {
106
+ column,
107
+ data,
108
+ key
109
+ }
110
+ });
111
+ }
112
+ async endEditSession(saveChanges = false) {
113
+ const type = "RPC_REQUEST";
114
+ const rpcName = "endEditSession";
115
+ const sessionDataSource = this.#sessionDataSource;
116
+ const rpcHost = sessionDataSource ?? this;
117
+ if (sessionDataSource) this.#sessionDataSource = void 0;
118
+ const rpcResponse = await rpcHost.rpcRequest?.(saveChanges ? {
119
+ type,
120
+ rpcName,
121
+ params: {
122
+ save: true
123
+ }
124
+ } : {
125
+ type,
126
+ rpcName,
127
+ params: {}
128
+ });
129
+ if (isRpcSuccess(rpcResponse)) {
130
+ sessionDataSource?.unsubscribe();
131
+ this.sendRowsToClient(true);
132
+ } else if (rpcResponse?.errorMessage === "stale update") {
133
+ sessionDataSource?.unsubscribe();
134
+ this.sendRowsToClient(true);
135
+ } else throw Error("unknown error");
136
+ }
137
+ async rpcRequest(rpcRequest) {
138
+ if (isTypeaheadRequest(rpcRequest)) {
139
+ const { params: { column, starts } } = rpcRequest;
140
+ const data = await this.getTypeaheadSuggestions(column, starts);
141
+ return {
142
+ type: "SUCCESS_RESULT",
143
+ data
144
+ };
145
+ }
146
+ {
147
+ const rpcService = this.#rpcServices?.find((service)=>service.rpcName === rpcRequest.rpcName);
148
+ if (rpcService) return rpcService.service({
149
+ ...rpcRequest,
150
+ context: {
151
+ type: "VIEWPORT_CONTEXT",
152
+ viewPortId: this.viewport
153
+ }
154
+ });
155
+ throw Error(`[TickingArrayDataSource] no service to handle RPC request ${rpcRequest.rpcName}`);
156
+ }
157
+ }
158
+ async menuRpcCall(rpcRequest) {
159
+ const rpcService = this.#rpcMenuServices?.find((service)=>service.rpcName === rpcRequest.rpcName);
160
+ if (rpcService) return rpcService.service({
161
+ ...rpcRequest,
162
+ vpId: this.viewport
163
+ });
164
+ throw Error(`[TickingArrayDataSource] menuRpcCall no service for ${rpcRequest.rpcName}`);
165
+ }
166
+ getTypeaheadSuggestions(column, pattern) {
167
+ if (this.#table) {
168
+ const columnIndex = this.columnMap[column];
169
+ if (void 0 !== columnIndex) return makeSuggestions(this.currentData, columnIndex, pattern);
170
+ console.warn(`[TickingArrayDataSource] getTypeaheadSuggestions. No column ${column}`);
171
+ return Promise.resolve([]);
172
+ }
173
+ throw Error("cannot call getTypeaheadSuggestions on TickingDataSource if table has not been provided");
174
+ }
175
+ get visualLink() {
176
+ return this._config.visualLink;
177
+ }
178
+ set visualLink(visualLink) {
179
+ this._config = {
180
+ ...this._config,
181
+ visualLink
182
+ };
183
+ if (visualLink) {
184
+ const { parentClientVpId, link: { fromColumn, toColumn } } = visualLink;
185
+ if (this.viewport) this.#visualLinkService?.({
186
+ childVpId: this.viewport,
187
+ childColumnName: fromColumn,
188
+ type: "CREATE_VISUAL_LINK",
189
+ parentVpId: parentClientVpId,
190
+ parentColumnName: toColumn
191
+ }).then((response)=>{
192
+ this.emit("visual-link-created", response);
193
+ });
194
+ } else this.#visualLinkService?.({
195
+ childVpId: this.viewport,
196
+ type: "REMOVE_VISUAL_LINK"
197
+ }).then(()=>{
198
+ this.emit("visual-link-removed");
199
+ });
200
+ }
201
+ freeze() {
202
+ super.freeze();
203
+ }
204
+ unfreeze() {
205
+ super.unfreeze();
206
+ }
207
+ }
208
+ export { TickingArrayDataSource };
@@ -0,0 +1,72 @@
1
+ import { generateNextBidAsk, nextRandomDouble, random } from "./data-utils.js";
2
+ const getNewValue = (value)=>{
3
+ const multiplier = random(0, 100) / 1000;
4
+ const direction = random(0, 10) >= 5 ? 1 : -1;
5
+ return value + value * multiplier * direction;
6
+ };
7
+ class BaseUpdateGenerator {
8
+ table;
9
+ range;
10
+ updating = false;
11
+ timer;
12
+ tickingColumns;
13
+ constructor(tickingColumns){
14
+ this.tickingColumns = tickingColumns;
15
+ }
16
+ setRange(range) {
17
+ this.range = range;
18
+ if (!this.updating && this.table) this.startUpdating();
19
+ }
20
+ setTable(table) {
21
+ this.table = table;
22
+ }
23
+ startUpdating() {
24
+ this.updating = true;
25
+ this.update();
26
+ }
27
+ stopUpdating() {
28
+ this.updating = false;
29
+ if (this.timer) {
30
+ window.clearTimeout(this.timer);
31
+ this.timer = void 0;
32
+ }
33
+ }
34
+ update = ()=>{
35
+ if (this.range && this.table) {
36
+ const data = this.table?.data;
37
+ const { bid, ask, last, ...rest } = this.tickingColumns;
38
+ if (data && data?.length > 0) {
39
+ const maxRange = Math.min(this.range.to, data.length);
40
+ for(let rowIndex = this.range.from; rowIndex < maxRange; rowIndex++){
41
+ let updateCount = 0;
42
+ const shallUpdateRow = random(0, 10) < 2;
43
+ if (shallUpdateRow) {
44
+ const rowUpdates = this.table.data[rowIndex];
45
+ const row = data[rowIndex];
46
+ if (void 0 !== bid && void 0 !== ask) {
47
+ const { [bid]: currentBid, [ask]: currentAsk } = row;
48
+ const [newBid, newAsk] = generateNextBidAsk(currentBid, currentAsk, 10, 5, nextRandomDouble);
49
+ rowUpdates[ask] = newAsk;
50
+ rowUpdates[bid] = newBid;
51
+ if (void 0 !== last) {
52
+ const newLast = Math.round((currentAsk + (newAsk - currentAsk) / 2) * 100) / 100.0;
53
+ rowUpdates[last] = newLast;
54
+ }
55
+ }
56
+ for (const colIdx of Object.values(rest)){
57
+ const shallUpdateColumn = random(0, 10) < 5;
58
+ if (shallUpdateColumn) {
59
+ updateCount += 1;
60
+ const newValue = getNewValue(row[colIdx]);
61
+ if (this.table) rowUpdates[colIdx] = newValue;
62
+ }
63
+ }
64
+ if (this.table && updateCount > 0) this.table.updateRow(rowUpdates);
65
+ }
66
+ }
67
+ }
68
+ }
69
+ if (this.updating) this.timer = window.setTimeout(this.update, 500);
70
+ };
71
+ }
72
+ export { BaseUpdateGenerator };