Stage 2: Websocket Management

Websocket connections are essential for real-time data streaming and order management in the Tradovate API. This stage validates your integration’s ability to maintain stable websocket connections and handle real-time events.

Overview

The websocket management stage ensures your application can:

  • Establish and maintain websocket connections
  • Handle authentication over websocket
  • Process real-time events and maintain idempotency
  • Manage connection heartbeats and reconnection logic
  • Handle rate limiting and synchronous requests

Required Tests

1. Websocket Login

Purpose: Authenticate websocket connection using access token.

Test Steps:

  1. Establish websocket connection to wss://demo.tradovateapi.com/v1/websocket
  2. Send authentication message with valid access token
  3. Verify successful authentication response
  4. Test with invalid/expired token to ensure proper error handling

Example Implementation:

1const ws = new WebSocket('wss://demo.tradovateapi.com/v1/websocket');
2
3ws.onopen = function() {
4 // Send authentication message
5 const authMessage = `authorize\n0\n\n${accessToken}`;
6 ws.send(authMessage);
7};
8
9ws.onmessage = function(event) {
10 const data = JSON.parse(event.data);
11 if (data.i === 0) {
12 // Authentication response
13 console.log('Authentication successful:', data);
14 }
15};

Expected Authentication Response:

1{
2 "i": 0,
3 "s": 200,
4}

Expected Error Response:

1{
2 "i": 0,
3 "s": 401,
4 "d": "Invalid access token"
5}

Validation Criteria:

  • ✅ Websocket connection establishes successfully
  • ✅ Authentication succeeds with valid token
  • ✅ Authentication fails with invalid token
  • ✅ Connection remains stable after authentication

2. Heartbeats

Purpose: Maintain connection health and detect disconnections.

Test Steps:

  1. Send periodic heartbeat messages
  2. Verify heartbeat responses are received
  3. Test heartbeat timeout scenarios
  4. Verify connection recovery after missed heartbeats

Example Implementation:

1// Track last message time
2let lastMessageTime = new Date().getTime();
3
4ws.onmessage = function(event) {
5 const timestamp = new Date().getTime();
6 if(timestamp - lastMessageTime > 2500) {
7 ws.send('[]'); // Empty frame is a heartbeat in our protocol
8 lastMessageTime = timestamp; // Update last message time
9 }
10 // carry on with message handling
11 // ...
12};

Validation Criteria:

  • ✅ Heartbeats are sent at regular intervals
  • ✅ Heartbeat mechanism works during high message volume

3. Event Handling

Purpose: Process real-time events from the websocket.

Test Steps:

  1. Manage real-time subscriptions
    • Start event streaming using user/syncrequest
    • subscribe to relevant entity types using the entityTypes parameter
  2. Process incoming events and maintain Idempotency

Example user/syncrequest:

1// Connect to the websocket
2const ws = new WebSocket('wss://demo.tradovateapi.com/v1/websocket');
3
4const requestBody = {
5 splitResponses: true,
6 // Optional, define sharding expression
7 shardingExpression: {
8 expressionType: 'modUserId', // | 'modAccountId'
9 divisor: 1, // each instance should have the same divisor
10 remainder: 0, // modulus of the ID of user or account to process on this instance
11 },
12 entityTypes: [
13 'account',
14 'accountRiskStatus',
15 'cashBalance',
16 'commandReport',
17 'command',
18 'executionReport',
19 'fill',
20 'fillPair',
21 'order',
22 'orderStrategy',
23 'position',
24 'product',
25 'user'
26 ],
27}
28
29ws.onopen = function() {
30 ws.send(`authorize\n0\n\n${accessToken}`);
31}
32
33ws.onmessage = function(event) {
34 const type = event.data.slice(0, 1);
35 let data = null;
36 if(type === 'a') {
37 data = JSON.parse(event.data.slice(1));
38 }
39 if(data.i === 0) {
40 // Authentication response
41 console.log('Authentication successful:', data);
42 // Send syncrequest
43 ws.send(`user/syncrequest\n1\n\n${JSON.stringify(requestBody)}`);
44 }
45}
46
47ws.onerror = function(event) {
48 console.error('WebSocket error:', event);
49}

Validation Criteria:

  • ✅ Only one syncrequest is sent per socket lifecycle.
  • ✅ Real-time events are received
  • ✅ Idempotency is maintained
  • ✅ Sharding is implemented correctly
  • ✅ Entity types are subscribed to correctly
  • ✅ Syncrequest is sent correctly
  • ✅ Event handlers are robust and don’t crash on malformed data
  • ✅ Message processing performance meets requirements

4. Rate Limit Handling (P-Ticket)

Purpose: Handle rate limiting and priority ticket system.

Test Steps:

  1. Send requests that trigger rate limiting
  2. Verify P-Ticket system responses
  3. Implement proper queuing and retry logic
  4. Test priority handling for different request types

Example Implementation:

1const send = requestData => {
2 return new Promise((res, rej) => {
3 let i = ++lastId;
4 let race = setTimeout(() => { reject(new Error('Request timeout'))}, 30000);
5 function handler(event) {
6 const type = event.data.slice(0, 1);
7 if(type === 'a') {
8 const data = JSON.parse(event.data.slice(1));
9 // data is always an array
10 for(const datum of data) {
11 if(datum.i === i) {
12 if(datum.d && 'p-ticket' in datum.d) {
13 const pTicket = datum.d['p-ticket'];
14 const pTime = datum.d['p-time'];
15 const pCaptcha = datum.d['p-captcha'];
16 if(pCaptcha) {
17 // Handle captcha, if you receive it you have been locked out for 1 hour
18 console.error('p-captcha received. Operations locked for 1 hour.');
19 return;
20 } else {
21 // Handle rate limiting with P-Ticket, resend the request
22 // with the p-ticket after p-time seconds.
23 setTimeout(() => {
24 send({
25 ...requestData,
26 body: { ...requestData.body, 'p-ticket': pTicket }
27 });
28 }, pTime * 1000);
29 ws.removeEventListener('message', handler);
30 }
31 } else {
32 clearTimeout(race);
33 res(datum.d);
34 ws.removeEventListener('message', handler);
35 }
36 }
37 }
38 }
39 }
40 // construct the message string
41 const queryString = requestData.query || ''
42 const bodyString = JSON.stringify(requestData.body || '')
43 const messageString = `${requestData.endpoint}\n${i}\n${queryString}\n${bodyString}`;
44 ws.addEventListener('message', handler);
45 ws.send(messageString);
46 });
47}

Validation Criteria:

  • ✅ Rate limiting responses are properly handled
  • ✅ P-Ticket system is implemented correctly

5. Reconnection

Purpose: Automatically reconnect after connection loss.

Test Steps:

  1. Simulate connection drops
  2. Verify automatic reconnection logic
  3. Test re-authentication after reconnection
  4. Verify state recovery after reconnection

Example Implementation:

1let lastMessageTime = new Date().getTime();
2
3ws.onmessage = async function(event) {
4 const timestamp = new Date().getTime();
5 if(timestamp - lastMessageTime > 15000) {
6 // connection has been idle for 15 seconds, reconnect
7 await reconnect();
8 }
9 lastMessageTime = timestamp;
10}

Validation Criteria:

  • ✅ Automatic reconnection works after connection loss
  • ✅ Re-authentication occurs after reconnection
  • ✅ State is properly recovered after reconnection

Error Handling

Your websocket implementation must handle:

Connection Errors

  • Network timeouts
  • DNS resolution failures
  • SSL/TLS handshake failures
  • Server unavailable errors

Authentication Errors

  • Invalid access tokens
  • Expired tokens during connection
  • Authentication timeout

Message Errors

  • Malformed JSON messages
  • Unknown message types
  • Invalid message parameters

Performance Requirements

  • Connection Time: Establish connection within 5 seconds
  • Authentication: Complete authentication within 2 seconds
  • Heartbeat: Send heartbeats every 30 seconds
  • Reconnection: Attempt reconnection within 10 seconds of disconnection
  • Message Processing: Process messages within 100ms

Testing Checklist

  • Websocket connection establishes successfully
  • Authentication works with valid tokens
  • Heartbeats are sent and received
  • Events are processed correctly
  • Idempotency is maintained
  • Rate limiting is handled properly
  • Syncrequests work as expected and are called only once per socket lifecycle
  • Reconnection works automatically
  • Error handling is robust

Next Steps

After completing Stage 2 websocket management tests, proceed to Stage 3: User Management.