File Coverage

blib/lib/WWW/betfair.pm
Criterion Covered Total %
statement 19 21 90.4
branch n/a
condition n/a
subroutine 7 7 100.0
pod n/a
total 26 28 92.8


line stmt bran cond sub pod time code
1             package WWW::betfair;
2 1     1   21656 use strict;
  1         3  
  1         44  
3 1     1   6 use warnings;
  1         2  
  1         41  
4 1     1   561 use WWW::betfair::Template;
  1         3  
  1         29  
5 1     1   548 use WWW::betfair::Request;
  1         6  
  1         32  
6 1     1   890 use WWW::betfair::TypeCheck;
  1         7  
  1         42  
7 1     1   1136 use Time::Piece;
  1         10582  
  1         8  
8 1     1   551 use XML::Simple;
  0            
  0            
9             use Carp qw /croak/;
10             use feature qw/switch/;
11              
12             =head1 NAME
13              
14             WWW::betfair - interact with the betfair API using OO Perl
15              
16             =head1 VERSION
17              
18             Version 1.02
19              
20             =cut
21              
22             our $VERSION = '1.02';
23              
24             =head1 WHAT IS BETFAIR?
25              
26             L is a sports betting services provider best known for hosting the largest sports betting exchange in the world. The sports betting exchange works like a marketplace: betfair provides an anonymous platform for individuals to offer and take bets on sports events at a certain price and size; it is the ebay of betting. betfair provides an API for the sports betting exchange which enables users to search for sports events and markets, place and update bets and manage their account by depositing and withdrawing funds.
27              
28             =head1 WHY USE THIS LIBRARY?
29              
30             The betfair API communicates using verbose XML files which contain various bugs and quirks. L makes it easier to use the betfair API by providing a Perl interface which manages the befair session, serializing API calls to betfair into the required XML format and de-serializing and parsing the betfair responses back into Perl data structures. Additionally L provides:
31              
32             =over
33              
34             =item *
35              
36             100% of the free and paid methods of the betfair API
37              
38             =item *
39              
40             Documentation for every method with an example method call and reference to the original betfair documentation
41              
42             =item *
43              
44             Type-checking of arguments before they are sent to betfair
45              
46             =back
47              
48             =head1 WARNING
49              
50             Betting using a software program can have unintended consequences. Check all argument types and values before using the methods in this library. Ensure that you adequately test any method of L before using the method and risking money on it. As per the software license it is provided AS IS and no liability is accepted for any costs or penalties caused by using L.
51              
52             To understand how to use the betfair API it is essential to read the L before using L. The betfair documentation is an excellent reference.
53              
54             =head1 SYNOPSIS
55              
56             L provides an object oriented Perl interface for the betfair v6 API. This library communicates via HTTPS to the betfair servers using XML. To use the API you must have an active and funded account with betfair, and be accessing the API from a location where betfair permits use (e.g. USA based connections are refused, but UK connections are allowed). L provides methods to connect to the betfair exchange, search for market prices place and update bets and manage your betfair account.
57              
58             Example
59              
60             use WWW::betfair;
61             use Data::Dumper;
62              
63             my $betfair = WWW::betfair->new;
64            
65             # login is required before performing any other services
66             if ($betfair->login({username => 'sillymoos', password => 'password123'}) {
67            
68             # check account balance
69             print Dumper($betfair->getAccountFunds);
70              
71             # get a list of all active event types (categories of sporting events e.g. football, tennis, boxing).
72             print Dumper($betfair->getActiveEventTypes);
73              
74             }
75             # login failed print the error message returned by betfair
76             else {
77             print Dumper($betfair->getError);
78             }
79              
80             =head1 NON API METHODS
81              
82             =head2 new
83              
84             Returns a new WWW::betfair object. Does not require any parameters.
85              
86             Example
87              
88             my $betfair = WWW::betfair->new;
89              
90             =cut
91              
92             sub new {
93             my $class = shift;
94             my $self = {
95             xmlsent => undef,
96             xmlreceived => undef,
97             headerError => undef,
98             bodyError => undef,
99             response => {},
100             sessionToken=> undef,
101             };
102             my $obj = bless $self, $class;
103             my $typechecker = WWW::betfair::TypeCheck->new;
104             $obj->{type} = $typechecker;
105             return $obj;
106             }
107              
108             =head2 getError
109              
110             Returns the error message from the betfair API response - this is useful when a request fails. After a successful call API the value returned by getError is 'OK'.
111              
112             Example
113              
114             my $error = $betfair->getError;
115              
116             =cut
117              
118             sub getError {
119             my $self = shift;
120             return $self->{headerError} eq 'OK' ? $self->{bodyError} : $self->{headerError};
121             }
122              
123             =head2 getXMLSent
124              
125             Returns a string of the XML message sent to betfair. This can be useful to inspect if de-bugging a failed API call.
126              
127             Example
128              
129             my $xmlSent = $betfair->getXMLSent;
130              
131             =cut
132              
133             sub getXMLSent {
134             my $self = shift;
135             return $self->{xmlsent};
136             }
137              
138             =head2 getXMLReceived
139              
140             Returns a string of the XML message received from betfair. This can be useful to inspect if de-bugging a failed API call.
141              
142             Example
143              
144             my $xmlReceived = $betfair->getXMLReceived;
145              
146             =cut
147              
148             sub getXMLReceived {
149             my $self = shift;
150             return $self->{xmlreceived};
151             }
152              
153             =head2 getHashReceived
154              
155             Returns a Perl data structure consisting of the entire de-serialized betfair XML response. This can be useful to inspect if de-bugging a failed API call and easier to read than the raw XML message, especially if used in conjunction with L.
156              
157             Example
158              
159             my $hashReceived = $betfair->getHashReceived;
160              
161             =cut
162              
163             sub getHashReceived {
164             my $self = shift;
165             return $self->{response};
166             }
167              
168             =head1 GENERAL API METHODS
169              
170             =head2 login
171              
172             Authenticates the user and starts a session with betfair. This is required before any other methods can be used. Returns 1 on success and 0 on failure. If login fails and you are sure that you are using the correct the credentials, check the $betfair->{error} attribute. A common reason for failure on login is not having a funded betfair account. To resolve this, simply make a deposit into your betfair account and the login should work. See L for details. Required arguments:
173              
174             =over
175              
176             =item *
177              
178             username: string of your betfair username
179              
180             =item *
181              
182             password: string of your betfair password
183              
184             =item *
185              
186             productID: integer that indicates the API product to be used (optional). This defaults to 82 (the free personal API). Provide this argument if using a commercial version of the betfair API.
187              
188             =back
189              
190             Example
191              
192             $betfair->login({
193             username => 'sillymoos',
194             password => 'password123',
195             });
196              
197             =cut
198              
199             sub login {
200             my ($self, $args) = @_;
201             my $paramChecks = {
202             username => ['username', 1],
203             password => ['password', 1],
204             productId => ['int', 0],
205             };
206             return 0 unless $self->_checkParams($paramChecks, $args);
207             my $params = {
208             username => $args->{username},
209             password => $args->{password},
210             productId => $args->{productId} || 82,
211             locationId => 0,
212             ipAddress => 0,
213             vendorId => 0,
214             exchangeId => 3,
215             };
216             return $self->_doRequest('login', $params);
217             }
218              
219             =head2 keepAlive
220              
221             Refreshes the current session with betfair. Returns 1 on success and 0 on failure. See L for details. Does not require any parameters. This method is not normally required as a session expires after 24 hours of inactivity.
222              
223             Example
224              
225             $betfair->keepAlive;
226              
227             =cut
228              
229             sub keepAlive {
230             my $self = shift;
231             return $self->_doRequest('keepAlive', {exchangeId => 3});
232             }
233              
234             =head2 logout
235              
236             Closes the current session with betfair. Returns 1 on success and 0 on failure. See L for details. Does not require any parameters.
237              
238             Example
239              
240             $betfair->logout;
241              
242             =cut
243              
244             sub logout {
245             my $self = shift;
246             if ($self->_doRequest('logout', {exchangeId => 3})) {
247             # check body error message, different to header error
248             my $self->{error}
249             = $self->{response}->{'soap:Body'}->{'n:logoutResponse'}->{'n:Result'}->{'errorCode'}->{content};
250             return 1 if $self->{error} eq 'OK';
251             }
252             return 0;
253             }
254              
255             =head1 READ ONLY BETTING API METHODS
256              
257             =head2 convertCurrency
258              
259             Returns the betfair converted amount of currency see L for details. Requires a hashref with the following parameters:
260              
261             =over
262              
263             =item *
264              
265             amount: this is the decimal amount of base currency to convert.
266              
267             =item *
268              
269             fromCurrency : this is the base currency to convert from.
270              
271             =item *
272              
273             toCurrency : this is the target currency to convert to.
274              
275             =back
276              
277             Example
278              
279             $betfair->convertCurrency({ amount => 5,
280             fromCurrency => 'GBP',
281             toCurrency => 'USD',
282             });
283              
284             =cut
285              
286             sub convertCurrency {
287             my ($self, $args) = @_;
288             my $checkParams = {
289             amount => ['decimal', 1],
290             fromCurrency => ['string', 1],
291             toCurrency => ['string', 1],
292             };
293             $args->{exchangeId} = 3;
294             return 0 unless $self->_checkParams($checkParams, $args);
295             if ($self->_doRequest('convertCurrency', $args) ) {
296             return { convertedAmount =>
297             $self->{response}->{'soap:Body'}->{'n:convertCurrencyResponse'}->{'n:Result'}->{'convertedAmount'}->{content}
298             };
299             }
300             return 0;
301             }
302              
303             =head2 getActiveEventTypes
304              
305             Returns an array of hashes of active event types or 0 on failure. See L for details. Does not require any parameters.
306              
307             Example
308              
309             my $activeEventTypes = $betfair->getActiveEventTypes;
310              
311             =cut
312              
313             sub getActiveEventTypes {
314             my $self = shift;
315             my $active_event_types =[];
316             if ($self->_doRequest('getActiveEventTypes', {exchangeId => 3}) ) {
317             foreach (@{$self->{response}->{'soap:Body'}->{'n:getActiveEventTypesResponse'}->{'n:Result'}->{'eventTypeItems'}->{'n2:EventType'}}) {
318             push(@{$active_event_types},{
319             name => $_->{'name'}->{content},
320             id => $_->{'id'}->{content},
321             exchangeId => $_->{'exchangeId'}->{content},
322             nextMarketId => $_->{'nextMarketId'}->{content},
323             });
324             }
325             return $active_event_types;
326             }
327             return 0;
328             }
329              
330             =head2 getAllCurrencies
331              
332             Returns an arrayref of currency codes and the betfair GBP exchange rate. See L. Requires no parameters.
333              
334             Example
335              
336             $betfair->getAllCurrencies;
337              
338             =cut
339              
340             sub getAllCurrencies {
341             my $self = shift;
342             my $currencies =[];
343             if ($self->_doRequest('getAllCurrencies', {exchangeId => 3}) ) {
344             foreach (@{$self->{response}->{'soap:Body'}->{'n:getAllCurrenciesResponse'}->{'n:Result'}->{'currencyItems'}->{'n2:Currency'}}) {
345             push(@{$currencies},{
346             currencyCode => $_->{'currencyCode'}->{content},
347             rateGBP => $_->{'rateGBP'}->{content},
348             });
349             }
350             return $currencies;
351             }
352             return 0;
353             }
354              
355             =head2 getAllCurrenciesV2
356              
357             Returns an arrayref of currency codes, the betfair GBP exchange rate and staking sizes for the currency. See L. Requires no parameters.
358              
359             Example
360              
361             $betfair->getAllCurrenciesV2;
362              
363             =cut
364              
365             sub getAllCurrenciesV2 {
366             my $self = shift;
367             my $currenciesV2 =[];
368             if ($self->_doRequest('getAllCurrenciesV2', {exchangeId => 3}) ) {
369             foreach (@{$self->{response}->{'soap:Body'}->{'n:getAllCurrenciesV2Response'}->{'n:Result'}->{'currencyItems'}->{'n2:CurrencyV2'}}) {
370             push(@{$currenciesV2},{
371             currencyCode => $_->{'currencyCode'}->{content},
372             rateGBP => $_->{'rateGBP'}->{content},
373             minimumStake => $_->{'minimumStake'}->{content},
374             minimumRangeStake => $_->{'minimumRangeStake'}->{content},
375             minimumBSPLayLiability => $_->{'minimumBSPLayLiability'}->{content},
376             });
377             }
378             return $currenciesV2;
379             }
380             return 0;
381             }
382              
383             =head2 getAllEventTypes
384              
385             Returns an array of hashes of all event types or 0 on failure. See L for details. Does not require any parameters.
386              
387             Example
388              
389             my $allEventTypes = $betfair->getAllEventTypes;
390              
391             =cut
392              
393             sub getAllEventTypes {
394             my $self = shift;
395             if ($self->_doRequest('getAllEventTypes', {exchangeId => 3})) {
396             my $all_event_types = [];
397             foreach (@{$self->{response}->{'soap:Body'}->{'n:getAllEventTypesResponse'}->{'n:Result'}->{'eventTypeItems'}->{'n2:EventType'} }) {
398             push(@{$all_event_types},{
399             name => $_->{'name'}->{content},
400             id => $_->{'id'}->{content},
401             exchangeId => $_->{'exchangeId'}->{content},
402             nextMarketId => $_->{'nextMarketId'}->{content},
403             });
404             }
405             return $all_event_types;
406             }
407             return 0;
408             }
409              
410             =head2 getAllMarkets
411              
412             Returns an array of hashes of all markets or 0 on failure. See L for details. Requires a hashref with the following parameters:
413              
414             =over
415              
416             =item *
417              
418             exchangeId : integer representing the exchange id to connect to, either 1 (UK and rest of the world) or 2 (Australia)
419              
420             =back
421              
422             Example
423              
424             my $allMarkets = $betfair->getAllMarkets({exchangeId => 1});
425              
426             =cut
427              
428             sub getAllMarkets {
429             my ($self, $args) = @_;
430             my $checkParams = {exchangeId => ['exchangeId', 1]};
431             return 0 unless $self->_checkParams($checkParams, $args);
432             if ($self->_doRequest('getAllMarkets', $args)) {
433             my $all_markets = [];
434             foreach (split /:/, $self->{response}->{'soap:Body'}->{'n:getAllMarketsResponse'}->{'n:Result'}->{'marketData'}->{content}) {
435             next unless $_;
436             my @market = split /~/;
437             push @{$all_markets}, {
438             marketId => $market[0],
439             marketName => $market[1],
440             marketType => $market[2],
441             marketStatus => $market[3],
442             marketDate => $market[4],
443             menuPath => $market[5],
444             eventHierarchy => $market[6],
445             betDelay => $market[7],
446             exchangeId => $market[8],
447             iso3CountryCode => $market[9],
448             lastRefresh => $market[10],
449             numberOfRunners => $market[11],
450             numberOfWinners => $market[12],
451             totalMatchedAmount => $market[13],
452             bspMarket => $market[14],
453             turningInPlay => $market[15],
454             };
455             }
456             return $all_markets;
457             }
458             return 0;
459             }
460              
461             =head2 getBet
462              
463             Returns a hashref of betfair's bet response, including an array of all matches to a bet. See L for details. Requires a hashref with the following argument:
464              
465             =over
466              
467             =item *
468              
469             betId - the betId integer of the bet to retrieve data about.
470              
471             =item *
472              
473             exchangeId : integer representing the exchange id to connect to, either 1 (UK and rest of the world) or 2 (Australia)
474              
475             =back
476              
477             Example
478              
479             my $bet = $betfair->getBet({betId => 123456789
480             exchangeId => 1,
481             });
482              
483             =cut
484              
485             sub getBet {
486             my ($self, $args) = @_;
487             my $checkParams = { betId => ['int', 1],
488             exchangeId => ['exchangeId', 1],
489             };
490             return 0 unless $self->_checkParams($checkParams, $args);
491             if ($self->_doRequest('getBet', $args)) {
492             my $response = $self->{response}->{'soap:Body'}->{'n:getBetResponse'}->{'n:Result'}->{bet};
493             my $bet = {
494             asianLineId => $response->{asianLineId}->{content},
495             avgPrice => $response->{avgPrice}->{content},
496             betCategoryType => $response->{betCategoryType}->{content},
497             betId => $response->{betId}->{content},
498             betPersistenceType => $response->{betPersistenceType}->{content},
499             betStatus => $response->{betStatus}->{content},
500             betType => $response->{betType}->{content},
501             bspLiability => $response->{bspLiability}->{content},
502             cancelledDate => $response->{cancelledDate}->{content},
503             executedBy => $response->{executedBy}->{content},
504             fullMarketName => $response->{fullMarketName}->{content},
505             handicap => $response->{handicap}->{content},
506             lapsedDate => $response->{lapsedDate}->{content},
507             marketId => $response->{marketId}->{content},
508             marketName => $response->{marketName}->{content},
509             marketType => $response->{marketType}->{content},
510             marketTypeVariant => $response->{marketTypeVariant}->{content},
511             matchedDate => $response->{matchedDate}->{content},
512             matchedSize => $response->{matchedSize}->{content},
513             matches => [],
514             placedDate => $response->{placedDate}->{content},
515             price => $response->{price}->{content},
516             profitAndLoss => $response->{profitAndLoss}->{content},
517             remainingSize => $response->{remainingSize}->{content},
518             requestedSize => $response->{requestedSize}->{content},
519             selectionId => $response->{selectionId}->{content},
520             selectionName => $response->{selectionName}->{content},
521             settledDate => $response->{settledDate}->{content},
522             voidedDate => $response->{voidedDate}->{content},
523             };
524             my $matches = $self->_forceArray($response->{matches}->{'n2:Match'});
525             foreach my $match (@{$matches}){
526             push @{$bet->{matches}}, {
527             betStatus => $match->{betStatus}->{content},
528             matchedDate => $match->{matchedDate}->{content},
529             priceMatched => $match->{priceMatched}->{content},
530             profitLoss => $match->{profitLoss}->{content},
531             settledDate => $match->{settledDate}->{content},
532             sizeMatched => $match->{sizeMatched}->{content},
533             transactionId => $match->{transactionId}->{content},
534             voidedDate => $match->{voidedDate}->{content},
535             };
536             }
537             return $bet;
538             }
539             return 0;
540             }
541              
542             =head2 getBetHistory
543              
544             Returns an arrayref of hashrefs of bets. See L for details. Requires a hashref with the following parameters:
545              
546             =over
547              
548             =item *
549              
550             betTypesIncluded : string of a valid BetStatusEnum type as defined by betfair (see L)
551              
552             =item *
553              
554             detailed : boolean string e.g. ('true' or 'false') indicating whether or not to include the details of all matches per bet.
555              
556             =item *
557              
558             eventTypeIds : an arrayref of integers that represent the betfair eventTypeIds. (e.g. [1, 6] would be football and boxing). This is not mandatory if the betTypesIncluded parameter equals 'M' or 'U'.
559              
560             =item *
561              
562             marketId : an integer representing the betfair marketId (optional).
563              
564             =item *
565              
566             marketTypesIncluded : arrayref of strings of the betfair marketTypesIncluded enum. See L for details.
567              
568             =item *
569              
570             placedDateFrom : string date for which to return records on or after this date (a string in the XML datetime format see example).
571              
572             =item *
573              
574             placedDateTo : string date for which to return records on or before this date (a string in the XML datetime format see example).
575              
576             =item *
577              
578             recordCount : integer representing the maximum number of records to retrieve (must be between 1 and 100).
579              
580             =item *
581              
582             sortBetsBy : string of a valid BetsOrderByEnum types as defined by betfair. see L
583              
584             =item *
585              
586             startRecord : integer of the index of the first record to retrieve. The index is zero-based so 0 would indicate the first record in the resultset
587              
588             =item *
589              
590             exchangeId : integer representing the exchange id to connect to, either 1 (UK and rest of the world) or 2 (Australia)
591              
592             =back
593              
594             Example
595              
596             my $betHistory = $betfair->getBetHistory({
597             betTypesIncluded => 'M',
598             detailed => 'false',
599             eventTypeIds => [6],
600             marketTypesIncluded => ['O', 'L', 'R'],
601             placedDateFrom => '2013-01-01T00:00:00.000Z',
602             placedDateTo => '2013-06-16T00:00:00.000Z',
603             recordCount => 100,
604             sortBetsBy => 'PLACED_DATE',
605             startRecord => 0,
606             exchangeId => 1,
607             });
608              
609             =cut
610              
611             sub getBetHistory {
612             my ($self, $args) = @_;
613             my $checkParams = {
614             betTypesIncluded => ['betStatusEnum', 1],
615             detailed => ['boolean', 1],
616             eventTypeIds => ['arrayInt', 1],
617             sortBetsBy => ['betsOrderByEnum', 1],
618             recordCount => ['int', 1,],
619             startRecord => ['int', 1],
620             placedDateTo => ['date', 1],
621             placedDateFrom => ['date', 1],
622             marketTypesIncluded => ['arrayMarketTypeEnum', 1],
623             marketId => ['int', 0],
624             exchangeId => ['exchangeId', 1],
625             };
626             # eventTypeIds is not mandatory if betTypesIncluded is 'M' or 'U'
627             $checkParams->{eventTypeIds}->[1] = 0 if grep{/$args->{betTypesIncluded}/} qw/M U/;
628              
629             # marketId is mandatory if betTypesIncluded is 'S', 'C', or 'V'
630             $checkParams->{marketId}->[1] = 1 if grep{/$args->betTypesIncluded/} qw/S C V/;
631            
632             return 0 unless $self->_checkParams($checkParams, $args);
633              
634             # make eventTypeIds an array of int
635             my @eventTypeIds = $args->{eventTypeIds};
636             delete $args->{eventTypeIds};
637             $args->{eventTypeIds}->{'int'} = \@eventTypeIds;
638              
639             # make marketTypesIncluded an array of marketTypeEnum
640             my @marketTypes = $args->{marketTypesIncluded};
641             delete $args->{marketTypesIncluded};
642             $args->{marketTypesIncluded}->{'MarketTypeEnum'} = \@marketTypes;
643              
644             if ($self->_doRequest('getBetHistory', $args) ) {
645             my $response = $self->_forceArray(
646             $self->{response}->{'soap:Body'}->{'n:getBetHistoryResponse'}->{'n:Result'}->{'betHistoryItems'}->{'n2:Bet'});
647             my $betHistory = [];
648             foreach (@{$response}) {
649             my $bet = {
650             asianLineId => $_->{asianLineId}->{content},
651             avgPrice => $_->{avgPrice}->{content},
652             betCategoryType => $_->{betCategoryType}->{content},
653             betId => $_->{betId}->{content},
654             betPersistenceType => $_->{betPersistenceType}->{content},
655             betStatus => $_->{betStatus}->{content},
656             betType => $_->{betType}->{content},
657             bspLiability => $_->{bspLiability}->{content},
658             cancelledDate => $_->{cancelledDate}->{content},
659             fullMarketName => $_->{fullMarketName}->{content},
660             handicap => $_->{handicap}->{content},
661             lapsedDate => $_->{lapsedDate}->{content},
662             marketId => $_->{marketId}->{content},
663             marketName => $_->{marketName}->{content},
664             marketType => $_->{marketType}->{content},
665             marketTypeVariant => $_->{marketTypeVariant}->{content},
666             matchedDate => $_->{matchedDate}->{content},
667             matchedSize => $_->{matchedSize}->{content},
668             matches => [],
669             placedDate => $_->{placedDate}->{content},
670             price => $_->{price}->{content},
671             profitAndLoss => $_->{profitAndLoss}->{content},
672             remainingSize => $_->{remainingSize}->{content},
673             requestedSize => $_->{requestedSize}->{content},
674             selectionId => $_->{selectionId}->{content},
675             selectionName => $_->{selectionName}->{content},
676             settledDate => $_->{settledDate}->{content},
677             voidedDate => $_->{voidedDate}->{content},
678             };
679             my $matches = $self->_forceArray($_->{matches}->{'n2:Match'});
680             foreach my $match (@{$matches}){
681             push @{$bet->{matches}}, {
682             betStatus => $match->{betStatus}->{content},
683             matchedDate => $match->{matchedDate}->{content},
684             priceMatched => $match->{priceMatched}->{content},
685             profitLoss => $match->{profitLoss}->{content},
686             settledDate => $match->{settledDate}->{content},
687             sizeMatched => $match->{sizeMatched}->{content},
688             transactionId => $match->{transactionId}->{content},
689             voidedDate => $match->{voidedDate}->{content},
690             };
691             }
692             push @{$betHistory}, $bet;
693             }
694             return $betHistory;
695             }
696             return 0;
697             }
698              
699             =head2 getBetLite
700              
701             Returns a hashref of bet information. See L for details. Requires a hashref with the following key pair/s:
702              
703             =over
704              
705             =item *
706              
707             betId : integer representing the betfair id for the bet to retrieve data about.
708              
709             =item *
710              
711             exchangeId : integer representing the exchange id to connect to, either 1 (UK and rest of the world) or 2 (Australia)
712              
713             =back
714              
715             Example
716              
717             my $betData = $betfair->getBetLite({betId => 123456789
718             exchangeId => 2,
719             });
720              
721             =cut
722              
723             sub getBetLite {
724             my ($self, $args) = @_;
725             my $checkParams = { betId => ['int', 1],
726             exchangeId => ['exchangeId', 1],
727             };
728             return 0 unless $self->_checkParams($checkParams, $args);
729             if ($self->_doRequest('getBetLite', $args)) {
730             my $response = $self->{response}->{'soap:Body'}->{'n:getBetLiteResponse'}->{'n:Result'}->{'betLite'};
731             return {
732             betCategoryType => $response->{betCategoryType}->{content},
733             betId => $response->{betId}->{content},
734             betPersistenceType => $response->{betPersistenceType}->{content},
735             betStatus => $response->{betStatus}->{content},
736             bspLiability => $response->{bspLiability}->{content},
737             marketId => $response->{marketId}->{content},
738             matchedSize => $response->{matchedSize}->{content},
739             remainingSize => $response->{remainingSize}->{content},
740             };
741             }
742             return 0;
743             }
744              
745              
746             =head2 getBetMatchesLite
747              
748             Returns an arrayref of hashrefs of matched bet information. See L for details. Requires a hashref with the following key pair/s:
749              
750             =over
751              
752             =item *
753              
754             betId : integer representing the betfair id for the bet to retrieve data about.
755              
756             =item *
757              
758             exchangeId : integer representing the exchange id to connect to, either 1 (UK and rest of the world) or 2 (Australia)
759              
760             =back
761              
762             Example
763              
764             my $betData = $betfair->getBetMatchesLite({ betId => 123456789
765             exchangeId => 1,
766             });
767              
768             =cut
769              
770             sub getBetMatchesLite {
771             my ($self, $args) = @_;
772             my $checkParams = { betId => ['int', 1],
773             exchangeId => ['exchangeId', 0],
774             };
775             return 0 unless $self->_checkParams($checkParams, $args);
776             if ($self->_doRequest('getBetMatchesLite', $args)) {
777             my $response = $self->_forceArray($self->{response}->{'soap:Body'}->{'n:getBetMatchesLiteResponse'}->{'n:Result'}->{matchLites}->{'n2:MatchLite'});
778             my $matchedBets = [];
779             foreach (@{$response}) {
780             push @{$matchedBets}, {
781             betStatus => $_->{betStatus}->{content},
782             matchedDate => $_->{matchedDate}->{content},
783             priceMatched => $_->{priceMatched}->{content},
784             sizeMatched => $_->{sizeMatched}->{content},
785             transactionId => $_->{transactionId}->{content},
786             };
787             }
788             return $matchedBets;
789             }
790             return 0;
791             }
792              
793             =head2 getCompleteMarketPricesCompressed
794              
795             Returns a hashref of market data including an arrayhashref of individual selection prices data. See L for details. Note that this method de-serializes the compressed string returned by the betfair method into a Perl data structure. Requires:
796              
797             =over
798              
799             =item *
800              
801             marketId : integer representing the betfair market id.
802              
803             =item *
804              
805             currencyCode : string representing the three letter ISO currency code. Only certain currencies are accepted by betfair GBP, USD, EUR, NOK, SGD, SEK, AUD, CAD, HKD, DKK (optional)
806              
807             =item *
808              
809             exchangeId : integer representing the exchange id to connect to, either 1 (UK and rest of the world) or 2 (Australia)
810              
811             =back
812              
813             Example
814              
815             my $marketPriceData = $betfair->getCompleteMarketPricesCompressed({ marketId => 123456789,
816             exchangeId => 2,
817             });
818              
819             =cut
820              
821             sub getCompleteMarketPricesCompressed {
822             my ($self, $args) = @_;
823             my $checkParams = {
824             marketId => ['int', 1],
825             currencyCode => ['currencyCode', 0],
826             exchangeId => ['exchangeId', 1],
827             };
828             return 0 unless $self->_checkParams($checkParams, $args);
829             if ($self->_doRequest('getCompleteMarketPricesCompressed', $args)) {
830             my $response = $self->{response}->{'soap:Body'}->{'n:getCompleteMarketPricesCompressedResponse'}->{'n:Result'}->{'completeMarketPrices'}->{content};
831             my @fields = split /:/, $response;
832             #109799180~0~;name,timeRemoved,reductionFactor;
833             my $idAndRemovedRunners = shift @fields; # not used yet
834             my $selections = [];
835             foreach my $selection (@fields) {
836             my @selectionFields = split /\|/, $selection;
837             my @selectionData = split /~/, shift @selectionFields;
838             my $prices = [];
839             next unless $selectionFields[0];
840             my @selectionPrices = split /~/, $selectionFields[0];
841             while (@selectionPrices) {
842             push @{$prices}, {
843             price => shift @selectionPrices,
844             back_amount => shift @selectionPrices,
845             lay_amount => shift @selectionPrices,
846             bsp_back_amount => shift @selectionPrices,
847             bsp_lay_amount => shift @selectionPrices,
848             };
849             }
850             push @{$selections}, {
851             prices => $prices,
852             selectionId => $selectionData[0],
853             orderIndex => $selectionData[1],
854             totalMatched => $selectionData[2],
855             lastPriceMatched => $selectionData[3],
856             asianHandicap => $selectionData[4],
857             reductionFactor => $selectionData[5],
858             vacant => $selectionData[6],
859             asianLineId => $selectionData[7],
860             farPriceSp => $selectionData[8],
861             nearPriceSp => $selectionData[9],
862             actualPriceSp => $selectionData[10],
863             };
864             }
865             return { marketId => $args->{marketId},
866             selections => $selections,
867             };
868             }
869             return 0;
870             }
871              
872             =head2 getCurrentBets
873              
874             Returns an arrayref of hashrefs of current bets or 0 on failure. See L for details. Requires a hashref with the following parameters:
875              
876             =over
877              
878             =item *
879              
880             betStatus : string of a valid BetStatus enum type as defined by betfair see L for details.
881              
882             =item *
883              
884             detailed : string of either true or false
885              
886             =item *
887              
888             orderBy : string of a valid BetsOrderByEnum types as defined by betfair (see L)
889              
890             =item *
891              
892             recordCount : integer of the maximum number of records to return
893              
894             =item *
895              
896             startRecord : integer of the index of the first record to retrieve. The index is zero-based so 0 would indicate the first record in the resultset
897              
898             =item *
899              
900             noTotalRecordCount : string of either true or false
901              
902             =item *
903              
904             marketId : integer of the betfair market id for which current bets are required (optional)
905              
906             =item *
907              
908             exchangeId : integer representing the exchange id to connect to, either 1 (UK and rest of the world) or 2 (Australia)
909              
910             =back
911              
912             Example
913              
914             my $bets = $betfair->getCurrentBets({
915             betStatus => 'M',
916             detailed => 'false',
917             orderBy => 'PLACED_DATE',
918             recordCount => 100,
919             startRecord => 0,
920             noTotalRecordCount => 'true',
921             exchangeId => 1,
922             });
923              
924             =cut
925              
926             sub getCurrentBets {
927             my ($self, $args) = @_;
928             my $checkParams = {
929             betStatus => ['betStatusEnum', 1],
930             detailed => ['boolean', 1],
931             orderBy => ['betsOrderByEnum', 1],
932             recordCount => ['int', 1,],
933             startRecord => ['int', 1],
934             noTotalRecordCount => ['boolean', 1],
935             marketId => ['int',0],
936             exchangeId => ['exchangeId', 1],
937             };
938             return 0 unless $self->_checkParams($checkParams, $args);
939             if ($self->_doRequest('getCurrentBets', $args) ) {
940             my $response = $self->_forceArray(
941             $self->{response}->{'soap:Body'}->{'n:getCurrentBetsResponse'}->{'n:Result'}->{'bets'}->{'n2:Bet'});
942             my $current_bets = [];
943             foreach (@{$response}) {
944             my $bet = {
945             asianLineId => $_->{asianLineId}->{content},
946             avgPrice => $_->{avgPrice}->{content},
947             betCategoryType => $_->{betCategoryType}->{content},
948             betId => $_->{betId}->{content},
949             betPersistenceType => $_->{betPersistenceType}->{content},
950             betStatus => $_->{betStatus}->{content},
951             betType => $_->{betType}->{content},
952             bspLiability => $_->{bspLiability}->{content},
953             cancelledDate => $_->{cancelledDate}->{content},
954             fullMarketName => $_->{fullMarketName}->{content},
955             handicap => $_->{handicap}->{content},
956             lapsedDate => $_->{lapsedDate}->{content},
957             marketId => $_->{marketId}->{content},
958             marketName => $_->{marketName}->{content},
959             marketType => $_->{marketType}->{content},
960             marketTypeVariant => $_->{marketTypeVariant}->{content},
961             matchedDate => $_->{matchedDate}->{content},
962             matchedSize => $_->{matchedSize}->{content},
963             matches => [],
964             placedDate => $_->{placedDate}->{content},
965             price => $_->{price}->{content},
966             profitAndLoss => $_->{profitAndLoss}->{content},
967             remainingSize => $_->{remainingSize}->{content},
968             requestedSize => $_->{requestedSize}->{content},
969             selectionId => $_->{selectionId}->{content},
970             selectionName => $_->{selectionName}->{content},
971             settledDate => $_->{settledDate}->{content},
972             voidedDate => $_->{voidedDate}->{content},
973             };
974             my $matches = $self->_forceArray($_->{matches}->{'n2:Match'});
975             foreach my $match (@{$matches}){
976             push @{$bet->{matches}}, {
977             betStatus => $match->{betStatus}->{content},
978             matchedDate => $match->{matchedDate}->{content},
979             priceMatched => $match->{priceMatched}->{content},
980             profitLoss => $match->{profitLoss}->{content},
981             settledDate => $match->{settledDate}->{content},
982             sizeMatched => $match->{sizeMatched}->{content},
983             transactionId => $match->{transactionId}->{content},
984             voidedDate => $match->{voidedDate}->{content},
985             };
986             }
987             push @{$current_bets}, $bet;
988             }
989             return $current_bets;
990             }
991             return 0;
992             }
993              
994             =head2 getCurrentBetsLite
995              
996             Returns an arrayref of hashrefs of current bets for a single market or the entire exchange. See L for details. Requires a hashref with the following parameters:
997              
998             =over
999              
1000             =item *
1001              
1002             betStatus : string of a valid BetStatus enum type as defined by betfair see L for details.
1003              
1004             =item *
1005              
1006             orderBy : string of a valid BetsOrderByEnum types as defined by betfair (see L)
1007              
1008             =item *
1009              
1010             recordCount : integer of the maximum number of records to return
1011              
1012             =item *
1013              
1014             startRecord : integer of the index of the first record to retrieve. The index is zero-based so 0 would indicate the first record in the resultset
1015              
1016             =item *
1017              
1018             noTotalRecordCount : string of either 'true' or 'false' to return a total record count
1019              
1020             =item *
1021              
1022             marketId : integer of the betfair market id for which current bets are required (optional)
1023              
1024             =item *
1025              
1026             exchangeId : integer representing the exchange id to connect to, either 1 (UK and rest of the world) or 2 (Australia)
1027              
1028             =back
1029              
1030             Example
1031              
1032             my $bets = $betfair->getCurrentBetsLite({
1033             betStatus => 'M',
1034             orderBy => 'PLACED_DATE',
1035             recordCount => 100,
1036             startRecord => 0,
1037             noTotalRecordCount => 'true',
1038             exchangeId => 1,
1039             });
1040              
1041             =cut
1042              
1043             sub getCurrentBetsLite {
1044             my ($self, $args) = @_;
1045             my $checkParams = {
1046             betStatus => ['betStatusEnum', 1],
1047             orderBy => ['betsOrderByEnum', 1],
1048             recordCount => ['int', 1,],
1049             startRecord => ['int', 1],
1050             noTotalRecordCount => ['boolean', 1],
1051             marketId => ['int', 0],
1052             exchangeId => ['exchangeId', 1],
1053             };
1054             return 0 unless $self->_checkParams($checkParams, $args);
1055             if ($self->_doRequest('getCurrentBetsLite', $args) ) {
1056             my $response = $self->_forceArray(
1057             $self->{response}->{'soap:Body'}->{'n:getCurrentBetsLiteResponse'}->{'n:Result'}->{'betLites'}->{'n2:BetLite'});
1058             my $current_bets = [];
1059             foreach (@{$response}) {
1060             push @{$current_bets}, {
1061             betCategoryType => $_->{betCategoryType}->{content},
1062             betId => $_->{betId}->{content},
1063             betPersistenceType => $_->{betPersistenceType}->{content},
1064             betStatus => $_->{betStatus}->{content},
1065             bspLiability => $_->{bspLiability}->{content},
1066             marketId => $_->{marketId}->{content},
1067             matchedSize => $_->{matchedSize}->{content},
1068             remainingSize => $_->{remainingSize}->{content},
1069             };
1070             }
1071             return $current_bets;
1072             }
1073             return 0;
1074             }
1075              
1076             =head2 getDetailAvailableMktDepth
1077              
1078             Returns an arrayref of current back and lay offers in a market for a specific selection. See L for details. Requires a hashref with the following arguments:
1079              
1080             =over
1081              
1082             =item *
1083              
1084             marketId : integer representing the betfair market id to return the market prices for.
1085              
1086             =item *
1087              
1088             selectionId : integer representing the betfair selection id to return market prices for.
1089              
1090             =item *
1091              
1092             asianLineId : integer representing the betfair asian line id of the market - only required if the market is an asian line market (optional).
1093              
1094             =item *
1095              
1096             exchangeId : integer representing the exchange id to connect to, either 1 (UK and rest of the world) or 2 (Australia)
1097              
1098             =item *
1099              
1100             currencyCode : string representing the three letter ISO currency code. Only certain currencies are accepted by betfair GBP, USD, EUR, NOK, SGD, SEK, AUD, CAD, HKD, DKK (optional)
1101              
1102             =back
1103              
1104             Example
1105              
1106             my $selectionPrices = $betfair->getDetailAvailableMktDepth({marketId => 123456789,
1107             selectionId => 987654321,
1108             exchangeId => 1,
1109             });
1110              
1111             =cut
1112              
1113             sub getDetailAvailableMktDepth {
1114             my ($self, $args) = @_;
1115             my $checkParams = { marketId => ['int', 1],
1116             selectionId => ['int', 1],
1117             asianLineId => ['int', 0],
1118             exchangeId => ['exchangeId', 1],
1119             currencyCode=> ['currencyCode', 0],
1120             };
1121             return 0 unless $self->_checkParams($checkParams, $args);
1122             if ($self->_doRequest('getDetailAvailableMktDepth', $args)) {
1123             my $response = $self->_forceArray(
1124             $self->{response}->{'soap:Body'}->{'n:getDetailAvailableMktDepthResponse'}->{'n:Result'}->{'priceItems'}->{'n2:AvailabilityInfo'});
1125             my $marketPrices = [];
1126             foreach (@{$response}){
1127             push @{$marketPrices}, {
1128             odds => $_->{odds}->{content},
1129             totalAvailableBackAmount=> $_->{totalAvailableBackAmount}->{content},
1130             totalAvailableLayAmount => $_->{totalAvailableLayAmount}->{content},
1131             totalBspBackAmount => $_->{totalBspBackAmount}->{content},
1132             totalBspLayAmount => $_->{totalBspLayAmount}->{content},
1133             };
1134             }
1135             return $marketPrices;
1136             }
1137             return 0;
1138             }
1139              
1140             =head2 getEvents
1141              
1142             Returns an array of hashes of events / markets or 0 on failure. See L for details. Requires:
1143              
1144             =over
1145              
1146             =item *
1147              
1148             eventParentId : an integer which is the betfair event id of the parent event
1149              
1150             =back
1151              
1152             Example
1153              
1154             # betfair event id of tennis is 14
1155             my $tennisEvents = $betfair->getEvents({eventParentId => 14});
1156              
1157             =cut
1158              
1159             sub getEvents {
1160             my ($self, $args) = @_;
1161             my $checkParams = { eventParentId => ['int', 1] };
1162             return 0 unless $self->_checkParams($checkParams, $args);
1163             $args->{exchangeId} = 3;
1164             if ($self->_doRequest('getEvents', $args)) {
1165             my $event_response = $self->_forceArray($self->{response}->{'soap:Body'}->{'n:getEventsResponse'}->{'n:Result'}->{'eventItems'}->{'n2:BFEvent'});
1166             my $events;
1167             foreach (@{$event_response}) {
1168             next unless defined($_->{eventId}->{content});
1169             push @{$events->{events}}, {
1170             eventId => $_->{eventId}->{content},
1171             eventName => $_->{eventName}->{content},
1172             menuLevel => $_->{menuLevel}->{content},
1173             orderIndex => $_->{orderIndex}->{content},
1174             eventTypeId => $_->{eventTypeId}->{content},
1175             startTime => $_->{startTime}->{content},
1176             timezone => $_->{timezone}->{content},
1177             };
1178             }
1179             my $market_response = $self->_forceArray(
1180             $self->{response}->{'soap:Body'}->{'n:getEventsResponse'}->{'n:Result'}->{'marketItems'}->{'n2:MarketSummary'});
1181             foreach (@{$market_response}) {
1182             next unless defined($_->{marketId}->{content});
1183             push @{$events->{markets}}, {
1184             marketId => $_->{marketId}->{content},
1185             marketName => $_->{marketName}->{content},
1186             menuLevel => $_->{menuLevel}->{content},
1187             orderIndex => $_->{orderIndex}->{content},
1188             marketType => $_->{marketType}->{content},
1189             marketTypeVariant => $_->{marketTypeVariant}->{content},
1190             exchangeId => $_->{exchangeId}->{content},
1191             venue => $_->{venue}->{content},
1192             betDelay => $_->{betDelay}->{content},
1193             numberOfWinners => $_->{numberOfWinners}->{content},
1194             startTime => $_->{startTime}->{content},
1195             timezone => $_->{timezone}->{content},
1196             eventTypeId => $_->{eventTypeId}->{content},
1197             };
1198             }
1199             return $events;
1200             }
1201             return 0;
1202             }
1203              
1204             =head2 getInPlayMarkets
1205              
1206             Returns an arrayref of hashrefs of market data or 0 on failure. See L for details. Requires the following parameter:
1207              
1208             =over
1209              
1210             =item *
1211              
1212             exchangeId : integer representing the exchange id to connect to, either 1 (UK and rest of the world) or 2 (Australia)
1213              
1214             =back
1215              
1216             Example
1217              
1218             my $inPlayMarkets = $betfair->getInPlayMarkets({exchangeId => 1});
1219              
1220             =cut
1221              
1222             sub getInPlayMarkets {
1223             my ($self, $args) = @_;
1224             my $checkParams = { exchangeId => ['exchangeId', 1] };
1225             return 0 unless $self->_checkParams($checkParams, $args);
1226             if ($self->_doRequest('getInPlayMarkets', $args) ) {
1227             my $response = $self->{response}->{'soap:Body'}->{'n:getInPlayMarketsResponse'}->{'n:Result'}->{'marketData'}->{content};
1228             my @markets;
1229             foreach (split /:/, $response) {
1230             next unless $_;
1231             my @data = split /~/, $_;
1232             push(@markets, {
1233             marketId => $data[0],
1234             marketName => $data[1],
1235             marketType => $data[2],
1236             marketStatus => $data[3],
1237             eventDate => $data[4],
1238             menuPath => $data[5],
1239             eventHierarchy => $data[6],
1240             betDelay => $data[7],
1241             exchangeId => $data[8],
1242             isoCountryCode => $data[9],
1243             lastRefresh => $data[10],
1244             numberOfRunner => $data[11],
1245             numberOfWinners => $data[12],
1246             totalAmountMatched => $data[13],
1247             bspMarket => $data[14],
1248             turningInPlay => $data[15],
1249             });
1250              
1251             }
1252             return \@markets;
1253             }
1254             return 0;
1255             }
1256              
1257             =head2 getMarket
1258              
1259             Returns a hash of market data or 0 on failure. See L for details. Requires:
1260              
1261             =over
1262              
1263             =item *
1264              
1265             marketId : integer which is the betfair id of the market
1266              
1267             =item *
1268              
1269             exchangeId : integer representing the exchange id to connect to, either 1 (UK and rest of the world) or 2 (Australia)
1270              
1271             =back
1272              
1273             Example
1274              
1275             my $marketData = $betfair->getMarket({ marketId => 108690258,
1276             exchangeId => 2,
1277             });
1278              
1279             =cut
1280              
1281             sub getMarket {
1282             my ($self, $args) = @_;
1283             my $checkParams = { marketId => ['int', 1],
1284             exchangeId => ['exchangeId', 1],
1285             };
1286             return 0 unless $self->_checkParams($checkParams, $args);
1287             if ($self->_doRequest('getMarket', $args) ) {
1288             my $response = $self->{response}->{'soap:Body'}->{'n:getMarketResponse'}->{'n:Result'}->{'market'};
1289             my $runners_list = $self->_forceArray($response->{'runners'}->{'n2:Runner'});
1290             my @parsed_runners = ();
1291             foreach (@{$runners_list}) {
1292             push(@parsed_runners, {
1293             name => $_->{'name'}->{content},
1294             selectionId => $_->{'selectionId'}->{content},
1295             });
1296             }
1297             return {
1298             name => $response->{'name'}->{content},
1299             marketId => $response->{'marketId'}->{content},
1300             eventTypeId => $response->{'eventTypeId'}->{content},
1301             marketTime => $response->{'marketTime'}->{content},
1302             marketStatus => $response->{'marketStatus'}->{content},
1303             runners => \@parsed_runners,
1304             marketDescription => $response->{'marketDescription'}->{content},
1305             activeFlag => 1,
1306             };
1307             }
1308             return 0;
1309             }
1310              
1311             =head2 getMarketInfo
1312              
1313             Returns a hash of market data or 0 on failure. See L for details. Requires a hashref with the following parameters:
1314              
1315             =over
1316              
1317             =item *
1318              
1319             marketId : integer which is the betfair id of the market
1320              
1321             =item *
1322              
1323             exchangeId : integer representing the exchange id to connect to, either 1 (UK and rest of the world) or 2 (Australia)
1324              
1325             =back
1326              
1327             Example
1328              
1329             my $marketData = $betfair->getMarketInfo({ marketId => 108690258,
1330             exchangeId => 1,
1331             });
1332              
1333             =cut
1334              
1335             sub getMarketInfo {
1336             my ($self, $args) = @_;
1337             my $checkParams = { marketId => ['int', 1],
1338             exchangeId => ['exchangeId', 1],
1339             };
1340             return 0 unless $self->_checkParams($checkParams, $args);
1341             if ($self->_doRequest('getMarketInfo', $args) ) {
1342             my $response = $self->{response}->{'soap:Body'}->{'n:getMarketInfoResponse'}->{'n:Result'}->{'marketLite'};
1343             return {
1344             delay => $response->{'delay'}->{content},
1345             numberOfRunners => $response->{'numberOfRunners'}->{content},
1346             marketSuspendTime => $response->{'marketSuspendTime'}->{content},
1347             marketTime => $response->{'marketTime'}->{content},
1348             marketStatus => $response->{'marketStatus'}->{content},
1349             openForBspBetting => $response->{'openForBspBetting'}->{content},
1350             };
1351             }
1352             return 0;
1353             }
1354              
1355             =head2 getMarketPrices
1356              
1357             Returns a hashref of market data or 0 on failure. See L for details. Requires:
1358              
1359             =over
1360              
1361             =item *
1362              
1363             marketId : integer which is the betfair id of the market
1364              
1365             =item *
1366              
1367             currencyCode : string representing the three letter ISO currency code. Only certain currencies are accepted by betfair GBP, USD, EUR, NOK, SGD, SEK, AUD, CAD, HKD, DKK (optional)
1368              
1369             =item *
1370              
1371             exchangeId : integer representing the exchange id to connect to, either 1 (UK and rest of the world) or 2 (Australia)
1372              
1373             =back
1374              
1375             Example
1376              
1377             my $marketPrices = $betfair->getMarketPrices({ marketId => 108690258
1378             exchangeId => 2,
1379             });
1380              
1381             =cut
1382              
1383             sub getMarketPrices {
1384             my ($self, $args) = @_;
1385             my $checkParams = {
1386             marketId => ['int', 1],
1387             currencyCode => ['currencyCode', 0],
1388             exchangeId => ['exchangeId', 1],
1389             };
1390             return 0 unless $self->_checkParams($checkParams, $args);
1391             if ($self->_doRequest('getMarketPrices', $args) ) {
1392             my $response = $self->{response}->{'soap:Body'}->{'n:getMarketPricesResponse'}->{'n:Result'}->{'marketPrices'};
1393             my $runners_list = $self->_forceArray($response->{'runnerPrices'}->{'n2:RunnerPrices'});
1394             my @parsed_runners = ();
1395             foreach my $runner (@{$runners_list}) {
1396             my $bestPricesToBack = $self->_forceArray($runner->{bestPricesToBack}->{'n2:Price'});
1397             my @backPrices = ();
1398             foreach my $backPrice (@{$bestPricesToBack}){
1399             push(@backPrices, {
1400             amountAvailable => $backPrice->{amountAvailable}->{content},
1401             betType => $backPrice->{betType}->{content},
1402             depth => $backPrice->{depth}->{content},
1403             price => $backPrice->{price}->{content},
1404             });
1405             }
1406             my $bestPricesToLay = $self->_forceArray($runner->{bestPricesToLay}->{'n2:Price'});
1407             my @layPrices = ();
1408             foreach my $layPrice (@{$bestPricesToLay}){
1409             push(@layPrices, {
1410             amountAvailable => $layPrice->{amountAvailable}->{content},
1411             betType => $layPrice->{betType}->{content},
1412             depth => $layPrice->{depth}->{content},
1413             price => $layPrice->{price}->{content},
1414             });
1415             }
1416             push(@parsed_runners, {
1417             actualBSP => $runner->{'actualBSP'}->{content},
1418             asianLineId => $runner->{asianLineId}->{content},
1419             bestPricesToBack => \@backPrices,
1420             bestPricesToLay => \@layPrices,
1421             farBSP => $runner->{farBSP}->{content},
1422             handicap => $runner->{handicap}->{content},
1423             lastPriceMatched => $runner->{lastPriceMatched}->{content},
1424             nearBSP => $runner->{nearBSP}->{content},
1425             reductionFactor => $runner->{reductionFactor}->{content},
1426             selectionId => $runner->{selectionId}->{content},
1427             sortOrder => $runner->{sortOrder}->{content},
1428             totalAmountMatched => $runner->{totalAmountMatched}->{content},
1429             vacant => $runner->{vacant}->{content},
1430             });
1431             }
1432             return {
1433             bspMarket => $response->{bspMarket}->{content},
1434             currencyCode => $response->{currencyCode}->{content},
1435             delay => $response->{delay}->{content},
1436             discountAllowed => $response->{discountAllowed}->{content},
1437             lastRefresh => $response->{lastRefresh}->{content},
1438             marketBaseRate => $response->{marketBaseRate}->{content},
1439             marketId => $response->{marketId}->{content},
1440             marketInfo => $response->{marketInfo}->{content},
1441             marketStatus => $response->{marketStatus}->{content},
1442             numberOfWinners => $response->{numberOfWinners}->{content},
1443             removedRunners => $response->{removedRunners}->{content},
1444             runners => \@parsed_runners,
1445             };
1446             }
1447             return 0;
1448             }
1449              
1450             =head2 getMarketPricesCompressed
1451              
1452             Returns a hashref of market data including an arrayhashref of individual selection prices data. See L for details. Note that this method de-serializes the compressed string returned by the betfair method into a Perl data structure. Requires:
1453              
1454             =over
1455              
1456             =item *
1457              
1458             marketId : integer representing the betfair market id.
1459              
1460             =item *
1461              
1462             currencyCode : string representing the three letter ISO currency code. Only certain currencies are accepted by betfair GBP, USD, EUR, NOK, SGD, SEK, AUD, CAD, HKD, DKK (optional)
1463              
1464             =item *
1465              
1466             exchangeId : integer representing the exchange id to connect to, either 1 (UK and rest of the world) or 2 (Australia)
1467              
1468             =back
1469              
1470             Example
1471              
1472             my $marketPriceData = $betfair->getMarketPricesCompressed({marketId => 123456789});
1473              
1474             =cut
1475              
1476             sub getMarketPricesCompressed {
1477             my ($self, $args) = @_;
1478             my $checkParams = { marketId => ['int', 1],
1479             currencyCode=> ['currencyCode', 0],
1480             exchangeId => ['exchangeId', 1],
1481             };
1482             return 0 unless $self->_checkParams($checkParams, $args);
1483             if ($self->_doRequest('getMarketPricesCompressed', $args)) {
1484             my $response = $self->{response}->{'soap:Body'}->{'n:getMarketPricesCompressedResponse'}->{'n:Result'}->{'marketPrices'}->{content};
1485             my @fields = split /:/, $response;
1486             my @marketData = split /~/, shift @fields;
1487             my @removedRunners;
1488             if ($marketData[9]){
1489             foreach (split /;/, $marketData[9]){
1490             next unless $_;
1491             my @removedRunnerData = split /,/;
1492             push (@removedRunners, {
1493             selectionId => $removedRunnerData[0],
1494             timeRemoved => $removedRunnerData[1],
1495             reductionFactor => $removedRunnerData[2],
1496             });
1497             }
1498             }
1499             my @selections;
1500             foreach my $selection (@fields) {
1501             my @selectionFields = split /\|/, $selection;
1502             next unless $selectionFields[0];
1503             my @selectionData = split /~/, $selectionFields[0];
1504             my (@backPrices, @layPrices);
1505             my @backPriceData = split /~/, $selectionFields[1];
1506             while (@backPriceData) {
1507             push (@backPrices, {
1508             price => shift @backPriceData,
1509             amount => shift @backPriceData,
1510             offerType => shift @backPriceData,
1511             depth => shift @backPriceData,
1512             });
1513             }
1514             my @layPriceData = split /~/, $selectionFields[2];
1515             while (@layPriceData) {
1516             push (@layPrices, {
1517             price => shift @layPriceData,
1518             amount => shift @layPriceData,
1519             offerType => shift @layPriceData,
1520             depth => shift @layPriceData,
1521             });
1522             }
1523             push (@selections, {
1524             backPrices => \@backPrices,
1525             layPrices => \@layPrices,
1526             selectionId => $selectionData[0],
1527             orderIndex => $selectionData[1],
1528             totalMatched => $selectionData[2],
1529             lastPriceMatched => $selectionData[3],
1530             asianHandicap => $selectionData[4],
1531             reductionFactor => $selectionData[5],
1532             vacant => $selectionData[6],
1533             farPriceSp => $selectionData[7],
1534             nearPriceSp => $selectionData[8],
1535             actualPriceSp => $selectionData[9],
1536             });
1537             }
1538             return { marketId => $args->{marketId},
1539             currency => $marketData[1],
1540             marketStatus => $marketData[2],
1541             InPlayDelay => $marketData[3],
1542             numberOfWinners => $marketData[4],
1543             marketInformation => $marketData[5],
1544             discountAllowed => $marketData[6],
1545             marketBaseRate => $marketData[7],
1546             refreshTimeMilliseconds => $marketData[8],
1547             BSPmarket => $marketData[10],
1548             removedRunnerInformation=> \@removedRunners,
1549             selections => \@selections,
1550             };
1551             }
1552             return 0;
1553             }
1554              
1555             =head2 getMUBets
1556              
1557             Returns an arrayref of hashes of bets or 0 on failure. See L for details. Requires:
1558              
1559             =over
1560              
1561             =item *
1562              
1563             betStatus : string of betfair betStatusEnum type, must be either matched, unmatched or both (M, U, MU). See L
1564              
1565             =item *
1566              
1567             orderBy : string of a valid BetsOrderByEnum types as defined by betfair. see L
1568              
1569             =item *
1570              
1571             recordCount : integer of the maximum number of records to return
1572              
1573             =item *
1574              
1575             startRecord : integer of the index of the first record to retrieve. The index is zero-based so 0 would indicate the first record in the resultset
1576              
1577             =item *
1578              
1579             noTotalRecordCount : string of either true or false
1580              
1581             =item *
1582              
1583             marketId : integer of the betfair market id for which current bets are required (optional)
1584              
1585             =item *
1586              
1587             betIds : an array of betIds (optional). If included, betStatus must be 'MU'.
1588              
1589             =item *
1590              
1591             exchangeId : integer representing the exchange id to connect to, either 1 (UK and rest of the world) or 2 (Australia)
1592              
1593             =back
1594              
1595             Example
1596              
1597             my $muBets = $betfair->getMUBets({
1598             betStatus => 'MU',
1599             orderBy => 'PLACED_DATE',
1600             recordCount => 1000,
1601             startRecord => 0,
1602             noTotalRecordCount => 'true',
1603             sortOrder => 'ASC',
1604             marketId => 123456789,
1605             exchangeId => 1,
1606             });
1607              
1608             =cut
1609              
1610             sub getMUBets {
1611             my ($self, $args ) = @_;
1612             my $checkParams = {
1613             betStatus => ['betStatusEnum', 1],
1614             orderBy => ['betsOrderByEnum', 1],
1615             recordCount => ['int', 1,],
1616             startRecord => ['int', 1],
1617             marketId => ['int', 0],
1618             sortOrder => ['sortOrderEnum', 1],
1619             betIds => ['arrayInt', 0],
1620             exchangeId => ['exchangeId', 1],
1621             };
1622             return 0 unless $self->_checkParams($checkParams, $args);
1623             if (exists $args->{betIds}) {
1624             my @betIds = $args->{betIds};
1625             $args->{betIds} = {betId => \@betIds};
1626             }
1627             my $mu_bets = [];
1628             if ($self->_doRequest('getMUBets', $args)) {
1629             my $response = $self->_forceArray(
1630             $self->{response}->{'soap:Body'}->{'n:getMUBetsResponse'}->{'n:Result'}->{'bets'}->{'n2:MUBet'});
1631             foreach (@{$response} ) {
1632             push @{$mu_bets}, {
1633             marketId => $_->{'marketId'}->{content},
1634             betType => $_->{'betType'}->{content},
1635             transactionId => $_->{'transactionId'}->{content},
1636             size => $_->{'size'}->{content},
1637             placedDate => $_->{'placedDate'}->{content},
1638             betId => $_->{'betId'}->{content},
1639             betStatus => $_->{'betStatus'}->{content},
1640             betCategory_type => $_->{'betCategoryType'}->{content},
1641             betPersistence => $_->{'betPersistenceType'}->{content},
1642             matchedDate => $_->{'matchedDate'}->{content},
1643             selectionId => $_->{'selectionId'}->{content},
1644             price => $_->{'price'}->{content},
1645             bspLiability => $_->{'bspLiability'}->{content},
1646             handicap => $_->{'handicap'}->{content},
1647             asianLineId => $_->{'asianLineId'}->{content}
1648             };
1649             }
1650             return $mu_bets;
1651             }
1652             return 0;
1653             }
1654              
1655             =head2 getMUBetsLite
1656              
1657             Returns an arrayref of hashes of bets or 0 on failure. See L for details. Requires:
1658              
1659             =over
1660              
1661             =item *
1662              
1663             betStatus : string of betfair betStatusEnum type, must be either matched, unmatched or both (M, U, MU). See L
1664              
1665             =item *
1666              
1667             marketId : integer of the betfair market id for which current bets are required (optional)
1668              
1669             =item *
1670              
1671             excludeLastSecond : boolean string value ('true' or 'false'). If true then excludes bets matched in the past second (optional)
1672              
1673             =item *
1674              
1675             matchedSince : a string datetime for which to only return bets matched since this datetime. Must be a valid XML datetime format, see example below (optional)
1676              
1677             =item *
1678              
1679             orderBy : string of a valid BetsOrderByEnum types as defined by betfair. see L
1680              
1681             =item *
1682              
1683             recordCount : integer of the maximum number of records to return
1684              
1685             =item *
1686              
1687             startRecord : integer of the index of the first record to retrieve. The index is zero-based so 0 would indicate the first record in the resultset
1688              
1689             =item *
1690              
1691             sortOrder : string of the betfair sortOrder enumerated type (either 'ASC' or 'DESC'). See L for details.
1692              
1693             =item *
1694              
1695             betIds : an array of betIds (optional). If included, betStatus must be 'MU'.
1696              
1697             =item *
1698              
1699             exchangeId : integer representing the exchange id to connect to, either 1 (UK and rest of the world) or 2 (Australia)
1700              
1701             =back
1702              
1703             Example
1704              
1705             my $muBets = $betfair->getMUBetsLite({
1706             betStatus => 'MU',
1707             orderBy => 'PLACED_DATE',
1708             excludeLastSecond => 'false',
1709             recordCount => 100,
1710             startRecord => 0,
1711             matchedSince => '2013-06-01T00:00:00.000Z',
1712             sortOrder => 'ASC',
1713             marketId => 123456789,
1714             exchangeId => 1,
1715             });
1716              
1717             =cut
1718              
1719             sub getMUBetsLite {
1720             my ($self, $args ) = @_;
1721             my $checkParams = {
1722             betStatus => ['betStatusEnum', 1],
1723             orderBy => ['betsOrderByEnum', 1],
1724             matchedSince => ['date', 0],
1725             excludeLastSecond => ['boolean', 0],
1726             recordCount => ['int', 1,],
1727             startRecord => ['int', 1],
1728             marketId => ['int', 0],
1729             sortOrder => ['sortOrderEnum', 1],
1730             betIds => ['arrayInt', 0],
1731             exchangeId => ['exchangeId', 1],
1732             };
1733             return 0 unless $self->_checkParams($checkParams, $args);
1734             if (exists $args->{betIds}) {
1735             my @betIds = $args->{betIds};
1736             $args->{betIds} = {betId => \@betIds};
1737             }
1738             my @muBetsLite;
1739             if ($self->_doRequest('getMUBetsLite', $args)) {
1740             my $response = $self->_forceArray(
1741             $self->{response}->{'soap:Body'}->{'n:getMUBetsLiteResponse'}->{'n:Result'}->{'betLites'}->{'n2:MUBetLite'});
1742             foreach (@{$response} ) {
1743             push (@muBetsLite, {
1744             betCategoryType => $_->{'betCategoryType'}->{content},
1745             betId => $_->{'betId'}->{content},
1746             betPersistenceType => $_->{'betPersistenceType'}->{content},
1747             betStatus => $_->{'betStatus'}->{content},
1748             bspLiability => $_->{'bspLiability'}->{content},
1749             marketId => $_->{'marketId'}->{content},
1750             betType => $_->{'betType'}->{content},
1751             size => $_->{'size'}->{content},
1752             transactionId => $_->{'transactionId'}->{content},
1753             });
1754             }
1755             return \@muBetsLite;
1756             }
1757             return 0;
1758             }
1759              
1760             =head2 getMarketProfitAndLoss
1761              
1762             Returns a hashref containing the profit and loss for a particular market. See L for details. Requires:
1763              
1764             =over
1765              
1766             =item *
1767              
1768             marketId : integer representing the betfair market id to return the market traded volume for
1769              
1770             =item *
1771              
1772             includeSettledBets : string boolean ('true' or 'false') to include settled bets in the P&L calculation (optional)
1773              
1774             =item *
1775              
1776             includeBspBets : string boolean ('true' or 'false') to include BSP bets in the P&L calculation
1777              
1778             =item *
1779              
1780             netOfCommission : string boolean ('true' or 'false') to include commission in P&L calculation (optional)
1781              
1782             =item *
1783              
1784             exchangeId : integer representing the exchange id to connect to, either 1 (UK and rest of the world) or 2 (Australia)
1785              
1786             =back
1787              
1788             Example
1789              
1790             my $marketProfitAndLoss = $betfair->getMarketProfitAndLoss({marketId => 923456791,
1791             includeBspBets => 'false',
1792             exchangeId => 1,
1793             });
1794              
1795             =cut
1796              
1797             sub getMarketProfitAndLoss {
1798             my ($self, $args) = @_;
1799             my $checkParams = { marketId => ['int', 1],
1800             includeSettledBets => ['boolean', 0],
1801             includeBspBets => ['boolean', 1],
1802             netOfCommission => ['boolean', 0],
1803             exchangeId => ['exchangeId', 1],
1804             };
1805             return 0 unless $self->_checkParams($checkParams, $args);
1806             # handle mis-capitalization of marketID expected by betfair
1807             $args->{marketID} = $args->{marketId};
1808             delete $args->{marketId};
1809             if ($self->_doRequest('getMarketProfitAndLoss', $args)) {
1810             my $response = $self->{response}->{'soap:Body'}->{'n:getMarketProfitAndLossResponse'}->{'n:Result'};
1811             my $profitAndLoss = {
1812             annotations => [],
1813             commissionApplied => $response->{commissionApplied}->{content},
1814             currencyCode => $response->{currencyCode}->{content},
1815             includesSettledBets => $response->{includesSettledBets}->{content},
1816             includesBspBets => $response->{includesBspBets}->{content},
1817             marketId => $response->{marketId}->{content},
1818             marketName => $response->{marketName}->{content},
1819             marketStatus => $response->{marketStatus}->{content},
1820             unit => $response->{unit}->{content},
1821             };
1822             if (exists $response->{annotations}->{'n2:ProfitAndLoss'}) {
1823             my $oddsAnnotations = $self->_forceArray($response->{annotations}->{'n2:ProfitAndLoss'});
1824             foreach (@$oddsAnnotations) {
1825             push @{$profitAndLoss->{annotations}}, {
1826             ifWin => $_->{ifWin}->{content},
1827             selectionId => $_->{selectionId}->{content},
1828             selectionName => $_->{selectionName}->{content},
1829             ifLoss => $_->{ifLoss}->{content},
1830             to => $_->{to}->{content},
1831             from => $_->{from}->{content},
1832             };
1833             }
1834             }
1835             return $profitAndLoss;
1836             }
1837             return 0;
1838             }
1839              
1840              
1841             =head2 getMarketTradedVolume
1842              
1843             Returns an arrayref of hashrefs containing the traded volume for a particular market and selection. See L for details. Requires:
1844              
1845             =over
1846              
1847             =item *
1848              
1849             marketId : integer representing the betfair market id to return the market traded volume for.
1850              
1851             =item *
1852              
1853             selectionId : integer representing the betfair selection id of the selection to return matched volume for.
1854              
1855             =item *
1856              
1857             asianLineId : integer representing the betfair asian line id - this is optional unless the request is for an asian line market.
1858              
1859             =item *
1860              
1861             currencyCode : string representing the three letter ISO currency code. Only certain currencies are accepted by betfair GBP, USD, EUR, NOK, SGD, SEK, AUD, CAD, HKD, DKK (optional)
1862              
1863             =item *
1864              
1865             exchangeId : integer representing the exchange id to connect to, either 1 (UK and rest of the world) or 2 (Australia)
1866              
1867             =back
1868              
1869             Example
1870              
1871             my $marketVolume = $betfair->getMarketTradedVolume({marketId => 923456791,
1872             selectionId => 30571,
1873             exchangeId => 2,
1874             });
1875              
1876             =cut
1877              
1878             sub getMarketTradedVolume {
1879             my ($self, $args) = @_;
1880             my $checkParams = { marketId => ['int', 1],
1881             asianLineId => ['int', 0],
1882             selectionId => ['int', 1],
1883             currencyCode=> ['currencyCode', 0],
1884             exchangeId => ['exchangeId', 1],
1885             };
1886             return 0 unless $self->_checkParams($checkParams, $args);
1887             if ($self->_doRequest('getMarketTradedVolume', $args)) {
1888             my $response = $self->_forceArray(
1889             $self->{response}->{'soap:Body'}->{'n:getMarketTradedVolumeResponse'}->{'n:Result'}->{'priceItems'}->{'n2:VolumeInfo'});
1890             my $tradedVolume = [];
1891             foreach (@{$response}) {
1892             push @{$tradedVolume}, {
1893             odds => $_->{odds}->{content},
1894             totalMatchedAmount => $_->{totalMatchedAmount}->{content},
1895             totalBspBackMatchedAmount => $_->{totalBspBackMatchedAmount}->{content},
1896             totalBspLiabilityMatchedAmount => $_->{totalBspLiabilityMatchedAmount}->{content},
1897             };
1898             }
1899             return $tradedVolume;
1900             }
1901             return 0;
1902             }
1903              
1904              
1905             =head2 getMarketTradedVolumeCompressed
1906              
1907             Returns an arrayref of selections with their total matched amounts plus an array of all traded volume with the trade size and amount. See L for details. Note that this service de-serializes the compressed string return by betfair into a Perl data structure. Requires:
1908              
1909             =over
1910              
1911             =item *
1912              
1913             marketId : integer representing the betfair market id to return the market traded volume for.
1914              
1915             =item *
1916              
1917             currencyCode : string representing the three letter ISO currency code. Only certain currencies are accepted by betfair GBP, USD, EUR, NOK, SGD, SEK, AUD, CAD, HKD, DKK (optional)
1918              
1919             =item *
1920              
1921             exchangeId : integer representing the exchange id to connect to, either 1 (UK and rest of the world) or 2 (Australia)
1922              
1923             =back
1924              
1925             Example
1926              
1927             my $marketVolume = $betfair->getMarketTradedVolumeCompressed({ marketId => 923456791,
1928             exchangeId => 2,
1929             });
1930              
1931             =cut
1932              
1933             sub getMarketTradedVolumeCompressed {
1934             my ($self, $args) = @_;
1935             my $checkParams = {
1936             marketId => ['int', 1],
1937             currencyCode => ['currencyCode', 0],
1938             exchangeId => ['exchangeId', 1],
1939             };
1940             return 0 unless $self->_checkParams($checkParams, $args);
1941             if ($self->_doRequest('getMarketTradedVolumeCompressed', $args)) {
1942             my $response = $self->{response}->{'soap:Body'}->{'n:getMarketTradedVolumeCompressedResponse'}->{'n:Result'}->{'tradedVolume'}->{content};
1943             my $marketTradedVolume = { marketId => $args->{marketId} };
1944             foreach my $selection (split /:/, $response) {
1945             my @selectionFields = split /\|/, $selection;
1946             next unless defined $selectionFields[0];
1947             my @selectionData = split /~/, shift @selectionFields;
1948             my $tradedAmounts = [];
1949             foreach (@selectionFields) {
1950             my ($odds, $size) = split /~/, $_;
1951             push @{$tradedAmounts}, {
1952             odds => $odds,
1953             size => $size,
1954             };
1955             }
1956              
1957             push @{$marketTradedVolume->{selections}}, {
1958             selectionId => $selectionData[0],
1959             asianLineId => $selectionData[1],
1960             actualBSP => $selectionData[2],
1961             totalBSPBackMatched => $selectionData[3],
1962             totalBSPLiabilityMatched => $selectionData[4],
1963             tradedAmounts => $tradedAmounts,
1964             } if (defined $selectionData[0]);
1965             }
1966             return $marketTradedVolume;
1967             }
1968             return 0;
1969             }
1970              
1971             =head2 getPrivateMarkets
1972              
1973             Returns an arrayref of private markets - see L for details. Requires a hashref with the following arguments:
1974              
1975             =over
1976              
1977             =item *
1978              
1979             eventTypeId : integer representing the betfair id of the event type to return private markets for.
1980              
1981             =item *
1982              
1983             marketType : string of the betfair marketType enum see L.
1984              
1985             =item *
1986              
1987             exchangeId : integer representing the exchange id to connect to, either 1 (UK and rest of the world) or 2 (Australia)
1988              
1989             =back
1990              
1991             Example
1992              
1993             my $privateMarkets = $betfair->getPrivateMarkets({ eventTypeId => 1,
1994             marketType => 'O',
1995             exchangeId => 1,
1996             });
1997              
1998             =cut
1999              
2000             sub getPrivateMarkets {
2001             my ($self, $args) = @_;
2002             my $checkParams = { eventTypeId => ['int', 1],
2003             marketType => ['marketTypeEnum', 1],
2004             exchangeId => ['exchangeId', 1],
2005             };
2006             return 0 unless $self->_checkParams($checkParams, $args);
2007             if ($self->_doRequest('getPrivateMarkets', $args)) {
2008             my $response = $self->_forceArray(
2009             $self->{response}->{'soap:Body'}->{'n:getPrivateMarketsResponse'}->{'n:Result'}->{'privateMarkets'}->{'n2:PrivateMarket'});
2010             my @privateMarkets;
2011             foreach (@{$response}) {
2012             push(@privateMarkets, {
2013             name => $_->{name}->{content},
2014             marketId => $_->{marketId}->{content},
2015             menuPath => $_->{menuPath}->{content},
2016             eventHierarchy => $_->{eventHierarchy}->{content},
2017             });
2018             }
2019             return \@privateMarkets;
2020             }
2021             return 0;
2022             }
2023              
2024             =head2 getSilks
2025              
2026             This method is not available on the free betfair API.
2027              
2028             Returns an arrayref of market racing silks data or 0 on failure. See L for details. Requires the following parameters:
2029              
2030             =over
2031              
2032             =item *
2033              
2034             markets : an arrayref of integers representing betfair market ids
2035              
2036             =item *
2037              
2038             exchangeId : integer representing the exchange id to connect to, either 1 (UK and rest of the world) or 2 (Australia)
2039              
2040             =back
2041              
2042             Example
2043              
2044             my $silks = $betfair->getSilksV2({ markets => [123456,9273649],
2045             exchangeId => 1,
2046             });
2047              
2048             =cut
2049              
2050             sub getSilks {
2051             my ($self, $args) = @_;
2052             my $checkParams = {
2053             markets => ['arrayInt', 1],
2054             exchangeId => ['exchangeId', 1],
2055             };
2056             return 0 unless $self->_checkParams($checkParams, $args);
2057             # adjust args into betfair api required structure
2058             my $params = { markets => { int => $args->{markets} },
2059             exchangeId => $args->{exchangeId},
2060             };
2061             if ($self->_doRequest('getSilks', $params)) {
2062             my $silks = [];
2063             my $response = $self->_forceArray(
2064             $self->{response}->{'soap:Body'}->{'n:getSilksResponse'}->{'n:Result'}->{'marketDisplayDetails'}->{'n2:MarketDisplayDetail'});
2065             foreach (@$response) {
2066             my $market = $_->{marketId}->{content};
2067             next unless $market;
2068             my $runners = $self->_forceArray($_->{racingSilks}->{'n2:RacingSilk'});
2069             my @racingSilks;
2070             foreach (@$runners) {
2071             push(@racingSilks, {
2072             selectionId => $_->{selectionId}->{content},
2073             silksURL => 'http://content-cache.betfair.com/feeds_images/Horses/SilkColours/' . $_->{silksURL}->{content},
2074             silksText => $_->{silksText}->{content},
2075             trainerName => $_->{trainerName}->{content},
2076             ageWeight => $_->{ageWeight}->{content},
2077             form => $_->{form}->{content},
2078             daysSinceLastRun => $_->{daysSince}->{content},
2079             jockeyClaim => $_->{jockeyClaim}->{content},
2080             wearing => $_->{wearing}->{content},
2081             saddleClothNumber=> $_->{saddleCloth}->{content},
2082             stallDraw => $_->{stallDraw}->{content},
2083             });
2084             }
2085             push(@$silks, {
2086             marketId => $market,
2087             runners => \@racingSilks,
2088             });
2089             }
2090             return $silks;
2091             }
2092             return 0;
2093             }
2094              
2095             =head2 getSilksV2
2096              
2097             This method is not available on the free betfair API.
2098              
2099             Returns an arrayref of market racing silks data or 0 on failure. See L for details. Requires the following parameters:
2100              
2101             =over
2102              
2103             =item *
2104              
2105             markets : an arrayref of integers representing betfair market ids
2106              
2107             =item *
2108              
2109             exchangeId : integer representing the exchange id to connect to, either 1 (UK and rest of the world) or 2 (Australia)
2110              
2111             =back
2112              
2113             Example
2114              
2115             my $silks = $betfair->getSilksV2({ markets => [123456,9273649],
2116             exchangeId => 1,
2117             });
2118              
2119             =cut
2120              
2121             sub getSilksV2 {
2122             my ($self, $args) = @_;
2123             my $checkParams = {
2124             markets => ['arrayInt', 1],
2125             exchangeId => ['exchangeId', 1],
2126             };
2127             return 0 unless $self->_checkParams($checkParams, $args);
2128             # adjust args into betfair api required structure
2129             my $params = { markets => { int => $args->{markets} },
2130             exchangeId => $args->{exchangeId},
2131             };
2132             if ($self->_doRequest('getSilksV2', $params)) {
2133             my $silks = [];
2134             my $response = $self->_forceArray(
2135             $self->{response}->{'soap:Body'}->{'n:getSilksV2Response'}->{'n:Result'}->{'marketDisplayDetails'}->{'n2:MarketDisplayDetail'});
2136             foreach (@$response) {
2137             my $market = $_->{marketId}->{content};
2138             next unless $market;
2139             my $runners = $self->_forceArray($_->{racingSilks}->{'n2:RacingSilk'});
2140             my @racingSilks;
2141             foreach (@$runners) {
2142             push(@racingSilks, {
2143             selectionId => $_->{selectionId}->{content},
2144             silksURL => 'http://content-cache.betfair.com/feeds_images/Horses/SilkColours/' . $_->{silksURL}->{content},
2145             silksText => $_->{silksText}->{content},
2146             trainerName => $_->{trainerName}->{content},
2147             ageWeight => $_->{ageWeight}->{content},
2148             form => $_->{form}->{content},
2149             daysSinceLastRun => $_->{daysSince}->{content},
2150             jockeyClaim => $_->{jockeyClaim}->{content},
2151             wearing => $_->{wearing}->{content},
2152             saddleClothNumber => $_->{saddleCloth}->{content},
2153             stallDraw => $_->{stallDraw}->{content},
2154             ownerName => $_->{ownerName}->{content},
2155             jockeyName => $_->{jockeyName}->{content},
2156             colour => $_->{colour}->{content},
2157             sex => $_->{sex}->{content},
2158             forecastPriceNumerator => $_->{forecastPriceNumerator}->{content},
2159             forecastPriceDenominator=> $_->{forecastPriceDenominator}->{content},
2160             officialRating => $_->{officialRating}->{content},
2161             sire => {name => $_->{sire}->{name}->{content},
2162             bred => $_->{sire}->{bred}->{content},
2163             yearBorn=> $_->{sire}->{yearBorn}->{content},
2164             },
2165             dam => {name => $_->{dam}->{name}->{content},
2166             bred => $_->{dam}->{bred}->{content},
2167             yearBorn=> $_->{dam}->{yearBorn}->{content},
2168             },
2169             damSire => {name => $_->{damSire}->{name}->{content},
2170             bred => $_->{damSire}->{bred}->{content},
2171             yearBorn=> $_->{damSire}->{yearBorn}->{content},
2172             },
2173             });
2174             }
2175             push(@$silks, {
2176             marketId => $market,
2177             runners => \@racingSilks,
2178             });
2179             }
2180             return $silks;
2181             }
2182             return 0;
2183             }
2184              
2185             =head1 BET PLACEMENT API METHODS
2186              
2187             =head2 cancelBets
2188              
2189             Cancels up to 40 unmatched and active bets on betfair. Returns an arrayref of hashes of cancelled bets. See L for details. Requires a hashref with the following parameters:
2190              
2191             =over
2192              
2193             =item *
2194              
2195             betIds : an arrayref of integers of betIds that should be cancelled, up to 40 betIds are permitted by betfair.
2196              
2197             =item *
2198              
2199             exchangeId : integer representing the exchange id to connect to, either 1 (UK and rest of the world) or 2 (Australia)
2200              
2201             =back
2202              
2203             Example
2204              
2205             my $cancelledBetsResults = $betfair->cancelBets({betIds => [123456789, 987654321]
2206             exchangeId => 2,
2207             });
2208              
2209             =cut
2210              
2211             sub cancelBets {
2212             my ($self, $args) = @_;
2213             my $checkParams = {
2214             betIds => ['arrayInt', 1],
2215             exchangeId => ['exchangeId', 1],
2216             };
2217             return 0 unless $self->_checkParams($checkParams, $args);
2218             # adjust args into betfair api required structure
2219             my $params = { bets => { CancelBets => {betId => $args->{betIds}} },
2220             exchangeId => $args->{exchangeID},
2221             };
2222             my $cancelled_bets = [];
2223             if ($self->_doRequest('cancelBets', $params)) {
2224             my $response = $self->_forceArray(
2225             $self->{response}->{'soap:Body'}->{'n:cancelBetsResponse'}->{'n:Result'}->{'betResults'}->{'n2:CancelBetsResult'});
2226             foreach (@{$response} ) {
2227             $cancelled_bets = _add_cancelled_bet($cancelled_bets, $_);
2228             }
2229             return $cancelled_bets;
2230             }
2231             return 0;
2232             sub _add_cancelled_bet {
2233             my ($cancelled_bets, $bet_to_be_added) = @_;
2234             push(@$cancelled_bets, {
2235             success => $bet_to_be_added->{'success'}->{content},
2236             result_code => $bet_to_be_added->{'resultCode'}->{content},
2237             size_matched => $bet_to_be_added->{'sizeMatched'}->{content},
2238             size_cancelled => $bet_to_be_added->{'sizeCancelled'}->{content},
2239             bet_id => $bet_to_be_added->{'betId'}->{content},
2240             });
2241             return $cancelled_bets;
2242             }
2243             }
2244              
2245             =head2 cancelBetsByMarket
2246              
2247             Receives an arrayref of marketIds and cancels all unmatched bets on those markets. Returns an arrayref of hashrefs of market ids and results. See L for details. Requires a hashref with the following parameters:
2248              
2249             =over
2250              
2251             =item *
2252              
2253             markets : arrayref of integers representing market ids.
2254              
2255             =item *
2256              
2257             exchangeId : integer representing the exchange id to connect to, either 1 (UK and rest of the world) or 2 (Australia)
2258              
2259             =back
2260              
2261             Example
2262              
2263             my $cancelledBets = $betfair->cancelBetsByMarket({markets => [123456789, 432596611],
2264             exchangeId => 1,
2265             });
2266              
2267             =cut
2268              
2269             sub cancelBetsByMarket {
2270             my ($self, $args) = @_;
2271             my $checkParams = {
2272             markets => ['arrayInt', 1],
2273             exchangeId => ['exchangeId', 1],
2274             };
2275             return 0 unless $self->_checkParams($checkParams, $args);
2276             # adjust args into betfair api required structure
2277             my $params = { markets => { int => $args->{markets} },
2278             exchangeId => $args->{exchangeId},
2279             };
2280             my $cancelled_bets = [];
2281             if ($self->_doRequest('cancelBetsByMarket', $params)) {
2282             my $response = $self->_forceArray(
2283             $self->{response}->{'soap:Body'}->{'n:cancelBetsByMarketResponse'}->{'n:Result'}->{results}->{'n2:CancelBetsByMarketResult'});
2284             foreach (@{$response} ) {
2285             push(@$cancelled_bets, {
2286             marketId => $_->{'marketId'}->{content},
2287             resultCode => $_->{'resultCode'}->{content},
2288             });
2289             }
2290             return $cancelled_bets;
2291             }
2292             return 0;
2293             }
2294              
2295              
2296             =head2 placeBets
2297              
2298             Places up to 60 bets on betfair and returns an array of results or zero on failure. See L for details. Requires:
2299              
2300             =over
2301              
2302             =item *
2303              
2304             bets : an arrayref of hashes of bets. Up to 60 hashes are permitted by betfair. Every bet hash should contain:
2305              
2306             =over 8
2307              
2308             =item *
2309              
2310             asianLineId : integer of the ID of the asian handicap market, usually 0 unless betting on an asian handicap market
2311              
2312             =item *
2313              
2314             betCategoryType : a string of the betCategoryTypeEnum, usually 'E' for exchange, see L for details.
2315              
2316             =item *
2317              
2318             betPersistenceType : a string of the betPersistenceTypeEnum, usually 'NONE' for standard exchange bets. See L for details.
2319              
2320             =item *
2321              
2322             betType : a string of the betTypeEnum. Either 'B' to back or 'L' to lay.
2323              
2324             =item *
2325              
2326             bspLiability : a number of the maximum amount to risk for a bsp bet. For a back / lay bet this is equivalent to the whole stake amount.
2327              
2328             =item *
2329              
2330             marketId : integer of the marketId for which the bet should be placed.
2331              
2332             =item *
2333              
2334             price : number of the decimal odds for the bet.
2335              
2336             =item *
2337              
2338             selectionId : integer of the betfair id of the runner (selection option) that the bet should be placed on.
2339              
2340             =item *
2341              
2342             size : number for the stake amount for this bet.
2343              
2344             =back
2345              
2346             =item *
2347              
2348             exchangeId : integer representing the exchange id to connect to, either 1 (UK and rest of the world) or 2 (Australia)
2349              
2350             =back
2351              
2352             Example
2353              
2354             $myBetPlacedResults = $betfair->placeBets({
2355             bets => [{ asianLineId => 0,
2356             betCategoryType => 'E',
2357             betPersistenceType => 'NONE',
2358             betType => 'B',
2359             bspLiability => 2,
2360             marketId => 123456789,
2361             price => 5,
2362             selectionId => 99,
2363             size => 10,
2364             }],
2365             exchangeId => 1,
2366             });
2367              
2368             =cut
2369              
2370             sub placeBets {
2371             my ($self, $args) = @_;
2372             # handle exchange id separately
2373             if (exists $args->{exchangeId}) {
2374             return 0 unless $self->_checkParams({exchangeId => ['exchangeId', 1]}, {exchangeId => $args->{exchangeId}});
2375             }
2376             else {
2377             return 0;
2378             }
2379             my $checkParams = {
2380             asianLineId => ['int', 1],
2381             betCategoryType => ['betCategoryTypeEnum', 1],
2382             betPersistenceType => ['betPersistenceTypeEnum', 1],
2383             betType => ['betTypeEnum', 1],
2384             bspLiability => ['int', 1],
2385             marketId => ['int', 1],
2386             price => ['decimal', 1],
2387             selectionId => ['int', 1],
2388             size => ['decimal', 1],
2389             };
2390             foreach (@{$args->{bets}}) {
2391             return 0 unless $self->_checkParams($checkParams, $_);
2392             }
2393             # adjust args into betfair api required structure
2394             my $params = { bets => { PlaceBets => $args->{bets} },
2395             exchangeId => $args->{exchangeId},
2396             };
2397             if ($self->_doRequest('placeBets', $params)) {
2398             my $response = $self->_forceArray($self->{response}->{'soap:Body'}->{'n:placeBetsResponse'}->{'n:Result'}->{'betResults'}->{'n2:PlaceBetsResult'});
2399             my $placed_bets = [];
2400             foreach (@{$response}) {
2401             push @{$placed_bets}, {
2402             success => $_->{'success'}->{content},
2403             result_code => $_->{'resultCode'}->{content},
2404             bet_id => $_->{'betId'}->{content},
2405             size_matched => $_->{'sizeMatched'}->{content},
2406             avg_price_matched => $_->{'averagePriceMatched'}->{content}
2407             };
2408             }
2409             return $placed_bets;
2410             }
2411             return 0;
2412             }
2413              
2414             =head2 updateBets
2415              
2416             Updates existing unmatched bets on betfair: the size, price and persistence can be updated. Note that only the size or the price can be updated in one request, if both parameters are provided betfair ignores the new size value. Returns an arrayref of hashes of updated bet results. See L for details. Requires:
2417              
2418             =over
2419              
2420             =item *
2421              
2422             bets : an arrayref of hashes of bets to be updated. Each hash represents one bet and must contain the following key / value pairs:
2423              
2424             =over 8
2425              
2426             =item *
2427              
2428             betId : integer of the betId to be updated
2429              
2430             =item *
2431              
2432             newBetPersistenceType : string of the betfair betPersistenceTypeEnum to be updated to see L for more details.
2433              
2434             =item *
2435              
2436             newPrice : number for the new price of the bet
2437              
2438             =item *
2439              
2440             newSize : number for the new size of the bet
2441              
2442             =item *
2443              
2444             oldBetPersistenceType : string of the current bet's betfair betPersistenceTypeEnum see L for more details.
2445              
2446             =item *
2447              
2448             oldPrice : number for the old price of the bet
2449              
2450             =item *
2451              
2452             oldSize : number for the old size of the bet
2453              
2454             =back
2455              
2456             =item *
2457              
2458             exchangeId : integer representing the exchange id to connect to, either 1 (UK and rest of the world) or 2 (Australia)
2459              
2460             =back
2461              
2462             Example
2463              
2464             my $updateBetDetails = $betfair->updateBets({
2465             bets => [{betId => 12345,
2466             newBetPersistenceType => 'NONE',
2467             newPrice => 5,
2468             newSize => 10,
2469             oldBetPersistenceType => 'NONE',
2470             oldPrice => 2,
2471             oldSize => 10,
2472             }],
2473             exchangeId => 1,
2474             });
2475              
2476              
2477             =cut
2478              
2479             sub updateBets {
2480             my ($self, $args) = @_;
2481             # handle exchange id separately
2482             if (exists $args->{exchangeId}) {
2483             return 0 unless $self->_checkParams({exchangeId => ['exchangeId', 1]}, {exchangeId => $args->{exchangeId}});
2484             }
2485             else {
2486             return 0;
2487             }
2488             my $checkParams = {
2489             betId => ['int', 1],
2490             newBetPersistenceType => ['betPersistenceTypeEnum', 1],
2491             oldBetPersistenceType => ['betPersistenceTypeEnum', 1],
2492             newSize => ['decimal', 1],
2493             oldSize => ['decimal', 1],
2494             newPrice => ['decimal', 1],
2495             oldPrice => ['decimal', 1],
2496             };
2497             foreach (@{$args->{bets}}) {
2498             return 0 unless $self->_checkParams($checkParams, $_);
2499             }
2500             my $params = {
2501             bets => { UpdateBets => $args->{bets} },
2502             exchangeId => $args->{exchangeId},
2503             };
2504             my $updated_bets = [];
2505             if ($self->_doRequest('updateBets', $params)) {
2506             my $response = $self->_forceArray($self->{response}->{'soap:Body'}->{'n:updateBetsResponse'}->{'n:Result'}->{'betResults'}->{'n2:UpdateBetsResult'});
2507             foreach (@{$response}) {
2508             push @{$updated_bets}, {
2509             success => $_->{'success'}->{content},
2510             size_cancelled => $_->{'sizeCancelled'}->{content},
2511             new_price => $_->{'newPrice'}->{content},
2512             bet_id => $_->{'betId'}->{content},
2513             new_bet_id => $_->{'newBetId'}->{content},
2514             result_code => $_->{content}->{content},
2515             new_size => $_->{'newSize'}->{content},
2516             };
2517             }
2518             return $updated_bets;
2519             }
2520             return 0;
2521             }
2522              
2523              
2524             =head1 ACCOUNT MANAGEMENT API METHODS
2525              
2526             =head2 addPaymentCard
2527              
2528             Adds a payment card to your betfair account. Returns an arrayref of hashes of payment card responses or 0 on failure. See L. Requires:
2529              
2530             =over
2531              
2532             =item *
2533              
2534             cardNumber : string of the card number
2535              
2536             =item *
2537              
2538             cardType : string of a valid betfair cardTypeEnum (e.g. 'VISA'). See L
2539              
2540             =item *
2541              
2542             cardStatus : string of a valid betfair paymentCardStatusEnum, either 'LOCKED' or 'UNLOCKED'
2543              
2544             =item *
2545              
2546             startDate : string of the card start date, optional depending on type of card
2547              
2548             =item *
2549              
2550             expiryDate : string of the card expiry date
2551              
2552             =item *
2553              
2554             issueNumber : string of the issue number or NULL if the cardType is not Solo or Switch
2555              
2556             =item *
2557              
2558             billingName : name of person on the billing account for the card
2559              
2560             =item *
2561              
2562             nickName : string of the card nickname must be less than 9 characters
2563              
2564             =item *
2565              
2566             password : string of the betfair account password
2567              
2568             =item *
2569              
2570             address1 : string of the first line of the address for the payment card
2571              
2572             =item *
2573              
2574             address2 : string of the second line of the address for the payment card
2575              
2576             =item *
2577              
2578             address3 : string of the third line of the address for the payment card (optional)
2579              
2580             =item *
2581              
2582             address4 : string of the fourth line of the address for the payment card (optional)
2583              
2584             =item *
2585              
2586             town : string of the town for the payment card
2587              
2588             =item *
2589              
2590             county : string of the county for the payment card
2591              
2592             =item *
2593              
2594             zipCode : string of the zip / postal code for the payment card
2595              
2596             =item *
2597              
2598             country : string of the country for the payment card
2599              
2600             =back
2601              
2602             Example
2603              
2604             my $addPaymentCardResponse = $betfair->addPaymentCard({
2605             cardNumber => '1234123412341234',
2606             cardType => 'VISA',
2607             cardStatus => 'UNLOCKED',
2608             startDate => '0113',
2609             expiryDate => '0116',
2610             issueNumber => 'NULL',
2611             billingName => 'The Sillymoose',
2612             nickName => 'democard',
2613             password => 'password123',
2614             address1 => 'Tasty bush',
2615             address2 => 'Mountain Plains',
2616             town => 'Hoofton',
2617             zipCode => 'MO13FR',
2618             county => 'Mooshire',
2619             country => 'UK',
2620             });
2621              
2622             =cut
2623              
2624             sub addPaymentCard {
2625             my ($self, $args) = @_;
2626             my $checkParams = {
2627             cardNumber => ['int', 1],
2628             cardType => ['cardTypeEnum', 1],
2629             cardStatus => ['cardStatusEnum', 1],
2630             startDate => ['cardDate', 1],
2631             expiryDate => ['cardDate', 1],
2632             issueNumber => ['int', 1],
2633             billingName => ['string', 1],
2634             nickName => ['string9', 1],
2635             password => ['password', 1],
2636             address1 => ['string', 1],
2637             address2 => ['string', 1],
2638             address3 => ['string', 0],
2639             address4 => ['string', 0],
2640             town => ['string', 1],
2641             zipCode => ['string', 1],
2642             county => ['string', 1],
2643             country => ['string', 1],
2644              
2645             };
2646             return 0 unless $self->_checkParams($checkParams, $args);
2647             $args->{exchangeId} = 3;
2648             if ($self->_doRequest('addPaymentCard', $args) ) {
2649             return $self->_addPaymentCardLine([], $self->{response}->{'soap:Body'}->{'n:addPaymentCardResponse'}->{'n:Result'}->{'n2:PaymentCard'});
2650             }
2651             return 0;
2652             }
2653              
2654             =head2 deletePaymentCard
2655              
2656             Deletes a registered payment card from your betfair account. See L for further details. Returns the betfair response as a hashref or 0 on failure. Requires:
2657              
2658             =over
2659              
2660             =item *
2661              
2662             nickName : string of the card nickname to be deleted (must be less than 9 characters)
2663              
2664             =item *
2665              
2666             password : string of the betfair account password
2667              
2668             =back
2669              
2670             Example
2671              
2672             my $deleteCardResponse = $betfair->deletePaymentCard({
2673             nickName => 'checking',
2674             password => 'password123',
2675             });
2676              
2677             =cut
2678              
2679             sub deletePaymentCard {
2680             my ($self, $args) = @_;
2681             my $checkParams = {
2682             nickName => ['string9', 1],
2683             password => ['password', 1],
2684             };
2685             return 0 unless $self->_checkParams($checkParams, $args);
2686             $args->{exchangeId} = 3;
2687             if ($self->_doRequest('deletePaymentCard', $args)) {
2688             my $response = $self->{response}->{'soap:Body'}->{'n:deletePaymentCardResponse'}->{'n:Result'};
2689             return {
2690             nickName => $response->{nickName}->{content},
2691             billingName => $response->{billingName}->{content},
2692             cardShortNumber => $response->{cardShortNumber}->{content},
2693             cardType => $response->{cardType}->{content},
2694             issuingCountry => $response->{issuingCountry}->{content},
2695             expiryDate => $response->{expiryDate}->{content},
2696             };
2697             }
2698             return 0;
2699             }
2700              
2701             =head2 depositFromPaymentCard
2702              
2703             Deposits money in your betfair account using a payment card. See L for further details. Returns the betfair response as a hashref or 0 on failure. Requires:
2704              
2705             =over
2706              
2707             =item *
2708              
2709             amount : number which represents the amount of money to deposit
2710              
2711             =item *
2712              
2713             cardIdentifier : string of the nickname for the payment card
2714              
2715             =item *
2716              
2717             cv2 : string of the CV2 digits from the payment card (also known as the security digits)
2718              
2719             =item *
2720              
2721             password : string of the betfair account password
2722              
2723             =back
2724              
2725             Example
2726              
2727             my $depositResponse = $betfair->depositFromPaymentCard({
2728             amount => 10,
2729             cardIdentifier => 'checking',
2730             cv2 => '999',
2731             password => 'password123',
2732             });
2733              
2734             =cut
2735              
2736             sub depositFromPaymentCard {
2737             my ($self, $args) = @_;
2738             my $checkParams = {
2739             amount => ['decimal', 1],
2740             cardIdentifier => ['string9', 1],
2741             cv2 => ['cv2', 1],
2742             password => ['password', 1],
2743             };
2744             return 0 unless $self->_checkParams($checkParams, $args);
2745             $args->{exchangeId} = 3;
2746             if ($self->_doRequest('depositFromPaymentCard', $args)) {
2747             my $deposit_response = $self->{response}->{'soap:Body'}->{'n:depositFromPaymentCardResponse'}->{'n:Result'};
2748             return {
2749             fee => $deposit_response->{'fee'}->{content},
2750             transactionId => $deposit_response->{'transactionId'}->{content},
2751             minAmount => $deposit_response->{'minAmount'}->{content},
2752             errorCode => $deposit_response->{'errorCode'}->{content},
2753             minorErrorCode => $deposit_response->{'minorErrorCode'}->{content},
2754             maxAmount => $deposit_response->{'maxAmount'}->{content},
2755             netAmount => $deposit_response->{'netAmount'}->{content},
2756             };
2757             }
2758             return 0;
2759             }
2760              
2761             =head2 forgotPassword
2762              
2763             NB. This service is largely redundant as it requires an authenticated session to work, however it is included for the sake of completeness.
2764              
2765             Resets the betfair account password via a 2 stage process. See L and the example below for details. Returns the betfair response as a hashref for stage 1, 1 on a successful passwprd reset or 0 on failure. Note that this service can be difficult to succeed with - user the getError method to inspect the response message from betfair. Requires:
2766              
2767             =over
2768              
2769             =item *
2770              
2771             username : string of the betfair username for the account to reset the password for
2772              
2773             =item *
2774              
2775             emailAddress : string of the betfair account email address
2776              
2777             =item *
2778              
2779             countryOfResidence : string of the country of residence the betfair account is registered to
2780              
2781             =item *
2782              
2783             forgottenPasswordAnswer1 : string of the answer to question1 as returned by this service on the first request (optional)
2784              
2785             =item *
2786              
2787             forgottenPasswordAnswer2 : string of the answer to question2 as returned by this service on the first request (optional)
2788              
2789             =item *
2790              
2791             newPassword : string of the new account password (optional)
2792              
2793             =item *
2794              
2795             newPasswordRepeat : string of the new account password (optional)
2796              
2797             =back
2798              
2799             Example
2800              
2801             use Data::Dumper;
2802              
2803             my $securityQuestions = $betfair->forgotPassword({
2804             username => 'sillymoose',
2805             emailAddress => 'sillymoos@cpan.org',
2806             countryOfResidence => 'United Kingdom',
2807             });
2808             print Dumper($securityQuestions);
2809              
2810             # now call service again with answers to security questions and new password parameters
2811             my $resetPasswordResponse = $betfair->forgotPassword({
2812             username => 'sillymoose',
2813             emailAddress => 'sillymoos@cpan.org',
2814             countryOfResidence => 'United Kingdom',
2815             forgottenPasswordAnswer1 => 'dasher',
2816             forgottenPasswordAnswer2 => 'hoofs',
2817             newPassword => 'moojolicious',
2818             newPasswordRepeat => 'moojolocious',
2819             });
2820              
2821             =cut
2822              
2823             sub forgotPassword {
2824             my ($self, $args) = @_;
2825             my $checkParams = {
2826             username => ['username', 1],
2827             emailAddress => ['string', 1],
2828             countryOfResidence => ['string',1],
2829             forgottenPasswordAnswer1 => ['string', 0],
2830             forgottenPasswordAnswer2 => ['string', 0],
2831             newPassword => ['password', 0],
2832             newPasswordRepeat => ['password', 0],
2833             };
2834             return 0 unless $self->_checkParams($checkParams, $args);
2835             $args->{exchangeId} = 3;
2836             if ($self->_doRequest('forgotPassword', $args)) {
2837             my $response = $self->{response}->{'soap:Body'}->{'n:forgotPasswordResponse'}->{'n:Result'};
2838             return 1 if exists $args->{forgottenPasswordAnswer1};
2839             return {
2840             question1 => $response->{'question1'}->{content},
2841             question2 => $response->{'question2'}->{content},
2842             };
2843             }
2844             return 0;
2845             }
2846              
2847             =head2 getAccountFunds
2848              
2849             Returns a hashref of the account funds betfair response. See L for details. Requires a hashref with the following parameters:
2850              
2851             =over
2852              
2853             =item *
2854              
2855             exchangeId : integer representing the exchange id to connect to, either 1 (UK and rest of the world) or 2 (Australia)
2856              
2857             =back
2858              
2859             Example
2860              
2861             my $funds = $betfair->getAccountFunds({exchangeId => 1});
2862              
2863             =cut
2864              
2865             sub getAccountFunds {
2866             my ($self, $args) = @_;
2867             my $checkParams = {
2868             exchangeId => ['exchangeId', 1],
2869             };
2870             return 0 unless $self->_checkParams($checkParams, $args);
2871             if ($self->_doRequest('getAccountFunds', $args)) {
2872             return {
2873             availBalance => $self->{response}->{'soap:Body'}->{'n:getAccountFundsResponse'}->{'n:Result'}->{'availBalance'}->{content},
2874             balance => $self->{response}->{'soap:Body'}->{'n:getAccountFundsResponse'}->{'n:Result'}->{'balance'}->{content},
2875             exposure => $self->{response}->{'soap:Body'}->{'n:getAccountFundsResponse'}->{'n:Result'}->{'exposure'}->{content},
2876             withdrawBalance => $self->{response}->{'soap:Body'}->{'n:getAccountFundsResponse'}->{'n:Result'}->{'withdrawBalance'}->{content}
2877             };
2878             }
2879             return 0;
2880             }
2881              
2882             =head2 getAccountStatement
2883              
2884             Returns an arrayref of hashes of account statement entries or 0 on failure. See L for further details. Requires:
2885              
2886             =over
2887              
2888             =item *
2889              
2890             startRecord : integer indicating the first record number to return. Record indexes are zero-based, hence 0 is the first record
2891              
2892             =item *
2893              
2894             recordCount : integer of the maximum number of records to return
2895              
2896             =item *
2897              
2898             startDate : date for which to return records on or after this date (a string in the XML datetime format see example)
2899              
2900             =item *
2901              
2902             endDate : date for which to return records on or before this date (a string in the XML datetime format see example)
2903              
2904             =item *
2905              
2906             itemsIncluded : string of the betfair AccountStatementIncludeEnum see L for details
2907              
2908             =item *
2909              
2910             exchangeId : integer representing the exchange id to connect to, either 1 (UK and rest of the world) or 2 (Australia)
2911              
2912             =back
2913              
2914             Example
2915              
2916             # return an account statement for all activity starting at record 1 up to 1000 records between 1st January 2013 and 16th June 2013
2917             my $statement = $betfair->getAccountStatement({
2918             startRecord => 0,
2919             recordCount => 1000,
2920             startDate => '2013-01-01T00:00:00.000Z',
2921             endDate => '2013-06-16T00:00:00.000Z',
2922             itemsIncluded => 'ALL',
2923             exchangeId => 2,
2924             });
2925              
2926             =cut
2927              
2928             sub getAccountStatement {
2929             my ($self, $args) = @_;
2930             my $checkParams = {
2931             startRecord => ['int', 1],
2932             recordCount => ['int', 1],
2933             startDate => ['date', 1],
2934             endDate => ['date', 1],
2935             itemsIncluded => ['accountStatementIncludeEnum', 1],
2936             exchangeId => ['exchangeId', 1],
2937             };
2938             return 0 unless $self->_checkParams($checkParams, $args);
2939             my @account_statement;
2940             if ($self->_doRequest('getAccountStatement', 1, $args)) {
2941             my $response =
2942             $self->_forceArray($self->{response}->{'soap:Body'}->{'n:getAccountStatementResponse'}->{'n:Result'}->{'items'}->{'n2:AccountStatementItem'});
2943             foreach (@{$response}) {
2944             push(@account_statement, {
2945             betType => $_->{'betType'}->{content},
2946             transactionId => $_->{'transactionId'}->{content},
2947             transactionType => $_->{'transactionType'}->{content},
2948             betSize => $_->{'betSize'}->{content},
2949             placedDate => $_->{'placedDate'}->{content},
2950             betId => $_->{'betId'}->{content},
2951             marketName => $_->{'marketName'}->{content},
2952             grossBetAmount => $_->{'grossBetAmount'}->{content},
2953             marketType => $_->{'marketType'}->{content},
2954             eventId => $_->{'eventId'}->{content},
2955             accountBalance => $_->{'accountBalance'}->{content},
2956             eventTypeId => $_->{'eventTypeId'}->{content},
2957             betCategoryType => $_->{'betCategoryType'}->{content},
2958             selectionName => $_->{'selectionName'}->{content},
2959             selectionId => $_->{'selectionId'}->{content},
2960             commissionRate => $_->{'commissionRate'}->{content},
2961             fullMarketName => $_->{'fullMarketName'}->{content},
2962             settledDate => $_->{'settledDate'}->{content},
2963             avgPrice => $_->{'avgPrice'}->{content},
2964             startDate => $_->{'startDate'}->{content},
2965             winLose => $_->{'winLose'}->{content},
2966             amount => $_->{'amount'}->{content}
2967             });
2968             }
2969             return \@account_statement;
2970             }
2971             return 0;
2972             }
2973              
2974             =head2 getPaymentCard
2975              
2976             Returns an arrayref of hashes of payment card or 0 on failure. See L for details. Does not require any parameters.
2977              
2978             Example
2979              
2980             my $cardDetails = $betfair->getPaymentCard;
2981              
2982             =cut
2983              
2984             sub getPaymentCard {
2985             my $self = shift;
2986             my $payment_cards = [];
2987             if ($self->_doRequest('getPaymentCard', {exchangeId => 3})) {
2988             my $response = $self->_forceArray(
2989             $self->{response}->{'soap:Body'}->{'n:getPaymentCardResponse'}->{'n:Result'}->{'paymentCardItems'}->{'n2:PaymentCard'});
2990             foreach (@{$response}) {
2991             $payment_cards = $self->_addPaymentCardLine($payment_cards, $_);
2992             }
2993             return $payment_cards;
2994             }
2995             return 0;
2996             }
2997              
2998             =head2 getSubscriptionInfo
2999              
3000             This service is not available with the free betfair API.
3001              
3002             Returns an arrayref of hashes of subscription or 0 on failure. See L for details. Does not require any parameters.
3003              
3004             Example
3005              
3006             my $subscriptionData = $betfair->getSubscriptionInfo;
3007              
3008             =cut
3009              
3010             sub getSubscriptionInfo {
3011             my ($self, $args) = @_;
3012             $args->{exchangeId} = 3;
3013             if ($self->_doRequest('getSubscriptionInfo', $args) ) {
3014             my $response = $self->{response}->{'soap:Body'}->{'n:getSubscriptionInfoResponse'}->{'n:Result'}->{subscriptions}->{'n2:Subscription'};
3015             my $subscriptionInfo = {
3016             billingAmount => $response->{billingAmount}->{content},
3017             billingDate => $response->{billingDate}->{content},
3018             billingPeriod => $response->{billingPeriod}->{content},
3019             productId => $response->{productId}->{content},
3020             productName => $response->{productName}->{content},
3021             subscribedDate => $response->{subscribedDate}->{content},
3022             status => $response->{status}->{content},
3023             vatEnabled => $response->{vatEnabled}->{content},
3024             setupCharge => $response->{setupCharge}->{content},
3025             setupChargeActive => $response->{setupChargeActive}->{content},
3026             services => [],
3027             };
3028             foreach (@{$response->{services}->{'n2:ServiceCall'}}) {
3029             push @{$subscriptionInfo->{services}}, {
3030             maxUsages => $_->{maxUsages}->{content},
3031             period => $_->{period}->{content},
3032             periodExpiry=> $_->{periodExpiry}->{content},
3033             serviceType => $_->{serviceType}->{content},
3034             usageCount => $_->{usageCount}->{content},
3035             };
3036             }
3037             return $subscriptionInfo;
3038             }
3039             return 0;
3040             }
3041              
3042             =head2 modifyPassword
3043              
3044             Changes the betfair account password. See L for details. Returns the betfair response as a hashref or 0 on failure. Requires:
3045              
3046             =over
3047              
3048             =item *
3049              
3050             password : string of the current account password
3051              
3052             =item *
3053              
3054             newPassword : string of the new account password
3055              
3056             =item *
3057              
3058             newPasswordRepeat : string of the new account password
3059              
3060             =back
3061              
3062             Example
3063              
3064             my $response = $betfair->modifyPassword({
3065             password => 'itsasecret',
3066             newPassword => 'moojolicious',
3067             newPasswordRepeat => 'moojolicious',
3068             });
3069              
3070             =cut
3071              
3072             sub modifyPassword {
3073             my ($self, $args) = @_;
3074             my $checkParams = {
3075             password => ['password', 1],
3076             newPassword => ['password', 1],
3077             newPasswordRepeat => ['password', 1],
3078             };
3079             return 0 unless $self->_checkParams($checkParams, $args);
3080             $args->{exchangeId} = 3;
3081             if ($self->_doRequest('modifyPassword', $args)) {
3082             return 1;
3083             }
3084             return 0;
3085             }
3086              
3087             =head2 modifyProfile
3088              
3089             Modifies the account profile details of the betfair account. See L for details. Returns 1 on success or 0 on failure. Requires a hashref with the following parameters:
3090              
3091             =over
3092              
3093             =item *
3094              
3095             password : string of the password for the betfair account
3096              
3097             =item *
3098              
3099             address1 : string of address line 1 (optional)
3100              
3101             =item *
3102              
3103             address2 : string of address line 2 (optional)
3104              
3105             =item *
3106              
3107             address3 : string of address line 3 (optional)
3108              
3109             =item *
3110              
3111             townCity : string of the town/city (optional)
3112              
3113             =item *
3114              
3115             countyState : string of the county or state - note for Australian accounts this must be a valid state (optional)
3116              
3117             =item *
3118              
3119             postCode : string of the postcode (aka zipcode). (optional)
3120              
3121             =item *
3122              
3123             countryOfResidence : string of the country of residence (optional)
3124              
3125             =item *
3126              
3127             homeTelephone : string of the home telephone number (optional)
3128              
3129             =item *
3130              
3131             workTelephone : string of the work telephone number (optional)
3132              
3133             =item *
3134              
3135             mobileTelephone : string of the mobile telephone number (optional)
3136              
3137             =item *
3138              
3139             emailAddress : string of the email address (optional)
3140              
3141             =item *
3142              
3143             timeZone : string of the timezone (optional)
3144              
3145             =item *
3146              
3147             depositLimit : integer of the deposite limit to set (optional)
3148              
3149             =item *
3150              
3151             depositLimitFrequency : string of the betfair GamcareLimitFreq enumerated type. See L for details (optional)
3152              
3153             =item *
3154              
3155             lossLimit : integer of the Gamcare loss limit for the account (optional)
3156              
3157             =item *
3158              
3159             lossLimitFrequency : string of the betfair GamcareLimitFreq enumerated type. See L for details (optional)
3160              
3161             =item *
3162              
3163             nationalIdentifier : string of the national identifier (optional)
3164              
3165             =back
3166              
3167             Example
3168              
3169             # update mobile number
3170             my $response = $betfair->modifyProfile({
3171             password => 'itsasecret',
3172             mobileTelephone => '07777777777',
3173             });
3174              
3175             =cut
3176              
3177              
3178             sub modifyProfile {
3179             my ($self, $args) = @_;
3180             my $checkParams = {
3181             password => ['password', 1],
3182             address1 => ['string', 0],
3183             address2 => ['string', 0],
3184             address3 => ['string', 0],
3185             townCity => ['string', 0],
3186             countyState => ['string', 0],
3187             postCode => ['string', 0],
3188             countryOfResidence => ['string', 0],
3189             homeTelephone => ['string', 0],
3190             workTelephone => ['string', 0],
3191             mobileTelephone => ['string', 0],
3192             emailAddress => ['string', 0],
3193             timeZone => ['string', 0],
3194             depositLimit => ['int', 0],
3195             depositLimitFrequency => ['gamcareLimitFreqEnum', 0],
3196             lossLimit => ['int', 0],
3197             lossLimitFrequency => ['gamcareLimitFreqEnum', 0],
3198             nationalIdentifier => ['string', 0],
3199             };
3200             return 0 unless $self->_checkParams($checkParams, $args);
3201             $args->{exchangeId} = 3;
3202             if ($self->_doRequest('modifyProfile', $args)) {
3203             return 1;
3204             }
3205             return 0;
3206             }
3207              
3208             =head2 retrieveLIMBMessage
3209              
3210             This service is not available with the betfair free API.
3211              
3212             Returns a hashref of the betfair response. See L for details. No parameters are required.
3213              
3214             Example
3215              
3216             my $limbMsg = $betfair->retrieveLimbMessage;
3217              
3218             =cut
3219              
3220             sub retrieveLIMBMessage {
3221             my $self = shift;
3222             if ($self->_doRequest('retrieveLIMBMessage', {exchangeId => 3})) {
3223             my $response = $self->{response}->{'soap:Body'}->{'n:retrieveLIMBMessageResponse'}->{'n:Result'};
3224             my $limbMsg = {
3225             totalMessageCount => $response->{totalMessageCount}->{content},
3226            
3227             retrievePersonalMessage => {
3228             message => $response->{retrievePersonalMessage}->{message}->{content},
3229             messageId => $response->{retrievePersonalMessage}->{messageId}->{content},
3230             enforceDate => $response->{retrievePersonalMessage}->{enforceDate}->{content},
3231             indicator => $response->{retrievePersonalMessage}->{indicator}->{content},
3232             },
3233              
3234             retrieveTCPrivacyPolicyChangeMessage => {
3235             reasonForChange => $response->{retrieveTCPrivacyPolicyChangeMessage}->{reasonForChange}->{content},
3236             messageId => $response->{retrieveTCPrivacyPolicyChangeMessage}->{messageId}->{content},
3237             enforceDate => $response->{retrieveTCPrivacyPolicyChangeMessage}->{enforceDate}->{content},
3238             indicator => $response->{retrieveTCPrivacyPolicyChangeMessage}->{indicator}->{content},
3239             },
3240             retrievePasswordChangeMessage => {
3241             messageId => $response->{retrievePasswordChangeMessage}->{messageId}->{content},
3242             enforceDate => $response->{retrievePasswordChangeMessage}->{enforceDate}->{content},
3243             indicator => $response->{retrievePasswordChangeMessage}->{indicator}->{content},
3244             },
3245             retrieveBirthDateCheckMessage => {
3246             messageId => $response->{retrieveBirthDateCheckMessage}->{messageId}->{content},
3247             enforceDate => $response->{retrieveBirthDateCheckMessage}->{enforceDate}->{content},
3248             indicator => $response->{retrieveBirthDateCheckMessage}->{indicator}->{content},
3249             birthDate => $response->{retrieveBirthDateCheckMessage}->{birthDate}->{content},
3250             },
3251             retrieveAddressCheckMessage => {
3252             messageId => $response->{retrieveAddressCheckMessage}->{messageId}->{content},
3253             enforceDate => $response->{retrieveAddressCheckMessage}->{enforceDate}->{content},
3254             indicator => $response->{retrieveAddressCheckMessage}->{indicator}->{content},
3255             address1 => $response->{retrieveAddressCheckMessage}->{address1}->{content},
3256             address2 => $response->{retrieveAddressCheckMessage}->{address2}->{content},
3257             address3 => $response->{retrieveAddressCheckMessage}->{address3}->{content},
3258             town => $response->{retrieveAddressCheckMessage}->{town}->{content},
3259             county => $response->{retrieveAddressCheckMessage}->{county}->{content},
3260             zipcode => $response->{retrieveAddressCheckMessage}->{zipcode}->{content},
3261             country => $response->{retrieveAddressCheckMessage}->{country}->{content},
3262             },
3263             retrieveContactDetailsCheckMessage => {
3264             messageId => $response->{retrieveContactDetailsCheckMessage}->{messageId}->{content},
3265             enforceDate => $response->{retrieveContactDetailsCheckMessage}->{enforceDate}->{content},
3266             indicator => $response->{retrieveContactDetailsCheckMessage}->{indicator}->{content},
3267             homeTelephone => $response->{retrieveContactDetailsCheckMessage}->{homeTelephone}->{content},
3268             workTelephone => $response->{retrieveContactDetailsCheckMessage}->{workTelephone}->{content},
3269             mobileTelephone => $response->{retrieveContactDetailsCheckMessage}->{mobileTelephone}->{content},
3270             emailAddress => $response->{retrieveContactDetailsCheckMessage}->{emailAddress}->{content},
3271             },
3272             retrieveChatNameChangeMessage => {
3273             messageId => $response->{retrieveChatNameChangeMessage}->{messageId}->{content},
3274             enforceDate => $response->{retrieveChatNameChangeMessage}->{enforceDate}->{content},
3275             indicator => $response->{retrieveChatNameChangeMessage}->{indicator}->{content},
3276             chatName => $response->{retrieveChatNameChangeMessage}->{chatName}->{content},
3277             },
3278             };
3279             my $billingAddressItems = $self->_forceArray(
3280             $response->{retrieveCardBillingAddressCheckItems}->{'n2:retrieveCarBillingAddressCheckLIMBMessage'});
3281             foreach (@{$billingAddressItems}) {
3282             push @{$limbMsg->{retrieveCardBillingAddressCheckItems}}, {
3283             messageId => $_->{messageId}->{content},
3284             enforceDate => $_->{enforceDate}->{content},
3285             indicator => $_->{indicator}->{content},
3286             nickName => $_->{nickName}->{content},
3287             cardShortNumber => $_->{cardShortNumber}->{content},
3288             address1 => $_->{address1}->{content},
3289             address2 => $_->{address2}->{content},
3290             address3 => $_->{address3}->{content},
3291             town => $_->{town}->{content},
3292             county => $_->{county}->{content},
3293             zipcode => $_->{zipcode}->{content},
3294             country => $_->{country}->{content},
3295             };
3296             }
3297             return $limbMsg;
3298             }
3299             return 0;
3300             }
3301              
3302             =head2 selfExclude
3303              
3304             WARNING - using this method will deactivate your betfair account for a minimum of 6 months. See L for details. Returns 1 on success or 0 on failure. Requires the following parameters in a hashref:
3305              
3306             =over
3307              
3308             =item *
3309              
3310             selfExclude : string boolean response (should be 'true' to succeed)
3311              
3312             =item *
3313              
3314             password : string of the betfair account password
3315              
3316             =back
3317              
3318             Example
3319              
3320             $excludeResult = $betfair->selfExclude({
3321             selfExclude => 'true',
3322             password => 'itsasecret',
3323             });
3324              
3325             =cut
3326              
3327             sub selfExclude {
3328             my ($self, $args) = @_;
3329             my $checkParams = {
3330             password => ['password', 1],
3331             selfExclude => ['boolean', 1],
3332             };
3333             return 0 unless $self->_checkParams($checkParams, $args);
3334             $args->{exchangeId} = 3;
3335             if ($self->_doRequest('selfExclude', $args)) {
3336             return 1;
3337             }
3338             return 0;
3339             }
3340              
3341             =head2 setChatName
3342              
3343             This service is not available with the free betfair API, nor with the paid personal betfair API.
3344              
3345             Sets the chat name of the betfair account. See L for details. Returns 1 on success or 0 on failure. Requires the following parameters in a hashref:
3346              
3347             =over
3348              
3349             =item *
3350              
3351             chatName : string of the desired chatname
3352              
3353             =item *
3354              
3355             password : string of the betfair account password
3356              
3357             =back
3358              
3359             Example
3360              
3361             $excludeResult = $betfair->setChatName({
3362             chatName => 'sillymoose',
3363             password => 'itsasecret',
3364             });
3365              
3366             =cut
3367              
3368             sub setChatName {
3369             my ($self, $args) = @_;
3370             my $checkParams = {
3371             password => ['password', 1],
3372             chatName => ['string', 1],
3373             };
3374             return 0 unless $self->_checkParams($checkParams, $args);
3375             $args->{exchangeId} = 3;
3376             if ($self->_doRequest('setChatName', $args)) {
3377             return 1;
3378             }
3379             return 0;
3380             }
3381              
3382             =head2 submitLIMBMessage
3383              
3384             This service is not available with the betfair free API.
3385              
3386             Submits a LIMB message to the betfair API. See L for details. Returns 1 on success or 0 on failure. betfair returns additional validation error information on failure, so be sure to check the error message using the getError method. Requires a hashref with the following parameters:
3387              
3388             =over
3389              
3390             =item *
3391              
3392             password : string of the betfair account password
3393              
3394             =item *
3395              
3396             submitPersonalMessage : a hashref containing the following key / pair values (optional):
3397              
3398             =over 8
3399              
3400             =item *
3401              
3402             messageId : integer of the message Id
3403              
3404             =item *
3405              
3406             acknowledgement : string 'Y'
3407              
3408             =back
3409              
3410             =item *
3411              
3412             submitTCPrivacyPolicyChangeMessage : a hashref containing the following key / value pairs (optional):
3413              
3414             =over 8
3415              
3416             =item *
3417              
3418             messageId : integer of the message Id
3419              
3420             =item *
3421              
3422             tCPrivacyPolicyChangeAcceptance : string 'Y'
3423              
3424             =back
3425              
3426             =item *
3427              
3428             submitPasswordChangeMessage : a hashref containing the following key / value pairs (optional):
3429              
3430             =over 8
3431              
3432             =item *
3433              
3434             messageId : integer of the message Id
3435              
3436             =item *
3437              
3438             newPassword : string of the new password
3439              
3440             =item *
3441              
3442             newPasswordRepeat : string of the new password
3443              
3444             =back
3445              
3446             =item *
3447              
3448             submitBirthDateCheckMessage : a hashref containing the following key / value pairs (optional):
3449              
3450             =over 8
3451              
3452             =item *
3453              
3454             messageId : integer of the message Id
3455              
3456             =item *
3457              
3458             detailsCorrect : string of either 'Y' or 'N'
3459              
3460             =item *
3461              
3462             correctBirthDate : string of the correct birthdate - should be a valid XML datetime format
3463              
3464             =back
3465              
3466             =item *
3467              
3468             submitAddressCheckMessage : a hashref containing the following key / value pairs (optional):
3469              
3470             =over 8
3471              
3472             =item *
3473              
3474             messageId : integer of the message Id
3475              
3476             =item *
3477              
3478             detailsCorrect : string of either 'Y' or 'N'
3479              
3480             =item *
3481              
3482             newAddress1 : string of the first line of the address
3483              
3484             =item *
3485              
3486             newAddress2 : string of the second line of the address
3487              
3488             =item *
3489              
3490             newAddress3 : string of the third line of the address
3491              
3492             =item *
3493              
3494             newTown: string of the town of the address
3495              
3496             =item *
3497              
3498             newZipCode: string of the postal code of the address
3499              
3500             =item *
3501              
3502             newCountry: string of the the Country of the address
3503              
3504             =back
3505              
3506             submitContactDetailsCheckMessage: a hashref containing the following key / value pairs (optional):
3507              
3508             =over 8
3509              
3510             =item *
3511              
3512             messageId : integer of the message Id
3513              
3514             =item *
3515              
3516             detailsCorrect : string of either 'Y' or 'N'
3517              
3518             =item *
3519              
3520             newHomeTelephone : string of the new home telephone number
3521              
3522             =item *
3523              
3524             newWorkTelephone : string of the new work telephone number
3525              
3526             =item *
3527              
3528             newMobileTelephone : string of the new mobile telephone number
3529              
3530             =item *
3531              
3532             newEmailAddress : string of the new email address
3533              
3534             =back
3535              
3536             =item *
3537              
3538             submitChatNameChangeMessage : a hashref containing the following key / value pairs (optional):
3539              
3540             =over 8
3541              
3542             =item *
3543              
3544             messageId : integer of the message Id
3545              
3546             =item *
3547              
3548             newChatName : string of the new chat name
3549              
3550             =back
3551              
3552             =item *
3553              
3554             submitCardBillingAddressCheckItems : an arrayref of hashrefs containing the following key / value pairs (optional):
3555              
3556             =over 8
3557              
3558             =item *
3559              
3560             messageId : integer of the message Id
3561              
3562             =item *
3563              
3564             detailsCorrect : string of either 'Y' or 'N'
3565              
3566             =item *
3567              
3568             nickName : string of the card nick name (8 characters or less)
3569              
3570             =item *
3571              
3572             newAddress1 : string of the first line of the address
3573              
3574             =item *
3575              
3576             newAddress2 : string of the second line of the address
3577              
3578             =item *
3579              
3580             newAddress3 : string of the third line of the address
3581              
3582             =item *
3583              
3584             newTown: string of the town of the address
3585              
3586             =item *
3587              
3588             newZipCode: string of the postal code of the address
3589              
3590             =item *
3591              
3592             newCountry: string of the the Country of the address
3593              
3594             =back
3595              
3596             =back
3597              
3598             Example
3599              
3600             my $limbMsg = $betfair->submitLimbMessage({
3601             password => 'itsasecret',
3602             submitPersonalMessage => { messageId => 123456789,
3603             acknowledgement=> 'Y',
3604             },
3605             });
3606              
3607             =cut
3608              
3609             sub submitLIMBMessage {
3610             my ($self, $args) = @_;
3611             my $checkParams = {
3612             password => ['password', 1],
3613             submitPersonalMessage => ['hash', 0],
3614             submitTCPrivacyPolicyChangeMessage => ['hash', 0],
3615             submitPasswordChangeMessage => ['hash', 0],
3616             submitBirthDateCheckMessage => ['hash', 0],
3617             submitAddressCheckMessage => ['hash', 0],
3618             submitContactDetailsCheckMessage => ['hash', 0],
3619             submitChatNameChangeMessage => ['hash', 0],
3620             submitCardBillingAddressCheckItems => ['hash', 0],
3621             };
3622             return 0 unless $self->_checkParams($checkParams, $args);
3623             $args->{exchangeId} = 3;
3624             if ($self->_doRequest('submitLIMBMessage', $args) ) {
3625             return 1;
3626             }
3627             # add any validation errors to the header error message so that user can retrieve the information using getError
3628              
3629             return 0 unless exists $self->{response}->{'soap:Body'}->{'n:submitLIMBMessageResponse'}->{'n:Result'}->{validationErrors};
3630             my $response = $self->_forceArray(
3631             $self->{response}->{'soap:Body'}->{'n:submitLIMBMessageResponse'}->{'n:Result'});
3632             my $validationErrors;
3633             foreach (@{$response}) {
3634             $validationErrors .= ' ' . $_->{content};
3635             }
3636             $self->{headerError} .= ' ' . $validationErrors;
3637             return 0;
3638             }
3639              
3640             =head2 transferFunds
3641              
3642             Transfers funds between the UK and Australian wallets. See L for details. Returns a hashref of the betfair response or 0 on failure. Requires the following parameters in a hashref:
3643              
3644             =over
3645              
3646             =item *
3647              
3648             sourceWalletId : integer either: 1 for UK wallet or 2 for the Australian wallet
3649              
3650             =item *
3651              
3652             targetWalletId : integer either: 1 for UK wallet or 2 for the Australian wallet
3653              
3654             =item *
3655              
3656             amount : number representing the amount of money to transfer between wallets
3657              
3658             =back
3659              
3660             Example
3661              
3662             # transfer 15 from the UK wallet to the Australian wallet
3663             $excludeResult = $betfair->transferFunds({
3664             sourceWalletId => 1,
3665             targetWalletId => 2,
3666             amount => 15.0,
3667             });
3668              
3669             =cut
3670              
3671             sub transferFunds {
3672             my ($self, $args) = @_;
3673             my $checkParams = {
3674             sourceWalletId => ['int', 1],
3675             targetWalletId => ['int', 1],
3676             amount => ['decimal', 1],
3677             };
3678             return 0 unless $self->_checkParams($checkParams, $args);
3679             $args->{exchangeId} = 3;
3680             if ($self->_doRequest('transferFunds', $args)) {
3681             my $response = $self->{response}->{'soap:Body'}->{'n:transferFundsResponse'}->{'n:Result'};
3682             return {
3683             monthlyDepositTotal => $response->{monthlyDepositTotal}->{content},
3684             };
3685             }
3686             return 0;
3687             }
3688              
3689             =head2 updatePaymentCard
3690              
3691             Updates a payment card on your betfair account. Returns a hashref betfair response or 0 on failure. See L. Requires:
3692              
3693             =over
3694              
3695             =item *
3696              
3697             cardStatus : string of a valid betfair paymentCardStatusEnum, either 'LOCKED' or 'UNLOCKED'
3698              
3699             =item *
3700              
3701             startDate : string of the card start date, optional depending on type of card
3702              
3703             =item *
3704              
3705             expiryDate : string of the card expiry date
3706              
3707             =item *
3708              
3709             issueNumber : string of the issue number or NULL if the cardType is not Solo or Switch
3710              
3711             =item *
3712              
3713             nickName : string of the card nickname must be less than 9 characters
3714              
3715             =item *
3716              
3717             password : string of the betfair account password
3718              
3719             =item *
3720              
3721             address1 : string of the first line of the address for the payment card
3722              
3723             =item *
3724              
3725             address2 : string of the second line of the address for the payment card
3726              
3727             =item *
3728              
3729             address3 : string of the third line of the address for the payment card (optional)
3730              
3731             =item *
3732              
3733             address4 : string of the fourth line of the address for the payment card (optional)
3734              
3735             =item *
3736              
3737             town : string of the town for the payment card
3738              
3739             =item *
3740              
3741             county : string of the county for the payment card
3742              
3743             =item *
3744              
3745             zipCode : string of the zip / postal code for the payment card
3746              
3747             =item *
3748              
3749             country : string of the country for the payment card
3750              
3751             =back
3752              
3753             Example
3754              
3755             my $updatePaymentCardResponse = $betfair->updatePaymentCard({
3756             cardStatus => 'UNLOCKED',
3757             startDate => '0113',
3758             expiryDate => '0116',
3759             issueNumber => 'NULL',
3760             billingName => 'The Sillymoose',
3761             nickName => 'democard',
3762             password => 'password123',
3763             address1 => 'Tasty bush',
3764             address2 => 'Mountain Plains',
3765             town => 'Hoofton',
3766             zipCode => 'MO13FR',
3767             county => 'Mooshire',
3768             country => 'UK',
3769             });
3770              
3771             =cut
3772              
3773             sub updatePaymentCard {
3774             my ($self, $args) = @_;
3775             my $checkParams = {
3776             cardStatus => ['cardStatusEnum', 1],
3777             startDate => ['cardDate', 1],
3778             expiryDate => ['cardDate', 1],
3779             issueNumber => ['int', 1],
3780             billingName => ['string', 1],
3781             nickName => ['string9', 1],
3782             password => ['password', 1],
3783             address1 => ['string', 1],
3784             address2 => ['string', 0],
3785             address3 => ['string', 0],
3786             address4 => ['string', 0],
3787             town => ['string', 1],
3788             zipCode => ['string', 1],
3789             county => ['string', 1],
3790             country => ['string', 1],
3791             };
3792             return 0 unless $self->_checkParams($checkParams, $args);
3793             $args->{exchangeId} = 3;
3794             if ($self->_doRequest('updatePaymentCard', $args) ) {
3795             my $response = $self->{response}->{'soap:Body'}->{'n:updatePaymentCardResponse'}->{'n:Result'};
3796             return {
3797             nickName => $response->{nickName}->{content},
3798             billingName => $response->{billingName}->{content},
3799             cardType => $response->{cardType}->{content},
3800             expiryDate => $response->{expiryDate}->{content},
3801             startDate => $response->{startDate}->{content},
3802             address1 => $response->{address1}->{content},
3803             address2 => $response->{address2}->{content},
3804             address3 => $response->{address3}->{content},
3805             address4 => $response->{address4}->{content},
3806             zipCode => $response->{zipCode}->{content},
3807             country => $response->{country}->{content},
3808             };
3809             }
3810             return 0;
3811             }
3812              
3813             =head2 viewProfile
3814              
3815             Returns a hashref betfair response or 0 on failure. See L. Requires no parameters.
3816              
3817             Example
3818              
3819             my $profile = $betfair->viewProfile;
3820              
3821             =cut
3822              
3823             sub viewProfile {
3824             my $self = shift;
3825             if ($self->_doRequest('viewProfile', {exchangeId => 3})) {
3826             my $response = $self->{response}->{'soap:Body'}->{'n:viewProfileResponse'}->{'n:Result'};
3827             return {
3828             title => $response->{title}->{content},
3829             firstName => $response->{firstName}->{content},
3830             surname => $response->{surname}->{content},
3831             userName => $response->{userName}->{content},
3832             forumName => $response->{forumName}->{content},
3833             address1 => $response->{address1}->{content},
3834             address2 => $response->{address2}->{content},
3835             address3 => $response->{address3}->{content},
3836             townCity => $response->{townCity}->{content},
3837             countyState => $response->{countyState}->{content},
3838             postCode => $response->{postCode}->{content},
3839             countryOfResidence => $response->{countryOfResidence}->{content},
3840             homeTelephone => $response->{homeTelephone}->{content},
3841             workTelephone => $response->{workTelephone}->{content},
3842             mobileTelephone => $response->{mobileTelephone}->{content},
3843             emailAddress => $response->{emailAddress}->{content},
3844             timeZone => $response->{timeZone}->{content},
3845             currency => $response->{currency}->{content},
3846             gamecareLimit => $response->{gamcareLimit}->{content},
3847             gamcareFrequency => $response->{gamcareFrequency}->{content},
3848             gamecareLossLimit => $response->{gamcareLossLimit}->{content},
3849             gamcareLossLimitFrequency=> $response->{gamcareLossLimitFrequency}->{content},
3850             };
3851             }
3852             return 0;
3853             }
3854              
3855             =head2 viewProfileV2
3856              
3857             Returns a hashref betfair response or 0 on failure. See L. Requires no parameters.
3858              
3859             Example
3860              
3861             my $profile = $betfair->viewProfileV2;
3862              
3863             =cut
3864              
3865             sub viewProfileV2 {
3866             my $self = shift;
3867             if ($self->_doRequest('viewProfileV2', {requestVersion => 'V1',
3868             exchangeId => 3,
3869             })) {
3870             my $response = $self->{response}->{'soap:Body'}->{'n:viewProfileV2Response'}->{'n:Result'};
3871             return {
3872             title => $response->{title}->{content},
3873             firstName => $response->{firstName}->{content},
3874             surname => $response->{surname}->{content},
3875             userName => $response->{userName}->{content},
3876             forumName => $response->{forumName}->{content},
3877             address1 => $response->{address1}->{content},
3878             address2 => $response->{address2}->{content},
3879             address3 => $response->{address3}->{content},
3880             townCity => $response->{townCity}->{content},
3881             countyState => $response->{countyState}->{content},
3882             postCode => $response->{postCode}->{content},
3883             countryOfResidence => $response->{countryOfResidence}->{content},
3884             homeTelephone => $response->{homeTelephone}->{content},
3885             workTelephone => $response->{workTelephone}->{content},
3886             mobileTelephone => $response->{mobileTelephone}->{content},
3887             emailAddress => $response->{emailAddress}->{content},
3888             timeZone => $response->{timeZone}->{content},
3889             currency => $response->{currency}->{content},
3890             gamecareLimit => $response->{gamcareLimit}->{content},
3891             gamcareFrequency => $response->{gamcareFrequency}->{content},
3892             gamecareLossLimit => $response->{gamcareLossLimit}->{content},
3893             gamcareLossLimitFrequency=> $response->{gamcareLossLimitFrequency}->{content},
3894             tAN => $response->{tAN}->{content},
3895             referAndEarnCode => $response->{referAndEarnCode}->{content},
3896             earthportId => $response->{earthportId}->{content},
3897             kYCStatus => $response->{kYCStatus}->{content},
3898             nationalIdentifier => $response->{nationalIdentifier}->{content},
3899             };
3900             }
3901             return 0;
3902             }
3903              
3904             =head2 viewReferAndEarn
3905              
3906             Returns a hashref containing the betfair account's refer and earn code or 0 on failure. See L for details. Requires no parameters.
3907              
3908             Example
3909              
3910             my $referAndEarnCode = $betfair->viewReferAndEarn;
3911              
3912             =cut
3913              
3914             sub viewReferAndEarn {
3915             my $self = shift;
3916             if ($self->_doRequest('viewReferAndEarn', {exchangeId => 3})) {
3917             my $response = $self->{response}->{'soap:Body'}->{'n:viewReferAndEarnResponse'}->{'n:Result'};
3918             return {
3919             referAndEarnCode => $response->{'referAndEarnCode'}->{content},
3920             };
3921             }
3922             return 0;
3923             }
3924              
3925             =head2 withdrawToPaymentCard
3926              
3927             Withdraws money from your betfair account to the payment card specified. Returns a hashref of the withdraw response from betfair or 0 on failure. See L for details. Requires:
3928              
3929             =over
3930              
3931             =item *
3932              
3933             amount : number representing the amount of money to withdraw
3934              
3935             =item *
3936              
3937             cardIdentifier : string of the nickname of the payment card
3938              
3939             =item *
3940              
3941             password : string of your betfair password
3942              
3943             =back
3944              
3945             Example
3946              
3947             my $withdrawalResult = $betfair->withdrawToPaymentCard({
3948             amount => 10,
3949             cardIdentifier => 'checking',
3950             password => 'password123',
3951             });
3952              
3953             =cut
3954              
3955             sub withdrawToPaymentCard {
3956             my ($self, $args) = @_;
3957             my $checkParams = {
3958             amount => ['decimal', 1],
3959             cardIdentifier => ['string9', 1],
3960             password => ['password', 1],
3961             };
3962             return 0 unless $self->_checkParams($checkParams, $args);
3963             $args->{exchangeId} = 3;
3964             if ($self->_doRequest('withdrawToPaymentCard', $args) ) {
3965             my $response = $self->{response}->{'soap:Body'}->{'n:withdrawToPaymentCardResponse'}->{'n:Result'};
3966             return {
3967             amountWithdrawn => $response->{'amountWithdrawn'}->{content},
3968             maxAmount => $response->{'maxAmount'}->{content}
3969             };
3970             }
3971             return 0;
3972             }
3973              
3974             =head1 INTERNAL METHODS
3975              
3976             =head2 _doRequest
3977              
3978             Processes requests to and from the betfair API.
3979              
3980             =cut
3981              
3982             sub _doRequest {
3983             my ($self, $action, $params) = @_;
3984              
3985             # get the server url and remove the server id from $params
3986             my $server = $params->{exchangeId};
3987             my $uri = $self->_getServerURI($server);
3988             delete $params->{exchangeId};
3989              
3990             # clear data from previous request
3991             $self->_clearData;
3992            
3993             # add header to $params
3994             $params->{header}->{sessionToken} = $self->{sessionToken} if defined $self->{sessionToken};
3995             $params->{header}->{clientStamp} = 0;
3996              
3997             # build xml message
3998             $self->{xmlsent} = WWW::betfair::Template::populate($uri, $action, $params);
3999              
4000             # save response, session token and error as attributes
4001             my $uaResponse = WWW::betfair::Request::new_request($uri, $action, $self->{xmlsent});
4002             $self->{xmlreceived} = $uaResponse->decoded_content(charset => 'none');
4003             $self->{response} = eval {XMLin($self->{xmlreceived})};
4004             if ($@) {
4005             croak 'error parsing betfair XML response ' . $@;
4006             }
4007             if ($self->{response}){
4008              
4009             $self->{sessionToken}
4010             = $self->{response}->{'soap:Body'}->{'n:'.$action.'Response'}->{'n:Result'}->{'header'}->{'sessionToken'}->{content};
4011            
4012             $self->{headerError}
4013             = $self->{response}->{'soap:Body'}->{'n:'.$action.'Response'}->{'n:Result'}->{'header'}->{'errorCode'}->{content}
4014             || 'OK';
4015              
4016             $self->{bodyError}
4017             = $self->{response}->{'soap:Body'}->{'n:'.$action.'Response'}->{'n:Result'}->{'errorCode'}->{content}
4018             || 'OK';
4019             return 1 if $self->getError eq 'OK';
4020             }
4021             return 0;
4022             }
4023              
4024             =head2 _getServerURI
4025              
4026             Returns the URI for the target betfair server depending on whether it is an exchange server (1 and 2) or the global server.
4027              
4028             =cut
4029              
4030             sub _getServerURI {
4031             my ($self, $server) = @_;
4032             given($server) {
4033             when (/1/) { return 'https://api.betfair.com/exchange/v5/BFExchangeService'}
4034             when (/2/) { return 'https://api-au.betfair.com/exchange/v5/BFExchangeService'}
4035             default { return 'https://api.betfair.com/global/v3/BFGlobalService'}
4036             }
4037             }
4038              
4039              
4040             =head2 _sortArrayRef
4041              
4042             Returns a sorted arrayref based on price.
4043              
4044             =cut
4045              
4046             sub _sortArrayRef {
4047             my $array_ref = shift;
4048             if (ref($array_ref) eq 'ARRAY'){
4049             return sort { $b->{price} <=> $a->{price} } @$array_ref;
4050             }
4051             return $array_ref;
4052             }
4053              
4054             =head2 _addPaymentCardLine
4055              
4056             Pushes a hashref of payment card key / value pairs into an arrayref and returns the result.
4057              
4058             =cut
4059              
4060             sub _addPaymentCardLine {
4061             my ($self, $payment_card, $line_to_be_added) = @_;
4062             push(@{$payment_card}, {
4063             countryCodeIso3 => $line_to_be_added->{'billingCountryIso3'}->{content},
4064             billingAddress1 => $line_to_be_added->{'billingAddress1'}->{content},
4065             billingAddress2 => $line_to_be_added->{'billingAddress2'}->{content},
4066             billingAddress3 => $line_to_be_added->{'billingAddress3'}->{content},
4067             billingAddress4 => $line_to_be_added->{'billingAddress4'}->{content},
4068             cardType => $line_to_be_added->{'cardType'}->{content},
4069             issuingCountryIso3 => $line_to_be_added->{'issuingCountryIso3'}->{content},
4070             totalWithdrawals => $line_to_be_added->{'totalWithdrawals'}->{content},
4071             expiryDate => $line_to_be_added->{'expiryDate'}->{content},
4072             nickName => $line_to_be_added->{'nickName'}->{content},
4073             cardStatus => $line_to_be_added->{'cardStatus'}->{content},
4074             issueNumber => $line_to_be_added->{'issueNumber'}->{content},
4075             country => $line_to_be_added->{'country'}->{content},
4076             county => $line_to_be_added->{'county'}->{content},
4077             billingName => $line_to_be_added->{'billingName'}->{content},
4078             town => $line_to_be_added->{'town'}->{content},
4079             postcode => $line_to_be_added->{'postcode'}->{content},
4080             netDeposits => $line_to_be_added->{'netDeposits'}->{content},
4081             cardShortNumber => $line_to_be_added->{'cardShortNumber'}->{content},
4082             totalDeposits => $line_to_be_added->{'totalDeposits'}->{content}
4083             });
4084             return $payment_card;
4085             }
4086              
4087             =head2 _forceArray
4088              
4089             Receives a reference variable and if the data is not an array, returns a single-element arrayref. Else returns the data as received.
4090              
4091             =cut
4092              
4093             sub _forceArray {
4094             my ($self, $data) = @_;
4095             return ref($data) eq 'ARRAY' ? $data : [$data];
4096             }
4097              
4098             =head2 _checkParams
4099              
4100             Receives an hashref of parameter types and a hashref of arguments. Checks that all mandatory arguments are present using _checkParam and that no additional parameters exist in the hashref.
4101              
4102             =cut
4103              
4104             sub _checkParams {
4105             my ($self, $paramChecks, $args) = @_;
4106              
4107             # check no rogue arguments have been included in parameters
4108             foreach my $paramName (keys %{$args}) {
4109             if (not exists $paramChecks->{$paramName}) {
4110             $self->{headerError} = "Error: unexpected parameter $paramName is not a correct argument for the method called.";
4111             return 0;
4112             }
4113             # if exists now check that the type is correct
4114             else {
4115             return 0 unless $self->_checkParam( $paramChecks->{$paramName}->[0],
4116             $args->{$paramName});
4117             }
4118             }
4119             # check all mandatory parameters are present
4120             foreach my $paramName (keys %{$paramChecks}){
4121             if ($paramChecks->{$paramName}->[1]){
4122             unless (exists $args->{$paramName}) {
4123             $self->{headerError} = "Error: missing mandatory parameter $paramName.";
4124             return 0;
4125             }
4126             }
4127             }
4128             return 1;
4129             }
4130              
4131             =head2 _checkParam
4132              
4133             Checks the parameter using the TypeCheck.pm object, returns 1 on success and 0 on failure.
4134              
4135             =cut
4136              
4137             sub _checkParam {
4138             my ($self, $type, $value) = @_;
4139             unless($self->{type}->checkParameter($type, $value)) {
4140             $self->{headerError} = "Error: message not sent as parameter $value failed the type requirements check for $type. Check the documentation at the command line: perldoc WWW::betfair::TypeCheck";
4141             return 0;
4142             }
4143             return 1;
4144             }
4145              
4146             =head2 _clearData
4147              
4148             Sets all message related object attributes to null - this is so that the error message from the previous API call is not mis-read as relevant to the current call.
4149              
4150             =cut
4151              
4152             sub _clearData {
4153             my $self = shift;
4154             $self->{xmlsent} = undef;
4155             $self->{xmlreceived} = undef;
4156             $self->{headerError} = undef;
4157             $self->{bodyError} = undef;
4158             $self->{response} = {};
4159             return 1;
4160             }
4161              
4162              
4163             1;
4164              
4165             =head1 AUTHOR
4166              
4167             David Farrell, C<< >>, L
4168              
4169             =head1 BUGS
4170              
4171             Please report any bugs or feature requests to C, or through
4172             the web interface at L. I will be notified, and then you'll
4173             automatically be notified of progress on your bug as I make changes.
4174              
4175             =head1 SUPPORT
4176              
4177             You can find documentation for this module with the perldoc command.
4178              
4179             perldoc WWW::betfair
4180              
4181              
4182             You can also look for information at:
4183              
4184             =over
4185              
4186             =item * RT: CPAN's request tracker (report bugs here)
4187              
4188             L
4189              
4190             =item * AnnoCPAN: Annotated CPAN documentation
4191              
4192             L
4193              
4194             =item * CPAN Ratings
4195              
4196             L
4197              
4198             =item * Search CPAN
4199              
4200             L
4201              
4202             =back
4203              
4204             =head1 ACKNOWLEDGEMENTS
4205              
4206             This project was inspired by the L Perl project. Although L uses a different approach, the betfair free project was a useful point of reference at inception. Thanks guys!
4207              
4208             Thanks to L for creating the exchange and API.
4209              
4210             =head1 LICENSE AND COPYRIGHT
4211              
4212             Copyright 2013 David Farrell.
4213              
4214             This program is free software; you can redistribute it and/or modify it
4215             under the terms of either: the GNU General Public License as published
4216             by the Free Software Foundation; or the Artistic License.
4217              
4218             See http://dev.perl.org/licenses/ for more information.
4219              
4220             =cut