SignalR Overview
The ProjectX SignalR (WebSocket) API provides real-time access to data updates involving accounts, orders, positions, and balances at your firm. This is useful if you want to update your CRM, trader dashboards or internal monitoring tools with real-time updates. You can also use this data to update account status.
This data updates very frequently. It is strongly advised to have proper backend handling to account for the amount of incoming updates.
What is SignalR?
SignalR is a real-time web application framework developed by Microsoft that simplifies the process of adding real-time functionality to web applications. It allows for bidirectional communication between clients (such as web browsers) and servers, enabling features like live chat, notifications, and real-time updates without the need for constant client-side polling or manual handling of connections.
SignalR abstracts away the complexities of real-time communication by providing high-level APIs for developers. It supports various transport protocols, including WebSockets, Server-Sent Events (SSE), Long Polling, and others, automatically selecting the most appropriate transport mechanism based on the capabilities of the client and server.
The framework handles connection management, message routing, and scaling across multiple servers, making it easier for developers to build scalable and responsive web applications. SignalR is available for multiple platforms, including .NET and JavaScript, allowing developers to build real-time applications using their preferred programming languages and frameworks.
Further information on SignalR can be found here.
Example Usage
- JavaScript
- TypeScript
// Import the necessary modules from @microsoft/signalr
const { HubConnectionBuilder, HttpTransportType } = require('@microsoft/signalr');
// Function to set up and start the SignalR connection
function setupSignalRConnection() {
const userApiUrl = 'https://userapi-demo.s2f.projectx.com/hubs/admin?access_token=${s2fApi.token}`;
// Create the connection
const adminConnection = new HubConnectionBuilder()
.withUrl(userApiUrl, {
skipNegotiation: true,
transport: HttpTransportType.WebSockets,
accessTokenFactory: () => "YOUR_TOKEN_HERE", // Replace with your current JWT token
timeout: 10000 // Optional timeout
})
.withAutomaticReconnect()
.build();
// Start the connection
adminConnection.start()
.then(() => {
// Function to subscribe to the necessary events
const subscribe = () => {
adminConnection.invoke('SubscribeAccounts');
adminConnection.invoke('SubscribePositionUpdates');
adminConnection.invoke('SubscribeOrders');
adminConnection.invoke('SubscribeBalanceUpdates');
adminConnection.invoke('SubscribeTrades');
adminConnection.invoke('SubscribePositionPnlUpdates');
adminConnection.invoke('SubscribeDailyLossLimitUpdates'); //for MLL updates - only triggered when the MLL changes after initial value
adminConnection.invoke('SubscribeMaximumLossLimitUpdates'); //for DLL updates - only triggered when the DLL changes after intiial value
};
// Functions to unsubscribe, if needed
const unsubscribe = () => {
adminConnection.invoke('UnsubscribeAccounts');
adminConnection.invoke('UnsubscribePositionUpdates');
adminConnection.invoke('UnsubscribeOrders');
adminConnection.invoke('UnsubscribeBalanceUpdates');
adminConnection.invoke('UnsubscribeTrades');
adminConnection.invoke('UnsubscribePositionPnlUpdates');
adminConnection.invoke('UnsubscribeDailyLossLimitUpdates');
adminConnection.invoke('UnsubscribeMaximumLossLimitUpdates');
};
// Set up the event listeners
adminConnection.on('RealTimePosition', (data) => {
console.log('Received position update', data);
});
adminConnection.on('RealTimeOrder', (data) => {
console.log('Received order update', data);
});
adminConnection.on('RealTimeAccount', (data) => {
console.log('Received account update', data);
});
adminConnection.on('RealTimeTrade', (data) => {
console.log('Received trade data update', data);
});
adminConnection.on('RealTimeAccountBalanceUpdate', (data) => {
console.log('Received balance update', data);
});
adminConnection.on('RealTimePositionPnl', (data) => {
console.log('Received position pnl update', data);
});
adminConnection.on('RealTimeMll', (data) => {
console.log('Received position pnl update', data);
});
adminConnection.on('RealTimeDll', (data) => {
console.log('Received real time daily loss limit update', data);
});
adminConnection.on('RealTimeMll', (data) => {
console.log('Received real time maximum loss limit update', data);
});
// Subscribe to the events
subscribe();
// Handle reconnection
adminConnection.onreconnected((connectionId) => {
console.log('Admin Connection Reconnected');
subscribe();
});
})
.catch((err) => {
console.error('Error starting connection:', err);
});
}
// Call the function to set up and start the connection
setupSignalRConnection();
useEffect(() => {
const userApiUrl = `https://userapi-demo.s2f.projectx.com/hubs/admin/hubs/admin?access_token=${s2fApi.token}`;
const adminConnection = new HubConnectionBuilder()
.withUrl(userApiUrl, {
skipNegotiation: true,
transport: HttpTransportType.WebSockets,
accessTokenFactory: () => "YOUR_TOKEN_HERE", //this should return your current JWT token
timeout: 10000 //optional timeout
})
.withAutomaticReconnect()
.build();
adminConnection.start().then(() => {
const subscribe = () => {
adminConnection.invoke('SubscribeAccounts');
adminConnection.invoke('SubscribePositionUpdates');
adminConnection.invoke('SubscribeOrders');
adminConnection.invoke('SubscribeBalanceUpdates');
adminConnection.invoke('SubscribeTrades');
adminConnection.invoke('SubscribePositionPnlUpdates');
adminConnection.invoke('SubscribeDailyLossLimitUpdates'); //for MLL updates - only triggered when the MLL changes after initial value
adminConnection.invoke('SubscribeMaximumLossLimitUpdates'); //for DLL updates - only triggered when the DLL changes after intiial value
};
adminConnection.on('RealTimePosition', (data) => {
console.log('Received position update', data);
});
adminConnection.on('RealTimeOrder', (data) => {
console.log('Received order update', data);
});
adminConnection.on('RealTimeAccount', (data) => {
console.log('Received account update', data);
});
adminConnection.on('RealTimeTrade', (data) => {
console.log('Received trade data update', data);
});
adminConnection.on('RealTimeAccountBalanceUpdate', (data) => {
console.log('Received balance update', data);
});
adminConnection.on('RealTimePositionPnl', (data) => {
console.log('Received position pnl update', data);
});
adminConnection.on('RealTimeDll', (data) => {
console.log('Received Dll update', data);
});
adminConnection.on('RealTimeMll', (data) => {
console.log('Received Mll update', data);
});
//invoke the functions which start the data feeds
subscribe();
//if we get disconnected, we need to re-subscribe, however the events (with the on method) still remain.
adminConnection.onreconnected((connectionId) => {
console.log('Admin Connection Reconnected');
subscribe();
});
}
);