Using VB2008 to acccess the Betfair API: A tutorial

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Ferbar11
    Junior Member
    • Apr 2011
    • 6

    #601
    Originally posted by Mumbles0 View Post
    The line where you call the API is wrong.

    Code:
    Dim Req As New betfair.UK.exchange.GetAccountFundsReq()
    Dim Resp As New betfair.UK.exchange.GetAccountFundsResp()
    With Req
      .header = oHeaderUK()
    End With
    
    '-------------------------------------------------------------
    'Resp = betfair.UK.exchange.GetAccountFunds(Req)   <<  Incorrect!
    'GetAccountFunds is not avaiable
    
    Resp = BetFairUK.getAccountFunds(Req)       '<<< Should be this
    
    '-----------------------------------------------------------
    With Resp
      CheckHeader(.header)
      If .errorCode = betfair.UK.exchange.GetAccountFundsErrorEnum.OK Then
        lbl.Text = .availBalance
      End If
    End With
    I think you are confusing the namespace (betfair.UK.exchange) with the service object (BetFairUK). Elsewhere in your project you should have something like:

    Private BetFairUK As New betfair.UK.exchange.BFExchangeService
    I try it but dint work here.

    Code:
    Dim Req As New BFUK.GetAccountFundsReq
            Dim Resp As New BFUK.GetAccountFundsResp
            With Req
                .header = oHeaderGL
            End With
    
            Resp = BetFairUK.getAccountFunds(Req)
    
            lShowUser.Text = Login.tbUser.Text
            lShowSaldo.Text = Resp.availBalance.ToString
    Last edited by Ferbar11; 17-04-2011, 03:29 PM.

    Comment

    • BigSprout
      Junior Member
      • Feb 2011
      • 60

      #602
      I think your problem is here:

      Code:
              With Req
                  .header = oHeaderGL
              End With
      GetAccountFunds is on the exchange server(s), you are calling the global server

      If you check the code you quoted from Mumbles it is:

      Code:
              With Req
                  .header = oHeaderUK()
              End With
      
      
                or simply:
      
      Req.header = oHeaderUK()
      cheers

      Comment

      • monkeymagix
        Junior Member
        • Jul 2010
        • 105

        #603
        A problem with the Throttle limit

        Hi Mumbles

        I am wondering if you or anyone else can help me with the error that sometimes arises usually when collecting runner prices.

        The error is caused when I call your CheckHeader method and receive the EXCEEDED_THROTTLE error code. This means I have reached the Betfair API request limit.

        This error usually comes up when I try to call a method that collects all the current prices for a market. I thought that rather than get a single horse at one time I would just loop through all the selections in the market and return a list object of a custom struct (bet selection) that could then be saved to the DB.

        However I keep running into these errors > EXCEEDED_THROTTLE

        so I came up with a little function to wait until the next minute before carrying on e.g


        Code:
        private void BeatThrottleLimit()
        {
            DateTime now = DateTime.UtcNow;
        
            // add 1 minute to the current time
            DateTime almostNextUpdateTime = now.AddMinutes(1);
        
            // get new datetime based on almostNextUpdateTime and set the seconds to 0
            DateTime nextUpdateTime = new DateTime(almostNextUpdateTime.Year, almostNextUpdateTime.Month, almostNextUpdateTime.Day, almostNextUpdateTime.Hour, almostNextUpdateTime.Minute, 0);
        
            // sleep for the difference between now and nextUpdateTime
            Thread.Sleep(nextUpdateTime.Subtract(now));
        
        }
        However when I come back from this function I seem to have lost all references to the relevant API object as subsequent function calls raise errors such as NULL object reference exceptions or in the example code provided which returns prices for all selections in a market I get Index was outside the bounds of the array error. This error only happens when I have to make a call to the BeatThrottleLimit function.

        I suspect it might be something to do with the Thread.Sleep command but I am not totally sure and I am wondering if anyone else has had similar problems or issues when using the free API and working around the request limit.

        Is there some function I could call after doing a "wait" / "beat throttle" method call so that I don't lose all my references.

        It is a bit hard to debug due to it being a windows service and not being able to throw the throttle error on demand. However thoughts would be appreciated.

        The relevant code is below


        Code:
        private void BeatThrottleLimit()
        {
            DateTime now = DateTime.UtcNow;
        
            // add 1 minute to the current time
            DateTime almostNextUpdateTime = now.AddMinutes(1);
        
            // get new datetime based on almostNextUpdateTime and set the seconds to 0
            DateTime nextUpdateTime = new DateTime(almostNextUpdateTime.Year, almostNextUpdateTime.Month, almostNextUpdateTime.Day, almostNextUpdateTime.Hour, almostNextUpdateTime.Minute, 0);
        
            // sleep for the difference between now and nextUpdateTime
            Thread.Sleep(nextUpdateTime.Subtract(now));
        
        }
        
        // similar overriden method exists for the BFGlobal.APIResponseHeader Header
        private void CheckHeader(BFUK.APIResponseHeader Header)
        {
            APIHeaderGL.sessionToken = Header.sessionToken;
        
            // set flag so other calls know if we had an issue
            ThrottleLimitError = false;
        
            // if we have broken the API request limit wait until the next minute when it gets reset
            if (Header.errorCode.ToString() == "EXCEEDED_THROTTLE")
            {
        	BeatThrottleLimit();
        
        	ThrottleLimitError = true;
        	
            }
        }
        
        
        // my function will return a list of SelectionPrice objects
        public struct SelectionPrice
        {
        	public int SelectionID;
        
        	public double BackPrice;
        
        	public double LayPrice;
        }
        
        // example of function that will fail due to this error
        public List<SelectionPrice> SaveAllSelectionPrices(int marketID, string betType)
        {
        
            List<SelectionPrice> runnerPrice = new List<SelectionPrice>();
            
            BFUK.GetMarketPricesResp MpriceResp = BetfairUK.getMarketPrices(MpricesReq(marketID));
        
            // Error might get raised here!
            CheckHeader(MpriceResp.header);
        
        
            if (MpriceResp.errorCode == BFUK.GetMarketPricesErrorEnum.INVALID_MARKET)
            {
        	// save market is invalid
        
        	return runnerPrice.ToList();
        
            }
            else if (MpriceResp.errorCode == BFUK.GetMarketPricesErrorEnum.OK)
            {
              
        	if (MpriceResp.marketPrices.marketStatus == BFUK.MarketStatusEnum.CLOSED)
        	{
        
        	    // save market closed
        
        	    return runnerPrice.ToList();
        
        	}
        	else
        	{
        
        	    double backPrice, layPrice;
        	    int selectionID;
        
        
        	    // loop through all selections and save their best price in turn
        	    for (int i = 0; i <= MpriceResp.marketPrices.runnerPrices.Length - 1; i++)
        	    {
        
        		backPrice = layPrice = 0;
        		selectionID = MpriceResp.marketPrices.runnerPrices[i].selectionId;
        
        		try
        		{
        
        		    // get both back and lay
        		   backPrice = MpriceResp.marketPrices.runnerPrices[i].bestPricesToBack[0].price;
        
        		   layPrice = MpriceResp.marketPrices.runnerPrices[i].bestPricesToLay[0].price;
        		}
        		catch (Exception e)
        		{
        		    // log message 
        		    // after a call to CheckHeader and then BeatThrottleLimit the error is usually >>  Error getting selection Price: Index was outside the bounds of the array.
        		    HelperLib.LogMsg("Error getting selection Price: " + e.Message.ToString());
        
        		}
        
        
        		if (backPrice > 0 || layPrice > 0)
        		{
        		    // add an item to my list which is a collection of stucts (my BetPrice object)                            
        		    runnerPrice.Add(new SelectionPrice { SelectionID = selectionID, BackPrice = backPrice, LayPrice = layPrice });
        
        		}
        
        	    }
        	}
            }
        
            return runnerPrice.ToList();
        
        }

        I am also wondering whether this problem is happening because I am running two different BOTs on different machines. One is my local PC and one is a webserver. One BOT just places BETS the other just gets prices.

        Is the API Request Limit linked to the Betfair account that is used to make the request or is it linked to the IP address of the PC making it? If I used different Betfair accounts but ran the BOT from the same PC would this get round the problem or would running multiple BOTS with the same account from different IP's get round it?

        Any help would be much appreciated.

        Thanks

        Comment

        • BigSprout
          Junior Member
          • Feb 2011
          • 60

          #604
          MM,
          I don't understand why you are calling for individual prices for a horse in a market??? - each call registers as one access, hence the exceeded throttle exception you are receiving.

          You can get all of the prices for the full field in one call (takes less than one second) and make several calls in a minute and not receive "Exceeded Throttle" error:

          GetMarketPrices.....10 times per minute (get the full market prices for a race 10 times)
          GetMarketPricesCompressed.....60/minute
          GetCompleteMarketPricesCompressed.....60/minute

          each of the above have been fully documented with coding by Mumbles in this thread

          Post #443 on this page, lists all the different types of procedures to access the free APi
          http://forum.bdp.betfair.com/showthr...?t=112&page=45


          If you use one or all of the above, you will be able to "get around" using the web service and the bot, in fact, you could get the bot to do both by:
          one market using GetMarketPricesCompressed
          the other calling GetCompleteMarketPricesCompressed

          The API has a much faster reaction time

          Cheers

          Edit:
          Err, just noticed you are not coding in VB2008/10 - the link will help in the layout of the calls and a short note on how they work
          Last edited by BigSprout; 19-04-2011, 01:54 AM. Reason: Edit:

          Comment

          • Ferbar11
            Junior Member
            • Apr 2011
            • 6

            #605
            Originally posted by BigSprout View Post
            I think your problem is here:

            Code:
                    With Req
                        .header = oHeaderGL
                    End With
            GetAccountFunds is on the exchange server(s), you are calling the global server

            If you check the code you quoted from Mumbles it is:

            Code:
                    With Req
                        .header = oHeaderUK()
                    End With
            
            
                      or simply:
            
            Req.header = oHeaderUK()
            cheers
            No, isn't work.. This show me 0€ but i got more.

            Dim BetfairGL As New BFGlobal.BFGlobalService
            Dim oHeaderUK As New BFUK.APIRequestHeader
            Dim BetFairUK As New BFUK.BFExchangeService


            ....


            Dim Req As New BFUK.GetAccountFundsReq
            Dim Resp As BFUK.GetAccountFundsResp

            Req.header = oHeaderUK

            Resp = BetFairUK.getAccountFunds(Req)

            lShowUser.Text = Login.tbUser.Text
            lShowSaldo.Text = Resp.availBalance


            what is wrong? :s

            Comment

            • monkeymagix
              Junior Member
              • Jul 2010
              • 105

              #606
              Beating Throttle Limit

              Thanks for replying Big Sprout but if you actually read what I said and look at the code I posted:

              a) I said the following "I thought that rather than get a single horse at one time I would just loop through all the selections in the market and return a list object of a custom struct (bet selection) that could then be saved to the DB."

              So I am not getting the price of a single horse at one time BUT rather I am doing it the way you suggested and getting all the selection prices for a market in one go.

              b) I am using BetfairUK.getMarketPrices to get all the prices for one market.

              I am looking into the compressed version but I would still like to solve this problem with the null object reference after a wait if possible.

              My bot only runs once every 30 seconds. So I should not be running into issues related to calling the same market more than once every 30 seconds and can only presume the fault lies when I am trying to get prices for multiple markets (e.g all markets for a day) or something else.

              Any ideas?

              Comment

              • Mumbles0
                Junior Member
                • Jan 2009
                • 240

                #607
                GetAccountFunds

                Ferbar11,

                Whenever you cal the API it is always a good idea to check for errors in case the call doesn't work properly. Do something like this:

                Code:
                  Dim Req As New BFUK.GetAccountFundsReq
                  Dim Resp As BFUK.GetAccountFundsResp
                
                  Req.header = oHeaderUK()
                  Resp = BetFairUK.getAccountFunds(Req)
                
                  With Resp
                    CheckHeader(.header)   'Check the header for API error
                    If .errorCode = BFUK.GetAccountFundsErrorEnum.OK Then
                
                      lShowSaldo.Text = .availBalance  'OK, show balance in the textbox
                
                    Else
                      Print(.errorCode.ToString)  'If getAccountFunds error
                    End If
                  End With
                The code shown here does full error checking and will only update the textbox if the call worked OK. Otherwise it will tell you what the problem is.

                Comment

                • BigSprout
                  Junior Member
                  • Feb 2011
                  • 60

                  #608
                  Originally posted by monkeymagix View Post
                  ...My bot only runs once every 30 seconds. So I should not be running into issues related to calling the same market more than once every 30 seconds and can only presume the fault lies when I am trying to get prices for multiple markets (e.g all markets for a day) or something else.

                  Any ideas?

                  Hmmm, seems I did misinterpret what you wrote

                  What I now understand is that you are calling multiple markets every 30 seconds using GetMarketPrices...if this is the case then I refer to my original post

                  You can only call GetMarketPrices 10/minute, any more than that and an "Exceeded_Throttle" error is sent, the 10/minute limit is for all markets - not for just one market.

                  You appear to be calling multiple markets twice/minute, if at any time the accumulative number of the markets exceed 10, then the error will occur.

                  Please advise if I am correct this time and we can then look at an alternative - as this is a tutorial on VB2008 it may be best if another thread was started

                  ...or...I could be wrong once again

                  cheers

                  Comment

                  • Ferbar11
                    Junior Member
                    • Apr 2011
                    • 6

                    #609
                    Originally posted by Mumbles0 View Post
                    Ferbar11,

                    Whenever you cal the API it is always a good idea to check for errors in case the call doesn't work properly. Do something like this:

                    Code:
                      Dim Req As New BFUK.GetAccountFundsReq
                      Dim Resp As BFUK.GetAccountFundsResp
                    
                      Req.header = oHeaderUK()
                      Resp = BetFairUK.getAccountFunds(Req)
                    
                      With Resp
                        CheckHeader(.header)   'Check the header for API error
                        If .errorCode = BFUK.GetAccountFundsErrorEnum.OK Then
                    
                          lShowSaldo.Text = .availBalance  'OK, show balance in the textbox
                    
                        Else
                          Print(.errorCode.ToString)  'If getAccountFunds error
                        End If
                      End With
                    The code shown here does full error checking and will only update the textbox if the call worked OK. Otherwise it will tell you what the problem is.
                    What is it; oHeaderUK() ? Method? Variable?

                    Comment

                    • Mumbles0
                      Junior Member
                      • Jan 2009
                      • 240

                      #610
                      oHeaderUK() is a function, described in Step 5.

                      Comment

                      • Ferbar11
                        Junior Member
                        • Apr 2011
                        • 6

                        #611
                        Originally posted by Mumbles0 View Post
                        oHeaderUK() is a function, described in Step 5.

                        Thanks for help me.

                        Comment

                        • Mumbles0
                          Junior Member
                          • Jan 2009
                          • 240

                          #612
                          Beating the throttle limit.

                          Monkeymagix,

                          Beating the throttle limit.

                          You have a scheme which attempts to deal with the call rate limits imposed by the free API. This scheme requires your computer’s clock to be synchronized to Betfair‘s.

                          It assumes that Betfair count the calls during a one minute time window and reset the counter at the end of each minute. I experimented with this, but my observations were inconsistent with this assumption. Exactly how Betfair determine the EXCEEDED_THROTTLE condition remains a mystery to me.

                          Sleeping the thread could freeze your app until the next minute commences. This may be OK for an unattended bot, but, in general, it may not be a sensible thing to do.

                          A more conservative strategy is to simply restrict your call rate using, say, a timer control, rather than firing off a barrage of calls and taking corrective action when the calls ultimately fail.

                          The contents of the program’s variables (including object references) should not be affected by the Thread.Sleep call. I don’t know what could be causing your problems here.

                          AFIK, the call count is done on a “user” basis, so you can’t “beat the throttle” by using multiple computers concurrently with the same Username.

                          BTW, as BigSprout has pointed out, getMarketPrices has a call limit of only 10/min, If you are running into throttle problems you would be better off calling getMarketPricesCompressed. This returns the same data but has a much higher call limit (60/min). See step 14.


                          Error: Index was outside the bounds of the array.

                          Sometime there is no money for a runner. In this case the .bestPricesToBack array (or .bestPricesToLay) will be empty. So you should always test the length of these arrays before you access any element. Do something like this (if you’ll pardon the VB):

                          Code:
                            With MpriceResp.marketPrices.runnerPrices(i)
                              If .bestPricesToBack.Length > 0 Then backPrice = .bestPricesToBack(0).price
                              If .bestPricesToLay.Length > 0 Then layPrice = .bestPricesToLay(0).price
                           End With
                          If you don’t do this you will get the error.
                          Last edited by Mumbles0; 20-04-2011, 12:02 PM.

                          Comment

                          • monkeymagix
                            Junior Member
                            • Jul 2010
                            • 105

                            #613
                            Throttle_limit

                            Cheers for replying Mumbles and BigSprout

                            I am already looking into compressed version of market prices but I would like to solve this issue as it is troubling me why my code loses all it's references after a call to my beat method.

                            My code is built as a windows service and is already using timers to initiate calls to my Bot at 30 second periods using a Timer object.

                            I will amend my code to check for the bestPrices length before accessing them to see if that fixes the problem but it does seem to happen ONLY after a THROTTLE LIMIT error so I am 99.99% sure the issue is down to that and I am wondering if there is some method I can call after a "Beat Throttle Limit" check to ensure all references are still available and if not re-gain them.

                            As for server time difference issues I have most certainly run into issues with this before. It would be nice to know how out of sync my server is with Betfair's so that I can add/subtract this to my calculations.

                            I know from my day job that our DEV and PRODUCTION servers are up to a minute out of sync and even on the PRODUCTION server our web and DB server are 10+ seconds out of sync which makes scanning log files looking for errors logged in the DB a right pain the XXX.

                            Thanks for your help!

                            Comment

                            • Ferbar11
                              Junior Member
                              • Apr 2011
                              • 6

                              #614
                              How can I place a bet with less than 2€?

                              Comment

                              • Ferbar11
                                Junior Member
                                • Apr 2011
                                • 6

                                #615
                                What is the best value for the purpose timer function with TabControl?

                                1000 ms?

                                Comment

                                Working...
                                X