betfair-exchange-api
Version:
A TypeScript client for the Betfair Exchange API
165 lines (164 loc) • 8.44 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
const stream_api_client_1 = require("./stream-api-client");
async function main() {
try {
// Replace with your app key and session token
const appKey = 'YOUR_APP_KEY';
const sessionToken = 'YOUR_SESSION_TOKEN';
// Create and connect the stream client
const streamClient = new stream_api_client_1.BetfairStreamClient(appKey, sessionToken);
// Event handlers
streamClient.on('connected', () => {
console.log('Connected to Betfair Stream API');
});
streamClient.on('disconnected', () => {
console.log('Disconnected from Betfair Stream API');
});
streamClient.on('error', (error) => {
console.error('Stream error:', error.message);
});
streamClient.on('connection', (connection) => {
console.log(`Connection established with ID: ${connection.connectionId}`);
});
streamClient.on('status', (status) => {
console.log(`Status: ${status.statusCode}${status.errorMessage ? ' - ' + status.errorMessage : ''}`);
// If authentication successful, subscribe to markets
if (status.id === 1 && status.statusCode === 'SUCCESS') {
console.log('Authentication successful, subscribing to markets...');
// Example: Subscribe to Horse Racing markets (eventTypeId: 7)
streamClient.subscribeToMarkets({
eventTypeIds: ['7'], // Horse Racing
marketTypes: ['WIN'], // Win markets only
}, {
fields: ['EX_BEST_OFFERS', 'EX_TRADED', 'EX_MARKET_DEF'],
ladderLevels: 3,
}, 1000, // conflateMs - conflation rate in milliseconds
5000 // heartbeatMs - heartbeat interval in milliseconds
);
// Also subscribe to orders
streamClient.subscribeToOrders({
includeOverallPosition: true,
}, 1000, // conflateMs
5000 // heartbeatMs
);
}
});
streamClient.on('marketChange', (marketChange) => {
console.log(`Market change received: ${marketChange.ct}`);
// Process market data
if (marketChange.mc && marketChange.mc.length > 0) {
marketChange.mc.forEach(market => {
console.log(`Market ID: ${market.id}`);
// Market definition (when available)
if (market.marketDefinition) {
console.log(` Status: ${market.marketDefinition.status}`);
console.log(` In play: ${market.marketDefinition.inPlay}`);
console.log(` Market time: ${market.marketDefinition.marketTime}`);
if (market.marketDefinition.runners) {
console.log(' Runners:');
market.marketDefinition.runners.forEach(runner => {
console.log(` ID: ${runner.id}, Status: ${runner.status}`);
});
}
}
// Runner changes
if (market.rc && market.rc.length > 0) {
console.log(' Runner changes:');
market.rc.forEach(runner => {
console.log(` Runner ID: ${runner.id}`);
// Best available to back
if (runner.batb && runner.batb.length > 0) {
console.log(' Best available to back:');
runner.batb.forEach(([level, price, size]) => {
console.log(` Level ${level}: ${price} @ ${size}`);
});
}
// Best available to lay
if (runner.batl && runner.batl.length > 0) {
console.log(' Best available to lay:');
runner.batl.forEach(([level, price, size]) => {
console.log(` Level ${level}: ${price} @ ${size}`);
});
}
// Last traded price
if (runner.ltp !== undefined) {
console.log(` Last traded price: ${runner.ltp}`);
}
// Traded volume
if (runner.tv !== undefined) {
console.log(` Traded volume: ${runner.tv}`);
}
});
}
});
}
});
streamClient.on('orderChange', (orderChange) => {
console.log(`Order change received: ${orderChange.ct}`);
// Process order data
if (orderChange.oc && orderChange.oc.length > 0) {
orderChange.oc.forEach(order => {
console.log(`Market ID: ${order.id}`);
// Process runner changes
if (order.orc && order.orc.length > 0) {
order.orc.forEach(runnerOrder => {
console.log(` Runner ID: ${runnerOrder.id}`);
// Unmatched orders
if (runnerOrder.uo && runnerOrder.uo.length > 0) {
console.log(' Unmatched orders:');
runnerOrder.uo.forEach(unmatchedOrder => {
console.log(` Order ID: ${unmatchedOrder.id}`);
console.log(` Side: ${unmatchedOrder.side === 'B' ? 'Back' : 'Lay'}`);
console.log(` Price: ${unmatchedOrder.p}`);
console.log(` Size: ${unmatchedOrder.s}`);
console.log(` Status: ${unmatchedOrder.status === 'E' ? 'Executable' : 'Execution Complete'}`);
console.log(` Matched: ${unmatchedOrder.sm}`);
console.log(` Remaining: ${unmatchedOrder.sr}`);
});
}
// Matched backs
if (runnerOrder.mb && runnerOrder.mb.length > 0) {
console.log(' Matched backs:');
runnerOrder.mb.forEach(([price, size]) => {
console.log(` ${price} @ ${size}`);
});
}
// Matched lays
if (runnerOrder.ml && runnerOrder.ml.length > 0) {
console.log(' Matched lays:');
runnerOrder.ml.forEach(([price, size]) => {
console.log(` ${price} @ ${size}`);
});
}
});
}
});
}
});
// Connect to the stream
console.log('Connecting to Betfair Stream API...');
streamClient.connect();
// Keep the process running
console.log('Press Ctrl+C to exit');
// Simple heartbeat mechanism to keep connection alive
// (should be run every few minutes, not seconds as we're doing here for demonstration)
const heartbeatInterval = setInterval(() => {
if (streamClient.isAuthenticated()) {
console.log('Sending heartbeat...');
streamClient.sendHeartbeat();
}
}, 30000); // Send heartbeat every 30 seconds
// Handle process termination
process.on('SIGINT', () => {
console.log('Disconnecting...');
clearInterval(heartbeatInterval);
streamClient.disconnect();
process.exit(0);
});
}
catch (error) {
console.error('Error:', error.message);
}
}
main();