Using VB2008 to acccess the Betfair API: A tutorial

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

  • Mumbles0
    replied
    G-Factor,

    Thanks for your post.

    Settings

    You suggestion to use the in-built Settings facility is good. I might post a step taking a closer look at this.

    Response time variations

    I too have noticed this. The first API call made after a project starts running take a lot longer than subsequent calls. I timed some calls made to getMarket with a VB program. The first call took 1.7 sec, while subsequent calls made every 30 sec thereafter took only 0.4 sec. If I ceased calling for a few minutes, the next call took longer (1.1 sec). I’m calling the UK exchange from Australia with a fairly modest line speed, using Windows XP.

    I also called getMarket using SoapUI (which a Java app). The Same effect was noticed (although the times were a bit different).

    I'm fairly sure this phenomenon is caused by the secure (SSL) behavior of the transmission. Using Wireshark I observed the packet sequence. On the initial call there was a lot of handshaking going on (exchanging certificates, etc.), whereas the subsequent transmissions were a lot briefer. This accounted for the time difference.

    Your times of “5 - 10 seconds” seem a bit excessive. Is this for all API calls? What does it reduce to? Have you enabled gzip? There are other tweaks that can be done. I suggest you take a closer look at your interactions using a network analyser such as Wireshark.

    Text styles in DataGridView

    Unlike Excel and HTML, you cannot have different text styles within a single cell of a DataGridView, although the cells can have individual text styles.

    But .... having said this I think there is a way it can be done using graphics. I will investigate this.
    Last edited by Mumbles0; 19-08-2010, 01:12 AM.

    Leave a comment:


  • G-Factor
    replied
    Inspired!

    Over the last few days I've worked my way through the whole thread.

    Firstly, all credit to you Mumbles0 for sparing your time and knowledge.

    I've made some crude apps with self-taught vb.net, but nothing very complicated.
    My progs normally manage to do what I want them to, but after reading this thread I realise (already suspected) that my code is very untidy! I plan to re-look at them and try to make them more efficient, and easier to read, if I can.

    You've said before that there can be many ways to do things in vb.net and I'd just like to suggest an alternative that I use to saving settings in a separate file.

    I use the settings built in to each project.

    For those that don't know, if you double-click "My Project" in the solution explorer a new 'tab' will open with lots of complicated settings that I wouldn't go near, but one of the options on the left hand side is Settings.

    If you click on that it will give you a list of settings currently being used. There should be your web references there as application settings, but you can add your own.
    Just choose a name, a type, and a value if required.

    These settings can then be accessed in your program using My.Settings. and will be available to you each time you run it.

    ***********************

    I was hoping to find answers to a couple of things that have been bugging (no pun intended) me for a while now, and haven't, so I hope you won't mind me asking them.

    Whenever I start my app, the first call to the API always takes way longer than any subsequent calls, typically 5-10 seconds! I know it's not just the Login call, as I've started my prog already logged in and a GetEvents call took just as long.
    It's only the first call though, weird!
    Has anyone got any ideas as to why this might be?

    Secondly, I've been trying to get my display to look a little easier to read.
    I display runners and prices in a datagridview, and would like to show price & amount available but with the price in bold text (as the website does).

    I've managed to concatenate the price and amount together and to display one above the other, but can't change from bold to not in the middle of it. I've tried tags and ascii characters but that's the limit of my ideas and I can't find anything by Googling.

    Any ideas? Is it even possible? It seems daft that I can do it in Excel and not .NET

    Thanks in advance for anyone who might be able to help.

    Leave a comment:


  • Mumbles0
    replied
    Reply to gvigliani (re: getCompleteMarketPricesCompressed)

    The two API “Prices” calls return runner prices differently. getMarketPricesCompressed returns two arrays for each runner in the unpacked response object:

    oMarketPrices.runnerPrices(i).bestPricesToBack()
    containing the best (up to) 3 prices available to back for runner i, and:

    oMarketPrices.runnerPrices(i).bestPricesToLay()
    containing the best (up to) 3 prices available to lay for the same runner. I see that you have succeeded in “digging out” these arrays.

    But getCompleteMarketPricesCompressed returns all prices (both back and lay) in a single array for each runner:

    oMarketPrices.runnerInfo(i).prices()
    If I modify the code of Step 10 a bit so that it now “prints” the .prices array:

    Code:
     [COLOR="Gray"] ......
      Dim oMarketPrices As New UnpackCompleteMarketPricesCompressed(.completeMarketPrices)
      With oMarketPrices
        Print(.marketId & "  " & .runnerInfo.Length & " runners")
        'Process returned market prices here.
        For i = 0 To .runnerInfo.Length - 1
          With .runnerInfo(i)
    [COLOR="Black"]        Print("Selection = " & .selectionId & vbCrLf & "price  backAmount layAmount")
            For j = 0 To .prices.Length - 1
              With .prices(j)
                Print(.price & " " & .backAmount & " " & .layAmount)
              End With
            Next[/COLOR]
          End With
        Next
      End With
      .....[/COLOR]
    we can see what's in the .prices array for a typical runner:

    Code:
    Selection = 201255
    price  backAmount layAmount
    1.01     64.14         0
    1.74     47.03         0
    1.99      4.88         0
    2.02      0.14         0
    2.06     30.16         0
    2.08     66.12         0
    2.1      15.26         0
    2.16    112.52         0
    2.26    113.64         0
    2.28     90.59         0
    2.4          0     144.3
    2.54         0    125.72
    2.6          0      0.11
    2.72         0      17.4
    1000         0      4.17
    From this you can see that the 3 best back prices are 2.28, 2.26 & 2.16. Also the 3 best lay prices are 2.4, 2.54 & 2.6.

    There are usually many prices for each runner. You may have a problem trying to fit them all on your UI form. You may need to write additional code to extract only the prices and amounts that interest you.

    Leave a comment:


  • Mumbles0
    replied
    Arrays in request objects

    granted,

    First read my tutorial post regarding arrays here. This, I hope, will give you a better understanding of arrays.

    If you look at the Sports API Guide for any API call you will see, under the heading Input, details of the request parameters that must be assigned. With VB2008/2010 these parameters are the properties of the request object. For each parameter a type is given. You must use either a value of the given type, or a value that VB can convert to the given type.

    For example, for getSilksV2 the markets request parameter has type ArrayOfInt (i.e. array of type integer). Using an array lets you request data for several markets in one call. If you only want one market then you must use an integer array with a length of one, with its’ single element containing the (integer) marketId. You can do it like this:

    Code:
    Dim oGetSilksV2Req As New BFAU.GetSilksV2Req
    With oGetSilksV2Req
      .header = oHeaderAU()
      ReDim .markets(0)
      .markets(0) = marketidt.Text
    End With
    Because the .markets property of oGetSilksV2Req is, in fact, an array of integer we can create a suitable array by ReDiming this to 0 (0 being the upper bound of the array). Because array elements are numbered from 0, this creates an array with one element. This single element is referred to as .markets(0), to which we assign the marketId.

    (Note that getSilksV2 is not available on the free API.)

    Your query about buttons and labels is a more advanced topic. I will look at this in a separate post.

    Leave a comment:


  • granted
    replied
    Get Silks V2 (exchange) - GetSilksV2Req is of type ArrayOfInt

    the GetSilksV2Req 'markets' parameter is of type ArrayOfInt.

    But i just want to put in one market id...the one im currently looking at

    i tried

    With oGetSilksV2Req
    .header = oHeaderAU()
    .markets = marketid.text

    but it says: value of type integer cannot be converted to a 1-dimensional array of integer

    what does it want me to put there?

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

    also, when we print the runners, they appear as follows for example:

    4290762 1. Sharufa
    3286065 2. Spend The Money
    4914968 3. Amberman
    4914969 4. Ieramugadu
    4183913 5. Last To Leave
    2127783 6. Intercode
    4914970 7. Charming Manners
    3661066 8. Enhanced Design
    2016704 9. Circus Pony
    4914971 10. Gangway

    how can i put each runners name into a vb 'label' and assign the runner id to a 'button'

    i know how to do it for the event name...because there's only one name...but here, there is an array

    can you help please...as even more confusing is on the GetMarketResp, the parameter runners is of type ArrayOfRunners

    thanks
    Last edited by granted; 14-08-2010, 05:34 AM.

    Leave a comment:


  • Mumbles0
    replied
    Reply to granted (getMarket code)

    granted,

    You learn by your mistakes.

    Code:
    Private Sub bLoad_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles bLoad.Click
    
      Print("*** MarketRunners ***")      '[COLOR="Red"]<<< Note 1[/COLOR]
      Dim oGetMarketReq As New BFAU.GetMarketReq 'Create the request object
      Dim oGetMarketResp As BFAU.GetMarketResp '[COLOR="Red"]<<< Note 2[/COLOR]
      With oGetMarketReq
        .header = oHeaderAU() 'Load request parameters
        .marketId = marketidt      '[COLOR="Red"]<<< Note 3[/COLOR]
      End With
      With BetFairAU.getMarket(oGetMarketReq) 'Call the API
        CheckHeader(.header)
        Print("ErrorCode = " & .errorCode.ToString)
        If .errorCode = BFAU.GetMarketErrorEnum.OK Then
          Dim Markets As New UnpackAllMarkets(.market)  '[COLOR="Red"]<<< Note 4[/COLOR]
          With Markets
            For i = 0 To .market.Length - 1      
                   '[COLOR="Red"]<<< Note 5[/COLOR]
            Next
            Print(.runners)
          End With
        End If
      End With
    
    End Sub
    1. If you are having a problem with this my guess that the Print sub of Step 1 is missing. Ensure that this sub (and its associated textbox tLog) is included somewhere in your project.

    2. The compiler is telling you that oGetMarketResp is unused because you’re not using it.

    3. The .marketId property of the request object can only hold an integer. marketidt is the textbox object, not what’s in it. You cannot assign this object to an integer, hence the error. What’s in the textbox is given by the .Text property. So try:

      .marketId = marketidt.Text
    4. You will be getting an error here. UnpackAllMarkets is a class to convert the data string returned by the API call getAllMarkets. It won’t work here because you are calling getMarket which returns an object which does not require unpacking. This statement is not right, so removed it. But when you do you will get more errors ...

    5. This For..Next loop contains no statements - it is useless. This suggests that you need to understand more about programming. There are many VB tutorials on the Internet, for example here.


    We covered what you are trying to do here in Step 12. Try to understand how we printed the list of runners in this step.

    Leave a comment:


  • gvigliani
    replied
    Originally posted by Mumbles0 View Post
    gvigliani,

    If you need more than 3 best prices (for a price ladder), call getCompleteMarketPricesCompressed. This returns all prices for each runner. See step 10.

    Working with multiple markets is more complicated, particularly if you are using async calls. When you receive a response you have to determine which market it is for. This is OK if you call getMarket or getMarketPricesCompressed because the marketId is returned in the response. This lets you update the correct group of controls for each market.
    Dear Mumbles0,
    I have tried in every way but I can not find a way to access different shares to be included in a Ladder:
    My code is:
    Code:
    Private Sub BetFairUK_getCompleteMarketPricesCompressedCompleted(ByVal sender As Object, ByVal e As BFUK.getCompleteMarketPricesCompressedCompletedEventArgs) Handles BetFairUK.getCompleteMarketPricesCompressedCompleted
            Dim RaceStart As Date = Nothing        'The time when the race turns in-play
            Dim RaceStarted As Boolean = Nothing    'A flag, set True when the race has started
            Try
                If Not e.Cancelled Then
    
                    With e.Result
    
                        CheckHeader(.header)
                        PrintRes("ErrorCode = " & .errorCode.ToString)
                        If .errorCode = BFUK.GetCompleteMarketPricesErrorEnum.OK Then
                            Dim oMarketPrices As New UnpackCompleteMarketPricesCompressed(.completeMarketPrices)
                            With oMarketPrices
                                t_run.Text = .runnerInfo.Length
                                If .delay > 0 Then     'Race is in-play
                                    Mark_status.BackColor = Color.Green
                                    Mark_status.Text = "Market In Play"
                                    If RaceStarted Then
                                        manca.Text = Now.Subtract(RaceStart).ToString.Substring(0, 8) 'Update the time label
                                    Else           'Initialize the variables
                                        RaceStart = Now       'Save the race start time
                                        RaceStarted = True    'Set the flag
                                    End If
                                Else
                                    Mark_status.BackColor = System.Drawing.Color.FromArgb(CType(CType(47, Byte), Integer), CType(CType(70, Byte), Integer), CType(CType(232, Byte), Integer))
                                End If
    
                            End With
                        End If
                    End With
                End If
     
            Catch ex As ApplicationException
                PrintRes(e.Error.Message)
            End Try
        End Sub
    Can you give me a help to better understand?

    Thank you so much!

    gvigliani

    Leave a comment:


  • granted
    replied
    load market runner error in my code

    i have a text box called marketidt and a button called Load, so i was hoping to code a load runners PRINT like we did before with events, login etc

    and here is the code i tried:

    Private Sub bLoad_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles bLoad.Click
    Print("*** MarketRunners ***")
    Dim oGetMarketReq As New BFAU.GetMarketReq 'Create the request object
    Dim oGetMarketResp As BFAU.GetMarketResp 'Create a variable for the response object
    With oGetMarketReq
    .header = oHeaderAU() 'Load request parameters
    .marketId = marketidt
    End With
    With BetFairAU.getMarket(oGetMarketReq) 'Call the API
    CheckHeader(.header)
    Print("ErrorCode = " & .errorCode.ToString)
    If .errorCode = BFAU.GetMarketErrorEnum.OK Then
    Dim Markets As New UnpackAllMarkets(.market) 'Unpack .market
    With Markets
    For i = 0 To .market.Length - 1

    Next
    Print(.runners)
    End With

    End If
    End With

    End Sub

    the error i get is that the marketidt text box cannot be converted to an integer and the other error i get is with Print("*** MarketRunners ***")

    it also told me that oGetMarketResp variable was not being used

    any help would be appreciated

    thanks
    Last edited by granted; 11-08-2010, 03:17 PM.

    Leave a comment:


  • Mumbles0
    replied
    Price ladder &amp; multi markets

    gviglinani,

    If you need more than 3 best prices (for a price ladder), call getCompleteMarketPricesCompressed. This returns all prices for each runner. See step 10.

    Working with multiple markets is more complicated, particularly if you are using async calls. When you receive a response you have to determine which market it is for. This is OK if you call getMarket or getMarketPricesCompressed because the marketId is returned in the response. This lets you update the correct group of controls for each market.

    Leave a comment:


  • Mumbles0
    replied
    Results

    WStecher,

    I don't think you can get results of matches via the API. You may have to resort to "scraping" web pages from sports websites.

    Has anyone got any suggestions?

    You could perhaps ask the question in the "General Sports Programming" section of the Forum.

    Leave a comment:


  • Mumbles0
    replied
    Event time sorting

    granted,

    There are many ways of achieving this. WStecher has outlined a way of loading the market data into a DataGridView control, then sorting the EventDate column. A more direct way would be to use a comparer class similar to what was done in Step 17.

    Code:
    Class CompareMarketTimes
      Implements IComparer(Of MarketDataType)
      Public Function Compare(ByVal x As Unpack.MarketDataType, ByVal y As Unpack.MarketDataType) As Integer Implements System.Collections.Generic.IComparer(Of Unpack.MarketDataType).Compare
        Return Date.Compare(x.eventDate, y.eventDate)
      End Function
    End Class
    Then add a line to perform the sort using an instance of this class:

    Code:
    [COLOR="Gray"]  .......
      Dim AllMarkets As New UnpackAllMarkets(.marketData) 'Unpack .marketData
      With AllMarkets
        [COLOR="Black"]Array.Sort(.marketData, New CompareMarketTimes)[/COLOR]
        For i = 0 To .marketData.Length - 1
          With .marketData(i)
          ..........[/COLOR]
    This sorts the .marketData array according to the .eventDate property.

    Leave a comment:


  • WStecher
    replied
    @granted: how would i add sorting by times to this sub?

    Hey granted,

    I think you have to put the data in a datatable and create a dataview on it.
    The dataview can be sorted. This will bring the data in a sorted tableview to you. If you don't want to have a DataGridView on your form, you can set visible = false to the datagridview.

    Just one idea. I would do it like this:
    First place a datagridview to your form and name it "DataGrid1"

    Add the following code to your class (not the sub):
    Code:
    Private dtInPlay As New DataTable("InPlay")
    
    With dtInPlay.Columns
       .Add("EventDate", GetType(System.DateTime))
       .Add("MarketID", GetType(System.String))
       .Add("Match", GetType(System.String))
       .Add("MarketName", GetType(System.String))
    End With
    
    DataGrid1.DataSource = dtInPlay
    Add the following code to your "bInPlay_Click_1" Sub
    Code:
    Dim matchdata(4) As Object
    Replace the code from
    - With AllMarkets
    to
    - End With
    in your "bInPlay_Click_1" Sub with the following code:
    Code:
    With AllMarkets
    
    For i = 0 To .marketData.Length - 1
    
       With .marketData(i)
    
          If .turningInPlay Then
    
             matchdata(0) = .eventDate.ToLocalTime
             matchdata(1) = .marketID
             matchdata(2) = .menuPath
             matchdata(3) = .marketName
    
             dtInPlay.Rows.Add(matchdata)
    
          End If
    
       End With
    
    Next
    
    DataGrid1.Sort(DataGrid1.Columns(0), System.ComponentModel.ListSortDirection.Ascending)
    
    End With
    
    'the data will be displayed sorted by EventDate in the DataGridView  
    'if you want to print it with the function "print()", add the following code:
    
    For Each DataGridRow As DataRow In DataGrid1.Rows
    Print(DataGridRow.Item(0).ToString & " " & DataGridRow.Item(1).ToString & " " & DataGridRow.Item(2).ToString & "\" & DataGridRow.Item(3).ToString)
    Next

    Leave a comment:


  • granted
    replied
    how would i add sorting by times to this sub?

    Private Sub bInPlay_Click_1(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles bInPlay.Click
    Print("*** InPlay Markets ***")
    Dim oMarketsReq As New BFAU.GetAllMarketsReq
    With oMarketsReq
    .header = oHeaderAU()
    .fromDate = Now
    .toDate = Now.AddDays(1) 'Specifies next 24 hour period
    End With
    With BetFairAU.getAllMarkets(oMarketsReq) 'Call the AU API
    CheckHeader(.header)
    Print("ErrorCode = " & .errorCode.ToString)
    If .errorCode = BFAU.GetAllMarketsErrorEnum.OK Then
    Dim AllMarkets As New UnpackAllMarkets(.marketData) 'Unpack .marketData
    With AllMarkets
    For i = 0 To .marketData.Length - 1
    With .marketData(i)
    If .turningInPlay Then 'This market will become InPlay
    Print(.eventDate.ToLocalTime.TimeOfDay.ToString & " " & .marketId & " " & .menuPath & "\" & .marketName)
    End If
    End With

    Next
    End With
    End If
    End With
    End Sub

    i want the printed list to be sorted by earliest to latest...but cant figure it out

    thanks
    christian

    Leave a comment:


  • WStecher
    replied
    Get results of all matches?

    Hello,

    first at all I want to say THANKS to this gread Thread. It helped me very much building my own Betfair software. At the end I still have one question:

    Is there any possibility in the betfair API to get the results (I only want to know which team or player has won) of all matches in a market?

    With getAccountStatement() I can get the results for each match I have placed a bet. But I also want to know the winning player/team for the matches I don't have placed a bet. So I can build up a history of what I could have had won if I would have placed a bet.

    Thanks for your ideas.

    Leave a comment:


  • gvigliani
    replied
    Originally posted by waldjunge View Post
    I have tried to write code for betting less then the minimum stake for Lay betting, according to this guideline.

    'Documentation will not help you with this issue. Trick is to do it in few steps.
    'If you want, for example, to place £0.1 bet then place regular £2 bet on highest quote (1000 if you want to back)
    'or lowest quote (1.01 if you want to lay). The bet will not be matched.
    'Change its amount to 2.1£ and as result you will have two bets: one with £2 and the other with £0.1 amount.
    'Cancel first one, change £0.1 bet quote on the desired value and that's it

    But I can not really update the bet to get a new betID and a new st
    Look my code.
    Best Regards

    Leave a comment:

Working...
X