-
Notifications
You must be signed in to change notification settings - Fork 15
Home
Betfair is about to switch to a next generation JSON based API. It is certainly good news as JSON is a native JavaScript format. Let's say goodbye to SOAP, XML generation/parsing, huge network traffic and many complexities of the old SOAP API. The current project is production-ready, but I would not recommend use it for new projects. The development of the betfair-sport-api is stopped. There is a new library for the new API, although it is not usable yet.
This tutorial intends to show the reader how to create the high-end Betfair applications in fast and easy manner. Many people who were trying to make a first Betfair bot faced the steep learning curve and it may took weeks or months to do simple things like logging to Betfair and placing a bet. I do hope it will take hours to make your first bot using Betfair Sports API for Node.js with the help of the Tutorial. There are following steps in the tutorial:
Step 1. Installing Node.js and Betfair Sports API
Step 2. Logging in to Betfair
Step 3. Login to Betfair, Send keepAlive and Logout
Step 4. Login to Betfair, Send keepAlive and Logout Done Right
Step 5. Getting All the Available Markets
Step 6. Reading the Market Details
Step 7. Getting the Market Prices
Step 8. Placing and Canceling Bets for the Market
Step 9. Updating Bets for the Market
Step 10. High-Performance Bot Programming
Betfair Sports API is a simple, yet powerful JavaScript library for the rapid development of the Betfair applications or bots. It is a result of many years experience of developing the Betfair bots using different programming languages and frameworks. There is a need for a tool that allows fast and easy development of the Betfair bots still without performance and latency compromises. While the Betfair Sports API is quite friendly for beginners it is certainly the high-performance tool intended for professionals.
Node.js is a platform built on Chrome's JavaScript runtime for easily building fast, scalable network applications. Node.js uses an event-driven, non-blocking I/O model that makes it lightweight and efficient, perfect for data-intensive real-time applications that run across distributed devices.
There are many benefits of using Betfair Sports API for Node.js:
* Extreme performance, 100 calls/sec is no problem, 1000 calls/sec achievable * Development in JavaScript is easy and rapid, it is faster than C++, C# or Java * JavaScript V8 Engine is fast, it is much faster than most of the other scipting languages * Fully asuncronous, placing inplay bet does not stops other markets to be refreshed * Cross-platform: you can develop on Windows, deploy on Linux and present on MacOSX * Hosting friendly, place the apps on VPS in UK and get fast ping * Low memory requirements, 512Mb VPS is enough for comfortable bot operation
This is not a JavaScript or Node.js tutorial, but very minimal knowledge of JavaScript and no prior knowledge of Node.js is required.
## Step 1. Installing Node.js and Betfair Sports API.Node.js works good on Windows, MacOSX and Linux. It is the Windows version used in the tutorial, but feel free using any other platform you like. To install Node.js on Windows, please visit the www.nodejs.org, go to the Download page and download the Windows Installer file. (at the moment of tutorial creation it is the http://nodejs.org/dist/v0.6.15/node-v0.6.15.msi file).
After downloading the MSI installer file, double click it (there might be a confirmation screen asking to confirm installer run, make sure there is Joyent publisher that signed the installer file). The first screen of the Installer Wizard is a welcome screen, just press Next button. Next screen asks you to accept the End User License Agreement, just do it. The following screen copies files into "*C:\Program Files\nodejs*" and then the Finish screen appears. That's all, there is nothing special, just the standard Windows application installation.
Node.js is now installed. There is some 8Mb of space on your hard drive used and there are two new things appear on you PC:
1. Node.exe - JavaScript V8 engine and Node.js framework in a single and compact executable file. 2. Npm - Node.js package manager, it allows to install thousands of Node.js packages on your PC
The interesting things are just starting. Go to the Windows Command Prompt (on Windows 7 just press Start button then just type cmd in search field). Let's create folder C:\Betfair and go there:
c:\Users\AlgoTrader>md c:\Betfair c:\Users\AlgoTrader>cd c:\Betfair c:\Betfair>
The rest of tutorial never installs anything outside the C:\Betfair directory, so you will be able just remove the directory to keep your PC clean. It is too much of installs, let's start using it. Type node from inside of C:\Betfair. To quit node, just press Ctrl-C twice.
c:\Betfair>node > 2+3 5 > 2*Math.PI*10 62.83185307179586 > console.log('Hello, world') Hello, world undefined >
It works! This is just an interactive JavaScript interpreter built-in in Node.js. The first two commands are pure JavaScript code, the last one is the Node.js console object that has log method. Now switch to another friend, npm that stands for Node Package Manager.
c:\Betfair>npm install betfair-sports-api npm http GET https://registry.npmjs.org/betfair-sports-api npm http 200 https://registry.npmjs.org/betfair-sports-api npm http GET https://registry.npmjs.org/betfair-sports-api/-/betfair-sports-api-0.1.5.tgz npm http 200 https://registry.npmjs.org/betfair-sports-api/-/betfair-sports-api-0.1.5.tgz npm http GET https://registry.npmjs.org/async npm http GET https://registry.npmjs.org/dom-js npm http 200 https://registry.npmjs.org/dom-js npm http GET https://registry.npmjs.org/dom-js/-/dom-js-0.0.7.tgz npm http 200 https://registry.npmjs.org/async npm http GET https://registry.npmjs.org/async/-/async-0.1.18.tgz npm http 200 https://registry.npmjs.org/dom-js/-/dom-js-0.0.7.tgz npm http 200 https://registry.npmjs.org/async/-/async-0.1.18.tgz npm http GET https://registry.npmjs.org/sax npm http 200 https://registry.npmjs.org/sax npm http GET https://registry.npmjs.org/sax/-/sax-0.4.0.tgz npm http 200 https://registry.npmjs.org/sax/-/sax-0.4.0.tgz [email protected] ./node_modules/betfair-sports-api ├── [email protected] └── [email protected] ([email protected])
Great, Betfair Sports API for Node is installed. There were two dependent modules installed: async and dom-js. The first one is JavaScript control-flow library, more about it later. The second is XML parser needed to parse XMLs from Betfair and encode XMLs about to send to Betfair. It's out of our interest.
## Step 2. Logging in to Betfair.Betfair uses SOAP protocol for accessing Betfair Sports API, SOAP stands for Simple Object Access Protocol. Despite it's name, the SOAP is not that simple. SOAP uses XML for requests and responses and a number of rules of how those XML requests/responses are encoded. Betfair API uses HTTPS transport, it is encrypted version of the HTTP that is needed to protect your personal data from being stolen. There is an example of the login SOAP request:
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http:
//www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/">
<soap:Body>
<login xmlns="http://www.betfair.com/publicapi/v3/BFGlobalService/">
<request>
<locationId>0</locationId>
<password>password</password>
<productId>82</productId>
<username>nobody</username>
<vendorSoftwareId>0</vendorSoftwareId>
</request>
</login>
</soap:Body>
</soap:Envelope>
Is that easy? Betfair provides three SOAP endpoints (URLs). The first is used primarily for the login/logout operations, and named Global Service. The second and third are UK and Australia exchanges and named UK Exchange and Australian Exchange. The URLs of the endpoints are following:
https://api.betfair.com/global/v3/BFGlobalService
https://api.betfair.com/exchange/v5/BFExchangeService
https://api-au.betfair.com/exchange/v5/BFExchangeService
In this tutorial we will use only the first two. When using Betfair Sports API for Node, you should not worry about the endpoints, the API knows where to send the specific API call (invocation). Now is the time to start coding, create file login.js and copy-paste the following code:
var betfair = require('betfair-sports-api');
var login='me';
var password='pass';
var session = betfair.newSession(login,password);
session.open(function(err,res) {
if(err)
console.log('login failed, error is', err);
else
console.log('login OK');
process.exit(1);
});
Please note that you need to be in *C:\Betfair* and betfair sports API should be installed previously by running npm install betfair-sports-api. There is a very important moment, session.open() method takes a function as the first argument. The function is defined inside the session.open() call, that is very common thing in JavaScript that may embarrass programmers that never saw such things. Now the time to run it:
C:\Betfair>node login.js login response: raw length=459, xml length=941, compression=51% login failed, error is INVALID_USERNAME_OR_PASSWORD
The login attempt failed as we provided invalid Betfair login and password. Please note there is some additional information printed, it would be probably removed in future versions of the library. Please edit the code and put there your Betfair login and password and try again.
C:\Betfair>node login.js login response: raw length=481, xml length=982, compression=51% Session token is: [skipped] login OK
Congratulations, login to Betfair was successful! The library does not show the session token for security reasons. The security token is a magic string that looks like 'oIa2RCtt6AH5KAegdPWZYzcSUTiaQohWf1gdybjFPGE=' that API sends to Betfair in every API call to confirm that you are logged in. The only exception is the login invocation, in login request there should be your Betfair password provided. I strongly recommend you to use logout call to invalidate the session token, if someone knows you active security token then he may access your money.
## Step 3. Login to Betfair, Send keepAlive and Logout.This step seems to be too simple and not much necessary but it is. If we used PHP, Python or C# there would not a need in the Step 3. Node.js is different in a single thing and the thing is of extreme importance. Node.js is fully asynchronous. It means that program never stops to wait anything, it never blocks on networks operations or file reads from filesystem (there are a few exceptions, but the issue out of scope of this tutorial). The first and naive approach is ther (copy-paste the text to naive.js)
var betfair = require('betfair-sports-api');
var bflogin='me';
var bfpassword='pass';
console.log('login to Betfair');
var session = betfair.newSession(bflogin,bfpassword);
session.open(function(err,res) {
if(err)
console.log('login failed, error is', err);
else
console.log('login OK');
});
console.log('send keepAlive');
var invocation = session.keepAlive();
invocation.execute(function(err,res) {
if(err)
console.log('keepAlive failed, error is', err);
else
console.log('keepAlive OK');
});
console.log('logout');
session.close(function(err,res) {
if(err)
console.log('logout failed, error is', err);
else
console.log('logout OK');
process.exit(1);
});
The result is funny:
C:\Betfair>node naive.js login to Betfair send keepAlive logout keepAlive response: raw length=404, xml length=812, compression=50% keepAlive failed, error is NO_SESSION logout response: raw length=411, xml length=828, compression=50% logout failed, error is NO_SESSION
First thing is there is no any stuff related to login. The second is the keepAlive is failed with error NO_SESSION and logout also failed with error NO_SESSION. What's up? The answer is easy: all the login, keepAlive and logout were sent at once. keepAlive and logout were finished before login did. That is certainly incorrect code. Your results may be different from mine, the code may provide strange surprises. We need to call login, keepAlive and logout in series! Here is the modified and correct version (copy paste to fixed.js):
var betfair = require('betfair-sports-api');
var bflogin = 'me';
var bfpassword = 'pass';
console.log('login to Betfair');
var session = betfair.newSession(bflogin, bfpassword);
session.open(function(err, res) {
if (err)
console.log('login failed, error is', err);
else {
console.log('login OK, send keepAlive');
var invocation = session.keepAlive();
invocation.execute(function(err, res) {
if (err)
console.log('keepAlive failed, error is', err);
else {
console.log('keepAlive OK, logout');
session.close(function(err, res) {
if (err)
console.log('logout failed, error is', err);
else
console.log('logout OK');
process.exit(1);
});
}
});
}
});
The execution result is correct now:
C:\Betfair>node fixed.js login to Betfair login response: raw length=478, xml length=982, compression=51% Session token is: [skipped] login OK, send keepAlive keepAlive response: raw length=445, xml length=858, compression=48% keepAlive OK, logout logout response: raw length=393, xml length=813, compression=52% logout OK
The code above works good, but is the code easy to read and understand? It is one of the most shit code I ever saw. The correctly written code can be the complete shit! The code provided above has own name and is called "callback hell code". It is the style of coding that use many web developers and it is coding style that cause many people to hate JavaScript. I also hated JavaScript. JavaScript is one of the most used programming languages in the world and it is also most misunderstood language as there are lots of arrogant web developers who cannot write simple things. We got six levels of indenting doing a very simple thing.
Forget about everything we did in Step 3. There is a survival of the "callback hell" and the async stuff though, let's fix the things up.
## Step 4. Login to Betfair, Send keepAlive and Logout done RightA JavaScript application can be either very ugly or very beautiful one. JavaScript is a beautiful language when used properly. JavaScript impacted my coding style very much and Node.js also made me rethink many things. I would say it requires think different.
There is a library for Node.js (it can work without Node also) that is designed to address the "callback hell" problem, its name is async. The library has lots of useful stuff but we need just a single function from there - series. The only purpose of the function is just do things serially. Lets rewrite the code from Step 3 using async (copy-paste to serial.js and type npm install async to install async module):
var betfair = require('betfair-sports-api');
var async = require('async');
var bflogin = 'me';
var bfpassword = 'pass';
var session;
async.series([ login, keepAlive, logout ], function(err, res) {
process.exit(0);
});
function login(callback) {
console.log('login to Betfair');
session = betfair.newSession(bflogin, bfpassword);
session.open(function(err, res) {
if (err)
console.log('login failed, error is', err);
else
console.log('login OK');
callback(err,res);
});
}
function keepAlive(callback) {
console.log('send keepAlive');
var invocation = session.keepAlive();
invocation.execute(function(err, res) {
if (err)
console.log('keepAlive failed, error is', err);
else
console.log('keepAlive OK');
callback(err,res);
});
}
function logout(callback) {
console.log('logout');
session.close(function(err, res) {
if (err)
console.log('logout failed, error is', err);
else
console.log('logout OK');
callback(err,res);
});
}
The invocation result is
C:\Betfair>node serial.js login to Betfair login response: raw length=483, xml length=982, compression=51% Session token is: [skipped] login OK send keepAlive keepAlive response: raw length=450, xml length=858, compression=48% keepAlive OK logout logout response: raw length=394, xml length=813, compression=52% logout OK
Although the code is a bit more lengthy, it is no longer difficult to understand. For the rest of the tutorial, I will use async library with async.series() to "linearize" the serial execution logic. If you think that async stuff is just a headache, think of the several cases when it help a lot. Supposedly you want to place an in-play bet and it will hang for 5 secs (BF "freeze" HTTP by 5 secs then send reply), if the application is synchronous it is either stopped to wait placeBets result or it has a number of threads and syncronization stuff (mutexes, events, semaphores, etc) that is also not so simple. The asynchronous logic helps to say goodbuy to threads, [dead]locks, races etc.
I recommend adding debug prints to the code to see what res
object is, you may be especially interested in what res.result is. Let's add console.log("res.result is", res.result);
in login callback:
session = betfair.newSession(bflogin, bfpassword);
session.open(function(err, res) {
if (err)
console.log('login failed, error is', err);
else
console.log('login OK');
console.log("res.result is", res.result);
callback(err, res);
});
The output will have following lines:
res.result is { header: { errorCode: 'OK', minorErrorCode: null, sessionToken: 'cRtIrpt1ekmzhy1sUHVxqpgUlRsAJZkXmZkz0RzoTcI=', timestamp: Sun, 06 May 2012 07:06:34 GMT }, currency: 'USD', errorCode: 'OK', minorErrorCode: null, validUntil: Mon, 01 Jan 1 00:00:00 GMT }
It is a parsed XML response from Betfair, but instead of the ugly SOAP XML it is the easy to use JavaScript object. For example, to check what the sessionToken is you may use console.log(res.result.header.sessionToken)
. Should be easy, isn't it? The last comment is the sessionToken is modified in order to keep my money safe.
To make any bets we should select a market first. It can be a soccer match, a horse race or anything else. For this tutorial we will use tennis. There is a getAllMarkets invocation that does exactly we need. Let's get all tennis markets that currently exists at the Betfair:
var betfair = require('betfair-sports-api');
var async = require('async');
var bflogin = 'me';
var bfpassword = 'pass';
var session;
async.series([ login, getAllMarkets, logout ], function(err, res) {
process.exit(0);
});
function login(callback) {
console.log('login to Betfair');
session = betfair.newSession(bflogin, bfpassword);
session.open(function(err, res) {
if (err)
console.log('login failed, error is', err);
else
console.log('login OK');
callback(err, res);
});
}
function getAllMarkets(cb) {
console.log('Get available tennis matches');
// eventTypeIds 1-soccer, 2-tennis
var inv = session.getAllMarkets({
eventTypeIds : [ 2 ]
});
inv.execute(function(err, res) {
console.log('action:', res.action, 'error:', err, 'duration:', res
.duration() / 1000);
if (err) {
cb("Error in getAllMarkets", null);
}
for ( var index in res.result.marketData) {
market = res.result.marketData[index];
if (market.marketName != 'Match Odds')
continue;
var path = market.menuPath.replace(/\\Tennis\\Group A\\/g, '')
console.log(path);
}
cb(null, "OK");
});
}
function logout(callback) {
console.log('logout');
session.close(function(err, res) {
if (err)
console.log('logout failed, error is', err);
else
console.log('logout OK');
callback(err, res);
});
}
Most of the code was inherited from the previous step. We just replaced the keepAlive function with the getAllMarkets function. Let's look at the execution results:
C:\Betfair>node getAllMarkets.js login to Betfair login response: raw length=481, xml length=982, compression=51% Session token is: [skipped] login OK Get available tennis matches getAllMarkets response: raw length=8975, xml length=108120, compression=92% action: getAllMarkets error: null duration: 0.156 Mutua Madrid Open 2012\Womens Tournament\First Round Matches\Azarenka v Kuznetsova Mutua Madrid Open 2012\Womens Tournament\First Round Matches\Petrova v King Mutua Madrid Open 2012\Womens Tournament\First Round Matches\A Radwanska v Arruabarrena Vecino Mutua Madrid Open 2012\Womens Tournament\First Round Matches\Scheepers v Errani Mutua Madrid Open 2012\Womens Tournament\First Round Matches\Wickmayer v Gajdosova Mutua Madrid Open 2012\Womens Tournament\First Round Matches\Vinci v Cibulkova Mutua Madrid Open 2012\Womens Tournament\First Round Matches\Peer v Hercog Mutua Madrid Open 2012\Womens Tournament\First Round Matches\Pironkova v Medina Garrigues Mutua Madrid Open 2012\Womens Tournament\First Round Matches\Kirilenko v Zheng Mutua Madrid Open 2012\Womens Tournament\First Round Matches\Makarova v Voskoboeva Mutua Madrid Open 2012\Womens Tournament\First Round Matches\Erakovic v Kvitova Mutua Madrid Open 2012\Womens Tournament\First Round Matches\Vesnina v S Williams Mutua Madrid Open 2012\Womens Tournament\First Round Matches\Jankovic v Suarez Navarro Mutua Madrid Open 2012\Womens Tournament\First Round Matches\Safarova v Kanepi Mutua Madrid Open 2012\Womens Tournament\First Round Matches\Begu v Sharapova Mutua Madrid Open 2012\Womens Tournament\First Round Matches\Wozniacki v Pervak Mutua Madrid Open 2012\Mens Tournament\First Round Matches\O Rochus v Wawrinka Mutua Madrid Open 2012\Mens Tournament\First Round Matches\Melzer v F Lopez Mutua Madrid Open 2012\Mens Tournament\First Round Matches\Simon v Fognini Mutua Madrid Open 2012\Mens Tournament\First Round Matches\Baghdatis v Garcia Lopez Mutua Madrid Open 2012\Mens Tournament\First Round Matches\Raonic v Nalbandian Mutua Madrid Open 2012\Mens Tournament\First Round Matches\Troicki v Young Mutua Madrid Open 2012\Mens Tournament\First Round Matches\Bellucci v Gasquet Mutua Madrid Open 2012\Mens Tournament\First Round Matches\Granollers v Berlocq Mutua Madrid Open 2012\Mens Tournament\First Round Matches\Stepanek v Tomic Mutua Madrid Open 2012\Mens Tournament\First Round Matches\Montanes v Cilic Mutua Madrid Open 2012\Mens Tournament\First Round Matches\Youzhny v Marti Mutua Madrid Open 2012\Mens Tournament\First Round Matches\F Mayer v Del Potro Mutua Madrid Open 2012\Mens Tournament\First Round Matches\Dolgopolov v Andujar Mutua Madrid Open 2012\Mens Tournament\First Round Matches\Llodra v Seppi Mutua Madrid Open 2012\Mens Tournament\First Round Matches\Anderson v Bogomolov Jr Mutua Madrid Open 2012\Mens Tournament\First Round Matches\Kohlschreiber v Monfils Mutua Madrid Open 2012\Mens Tournament\First Round Matches\Verdasco v Istomin Mutua Madrid Open 2012\Mens Tournament\First Round Matches\Karlovic v Davydenko Mutua Madrid Open 2012\Mens Tournament\Qualifying Matches\Gil v Gimeno Traver Mutua Madrid Open 2012\Mens Tournament\Qualifying Matches\Cipolla v Hanescu Mutua Madrid Open 2012\Mens Tournament\Qualifying Matches\Sanjurjo Hermida v Delbonis BMW Open 2012\The Final\Cilic v Kohlschreiber BMW Open 2012\Doubles Matches\Cermak/Polasek v Malisse/Norman Mutua Madrid Open 2012\Mens Tournament\Qualifying Matches\Giraldo v Munoz de la Nava Mutua Madrid Open 2012\Mens Tournament\Qualifying Matches\Stakhovsky v Roger Vasselin Mutua Madrid Open 2012\Mens Tournament\Qualifying Matches\Andreev v Bautista Agut \Tennis\Mutua Madrid Open 2012\Womens Tournament\Second Round Matches\Stosur v McHale Estoril Open 2012\Mens Tournament\The Final\Del Potro v Gasquet Serbia Open 2012\The Final\Paire v Seppi Mutua Madrid Open 2012\Mens Tournament\Qualifying Matches\Falla v Cervantes Estoril Open 2012\Doubles Matches\Qureshi/Rojer v Knowle/Marrero Mutua Madrid Open 2012\Womens Tournament\Second Round Matches\Soler Espinosa v Li Serbia Open 2012\Doubles Matches\Erlich/A Ram v Emmrich/Siljestrom Mutua Madrid Open 2012\Womens Tournament\First Round Matches\Kerber v Larsson Mutua Madrid Open 2012\Womens Tournament\First Round Matches\Niculescu v Dominguez Lino Mutua Madrid Open 2012\Womens Tournament\First Round Matches\Johansson v Ivanovic Mutua Madrid Open 2012\Womens Tournament\First Round Matches\Pavlyuchenkova v Craybas Mutua Madrid Open 2012\Womens Tournament\First Round Matches\Schiavone v Lepchenko logout logout response: raw length=394, xml length=813, compression=52% logout OK
It works great. Plese make a note the time getAllMarket taken, it is 0.156 seconds. It is the pretty bad result, but alas, I have a poor internet connection at home. There is regex expression used in the code, to cut some stuff from menuPath that is out of interest.
# Step 6. Reading the Market Details
var betfair = require('betfair-sports-api');
var async = require('async');
var bflogin = 'me';
var bfpassword = 'pass';
var session;
var marketId;
async.series([ login, getAllMarkets, getMarket, logout ], function(err, res) {
process.exit(0);
});
function login(callback) {
console.log('login to Betfair');
session = betfair.newSession(bflogin, bfpassword);
session.open(function(err, res) {
if (err)
console.log('login failed, error is', err);
else
console.log('login OK');
callback(err, res);
});
}
function getAllMarkets(cb) {
console.log('Get available tennis matches');
// eventTypeIds 1-soccer, 2-tennis
var inv = session.getAllMarkets({
eventTypeIds : [ 2 ]
});
inv.execute(function(err, res) {
console.log('action:', res.action, 'error:', err, 'duration:',
res.duration() / 1000);
if (err) {
cb("Error in getAllMarkets", null);
}
var markets = res.result.marketData.filter(function(m) {
return m.marketName === 'Match Odds'
});
// sort by eventDate descending
markets.sort(function(first, second) {
return second.eventDate - first.eventDate
});
var market = markets[0];
marketId = market.marketId;
console.log('Selected market %s', marketId);
cb(null, "OK");
});
}
function getMarket(cb) {
console.log('Call getMarket for marketId="%s"', marketId);
var inv = session.getMarket(marketId);
inv.execute(function(err, res) {
console.log('action:', res.action, 'error:', err, 'duration:',
res.duration() / 1000);
if (err) {
cb("Error in getMarket", null);
}
// console.log( util.inspect(res.result, false, 10) );
console.log("marketId:", res.result.market.marketId);
console.log("market name:", res.result.market.name);
console.log("market time:", res.result.market.marketTime);
console.log("\tplayerOneId:", res.result.market.runners[0].selectionId);
console.log("\tplayerOneName:", res.result.market.runners[0].name);
console.log("\tplayerTwoId:", res.result.market.runners[1].selectionId);
console.log("\tplayerTwoName:", res.result.market.runners[1].name);
cb(null, "OK");
});
}
function logout(callback) {
console.log('logout');
session.close(function(err, res) {
if (err)
console.log('logout failed, error is', err);
else
console.log('logout OK');
callback(err, res);
});
}
The execution result is
C:\Betfair>node getMarket.js login to Betfair login response: raw length=479, xml length=982, compression=51% Session token is: [skipped] login OK Get available tennis matches getAllMarkets response: raw length=7633, xml length=95545, compression=92% action: getAllMarkets error: null duration: 0.188 Selected market 105672838 Call getMarket for marketId="105672838" getMarket response: raw length=1819, xml length=4769, compression=62% action: getMarket error: null duration: 0.125 marketId: 105672838 market name: Match Odds market time: Wed, 09 May 2012 09:00:00 GMT playerOneId: 2256470 playerOneName: Tomas Berdych playerTwoId: 2519549 playerTwoName: Kevin Anderson logout logout response: raw length=395, xml length=813, compression=51% logout OK
It works
# Step 7. Getting the Market Prices
var betfair = require('betfair-sports-api');
var async = require('async');
var bflogin = 'me';
var bfpassword = 'pass';
var session;
var marketId;
async.series([ login, getAllMarkets, getMarketPrices, logout ], function(err, res) {
process.exit(0);
});
function login(callback) {
console.log('login to Betfair');
session = betfair.newSession(bflogin, bfpassword);
session.open(function(err, res) {
if (err)
console.log('login failed, error is', err);
else
console.log('login OK');
callback(err, res);
});
}
function getAllMarkets(cb) {
console.log('Get available tennis matches');
// eventTypeIds 1-soccer, 2-tennis
var inv = session.getAllMarkets({
eventTypeIds : [ 2 ]
});
inv.execute(function(err, res) {
console.log('action:', res.action, 'error:', err, 'duration:',
res.duration() / 1000);
if (err) {
cb("Error in getAllMarkets", null);
}
var markets = res.result.marketData.filter(function(m) {
return m.marketName === 'Match Odds'
});
// sort by eventDate descending
markets.sort(function(first, second) {
return second.eventDate - first.eventDate
});
var market = markets[0];
marketId = market.marketId;
console.log('Selected market %s', marketId);
cb(null, "OK");
});
}
function getMarketPrices(cb) {
console.log('Call getMarketPricesCompressed for marketId="%s"', marketId);
var inv = session.getMarketPricesCompressed(marketId);
inv.execute(function(err, res) {
console.log('action:', res.action, 'error:', err, 'duration:',
res.duration() / 1000);
if (err) {
cb("Error in getMarketPricesCompressed", null);
}
//console.log(util.inspect(res.result, false, 10));
var market = res.result.marketPrices;
console.log("marketId:", market.marketId);
console.log("currency:", market.currency);
console.log("marketStatus:", market.marketStatus);
console.log("inPlayDelay:", market.inPlayDelay);
// print players info
for ( var playerIndex = 0; playerIndex < market.runners.length; ++playerIndex) {
console.log("player %s", playerIndex);
var runner = market.runners[playerIndex];
console.log("\tselectionId:", runner.selectionId);
console.log("\tlastPriceMatched:", runner.lastPriceMatched);
console.log("\ttotalMatched:", runner.totalMatched);
for ( var cnt = 0; cnt < runner.backPrices.length; ++cnt) {
var item = runner.backPrices[cnt];
console.log("\t back price:%s amount:%s", item.price, item.amount);
}
for ( var cnt = 0; cnt < runner.layPrices.length; ++cnt) {
var item = runner.layPrices[cnt];
console.log("\t lay price:%s amount:%s", item.price, item.amount);
}
}
cb(null, "OK");
});
}
function logout(callback) {
console.log('logout');
session.close(function(err, res) {
if (err)
console.log('logout failed, error is', err);
else
console.log('logout OK');
callback(err, res);
});
}
The result is
C:\Betfair>node getPrices.js login to Betfair login response: raw length=483, xml length=982, compression=51% Session token is: [skipped] login OK Get available tennis matches getAllMarkets response: raw length=7644, xml length=95548, compression=92% action: getAllMarkets error: null duration: 0.157 Selected market 105672838 Call getMarketPricesCompressed for marketId="105672838" getMarketPricesCompressed response: raw length=619, xml length=1242, compression=50% action: getMarketPricesCompressed error: null duration: 0.109 marketId: 105672838 currency: USD marketStatus: ACTIVE inPlayDelay: 0 player 0 selectionId: 2256470 lastPriceMatched: 1.28 totalMatched: 26.24 back price:1.28 amount:7.38 back price:1.14 amount:2346.53 back price:1.08 amount:15761.82 lay price:1.37 amount:150.0 lay price:1.87 amount:323.66 lay price: amount:undefined player 1 selectionId: 2519549 lastPriceMatched: totalMatched: 0.0 back price:3.75 amount:6.0 back price:1.06 amount:5.82 back price:1.05 amount:15765.68 lay price:4.7 amount:150.0 lay price: amount:undefined lay price:undefined amount:undefined logout logout response: raw length=394, xml length=813, compression=52% logout OK# Step 8. Placing and Canceling Bets for the Market # Step 9. Updating Bets for the Market # Step 10. High-Performance Bot Programming
I hope you got fun reading and possibly following this tutorial. JavaScript is a worth language to use for creating Betfair bots and you may want to learn it in systematic and thorough way. There are hundreds of shit books about JavaScript and I know only one that is good enough. It is the David Flanagan's "JavaScript, the Definitive Guide". It's worth read.
Any feedback is appreciated. Yours faithfully, AlgoTrader