Using VB2008 to acccess the Betfair API: A tutorial

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • hughmac
    Junior Member
    • Apr 2009
    • 2

    #91
    Re: Betfair.BFUK.APIResponseHeader

    Doh! thx mumbles....knew it had to my code .......assumed that these steps had been downloaded hundreds of times and any bugs would have been ironed out a long time ago!

    ah well...time for another eye test

    Comment

    • Drifter
      Junior Member
      • Mar 2009
      • 30

      #92
      Type conversion issue

      Mumbles,

      The line:
      Dim NonRunners = New UnpackRemovedRunners(.removedRunners) 'Unpack the removed runners

      is throwing up the following error for me-

      Error 1 Value of type '1-dimensional array of BasicApp_VBA.Unpack2.RemovedRunnerType' cannot be converted to 'String'.

      Can't see why it should be - i cross checked all the types you have in Unpack2 and they seem to match up OK.

      Not at all sure why this should be happening.

      Comment

      • Mumbles0
        Junior Member
        • Jan 2009
        • 240

        #93
        Reply to Drifter (re: NonRunners)

        I think your problem arises because the name removedRunners is used (perhaps unwisely) for two different purposes. In class UnpackMarketPricesCompressed it is a string containing the packed removed runner data (inherited from class BFUK.MarketPrices), while in class UnpackRemovedRunners it is an array of RemovedRunnerType. Sub New in class UnpackRemovedRunners expects a string parameter, but for some reason you are calling it with an array of RemovedRunnerType, hence the error.

        Check the line where the oMarketPrices object is created. Make sure it is as shown below. Also ensure that the offending line is enclosed within the With oMarketPrices ..... End With bracket

        Code:
        Dim oMarketPrices As New UnpackMarketPricesCompressed(.marketPrices)
        With oMarketPrices
          .........
        
          Dim NonRunners = New UnpackRemovedRunners(.removedRunners)   'Unpack the removed runners
          .........
        
        End With
        If you don’t have any luck with this, post more code so we can have a closer look.

        -------------------------------------------------

        I don’t think that the following has anything to do with your error but, while we are here, note that I’ve changed "=" to "As" in the step 16 code so that this line now becomes:

        Code:
        Dim NonRunners As New UnpackRemovedRunners(.removedRunners)   'Unpack the removed runners
        Even though both ways are acceptable, I think it might be “more correct” to use "As". (Also this is more consistent with what I’ve used elsewhere.)
        Last edited by Mumbles0; 27-04-2009, 03:52 AM.

        Comment

        • winning_streak
          Junior Member
          • Apr 2009
          • 4

          #94
          Problems with event ids

          Hi Mumbles

          Firstly thanks for this great tutorial. It's basically allowed me to get my own bot up and running.

          With that said for some reason today the getAllMarkets function isn't working for some event ids?

          Yesterday it worked fine but today things like the soccer, soccer fixtures, todays card horse racing etc. are returning 0 records. Some others are OK.

          I used the code in your examples and as I said the test application ran fine up until today.

          Any body else noticed this problem today. Any solutions?

          Thanks again Mumbles

          WS
          Last edited by winning_streak; 27-04-2009, 11:23 PM.

          Comment

          • winning_streak
            Junior Member
            • Apr 2009
            • 4

            #95
            Here's what the sub looks like as I have it. It's taken straight from the tutorial and was working fine 2 days ago but now some of the markets don't return results (1,14 etc.)

            Code:
                Private Sub bMarkets_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles bMarkets.Click
                    Print("*** Markets ***")
                    Dim oMarketsReq As New BFUK.GetAllMarketsReq
                    Dim oMarketsResp As New BFUK.GetAllMarketsResp
                    With oMarketsReq
                        .header = oHeaderUK()
                        ReDim .eventTypeIds(0) : .eventTypeIds(0) = 14' 1 for Soccer fixtures, 7 For horse racing
                        ReDim .countries(1) : .countries(0) = "GBR" : .countries(1) = "ZAF"
                        .fromDate = Today
                        .toDate = Today.AddDays(1)
                    End With
                    oMarketsResp = BetFairUK.getAllMarkets(oMarketsReq)  'Call the UK API
                    With oMarketsResp
                        CheckHeader(.header)
                        Print("ErrorCode = " & .errorCode.ToString)
                        If .errorCode = BFUK.GetAllMarketsErrorEnum.OK Then
                            Dim AllMarkets As New UnpackAllMarkets(.marketData)   'Create an object and unpack the string
                            With AllMarkets
                                For i = 0 To .marketData.Length - 1
                                    With .marketData(i)
                                        Print(.marketId & " " & .marketStatus & "  " & .marketName & "  " & .menuPath)
                                    End With
                                Next
                            End With
                        End If
                    End With
            
                End Sub
            Is nobody else having problems with this?

            Thanks

            WS

            Comment

            • Mumbles0
              Junior Member
              • Jan 2009
              • 240

              #96
              Reply to winning_streak (re: getAllMarkets)

              I can’t see anything wrong with your code. Note that eventTypeId = 13 (Horse racing - Todays card) doesn’t work on the UK exchange. Perhaps your date limits aren't wide enough. The “time window” specified by fromDate and toDate might require some clarification. This can be a bit confusing, particularly if you are calling from another time zone. This code:

              Code:
              .fromDate = Today 
              .toDate = Today.AddDays(1)
              does not mean “today and tomorrow”. It means “from now until midnight tonight” (your local time). For example, if you are calling from UK, Today sends the date string "2009-04-28T00:00:00+00:00" which represents the instant just after midnight this morning, while Today.AddDays(1) sends the date string "2009-04-29T00:00:00+00:00" which represents the instant just after midnight tomorrow morning. If you call the API at, say, 10pm (UK time) it is unlikely that any UK soccer matches will commence in the next 2 hours, hence getAllMarkets does not return any markets in this case.

              Alternatively you could use:

              Code:
              .fromDate = Today
              .toDate = Today.AddDays(2)
              This means “the remainder of today and all of tomorrow”, or:

              Code:
              .fromDate = Now
              .toDate = Now.AddDays(1)
              specifies the next 24-hour period. You can use date literals:

              Code:
              .fromDate = #4/28/2009#   'Start of 28 April 2009
              .toDate = #5/2/2009#      'Start of 2 May 2009
              or any DateTime expression. For more info refer here.

              Having said all this, I too am puzzled by what comes back from getAllMarkets. Today when I used eventTypeId = 14 (Soccer - Fixtures) nothing was returned. However several markets are returned with “Fixtures” in the menuPath when I use eventTypeId = 1 (Soccer). Also, if I search for markets by making successive calls to getEvents starting with .eventParentId = 14, I get these markets. It look like getAllMarkets doesn’t work with eventTypeId = 14.

              So the question is: does getAllMarkets return anything for eventTypeId = 14 ? Perhaps someone could help us with this.
              Last edited by Mumbles0; 05-05-2009, 12:17 PM. Reason: Correction

              Comment

              • willyray1
                Junior Member
                • Apr 2009
                • 9

                #97
                Originally posted by Mumbles0 View Post
                So the question is: does getAllMarkets return anything for eventTypeId = 14 ? Perhaps someone could help us with this.
                I don't think 14 returns anything either. This relates to my first few posts in that you can populate all the events first into the marketview, then drill down when clicking on the tree nodes. Events shows fixtures in their own node.

                If I load all the events into the treeview, then load all the markets into the events, the only things that aren't populated further are:
                Australian Rules
                Greyhound - Todays Card
                Horse Racing - Todays Card
                Netball
                Soccer - Fixtures
                Last edited by willyray1; 28-04-2009, 07:45 AM.

                Comment

                • winning_streak
                  Junior Member
                  • Apr 2009
                  • 4

                  #98
                  Thanks for trying to help guys

                  This is turning into a real head scratcher. I've been on it for the past couple of days with no luck. I've emailed BDP support so hopefully they can shed some light on this issue. I'm suprised nobody has ever flagged this before.

                  If I hear back from them I'll update this post.

                  Thanks

                  WS

                  Comment

                  • winning_streak
                    Junior Member
                    • Apr 2009
                    • 4

                    #99
                    Ok so I got a reply back from Neil and that coupled with Mumbles advice about time selection has cracked it!

                    Here's what Neil said...

                    The eventtypeId's 13 (Horse Racing - Today's Card), 14 (Soccer - Fixtures), 15 (Greyhound - Today Cards) are special cases used to display each set of data via the Betfair website.
                    All of these eventTypeIds belong to a specific parent eventTypeId (i.e. 1, 7 and 4339) and are not returned by getAllMarkets.
                    I also adjusted my time selection to be ...

                    Code:
                                .fromDate = Now
                                .toDate = Now.AddDays(1)
                    and bingo! I solved it.

                    Hopefully that will help anybody else who runs into the same problems.

                    Regards

                    WS

                    EDIT: Spoke to soon Using eventid 1 and the revised from and to dates only returns a small portion of the total events. Not sure why. I've got another support request in with Neil at BDP.

                    EDIT2: Just heard back from Neil and it seems it was the fact that I was limiting the results to GBP and ZAF as per Mumbles instructions meant that only GBP games were being returned. Once I commented out the line that sets the countries I got all the games for today.

                    Mumbles - You said a few pages ago you would show an example of placing a bet. I'm trying to write that now and think I've got it all correct but no bet seems to be placed. I'm setting up the request etc. then checking the response but the bit I think I'm missing is where you assign the request to the response. I've looked through the API documentation and I can't see anlything obvious.

                    Looking forward to you 'Placing A Bet' tutorial
                    Last edited by winning_streak; 28-04-2009, 01:09 PM.

                    Comment

                    • willyray1
                      Junior Member
                      • Apr 2009
                      • 9

                      #100
                      Could tweak the Populate Treeview code:

                      Just need to load all events into the treeview, then load the markets, then
                      something like If InStr(.menuPath, "Fixtures")... to add the node to the 13, 14 and 15 parents.

                      I already use the following to add times to horses and greyhound races:
                      Code:
                      If Ids(1) = 7 Or Ids(1) = 4339 Then 'Horse Racing and Greyhounds, add the time to the event[INDENT] Node.Text = If(j <= UBound(Names), Names(j), Format(.eventDate, "HH:mm") & " " & .marketName)
                      [/INDENT][INDENT][INDENT] Else
                      [/INDENT][/INDENT][INDENT] Node.Text = If(j <= UBound(Names), Names(j), .marketName)
                      [/INDENT]End If
                      and hours to ensure I get 24 hours worth of markets everytime:
                      Code:
                      .fromDate = Now
                      .toDate = Now.AddHours(24)

                      Comment

                      • Drifter
                        Junior Member
                        • Mar 2009
                        • 30

                        #101
                        re: type error

                        It was because I tried to apply the change for the newly globalised oMarketPrices for the sub BetFairUK_getMarketPricesCompressedCompleted instead of the sub BetFairUK_getCompleteMarketPricesCompressedComplet ed.

                        But why would this throw up an error? Surely if oMarketPrices is global it would need to be the same type be the same in both subs. So it seems that oMarketPrices is not the same object / type in both places; correct?

                        OK, if that is the case, I understand then why I got a type mismatch. But what appears to have happened is that the scope of oMarketPrices has been widened to global, but the compiler doesn't object to there being an identically named variable in scope which is being re-defined and with a different type. Isn't there some unnecessary confusion here?
                        Last edited by Drifter; 01-05-2009, 01:44 PM. Reason: Tidying up, rather than start a new post

                        Comment

                        • Mumbles0
                          Junior Member
                          • Jan 2009
                          • 240

                          #102
                          Reply to Drifter (re: oMarketPrices)

                          Yes. In Sub BetFairUK_getCompleteMarketPricesCompressedComplet ed, the object variable oMarketPrices is of type UnpackCompleteMarketPricesCompressed. (This is the variable that was globalized by Dodgee.)

                          But in Sub BetFairUK_getMarketPricesCompressedCompleted we declare (with the Dim statement) another variable called oMarketPrices which is of type UnpackMarketPricesCompressed. Even though it has the same name, it is a completely different variable! This is termed a local variable because it is known only within this Sub.

                          If you attempt to assign the new object to an existing global oMarketPrices variable you get errors because it is a different type. So you must define another variable with a different name if you require global access to this object too. For example:

                          Code:
                          Private oCompleteMarketPrices As UnpackCompleteMarketPricesCompressed
                          Private oMarketPrices As UnpackMarketPricesCompressed
                          
                          Private Sub BetFairUK_getCompleteMarketPricesCompressedCompleted
                            ..........
                          
                            oCompleteMarketPrices = New UnpackCompleteMarketPricesCompressed(.completeMarketPrices)
                            ..........
                          End Sub
                          
                          Private Sub BetFairUK_getMarketPricesCompressedCompleted
                            ..........
                          
                            oMarketPrices = New UnpackMarketPricesCompressed(.marketPrices)
                            ..........
                          End Sub
                          Speaking generally, using the same name for different things can be confusing, but it is quite within the rules (unlike some older languages that you may be familiar with). The compiler sorts similarly-named entities out using the rules of context and scope.

                          Comment

                          • Mumbles0
                            Junior Member
                            • Jan 2009
                            • 240

                            #103
                            Step 17. Sorting Runner Info Arrays.

                            As mentioned in step 12, it may be advantageous to sort the arrays of runner data returned from calls such as getMarketPricesCompressed and getCompleteMarketPricesCompressed to ensure that the order of this runner data corresponds to the list of runners returned from the getMarket call for the same market. getMarket returns the list in “official Betfair order” as shown on the website. They often line up, but you cannot assume that this is always the case.

                            For this exercise we will sort the .runnerInfo array returned in the UnpackCompleteMarketPricesCompressed object we constructed in Step 10 according to the value of the .sortOrder property. Rather than write code to do this, .NET has a convenient Array.Sort method we can use.

                            If we had an array (say, Numbers) containing integer values, we could sort this simply by writing Array.Sort(Numbers). But each element of the .runnerInfo array contains an object of RunnerInfoType. How do we sort this? We must somehow tell the sort method the basis on which we want the sort to proceed. We do this by creating a class containing the comparison method we want Array.Sort to use.

                            Add this class to the existing UnPack2 module of the Betfair tester:

                            Code:
                            Class CompareRunnerInfo  'A class to provide the comparison method for the RunnerInfo array sort
                              Implements IComparer(Of RunnerInfoType)
                              Public Function Compare(ByVal x As RunnerInfoType, ByVal y As RunnerInfoType) As Integer Implements System.Collections.Generic.IComparer(Of RunnerInfoType).Compare
                                Return x.sortOrder - y.sortOrder   'To sort according to OrderIndex
                              End Function
                            End Class
                            I suggest that you type this in (rather than use copy/paste). As you type you will notice that VB2008 completes most of the code for you. All you have to do is complete Function Compare. Note the Implements statement. Here IComparer is called an “Interface” . IComparer is defined within .NET and its job is to ensure that this class includes the Compare method exactly as required by Array.Sort. When running, Array.Sort calls this method to compare two array elements (x and y). Compare returns a simple integer value: negative if element x is considered to be less than element y, positive if x is greater than y, and zero if x and y are the same for the purpose of the sort. Because we use the .sortOrder property to compute the return value, the array elements will be sorted according to their .sortOrder values.

                            To test this select the TestForm code. Locate this existing sub and add another line after the ‘Process returned market prices here’ comment:

                            Code:
                            [COLOR="Gray"]Private Sub BetFairUK_getCompleteMarketPricesCompressedCompleted( ........)
                              Try
                                ..........
                                  ..........
                                    ..........
                                
                                      oMarketPrices = New UnpackCompleteMarketPricesCompressed(.completeMarketPrices)
                                      With oMarketPrices
                                        Print(.marketId & "  " & .runnerInfo.Length & " runners")
                                        'Process returned market prices here.
                                        [COLOR="Black"]Array.Sort(.runnerInfo, New CompareRunnerInfo)   'Sort according to .sortOrder value[/COLOR]
                                        For i = 0 To .runnerInfo.Length - 1
                                          With .runnerInfo(i)
                                            Print(.sortOrder & " " & .selectionId & " " & .totalAmountMatched & " " & .lastPriceMatched)
                                          End With
                                        Next
                                      End With
                                    ..........
                                  ..........
                                ..........        
                               
                            End Sub[/COLOR]
                            Here the sort is performed in a single statement. To specify how we want the sort to be performed we simply pass a new instance of our CompareRunnerInfo class into the Array.Sort method. Because this class implements the IComparer interface, compatibility is ensured.

                            Now when we click the “MarketPrices” button a sorted list of runner data should print. If you wish, comment out the Array.Sort statement to observe the unsorted data.

                            This step demonstrates how to sort an array of objects any way we choose using the inbuilt Array.Sort method and the IComparer interface. It also introduces the Interface entity.

                            Comment

                            • TIP102
                              Junior Member
                              • Apr 2009
                              • 3

                              #104
                              Sava data to database

                              Hi,

                              First of all thank you for this great tutorial on how to use Betfair API with VB. I am a complete newbie and you helped me a lot!

                              I managed to get data from getMarketPrices but I would like to save data in some way.

                              How to save data that I get with getMarketPrices to database MS SQL Express?

                              Best regards!

                              Comment

                              • Tam's Loup
                                Junior Member
                                • Jan 2009
                                • 4

                                #105
                                The way I do it is to create an ODBC connection to a database.
                                Control Panel -> Administrative Tools -> Data Sources (ODBC)
                                In my case it is Microsoft Access, but I'm sure it would be the same with any kind of database. It will require some knowledge of SQL though.

                                Then in my code, I set up the connection as follows:

                                db = New ADODB.Connection
                                db.Open("myDB", "myUser", "myPassword")

                                Then I build a SQL statement to insert data.

                                dim strSQL as string

                                strSQL = "INSERT INTO myTable (myCol1, myCol2) VALUES (1, 'Two')"
                                'and then execute the SQL
                                db.Execute(strSQL)

                                However, in real life, the SQL statement is more likely to include values held in variables, so the statement would need to be built using them. For example:

                                dim myNumber as integer
                                dim myString as string
                                myNumber = 1
                                myString = "Two"
                                strSQL = "INSERT INTO myTable (myCol1, myCol2) VALUES ("
                                strSQL = strSQL & myNumber & ", '" & myString & "')"

                                You can check your syntax by displaying the SQL string.
                                msgbox strSQL

                                Comment

                                Working...
                                X