Overview
PriceSignal provides real-time price updates through GraphQL subscriptions using the WebSocket protocol. This allows your application to receive live market data as prices change, without polling.
WebSocket Endpoint
Connect to the WebSocket endpoint at:
wss://api.pricesignal.com/graphql
The same endpoint (/graphql) is used for both HTTP and WebSocket connections. The server automatically detects the protocol.
Connection Setup
The API uses the graphql-ws protocol (WebSocket subprotocol graphql-transport-ws).
Step 1: Enable WebSockets
The server has WebSockets enabled in Program.cs:159:
app . UseWebSockets ();
app . MapGraphQL ();
PriceSignal uses HotChocolate’s in-memory subscription provider:
. AddSubscriptionType ()
. AddInMemorySubscriptions ()
This handles subscription lifecycle and message delivery automatically.
Available Subscriptions
onPriceUpdated
Subscribe to real-time price updates for a specific cryptocurrency symbol.
The trading pair symbol (e.g., “BTCUSDT”, “ETHUSDT”)
Real-time price candle data Opening price for the candle
Highest price during the candle period
Lowest price during the candle period
Timestamp of the price candle
Exchange name (e.g., “BINANCE”)
Client Implementation
Using graphql-ws (Recommended)
Basic Connection
React Hook
import { createClient } from 'graphql-ws' ;
import { getAuth } from 'firebase/auth' ;
const client = createClient ({
url: 'wss://api.pricesignal.com/graphql' ,
connectionParams : async () => {
const auth = getAuth ();
const token = await auth . currentUser ?. getIdToken ();
return {
Authorization: `Bearer ${ token } `
};
}
});
// Subscribe to Bitcoin price updates
const unsubscribe = client . subscribe (
{
query: `
subscription OnBitcoinPrice {
onPriceUpdated(symbol: "BTCUSDT") {
symbol
close
high
low
volume
bucket
}
}
`
},
{
next : ( data ) => {
console . log ( 'Price update:' , data );
},
error : ( error ) => {
console . error ( 'Subscription error:' , error );
},
complete : () => {
console . log ( 'Subscription completed' );
}
}
);
// Cleanup when done
// unsubscribe();
Using Apollo Client
Apollo Setup
Apollo Subscription Hook
import { ApolloClient , InMemoryCache , HttpLink , split } from '@apollo/client' ;
import { GraphQLWsLink } from '@apollo/client/link/subscriptions' ;
import { getMainDefinition } from '@apollo/client/utilities' ;
import { createClient } from 'graphql-ws' ;
import { getAuth } from 'firebase/auth' ;
const httpLink = new HttpLink ({
uri: 'https://api.pricesignal.com/graphql'
});
const wsLink = new GraphQLWsLink (
createClient ({
url: 'wss://api.pricesignal.com/graphql' ,
connectionParams : async () => {
const auth = getAuth ();
const token = await auth . currentUser ?. getIdToken ();
return { Authorization: `Bearer ${ token } ` };
}
})
);
const splitLink = split (
({ query }) => {
const definition = getMainDefinition ( query );
return (
definition . kind === 'OperationDefinition' &&
definition . operation === 'subscription'
);
},
wsLink ,
httpLink
);
export const client = new ApolloClient ({
link: splitLink ,
cache: new InMemoryCache ()
});
How It Works
The subscription implementation in PriceSignal:
Client subscribes to onPriceUpdated with a specific symbol
Server creates a stream filtered by the requested symbol
Background service (BinancePriceFetcherService) publishes price updates to the event topic
Subscription resolver receives events and filters by symbol
Matching prices are pushed to the client in real-time
From PriceSubscriptions.cs:14-37:
public async IAsyncEnumerable < Price > SubscribeToUpdates (
[ Service ] ITopicEventReceiver eventReceiver ,
string symbol ,
[ EnumeratorCancellation ] CancellationToken cancellationToken )
{
var stream = await eventReceiver . SubscribeAsync < Price >(
nameof ( OnPriceUpdated ), cancellationToken );
await foreach ( var price in stream . ReadEventsAsync ()
. WithCancellation ( cancellationToken ))
{
if ( price . Symbol != symbol ) continue ;
yield return price ;
}
}
Multiple Subscriptions
You can subscribe to multiple symbols simultaneously:
const subscriptions = [ 'BTCUSDT' , 'ETHUSDT' , 'BNBUSDT' ]. map ( symbol =>
client . subscribe (
{
query: `
subscription OnPriceUpdated($symbol: String!) {
onPriceUpdated(symbol: $symbol) {
symbol
close
bucket
}
}
` ,
variables: { symbol }
},
{
next : ( data ) => console . log ( ` ${ symbol } update:` , data )
}
)
);
// Cleanup all subscriptions
subscriptions . forEach ( unsub => unsub ());
Supported Symbols
The API currently supports Binance trading pairs. Common symbols include:
BTCUSDT - Bitcoin/USDT
ETHUSDT - Ethereum/USDT
Use the GraphQL instruments query to get the full list of available symbols:
query GetInstruments {
instruments {
symbol
name
exchange
}
}
Error Handling
Always implement proper error handling for network issues, authentication failures, and subscription termination.
Common Errors
Check your WebSocket URL and network connectivity
Verify your Firebase JWT token is valid and included in connection parameters
The server may have restarted or the token expired. Implement reconnection logic.
Reconnection Strategy
import { createClient } from 'graphql-ws' ;
const client = createClient ({
url: 'wss://api.pricesignal.com/graphql' ,
connectionParams : async () => {
const token = await getAuth (). currentUser ?. getIdToken ();
return { Authorization: `Bearer ${ token } ` };
},
retryAttempts: 5 ,
retryWait : async ( retries ) => {
await new Promise ( resolve =>
setTimeout ( resolve , Math . min ( 1000 * 2 ** retries , 30000 ))
);
},
on: {
connected : () => console . log ( 'WebSocket connected' ),
closed : () => console . log ( 'WebSocket closed' ),
error : ( error ) => console . error ( 'WebSocket error:' , error )
}
});
Limit concurrent subscriptions - Each subscription maintains a server-side stream
Unsubscribe when done - Always clean up subscriptions in component unmount
Use connection pooling - Reuse the same WebSocket client for multiple subscriptions
Monitor memory usage - Long-running subscriptions can accumulate data in client cache
Testing Subscriptions
You can test subscriptions using tools like:
GraphQL Playground - Built into the development server
Postman - Supports GraphQL subscriptions
graphql-ws CLI - Command-line subscription testing
Next Steps
GraphQL API Overview Learn about queries and mutations
Authentication Understand how to secure your WebSocket connections