Thursday, 26 February 2009

BetFair Java API with Apache CXF, Spring and Maven

In this post I present how to login and place a bet on BetFair in Java. Betfair provides a webservice API to get events, markets, place a bet and do many other things. There are several ways to use this API in Java but personally I prefer one of the easiest and quickest of them, which is based on Apache CXF technology.

Apache CXF is a professional open-source Java library to create webservice clients and servers. It generates a webservice java client automatically from a wsdl file, that works very well with BetFair API. Thus calling most of a BetFair operations such a login, getEvents, placeBet is very simple and is just a couple of lines.

The diagram below presents how BetfairService is designed and used in my betting application:

Diagram details:
  • BFGlobalService/BFExchangeService - Betfair webservices generated by Apache CXF. GlobalService contains login operation and others, which don't require logging in. Whereas ExchangeService allows to get market data, place bets, get account information and others, which require user to be logged in.
  • BettingServiceImpl - BetFair Facade, that simplifies access to the BetFair operations from a BettingEngine.
  • BettingEngine - Module of my application responsible for executing betting strategies.
How to login to a Betfair account?


The login operation is provided by a BFGlobalService. To login to a Betfair account three parameters are required: user, password and productId. For Betfair free API the productId is 82.
//Login to a BetFair account.
//
public void login(String userName, String password, int productId) {

//Creating login command which contains all login parameters.
LoginReq req = new LoginReq();
req.setUsername(userName);
req.setPassword(password);
req.setProductId(productId);
req.setLocationId(0);
req.setVendorSoftwareId(0);

//Calling BetFair webservice login operaton.
LoginResp resp = globalWebService.login(req);

//Checking login result and storing session token, which is necessary to call BFExchangeService operations, e.g. getMarkets, placeBet.
if (resp.getErrorCode().equals(LoginErrorEnum.OK))
{
state.setSessionToken(resp.getHeader(). getSessionToken());
} else {
throw new BetFairException("Login error. Error code: " + resp.getErrorCode() + ", api code: "
+ resp.getHeader().getErrorCode());
}
}

How to place a bet?


The placeBet operation is provided by a BFExchangeService. There are many different bet types available. This example show how to place a back/lay bet on a betting exchange. The code snippet below presents a placeBet method with parameters:
  • marketId/selectionId - Which market runner the bet is placed on, e.g. draw in a football match, tennis player in a tennis match or horse in a horse race.
  • betType - Back or lay , e.g. back bet means that something will happen, e.g. draw in a football match, lay means that it will not happen, e.g. tennis player will not win the match.
  • betCategory - Exchange or SP(starting price) bet.
  • price - Binary odds of a bet, e.g. 2.0
  • size - Stake of a bet, e.g. 20 dollars.
//Place a bet on a BetFair
//betting exchange.
public void placeBet(int marketId, int selectionId, BetTypeEnum betType, BetCategoryTypeEnum betCategory,
double price, double size) {

//Creating request header with a session token returned by login operation.
APIRequestHeader requestHeader = new APIRequestHeader();
requestHeader.setSessionToken(sessionToken);

//Creating placeBet command, which contains all required parameters.
PlaceBetsReq req = new PlaceBetsReq();
req.setHeader(requestHeader);

ArrayOfPlaceBets arrayOfBets = new ArrayOfPlaceBets();
PlaceBets placeBets = new PlaceBets();
placeBets.setAsianLineId(0);
placeBets.setBetCategoryType(betCategory);
placeBets.setPrice(price);
placeBets.setSize(size);
placeBets.setBspLiability(0d);
placeBets.setBetPersistenceType( BetPersistenceTypeEnum.NONE);
placeBets.setBetType(betType);
placeBets.setMarketId(marketId);
placeBets.setSelectionId(selectionId);
arrayOfBets.getPlaceBets().add(placeBets);
req.setBets(arrayOfBets);

//Calling placeBet operation on a BetFair webservice.
PlaceBetsResp resp = exchangeWebService.placeBets(req);
if (resp.getErrorCode().equals(...) {
//Checking placing bet result.
}
}

How to generate BFGlobal and BFExchange services with Maven and cxf-codegen-plugin?

Because my betting tool uses a Maven build system, I use a cxf-codegen-plugin to generate java classes for BetFair webservices. There are two plugin executions to generate java classes for BFGlobal and BFExchange services. Java classes are generated from the wsdl files. See lines 17 and 37.


org.apache.cxf
cxf-codegen-plugin
2.0.5-incubator



generate-sources_BFGlobalService
generate-sources


${basedir}/target/generated-sources/src/main/ java




${basedir}/src/main/wsdl/ BFGlobalService.wsdl





wsdl2java




generate-sources_BFExchangeService
generate-sources


${basedir}/target/generated-sources/src/main/ java




${basedir}/src/main/wsdl/ BFExchangeService.wsdl





wsdl2java





How to configure BFGlobal and BFExchange services with Spring?

The BFGlobal and BFExchange services are created by a JaxWsProxyFactory bean, which is configured using the class name of generated webservice and the url of a BetFair webservice. Afterwards BetFair services are injected into a BetFair facade, which is used by my betting application.




 




 
 






 
 





Resources

References
Bye,
Daniel