@quotemedia.com/streamer 2.39.0 → 2.41.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,682 +1,682 @@
1
- <!DOCTYPE html>
2
- <html lang="en">
3
-
4
- <head>
5
- <script src="qmci-streamer-2.39.0.min.js"></script>
6
- <script src="https://cdnjs.cloudflare.com/ajax/libs/stomp.js/2.3.3/stomp.min.js"></script>
7
- </head>
8
-
9
- <body>
10
-
11
- <span>Subscription Examples:</span></br>
12
-
13
- <span>
14
- <label>Sid Subscription: </label>
15
- <select id="sid_user_subscription_example">
16
- <option value="subscribe">subscribe</option>
17
- <option value="subscribeMultiDataTypes">subscribeMultiDataTypes</option>
18
- <option value="subscribeMultiSymbolsMultiDataTypes">subscribeMultiSymbolsMultiDataTypes</option>
19
- <option value="subscribeMultiMessages">subscribeMultiMessages</option>
20
- <option value="subscribeLargerSymbolLists">subscribeLargerSymbolLists</option>
21
- <option value="subscribeExchange">subscribeExchange</option>
22
- </select>
23
- </span>
24
- <input id="sid_user_get_sid" type="button" value="Get SID">
25
- <input id="sid_user_subscribe" type="button" value="Subscribe">
26
- <input id="sid_user_unsubscribe" type="button" value="Unsubscribe"></br>
27
-
28
- <span>
29
- <label>Enterprise Subscription: </label>
30
- <select id="enterprise_user_subscription_example">
31
- <option value="subscribe">subscribe</option>
32
- <option value="subscribeMultiDataTypes">subscribeMultiDataTypes</option>
33
- <option value="subscribeMultiSymbolsMultiDataTypes">subscribeMultiSymbolsMultiDataTypes</option>
34
- </select>
35
- </span>
36
- <input id="enterprise_user_subscribe" type="button" value="Subscribe">
37
- <input id="enterprise_user_unsubscribe" type="button" value="Unsubscribe"></br>
38
-
39
- <span>
40
- <label>Wmid Subscription: </label>
41
- <select id="wmid_user_subscription_example">
42
- <option value="subscribe">subscribe</option>
43
- <option value="subscribeMultiDataTypes">subscribeMultiDataTypes</option>
44
- <option value="subscribeMultiSymbolsMultiDataTypes">subscribeMultiSymbolsMultiDataTypes</option>
45
- </select>
46
- </span>
47
- <input id="wmid_user_subscribe" type="button" value="Subscribe">
48
- <input id="wmid_user_unsubscribe" type="button" value="Unsubscribe"></br>
49
-
50
- <input id="stomp_connection_close" type="button" value="Connection Close"></br>
51
-
52
- <div id="msg_print"></div>
53
-
54
- <script type="text/javascript">
55
- // Set up the event Listeners SidUserUnsubscribe
56
- document.getElementById("sid_user_get_sid").addEventListener("click", getSid);
57
- document.getElementById("sid_user_subscribe").addEventListener("click", SidUserSubscription);
58
- document.getElementById("sid_user_unsubscribe").addEventListener("click", SidUserUnsubscribe);
59
- document.getElementById("enterprise_user_subscribe").addEventListener("click", EnterpriseUserSubscription);
60
- document.getElementById("enterprise_user_unsubscribe").addEventListener("click", EnterpriseUserUnsubscribe);
61
- document.getElementById("wmid_user_subscribe").addEventListener("click", WmidUserSubscription);
62
- document.getElementById("wmid_user_unsubscribe").addEventListener("click", WmidUserUnsubscribe);
63
- document.getElementById("stomp_connection_close").addEventListener("click", disconnect);
64
-
65
- // We need to use qmci.streamer to get the sid and use for Sid User Method
66
- var Streamer = qmci.Streamer;
67
- // Set up the message formatter, and it included in Streamer official JavaScript SDK library
68
- var msgfmt = new qmci.Streamer.formatting.Formatter();
69
- // This is URL use to connect Stomp endpoint
70
- const url = "ws://app.quotemedia.com/cache/stream/connect";
71
- // Stomp subscribe url route
72
- const STOMP_SUBSCRIBE_URL = "/user/queue/messages";
73
- // Stomp message send url route
74
- const STOMP_SEND_MESSAGE_URL = "/stream/message";
75
- // Sid for the end user Auth
76
- var SID = null;
77
- // Set up the Stomp client
78
- var stompClient = null;
79
- // To record the max allow to entitle for this user id
80
- var maxEntitlementsPerSubscription = 0;
81
- // To track the commands/control messages ordering
82
- var ID = 1;
83
-
84
- // Subscription msg lists use for multiple subscription request
85
- var msgArrSubList = [{
86
- "@T": "C2",
87
- "action": "SUBSCRIBE",
88
- "symbols": ["GOOG"],
89
- "types": ["QUOTE"],
90
- "mimetype": "application/json",
91
- "conflation": null,
92
- "id": ID++
93
- },
94
- {
95
- "@T": "C2",
96
- "action": "SUBSCRIBE",
97
- "symbols": ["AAPL"],
98
- "types": ["TRADE"],
99
- "mimetype": "application/json",
100
- "conflation": null,
101
- "id": ID++
102
- },
103
- {
104
- "@T": "C2",
105
- "action": "SUBSCRIBE",
106
- "symbols": ["MSFT"],
107
- "types": ["PRICEDATA"],
108
- "mimetype": "application/json",
109
- "conflation": null,
110
- "id": ID++
111
- }
112
- ];
113
-
114
- // Unsubscription msg lists use for multiple subscription request
115
- var msgArrUnsubList = [{
116
- "@T": "C2",
117
- "action": "UNSUBSCRIBE",
118
- "symbols": ["GOOG"],
119
- "types": ["QUOTE"],
120
- "mimetype": "application/json",
121
- "conflation": null,
122
- "id": ID++
123
- },
124
- {
125
- "@T": "C2",
126
- "action": "UNSUBSCRIBE",
127
- "symbols": ["AAPL"],
128
- "types": ["TRADE"],
129
- "mimetype": "application/json",
130
- "conflation": null,
131
- "id": ID++
132
- },
133
- {
134
- "@T": "C2",
135
- "action": "UNSUBSCRIBE",
136
- "symbols": ["MSFT"],
137
- "types": ["PRICEDATA"],
138
- "mimetype": "application/json",
139
- "conflation": null,
140
- "id": ID++
141
- }
142
- ];
143
-
144
- // Lager symbol lists with 200 symbols
145
- var symbolLists = [
146
- "A", "AA", "AAAU", "AACG", "AADR", "AAL", "AAMC", "AAME", "AAN", "AAOI", "AAP", "AAPL", "AAT", "AAU", "AAWW", "AAXJ", "AAXN", "AB", "ABB", "ABBV",
147
- "ABC", "ABCB", "ABDC", "ABEO", "ABEV", "ABG", "ABIO", "ABM", "ABMD", "ABR", "ABT", "ABTX", "ABUS", "AC", "ACA", "ACAD", "ACAM", "ACB", "ACBI", "ACC",
148
- "ACCO", "ACEL", "ACER", "ACES", "ACGL", "ACH", "ACHC", "ACHN", "ACHV", "ACIA", "ACIO", "ACIU", "ACIW", "ACLS", "ACM", "ACMR", "ACN", "ACNB", "ACOR", "ACP",
149
- "ACRE", "ACRS", "ACRX", "ACSI", "ACST", "ACT", "ACTG", "ACTT", "ACTTU", "ACU", "ACV", "ACWF", "ACWI", "ACWV", "ACWX", "ACY", "ADAP", "ADBE", "ADC", "ADES",
150
- "ADI", "ADIL", "ADM", "ADMA", "ADME", "ADMP", "ADMS", "ADNT", "ADP", "ADPT", "ADRA", "ADRD", "ADRE", "ADRO", "ADS", "ADSK", "ADSW", "ADT", "ADTN", "NIO",
151
- "AMD", "CHK", "BAC", "EEM", "NK", "SDC", "MNK", "WFC", "MS", "F", "QD", "NOK", "SPY", "XLF", "MNI", "SIG", "SNAP", "FPAC", "GE", "VXX",
152
- "T", "UBER", "FCEL", "GDX", "CETX", "TSLA", "MU", "XOP", "ITUP", "TEVA", "OGI", "IWM", "IAU", "CRON", "MRVL", "SWN", "JCP", "HYG", "TWTR", "TQQQ",
153
- "FXI", "IEMG", "PINS", "SQQQ", "BBD", "MSFT", "CGC", "SPCE", "USO", "LK", "AMLP", "CMCSA", "PLUG", "HEXO", "PBR", "ECA", "BYND", "FCX", "EWZ", "DWT",
154
- "QQQ", "CSCO", "RIG", "ZNGA", "NRZ", "VALE", "INTC", "ABEV", "BABA", "IAG", "AEMD", "DUST", "VWO", "ROKU", "UVXY", "BK", "AUY", "PFE", "ENDP", "CLVS",
155
- "HTBX", "SAN", "MDR", "CTL", "TSM", "NUGT", "AMRN", "LQD", "RBZ", "USB", "IBIO", "SXTC", "APEX", "NLOK", "SIRI", "CSR", "ZYXI", "ZYNE", "ZYME", "ZVO"
156
- ];
157
-
158
- // Data types that Streamer available to make subscription
159
- var dataTypes = [
160
- // D1
161
- // Market data message returns:
162
- // {Q, timestamp, symbol, locateCode, indicator, sharesPerSizeUnit, bidPrice, bidSize, bidExcode, bidCondition, askPrice, askSize, askExcode, askCondition}
163
- "QUOTE",
164
- // D2
165
- // Market data message returns:
166
- // {P,timestamp, symbol, locateCode, last, lastTradeSize, change, percentChange, tick, tradeCount, close, previousClose,
167
- // open, high, annualHigh, low, annualLow, lastTradeTime, accumulatedPrice, accumulatedVolume, accumulatedTradeValue,
168
- // twap, vwap, preMarketTradeTime, preMarketLast, preMarketVolume, preMarketChange, preMarketPercentChange, postMarketTradeTime,
169
- // postMarketLast, postMarketVolume, postMarketChange, postMarketPercentChange, lastTradeExcode, currencyID}
170
- "PRICEDATA",
171
- // D3
172
- // Market data message returns:
173
- // {T, timestamp, symbol, locateCode, excode, sequenceNumber, matchID, price, size, tick, indicator, rangeIndicator, sellerID, buyerID, accumulatedVolume, vwap}
174
- "TRADE",
175
- // D4
176
- // Market data message returns:
177
- // {BO, timestamp, symbol, locateCode, excode, orderID, orderReference, marketMakerID, orderSide, lastUpdate, price, size, display, orderChangeType}
178
- "ORDERBOOK",
179
- // D7
180
- // Market data message returns:
181
- // {MMQ, timestamp, symbol, locateCode, bidPrice, bidSize, bidChange, askPrice, askSize, askChange, indicator, marketMakerID, sharesPerSizeUnit}
182
- "MMQUOTE",
183
- // D8
184
- // Market data message returns:
185
- // {I, timestamp, symbol, locateCode, last, lastTime, open, openTime, high, low, startTime, tradeValue, volume, vwap}
186
- "INTERVAL",
187
- // D9
188
- // Market data message returns:
189
- // {NHP, timestamp, symbol, locateCode, marketMakerID, buyValue, buyVolume, buyBlockTransactions, buyBlockValue, buyBlockVolume, sellValue, sellVolume,
190
- // sellBlockTransactions, sellBlockValue, sellBlockVolume}
191
- "NETHOUSEPOSITION",
192
- // D13
193
- // Market data message returns:
194
- // {LS, timestamp, symbol, locateCode, last, change, percentChange, accumulatedVolume, tick, lastTradeExcode}
195
- "LASTSALE",
196
- // D14
197
- // Market data message returns:
198
- // {LULD, symbol, locateCode, effectiveTime, lowerLimit, upperLimit, bidNotExecutable, askNotExecutable}
199
- "LIMITUPLIMITDOWN",
200
- // D15
201
- // Market data message returns:
202
- // {IVG, lastCalculation, symbol, locateCode, delta, gamma, vega, rho, theta, midIV, midIVChange, bidIV, askIV, mark, intrinsicValue, extrinsicValue,
203
- // previousMark, markChange, markChangePercent}
204
- "IVGREEKS",
205
- // D16
206
- // Market data message returns:
207
- // {IS, timestamp, symbol, locateCode, imbalanceType, referencePrice, size, side, pairedVolume, nearIndicativePrice, farIndicativePrice, priceVariation}
208
- "IMBALANCESTATUS"
209
- ];
210
-
211
- const headers = {
212
- // This header is optional we could use
213
- 'X-Stream-Format': 'application/json'
214
- };
215
-
216
- /** We could use following auth method to make subscription with streaming data
217
- * Sid
218
- * Enterprise Token
219
- * Wmid
220
- */
221
-
222
- /** For the Sid User we need to use qmci.Streamer library to get the sid first, then use the sid for login Auth */
223
- function getSid() {
224
- Streamer.login({
225
- host: 'https://app.quotemedia.com/auth',
226
- credentials: {
227
- wmid: "YourWebmasterID",
228
- username: "YourUsername",
229
- password: "YourPassword"
230
- }
231
- }, (err, sid) => {
232
- if (err) {
233
- console.error(err);
234
- } else if (sid) {
235
- SID = sid;
236
- console.log("SID: ", SID);
237
- }
238
- });
239
- }
240
-
241
- /** Sid User example we need to get the sid before to run this example */
242
- function SidUserSubscription() {
243
- if (SID == null) {
244
- console.log("SID is invalid: ", SID);
245
- return;
246
- }
247
-
248
- if (stompClient == null || stompClient.ws.readyState === 3) {
249
- stompClient = Stomp.client(url);
250
- SidAuthMethod(SID, stompClient, headers);
251
- }
252
-
253
- /** Subscription Examples: Start */
254
- /** To see the example result by uncomment the code */
255
- const selectedExample = document.getElementById("sid_user_subscription_example").value;
256
-
257
- if (selectedExample === "subscribe") {
258
- subscribe(stompClient, headers);
259
- }
260
-
261
- if (selectedExample === "subscribeMultiDataTypes") {
262
- subscribeMultiDataTypes(stompClient, headers);
263
- }
264
-
265
- if (selectedExample === "subscribeMultiSymbolsMultiDataTypes") {
266
- subscribeMultiSymbolsMultiDataTypes(stompClient, headers);
267
- }
268
-
269
- if (selectedExample === "subscribeMultiMessages") {
270
- subscribeMultiMessages(stompClient, headers, msgArrSubList);
271
- }
272
-
273
- if (selectedExample === "subscribeLargerSymbolLists") {
274
- subscribeLargerSymbolLists(stompClient, headers, symbolLists, dataTypes);
275
- }
276
-
277
- if (selectedExample === "subscribeExchange") {
278
- subscribeExchange(stompClient, headers);
279
- }
280
- /** Subscription Examples: End */
281
- }
282
-
283
- function SidUserUnsubscribe() {
284
- const selectedExample = document.getElementById("sid_user_subscription_example").value;
285
- if (selectedExample === "subscribe") {
286
- unsubscribe(stompClient, headers);
287
- }
288
-
289
- if (selectedExample === "subscribeMultiDataTypes") {
290
- unsubscribeMultiDataTypes(stompClient, headers);
291
- }
292
-
293
- if (selectedExample === "subscribeMultiSymbolsMultiDataTypes") {
294
- unsubscribeMultiSymbolsMultiDataTypes(stompClient, headers);
295
- }
296
-
297
- if (selectedExample === "subscribeMultiMessages") {
298
- unsubscribeMultiMessages(stompClient, headers, msgArrUnsubList);
299
- }
300
-
301
- if (selectedExample === "subscribeLargerSymbolLists") {
302
- unsubscribeLargerSymbolLists(stompClient, headers, symbolLists, dataTypes);
303
- }
304
-
305
- if (selectedExample === "subscribeExchange") {
306
- unsubscribeExchange(stompClient, headers);
307
- }
308
- }
309
-
310
- /** Enterprise User example */
311
- function EnterpriseUserSubscription() {
312
- // Set up the Enterprise token and WebmasterID
313
- const enterpriseToken = 'YourEnterpriseToken';
314
- const wmid = 'YourWebmasterID';
315
-
316
- if (stompClient == null || stompClient.ws.readyState === 3) {
317
- stompClient = Stomp.client(url);
318
- EnterpriseAuthMethod(enterpriseToken, wmid, stompClient, headers);
319
- }
320
-
321
- /** Subscription Examples: Start */
322
- /** To see the example result by uncomment the code */
323
- const selectedExample = document.getElementById("enterprise_user_subscription_example").value;
324
-
325
- if (selectedExample === "subscribe") {
326
- subscribe(stompClient, headers);
327
- }
328
-
329
- if (selectedExample === "subscribeMultiDataTypes") {
330
- subscribeMultiDataTypes(stompClient, headers);
331
- }
332
-
333
- if (selectedExample === "subscribeMultiSymbolsMultiDataTypes") {
334
- subscribeMultiSymbolsMultiDataTypes(stompClient, headers);
335
- }
336
- /** Subscription Examples: End */
337
- }
338
-
339
- function EnterpriseUserUnsubscribe() {
340
- const selectedExample = document.getElementById("enterprise_user_subscription_example").value;
341
- if (selectedExample === "subscribe") {
342
- unsubscribe(stompClient, headers);
343
- }
344
-
345
- if (selectedExample === "subscribeMultiDataTypes") {
346
- unsubscribeMultiDataTypes(stompClient, headers);
347
- }
348
-
349
- if (selectedExample === "subscribeMultiSymbolsMultiDataTypes") {
350
- unsubscribeMultiSymbolsMultiDataTypes(stompClient, headers);
351
- }
352
- }
353
-
354
- /** Wmid User example */
355
- function WmidUserSubscription() {
356
- // Set up the Wmid
357
- const wmid = 'YourWebmasterID';
358
-
359
- if (stompClient == null || stompClient.ws.readyState === 3) {
360
- stompClient = Stomp.client(url);
361
- WmidAuthMethod(wmid, stompClient, headers);
362
- }
363
-
364
- /** Subscription Examples: Start */
365
- /** To see the example result by uncomment the code */
366
- const selectedExample = document.getElementById("wmid_user_subscription_example").value;
367
-
368
- if (selectedExample === "subscribe") {
369
- subscribe(stompClient, headers);
370
- }
371
-
372
- if (selectedExample === "subscribeMultiDataTypes") {
373
- subscribeMultiDataTypes(stompClient, headers);
374
- }
375
-
376
- if (selectedExample === "subscribeMultiSymbolsMultiDataTypes") {
377
- subscribeMultiSymbolsMultiDataTypes(stompClient, headers);
378
- }
379
- /** Subscription Examples: End */
380
- }
381
-
382
- function WmidUserUnsubscribe() {
383
- const selectedExample = document.getElementById("wmid_user_subscription_example").value;
384
- if (selectedExample === "subscribe") {
385
- unsubscribe(stompClient, headers);
386
- }
387
-
388
- if (selectedExample === "subscribeMultiDataTypes") {
389
- unsubscribeMultiDataTypes(stompClient, headers);
390
- }
391
-
392
- if (selectedExample === "subscribeMultiSymbolsMultiDataTypes") {
393
- unsubscribeMultiSymbolsMultiDataTypes(stompClient, headers);
394
- }
395
- }
396
-
397
- /** To build Sid Auth message */
398
- function SidAuthMethod(authorization, stompClient, headers = {}) {
399
- if (stompClient.ws.readyState === 0) {
400
- authMessage = BuildAuthMessage("sid", authorization);
401
-
402
- stompClient.connect({}, function(frame) {
403
- stompClient.subscribe(STOMP_SUBSCRIBE_URL, function(responseMessage) {
404
- responseMsgHandler(JSON.parse(responseMessage.body))
405
- });
406
- stompClient.send(STOMP_SEND_MESSAGE_URL, headers, JSON.stringify(authMessage));
407
- });
408
- }
409
- }
410
-
411
- /** To build Enterprise Auth message */
412
- function EnterpriseAuthMethod(authorization, wmid, stompClient, headers = {}) {
413
- if (stompClient.ws.readyState === 0) {
414
- authMessage = BuildAuthMessage("enterprise", authorization, wmid);
415
-
416
- stompClient.connect({}, function(frame) {
417
- stompClient.subscribe(STOMP_SUBSCRIBE_URL, function(responseMessage) {
418
- responseMsgHandler(JSON.parse(responseMessage.body))
419
- });
420
- stompClient.send(STOMP_SEND_MESSAGE_URL, headers, JSON.stringify(authMessage));
421
- });
422
- }
423
- }
424
-
425
- /** To build Wmid Auth message */
426
- function WmidAuthMethod(authorization, stompClient, headers = {}) {
427
- if (stompClient.ws.readyState === 0) {
428
- authMessage = BuildAuthMessage("wmid", authorization);
429
-
430
- stompClient.connect({}, function(frame) {
431
- stompClient.subscribe(STOMP_SUBSCRIBE_URL, function(responseMessage) {
432
- responseMsgHandler(JSON.parse(responseMessage.body))
433
- });
434
- stompClient.send(STOMP_SEND_MESSAGE_URL, headers, JSON.stringify(authMessage));
435
- });
436
- }
437
- }
438
-
439
- /**
440
- *
441
- * @param action {string}
442
- * @param symbols {Array.<string>}
443
- * @param types {Array.<string>}
444
- * @param mimetype {string}
445
- * @param conflation {int}
446
- * @param id {int}
447
- * @returns {boolean|{"@T": string, action, symbols, types, mimetype, conflation, id}}
448
- */
449
- function buildMarketDataMsg(action, symbols, types, mimetype, conflation, id) {
450
- if (maxEntitlementsPerSubscription <= 0 && maxEntitlementsPerSubscription < symbols.length) {
451
- return false;
452
- }
453
- console.log("The sub/unsub symbols size is: ", symbols.length);
454
-
455
- const msg = {
456
- "@T": "C2",
457
- "action": action,
458
- "symbols": symbols,
459
- "types": types,
460
- "mimetype": mimetype,
461
- "conflation": conflation,
462
- "id": id
463
- }
464
- return msg;
465
- }
466
-
467
- /** Subscription with one symbol and one data type */
468
- function subscribe(stompClient, headers = {}) {
469
- if (stompClient.ws.readyState === 1) {
470
- msg = buildMarketDataMsg("SUBSCRIBE", ["GOOG"], ["QUOTE"], "application/json", null, ID++)
471
- if (msg != false) {
472
- stompClient.send(STOMP_SEND_MESSAGE_URL, headers, JSON.stringify(msg));
473
- }
474
- } else {
475
- setTimeout(subscribe, 1000, stompClient, headers);
476
- }
477
- }
478
-
479
- function unsubscribe(stompClient, headers = {}) {
480
- if (stompClient.ws.readyState === 1) {
481
- msg = buildMarketDataMsg("UNSUBSCRIBE", ["GOOG"], ["QUOTE"], "application/json", null, ID++)
482
- stompClient.send(STOMP_SEND_MESSAGE_URL, headers, JSON.stringify(msg));
483
- }
484
- }
485
-
486
- /** Subscription with one symbol and multiple data types */
487
- function subscribeMultiDataTypes(stompClient, headers = {}) {
488
- if (stompClient.ws.readyState === 1) {
489
- msg = buildMarketDataMsg("SUBSCRIBE", ["GOOG"], ["QUOTE", "TRADE"], "application/json", null, ID++)
490
- stompClient.send(STOMP_SEND_MESSAGE_URL, headers, JSON.stringify(msg));
491
- } else {
492
- setTimeout(subscribeMultiDataTypes, 1000, stompClient, headers);
493
- }
494
- }
495
-
496
- function unsubscribeMultiDataTypes(stompClient, headers = {}) {
497
- if (stompClient.ws.readyState === 1) {
498
- msg = buildMarketDataMsg("UNSUBSCRIBE", ["GOOG"], ["QUOTE", "TRADE"], "application/json", null, ID++)
499
- stompClient.send(STOMP_SEND_MESSAGE_URL, headers, JSON.stringify(msg));
500
- }
501
- }
502
-
503
- /** Subscription with multiple symbols and multiple data types */
504
- function subscribeMultiSymbolsMultiDataTypes(stompClient, headers = {}) {
505
- if (stompClient.ws.readyState === 1) {
506
- msg = buildMarketDataMsg("SUBSCRIBE", ["GOOG", "AAPL"], ["QUOTE", "TRADE"], "application/json", null, ID++)
507
- stompClient.send(STOMP_SEND_MESSAGE_URL, headers, JSON.stringify(msg));
508
- } else {
509
- setTimeout(subscribeMultiSymbolsMultiDataTypes, 1000, stompClient, headers);
510
- }
511
- }
512
-
513
- function unsubscribeMultiSymbolsMultiDataTypes(stompClient, headers = {}) {
514
- if (stompClient.ws.readyState === 1) {
515
- msg = buildMarketDataMsg("UNSUBSCRIBE", ["GOOG", "AAPL"], ["QUOTE", "TRADE"], "application/json", null, ID++)
516
- stompClient.send(STOMP_SEND_MESSAGE_URL, headers, JSON.stringify(msg));
517
- }
518
- }
519
-
520
- /** Subscription to loop a lists contains multiple subscription request messages */
521
- function subscribeMultiMessages(stompClient, headers = {}, msgArr) {
522
- if (stompClient.ws.readyState === 1) {
523
- for (let i = 0; i < msgArr.length; i++) {
524
- stompClient.send(STOMP_SEND_MESSAGE_URL, headers, JSON.stringify(msgArr[i]));
525
- }
526
- } else {
527
- setTimeout(subscribeMultiMessages, 1000, stompClient, headers, msgArr);
528
- }
529
- }
530
-
531
- function unsubscribeMultiMessages(stompClient, headers = {}, msgArr) {
532
- if (stompClient.ws.readyState === 1) {
533
- for (let i = 0; i < msgArr.length; i++) {
534
- stompClient.send(STOMP_SEND_MESSAGE_URL, headers, JSON.stringify(msgArr[i]));
535
- }
536
- }
537
- }
538
-
539
- /** Subscription with larger symbol(200 symbols) lists and multiple data types */
540
- function subscribeLargerSymbolLists(stompClient, headers = {}, symbolLists, dataTypes) {
541
- if (stompClient.ws.readyState === 1) {
542
- msg = buildMarketDataMsg("SUBSCRIBE", symbolLists, dataTypes, "application/json", null, ID++)
543
- if (msg != false) {
544
- stompClient.send(STOMP_SEND_MESSAGE_URL, headers, JSON.stringify(msg));
545
- }
546
- } else {
547
- setTimeout(subscribeLargerSymbolLists, 1000, stompClient, headers, symbolLists, dataTypes);
548
- }
549
- }
550
-
551
- function unsubscribeLargerSymbolLists(stompClient, headers = {}, symbolLists, dataTypes) {
552
- if (stompClient.ws.readyState === 1) {
553
- msg = buildMarketDataMsg("UNSUBSCRIBE", symbolLists, dataTypes, "application/json", null, ID++)
554
- stompClient.send(STOMP_SEND_MESSAGE_URL, headers, JSON.stringify(msg));
555
- }
556
- }
557
-
558
- /**
559
- *
560
- * @param action {string}
561
- * @param exchange {string}
562
- * @param mimetype {string}
563
- * @param conflation {int}
564
- * @param id {int}
565
- * @returns
566
- */
567
- function buildExchangeMsg(action, exchange, mimetype, conflation, id) {
568
- const msg = {
569
- "@T": "C14",
570
- "action": action,
571
- "exchange": exchange,
572
- "mimetype": mimetype,
573
- "conflation": conflation,
574
- "id": id
575
- }
576
- return msg;
577
- }
578
-
579
- /** Subscription for exchange */
580
- function subscribeExchange(stompClient, headers = {}) {
581
- if (stompClient.ws.readyState === 1) {
582
- msg = buildExchangeMsg("SUBSCRIBE", "TSX", "application/json", null, ID++);
583
- stompClient.send(STOMP_SEND_MESSAGE_URL, headers, JSON.stringify(msg));
584
- } else {
585
- setTimeout(subscribeExchange, 1000, stompClient, headers);
586
- }
587
- }
588
-
589
- function unsubscribeExchange(stompClient, headers = {}) {
590
- if (stompClient.ws.readyState === 1) {
591
- msg = buildExchangeMsg("UNSUBSCRIBE", "TSX", "application/json", null, ID++);
592
- stompClient.send(STOMP_SEND_MESSAGE_URL, headers, JSON.stringify(msg));
593
- }
594
- }
595
-
596
- /** Disconnect the Stomp connection */
597
- function disconnect() {
598
- if (stompClient.ws.readyState === 1) {
599
- stompClient.disconnect();
600
- }
601
- }
602
-
603
- /** To listen and handle the message sent from Streaming server */
604
- function responseMsgHandler(msg) {
605
- // C5 is for connect response and here we are trying to get the max entitlements number,
606
- // and this number is for maximum symbols allow for per subscription.
607
- if (msg["@T"] === 'C5') {
608
- maxEntitlementsPerSubscription = msg.maxEntitlementsPerSubscription;
609
- console.log("The max ET number per subscription is: ", maxEntitlementsPerSubscription);
610
- }
611
- // C28 is for Flow Control message
612
- // To control latency and in cases where client connections cannot keep up with the amount of streamed messages,
613
- // there are mechanisms in place to limit negative effects from “slow” clients. These requirements MUST be
614
- // implemented and adhered to on the client implementation, or else connections will be disconnected.
615
- // When the client connection receives that message they must IMMEDIATELY respond back to the server with the
616
- // exact same message, containing the same field and value.
617
- else if (msg["@T"] === 'C28') {
618
- if (stompClient.ws.readyState === 1) {
619
- stompClient.send(STOMP_SEND_MESSAGE_URL, {}, JSON.stringify(msg));
620
- }
621
- }
622
- // C3 is for subscribe response, it will return the status code and reason back to client,
623
- // if the subscription is successfully server will return status code with 200
624
- else if (msg["@T"] === 'C3') {
625
- if (msg["code"] === 200) {
626
- console.log("Subscription succeed!");
627
- }
628
- }
629
- // C4 is for unsubscribe response, it will return the status code and reason back to client,
630
- // if the unsubscription is successfully server will return status code with 200
631
- else if (msg["@T"] === 'C4') {
632
- if (msg["code"] === 200) {
633
- console.log("Unsubscription succeed!");
634
- }
635
- }
636
- // D1 is for Quote messages
637
- else if (msg["@T"] === 'D1') {
638
- const node = document.createElement("p").appendChild(document.createTextNode(JSON.stringify(msgfmt.fmt(msg))));
639
- const brNode = document.createElement("br");
640
- document.getElementById("msg_print").appendChild(node);
641
- document.getElementById("msg_print").appendChild(brNode);
642
- }
643
- // D2 is for PriceData messages
644
- else if (msg["@T"] === 'D2') {
645
- const node = document.createElement("p").appendChild(document.createTextNode(JSON.stringify(msgfmt.fmt(msg))));
646
- const brNode = document.createElement("br");
647
- document.getElementById("msg_print").appendChild(node);
648
- document.getElementById("msg_print").appendChild(brNode);
649
- }
650
- // D3 is for Trade messages
651
- else if (msg["@T"] === 'D3') {
652
- const node = document.createElement("p").appendChild(document.createTextNode(JSON.stringify(msgfmt.fmt(msg))));
653
- const brNode = document.createElement("br");
654
- document.getElementById("msg_print").appendChild(node);
655
- document.getElementById("msg_print").appendChild(brNode);
656
- }
657
- // To catch other MarketData messages
658
- else {
659
- const node = document.createElement("p").appendChild(document.createTextNode(JSON.stringify(msgfmt.fmt(msg))));
660
- const brNode = document.createElement("br");
661
- document.getElementById("msg_print").appendChild(node);
662
- document.getElementById("msg_print").appendChild(brNode);
663
- }
664
- }
665
-
666
- /** To build the Auth Message, if using enterprise authenticationMethod,
667
- * and we need to set the wmid otherwise we could default and set it to null */
668
- function BuildAuthMessage(authenticationMethod, authorization, wmid = null, conflation = null, rejectExcessiveConnection = false) {
669
- var authMessage = {
670
- '@T': 'C27',
671
- 'authenticationMethod': authenticationMethod,
672
- 'authorization': authorization,
673
- 'wmid': wmid,
674
- 'conflation': conflation,
675
- 'rejectExcessiveConnection': rejectExcessiveConnection
676
- };
677
- return authMessage;
678
- }
679
- </script>
680
- </body>
681
-
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+
4
+ <head>
5
+ <script src="qmci-streamer-2.41.0.min.js"></script>
6
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/stomp.js/2.3.3/stomp.min.js"></script>
7
+ </head>
8
+
9
+ <body>
10
+
11
+ <span>Subscription Examples:</span></br>
12
+
13
+ <span>
14
+ <label>Sid Subscription: </label>
15
+ <select id="sid_user_subscription_example">
16
+ <option value="subscribe">subscribe</option>
17
+ <option value="subscribeMultiDataTypes">subscribeMultiDataTypes</option>
18
+ <option value="subscribeMultiSymbolsMultiDataTypes">subscribeMultiSymbolsMultiDataTypes</option>
19
+ <option value="subscribeMultiMessages">subscribeMultiMessages</option>
20
+ <option value="subscribeLargerSymbolLists">subscribeLargerSymbolLists</option>
21
+ <option value="subscribeExchange">subscribeExchange</option>
22
+ </select>
23
+ </span>
24
+ <input id="sid_user_get_sid" type="button" value="Get SID">
25
+ <input id="sid_user_subscribe" type="button" value="Subscribe">
26
+ <input id="sid_user_unsubscribe" type="button" value="Unsubscribe"></br>
27
+
28
+ <span>
29
+ <label>Enterprise Subscription: </label>
30
+ <select id="enterprise_user_subscription_example">
31
+ <option value="subscribe">subscribe</option>
32
+ <option value="subscribeMultiDataTypes">subscribeMultiDataTypes</option>
33
+ <option value="subscribeMultiSymbolsMultiDataTypes">subscribeMultiSymbolsMultiDataTypes</option>
34
+ </select>
35
+ </span>
36
+ <input id="enterprise_user_subscribe" type="button" value="Subscribe">
37
+ <input id="enterprise_user_unsubscribe" type="button" value="Unsubscribe"></br>
38
+
39
+ <span>
40
+ <label>Wmid Subscription: </label>
41
+ <select id="wmid_user_subscription_example">
42
+ <option value="subscribe">subscribe</option>
43
+ <option value="subscribeMultiDataTypes">subscribeMultiDataTypes</option>
44
+ <option value="subscribeMultiSymbolsMultiDataTypes">subscribeMultiSymbolsMultiDataTypes</option>
45
+ </select>
46
+ </span>
47
+ <input id="wmid_user_subscribe" type="button" value="Subscribe">
48
+ <input id="wmid_user_unsubscribe" type="button" value="Unsubscribe"></br>
49
+
50
+ <input id="stomp_connection_close" type="button" value="Connection Close"></br>
51
+
52
+ <div id="msg_print"></div>
53
+
54
+ <script type="text/javascript">
55
+ // Set up the event Listeners SidUserUnsubscribe
56
+ document.getElementById("sid_user_get_sid").addEventListener("click", getSid);
57
+ document.getElementById("sid_user_subscribe").addEventListener("click", SidUserSubscription);
58
+ document.getElementById("sid_user_unsubscribe").addEventListener("click", SidUserUnsubscribe);
59
+ document.getElementById("enterprise_user_subscribe").addEventListener("click", EnterpriseUserSubscription);
60
+ document.getElementById("enterprise_user_unsubscribe").addEventListener("click", EnterpriseUserUnsubscribe);
61
+ document.getElementById("wmid_user_subscribe").addEventListener("click", WmidUserSubscription);
62
+ document.getElementById("wmid_user_unsubscribe").addEventListener("click", WmidUserUnsubscribe);
63
+ document.getElementById("stomp_connection_close").addEventListener("click", disconnect);
64
+
65
+ // We need to use qmci.streamer to get the sid and use for Sid User Method
66
+ var Streamer = qmci.Streamer;
67
+ // Set up the message formatter, and it included in Streamer official JavaScript SDK library
68
+ var msgfmt = new qmci.Streamer.formatting.Formatter();
69
+ // This is URL use to connect Stomp endpoint
70
+ const url = "ws://app.quotemedia.com/cache/stream/connect";
71
+ // Stomp subscribe url route
72
+ const STOMP_SUBSCRIBE_URL = "/user/queue/messages";
73
+ // Stomp message send url route
74
+ const STOMP_SEND_MESSAGE_URL = "/stream/message";
75
+ // Sid for the end user Auth
76
+ var SID = null;
77
+ // Set up the Stomp client
78
+ var stompClient = null;
79
+ // To record the max allow to entitle for this user id
80
+ var maxEntitlementsPerSubscription = 0;
81
+ // To track the commands/control messages ordering
82
+ var ID = 1;
83
+
84
+ // Subscription msg lists use for multiple subscription request
85
+ var msgArrSubList = [{
86
+ "@T": "C2",
87
+ "action": "SUBSCRIBE",
88
+ "symbols": ["GOOG"],
89
+ "types": ["QUOTE"],
90
+ "mimetype": "application/json",
91
+ "conflation": null,
92
+ "id": ID++
93
+ },
94
+ {
95
+ "@T": "C2",
96
+ "action": "SUBSCRIBE",
97
+ "symbols": ["AAPL"],
98
+ "types": ["TRADE"],
99
+ "mimetype": "application/json",
100
+ "conflation": null,
101
+ "id": ID++
102
+ },
103
+ {
104
+ "@T": "C2",
105
+ "action": "SUBSCRIBE",
106
+ "symbols": ["MSFT"],
107
+ "types": ["PRICEDATA"],
108
+ "mimetype": "application/json",
109
+ "conflation": null,
110
+ "id": ID++
111
+ }
112
+ ];
113
+
114
+ // Unsubscription msg lists use for multiple subscription request
115
+ var msgArrUnsubList = [{
116
+ "@T": "C2",
117
+ "action": "UNSUBSCRIBE",
118
+ "symbols": ["GOOG"],
119
+ "types": ["QUOTE"],
120
+ "mimetype": "application/json",
121
+ "conflation": null,
122
+ "id": ID++
123
+ },
124
+ {
125
+ "@T": "C2",
126
+ "action": "UNSUBSCRIBE",
127
+ "symbols": ["AAPL"],
128
+ "types": ["TRADE"],
129
+ "mimetype": "application/json",
130
+ "conflation": null,
131
+ "id": ID++
132
+ },
133
+ {
134
+ "@T": "C2",
135
+ "action": "UNSUBSCRIBE",
136
+ "symbols": ["MSFT"],
137
+ "types": ["PRICEDATA"],
138
+ "mimetype": "application/json",
139
+ "conflation": null,
140
+ "id": ID++
141
+ }
142
+ ];
143
+
144
+ // Lager symbol lists with 200 symbols
145
+ var symbolLists = [
146
+ "A", "AA", "AAAU", "AACG", "AADR", "AAL", "AAMC", "AAME", "AAN", "AAOI", "AAP", "AAPL", "AAT", "AAU", "AAWW", "AAXJ", "AAXN", "AB", "ABB", "ABBV",
147
+ "ABC", "ABCB", "ABDC", "ABEO", "ABEV", "ABG", "ABIO", "ABM", "ABMD", "ABR", "ABT", "ABTX", "ABUS", "AC", "ACA", "ACAD", "ACAM", "ACB", "ACBI", "ACC",
148
+ "ACCO", "ACEL", "ACER", "ACES", "ACGL", "ACH", "ACHC", "ACHN", "ACHV", "ACIA", "ACIO", "ACIU", "ACIW", "ACLS", "ACM", "ACMR", "ACN", "ACNB", "ACOR", "ACP",
149
+ "ACRE", "ACRS", "ACRX", "ACSI", "ACST", "ACT", "ACTG", "ACTT", "ACTTU", "ACU", "ACV", "ACWF", "ACWI", "ACWV", "ACWX", "ACY", "ADAP", "ADBE", "ADC", "ADES",
150
+ "ADI", "ADIL", "ADM", "ADMA", "ADME", "ADMP", "ADMS", "ADNT", "ADP", "ADPT", "ADRA", "ADRD", "ADRE", "ADRO", "ADS", "ADSK", "ADSW", "ADT", "ADTN", "NIO",
151
+ "AMD", "CHK", "BAC", "EEM", "NK", "SDC", "MNK", "WFC", "MS", "F", "QD", "NOK", "SPY", "XLF", "MNI", "SIG", "SNAP", "FPAC", "GE", "VXX",
152
+ "T", "UBER", "FCEL", "GDX", "CETX", "TSLA", "MU", "XOP", "ITUP", "TEVA", "OGI", "IWM", "IAU", "CRON", "MRVL", "SWN", "JCP", "HYG", "TWTR", "TQQQ",
153
+ "FXI", "IEMG", "PINS", "SQQQ", "BBD", "MSFT", "CGC", "SPCE", "USO", "LK", "AMLP", "CMCSA", "PLUG", "HEXO", "PBR", "ECA", "BYND", "FCX", "EWZ", "DWT",
154
+ "QQQ", "CSCO", "RIG", "ZNGA", "NRZ", "VALE", "INTC", "ABEV", "BABA", "IAG", "AEMD", "DUST", "VWO", "ROKU", "UVXY", "BK", "AUY", "PFE", "ENDP", "CLVS",
155
+ "HTBX", "SAN", "MDR", "CTL", "TSM", "NUGT", "AMRN", "LQD", "RBZ", "USB", "IBIO", "SXTC", "APEX", "NLOK", "SIRI", "CSR", "ZYXI", "ZYNE", "ZYME", "ZVO"
156
+ ];
157
+
158
+ // Data types that Streamer available to make subscription
159
+ var dataTypes = [
160
+ // D1
161
+ // Market data message returns:
162
+ // {Q, timestamp, symbol, locateCode, indicator, sharesPerSizeUnit, bidPrice, bidSize, bidExcode, bidCondition, askPrice, askSize, askExcode, askCondition}
163
+ "QUOTE",
164
+ // D2
165
+ // Market data message returns:
166
+ // {P,timestamp, symbol, locateCode, last, lastTradeSize, change, percentChange, tick, tradeCount, close, previousClose,
167
+ // open, high, annualHigh, low, annualLow, lastTradeTime, accumulatedPrice, accumulatedVolume, accumulatedTradeValue,
168
+ // twap, vwap, preMarketTradeTime, preMarketLast, preMarketVolume, preMarketChange, preMarketPercentChange, postMarketTradeTime,
169
+ // postMarketLast, postMarketVolume, postMarketChange, postMarketPercentChange, lastTradeExcode, currencyID}
170
+ "PRICEDATA",
171
+ // D3
172
+ // Market data message returns:
173
+ // {T, timestamp, symbol, locateCode, excode, sequenceNumber, matchID, price, size, tick, indicator, rangeIndicator, sellerID, buyerID, accumulatedVolume, vwap}
174
+ "TRADE",
175
+ // D4
176
+ // Market data message returns:
177
+ // {BO, timestamp, symbol, locateCode, excode, orderID, orderReference, marketMakerID, orderSide, lastUpdate, price, size, display, orderChangeType}
178
+ "ORDERBOOK",
179
+ // D7
180
+ // Market data message returns:
181
+ // {MMQ, timestamp, symbol, locateCode, bidPrice, bidSize, bidChange, askPrice, askSize, askChange, indicator, marketMakerID, sharesPerSizeUnit}
182
+ "MMQUOTE",
183
+ // D8
184
+ // Market data message returns:
185
+ // {I, timestamp, symbol, locateCode, last, lastTime, open, openTime, high, low, startTime, tradeValue, volume, vwap}
186
+ "INTERVAL",
187
+ // D9
188
+ // Market data message returns:
189
+ // {NHP, timestamp, symbol, locateCode, marketMakerID, buyValue, buyVolume, buyBlockTransactions, buyBlockValue, buyBlockVolume, sellValue, sellVolume,
190
+ // sellBlockTransactions, sellBlockValue, sellBlockVolume}
191
+ "NETHOUSEPOSITION",
192
+ // D13
193
+ // Market data message returns:
194
+ // {LS, timestamp, symbol, locateCode, last, change, percentChange, accumulatedVolume, tick, lastTradeExcode}
195
+ "LASTSALE",
196
+ // D14
197
+ // Market data message returns:
198
+ // {LULD, symbol, locateCode, effectiveTime, lowerLimit, upperLimit, bidNotExecutable, askNotExecutable}
199
+ "LIMITUPLIMITDOWN",
200
+ // D15
201
+ // Market data message returns:
202
+ // {IVG, lastCalculation, symbol, locateCode, delta, gamma, vega, rho, theta, midIV, midIVChange, bidIV, askIV, mark, intrinsicValue, extrinsicValue,
203
+ // previousMark, markChange, markChangePercent}
204
+ "IVGREEKS",
205
+ // D16
206
+ // Market data message returns:
207
+ // {IS, timestamp, symbol, locateCode, imbalanceType, referencePrice, size, side, pairedVolume, nearIndicativePrice, farIndicativePrice, priceVariation}
208
+ "IMBALANCESTATUS"
209
+ ];
210
+
211
+ const headers = {
212
+ // This header is optional we could use
213
+ 'X-Stream-Format': 'application/json'
214
+ };
215
+
216
+ /** We could use following auth method to make subscription with streaming data
217
+ * Sid
218
+ * Enterprise Token
219
+ * Wmid
220
+ */
221
+
222
+ /** For the Sid User we need to use qmci.Streamer library to get the sid first, then use the sid for login Auth */
223
+ function getSid() {
224
+ Streamer.login({
225
+ host: 'https://app.quotemedia.com/auth',
226
+ credentials: {
227
+ wmid: "YourWebmasterID",
228
+ username: "YourUsername",
229
+ password: "YourPassword"
230
+ }
231
+ }, (err, sid) => {
232
+ if (err) {
233
+ console.error(err);
234
+ } else if (sid) {
235
+ SID = sid;
236
+ console.log("SID: ", SID);
237
+ }
238
+ });
239
+ }
240
+
241
+ /** Sid User example we need to get the sid before to run this example */
242
+ function SidUserSubscription() {
243
+ if (SID == null) {
244
+ console.log("SID is invalid: ", SID);
245
+ return;
246
+ }
247
+
248
+ if (stompClient == null || stompClient.ws.readyState === 3) {
249
+ stompClient = Stomp.client(url);
250
+ SidAuthMethod(SID, stompClient, headers);
251
+ }
252
+
253
+ /** Subscription Examples: Start */
254
+ /** To see the example result by uncomment the code */
255
+ const selectedExample = document.getElementById("sid_user_subscription_example").value;
256
+
257
+ if (selectedExample === "subscribe") {
258
+ subscribe(stompClient, headers);
259
+ }
260
+
261
+ if (selectedExample === "subscribeMultiDataTypes") {
262
+ subscribeMultiDataTypes(stompClient, headers);
263
+ }
264
+
265
+ if (selectedExample === "subscribeMultiSymbolsMultiDataTypes") {
266
+ subscribeMultiSymbolsMultiDataTypes(stompClient, headers);
267
+ }
268
+
269
+ if (selectedExample === "subscribeMultiMessages") {
270
+ subscribeMultiMessages(stompClient, headers, msgArrSubList);
271
+ }
272
+
273
+ if (selectedExample === "subscribeLargerSymbolLists") {
274
+ subscribeLargerSymbolLists(stompClient, headers, symbolLists, dataTypes);
275
+ }
276
+
277
+ if (selectedExample === "subscribeExchange") {
278
+ subscribeExchange(stompClient, headers);
279
+ }
280
+ /** Subscription Examples: End */
281
+ }
282
+
283
+ function SidUserUnsubscribe() {
284
+ const selectedExample = document.getElementById("sid_user_subscription_example").value;
285
+ if (selectedExample === "subscribe") {
286
+ unsubscribe(stompClient, headers);
287
+ }
288
+
289
+ if (selectedExample === "subscribeMultiDataTypes") {
290
+ unsubscribeMultiDataTypes(stompClient, headers);
291
+ }
292
+
293
+ if (selectedExample === "subscribeMultiSymbolsMultiDataTypes") {
294
+ unsubscribeMultiSymbolsMultiDataTypes(stompClient, headers);
295
+ }
296
+
297
+ if (selectedExample === "subscribeMultiMessages") {
298
+ unsubscribeMultiMessages(stompClient, headers, msgArrUnsubList);
299
+ }
300
+
301
+ if (selectedExample === "subscribeLargerSymbolLists") {
302
+ unsubscribeLargerSymbolLists(stompClient, headers, symbolLists, dataTypes);
303
+ }
304
+
305
+ if (selectedExample === "subscribeExchange") {
306
+ unsubscribeExchange(stompClient, headers);
307
+ }
308
+ }
309
+
310
+ /** Enterprise User example */
311
+ function EnterpriseUserSubscription() {
312
+ // Set up the Enterprise token and WebmasterID
313
+ const enterpriseToken = 'YourEnterpriseToken';
314
+ const wmid = 'YourWebmasterID';
315
+
316
+ if (stompClient == null || stompClient.ws.readyState === 3) {
317
+ stompClient = Stomp.client(url);
318
+ EnterpriseAuthMethod(enterpriseToken, wmid, stompClient, headers);
319
+ }
320
+
321
+ /** Subscription Examples: Start */
322
+ /** To see the example result by uncomment the code */
323
+ const selectedExample = document.getElementById("enterprise_user_subscription_example").value;
324
+
325
+ if (selectedExample === "subscribe") {
326
+ subscribe(stompClient, headers);
327
+ }
328
+
329
+ if (selectedExample === "subscribeMultiDataTypes") {
330
+ subscribeMultiDataTypes(stompClient, headers);
331
+ }
332
+
333
+ if (selectedExample === "subscribeMultiSymbolsMultiDataTypes") {
334
+ subscribeMultiSymbolsMultiDataTypes(stompClient, headers);
335
+ }
336
+ /** Subscription Examples: End */
337
+ }
338
+
339
+ function EnterpriseUserUnsubscribe() {
340
+ const selectedExample = document.getElementById("enterprise_user_subscription_example").value;
341
+ if (selectedExample === "subscribe") {
342
+ unsubscribe(stompClient, headers);
343
+ }
344
+
345
+ if (selectedExample === "subscribeMultiDataTypes") {
346
+ unsubscribeMultiDataTypes(stompClient, headers);
347
+ }
348
+
349
+ if (selectedExample === "subscribeMultiSymbolsMultiDataTypes") {
350
+ unsubscribeMultiSymbolsMultiDataTypes(stompClient, headers);
351
+ }
352
+ }
353
+
354
+ /** Wmid User example */
355
+ function WmidUserSubscription() {
356
+ // Set up the Wmid
357
+ const wmid = 'YourWebmasterID';
358
+
359
+ if (stompClient == null || stompClient.ws.readyState === 3) {
360
+ stompClient = Stomp.client(url);
361
+ WmidAuthMethod(wmid, stompClient, headers);
362
+ }
363
+
364
+ /** Subscription Examples: Start */
365
+ /** To see the example result by uncomment the code */
366
+ const selectedExample = document.getElementById("wmid_user_subscription_example").value;
367
+
368
+ if (selectedExample === "subscribe") {
369
+ subscribe(stompClient, headers);
370
+ }
371
+
372
+ if (selectedExample === "subscribeMultiDataTypes") {
373
+ subscribeMultiDataTypes(stompClient, headers);
374
+ }
375
+
376
+ if (selectedExample === "subscribeMultiSymbolsMultiDataTypes") {
377
+ subscribeMultiSymbolsMultiDataTypes(stompClient, headers);
378
+ }
379
+ /** Subscription Examples: End */
380
+ }
381
+
382
+ function WmidUserUnsubscribe() {
383
+ const selectedExample = document.getElementById("wmid_user_subscription_example").value;
384
+ if (selectedExample === "subscribe") {
385
+ unsubscribe(stompClient, headers);
386
+ }
387
+
388
+ if (selectedExample === "subscribeMultiDataTypes") {
389
+ unsubscribeMultiDataTypes(stompClient, headers);
390
+ }
391
+
392
+ if (selectedExample === "subscribeMultiSymbolsMultiDataTypes") {
393
+ unsubscribeMultiSymbolsMultiDataTypes(stompClient, headers);
394
+ }
395
+ }
396
+
397
+ /** To build Sid Auth message */
398
+ function SidAuthMethod(authorization, stompClient, headers = {}) {
399
+ if (stompClient.ws.readyState === 0) {
400
+ authMessage = BuildAuthMessage("sid", authorization);
401
+
402
+ stompClient.connect({}, function(frame) {
403
+ stompClient.subscribe(STOMP_SUBSCRIBE_URL, function(responseMessage) {
404
+ responseMsgHandler(JSON.parse(responseMessage.body))
405
+ });
406
+ stompClient.send(STOMP_SEND_MESSAGE_URL, headers, JSON.stringify(authMessage));
407
+ });
408
+ }
409
+ }
410
+
411
+ /** To build Enterprise Auth message */
412
+ function EnterpriseAuthMethod(authorization, wmid, stompClient, headers = {}) {
413
+ if (stompClient.ws.readyState === 0) {
414
+ authMessage = BuildAuthMessage("enterprise", authorization, wmid);
415
+
416
+ stompClient.connect({}, function(frame) {
417
+ stompClient.subscribe(STOMP_SUBSCRIBE_URL, function(responseMessage) {
418
+ responseMsgHandler(JSON.parse(responseMessage.body))
419
+ });
420
+ stompClient.send(STOMP_SEND_MESSAGE_URL, headers, JSON.stringify(authMessage));
421
+ });
422
+ }
423
+ }
424
+
425
+ /** To build Wmid Auth message */
426
+ function WmidAuthMethod(authorization, stompClient, headers = {}) {
427
+ if (stompClient.ws.readyState === 0) {
428
+ authMessage = BuildAuthMessage("wmid", authorization);
429
+
430
+ stompClient.connect({}, function(frame) {
431
+ stompClient.subscribe(STOMP_SUBSCRIBE_URL, function(responseMessage) {
432
+ responseMsgHandler(JSON.parse(responseMessage.body))
433
+ });
434
+ stompClient.send(STOMP_SEND_MESSAGE_URL, headers, JSON.stringify(authMessage));
435
+ });
436
+ }
437
+ }
438
+
439
+ /**
440
+ *
441
+ * @param action {string}
442
+ * @param symbols {Array.<string>}
443
+ * @param types {Array.<string>}
444
+ * @param mimetype {string}
445
+ * @param conflation {int}
446
+ * @param id {int}
447
+ * @returns {boolean|{"@T": string, action, symbols, types, mimetype, conflation, id}}
448
+ */
449
+ function buildMarketDataMsg(action, symbols, types, mimetype, conflation, id) {
450
+ if (maxEntitlementsPerSubscription <= 0 && maxEntitlementsPerSubscription < symbols.length) {
451
+ return false;
452
+ }
453
+ console.log("The sub/unsub symbols size is: ", symbols.length);
454
+
455
+ const msg = {
456
+ "@T": "C2",
457
+ "action": action,
458
+ "symbols": symbols,
459
+ "types": types,
460
+ "mimetype": mimetype,
461
+ "conflation": conflation,
462
+ "id": id
463
+ }
464
+ return msg;
465
+ }
466
+
467
+ /** Subscription with one symbol and one data type */
468
+ function subscribe(stompClient, headers = {}) {
469
+ if (stompClient.ws.readyState === 1) {
470
+ msg = buildMarketDataMsg("SUBSCRIBE", ["GOOG"], ["QUOTE"], "application/json", null, ID++)
471
+ if (msg != false) {
472
+ stompClient.send(STOMP_SEND_MESSAGE_URL, headers, JSON.stringify(msg));
473
+ }
474
+ } else {
475
+ setTimeout(subscribe, 1000, stompClient, headers);
476
+ }
477
+ }
478
+
479
+ function unsubscribe(stompClient, headers = {}) {
480
+ if (stompClient.ws.readyState === 1) {
481
+ msg = buildMarketDataMsg("UNSUBSCRIBE", ["GOOG"], ["QUOTE"], "application/json", null, ID++)
482
+ stompClient.send(STOMP_SEND_MESSAGE_URL, headers, JSON.stringify(msg));
483
+ }
484
+ }
485
+
486
+ /** Subscription with one symbol and multiple data types */
487
+ function subscribeMultiDataTypes(stompClient, headers = {}) {
488
+ if (stompClient.ws.readyState === 1) {
489
+ msg = buildMarketDataMsg("SUBSCRIBE", ["GOOG"], ["QUOTE", "TRADE"], "application/json", null, ID++)
490
+ stompClient.send(STOMP_SEND_MESSAGE_URL, headers, JSON.stringify(msg));
491
+ } else {
492
+ setTimeout(subscribeMultiDataTypes, 1000, stompClient, headers);
493
+ }
494
+ }
495
+
496
+ function unsubscribeMultiDataTypes(stompClient, headers = {}) {
497
+ if (stompClient.ws.readyState === 1) {
498
+ msg = buildMarketDataMsg("UNSUBSCRIBE", ["GOOG"], ["QUOTE", "TRADE"], "application/json", null, ID++)
499
+ stompClient.send(STOMP_SEND_MESSAGE_URL, headers, JSON.stringify(msg));
500
+ }
501
+ }
502
+
503
+ /** Subscription with multiple symbols and multiple data types */
504
+ function subscribeMultiSymbolsMultiDataTypes(stompClient, headers = {}) {
505
+ if (stompClient.ws.readyState === 1) {
506
+ msg = buildMarketDataMsg("SUBSCRIBE", ["GOOG", "AAPL"], ["QUOTE", "TRADE"], "application/json", null, ID++)
507
+ stompClient.send(STOMP_SEND_MESSAGE_URL, headers, JSON.stringify(msg));
508
+ } else {
509
+ setTimeout(subscribeMultiSymbolsMultiDataTypes, 1000, stompClient, headers);
510
+ }
511
+ }
512
+
513
+ function unsubscribeMultiSymbolsMultiDataTypes(stompClient, headers = {}) {
514
+ if (stompClient.ws.readyState === 1) {
515
+ msg = buildMarketDataMsg("UNSUBSCRIBE", ["GOOG", "AAPL"], ["QUOTE", "TRADE"], "application/json", null, ID++)
516
+ stompClient.send(STOMP_SEND_MESSAGE_URL, headers, JSON.stringify(msg));
517
+ }
518
+ }
519
+
520
+ /** Subscription to loop a lists contains multiple subscription request messages */
521
+ function subscribeMultiMessages(stompClient, headers = {}, msgArr) {
522
+ if (stompClient.ws.readyState === 1) {
523
+ for (let i = 0; i < msgArr.length; i++) {
524
+ stompClient.send(STOMP_SEND_MESSAGE_URL, headers, JSON.stringify(msgArr[i]));
525
+ }
526
+ } else {
527
+ setTimeout(subscribeMultiMessages, 1000, stompClient, headers, msgArr);
528
+ }
529
+ }
530
+
531
+ function unsubscribeMultiMessages(stompClient, headers = {}, msgArr) {
532
+ if (stompClient.ws.readyState === 1) {
533
+ for (let i = 0; i < msgArr.length; i++) {
534
+ stompClient.send(STOMP_SEND_MESSAGE_URL, headers, JSON.stringify(msgArr[i]));
535
+ }
536
+ }
537
+ }
538
+
539
+ /** Subscription with larger symbol(200 symbols) lists and multiple data types */
540
+ function subscribeLargerSymbolLists(stompClient, headers = {}, symbolLists, dataTypes) {
541
+ if (stompClient.ws.readyState === 1) {
542
+ msg = buildMarketDataMsg("SUBSCRIBE", symbolLists, dataTypes, "application/json", null, ID++)
543
+ if (msg != false) {
544
+ stompClient.send(STOMP_SEND_MESSAGE_URL, headers, JSON.stringify(msg));
545
+ }
546
+ } else {
547
+ setTimeout(subscribeLargerSymbolLists, 1000, stompClient, headers, symbolLists, dataTypes);
548
+ }
549
+ }
550
+
551
+ function unsubscribeLargerSymbolLists(stompClient, headers = {}, symbolLists, dataTypes) {
552
+ if (stompClient.ws.readyState === 1) {
553
+ msg = buildMarketDataMsg("UNSUBSCRIBE", symbolLists, dataTypes, "application/json", null, ID++)
554
+ stompClient.send(STOMP_SEND_MESSAGE_URL, headers, JSON.stringify(msg));
555
+ }
556
+ }
557
+
558
+ /**
559
+ *
560
+ * @param action {string}
561
+ * @param exchange {string}
562
+ * @param mimetype {string}
563
+ * @param conflation {int}
564
+ * @param id {int}
565
+ * @returns
566
+ */
567
+ function buildExchangeMsg(action, exchange, mimetype, conflation, id) {
568
+ const msg = {
569
+ "@T": "C14",
570
+ "action": action,
571
+ "exchange": exchange,
572
+ "mimetype": mimetype,
573
+ "conflation": conflation,
574
+ "id": id
575
+ }
576
+ return msg;
577
+ }
578
+
579
+ /** Subscription for exchange */
580
+ function subscribeExchange(stompClient, headers = {}) {
581
+ if (stompClient.ws.readyState === 1) {
582
+ msg = buildExchangeMsg("SUBSCRIBE", "TSX", "application/json", null, ID++);
583
+ stompClient.send(STOMP_SEND_MESSAGE_URL, headers, JSON.stringify(msg));
584
+ } else {
585
+ setTimeout(subscribeExchange, 1000, stompClient, headers);
586
+ }
587
+ }
588
+
589
+ function unsubscribeExchange(stompClient, headers = {}) {
590
+ if (stompClient.ws.readyState === 1) {
591
+ msg = buildExchangeMsg("UNSUBSCRIBE", "TSX", "application/json", null, ID++);
592
+ stompClient.send(STOMP_SEND_MESSAGE_URL, headers, JSON.stringify(msg));
593
+ }
594
+ }
595
+
596
+ /** Disconnect the Stomp connection */
597
+ function disconnect() {
598
+ if (stompClient.ws.readyState === 1) {
599
+ stompClient.disconnect();
600
+ }
601
+ }
602
+
603
+ /** To listen and handle the message sent from Streaming server */
604
+ function responseMsgHandler(msg) {
605
+ // C5 is for connect response and here we are trying to get the max entitlements number,
606
+ // and this number is for maximum symbols allow for per subscription.
607
+ if (msg["@T"] === 'C5') {
608
+ maxEntitlementsPerSubscription = msg.maxEntitlementsPerSubscription;
609
+ console.log("The max ET number per subscription is: ", maxEntitlementsPerSubscription);
610
+ }
611
+ // C28 is for Flow Control message
612
+ // To control latency and in cases where client connections cannot keep up with the amount of streamed messages,
613
+ // there are mechanisms in place to limit negative effects from “slow” clients. These requirements MUST be
614
+ // implemented and adhered to on the client implementation, or else connections will be disconnected.
615
+ // When the client connection receives that message they must IMMEDIATELY respond back to the server with the
616
+ // exact same message, containing the same field and value.
617
+ else if (msg["@T"] === 'C28') {
618
+ if (stompClient.ws.readyState === 1) {
619
+ stompClient.send(STOMP_SEND_MESSAGE_URL, {}, JSON.stringify(msg));
620
+ }
621
+ }
622
+ // C3 is for subscribe response, it will return the status code and reason back to client,
623
+ // if the subscription is successfully server will return status code with 200
624
+ else if (msg["@T"] === 'C3') {
625
+ if (msg["code"] === 200) {
626
+ console.log("Subscription succeed!");
627
+ }
628
+ }
629
+ // C4 is for unsubscribe response, it will return the status code and reason back to client,
630
+ // if the unsubscription is successfully server will return status code with 200
631
+ else if (msg["@T"] === 'C4') {
632
+ if (msg["code"] === 200) {
633
+ console.log("Unsubscription succeed!");
634
+ }
635
+ }
636
+ // D1 is for Quote messages
637
+ else if (msg["@T"] === 'D1') {
638
+ const node = document.createElement("p").appendChild(document.createTextNode(JSON.stringify(msgfmt.fmt(msg))));
639
+ const brNode = document.createElement("br");
640
+ document.getElementById("msg_print").appendChild(node);
641
+ document.getElementById("msg_print").appendChild(brNode);
642
+ }
643
+ // D2 is for PriceData messages
644
+ else if (msg["@T"] === 'D2') {
645
+ const node = document.createElement("p").appendChild(document.createTextNode(JSON.stringify(msgfmt.fmt(msg))));
646
+ const brNode = document.createElement("br");
647
+ document.getElementById("msg_print").appendChild(node);
648
+ document.getElementById("msg_print").appendChild(brNode);
649
+ }
650
+ // D3 is for Trade messages
651
+ else if (msg["@T"] === 'D3') {
652
+ const node = document.createElement("p").appendChild(document.createTextNode(JSON.stringify(msgfmt.fmt(msg))));
653
+ const brNode = document.createElement("br");
654
+ document.getElementById("msg_print").appendChild(node);
655
+ document.getElementById("msg_print").appendChild(brNode);
656
+ }
657
+ // To catch other MarketData messages
658
+ else {
659
+ const node = document.createElement("p").appendChild(document.createTextNode(JSON.stringify(msgfmt.fmt(msg))));
660
+ const brNode = document.createElement("br");
661
+ document.getElementById("msg_print").appendChild(node);
662
+ document.getElementById("msg_print").appendChild(brNode);
663
+ }
664
+ }
665
+
666
+ /** To build the Auth Message, if using enterprise authenticationMethod,
667
+ * and we need to set the wmid otherwise we could default and set it to null */
668
+ function BuildAuthMessage(authenticationMethod, authorization, wmid = null, conflation = null, rejectExcessiveConnection = false) {
669
+ var authMessage = {
670
+ '@T': 'C27',
671
+ 'authenticationMethod': authenticationMethod,
672
+ 'authorization': authorization,
673
+ 'wmid': wmid,
674
+ 'conflation': conflation,
675
+ 'rejectExcessiveConnection': rejectExcessiveConnection
676
+ };
677
+ return authMessage;
678
+ }
679
+ </script>
680
+ </body>
681
+
682
682
  </html>