jspurefix 5.11.3 → 5.11.4

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 (100) hide show
  1. package/.gitattributes +4 -0
  2. package/dist/buffer/index.d.ts +6 -0
  3. package/dist/buffer/index.js +6 -0
  4. package/dist/buffer/index.js.map +1 -1
  5. package/dist/collections/index.d.ts +1 -0
  6. package/dist/collections/index.js +16 -0
  7. package/dist/collections/index.js.map +1 -1
  8. package/dist/dictionary/contained/index.d.ts +3 -0
  9. package/dist/dictionary/contained/index.js +3 -0
  10. package/dist/dictionary/contained/index.js.map +1 -1
  11. package/dist/dictionary/index.d.ts +5 -0
  12. package/dist/dictionary/index.js +5 -0
  13. package/dist/dictionary/index.js.map +1 -1
  14. package/dist/generator/applicability.d.ts +3 -0
  15. package/dist/generator/applicability.js +48 -0
  16. package/dist/generator/applicability.js.map +1 -0
  17. package/dist/generator/case-builder.d.ts +34 -0
  18. package/dist/generator/case-builder.js +111 -0
  19. package/dist/generator/case-builder.js.map +1 -0
  20. package/dist/generator/corpus-store.d.ts +43 -0
  21. package/dist/generator/corpus-store.js +115 -0
  22. package/dist/generator/corpus-store.js.map +1 -0
  23. package/dist/generator/index.d.ts +12 -0
  24. package/dist/generator/index.js +29 -0
  25. package/dist/generator/index.js.map +1 -0
  26. package/dist/generator/instrument-universe.d.ts +54 -0
  27. package/dist/generator/instrument-universe.js +286 -0
  28. package/dist/generator/instrument-universe.js.map +1 -0
  29. package/dist/generator/layout.d.ts +46 -0
  30. package/dist/generator/layout.js +208 -0
  31. package/dist/generator/layout.js.map +1 -0
  32. package/dist/generator/market-context.d.ts +64 -0
  33. package/dist/generator/market-context.js +119 -0
  34. package/dist/generator/market-context.js.map +1 -0
  35. package/dist/generator/outcome.d.ts +16 -0
  36. package/dist/generator/outcome.js +71 -0
  37. package/dist/generator/outcome.js.map +1 -0
  38. package/dist/generator/realistic-generator.d.ts +53 -0
  39. package/dist/generator/realistic-generator.js +275 -0
  40. package/dist/generator/realistic-generator.js.map +1 -0
  41. package/dist/generator/rng.d.ts +12 -0
  42. package/dist/generator/rng.js +60 -0
  43. package/dist/generator/rng.js.map +1 -0
  44. package/dist/generator/scatter.d.ts +50 -0
  45. package/dist/generator/scatter.js +285 -0
  46. package/dist/generator/scatter.js.map +1 -0
  47. package/dist/generator/scenarios.d.ts +13 -0
  48. package/dist/generator/scenarios.js +139 -0
  49. package/dist/generator/scenarios.js.map +1 -0
  50. package/dist/generator/value-conventions.d.ts +15 -0
  51. package/dist/generator/value-conventions.js +217 -0
  52. package/dist/generator/value-conventions.js.map +1 -0
  53. package/dist/index.d.ts +6 -0
  54. package/dist/index.js +4 -0
  55. package/dist/index.js.map +1 -1
  56. package/dist/jsfix-cmd.d.ts +5 -0
  57. package/dist/jsfix-cmd.js +161 -0
  58. package/dist/jsfix-cmd.js.map +1 -1
  59. package/dist/store/fix-msg-ascii-store-resend.js +2 -2
  60. package/dist/store/fix-msg-ascii-store-resend.js.map +1 -1
  61. package/dist/store/fix-msg-store-record.d.ts +1 -1
  62. package/dist/store/fix-msg-store-record.js.map +1 -1
  63. package/dist/store/index.d.ts +1 -0
  64. package/dist/store/index.js +1 -0
  65. package/dist/store/index.js.map +1 -1
  66. package/dist/transport/index.d.ts +7 -0
  67. package/dist/transport/index.js +7 -0
  68. package/dist/transport/index.js.map +1 -1
  69. package/dist/transport/session/index.d.ts +1 -0
  70. package/dist/transport/session/index.js +1 -0
  71. package/dist/transport/session/index.js.map +1 -1
  72. package/docs/generated-cases.md +237 -0
  73. package/docs/scattered-components.md +60 -5
  74. package/jsfix.test_client.txt +62 -62
  75. package/jsfix.test_server.txt +72 -72
  76. package/package.json +5 -2
  77. package/src/buffer/index.ts +6 -0
  78. package/src/collections/index.ts +1 -1
  79. package/src/dictionary/contained/index.ts +3 -0
  80. package/src/dictionary/index.ts +5 -0
  81. package/src/generator/applicability.ts +87 -0
  82. package/src/generator/case-builder.ts +167 -0
  83. package/src/generator/corpus-store.ts +166 -0
  84. package/src/generator/index.ts +12 -0
  85. package/src/generator/instrument-universe.ts +347 -0
  86. package/src/generator/layout.ts +279 -0
  87. package/src/generator/market-context.ts +207 -0
  88. package/src/generator/outcome.ts +102 -0
  89. package/src/generator/realistic-generator.ts +404 -0
  90. package/src/generator/rng.ts +92 -0
  91. package/src/generator/scatter.ts +432 -0
  92. package/src/generator/scenarios.ts +167 -0
  93. package/src/generator/value-conventions.ts +295 -0
  94. package/src/index.ts +12 -0
  95. package/src/jsfix-cmd.ts +204 -0
  96. package/src/store/fix-msg-ascii-store-resend.ts +2 -1
  97. package/src/store/fix-msg-store-record.ts +4 -1
  98. package/src/store/index.ts +1 -0
  99. package/src/transport/index.ts +10 -0
  100. package/src/transport/session/index.ts +1 -0
@@ -0,0 +1,54 @@
1
+ import { Rng } from './rng';
2
+ export declare enum AssetClass {
3
+ Equity = "equity",
4
+ Future = "future",
5
+ Option = "option",
6
+ Spread = "spread",
7
+ Fx = "fx",
8
+ Bond = "bond"
9
+ }
10
+ export interface ILegSpec {
11
+ readonly symbol: string;
12
+ readonly securityId: string;
13
+ readonly securityIdSource: string;
14
+ readonly securityType: string;
15
+ readonly maturityMonthYear?: string;
16
+ readonly side: string;
17
+ readonly ratio: number;
18
+ readonly refPx: number;
19
+ }
20
+ export interface IInstrumentSpec {
21
+ readonly name: string;
22
+ readonly assetClass: AssetClass;
23
+ readonly symbol: string;
24
+ readonly securityId: string;
25
+ readonly securityIdSource: string;
26
+ readonly securityExchange: string;
27
+ readonly securityType: string;
28
+ readonly cfiCode: string;
29
+ readonly currency: string;
30
+ readonly refPx: number;
31
+ readonly tick: number;
32
+ readonly lotSize: number;
33
+ readonly contractMultiplier?: number;
34
+ readonly maturityMonthYear?: string;
35
+ readonly maturityDate?: string;
36
+ readonly strikePrice?: number;
37
+ readonly putOrCall?: number;
38
+ readonly product?: number;
39
+ readonly legs?: readonly ILegSpec[];
40
+ }
41
+ declare function byClass(assetClass: AssetClass): readonly IInstrumentSpec[];
42
+ export declare const InstrumentUniverse: {
43
+ equities: readonly IInstrumentSpec[];
44
+ futures: readonly IInstrumentSpec[];
45
+ options: readonly IInstrumentSpec[];
46
+ fx: readonly IInstrumentSpec[];
47
+ bonds: readonly IInstrumentSpec[];
48
+ spreads: readonly IInstrumentSpec[];
49
+ all: readonly IInstrumentSpec[];
50
+ byClass: typeof byClass;
51
+ byName(name: string): IInstrumentSpec | undefined;
52
+ choose(rng: Rng, assetClass?: AssetClass): IInstrumentSpec;
53
+ };
54
+ export {};
@@ -0,0 +1,286 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.InstrumentUniverse = exports.AssetClass = void 0;
4
+ var AssetClass;
5
+ (function (AssetClass) {
6
+ AssetClass["Equity"] = "equity";
7
+ AssetClass["Future"] = "future";
8
+ AssetClass["Option"] = "option";
9
+ AssetClass["Spread"] = "spread";
10
+ AssetClass["Fx"] = "fx";
11
+ AssetClass["Bond"] = "bond";
12
+ })(AssetClass || (exports.AssetClass = AssetClass = {}));
13
+ const equities = [
14
+ {
15
+ name: 'Apple Inc',
16
+ assetClass: AssetClass.Equity,
17
+ symbol: 'AAPL',
18
+ securityId: 'US0378331005',
19
+ securityIdSource: '4',
20
+ securityExchange: 'XNAS',
21
+ securityType: 'CS',
22
+ cfiCode: 'ESVUFR',
23
+ currency: 'USD',
24
+ refPx: 214.5,
25
+ tick: 0.01,
26
+ lotSize: 100,
27
+ product: 5
28
+ },
29
+ {
30
+ name: 'Vodafone Group',
31
+ assetClass: AssetClass.Equity,
32
+ symbol: 'VOD.L',
33
+ securityId: 'GB00BH4HKS39',
34
+ securityIdSource: '4',
35
+ securityExchange: 'XLON',
36
+ securityType: 'CS',
37
+ cfiCode: 'ESVUFR',
38
+ currency: 'GBP',
39
+ refPx: 0.762,
40
+ tick: 0.0001,
41
+ lotSize: 1000,
42
+ product: 5
43
+ },
44
+ {
45
+ name: 'SAP SE',
46
+ assetClass: AssetClass.Equity,
47
+ symbol: 'SAP',
48
+ securityId: 'DE0007164600',
49
+ securityIdSource: '4',
50
+ securityExchange: 'XETR',
51
+ securityType: 'CS',
52
+ cfiCode: 'ESVUFR',
53
+ currency: 'EUR',
54
+ refPx: 196.3,
55
+ tick: 0.01,
56
+ lotSize: 100,
57
+ product: 5
58
+ }
59
+ ];
60
+ const futures = [
61
+ {
62
+ name: 'ICE Brent Crude Jan26',
63
+ assetClass: AssetClass.Future,
64
+ symbol: 'BRN',
65
+ securityId: 'BRN FMF0026!',
66
+ securityIdSource: '8',
67
+ securityExchange: 'IFEU',
68
+ securityType: 'FUT',
69
+ cfiCode: 'FCEPSX',
70
+ currency: 'USD',
71
+ refPx: 71.35,
72
+ tick: 0.01,
73
+ lotSize: 1,
74
+ contractMultiplier: 1000,
75
+ maturityMonthYear: '202601',
76
+ maturityDate: '20251130',
77
+ product: 2
78
+ },
79
+ {
80
+ name: 'ICE Low Sulphur Gasoil Feb26',
81
+ assetClass: AssetClass.Future,
82
+ symbol: 'GAS',
83
+ securityId: 'GAS FMG0026!',
84
+ securityIdSource: '8',
85
+ securityExchange: 'IFEU',
86
+ securityType: 'FUT',
87
+ cfiCode: 'FCEPSX',
88
+ currency: 'USD',
89
+ refPx: 668.25,
90
+ tick: 0.25,
91
+ lotSize: 1,
92
+ contractMultiplier: 100,
93
+ maturityMonthYear: '202602',
94
+ maturityDate: '20260112',
95
+ product: 2
96
+ },
97
+ {
98
+ name: 'CME E-mini S and P 500 Dec25',
99
+ assetClass: AssetClass.Future,
100
+ symbol: 'ES',
101
+ securityId: 'ESZ5',
102
+ securityIdSource: '8',
103
+ securityExchange: 'XCME',
104
+ securityType: 'FUT',
105
+ cfiCode: 'FFICSX',
106
+ currency: 'USD',
107
+ refPx: 6042.25,
108
+ tick: 0.25,
109
+ lotSize: 1,
110
+ contractMultiplier: 50,
111
+ maturityMonthYear: '202512',
112
+ maturityDate: '20251219',
113
+ product: 5
114
+ }
115
+ ];
116
+ const options = [
117
+ {
118
+ name: 'CME E-mini Dec25 6000 Call',
119
+ assetClass: AssetClass.Option,
120
+ symbol: 'ES',
121
+ securityId: 'ESZ5 C6000',
122
+ securityIdSource: '8',
123
+ securityExchange: 'XCME',
124
+ securityType: 'OPT',
125
+ cfiCode: 'OCEFCS',
126
+ currency: 'USD',
127
+ refPx: 118.75,
128
+ tick: 0.25,
129
+ lotSize: 1,
130
+ contractMultiplier: 50,
131
+ maturityMonthYear: '202512',
132
+ maturityDate: '20251219',
133
+ strikePrice: 6000,
134
+ putOrCall: 1,
135
+ product: 5
136
+ }
137
+ ];
138
+ const fx = [
139
+ {
140
+ name: 'EUR/USD spot',
141
+ assetClass: AssetClass.Fx,
142
+ symbol: 'EUR/USD',
143
+ securityId: 'EURUSD',
144
+ securityIdSource: '8',
145
+ securityExchange: 'XOFF',
146
+ securityType: 'FXSPOT',
147
+ cfiCode: 'MRCXXX',
148
+ currency: 'EUR',
149
+ refPx: 1.0842,
150
+ tick: 0.00005,
151
+ lotSize: 1000000,
152
+ product: 4
153
+ }
154
+ ];
155
+ const bonds = [
156
+ {
157
+ name: 'US Treasury 4.25 Nov 2034',
158
+ assetClass: AssetClass.Bond,
159
+ symbol: 'T 4.25 11/34',
160
+ securityId: 'US91282CLW12',
161
+ securityIdSource: '4',
162
+ securityExchange: 'XOFF',
163
+ securityType: 'TBOND',
164
+ cfiCode: 'DBFUFR',
165
+ currency: 'USD',
166
+ refPx: 99.421875,
167
+ tick: 0.015625,
168
+ lotSize: 1000,
169
+ maturityDate: '20341115',
170
+ product: 6
171
+ }
172
+ ];
173
+ const spreads = [
174
+ {
175
+ name: 'ICE Brent Jan26/Feb26 calendar spread',
176
+ assetClass: AssetClass.Spread,
177
+ symbol: 'BRN',
178
+ securityId: 'BRN JAN26-FEB26',
179
+ securityIdSource: '8',
180
+ securityExchange: 'IFEU',
181
+ securityType: 'MLEG',
182
+ cfiCode: 'FMEPSX',
183
+ currency: 'USD',
184
+ refPx: 0.34,
185
+ tick: 0.01,
186
+ lotSize: 1,
187
+ contractMultiplier: 1000,
188
+ maturityMonthYear: '202601',
189
+ product: 2,
190
+ legs: [
191
+ {
192
+ symbol: 'BRN',
193
+ securityId: 'BRN FMF0026!',
194
+ securityIdSource: '8',
195
+ securityType: 'FUT',
196
+ maturityMonthYear: '202601',
197
+ side: '1',
198
+ ratio: 1,
199
+ refPx: 71.35
200
+ },
201
+ {
202
+ symbol: 'BRN',
203
+ securityId: 'BRN FMG0026!',
204
+ securityIdSource: '8',
205
+ securityType: 'FUT',
206
+ maturityMonthYear: '202602',
207
+ side: '2',
208
+ ratio: 1,
209
+ refPx: 71.01
210
+ }
211
+ ]
212
+ },
213
+ {
214
+ name: 'ICE Brent/Gasoil crack spread',
215
+ assetClass: AssetClass.Spread,
216
+ symbol: 'BRNGAS',
217
+ securityId: 'BRN-GAS CRACK',
218
+ securityIdSource: '8',
219
+ securityExchange: 'IFEU',
220
+ securityType: 'MLEG',
221
+ cfiCode: 'FMEPSX',
222
+ currency: 'USD',
223
+ refPx: 12.68,
224
+ tick: 0.01,
225
+ lotSize: 1,
226
+ contractMultiplier: 1000,
227
+ maturityMonthYear: '202602',
228
+ product: 2,
229
+ legs: [
230
+ {
231
+ symbol: 'GAS',
232
+ securityId: 'GAS FMG0026!',
233
+ securityIdSource: '8',
234
+ securityType: 'FUT',
235
+ maturityMonthYear: '202602',
236
+ side: '1',
237
+ ratio: 1,
238
+ refPx: 668.25
239
+ },
240
+ {
241
+ symbol: 'BRN',
242
+ securityId: 'BRN FMG0026!',
243
+ securityIdSource: '8',
244
+ securityType: 'FUT',
245
+ maturityMonthYear: '202602',
246
+ side: '2',
247
+ ratio: 1,
248
+ refPx: 71.2
249
+ }
250
+ ]
251
+ }
252
+ ];
253
+ function byClass(assetClass) {
254
+ switch (assetClass) {
255
+ case AssetClass.Equity: return equities;
256
+ case AssetClass.Future: return futures;
257
+ case AssetClass.Option: return options;
258
+ case AssetClass.Fx: return fx;
259
+ case AssetClass.Bond: return bonds;
260
+ case AssetClass.Spread: return spreads;
261
+ default: return equities;
262
+ }
263
+ }
264
+ const all = [
265
+ ...equities, ...futures, ...options, ...fx, ...bonds, ...spreads
266
+ ];
267
+ exports.InstrumentUniverse = {
268
+ equities,
269
+ futures,
270
+ options,
271
+ fx,
272
+ bonds,
273
+ spreads,
274
+ all,
275
+ byClass,
276
+ byName(name) {
277
+ const lower = name.toLowerCase();
278
+ return all.find(i => i.symbol.toLowerCase() === lower ||
279
+ i.securityId.toLowerCase() === lower ||
280
+ i.name.toLowerCase() === lower);
281
+ },
282
+ choose(rng, assetClass) {
283
+ return rng.pick(assetClass ? byClass(assetClass) : all);
284
+ }
285
+ };
286
+ //# sourceMappingURL=instrument-universe.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"instrument-universe.js","sourceRoot":"","sources":["../../src/generator/instrument-universe.ts"],"names":[],"mappings":"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","sourcesContent":["import { Rng } from './rng'\n\n/**\n * A small book of instruments that read like instruments.\n *\n * The point is not coverage - it is that a generated message can be scanned by eye and\n * recognised. `55=BRN` with `541=20251231` and `44=71.35` is a Brent future at a\n * plausible price; `55=Lorem` with `44=-4534.7` is noise that happens to encode.\n *\n * Prices carry a tick and a lot size so quantities and prices agree with the contract\n * they claim to be, and a spread carries its legs so a multileg message can be built\n * with parent and legs that actually correspond.\n */\n\nexport enum AssetClass {\n Equity = 'equity',\n Future = 'future',\n Option = 'option',\n Spread = 'spread',\n Fx = 'fx',\n Bond = 'bond'\n}\n\nexport interface ILegSpec {\n readonly symbol: string\n readonly securityId: string\n readonly securityIdSource: string\n readonly securityType: string\n readonly maturityMonthYear?: string\n readonly side: string\n readonly ratio: number\n readonly refPx: number\n}\n\nexport interface IInstrumentSpec {\n readonly name: string\n readonly assetClass: AssetClass\n readonly symbol: string\n readonly securityId: string\n /** 1 CUSIP, 2 SEDOL, 4 ISIN, 8 exchange symbol, 9 CTA */\n readonly securityIdSource: string\n readonly securityExchange: string\n readonly securityType: string\n readonly cfiCode: string\n readonly currency: string\n readonly refPx: number\n readonly tick: number\n readonly lotSize: number\n readonly contractMultiplier?: number\n readonly maturityMonthYear?: string\n readonly maturityDate?: string\n readonly strikePrice?: number\n readonly putOrCall?: number\n readonly product?: number\n readonly legs?: readonly ILegSpec[]\n}\n\nconst equities: readonly IInstrumentSpec[] = [\n {\n name: 'Apple Inc',\n assetClass: AssetClass.Equity,\n symbol: 'AAPL',\n securityId: 'US0378331005',\n securityIdSource: '4',\n securityExchange: 'XNAS',\n securityType: 'CS',\n cfiCode: 'ESVUFR',\n currency: 'USD',\n refPx: 214.5,\n tick: 0.01,\n lotSize: 100,\n product: 5\n },\n {\n name: 'Vodafone Group',\n assetClass: AssetClass.Equity,\n symbol: 'VOD.L',\n securityId: 'GB00BH4HKS39',\n securityIdSource: '4',\n securityExchange: 'XLON',\n securityType: 'CS',\n cfiCode: 'ESVUFR',\n currency: 'GBP',\n refPx: 0.762,\n tick: 0.0001,\n lotSize: 1000,\n product: 5\n },\n {\n name: 'SAP SE',\n assetClass: AssetClass.Equity,\n symbol: 'SAP',\n securityId: 'DE0007164600',\n securityIdSource: '4',\n securityExchange: 'XETR',\n securityType: 'CS',\n cfiCode: 'ESVUFR',\n currency: 'EUR',\n refPx: 196.3,\n tick: 0.01,\n lotSize: 100,\n product: 5\n }\n]\n\nconst futures: readonly IInstrumentSpec[] = [\n {\n name: 'ICE Brent Crude Jan26',\n assetClass: AssetClass.Future,\n symbol: 'BRN',\n securityId: 'BRN FMF0026!',\n securityIdSource: '8',\n securityExchange: 'IFEU',\n securityType: 'FUT',\n cfiCode: 'FCEPSX',\n currency: 'USD',\n refPx: 71.35,\n tick: 0.01,\n lotSize: 1,\n contractMultiplier: 1000,\n maturityMonthYear: '202601',\n maturityDate: '20251130',\n product: 2\n },\n {\n name: 'ICE Low Sulphur Gasoil Feb26',\n assetClass: AssetClass.Future,\n symbol: 'GAS',\n securityId: 'GAS FMG0026!',\n securityIdSource: '8',\n securityExchange: 'IFEU',\n securityType: 'FUT',\n cfiCode: 'FCEPSX',\n currency: 'USD',\n refPx: 668.25,\n tick: 0.25,\n lotSize: 1,\n contractMultiplier: 100,\n maturityMonthYear: '202602',\n maturityDate: '20260112',\n product: 2\n },\n {\n name: 'CME E-mini S and P 500 Dec25',\n assetClass: AssetClass.Future,\n symbol: 'ES',\n securityId: 'ESZ5',\n securityIdSource: '8',\n securityExchange: 'XCME',\n securityType: 'FUT',\n cfiCode: 'FFICSX',\n currency: 'USD',\n refPx: 6042.25,\n tick: 0.25,\n lotSize: 1,\n contractMultiplier: 50,\n maturityMonthYear: '202512',\n maturityDate: '20251219',\n product: 5\n }\n]\n\nconst options: readonly IInstrumentSpec[] = [\n {\n name: 'CME E-mini Dec25 6000 Call',\n assetClass: AssetClass.Option,\n symbol: 'ES',\n securityId: 'ESZ5 C6000',\n securityIdSource: '8',\n securityExchange: 'XCME',\n securityType: 'OPT',\n cfiCode: 'OCEFCS',\n currency: 'USD',\n refPx: 118.75,\n tick: 0.25,\n lotSize: 1,\n contractMultiplier: 50,\n maturityMonthYear: '202512',\n maturityDate: '20251219',\n strikePrice: 6000,\n putOrCall: 1,\n product: 5\n }\n]\n\nconst fx: readonly IInstrumentSpec[] = [\n {\n name: 'EUR/USD spot',\n assetClass: AssetClass.Fx,\n symbol: 'EUR/USD',\n securityId: 'EURUSD',\n securityIdSource: '8',\n securityExchange: 'XOFF',\n securityType: 'FXSPOT',\n cfiCode: 'MRCXXX',\n currency: 'EUR',\n refPx: 1.0842,\n tick: 0.00005,\n lotSize: 1000000,\n product: 4\n }\n]\n\nconst bonds: readonly IInstrumentSpec[] = [\n {\n name: 'US Treasury 4.25 Nov 2034',\n assetClass: AssetClass.Bond,\n symbol: 'T 4.25 11/34',\n securityId: 'US91282CLW12',\n securityIdSource: '4',\n securityExchange: 'XOFF',\n securityType: 'TBOND',\n cfiCode: 'DBFUFR',\n currency: 'USD',\n refPx: 99.421875,\n tick: 0.015625,\n lotSize: 1000,\n maturityDate: '20341115',\n product: 6\n }\n]\n\n/**\n * The shape the whole scattered component exercise is really about. ICE publishes\n * calendar and crack spreads as single tradeable instruments whose fills report a parent\n * and one leg per contract, and a trade capture for one of these is where deep nesting\n * shows up in real life.\n */\nconst spreads: readonly IInstrumentSpec[] = [\n {\n name: 'ICE Brent Jan26/Feb26 calendar spread',\n assetClass: AssetClass.Spread,\n symbol: 'BRN',\n securityId: 'BRN JAN26-FEB26',\n securityIdSource: '8',\n securityExchange: 'IFEU',\n securityType: 'MLEG',\n cfiCode: 'FMEPSX',\n currency: 'USD',\n refPx: 0.34,\n tick: 0.01,\n lotSize: 1,\n contractMultiplier: 1000,\n maturityMonthYear: '202601',\n product: 2,\n legs: [\n {\n symbol: 'BRN',\n securityId: 'BRN FMF0026!',\n securityIdSource: '8',\n securityType: 'FUT',\n maturityMonthYear: '202601',\n side: '1',\n ratio: 1,\n refPx: 71.35\n },\n {\n symbol: 'BRN',\n securityId: 'BRN FMG0026!',\n securityIdSource: '8',\n securityType: 'FUT',\n maturityMonthYear: '202602',\n side: '2',\n ratio: 1,\n refPx: 71.01\n }\n ]\n },\n {\n name: 'ICE Brent/Gasoil crack spread',\n assetClass: AssetClass.Spread,\n symbol: 'BRNGAS',\n securityId: 'BRN-GAS CRACK',\n securityIdSource: '8',\n securityExchange: 'IFEU',\n securityType: 'MLEG',\n cfiCode: 'FMEPSX',\n currency: 'USD',\n refPx: 12.68,\n tick: 0.01,\n lotSize: 1,\n contractMultiplier: 1000,\n maturityMonthYear: '202602',\n product: 2,\n legs: [\n {\n symbol: 'GAS',\n securityId: 'GAS FMG0026!',\n securityIdSource: '8',\n securityType: 'FUT',\n maturityMonthYear: '202602',\n side: '1',\n ratio: 1,\n refPx: 668.25\n },\n {\n symbol: 'BRN',\n securityId: 'BRN FMG0026!',\n securityIdSource: '8',\n securityType: 'FUT',\n maturityMonthYear: '202602',\n side: '2',\n ratio: 1,\n refPx: 71.2\n }\n ]\n }\n]\n\nfunction byClass (assetClass: AssetClass): readonly IInstrumentSpec[] {\n switch (assetClass) {\n case AssetClass.Equity: return equities\n case AssetClass.Future: return futures\n case AssetClass.Option: return options\n case AssetClass.Fx: return fx\n case AssetClass.Bond: return bonds\n case AssetClass.Spread: return spreads\n default: return equities\n }\n}\n\nconst all: readonly IInstrumentSpec[] = [\n ...equities, ...futures, ...options, ...fx, ...bonds, ...spreads\n]\n\nexport const InstrumentUniverse = {\n equities,\n futures,\n options,\n fx,\n bonds,\n spreads,\n all,\n byClass,\n\n byName (name: string): IInstrumentSpec | undefined {\n const lower = name.toLowerCase()\n return all.find(i =>\n i.symbol.toLowerCase() === lower ||\n i.securityId.toLowerCase() === lower ||\n i.name.toLowerCase() === lower)\n },\n\n choose (rng: Rng, assetClass?: AssetClass): IInstrumentSpec {\n return rng.pick(assetClass ? byClass(assetClass) : all)\n }\n}\n"]}
@@ -0,0 +1,46 @@
1
+ import { ILooseObject } from '../collections/collection';
2
+ import { IContainedSet } from '../dictionary/contained';
3
+ export interface IToken {
4
+ readonly tag: number;
5
+ readonly text: string;
6
+ }
7
+ export declare enum LayoutKind {
8
+ Message = "message",
9
+ Component = "component",
10
+ Group = "group",
11
+ Instance = "instance",
12
+ Field = "field"
13
+ }
14
+ export declare class LayoutNode {
15
+ readonly kind: LayoutKind;
16
+ readonly name: string;
17
+ readonly path: string;
18
+ readonly tokenIndex: number;
19
+ readonly set: IContainedSet | null;
20
+ readonly extraTokenIndex: number;
21
+ readonly children: LayoutNode[];
22
+ constructor(kind: LayoutKind, name: string, path: string, tokenIndex?: number, set?: IContainedSet | null, extraTokenIndex?: number);
23
+ canonical(into?: number[]): number[];
24
+ get isLevel(): boolean;
25
+ }
26
+ export declare function tokenise(wire: string, delimiter: string): IToken[];
27
+ export declare function assemble(tokens: readonly IToken[], order: readonly number[], delimiter: string): string;
28
+ export interface ILayout {
29
+ readonly root: LayoutNode;
30
+ readonly tokens: readonly IToken[];
31
+ readonly bodyStart: number;
32
+ readonly bodyEnd: number;
33
+ }
34
+ export declare class Layout {
35
+ private index;
36
+ private constructor();
37
+ static build(wire: string, delimiter: string, object: ILooseObject, set: IContainedSet): ILayout;
38
+ private static expectedTags;
39
+ private static locate;
40
+ private static presentFields;
41
+ private static instancesOf;
42
+ private static lengthField;
43
+ private static lengthName;
44
+ private static lengthTag;
45
+ private walk;
46
+ }
@@ -0,0 +1,208 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.Layout = exports.LayoutNode = exports.LayoutKind = void 0;
4
+ exports.tokenise = tokenise;
5
+ exports.assemble = assemble;
6
+ const contained_1 = require("../dictionary/contained");
7
+ const tag_type_1 = require("../buffer/tag/tag-type");
8
+ var LayoutKind;
9
+ (function (LayoutKind) {
10
+ LayoutKind["Message"] = "message";
11
+ LayoutKind["Component"] = "component";
12
+ LayoutKind["Group"] = "group";
13
+ LayoutKind["Instance"] = "instance";
14
+ LayoutKind["Field"] = "field";
15
+ })(LayoutKind || (exports.LayoutKind = LayoutKind = {}));
16
+ class LayoutNode {
17
+ constructor(kind, name, path, tokenIndex = -1, set = null, extraTokenIndex = -1) {
18
+ this.kind = kind;
19
+ this.name = name;
20
+ this.path = path;
21
+ this.tokenIndex = tokenIndex;
22
+ this.set = set;
23
+ this.extraTokenIndex = extraTokenIndex;
24
+ this.children = [];
25
+ }
26
+ canonical(into = []) {
27
+ if (this.tokenIndex >= 0)
28
+ into.push(this.tokenIndex);
29
+ if (this.extraTokenIndex >= 0)
30
+ into.push(this.extraTokenIndex);
31
+ for (const c of this.children) {
32
+ c.canonical(into);
33
+ }
34
+ return into;
35
+ }
36
+ get isLevel() {
37
+ return this.kind === LayoutKind.Message || this.kind === LayoutKind.Instance;
38
+ }
39
+ }
40
+ exports.LayoutNode = LayoutNode;
41
+ function tokenise(wire, delimiter) {
42
+ const parts = wire.split(delimiter);
43
+ const tokens = [];
44
+ for (const p of parts) {
45
+ if (p.length === 0)
46
+ continue;
47
+ const eq = p.indexOf('=');
48
+ if (eq <= 0)
49
+ continue;
50
+ tokens.push({ tag: parseInt(p.substring(0, eq), 10), text: p });
51
+ }
52
+ return tokens;
53
+ }
54
+ function assemble(tokens, order, delimiter) {
55
+ let out = '';
56
+ for (const i of order) {
57
+ out += tokens[i].text;
58
+ out += delimiter;
59
+ }
60
+ return out;
61
+ }
62
+ class Layout {
63
+ constructor(start) {
64
+ this.index = 0;
65
+ this.index = start;
66
+ }
67
+ static build(wire, delimiter, object, set) {
68
+ const tokens = tokenise(wire, delimiter);
69
+ const expected = Layout.expectedTags(object, set);
70
+ const bodyStart = Layout.locate(tokens, expected);
71
+ const builder = new Layout(bodyStart);
72
+ const root = new LayoutNode(LayoutKind.Message, set.name, set.name, -1, set);
73
+ builder.walk(object, set, root, set.name);
74
+ return {
75
+ root,
76
+ tokens,
77
+ bodyStart,
78
+ bodyEnd: builder.index
79
+ };
80
+ }
81
+ static expectedTags(object, set) {
82
+ const out = [];
83
+ const collect = (o, s) => {
84
+ for (const field of Layout.presentFields(o, s)) {
85
+ switch (field.type) {
86
+ case contained_1.ContainedFieldType.Simple: {
87
+ const sf = field;
88
+ if (sf.definition.tagType === tag_type_1.TagType.RawData && o[Layout.lengthName(s, sf)] == null) {
89
+ out.push(Layout.lengthTag(s, sf));
90
+ }
91
+ out.push(sf.definition.tag);
92
+ break;
93
+ }
94
+ case contained_1.ContainedFieldType.Component: {
95
+ const cf = field;
96
+ collect(o[cf.name], cf.definition);
97
+ break;
98
+ }
99
+ case contained_1.ContainedFieldType.Group: {
100
+ const gf = field;
101
+ const nof = gf.definition.noOfField;
102
+ if (!nof)
103
+ break;
104
+ out.push(nof.tag);
105
+ const instances = Layout.instancesOf(o, gf);
106
+ for (const instance of instances) {
107
+ collect(instance, gf.definition);
108
+ }
109
+ break;
110
+ }
111
+ default:
112
+ break;
113
+ }
114
+ }
115
+ };
116
+ collect(object, set);
117
+ return out;
118
+ }
119
+ static locate(tokens, expected) {
120
+ if (expected.length === 0)
121
+ return 0;
122
+ for (let start = 0; start + expected.length <= tokens.length; ++start) {
123
+ let ok = true;
124
+ for (let i = 0; i < expected.length; ++i) {
125
+ if (tokens[start + i].tag !== expected[i]) {
126
+ ok = false;
127
+ break;
128
+ }
129
+ }
130
+ if (ok)
131
+ return start;
132
+ }
133
+ throw new Error('layout walk does not match the encoded message - the mirror of AsciiEncoder has drifted');
134
+ }
135
+ static presentFields(o, set) {
136
+ const fields = [];
137
+ for (const key of Object.keys(o)) {
138
+ const field = set.localNameToField.get(key);
139
+ if (field)
140
+ fields.push(field);
141
+ }
142
+ fields.sort((a, b) => a.position - b.position);
143
+ return fields;
144
+ }
145
+ static instancesOf(o, gf) {
146
+ var _a;
147
+ const nof = gf.definition.noOfField;
148
+ const instances = (_a = o[gf.name]) !== null && _a !== void 0 ? _a : (nof ? o[nof.name] : null);
149
+ return Array.isArray(instances) ? instances : [];
150
+ }
151
+ static lengthField(set, sf) {
152
+ const prior = set.fields[sf.position - 1];
153
+ if (!prior || prior.type !== contained_1.ContainedFieldType.Simple)
154
+ return null;
155
+ return prior;
156
+ }
157
+ static lengthName(set, sf) {
158
+ var _a, _b;
159
+ return (_b = (_a = Layout.lengthField(set, sf)) === null || _a === void 0 ? void 0 : _a.name) !== null && _b !== void 0 ? _b : '';
160
+ }
161
+ static lengthTag(set, sf) {
162
+ var _a, _b;
163
+ return (_b = (_a = Layout.lengthField(set, sf)) === null || _a === void 0 ? void 0 : _a.definition.tag) !== null && _b !== void 0 ? _b : 0;
164
+ }
165
+ walk(o, set, parent, path) {
166
+ for (const field of Layout.presentFields(o, set)) {
167
+ switch (field.type) {
168
+ case contained_1.ContainedFieldType.Simple: {
169
+ const sf = field;
170
+ let lengthIndex = -1;
171
+ if (sf.definition.tagType === tag_type_1.TagType.RawData && o[Layout.lengthName(set, sf)] == null) {
172
+ lengthIndex = this.index++;
173
+ }
174
+ const dataIndex = this.index++;
175
+ parent.children.push(new LayoutNode(LayoutKind.Field, sf.name, `${path}.${sf.name}`, lengthIndex >= 0 ? lengthIndex : dataIndex, null, lengthIndex >= 0 ? dataIndex : -1));
176
+ break;
177
+ }
178
+ case contained_1.ContainedFieldType.Component: {
179
+ const cf = field;
180
+ const node = new LayoutNode(LayoutKind.Component, cf.name, `${path}.${cf.name}`, -1, cf.definition);
181
+ parent.children.push(node);
182
+ this.walk(o[cf.name], cf.definition, node, node.path);
183
+ break;
184
+ }
185
+ case contained_1.ContainedFieldType.Group: {
186
+ const gf = field;
187
+ const nof = gf.definition.noOfField;
188
+ if (!nof)
189
+ break;
190
+ const countIndex = this.index++;
191
+ const node = new LayoutNode(LayoutKind.Group, gf.name, `${path}.${gf.name}`, countIndex, gf.definition);
192
+ parent.children.push(node);
193
+ const instances = Layout.instancesOf(o, gf);
194
+ for (let i = 0; i < instances.length; ++i) {
195
+ const instance = new LayoutNode(LayoutKind.Instance, `${gf.name}[${i}]`, `${node.path}[${i}]`, -1, gf.definition);
196
+ node.children.push(instance);
197
+ this.walk(instances[i], gf.definition, instance, instance.path);
198
+ }
199
+ break;
200
+ }
201
+ default:
202
+ break;
203
+ }
204
+ }
205
+ }
206
+ }
207
+ exports.Layout = Layout;
208
+ //# sourceMappingURL=layout.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"layout.js","sourceRoot":"","sources":["../../src/generator/layout.ts"],"names":[],"mappings":"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","sourcesContent":["import { ILooseObject } from '../collections/collection'\nimport {\n ContainedComponentField,\n ContainedField,\n ContainedFieldType,\n ContainedGroupField,\n ContainedSimpleField,\n IContainedSet\n} from '../dictionary/contained'\nimport { TagType } from '../buffer/tag/tag-type'\n\n/**\n * Where every tag on the wire came from in the dictionary.\n *\n * The parser answers this question from position, which is exactly the assumption the\n * scattered component work is about, so it cannot be the source of truth here. Instead\n * the layout is built by walking the object and the dictionary in lock step with\n * `AsciiEncoder.encodeObject` - same field ordering, same treatment of components,\n * groups and raw data - and consuming one token per emission. The walk is not a parse:\n * it knows what the encoder was about to write before it wrote it.\n *\n * If the two ever disagree the token stream will not line up and `Layout.build` throws,\n * which makes this a standing check that the mirror is still faithful.\n */\n\nexport interface IToken {\n readonly tag: number\n /** the `tag=value` text exactly as encoded, without the delimiter */\n readonly text: string\n}\n\nexport enum LayoutKind {\n Message = 'message',\n Component = 'component',\n Group = 'group',\n Instance = 'instance',\n Field = 'field'\n}\n\nexport class LayoutNode {\n public readonly children: LayoutNode[] = []\n\n constructor (\n public readonly kind: LayoutKind,\n public readonly name: string,\n public readonly path: string,\n /** for a field, its token; for a group, the token carrying NoXXX */\n public readonly tokenIndex: number = -1,\n public readonly set: IContainedSet | null = null,\n /** a raw data field is written as a Length token and then the data token */\n public readonly extraTokenIndex: number = -1) {\n }\n\n /** token indices below this node, in the order the encoder wrote them */\n public canonical (into: number[] = []): number[] {\n if (this.tokenIndex >= 0) into.push(this.tokenIndex)\n if (this.extraTokenIndex >= 0) into.push(this.extraTokenIndex)\n for (const c of this.children) {\n c.canonical(into)\n }\n return into\n }\n\n public get isLevel (): boolean {\n return this.kind === LayoutKind.Message || this.kind === LayoutKind.Instance\n }\n}\n\n/**\n * split a wire message into tokens. Values containing the delimiter would defeat this,\n * which is why the generator never produces one.\n */\nexport function tokenise (wire: string, delimiter: string): IToken[] {\n const parts = wire.split(delimiter)\n const tokens: IToken[] = []\n for (const p of parts) {\n if (p.length === 0) continue\n const eq = p.indexOf('=')\n if (eq <= 0) continue\n tokens.push({ tag: parseInt(p.substring(0, eq), 10), text: p })\n }\n return tokens\n}\n\nexport function assemble (tokens: readonly IToken[], order: readonly number[], delimiter: string): string {\n let out = ''\n for (const i of order) {\n out += tokens[i].text\n out += delimiter\n }\n return out\n}\n\nexport interface ILayout {\n readonly root: LayoutNode\n readonly tokens: readonly IToken[]\n /** index of the first body token; everything before it is the standard header */\n readonly bodyStart: number\n /** index one past the last body token; everything from here is the trailer */\n readonly bodyEnd: number\n}\n\nexport class Layout {\n private index: number = 0\n\n private constructor (start: number) {\n this.index = start\n }\n\n /**\n * Build the layout of `object` encoded as `wire`.\n *\n * The header and trailer are written by the transmitter rather than from the object,\n * so their extent is discovered rather than walked: the body is located by matching\n * the tag sequence the walk predicts against the token stream.\n */\n public static build (\n wire: string,\n delimiter: string,\n object: ILooseObject,\n set: IContainedSet): ILayout {\n const tokens = tokenise(wire, delimiter)\n const expected = Layout.expectedTags(object, set)\n const bodyStart = Layout.locate(tokens, expected)\n const builder = new Layout(bodyStart)\n const root = new LayoutNode(LayoutKind.Message, set.name, set.name, -1, set)\n builder.walk(object, set, root, set.name)\n return {\n root,\n tokens,\n bodyStart,\n bodyEnd: builder.index\n }\n }\n\n /**\n * the tag sequence the encoder will write for this object, used only to find where\n * the body begins\n */\n private static expectedTags (object: ILooseObject, set: IContainedSet): number[] {\n const out: number[] = []\n const collect = (o: ILooseObject, s: IContainedSet): void => {\n for (const field of Layout.presentFields(o, s)) {\n switch (field.type) {\n case ContainedFieldType.Simple: {\n const sf = field as ContainedSimpleField\n if (sf.definition.tagType === TagType.RawData && o[Layout.lengthName(s, sf)] == null) {\n out.push(Layout.lengthTag(s, sf))\n }\n out.push(sf.definition.tag)\n break\n }\n case ContainedFieldType.Component: {\n const cf = field as ContainedComponentField\n collect(o[cf.name] as ILooseObject, cf.definition)\n break\n }\n case ContainedFieldType.Group: {\n const gf = field as ContainedGroupField\n const nof = gf.definition.noOfField\n if (!nof) break\n out.push(nof.tag)\n const instances = Layout.instancesOf(o, gf)\n for (const instance of instances) {\n collect(instance, gf.definition)\n }\n break\n }\n default:\n break\n }\n }\n }\n collect(object, set)\n return out\n }\n\n private static locate (tokens: readonly IToken[], expected: readonly number[]): number {\n if (expected.length === 0) return 0\n for (let start = 0; start + expected.length <= tokens.length; ++start) {\n let ok = true\n for (let i = 0; i < expected.length; ++i) {\n if (tokens[start + i].tag !== expected[i]) {\n ok = false\n break\n }\n }\n if (ok) return start\n }\n throw new Error('layout walk does not match the encoded message - the mirror of AsciiEncoder has drifted')\n }\n\n /**\n * the fields of `set` that `o` actually carries, in the order the encoder writes them.\n * This is `AsciiEncoder.getFields`, deliberately duplicated rather than shared, because\n * the encoder is a hot path and should not grow a seam for a test tool.\n */\n private static presentFields (o: ILooseObject, set: IContainedSet): ContainedField[] {\n const fields: ContainedField[] = []\n for (const key of Object.keys(o)) {\n const field = set.localNameToField.get(key)\n if (field) fields.push(field)\n }\n fields.sort((a, b) => a.position - b.position)\n return fields\n }\n\n private static instancesOf (o: ILooseObject, gf: ContainedGroupField): ILooseObject[] {\n const nof = gf.definition.noOfField\n const instances = o[gf.name] ?? (nof ? o[nof.name] : null)\n return Array.isArray(instances) ? instances : []\n }\n\n private static lengthField (set: IContainedSet, sf: ContainedSimpleField): ContainedSimpleField | null {\n const prior = set.fields[sf.position - 1]\n if (!prior || prior.type !== ContainedFieldType.Simple) return null\n return prior as ContainedSimpleField\n }\n\n private static lengthName (set: IContainedSet, sf: ContainedSimpleField): string {\n return Layout.lengthField(set, sf)?.name ?? ''\n }\n\n private static lengthTag (set: IContainedSet, sf: ContainedSimpleField): number {\n return Layout.lengthField(set, sf)?.definition.tag ?? 0\n }\n\n private walk (o: ILooseObject, set: IContainedSet, parent: LayoutNode, path: string): void {\n for (const field of Layout.presentFields(o, set)) {\n switch (field.type) {\n case ContainedFieldType.Simple: {\n const sf = field as ContainedSimpleField\n let lengthIndex = -1\n if (sf.definition.tagType === TagType.RawData && o[Layout.lengthName(set, sf)] == null) {\n lengthIndex = this.index++\n }\n const dataIndex = this.index++\n // the length and its data are one indivisible unit - separating them would\n // produce a message that is not merely scattered but unparseable\n parent.children.push(new LayoutNode(\n LayoutKind.Field,\n sf.name,\n `${path}.${sf.name}`,\n lengthIndex >= 0 ? lengthIndex : dataIndex,\n null,\n lengthIndex >= 0 ? dataIndex : -1))\n break\n }\n case ContainedFieldType.Component: {\n const cf = field as ContainedComponentField\n const node = new LayoutNode(\n LayoutKind.Component, cf.name, `${path}.${cf.name}`, -1, cf.definition)\n parent.children.push(node)\n this.walk(o[cf.name] as ILooseObject, cf.definition, node, node.path)\n break\n }\n case ContainedFieldType.Group: {\n const gf = field as ContainedGroupField\n const nof = gf.definition.noOfField\n if (!nof) break\n const countIndex = this.index++\n const node = new LayoutNode(\n LayoutKind.Group, gf.name, `${path}.${gf.name}`, countIndex, gf.definition)\n parent.children.push(node)\n const instances = Layout.instancesOf(o, gf)\n for (let i = 0; i < instances.length; ++i) {\n const instance = new LayoutNode(\n LayoutKind.Instance, `${gf.name}[${i}]`, `${node.path}[${i}]`, -1, gf.definition)\n node.children.push(instance)\n this.walk(instances[i], gf.definition, instance, instance.path)\n }\n break\n }\n default:\n break\n }\n }\n }\n}\n"]}