Using VB2008 to acccess the Betfair API: A tutorial

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts

  • Mumbles0
    replied
    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.

    Leave a comment:


  • Mumbles0
    replied
    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).

    Leave a comment:


  • waynebrayn
    replied
    Mumbles,

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

    Regards,

    Wayne

    Leave a comment:


  • Mumbles0
    replied
    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.

    Leave a comment:


  • waynebrayn
    replied
    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

    Leave a comment:


  • Mumbles0
    replied
    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.

    Leave a comment:


  • waldjunge
    replied
    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

    Leave a comment:


  • Monairda
    replied
    Hello Mumbles0

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

    Leave a comment:


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

    Leave a comment:


  • Mumbles0
    replied
    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

    Leave a comment:


  • Monairda
    replied
    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.

    Leave a comment:


  • Mumbles0
    replied
    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.

    Leave a comment:


  • Mumbles0
    replied
    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.

    Leave a comment:


  • waldjunge
    replied
    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

    Leave a comment:


  • waldjunge
    replied
    thanks a lot Mumbles0!

    Leave a comment:

Working...
X