Using VB2008 to acccess the Betfair API: A tutorial

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • waynebrayn
    Junior Member
    • Feb 2010
    • 7

    #331
    Hello Mumbles,

    Thanks for creating this excellent thread and tutorial. Using the guidance provided I have written a (working!) program to find my markets of interest, make selections and place bets, all with very little previous programming experience (I'm good with Excel macros etc, but that's it).

    As my skills are limited my program could certainly be improved. One area I would like to learn more about is how to use arrays to place more than one bet at a time. Following the tutorial has led to my bets being placed one at a time i.e. place bet, wait for response, place next bet etc. This works OK but is not optimum and is sometimes slow.

    Is there any information you can share that will help, or can you point me in the direction of a good source of knowledge about using arrays in Visual Basic?

    Thanks in advance.

    Wayne

    Comment

    • Mumbles0
      Junior Member
      • Jan 2009
      • 240

      #332
      waynebrayn,

      Thanks for your post.

      For the benefit of those, like yourself, who are new to programming (or at least new to Visual Basic programming) I am preparing some steps reviewing array fundamentals and object references. We will then look at placing multiple bets using placeBets.

      M0.

      Comment

      • waynebrayn
        Junior Member
        • Feb 2010
        • 7

        #333
        Mumbles,

        Thanks for your response, I'm looking forward to the learning!

        Regards,

        Wayne

        Comment

        • Mumbles0
          Junior Member
          • Jan 2009
          • 240

          #334
          Step 26. Array fundamentals

          For the benefit of those who are new to programming, a review of array fundamentals is worthwhile.
          Here are some of my ideas on the subject.

          I like to think of a variable as a box with a name, in which you can place something.
          We can define a simple integer variable, named Mike, with a Dim statement:
          Dim Mike As Integer

          This gives us a box, named Mike, located somewhere in memory, which looks like this:
          Code:
                       ________
                Mike  |[U]      0 [/U]|
          Note that the box contains the value zero. This is the default value for type Integer.
          We can put another value in the box with an assignment statement:
          Mike = 274

          This places the value 274 in the box which now looks like this:
          Code:
                       ________
                Mike  |[U]    274 [/U]|
          Thus our simple variable holds a single value. We can extend this concept to an array.
          Think of an array as a "multi-level" box with a name, in which you can place several things.
          We can define a simple integer array, named Jack, again with a Dim statement:
          Dim Jack(3) As Integer

          This creates a multi-level box, named Jack, located somewhere in memory which looks like this:
          Code:
                        ________
               Jack  0 |[U]      0 [/U]|
                     1 |[U]      0 [/U]|
                     2 |[U]      0 [/U]|
                     3 |[U]      0 [/U]|
          Each element ("level") is referred to by a number called the index. For example, the 2nd element is Jack(1). The elements are numbered consecutively, always starting at 0.

          For this array the highest-numbered index (3) is called the upper bound. The length of the array is 4. The upper bound is always one less than the length.

          Because, in this case, we have an array of Integer, all elements are initialized to 0.

          We can assign a set of values to the array with a series of assignment statements:
          Jack(0) = 572
          Jack(1) = 820
          Jack(2) = 123
          Jack(3) = 707

          The array now becomes:
          Code:
                        ________
               Jack  0 |[U]    572 [/U]|
                     1 |[U]    820 [/U]|
                     2 |[U]    123 [/U]|
                     3 |[U]    707 [/U]|
          To iterate (scan) the array a For..Next loop is commonly used:
          Code:
              For i = 0 To Jack.Length - 1
                Print(Jack(i))
              Next
          The array Jack is actually a type of object. We use its Length property here. The loop prints the entire set of values held by the array:
          572
          820
          123
          707

          Alternatively, you can use the Ubound (upper bound) function:
          Code:
              For i = 0 To UBound(Jack)
                Print(Jack(i))
              Next
          This gives the same result and demonstrates how VB often has many ways of doing the same thing. This is particularly true for setting up arrays. We could have defined and initialized the array in a single statement like this:
          Dim Jack As Integer() = {572, 820, 123, 707}

          or like this:
          Dim Jack() As Integer = {572, 820, 123, 707}

          or like this:
          Dim Jack As Array = New Integer() {572, 820, 123, 707}

          I’m sure there are other ways too.

          Arrays in .NET are said to be dynamic. This means that the length of an array can be varied by a program while it executes. For example, the length of Jack is currently 4. We can increase this to 7 using a Redim statement, specifying a new upper bound (6):
          ReDim Jack(6)

          The array now becomes:
          Code:
                        ________
               Jack  0 |[U]      0[/U] |
                     1 |[U]      0 [/U]|
                     2 |[U]      0 [/U]|
                     3 |[U]      0 [/U]|
                     4 |[U]      0 [/U]|
                     5 |[U]      0 [/U]|
                     6 |[U]      0 [/U]|
          with all elements reset to zero. If we had used instead:
          ReDim Preserve Jack(6)

          we would have retained the original values and added 3 new elements:
          Code:
                        _________
               Jack  0 |[U]    572 [/U]|
                     1 |[U]    820 [/U]|
                     2 |[U]    123 [/U]|
                     3 |[U]    707 [/U]|
                     4 |[U]      0 [/U]|
                     5 |[U]      0 [/U]|
                     6 |[U]      0 [/U]|

          You may see an array declaration without an upper bound specified or any initial values:
          Dim Jack As Integer()

          This simply defines a variable, named Jack, to hold an array of type Integer. It does not create the array. A subsequent Redim statement (or similar) must be used to create the array before it can be accessed. If you don’t do this you will get the dreaded "Null Reference Exception (object reference not set to an instance of an object)" if you attempt to access any property or element of the array.

          This may sound a bit strange but sometimes you require a zero-length array. The variable Jack that we’ve just defined contains Nothing. This is not a zero-length array, it is Nothing. You define a zero-length array with the Redim statement:
          ReDim Jack(-1)

          Alternatively, you can declare:
          Dim Jack As Integer() = {}

          to create a zero-length array.


          Arrays of Objects.

          Arrays can be used to hold objects. To demonstrate this we’ll define a simple class:

          Code:
            
              Class Giraffe
                Public Height As Single = 4.3  'Height in metres
                Public Spots As Integer = 470  'Number of spots
              End Class
          Now create an array, named Field, of type Giraffe, 4 elements long (i.e. upper bound = 3) with these statements:
          Dim Field As Giraffe()
          ReDim Field(3)


          This creates an array which is simply a multi-level box capable of holding 4 objects of type Giraffe:
          Code:
                        ________
              Field  0 |________|
                     1 |________|
                     2 |________|
                     3 |________|
          Note that the array is now completely empty. There are no Giraffe objects in it, each element contains Nothing. If you attempt to access an object in an element you will get the "Null Reference Exception (object reference not set to an instance of an object)". So we must now load the array with Giraffe objects. We can do this with a simple loop:

          Code:
            For i = 0 To UBound(Field)
              Field(i) = New Giraffe
            Next
          The Field array now contains four Giraffe objects:
          Code:
                        _________
              Field  0 |[U] Giraffe [/U]|
                     1 |[U] Giraffe [/U]|
                     2 |[U] Giraffe [/U]|
                     3 |[U] Giraffe [/U]|
          We can access the members of the individual objects using the corresponding array element reference, for example:
          Code:
              Field(0).Spots = 523         'Spots on the 1st giraffe
              Print(Field(2).Height)       'Height of the 3rd giraffe
          In general, the ideas that I've described for the simple integer array also apply to arrays containing objects. The main thing to remember is that you must assign an object to each element of an array before it is accessed.

          That, I hope, covers the fundamentals. I will discuss more about object variables and arrays in the next step.


          Further reading.

          The MSDN section Arrays in Visual Basic (and the Related Topics) is worthwhile reading.

          The main reference is ArrayClass (and Array Members). This defines all the members of the Array class. Here you will find many methods which perform array operations such as Array.Sort (which was discussed in Step 17).

          There are also several classes derived from Array, such as ArrayList, List, Dictionary, Queue and Stack. From theses classes you can construct useful array-based objects.

          In this step I have discussed single-dimensioned arrays only. I have not mentioned multi-dimensioned arrays because the API does not use them and “to keep things simple”. There are many articles on these and other types of arrays available on the internet.

          An internet search on “Visual Basic Arrays” will list many articles on this interesting subject. Some relate to VB6. I suggest you don’t read these because arrays in VB6 behave differently to arrays in VB.NET. Read only the items relating to VB.NET (VB2005, VB2008 & VB2010).

          Comment

          • Mumbles0
            Junior Member
            • Jan 2009
            • 240

            #335
            Step 27. Understanding Object References

            If you are new to Object Oriented Programming (OOP) this Step should interest you.

            When I first started programming with objects things didn‘t always go smoothly. Although I had a fair understanding of classes (at least simple ones), often when I tried to use objects made from these classes my program would behave unexpectedly and frequently crashed with "Null Reference Exception (object reference not set to an instance of an object)". I also had difficulty knowing when to use, or not to use, the New keyword. After a while I realised that the cause of my problems was because I did not properly understand how objects are stored in memory. When I learnt more about this my programming improved.

            Here’s a simple quiz.
            Consider this code snippet involving 2 integer variables x and y:

            Code:
             Dim x, y As Integer
              y = x
              x = 3
              y = 7
              Print(x)
            Question: what is printed? Obviously the answer is 3.
            Now let’s introduce a simple class Var with an integer Value property:

            Code:
              Class Var
                Public Value As Integer
              End Class
            Now consider this code snippet involving 2 object variables x and y of type Var

            Code:
              Dim x, y As Var
              x = New Var
              y = x
              x.Value = 3
              y.Value = 7
              Print(x.Value)
            Again, what is printed? If you answered 3, read on...

            The correct answer is 7. The reason is because x and y refer to the same object.
            Let’s look at this a bit closer using the Giraffe class from the previous step:

            Code:
              Class Giraffe
                Public Height As Single = 4.3  'Height in metres
                Public Spots As Integer = 470  'Number of spots
              End Class
            We declare a variable of type Giraffe with the statement:
            Dim George As Giraffe

            We can now assign a new Giraffe object to this variable with:
            George = New Giraffe

            Alternatively, these two statements could be replaced with:
            Dim George As New Giraffe

            This declares the variable and assigns the new Giraffe object in one statement.

            Whichever way we do it we can say that George now contains a Giraffe object - but this is an illusion! George does not contain a Giraffe object at all - it contain a reference to a Giraffe object.

            To better understand this let’s go through this again in greater detail, looking at what happens "beneath the surface".

            The statement :
            Dim George As Giraffe

            creates a variable named George which is initially empty (it contains Nothing).
            Code:
                      __________
              George |__________|
            When the statement:
            George = New Giraffe

            executes, the New keyword causes a new Giraffe object to be created, not in the variable, but in another part of the system’s memory known as "The Heap".
            Code:
            [SIZE="1"][COLOR="Gray"]              The variable                   The Giraffe object (in the heap)[/COLOR][/SIZE] 
                      __________                       ______________
              George |[u] 3fa85e02 [/u]|            3fa85e02 |[u]   4.3 |  470 [/u]|
            [SIZE="1"][COLOR="Gray"]                                                            Height    Spots[/COLOR][/SIZE]
            The address where the new object is stored is placed into the variable, Thus the variable is said to contain a reference to the object, i.e. something which tells the process where the object is actually located. The variable does not contain the object’s data.

            In this example I have shown the object at a fictitious address 3fa85e02. We don’t know (or care) what this address actually is - only the process knows. Note that the object is not named George. It is simply "the Giraffe object at 3fa85e02".

            If we declare another variable:
            Dim Gerald As Giraffe

            and then make the assignment:
            Gerald = George

            we are not copying the object. We are simply copying the object reference in George into Gerald. We now have also:
            Code:
                        __________
                Gerald |[u] 3fa85e02 [/u]|
            which is a reference to the same object. In other words, George and Gerald refer to the same Giraffe! So if we change George’s height and print both heights before and after with:

            Code:
              Print(George.Height & " " & Gerald.Height)
              George.Height = 5.7
              Print(George.Height & " " & Gerald.Height)
            We print:
            4.3 4.3
            5.7 5.7
            You can see that changing a property of George also changes the same property of Gerald. This confirms the theory.

            It’s worth mentioning that the "built-in" data types (Integer, Single, Double, Date, Boolean, etc.) don’t behave like objects constructed from classes as discussed above. For these types the value is actually contained in the variable, hence they are called value types, while objects constructed from classes are called reference types.


            Arrays of Objects

            Because it is constructed from a .NET-supplied class, an array is itself a reference type of object. Let’s look at again at setting up an array of Giraffe objects (as in Step 26) in greater detail.

            The declaration:
            Dim Field As Giraffe()

            simply creates a variable, named Field, capable of holding a reference to an array of Giraffe objects. Initially this variable is empty (it contains Nothing). All we have is this:
            Code:
                       __________
                Field |__________|
            Now if we execute the statement:
            ReDim Field(3)

            the processor creates a 4-element array in the heap and assigns its starting address to the Field variable. Note that each array element is initially empty (contains Nothing):
            Code:
            [SIZE="1"][COLOR="Gray"]         The Array variable              The Array object (in the heap)[/COLOR][/SIZE]
                      __________                    __________
               Field |[u] 3fa9b428 [/u]|         3fa9b428 |__________| [COLOR="Gray"]0[/COLOR]
                                                   |__________| [COLOR="Gray"]1[/COLOR]
                                                   |__________| [COLOR="Gray"]2[/COLOR] 
                                                   |__________| [COLOR="Gray"]3[/COLOR]
            If we load the array with Giraffe objects using the loop:

            Code:
              For i = 0 To UBound(Field)
                Field(i) = New Giraffe
              Next
            we create 4 new Giraffe objects (also in the heap). The address of each object is assigned to the corresponding array element. We now have:
            Code:
            [SIZE="1"][COLOR="Gray"]       The array variable         The Array object (in the heap)      The Giraffe objects (in the heap)[/COLOR][/SIZE]
                    __________                 __________                 ______________
             Field |[u] 3fa9b428 [/u]|      3fa9b428 |[u] 3fb02c40 [/u]| [COLOR="Gray"]0[/COLOR]    3fb02c40 |[u]   4.3 |  470 [/u]| 
                                              |[u] 3fb02c48 [/u]| [COLOR="Gray"]1[/COLOR]    3fb02c48 |[u]   4.3 |  470 [/u]|
                                              |[u] 3fb02c50 [/u]| [COLOR="Gray"]2[/COLOR]    3fb02c50 |[u]   4.3 |  470 [/u]|
                                              |[u] 3fb02c58 [/u]| [COLOR="Gray"]3[/COLOR]    3fb02c58 |[u]   4.3 |  470 [/u]|
            [SIZE="1"][COLOR="Gray"]                                                                                     Height    Spots[/COLOR][/SIZE]
            Again each array element contains a reference to a Giraffe object, rather than the actual object.

            This gives us a more detailed picture of what actually happens when we set up an array of objects. If, for example, the Giraffe class had another property which was object, an additional set of objects would be created and referenced in the heap. This referencing process could go on forever!

            If we assign the array to another variable with:
            Dim Paddock As Giraffe() = Field

            All we are doing is creating another reference (in Paddock) to the same array. We are not copying the array.

            This Step illustrates what objects references are. The main points to remember are:
            • An object variable initially contains Nothing until an object is assigned to it.
            • An object (or more correctly the data associated with an object) is not stored in the object variable. The variable simply contains a link to where the object’s data is.

            If you understand this I’m sure you will become better OOPs.

            Comment

            • waldjunge
              Junior Member
              • Apr 2009
              • 12

              #336
              Minumum Stake

              The minimum Stake for Back is 2 pounds. There are some tools available which can place less then 2 pounds. Does anybody know how this works? I could not find any help in the API manual.

              Thanks

              Martin

              Comment

              • Monairda
                Junior Member
                • Jan 2009
                • 32

                #337
                Handling async calls for multiple markets and linking horse Namess's

                Hi Mumbles0


                Originally posted by Mumbles0 View Post
                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....

                http://forum.bdp.betfair.com/showthr...?t=112&page=33
                I have a problem trying to link the names of the horses at the table created in the call asynchronous.
                I had thought of using the step 12 to carry the load of the form to the selected market.
                But I do not work.
                Code:
                Private Sub MarketForm_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
                        Dim oMarketReq As New BFUK.GetMarketReq       'Create the request object
                        Dim oMarketResp As BFUK.GetMarketResp     'Create a varaible for the response object
                        Dim tabla As New DataTable
                        tabla.Columns.Add("IdSelection")
                        tabla.Columns.Add("Name")
                
                        Dim row As DataRow
                
                        With oMarketReq
                            .header = oHeaderUK()
                            .marketId = MarketId
                        End With
                        oMarketResp = BetFairUK.getMarket(oMarketReq)    'Call the API
                
                        With oMarketResp                      'Process the response
                            CheckHeader(.header)
                            'Print("ErrorCode = " & .errorCode.ToString)
                            If .errorCode = BFUK.GetMarketErrorEnum.OK Then
                                With .market
                                    'Print("MarketId = " & .marketId)    'Print id, name and status
                                    'Print("Name = " & .name)
                                    'Print("Status = " & .marketStatus.ToString)
                                    For i = 0 To .runners.Length - 1
                                        With .runners(i)
                                            row = tabla.NewRow
                                            row("IdSelection") = .selectionId
                                            row("Name") = .name.ToString
                                            tabla.Rows.Add(row)
                                            'Print(.selectionId & "  " & .name)   'Print list of runners
                                        End With
                                    Next
                                End With
                            End If
                        End With
                        gvDataName.DataSource = tabla
                        gvDataName.Refresh()
                    End Sub
                I would like to link the names of the horses to the table created by the data collected on objects in the Private Sub BuildDatatable(), but I do not know how to do it. Could you help me, please?


                Thanks for your help!!

                Comment

                • Mumbles0
                  Junior Member
                  • Jan 2009
                  • 240

                  #338
                  Using a DataTable

                  Monairda,

                  It looks like you have two DataGridView controls side by side, one with runner names (gvDataName) and the other with price and volume data (gvPrices). It is OK to call getMarket to get the list of runner names from Sub MarketForm_Load.

                  It may be better to put everything in one table. You could set up all columns of the table in Sub MarketForm_Load and update with price and volume data when it arrives with Sub BuildDataTable.

                  Code:
                  Private Tabla As New DataTable  'The data table
                  
                  Private Sub MarketForm_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
                  
                    Dim oMarketReq As New BFUK.GetMarketReq       'Create the request object
                    Dim oMarketResp As BFUK.GetMarketResp     'Create a varaible for the response object
                    Dim row As DataRow
                  
                    With Tabla.Columns     'Set up all columns
                      .Add("SelectionId")
                      .Add("Name")
                      .Add("OddBack")
                      .Add("OddLay")
                      .Add("LPM")
                      .Add("Vol")
                      .Add("AmountBack")
                      .Add("AmountLay")
                      .Add("TotalBack")
                      .Add("TotalLay")
                    End With
                  
                    With oMarketReq
                      .header = MainForm.oHeaderUK()
                      .marketId = MarketId
                    End With
                    oMarketResp = MainForm.BetfairUK.getMarket(oMarketReq)    'Call the API (getMarket)
                  
                    With oMarketResp                      'Process the response
                      MainForm.CheckHeader(.header)
                      If .errorCode = BFUK.GetMarketErrorEnum.OK Then
                        With .market
                          For i = 0 To .runners.Length - 1
                            With .runners(i)
                              row = Tabla.NewRow
                              row("SelectionId") = .selectionId   'Add the Selection Ids
                              row("Name") = .name                 'and runner names
                              Tabla.Rows.Add(row)
                            End With
                          Next
                        End With
                      End If
                    End With
                  
                    gvDataName.DataSource = Tabla   'Show the data
                    gvDataName.Refresh()
                  
                  End Sub

                  For this sub the API access objects and methods are on MainForm. You may have to change the scope of the BetfairUK object to Friend or Public.

                  Sub BuildDataTable updates the columns row by row. We use the Array.FindIndex method to get the element in the .runnerPrices (and .runnerVolume) corresponding to the selectionId for the row. The order of these arrays is not necessarily the same as the .runners array from getMarket. Also there could be a removed runner.
                  Code:
                  Private Sub BuildDataTable()
                    Dim i, j, k As Integer
                    Dim BestBack As Decimal
                    Dim TotalBack As Decimal
                    Dim TotalLay As Decimal
                    Dim TotalVolumen As Decimal
                    Dim RowSel As Integer
                  
                    For i = 0 To Tabla.Rows.Count - 1  'For each row in the DataTable
                      RowSel = Tabla.Rows(i)("SelectionId")  'The selectionId for this row
                  
                      j = Array.FindIndex(oMarketPrices.runnerPrices, Function(x) x.selectionId = RowSel)  'The .runnerPrices array index for this selectionId
                      If j >= 0 Then  'Runner exists in .runnerPrices array
                  
                        With oMarketPrices.runnerPrices(j)   'Update the DataTable
                          Tabla.Rows(i)("Vol") = .totalAmountMatched
                          Tabla.Rows(i)("LPM") = .lastPriceMatched
                          If .bestPricesToBack.Length > 0 Then
                            Tabla.Rows(i)("OddBack") = .bestPricesToBack(0).price
                            Tabla.Rows(i)("AmountBack") = .bestPricesToBack(0).amountAvailable
                            BestBack = .bestPricesToBack(0).price
                          End If
                          If .bestPricesToLay.Length > 0 Then
                            Tabla.Rows(i)("OddLay") = .bestPricesToLay(0).price
                            Tabla.Rows(i)("AmountLay") = .bestPricesToLay(0).amountAvailable
                          End If
                        End With
                      End If
                  
                      TotalBack = 0 : TotalLay = 0 : TotalVolumen = 0
                      k = Array.FindIndex(oTradedVolume.runnerVolume, Function(x) x.selectionId = RowSel) 'The .runnerVolume array index for this selection
                      If k >= 0 Then'    Runner exists in .runnerVolume array
                  
                        With oTradedVolume.runnerVolume(k)   'Update the DataTable
                          For j = 0 To .tradedVolume.Length - 1
                            If BestBack <= .tradedVolume(j).odds Then
                              TotalBack = TotalBack + .tradedVolume(j).totalMatchedAmount
                            Else
                              TotalLay = TotalLay + .tradedVolume(j).totalMatchedAmount
                            End If
                            TotalVolumen = TotalVolumen + .tradedVolume(j).totalMatchedAmount
                          Next
                        End With
                      End If
                  
                      Tabla.Rows(i)("TotalBack") = TotalBack  'Update the DataGridView
                      Tabla.Rows(i)("TotalLay") = TotalLay
                  
                    Next  'Next row
                  
                  End Sub

                  Comment

                  • waldjunge
                    Junior Member
                    • Apr 2009
                    • 12

                    #339
                    Hi Mumbles0,
                    do you know how to place a bet with a stake less then 2? Lets say for example 0.01 pounds?
                    Regards
                    Martin

                    Comment

                    • Mumbles0
                      Junior Member
                      • Jan 2009
                      • 240

                      #340
                      Step 28. Placing Multiple Bets with placeBets.

                      In Step 19 we called placeBets to place a single bet. In the example we assigned our desired bet parameters to the properties of an oBet object (of type BFUK.PlaceBets), then assigned this object to the first element of the .bets array in the request object oPlaceBetsReq. Because the .bets property is an array, we can use this to place several bets at once simply by increasing the length of this array (with a Redim statement), and assigning the parameters for each bet to each element of this array. The length of the .bets array must equal the number of bets to be placed.

                      Note this restriction: all bets must be on the same market.

                      A scheme to place 3 bets could be like this:

                      Code:
                        Dim oPlaceBetsReq As New BFUK.PlaceBetsReq      'Create the request object
                        Dim oPlaceBetsResp As BFUK.PlaceBetsResp    'A variable to hold the response object
                        With oPlaceBetsReq
                          .header = oHeaderUK()       'The standard header
                          ReDim .bets(2)   'Set array upper bound = 2 (to hold 3 bets)
                      
                          .bets(0) = New BFUK.PlaceBets  'Create an object in element(0)
                          With .bets(0)
                            [I]'Assign properties to specify 1st bet[/I]
                          End With
                      
                          .bets(1) = New BFUK.PlaceBets  'Create an object in element(1)
                          With .bets(1)
                            [I]'Assign properties to specify 2nd bet[/I]
                          End With
                      
                          .bets(2) = New BFUK.PlaceBets    'Create an object in element(2)
                          With .bets(2)
                            [I]'Assign properties to specify 3rd bet[/I]
                          End With
                      
                        End With
                      
                        oPlaceBetsResp = BetfairUK.placeBets(oPlaceBetsReq)  'Call API to place the bet
                      
                        ...........................
                      
                        [I]process response as per step 19 example[/I]
                        ............................
                      This extends the example in Step 19 to the multiple bet scenario. In the code there is a minor difference. We don’t create an intermediate oBet object. Here we put a BFUK.PlaceBets object into each element of .bets and assign the properties directly.

                      The results of the bet placement are returned in the .betResults array of the response object in the same order as they appear in the .bets array of the request object (at least I assume this is the case - the documentation does not specifically say so but this seems to be what happens).

                      Here is another example which uses a List(Of T) object to hold a list of bet details. This is a convenient array-based object because it grows automatically as you add more items. No Redim is required.

                      In an application you may be analysing a market looking for betting opportunities. Rather than call placeBets whenever a bet is found, you can save the bet details in this list and submit a batch of bets later on. We create a suitable List object with this statement:

                      Code:
                      Private BetList As New List(Of BFUK.PlaceBets)
                      You call Sub ListBet whenever you wish to add a bet to the List:

                      Code:
                      Sub ListBet(ByVal MarketId As Integer, ByVal YourSelection As Integer, ByVal YourBetType As BFUK.BetTypeEnum, ByVal BetPrice As Decimal, ByVal BetSize As Decimal)
                      
                        Dim oBet As New BFUK.PlaceBets   'An object to specify the bet
                        With oBet                        'Specify the bet details:
                          .asianLineId = 0               'Non-asian handicap market 
                          .betCategoryType = BFUK.BetCategoryTypeEnum.E    'Normal exchange bet
                          .betPersistenceType = BFUK.BetPersistenceTypeEnum.NONE  'Standard bet (not SP or InPlay persistence)
                          .betType = YourBetType         'Back or Lay
                          .marketId = MarketId           'The market of interest
                          .price = BetPrice              'The desired price (odds)
                          .selectionId = YourSelection   'Your selection of interest
                          .size = BetSize                'The bet amount (stake)
                          .bspLiability = 0              'Must be 0 for non-SP bet
                        End With
                        BetList.Add(oBet)     'Add this bet to the list
                      
                      End Sub
                      This sub sets up an oBet object in a similar way to Sub PlaceBet of Step 19, but this object is saved in BetList, rather than sent immediately to the API in the request object. You can keep calling Sub ListBet to add bets to the list. You can then send the listed bets to the API in one hit using Sub SubmitBets:

                      Code:
                      Sub SubmitBets(ByVal MarketId As Integer)
                        Dim oPlaceBetsReq As New BFUK.PlaceBetsReq      'Create the request object
                        With oPlaceBetsReq
                          .header = oHeaderUK()         'The standard header
                          .bets = BetList.ToArray       'The array containing the list of bets
                        End With
                        BetfairUK.placeBetsAsync(oPlaceBetsReq, New UserState(MarketId))  'Call API to place the bets
                        BetList.Clear()   'Clear the list
                      End Sub
                      Here we assign the request object in the usual way. Note the use of the .ToArray property of BetList. This returns a reference to BetList’s internal array.

                      I have made this an async call to provide best efficiency, particularly when working with multiple markets. For multiple markets you can to repeat the “list and submit” process for your bets on each market. This can be done in rapid succession.

                      Each async call responds via a common event handler (placeBetsCompleted). If you look at the API Guide for placeBets you will see that the response contains the betResults array which returns the betIds (if successful), but there is no marketId or other identifying parameter. So if you receive several responses at once for bets placed on different markets, you don’t know which market each response is for.

                      To overcome this problem we can make good use of the optional userState parameter of the async call. We require a simple class to encapsulate a user parameter (or set of parameters in an object or structure):

                      Code:
                      Class UserState
                        Property Param As Object
                        Sub New(ByVal Value As Object)
                          Param = Value
                        End Sub
                      End Class
                      (Note here I’m using the new single-line Property statement of VB2010. If you are using VB2008 either complete the Property Get/Set snippet or use the Public keyword.)

                      Using this we send the marketId along with the request object in the async call. Because this UserState object is returned in the response, we can identify the market associated with each response. The UserState objects thus sent are considered to be unique (even if the marketId is the same).

                      An event handler for testing this:

                      Code:
                      Private Sub BetfairUK_placeBetsCompleted(ByVal sender As Object, ByVal e As BFUK.placeBetsCompletedEventArgs) Handles BetfairUK.placeBetsCompleted
                        Try
                          If Not e.Cancelled Then
                            With e.Result
                              CheckHeader(.header)
                              Print("MarketId = " & e.UserState.Param) 'The marketId comes back in e.UserState
                              If .errorCode = BFUK.PlaceBetsErrorEnum.OK Then  'placeBets call OK
                      
                                For i = 0 To .betResults.Length - 1
                                  With .betResults(i)
                                    Print(.resultCode.ToString)   'Result of the bet placement
                                    If .success Then Print("BetId = " & .betId) 'Print the betId if successful
                                  End With
                                Next
                      
                              Else
                                Print("errorCode = " & .errorCode.ToString) 'If placeBets error
                              End If
                            End With
                          End If
                      
                        Catch ex As ApplicationException  'If problem
                          Print(ex.Message)
                        End Try
                      
                      End Sub
                      Note that the response object is returned in e.Result, and e.UserState contains the UserState object exactly as sent in Sub SubmitBets.

                      If you can get a scheme working based on these ideas your project should be capable of placing a large number of bets in a short space of time. Good luck.


                      An Afterthought:

                      If you try a scheme based on this Step to place bets across several markets at once you may be disappointed with the response times. This could be due to a .NET constraint on the number of simultaneous HTTP connections available to make the placeBets calls (the default is 2). To alleviate this, include this statement in your initialization section (I suggest in your startup form’s Load event):

                      Net.ServicePointManager.DefaultConnectionLimit = 20
                      This will increase the maximum number of HTTP connections from 2 to 20. The number you chose should be the maximum number of concurrent API calls you are likely to make.
                      Last edited by Mumbles0; 07-12-2010, 12:55 AM. Reason: Afterthought added

                      Comment

                      • Monairda
                        Junior Member
                        • Jan 2009
                        • 32

                        #341
                        Hi Mumbles0,

                        Thanks for everything. I'll try it!

                        Best Regards

                        Comment

                        • beans
                          Junior Member
                          • Jun 2009
                          • 6

                          #342
                          Any idea's why the 'params' does not show up on intelli-sense for UserState? If I type it in I get no error's but it's never listed as one of the possible options.
                          I'm wondering how far the userstate object could be extended, for example could we include a StopWatch in it so we can keep track of a response time from the API for async calls?

                          Comment

                          • Mumbles0
                            Junior Member
                            • Jan 2009
                            • 240

                            #343
                            UserState object.

                            A good question beans.

                            For the placeBets example of Step 28:

                            In the async response object e the property e.UserState is of type Object, hence it can contain an object of any type. At design time Intellisense does not know what type of object will ultimately be assigned to this property, so it cannot offer any suggestions (apart from the members of the fundamental Object class). The complier will accept anything you type in here. This property name will be resolved at run time when the expression:
                            e.UserState.Param

                            is evaluated (in a process called "late binding"). If the Param member doesn’t exist (or you’ve miss-spelt it) you will get "MissingMemberException (Public member 'xxx' on type 'UserState' not found)" when your program runs.

                            If you wish you can introduce an intermediate variable u in a separate statement to cast the object back to type UserState:
                            Dim u As UserState = e.UserState
                            Print("MarketId = " & u.Param)

                            Intellisense will now work as expected on the variable u.

                            A point of confusion: Perhaps unwisely, UserState is the name I’ve given to the class which holds the user parameter. It is also the name of the property of the async response object (e.UserState) which holds our parameter-containing object. So the name UserState refers to two completely different entities. The compiler does not have a problem with this because it sorts names out by context. Thus names can be reused freely as long as their context is unambiguous.


                            Response time measurement

                            Because UserState can be an object of any complexity, it can hold more than one parameter. Let’s now define another class to hold two parameters:

                            Code:
                            Class Params
                              Property MarketId As Integer
                              Property SendTime As Date
                              Sub New(ByVal _MarketId As Integer)
                                MarketId = _MarketId   'The marketId parameter
                                SendTime = Now         'The current time parameter
                              End Sub
                            End Class
                            and use an object from this class instead in the async call statement:
                            BetfairUK.placeBetsAsync(oPlaceBetsReq, New Params(MarketId)) 'Call API to place the bets

                            This sends the two parameters along with the request object. The parameters are MarketId (as before) and SendTime (which holds the time when the async call was made). These parameters can be recovered in Sub BetfairUK_placeBetsCompleteted (and the overall response time calculated) using code something like this:

                            Code:
                                  ............
                            
                                  With e.Result
                                    CheckHeader(.header)
                            
                                    Dim p As Params = e.UserState  'The object containing the parameters
                                    Dim t As TimeSpan = Now - p.SendTime  'The overall response time
                                    Print("MarketId = " & p.MarketId & "  Time = " & t.ToString)
                            
                                    If .errorCode = BFUK.PlaceBetsErrorEnum.OK Then  'placeBets call OK
                                    ............
                                    ............
                            You can extend on this idea to pass as many parameters as you like to the event handler for any async call. The UserState object can provide a very useful facility.

                            Comment

                            • UncleScrooge
                              Junior Member
                              • Feb 2010
                              • 2

                              #344
                              Hi all.
                              I'm an amateur in programming in VB.
                              Just getting through this thread (absolutely fantastic for the material shown and the patience profuse by Mumble0).
                              I started to build the app from "square one" trying to get through all the exercises proposed.
                              I downloaded and installed VB 2010 Express.
                              I'm still stuck at the beginning.
                              I got this error message from VB
                              "New" Cannot be used on an interface
                              It refers to this:


                              Code:
                              Public Class BetfairTester
                                  Dim oHeaderGL As New BFGlobal.APIRequestHeader
                                  [COLOR="Red"][B]Dim BetfairGL As New BFGlobal.BFGlobalService[/B][/COLOR]
                              
                                  Sub Print(ByVal Message As String)
                                      With tLog
                                          .SelectionStart = .Text.Length
                                          .SelectedText = vbCrLf & Message
                                      End With
                                  End Sub
                              
                                  Private Sub bLogin_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles bLogin.Click
                                      Print("*** Login ***")
                                      Dim oLoginReq As New BFGlobal.LoginReq
                                      Dim oLoginResp As BFGlobal.LoginResp
                                      With oLoginReq
                                          .username = "UserName"
                                          .password = "Password"
                                          .productId = 82           'For free API
                                      End With
                                      oLoginResp = BetfairGL.login(oLoginReq)     'Call the API
                                      With oLoginResp
                                          CheckHeader(.header)
                                          Print("ErrorCode = " & .errorCode.ToString)
                                      End With
                                  End Sub
                              
                                  Private Sub bLogout_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles bLogout.Click
                                      Print("*** Logout ***")
                                  End Sub
                              
                                  Private Sub bKeepAlive_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles bKeepAlive.Click
                                      Print("*** KeepAlive ***")
                                  End Sub
                                  Sub CheckHeader(ByVal Header As BFGlobal.APIResponseHeader)
                                      With Header
                                          Print("HeaderCode = " & .errorCode.ToString)
                                          oHeaderGL.sessionToken = .sessionToken
                                      End With
                                  End Sub
                              End Class
                              it might well be a stupid question so pls forgive my inexperience and naivety.
                              Tnhx in advance
                              Last edited by UncleScrooge; 29-06-2010, 07:15 AM.

                              Comment

                              • Mumbles0
                                Junior Member
                                • Jan 2009
                                • 240

                                #345
                                UncleScrooge,

                                Looks like you've added a service reference instead of a web reference in Step 2. See this post.

                                (You're not the first to do this.)

                                Comment

                                Working...
                                X