betfair-exchange-api
Version:
A TypeScript client for the Betfair Exchange API
510 lines (509 loc) • 23 kB
JavaScript
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.BetfairClient = exports.HeartbeatAPI = exports.AccountsAPI = exports.BettingAPI = exports.BetfairApiBase = exports.ActionPerformed = exports.Wallet = exports.IncludeItem = exports.SubscriptionStatus = exports.TimeGranularity = exports.GroupBy = exports.BetStatus = exports.BetTargetType = exports.TimeInForce = exports.PersistenceType = exports.OrderType = exports.Side = exports.OrderProjection = exports.MatchProjection = exports.PriceData = exports.MarketSort = exports.MarketProjection = exports.OrderStatus = exports.MarketBettingType = void 0;
const axios_1 = __importDefault(require("axios"));
const https_1 = __importDefault(require("https"));
var MarketBettingType;
(function (MarketBettingType) {
MarketBettingType["ODDS"] = "ODDS";
MarketBettingType["LINE"] = "LINE";
MarketBettingType["RANGE"] = "RANGE";
MarketBettingType["ASIAN_HANDICAP_DOUBLE_LINE"] = "ASIAN_HANDICAP_DOUBLE_LINE";
MarketBettingType["ASIAN_HANDICAP_SINGLE_LINE"] = "ASIAN_HANDICAP_SINGLE_LINE";
MarketBettingType["FIXED_ODDS"] = "FIXED_ODDS";
})(MarketBettingType || (exports.MarketBettingType = MarketBettingType = {}));
var OrderStatus;
(function (OrderStatus) {
OrderStatus["PENDING"] = "PENDING";
OrderStatus["EXECUTION_COMPLETE"] = "EXECUTION_COMPLETE";
OrderStatus["EXECUTABLE"] = "EXECUTABLE";
OrderStatus["EXPIRED"] = "EXPIRED";
})(OrderStatus || (exports.OrderStatus = OrderStatus = {}));
var MarketProjection;
(function (MarketProjection) {
MarketProjection["COMPETITION"] = "COMPETITION";
MarketProjection["EVENT"] = "EVENT";
MarketProjection["EVENT_TYPE"] = "EVENT_TYPE";
MarketProjection["MARKET_START_TIME"] = "MARKET_START_TIME";
MarketProjection["MARKET_DESCRIPTION"] = "MARKET_DESCRIPTION";
MarketProjection["RUNNER_DESCRIPTION"] = "RUNNER_DESCRIPTION";
MarketProjection["RUNNER_METADATA"] = "RUNNER_METADATA";
})(MarketProjection || (exports.MarketProjection = MarketProjection = {}));
var MarketSort;
(function (MarketSort) {
MarketSort["MINIMUM_TRADED"] = "MINIMUM_TRADED";
MarketSort["MAXIMUM_TRADED"] = "MAXIMUM_TRADED";
MarketSort["MINIMUM_AVAILABLE"] = "MINIMUM_AVAILABLE";
MarketSort["MAXIMUM_AVAILABLE"] = "MAXIMUM_AVAILABLE";
MarketSort["FIRST_TO_START"] = "FIRST_TO_START";
MarketSort["LAST_TO_START"] = "LAST_TO_START";
})(MarketSort || (exports.MarketSort = MarketSort = {}));
var PriceData;
(function (PriceData) {
PriceData["SP_AVAILABLE"] = "SP_AVAILABLE";
PriceData["SP_TRADED"] = "SP_TRADED";
PriceData["EX_BEST_OFFERS"] = "EX_BEST_OFFERS";
PriceData["EX_ALL_OFFERS"] = "EX_ALL_OFFERS";
PriceData["EX_TRADED"] = "EX_TRADED";
})(PriceData || (exports.PriceData = PriceData = {}));
var MatchProjection;
(function (MatchProjection) {
MatchProjection["NO_ROLLUP"] = "NO_ROLLUP";
MatchProjection["ROLLED_UP_BY_PRICE"] = "ROLLED_UP_BY_PRICE";
MatchProjection["ROLLED_UP_BY_AVG_PRICE"] = "ROLLED_UP_BY_AVG_PRICE";
})(MatchProjection || (exports.MatchProjection = MatchProjection = {}));
var OrderProjection;
(function (OrderProjection) {
OrderProjection["ALL"] = "ALL";
OrderProjection["EXECUTABLE"] = "EXECUTABLE";
OrderProjection["EXECUTION_COMPLETE"] = "EXECUTION_COMPLETE";
})(OrderProjection || (exports.OrderProjection = OrderProjection = {}));
var Side;
(function (Side) {
Side["BACK"] = "BACK";
Side["LAY"] = "LAY";
})(Side || (exports.Side = Side = {}));
var OrderType;
(function (OrderType) {
OrderType["LIMIT"] = "LIMIT";
OrderType["LIMIT_ON_CLOSE"] = "LIMIT_ON_CLOSE";
OrderType["MARKET_ON_CLOSE"] = "MARKET_ON_CLOSE";
})(OrderType || (exports.OrderType = OrderType = {}));
var PersistenceType;
(function (PersistenceType) {
PersistenceType["LAPSE"] = "LAPSE";
PersistenceType["PERSIST"] = "PERSIST";
PersistenceType["MARKET_ON_CLOSE"] = "MARKET_ON_CLOSE";
})(PersistenceType || (exports.PersistenceType = PersistenceType = {}));
var TimeInForce;
(function (TimeInForce) {
TimeInForce["FILL_OR_KILL"] = "FILL_OR_KILL";
})(TimeInForce || (exports.TimeInForce = TimeInForce = {}));
var BetTargetType;
(function (BetTargetType) {
BetTargetType["BACKERS_PROFIT"] = "BACKERS_PROFIT";
BetTargetType["PAYOUT"] = "PAYOUT";
})(BetTargetType || (exports.BetTargetType = BetTargetType = {}));
var BetStatus;
(function (BetStatus) {
BetStatus["SETTLED"] = "SETTLED";
BetStatus["VOIDED"] = "VOIDED";
BetStatus["LAPSED"] = "LAPSED";
BetStatus["CANCELLED"] = "CANCELLED";
})(BetStatus || (exports.BetStatus = BetStatus = {}));
var GroupBy;
(function (GroupBy) {
GroupBy["EVENT_TYPE"] = "EVENT_TYPE";
GroupBy["EVENT"] = "EVENT";
GroupBy["MARKET"] = "MARKET";
GroupBy["SIDE"] = "SIDE";
GroupBy["BET"] = "BET";
})(GroupBy || (exports.GroupBy = GroupBy = {}));
var TimeGranularity;
(function (TimeGranularity) {
TimeGranularity["DAYS"] = "DAYS";
TimeGranularity["HOURS"] = "HOURS";
TimeGranularity["MINUTES"] = "MINUTES";
})(TimeGranularity || (exports.TimeGranularity = TimeGranularity = {}));
var SubscriptionStatus;
(function (SubscriptionStatus) {
SubscriptionStatus["ALL"] = "ALL";
SubscriptionStatus["ACTIVATED"] = "ACTIVATED";
SubscriptionStatus["UNACTIVATED"] = "UNACTIVATED";
SubscriptionStatus["CANCELLED"] = "CANCELLED";
SubscriptionStatus["EXPIRED"] = "EXPIRED";
})(SubscriptionStatus || (exports.SubscriptionStatus = SubscriptionStatus = {}));
var IncludeItem;
(function (IncludeItem) {
IncludeItem["ALL"] = "ALL";
IncludeItem["DEPOSITS_WITHDRAWALS"] = "DEPOSITS_WITHDRAWALS";
IncludeItem["EXCHANGE"] = "EXCHANGE";
IncludeItem["POKER_ROOM"] = "POKER_ROOM";
})(IncludeItem || (exports.IncludeItem = IncludeItem = {}));
var Wallet;
(function (Wallet) {
Wallet["UK"] = "UK";
})(Wallet || (exports.Wallet = Wallet = {}));
var ActionPerformed;
(function (ActionPerformed) {
ActionPerformed["NONE"] = "NONE";
ActionPerformed["CANCELLATION_REQUEST_SUBMITTED"] = "CANCELLATION_REQUEST_SUBMITTED";
ActionPerformed["ALL_BETS_CANCELLED"] = "ALL_BETS_CANCELLED";
ActionPerformed["SOME_BETS_NOT_CANCELLED"] = "SOME_BETS_NOT_CANCELLED";
ActionPerformed["CANCELLATION_REQUEST_ERROR"] = "CANCELLATION_REQUEST_ERROR";
ActionPerformed["CANCELLATION_STATUS_UNKNOWN"] = "CANCELLATION_STATUS_UNKNOWN";
})(ActionPerformed || (exports.ActionPerformed = ActionPerformed = {}));
// =========================================================================
// Main API Client Class
// =========================================================================
// Create a base class for shared functionality
class BetfairApiBase {
constructor(appKey) {
this.sessionToken = null;
this.appKey = appKey;
this.axiosInstance = axios_1.default.create({
headers: {
'Content-Type': 'application/json',
},
});
}
setSessionToken(token) {
this.sessionToken = token;
}
async executeRequest(method, params) {
if (!this.sessionToken) {
throw new Error('Not authenticated. Call authenticate first.');
}
const config = {
headers: {
'X-Application': this.appKey,
'X-Authentication': this.sessionToken,
},
};
const jsonRpcRequest = {
jsonrpc: '2.0',
method: method,
params: params,
id: 1,
};
try {
const response = await this.axiosInstance.post(method, jsonRpcRequest, config);
if (response.data.error) {
throw new Error(`API error: ${response.data.error.message}`);
}
return response.data.result;
}
catch (error) {
throw new Error(`API execution error: ${error instanceof Error ? error.message : 'Unknown error'}`);
}
}
}
exports.BetfairApiBase = BetfairApiBase;
// Update API classes to use composition instead of inheritance
class BettingAPI {
constructor(appKey) {
this.endpoint = 'https://api.betfair.com/exchange/betting/json-rpc/v1';
this.prefix = 'SportsAPING/v1.0';
this.base = new BetfairApiBase(appKey);
}
setSessionToken(token) {
this.base.setSessionToken(token);
}
async listEventTypes(filter = {}, locale) {
return this.base.executeRequest(`${this.endpoint}/${this.prefix}/listEventTypes`, { filter, locale });
}
async listCompetitions(filter = {}, locale) {
return this.base.executeRequest(`${this.endpoint}/${this.prefix}/listCompetitions`, { filter, locale });
}
async listTimeRanges(filter = {}, granularity = TimeGranularity.DAYS) {
return this.base.executeRequest(`${this.endpoint}/${this.prefix}/listTimeRanges`, { filter, granularity });
}
async listEvents(filter = {}, locale) {
return this.base.executeRequest(`${this.endpoint}/${this.prefix}/listEvents`, { filter, locale });
}
async listMarketTypes(filter = {}, locale) {
return this.base.executeRequest(`${this.endpoint}/${this.prefix}/listMarketTypes`, { filter, locale });
}
async listCountries(filter = {}, locale) {
return this.base.executeRequest(`${this.endpoint}/${this.prefix}/listCountries`, { filter, locale });
}
async listVenues(filter = {}, locale) {
return this.base.executeRequest(`${this.endpoint}/${this.prefix}/listVenues`, { filter, locale });
}
async listMarketCatalogue(filter = {}, marketProjection, sort, maxResults = 1, locale) {
return this.base.executeRequest(`${this.endpoint}/${this.prefix}/listMarketCatalogue`, { filter, marketProjection, sort, maxResults, locale });
}
async listMarketBook(marketIds, priceProjection, orderProjection, matchProjection, includeOverallPosition, partitionMatchedByStrategyRef, customerStrategyRefs, currencyCode, locale, matchedSince, betIds) {
return this.base.executeRequest(`${this.endpoint}/${this.prefix}/listMarketBook`, {
marketIds,
priceProjection,
orderProjection,
matchProjection,
includeOverallPosition,
partitionMatchedByStrategyRef,
customerStrategyRefs,
currencyCode,
locale,
matchedSince,
betIds,
});
}
async listRunnerBook(marketId, selectionId, handicap = 0, priceProjection, orderProjection, matchProjection, includeOverallPosition, partitionMatchedByStrategyRef, customerStrategyRefs, currencyCode, locale, matchedSince, betIds) {
return this.base.executeRequest(`${this.endpoint}/${this.prefix}/listRunnerBook`, {
marketId,
selectionId,
handicap,
priceProjection,
orderProjection,
matchProjection,
includeOverallPosition,
partitionMatchedByStrategyRef,
customerStrategyRefs,
currencyCode,
locale,
matchedSince,
betIds,
});
}
async listMarketProfitAndLoss(marketIds, includeSettledBets, includeBspBets, netOfCommission) {
return this.base.executeRequest(`${this.endpoint}/${this.prefix}/listMarketProfitAndLoss`, { marketIds, includeSettledBets, includeBspBets, netOfCommission });
}
async listCurrentOrders(betIds, marketIds, orderProjection, customerOrderRefs, customerStrategyRefs, dateRange, orderBy, sortDir, fromRecord, recordCount, includeItemDescription) {
return this.base.executeRequest(`${this.endpoint}/${this.prefix}/listCurrentOrders`, {
betIds,
marketIds,
orderProjection,
customerOrderRefs,
customerStrategyRefs,
dateRange,
orderBy,
sortDir,
fromRecord,
recordCount,
includeItemDescription,
});
}
async listClearedOrders(betStatus, eventTypeIds, eventIds, marketIds, runnerIds, betIds, customerOrderRefs, customerStrategyRefs, side, settledDateRange, groupBy, includeItemDescription, locale, fromRecord, recordCount) {
return this.base.executeRequest(`${this.endpoint}/${this.prefix}/listClearedOrders`, {
betStatus,
eventTypeIds,
eventIds,
marketIds,
runnerIds,
betIds,
customerOrderRefs,
customerStrategyRefs,
side,
settledDateRange,
groupBy,
includeItemDescription,
locale,
fromRecord,
recordCount,
});
}
async placeOrders(marketId, instructions, customerRef, marketVersion, customerStrategyRef, async) {
return this.base.executeRequest(`${this.endpoint}/${this.prefix}/placeOrders`, {
marketId,
instructions,
customerRef,
marketVersion,
customerStrategyRef,
async,
});
}
async cancelOrders(marketId, instructions, customerRef) {
return this.base.executeRequest(`${this.endpoint}/${this.prefix}/cancelOrders`, { marketId, instructions, customerRef });
}
async replaceOrders(marketId, instructions, customerRef, marketVersion, async) {
return this.base.executeRequest(`${this.endpoint}/${this.prefix}/replaceOrders`, { marketId, instructions, customerRef, marketVersion, async });
}
async updateOrders(marketId, instructions, customerRef) {
return this.base.executeRequest(`${this.endpoint}/${this.prefix}/updateOrders`, { marketId, instructions, customerRef });
}
}
exports.BettingAPI = BettingAPI;
class AccountsAPI {
constructor(appKey) {
this.endpoint = 'https://api.betfair.com/exchange/account/json-rpc/v1';
this.prefix = 'AccountAPING/v1.0';
this.base = new BetfairApiBase(appKey);
}
setSessionToken(token) {
this.base.setSessionToken(token);
}
async createDeveloperAppKeys(appName) {
return this.base.executeRequest(`${this.endpoint}/${this.prefix}/createDeveloperAppKeys`, { appName });
}
async getDeveloperAppKeys() {
return this.base.executeRequest(`${this.endpoint}/${this.prefix}/getDeveloperAppKeys`, {});
}
async getAccountFunds(wallet) {
return this.base.executeRequest(`${this.endpoint}/${this.prefix}/getAccountFunds`, { wallet });
}
async getAccountDetails() {
return this.base.executeRequest(`${this.endpoint}/${this.prefix}/getAccountDetails`, {});
}
async getVendorClientId() {
return this.base.executeRequest(`${this.endpoint}/${this.prefix}/getVendorClientId`, {});
}
async getApplicationSubscriptionToken(subscriptionLength, clientReference) {
return this.base.executeRequest(`${this.endpoint}/${this.prefix}/getApplicationSubscriptionToken`, { subscriptionLength, clientReference });
}
async activateApplicationSubscription(subscriptionToken) {
return this.base.executeRequest(`${this.endpoint}/${this.prefix}/activateApplicationSubscription`, { subscriptionToken });
}
async cancelApplicationSubscription(subscriptionToken) {
return this.base.executeRequest(`${this.endpoint}/${this.prefix}/cancelApplicationSubscription`, { subscriptionToken });
}
async updateApplicationSubscription(vendorClientId, subscriptionLength) {
return this.base.executeRequest(`${this.endpoint}/${this.prefix}/updateApplicationSubscription`, { vendorClientId, subscriptionLength });
}
async listApplicationSubscriptionTokens(subscriptionStatus) {
return this.base.executeRequest(`${this.endpoint}/${this.prefix}/listApplicationSubscriptionTokens`, { subscriptionStatus });
}
async listAccountSubscriptionTokens() {
return this.base.executeRequest(`${this.endpoint}/${this.prefix}/listAccountSubscriptionTokens`, {});
}
async getApplicationSubscriptionHistory(vendorClientId, applicationKey) {
return this.base.executeRequest(`${this.endpoint}/${this.prefix}/getApplicationSubscriptionHistory`, { vendorClientId, applicationKey });
}
async getAccountStatement(locale, fromRecord, recordCount, itemDateRange, includeItem, wallet) {
return this.base.executeRequest(`${this.endpoint}/${this.prefix}/getAccountStatement`, { locale, fromRecord, recordCount, itemDateRange, includeItem, wallet });
}
async listCurrencyRates(fromCurrency) {
return this.base.executeRequest(`${this.endpoint}/${this.prefix}/listCurrencyRates`, { fromCurrency });
}
async token(clientId, grantType, code, clientSecret, refreshToken) {
return this.base.executeRequest(`${this.endpoint}/${this.prefix}/token`, { client_id: clientId, grant_type: grantType, code, client_secret: clientSecret, refresh_token: refreshToken });
}
async getVendorDetails(vendorId) {
return this.base.executeRequest(`${this.endpoint}/${this.prefix}/getVendorDetails`, { vendorId });
}
async revokeAccessToWebApp(vendorId) {
return this.base.executeRequest(`${this.endpoint}/${this.prefix}/revokeAccessToWebApp`, { vendorId });
}
async listAuthorizedWebApps() {
return this.base.executeRequest(`${this.endpoint}/${this.prefix}/listAuthorizedWebApps`, {});
}
async isAccountSubscribedToWebApp(vendorId) {
return this.base.executeRequest(`${this.endpoint}/${this.prefix}/isAccountSubscribedToWebApp`, { vendorId });
}
async getAffiliateRelation(vendorClientIds) {
return this.base.executeRequest(`${this.endpoint}/${this.prefix}/getAffiliateRelation`, { vendorClientIds });
}
}
exports.AccountsAPI = AccountsAPI;
class HeartbeatAPI {
constructor(appKey) {
this.endpoint = 'https://api.betfair.com/exchange/heartbeat/json-rpc/v1';
this.prefix = 'HeartbeatAPING/v1.0';
this.base = new BetfairApiBase(appKey);
}
setSessionToken(token) {
this.base.setSessionToken(token);
}
async heartbeat(preferredTimeoutSeconds) {
return this.base.executeRequest(`${this.endpoint}/${this.prefix}/heartbeat`, { preferredTimeoutSeconds });
}
}
exports.HeartbeatAPI = HeartbeatAPI;
// Main client class
class BetfairClient extends BetfairApiBase {
constructor(appKey, config) {
super(appKey);
this.exchangeApi = new BettingAPI(appKey);
this.accountsApi = new AccountsAPI(appKey);
this.heartbeatApi = new HeartbeatAPI(appKey);
}
get betting() {
return this.exchangeApi;
}
get accounts() {
return this.accountsApi;
}
get heartbeat() {
return this.heartbeatApi;
}
async authenticate(username, password, certificatePath) {
try {
const config = {
headers: {
'X-Application': this.appKey,
'Content-Type': 'application/x-www-form-urlencoded',
},
};
if (certificatePath) {
config.httpsAgent = new https_1.default.Agent({
cert: certificatePath
});
}
const response = await axios_1.default.post('https://identitysso-cert.betfair.com/api/certlogin', `username=${encodeURIComponent(username)}&password=${encodeURIComponent(password)}`, config);
if (response.data.loginStatus === 'SUCCESS') {
const sessionToken = response.data.sessionToken;
this.sessionToken = sessionToken;
// Propagate session token to API instances
this.exchangeApi.setSessionToken(sessionToken);
this.accountsApi.setSessionToken(sessionToken);
this.heartbeatApi.setSessionToken(sessionToken);
}
else {
throw new Error(`Authentication failed: ${response.data.loginStatus}`);
}
}
catch (error) {
throw new Error(`Authentication error: ${error instanceof Error ? error.message : 'Unknown error'}`);
}
}
async keepAlive() {
try {
const response = await axios_1.default.get('https://identitysso.betfair.com/api/keepAlive', {
headers: {
'Accept': 'application/json',
'X-Application': this.appKey,
'X-Authentication': this.sessionToken,
},
});
return response.data.status === 'SUCCESS';
}
catch (error) {
throw new Error(`Keep alive error: ${error instanceof Error ? error.message : 'Unknown error'}`);
}
}
async logout() {
try {
const response = await axios_1.default.get('https://identitysso.betfair.com/api/logout', {
headers: {
'Accept': 'application/json',
'X-Application': this.appKey,
'X-Authentication': this.sessionToken,
},
});
if (response.data.status === 'SUCCESS') {
this.sessionToken = null;
// Clear session token from API instances
this.exchangeApi.setSessionToken(null);
this.accountsApi.setSessionToken(null);
this.heartbeatApi.setSessionToken(null);
return true;
}
return false;
}
catch (error) {
throw new Error(`Logout error: ${error instanceof Error ? error.message : 'Unknown error'}`);
}
}
getAppKey() {
return this.appKey;
}
getSessionToken() {
return this.sessionToken;
}
async authenticateInteractive(username, password) {
try {
const response = await axios_1.default.post('https://identitysso.betfair.com/api/login', `username=${encodeURIComponent(username)}&password=${encodeURIComponent(password)}`, {
headers: {
'X-Application': this.appKey,
'Content-Type': 'application/x-www-form-urlencoded',
},
});
if (response.data.status === 'SUCCESS') {
const sessionToken = response.data.token;
this.sessionToken = sessionToken;
this.exchangeApi.setSessionToken(sessionToken);
this.accountsApi.setSessionToken(sessionToken);
this.heartbeatApi.setSessionToken(sessionToken);
}
else {
throw new Error(`Authentication failed: ${response.data.error}`);
}
}
catch (error) {
throw new Error(`Authentication error: ${error instanceof Error ? error.message : 'Unknown error'}`);
}
}
}
exports.BetfairClient = BetfairClient;