Using VB2008 to acccess the Betfair API: A tutorial

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • ribogio7
    Junior Member
    • Apr 2010
    • 4

    #316
    Thanks a lot Mumbles0.

    Right Code is here.

    Code:
    Dim oGBHReq As New BFExchange.GetBetHistoryReq
            Dim oGBHResp As New BFExchange.GetBetHistoryResp
    
            With oGBHReq
                .header = oHeaderUK
                .placedDateFrom = Now.AddDays(-7)
                .placedDateTo = Now
                .startRecord = 0
                .recordCount = 30
                .betTypesIncluded = BFExchange.BetStatusEnum.S 
                ReDim .eventTypeIds(0) : .eventTypeIds(0) = 1 'For soccer
                ReDim .marketTypesIncluded(0) : .marketTypesIncluded(0) = BFExchange.MarketTypeEnum.O
                .sortBetsBy = BFExchange.BetsOrderByEnum.PLACED_DATE
            End With
    What's the difference between BFExchange.MarketTypeEnum.O,L,R,A...?

    ps: Keep up the good work Mumbles0.

    Comment

    • Mumbles0
      Junior Member
      • Jan 2009
      • 240

      #317
      Market types

      O, L, R, A refer to the different type of markets offered by Betfair (Odds, Line, Range & Asian handicap).

      Some info is given in the Betfair help here.

      Comment

      • waldjunge
        Junior Member
        • Apr 2009
        • 12

        #318
        BFUK.MarketStatusEnum.ACTIVE Error?

        I get sometimes a "Null reference exception Error" in the line 'If .marketPrices.marketStatus = BFUK.MarketStatusEnum.ACTIVE Then'
        Anybody knows why?


        Code:
          Sub findBestPrice4Betting(ByVal MpriceResp As BFUK.GetMarketPricesResp, ByVal horse2searchID As Integer, ByVal BackOrLay As String)
                Dim Back As String
        
                myFoundPrice = 0
                With MpriceResp
                    CheckHeader(.header)   'OK
                    'print6(TimeString & " Single Horse Price -> " & .errorCode)
                    If .marketPrices.marketStatus = BFUK.MarketStatusEnum.ACTIVE Then
                        If .errorCode = BFUK.GetMarketPricesErrorEnum.OK Then
                            With .marketPrices
                                For i = 0 To .runnerPrices.Length - 1

        Comment

        • Mumbles0
          Junior Member
          • Jan 2009
          • 240

          #319
          Null reference exception

          waldjunge,

          It look like you are getting an API error. If so, the response object property.marketPrices is not set (i.e. is set to Nothing). This causes the “Null Reference Exception”. You should always ensure that .errorCode = OK before accessing the .marketPrices object.

          To fix this, swap the two If statements over in your code:

          Code:
            If .errorCode = BFUK.GetMarketPricesErrorEnum.OK Then
             If .marketPrices.marketStatus = BFUK.MarketStatusEnum.ACTIVE Then
               With .marketPrices
                  .......
          If you look at the .errorCode in the response header you will see what's causing the API error.

          Comment

          • glenn1000
            Junior Member
            • Apr 2010
            • 1

            #320
            Hi there sorry to bother you but i am new here.
            the tuts where great thanks.has anyone got a piece of code to parse the compressed data for vb2008 or a quick breakdown of the info in the compressed code so i can try ?? to parse it myself.

            cheers glenn

            Comment

            • waldjunge
              Junior Member
              • Apr 2009
              • 12

              #321
              thanks a lot Mumbles0!

              Comment

              • waldjunge
                Junior Member
                • Apr 2009
                • 12

                #322
                I get the error message "Index our of Array" in line:

                With .bestPricesToLay(i)

                How big is the index of the array .bestPricesToLay(i) ? Is this index=number of runners? For example 12 runners -> .bestPricesToLay(12)
                Or is index=number of Odds? Means this index can have a maximum of 2 (0,1,2)-> .bestPricesToLay(2) ?

                So .bestPricesToLay(number of runners) is wrong?



                Code:
                 Sub findBestPrice4Betting(ByVal MpriceResp As BFUK.GetMarketPricesResp, ByVal horse2searchID As Integer, ByVal BackOrLay As String)
                        Dim Back As String
                        Dim indexI As Long = 0
                
                        myFoundPrice = 0
                        With MpriceResp
                            CheckHeader(.header)   'OK
                            'print6(TimeString & " Single Horse Price -> " & .errorCode)
                            '  
                            If .errorCode = BFUK.GetMarketPricesErrorEnum.OK Then
                                If .marketPrices.marketStatus = BFUK.MarketStatusEnum.ACTIVE Then
                                    With .marketPrices
                                        For i = 0 To .runnerPrices.Length - 1
                                            With .runnerPrices(i)
                                                horse2Find = .selectionId
                                                'print6(TimeString & " Find -> " & horse2searchID & " = " & .selectionId & "   ->" & .bestPricesToBack(0).price) '& " " & .bestPricesToBack(1).price)
                                                Back = ""
                                                '   For j = 0 To .bestPricesToBack.Length - 1
                                                If BackOrLay = "B" Then
                                                    With .bestPricesToBack(i)
                                                        If horse2Find = horse2searchID Then
                                                            einzelhorse(i)
                                                            If horseName2Bet = "ERROR" Then einzelhorse(i)
                                                            If horseName2Bet = "ERROR" Then einzelhorse(i)
                                                            myFoundPrice = .price
                                                            amountAvailableOnHorse = .amountAvailable
                                                        End If
                
                                                    End With
                                                End If
                                            End With
                                        Next i
                                    End With
                
                                    With .marketPrices
                                        For i = 0 To .runnerPrices.Length - 1
                                            With .runnerPrices(i)
                                                horse2Find = .selectionId
                                                If BackOrLay = "L" Then
                                                    With .bestPricesToLay(i)
                                                        If horse2Find = horse2searchID Then
                                                            einzelhorse(i)
                                                            If horseName2Bet = "ERROR" Then einzelhorse(i)
                                                            If horseName2Bet = "ERROR" Then einzelhorse(i)
                                                            myFoundPrice = .price
                                                            amountAvailableOnHorse = .amountAvailable
                                                        End If
                                                    End With
                                                End If
                                            End With
                                        Next i
                                    End With
                                End If
                            End If
                        End With
                    End Sub

                Comment

                • Mumbles0
                  Junior Member
                  • Jan 2009
                  • 240

                  #323
                  bestPrices arrays

                  Yes, bestPricesToLay(number of runners) is wrong.

                  The maximum length of the .bestPricesToBack and .bestPricesToLay arrays is 3, with the best price in element 0. These arrays hold the 3 best available prices for each runner. These prices are the same as those shown on the web page for the market.

                  Comment

                  • Mumbles0
                    Junior Member
                    • Jan 2009
                    • 240

                    #324
                    Reply to glen1000 (Re: Compressed responses)

                    The tutorial has covered parsing (unpacking) the compressed data responses for these calls:

                    Step 6 - getAllMarkets
                    Step 10 - getCompleteMarketPricesCompressed
                    Step 14 - getMarketPricesCompressed
                    Step 24 - getMarketTradedVolumeCompressed

                    The Sports API Guide provides details of the compressed data returned by each call.

                    Comment

                    • Monairda
                      Junior Member
                      • Jan 2009
                      • 32

                      #325
                      Processing data from more than 2 async calls.

                      Hi Mumbles

                      I'll follow this steps and works perfect!! Thanks

                      Originally posted by Mumbles0 View Post
                      Monairda,

                      Perhaps your problem is when to process the data from the 2 responses. This is what I do:
                      Define a call counter to count the responses, clear it, the send the 2 async requests:

                      Code:
                      [COLOR="Gray"]Private oMarketPrices As UnpackMarketPricesCompressed
                      Private oTradedVolume As UnpackMarketTradedVolumeCompressed
                      [COLOR="Black"]Private CallCount As Integer[/COLOR]
                      
                      Private Sub GetMarketData()    'Sub to send the requests
                        [COLOR="Black"]CallCount = 0  'Clear the call count
                        [I]Call getMarketPricesCompressedAsync (as per step 14)[/I]
                        [I]Call getMarketTradedVolumeCompressedAsync (as per step 24)[/I][/COLOR] 
                      End Sub[/COLOR]
                      The API now sends back the 2 responses. Problem is we don’t know which one comes back first, so we count them in the event handlers. When both responses have been received CallCount = 2, so now we call a sub to process the 2 unpacked data objects.

                      Code:
                      [COLOR="Gray"]Private Sub BetfairUK_getMarketPricesCompressedCompleted(ByVal sender As Object, ByVal e As BFUK.getMarketPricesCompressedCompletedEventArgs) Handles BetfairUK.getMarketPricesCompressedCompleted
                        .........
                        [I](Code similar to Step 14)[/I]
                        .........
                        If .errorCode = BFUK.GetMarketPricesErrorEnum.OK Then
                          oMarketPrices = New UnpackMarketPricesCompressed(.marketPrices)   'Unpack the market prices data
                          [COLOR="Black"]CallCount += 1    'Count this response
                          If CallCount = 2 Then BuildDataTable()   'Process responses when both received[/COLOR]
                        End If
                        .........
                        .........
                      End Sub
                      
                      Private Sub BetfairUK_getMarketTradedVolumeCompressedCompleted(ByVal sender As Object, ByVal e As BFUK.getMarketTradedVolumeCompressedCompletedEventArgs) Handles BetfairUK.getMarketTradedVolumeCompressedCompleted
                        ........
                        [I](Code similar to Step 24)[/I]
                        ........
                        If .errorCode = BFUK.GetMarketTradedVolumeCompressedErrorEnum.OK Then
                          oTradedVolume = New UnpackMarketTradedVolumeCompressed(.tradedVolume)  'Unpack the traded volume data
                          [COLOR="Black"]CallCount += 1  'Count this response
                          If CallCount = Ncalls Then BuildDataTable()  'Process responses when both received[/COLOR]
                        End If
                        .........
                        .........
                      End Sub
                      
                      [COLOR="Black"]Private Sub BuildDataTable()
                        [I]Builds a data table from data contained in oMarketPrices and oTradedVolume objects[/I]
                      End Sub[/COLOR][/COLOR]
                      Sub BuildDataTable is only called once, from the event handler which handles the second response (whichever that is). This ensures that both responses have arrived before output processing commences.
                      This is the BuildDataTable:

                      Code:
                      Private Sub BuildDatatable()
                              Dim TablaOddTradedVolumen As New DataTable
                              TablaOddTradedVolumen.Columns.Add("Marketid")
                              TablaOddTradedVolumen.Columns.Add("SelectionId")
                              TablaOddTradedVolumen.Columns.Add("OddBack")
                              TablaOddTradedVolumen.Columns.Add("OddLay")
                              TablaOddTradedVolumen.Columns.Add("LPM")
                              TablaOddTradedVolumen.Columns.Add("Vol")
                              TablaOddTradedVolumen.Columns.Add("AmountBack")
                              TablaOddTradedVolumen.Columns.Add("AmountLay")
                              TablaOddTradedVolumen.Columns.Add("TotalBack")
                              TablaOddTradedVolumen.Columns.Add("TotalLay")
                              
                      
                              Dim market As Integer
                              Dim ofila As DataRow
                              Dim seleccion As Integer
                              Dim back As Decimal
                              Dim totalback As Decimal
                              Dim totallay As Decimal
                              Dim totalvolumen As Decimal
                      
                              With oMarketPrices
                                  market = .marketId
                                  'Process returned market prices here.
                                  For i = 0 To .runnerPrices.Length - 1
                                      With .runnerPrices(i)
                                          ofila = TablaOddTradedVolumen.NewRow
                                          ofila("Marketid") = market
                                          ofila("SelectionId") = .selectionId
                                          ofila("Vol") = .totalAmountMatched
                                          ofila("lPM") = .lastPriceMatched
                                          ofila("Oddback") = .bestPricesToBack(0).price
                                          ofila("Amountback") = .bestPricesToBack(0).amountAvailable
                                          ofila("Oddlay") = .bestPricesToLay(0).price
                                          ofila("Amountlay") = .bestPricesToLay(0).amountAvailable
                                          TablaOddTradedVolumen.Rows.Add(ofila)
                                          seleccion = .selectionId.ToString
                                          back = .bestPricesToBack(0).price
                                          totalback = 0
                                          totallay = 0
                                          totalvolumen = 0
                                      End With
                                      [COLOR="red"]
                                      'I walk the object oTradedVolume for each object oMarket.
                                      'It's a bit slow but I have not found another way to do
                                      [/COLOR]
                                      With oTradedVolume  'Process the unpacked data
                                          For t = 0 To .RunnerVolume.Length - 1   'For each runner
                                              With .RunnerVolume(t)
                                                  
                                                  For j = 0 To .tradedVolume.Length - 1  'Print the table of odds and amounts matched
                                                      If seleccion = .selectionId Then
                                                          If back <= .tradedVolume(j).odds Then
                                                              totalback = totalback + .tradedVolume(j).totalMatchedAmount
                                                          Else
                                                              totallay = totallay + .tradedVolume(j).totalMatchedAmount
                                                          End If
                                                          totalvolumen = totalvolumen + .tradedVolume(j).totalMatchedAmount
                                                      End If
                      
                                                      
                                                  Next
                                                  ofila("totalback") = totalback
                                                  ofila("totallay") = totallay
                                                  
                                              End With
                                          Next
                                      End With
                                  Next
                              End With
                              gvPrices.DataSource = TablaOddTradedVolumen
                              gvPrices.Refresh()
                          End Sub

                      Do not know how to proceed to the next problem. The routine works perfectly to call a market and control the data of the two asynchronous calls. But how I can do to control the answers when applying for various markets and we have more than two async calls?


                      Thank you very much
                      Last edited by Monairda; 13-05-2010, 11:49 AM.

                      Comment

                      • Mumbles0
                        Junior Member
                        • Jan 2009
                        • 240

                        #326
                        Handling async calls for multiple markets

                        Monairda,

                        There are many ways to handle multiple markets. Here is an approach which uses a separate form for each market of interest using common async call handlers.

                        For this, add a new form to the project. Name it MarketForm. Add your DataGridView control (gvPrices), plus any other controls you may require for the market data. The code for this form is this:

                        Code:
                        Public Class MarketForm
                        
                          Friend MarketId As Integer     'The MarketId for this form
                          Friend CallCount As Integer    'The call counter
                          Private oMarketPrices As UnpackMarketPricesCompressed
                          Private oTradedVolume As UnpackMarketTradedVolumeCompressed
                        
                          Friend Sub MarketPricesReceived(ByVal _MarketPrices As UnpackMarketPricesCompressed)
                            oMarketPrices = _MarketPrices    'Save the unpacked market prices object
                            CallCount += 1                      'Count this response
                            If CallCount = 2 Then BuildDatatable() 'Process responses when both received
                          End Sub
                        
                          Friend Sub TradedVolumeReceived(ByVal _TradedVolume As UnpackMarketTradedVolumeCompressed)
                            oTradedVolume = _TradedVolume   'Save the unpacked traded volume object
                            CallCount += 1                     'Count this response
                            If CallCount = 2 Then BuildDatatable() 'Process responses when both received
                          End Sub
                        
                          Private Sub BuildDatatable()
                           [I]Builds a data table from data contained in oMarketPrices and oTradedVolume objects [/I]
                          End Sub
                        
                          Private Sub MarketForm_FormClosing(ByVal sender As Object, ByVal e As System.Windows.Forms.FormClosingEventArgs) Handles Me.FormClosing
                            MainForm.MyMarkets.Remove(MarketId.ToString)  'Remove this market from the collection
                          End Sub
                        
                        End Class
                        Your main form (which I’ve called MainForm) will have facilities to enter the markets you want.

                        Add the MyMarkets collection object and Sub ShowMarket to the MainForm code. For each market of interest you must call Sub ShowMarket with the MarketId.

                        Code:
                          
                        Public Class MainForm
                        
                          Friend MyMarkets As New Collection  'The markets of interest
                        
                          Private Sub ShowMarket(ByVal MarketId As Integer)
                            Dim Key As String = MarketId   'Use MarketId for the collection key
                        
                            If MyMarkets.Contains(Key) Then  'MarketForm exists for this market
                              MyMarkets(Key).BringToFront()  'Display it
                        
                            Else  'Create a new MarketForm for this market
                              Dim Market As New MarketForm   'The new form
                              With Market
                                .MarketId = MarketId    'Assign the MarketId
                                .Text = "Market " & MarketId   'Set the caption
                                .Show()    'Show the new MarketForm
                        
                                [I]Other MarketForm initialization if required[/I]
                        
                              End With
                              MyMarkets.Add(Market, Key)  'Add this form to the collection
                        
                            End If
                          End Sub
                        
                        
                          [I]Other code on the main form
                          ............
                          ............[/I]
                        
                        End Class
                        When ShowMarket is called with a new MarketId, a new form is launched, so you will have a separate MarketForm for each market. The MyMarkets collection object keeps track of the markets and holds a list of the MarketForms currently open. If you close a MarketForm, its reference is removed from the collection (by the FormClosing event handler).

                        Test this to make sure it works OK, then add the code to call the API. (Put this code in MainForm.)

                        Code:
                        Private Sub GetMarketData()
                            Dim Market As MarketForm
                        
                            For Each Market In MyMarkets
                        
                              Market.CallCount = 0  'Clear the call counter
                        
                              Dim oMPCreq As New BFUK.GetMarketPricesCompressedReq
                              With oMPCreq
                                .header = oHeaderUK()
                                .marketId = Market.MarketId   
                              End With
                              StateCount += 1
                              BetfairUK.getMarketPricesCompressedAsync(oMPCreq, StateCount)  'Call the API
                        
                              Dim oMTVCReq As New BFUK.GetMarketTradedVolumeCompressedReq      'The request object
                              With oMTVCReq
                                .header = oHeaderUK()
                                .marketId = Market.MarketId      
                              End With
                              StateCount += 1
                              BetfairUK.getMarketTradedVolumeCompressedAsync(oMTVCReq, StateCount)    'Call the API
                        
                            Next
                        
                          End Sub
                        
                          Private Sub BetfairUK_getMarketPricesCompressedCompleted(ByVal sender As Object, ByVal e As BFUK.getMarketPricesCompressedCompletedEventArgs) Handles BetfairUK.getMarketPricesCompressedCompleted
                            Try
                              If Not e.Cancelled Then
                                With e.Result
                                  CheckHeader(.header)
                                  If .errorCode = BFUK.GetMarketPricesErrorEnum.OK Then
                        
                                    Dim oMarketPrices As New UnpackMarketPricesCompressed(.marketPrices)  'Unpack the prices
                                    Dim Key As String = oMarketPrices.marketId    'The key for this market
                                    If MyMarkets.Contains(Key) Then                'The MarketForm is open
                                      Dim Market As MarketForm = MyMarkets(Key)     'A reference to the form for this market
                                      Market.MarketPricesReceived(oMarketPrices)   'Process the prices response
                                    End If
                        
                                  Else
                                    Print("ErrorCode = " & .errorCode.ToString)
                                  End If
                                End With
                              End If
                            Catch ex As ApplicationException
                              Print(ex.Message)
                            End Try
                        
                          End Sub
                        
                          Private Sub BetfairUK_getMarketTradedVolumeCompressedCompleted(ByVal sender As Object, ByVal e As BFUK.getMarketTradedVolumeCompressedCompletedEventArgs) Handles BetfairUK.getMarketTradedVolumeCompressedCompleted
                            Try
                              If Not e.Cancelled Then
                                With e.Result
                                  CheckHeader(.header)
                                  If .errorCode = BFUK.GetMarketTradedVolumeCompressedErrorEnum.OK Then
                        
                                    Dim oTradedVolume As New UnpackMarketTradedVolumeCompressed(.tradedVolume)  'Unpack the traded volumes
                                    Dim Key As String = .marketId           'The key for this market
                                    If MyMarkets.Contains(Key) Then            'The MarketForm is open
                                      Dim Market As MarketForm = MyMarkets(Key)   'A reference to the form for this market
                                      Market.TradedVolumeReceived(oTradedVolume)  'Process the volume response
                                    End If 
                                   
                                  Else
                                    Print("ErrorCode = " & .errorCode.ToString)
                                  End If
                                End With
                              End If
                            Catch ex As ApplicationException  'If problem
                              Print(ex.Message)
                            End Try
                        
                          End Sub
                        Sub GetMarketData would typically be called from a Timer Tick event at regular intervals.

                        As before, it clears the call counter, then makes async calls to getMarketPricesCompressed and getMarketTradedVolumeCompressed, but this process is now in a For Each... loop and is executed for each MarketForm in the collection. Note that we now have a separate call counter for each market.

                        The responses can be returned by the API in any order. The handlers check the integrity of each response and, if OK, unpack the data. By looking at the MarketId parameter in the received data, the handlers determine which MarketForm the data is intended for and call the appropriate MarketPricesReceived or TradedVolumeReceived methods. As before, these methods use CallCount to ensure that the Sub BuildDataTable is only called after both responses have been received for this market.
                        Last edited by Mumbles0; 17-05-2010, 02:08 AM. Reason: Code revision

                        Comment

                        • Monairda
                          Junior Member
                          • Jan 2009
                          • 32

                          #327
                          Thank you very much Mumbles0.
                          I'll try it!!
                          Last edited by Monairda; 17-05-2010, 03:59 PM.

                          Comment

                          • Monairda
                            Junior Member
                            • Jan 2009
                            • 32

                            #328
                            Hello Mumbles0

                            Thank you very much for being our source of wisdom.
                            The solution works perfectly!!

                            Comment

                            • waldjunge
                              Junior Member
                              • Apr 2009
                              • 12

                              #329
                              I get a "TargetInvocation Exception" error when running this code. I think it has something to do with StateCount. The declaration should be an object, but it is an Integer!?

                              Any idea?
                              Thanks, Martin


                              Code:
                               
                              Private StateCount As Integer    'The unique state object
                              
                              Private Sub bGetMPricesComp_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ccc.Click
                                      'Print("*** MarketPricesCompressed ****")
                              
                                      Dim oMPCreq As New BFUK.GetMarketPricesCompressedReq
                              
                                      With oMPCreq
                                          .header = oHeaderUK()
                                          .marketId = 101431014   'an active market ID
                                      End With
                                      StateCount += 1
                                      BetFairUK.getMarketPricesCompressedAsync(oMPCreq, StateCount) 'Call the API
                                  End Sub

                              Comment

                              • Mumbles0
                                Junior Member
                                • Jan 2009
                                • 240

                                #330
                                User state object

                                waldjunge,

                                The code you've shown that calls getMarketPricesCompressedAsync is as per Step 14. There is nothing wrong with this. If you are getting an exception it must be caused by something else.

                                It's OK to use an integer (or any other data type) where an argument of type object is required.

                                Here we use the incrementing StateCount integer variable to provide a simple unique UserState object that .NET requires if there is more than one outstanding (concurrent) async request.

                                The UserState parameter can be any object you like, provided it is unique (whatever that means - it is not clearly stated in the documentation). This object comes back to you in the response and can be used for your convenience, for example to identify the request that initiated the response.

                                Comment

                                Working...
                                X