Using VB2008 to acccess the Betfair API: A tutorial

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

    #121
    Originally posted by John Moore View Post
    Hi Mumbles, thanks for this thread. I`m attempting to write a bet bot. I am storing my marketIds, selectionIds into a dim array. but I am having trouble retriving the event date/time. Can you suggest which API call to make, and when to call it?

    Thanks again John Moore
    Hi John

    Depends on when/how you call your market but you could use the PopulateTreeView routine and bung it in the tag of the node:
    Node.Name = Ids(j) 'This is the key

    Node.Tag = Format(.eventDate, "HH:mm")
    Nodes.Add(Node)

    When you call your market just use the tvMarkets.SelectedNode.Tag and bung it in a variable or use it straight away.
    Last edited by willyray1; 08-05-2009, 06:34 PM. Reason: typo

    Comment

    • Mumbles0
      Junior Member
      • Jan 2009
      • 240

      #122
      Reply to John Moore (re: Event times)

      I not exactly sure of your problem, but you should have the date & time info already without having to make an additional call. If you have called getAllMarkets to get your marketId, then the .eventDate parameter countains the scheduled market start time for each returned market. You have probably called getMarket to get your selectionIds. This call returns a parameter called .marketTime which contains the same info. These parameters are of type DateTime which have both date and time parts.

      Comment

      • Mumbles0
        Junior Member
        • Jan 2009
        • 240

        #123
        Reply to daylosh (re: Step 6 code)

        The code shown in step 6 already includes 'string.split'. This executes as fast as I can get it. No more changes are required (unless, of course, you can think of any improvements).

        Comment

        • Mumbles0
          Junior Member
          • Jan 2009
          • 240

          #124
          Reply to Vadim (re: updateBets)

          All parameters in the request object should be assigned:

          Code:
          With oUpdateBets
            .betId = 7919011854
            .newBetPersistenceType = BFUK.BetPersistenceTypeEnum.NONE
            .newPrice = 1000
            .newSize = 4.5
            .oldBetPersistenceType = BFUK.BetPersistenceTypeEnum.NONE
            .oldPrice = 1000
            .oldSize = 4
          End With
          The API Guide says include the old values, so do this.
          General rule is don't omit parameters unless you're sure it's OK to do so.

          Also, change this line further down in your code:

          Code:
          If .errorCode = BFUK.UpdateBetsErrorEnum.OK Then
          This did not cause the problem, but is more correct.

          Comment

          • Vadim
            Junior Member
            • Mar 2009
            • 12

            #125
            Multithreading and UI problem

            Mumbles0, method that you described in step 11 is good, but if you interact with the user interface is used BeginInvoke.
            I try to modify the code using BeginInvoke:
            Code:
            Imports System.Threading
            Public Class ThreadForm
                Public Delegate Sub dPrint(ByVal tLog As TextBox, ByVal Message As String) 'Delegate
                Private StopFlag As Boolean
                Public Sub Print(ByVal tLog As TextBox, ByVal Message As String)
                    With tLog
                        .SelectionStart = .Text.Length
                        .SelectedText = vbCrLf & Message
                    End With
                End Sub
            
                Sub DoTheWork()
                    Do
                        Print("My message")   '??????????????
                    Loop Until StopFlag
                    Beep()
                End Sub
            
               Private Sub bStart_Click(ByVal sender As Object, ByVal e As EventArgs) Handles bStart.Click
                    StopFlag = False
                    bStart.Enabled = False
                    Dim Fred As New Thread(AddressOf DoTheWork)
                    tLog.BeginInvoke(New dPrint(AddressOf Print), Fred) 'BeginInvoke
                    Fred.Start()
                End Sub
            
                Private Sub bStop_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles bStop.Click
                    StopFlag = True
                    bStart.Enabled = True
                End Sub
            
            End Class
            On line Print("My message") errors.

            Comment

            • Mumbles0
              Junior Member
              • Jan 2009
              • 240

              #126
              Reply to Vadim (re: Multithreading)

              I have no idea what your code is trying to do. When you make the call:

              Print("My message")

              to a sub declared like this:

              Public Sub Print(ByVal tLog As TextBox, ByVal Message As String)

              this suggests to me that you have a lot more to learn about programming fundamentals. I suggest you concentrate on this before you tackle the very complex area of multithreading.

              Step 11 is a “side topic” and was included to illustrate the basic idea of multithreading. This code is not used to access the API.

              Multithreading requires very advanced programming and you will run into problems when you try to access controls on the user interface from separate threads. I don’t know much about this subject myself.

              Comment

              • Vadim
                Junior Member
                • Mar 2009
                • 12

                #127
                Sort array

                The question is closer to the subject. How to sort array MarketPricesCompressed runnerPrices on bestPricesToBack(0) in descending order.
                For example:
                Code:
                Original:
                Runners      BestPriseToBack(0)
                1                           7.7
                2                           1.3
                3                           5.6
                
                Result:
                Runners      BestPriseToBack(0)
                1                           7.7
                2                           5.6
                3                           1.3

                Comment

                • Vreljanski
                  Junior Member
                  • May 2009
                  • 16

                  #128
                  Hey Mumbles!

                  great tutorial and post man I have been reading it for a week now and slowly been building my custom bet angel looking app.

                  I sucessfully implemented most of the steps you described and i needed them and so far managed to get all suport when i was stuck just from the forums.

                  Now i am facing one small problem.

                  I display full market depth for my horse runners but i want to add matched volume for the each price if there was any matching.

                  and I havent been able to find a way how. I red the docmentations also and didnt figured it out.

                  Cheers and thanks

                  also as soon as i catch some time i will post how to definately filter only horse win markets as i saw that is a problem to some ppl.

                  Comment

                  • Mumbles0
                    Junior Member
                    • Jan 2009
                    • 240

                    #129
                    Reply to Vreljanski (re: Matched Volume)

                    I think getMarketTradedVolumeCompressed will give you the data you want. This gives you the values shown in the ‘Price’ and ‘Traded’ columns on the ‘Market Information’ page for each runner shown on the website’s page for your market.

                    This service can be called 60/min on the free API. It’s best to call getMarketTradedVolumeCompressedAsync because this is more efficient.

                    This call returns a compressed .tradedVolume string which can be unpacked using these classes:

                    Code:
                    Class RunnerVolumeType
                      Public selectionId As Integer
                      Public asianLineId As Integer
                      Public actualBSP As Double
                      Public totalBspBackMatchedAmount As Double
                      Public totalBspLiabilityMatchedAmount As Double
                      Public tradedVolume As VolumeType()
                    End Class
                    
                    Class VolumeType
                      Public odds As Double
                      Public totalMatchedAmount As Double
                    End Class
                    
                    Class UnpackMarketTradedVolumeCompressed
                      Public RunnerVolume As RunnerVolumeType() = {}
                    
                      Sub New(ByVal TradedVolume As String)
                        Dim Tvolume, Part, Field As String(), m, n As Integer
                    
                        Tvolume = TradedVolume.Split(":")       'Split data for each runner
                        n = UBound(Tvolume) - 1
                        ReDim RunnerVolume(n)
                        For i = 0 To n    'For each runner
                          Part = Tvolume(i + 1).Split("|")
                          Field = Part(0).Split("~")
                          RunnerVolume(i) = New RunnerVolumeType
                          With RunnerVolume(i)
                            .selectionId = Field(0)
                            .asianLineId = Field(1)
                            .actualBSP = Val(Field(2))
                            .totalBspBackMatchedAmount = Val(Field(3))
                            .totalBspLiabilityMatchedAmount = Val(Field(4))
                            m = UBound(Part) - 1
                            ReDim .tradedVolume(m)
                            For j = 0 To m
                              Field = Part(j + 1).Split("~")
                              .tradedVolume(j) = New VolumeType
                              .tradedVolume(j).odds = Val(Field(0))
                              .tradedVolume(j).totalMatchedAmount = Val(Field(1))
                            Next
                          End With
                        Next
                    
                      End Sub
                    End Class
                    Unpack the returned data by creating a new UnpackMarketTradedVolumeCompressed object, similar to what we've done in steps 10 and 14. A list of odds & traded amounts is returned for each runner in the .tradedVolume array.

                    Note that no .sortOrder parameter is returned, so you will have to use .selectionId to identify the runner data.

                    Comment

                    • Mumbles0
                      Junior Member
                      • Jan 2009
                      • 240

                      #130
                      Reply to Vadim (re: Sorting .runnerPrices according to bestBackPrice)

                      The sort can be done similar to step 17, but using a different comparison method. You require another class to compare the .bestPricesToBack(0) values:

                      Code:
                      Class CompareBestBack     'A class to allow sorting according to the highest back price
                        Implements IComparer(Of BFUK.RunnerPrices)
                      
                        Public Function Compare(ByVal x As BFUK.RunnerPrices, ByVal y As BFUK.RunnerPrices) As Integer Implements System.Collections.Generic.IComparer(Of BFUK.RunnerPrices).Compare
                          Return bestBack(y) - bestBack(x)
                        End Function
                      
                        Private Function bestBack(ByVal w As BFUK.RunnerPrices) As Integer
                          Return If(w.bestPricesToBack.Length > 0, w.bestPricesToBack(0).price * 100, 0)
                        End Function
                      
                      End Class
                      There are two things to watch here. If no back bets have been placed on a runner, then .bestPricesToBack(0) will not exist. Function bestBack checks this and returns zero if the bestPricesToBack array is empty, thereby avoiding an exception. Any runner with no back bets will be sorted to the end of the array.

                      Also, if we compare two close prices (e.g. 2.70 and 2.80) simply by subtracting them, we get 0.10. This will be rounded to 0 by Function Compare because it returns type Integer. This means that runners having close prices could be treated as being equal for the purpose of the sort which would result in an incorrect sort. To avoid this problem we multiply each price by 100 before the subtraction.

                      To perform the sort add a new line to Sub BetFairUK_getMarketPricesCompressedCompleted:

                      Code:
                      [COLOR="Gray"].....
                        .....
                          With oMarketPrices
                            Print(.marketId & " " & .marketStatus.ToString & " " & .runnerPrices.Length & " runners")
                            'Process returned market prices here.
                            [COLOR="Black"]Array.Sort(.runnerPrices, New CompareBestBack)[/COLOR]
                            For i = 0 To .runnerPrices.Length - 1
                              With .runnerPrices(i)
                            .....
                          .....
                        .....
                      .....[/COLOR]

                      Comment

                      • Vadim
                        Junior Member
                        • Mar 2009
                        • 12

                        #131
                        I tried to do it seems, but I failed. Thank you, Membles0

                        Comment

                        • Dodgee
                          Junior Member
                          • Jan 2009
                          • 17

                          #132
                          Another question about making objects available to other classes

                          Another newbie question here...

                          I'm just trying to rearrange things a bit to make my client look better and work more intuitively. I've created a separate login form which is now the startup form. The class for the form handles the login process, performs error handling and, if there is no error, displays the main window and initiates the population of the events/markets treeview.

                          So now I have two different classes which both need to be able to work with headers to perform their calls, so I need the Checkheader subs and oHeaderUK function to be available to both classes.

                          What's the best way to achieve this? I tried a few ways: making the required variables, subs and function public and referencing them from the other class; creating a new module and making everything friend or public (like the Unpack modules). However, I either get an error or an empty header which of course leads to a "no session" error from the api when making subsequent calls.

                          I'm probably missing something simple...

                          Comment

                          • Mumbles0
                            Junior Member
                            • Jan 2009
                            • 240

                            #133
                            Reply to Dodgee (re: common access)

                            I prefer to put common variables and procedures into a separate module. If they are declared Friend or Public they will be accessible from all classes and modules in your project. For example the Betfair tester works fine if we relocate these procedures into a new module as shown here:

                            Code:
                            Module MiscMod
                            
                              [COLOR="Black"]Friend[/COLOR] oHeaderGL As New BFGlobal.APIRequestHeader     '<<< Change access to Friend (or Public)
                            
                              Function oHeaderUK() As BFUK.APIRequestHeader
                                Dim Header As New BFUK.APIRequestHeader
                                Header.sessionToken = oHeaderGL.sessionToken
                                Return Header
                              End Function
                            
                              Sub CheckHeader(ByVal Header As BFGlobal.APIResponseHeader)
                                With Header
                                  Print("HeaderCode = " & .errorCode.ToString)
                                  oHeaderGL.sessionToken = .sessionToken
                                End With
                              End Sub
                            
                              Sub CheckHeader(ByVal Header As BFUK.APIResponseHeader)
                                With Header
                                  Print("HeaderCode = " & .errorCode.ToString)
                                  oHeaderGL.sessionToken = .sessionToken
                                End With
                              End Sub
                            
                              Sub Print(ByVal Message As String)
                                With [COLOR="Black"]TestForm[/COLOR].tLog                              '<<< Nominate the form containing the TextBox.
                                  .SelectionStart = .Text.Length
                                  .SelectedText = vbCrLf & Message
                                End With
                              End Sub
                            
                             ...............
                             ...............
                            
                            End Module
                            Note that a couple of minor changes are required as shown. In a module the access level for the procedures is Friend by default.

                            You say you’ve tried this but it didn’t work. I’m only guessing, but perhaps you have another oHeaderGL object declared elsewhere (in one of your form classes?). Ensure that there is only one. Also check that none of these procedures exist elsewhere (in your classes).

                            Keep trying....

                            Comment

                            • Dodgee
                              Junior Member
                              • Jan 2009
                              • 17

                              #134
                              Problem solved

                              I found the issue. I figured I was missing something, like forgetting to comment out some other declaration of the oHeaderGL object elsewhere in the code, as you suggested.

                              It was actually because of the sub that tries to read the session token from a file. I forgot to move this sub (code below) to the start of the login form class, so the first time I ran the app, the login form would work fine but as soon as the main form was loaded, it would try and read the session token from the file, which of course at this point was empty. Hence any subsequent calls resulted in a no session error.

                              Code:
                                  Private Sub LoginForm2_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
                                      oHeaderGL.sessionToken = My.Computer.FileSystem.ReadAllText(SessTokFile)
                                  End Sub

                              Comment

                              • Vreljanski
                                Junior Member
                                • May 2009
                                • 16

                                #135
                                Again thankles Mumbles0 for all the help it has been really great to have it all in one discusion and its really valuable resource.

                                I have further thing to ask. I have seeked trought discussion and found something similar to what i need but it dont help me.

                                I place bets and when its all done i want to know how much i made or lost on that market.

                                How do I do that ?

                                Thanks

                                Comment

                                Working...
                                X