Using VB2008 to acccess the Betfair API: A tutorial

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Mumbles0
    Junior Member
    • Jan 2009
    • 240

    #751
    Step 36. Handling Excel events

    Excel can raise events which can be handled by the VB2010 project. An event indicates that something has happened within Excel, and usually originates from an Application, Workbook or Worksheet object.

    If you add the WithEvents keyword to the object variable declarations, the events associated with each object will be listed in the left-hand dropdown of the code window. You will see that there are many events. In most cases the name gives a brief description of the event.

    Code:
    [COLOR="Gray"]Private [COLOR="Black"]WithEvents[/COLOR] Exl As Application   'A variable for the Excel object
    Private [COLOR="Black"]WithEvents[/COLOR] Mbook As Workbook    'A variable for the markets workbook
    Private [COLOR="Black"]WithEvents[/COLOR] Msheet As Worksheet  'A variable for the market worksheet
    
    Private Sub ExcelEx_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
    
      ........
      ........
    
      Exl = New Excel.Application  'Launch an instance of Excel
      With Exl
        .WindowState = XlWindowState.xlNormal
        .Visible = True           'Show it
        If My.Computer.FileSystem.FileExists(MarketsFile) Then
          Mbook = .Workbooks.Open(MarketsFile)   'Open the Excel file if it exists
          [COLOR="Black"]Msheet = .ActiveSheet [/COLOR] 
        End If
      End With
    
    End Sub[/COLOR]
    Also add the line Msheet = .ActiveSheet to the Load event sub (to make this example work better).

    You handle events originating from Excel in the same way as events originating in the VB2010 project itself. For this example a handler for the Excel application’s SheetActivate event is:

    Code:
    [COLOR="Black"]Private Sub Exl_SheetActivate(ByVal Sh As Object) Handles Exl.SheetActivate
      Msheet = Exl.ActiveSheet  'Msheet refers to the active worksheet
    End Sub[/COLOR]
    This event fires whenever a new worksheet is selected. This allows the variable Msheet to keep track of the currently active worksheet.

    Now add a handler for the worksheet’s Change event:

    Code:
    [COLOR="Black"]Private Sub Msheet_Change(ByVal Target As Excel.Range) Handles Msheet.Change
    
      With Target
        If .Column = 6 Then  'A cell in column F has changed
          Print(.Offset(0, -4).Value & " " & .Offset(0, -3).Value)  'Print selectionId & name
        End If
      End With
    
    End Sub[/COLOR]
    The Change event fires whenever the contents of a cell on the currently-active worksheet changes. The Target parameter is a Range object which references the changed cell. If you manually enter something into a cell in column F, alongside the runner list, this sub should print the selectionId and name of the runner on the same line.

    Looks simple, but... if you try it you will probably get this exception when Sub Print executes:
    Cross-thread operation not valid:
    Control 'tLog' accessed from a thread other than the thread it was created on.

    As I mentioned previously, the Excel application executes on a different thread to your VB2010 project. This means that the event handlers we’ve just added also execute on the Excel application’s thread. Textbox tLog (which is used by Sub Print to log messages) belongs to the VB2010 project’s thread and raises the exception if we attempt to access it from Excel’s thread.

    There is a quick fix for this problem. Put this statement in you form’s Load event handler:

    System.Windows.Forms.TextBox.CheckForIllegalCrossT hreadCalls = False
    This turns off the system’s cross-thread checking facility and Sub Msheet_Change should now work. However, this approach is not recommended by the powers that be. Apparently it is a case of two wrongs making a right. The "proper" way of doing it is to declare a Delegate for the Print sub, then invoke this Delegate if calling from a another thread. We now revise the Print sub:

    Code:
    [COLOR="Black"]Delegate Sub PrintDelegate(ByVal Message As String)  'The delegate declaration
    
    Sub Print(ByVal Message As String)
      If tLog.InvokeRequired Then  'Call is from another thread
        Dim PrintDel As New PrintDelegate(AddressOf Printx) 'Create a delegate for Sub Printx
        Invoke(PrintDel, New Object() {Message})  'Invoke Sub Printx
      Else              'Call is from tLog's thread
        Printx(Message)     'Call Sub Printx normally
      End If
    End Sub
    
    [COLOR="Gray"]Sub [COLOR="Black"]Printx[/COLOR](ByVal Message As String)  'The existing Print sub (re-named Printx)
      With tLog
        .SelectionStart = .Text.Length
        .SelectedText = vbCrLf & Message
      End With
    End Sub[/COLOR][/COLOR]
    Here we have changed the name of the existing Print sub to Printx and added a new Sub Print. The Delegate statement is simply a template for Sub Printx, having the same "signature" i.e. number and type of calling parameters.

    Now, when Sub Print is called, the InvokeRequired property of the tLog textbox is tested to see if the call is being made on the form’s thread or on a different (i.e. Excel’s) thread. If the call is on a different thread, tLog.InvokeRequired returns True, and the delegate PrintDel is created. This delegate "represents" Sub Printx. The form’s Invoke method is now called using this delegate as an argument. This has the effect of marshalling Printx onto the form’s thread. Note that the Message parameter required by Sub Printx is passed in an Object array.

    If the call is on the form’s (i.e. tLog’s) thread then tLog.InvokeRequired returns False, and Sub Printx is called in the usual way.

    I hope this makes sense. Multithreading is a complex field with many pitfalls, and I’m no expert.

    In a typical VB2010 project your UI will consist of several controls on a form. If you intend updating these controls from event handlers driven from an Excel application, the rule is you must Invoke an updating sub via a Delegate, rather than access the control directly from Excel's thread.

    Comment

    • Hoytman999
      Junior Member
      • Jun 2011
      • 3

      #752
      Hi All,

      I'm (occasionally) getting an "INVALID_PRICE" returned by the .resultcode part of the BFUK.PlaceBetsResp object. In trying to ensure that the price requested is a valid betfair price i've used the following logic:

      Dim tempBackPrice As double
      Dim betfairBackPrice As double

      'Assign value to tempBackPrice here

      If tempBackPrice >= 1 And tempBackPrice < 2 Then betfairBackPrice = 0.01 * Math.Round(tempBackPrice / 0.01, 0)
      If tempBackPrice >= 2 And tempBackPrice < 3 Then betfairBackPrice = 0.02 * Math.Round(tempBackPrice / 0.02, 0)
      If tempBackPrice >= 3 And tempBackPrice < 4 Then betfairBackPrice = 0.05 * Math.Round(tempBackPrice / 0.05, 0)
      If tempBackPrice >= 4 And tempBackPrice < 6 Then betfairBackPrice = 0.1 * Math.Round(tempBackPrice / 0.1, 0)
      If tempBackPrice >= 6 And tempBackPrice < 10 Then betfairBackPrice = 0.2 * Math.Round(tempBackPrice / 0.2, 0)
      If tempBackPrice >= 10 And tempBackPrice < 20 Then betfairBackPrice = 0.5 * Math.Round(tempBackPrice / 0.5, 0)
      If tempBackPrice >= 20 And tempBackPrice < 30 Then betfairBackPrice = Math.Round(tempBackPrice, 0)
      If tempBackPrice >= 30 And tempBackPrice < 50 Then betfairBackPrice = 2 * Math.Round(tempBackPrice / 2, 0)
      If tempBackPrice >= 50 And tempBackPrice < 100 Then betfairBackPrice = 5 * Math.Round(tempBackPrice / 5, 0)
      If tempBackPrice >= 100 And tempBackPrice <= 1000 Then betfairBackPrice = 10 * Math.Round(tempBackPrice / 10, 0)

      Can anyone see any problems with this logic? Is there an easier way to assign a valid betfair price?

      Apologies if this has been asked/answered before but I can't find it anywhere on the forum.

      Thanks

      Comment

      • BigSprout
        Junior Member
        • Feb 2011
        • 60

        #753
        Hi Hoytman,

        Mumbles produced a couple of functions called "IncToPrice" and "PriceToInc", which I use and have never had an "Invalid_Price" error.

        I also use Decimal.Round(Cdec("MyPrice"),2) rather than Math.Round....



        Here we are Page 52, #519 (PriceToInc stuff)

        cheers

        Comment

        • Hoytman999
          Junior Member
          • Jun 2011
          • 3

          #754
          Thanks for the swift reply BigSprout,

          I'll give those a whirl sometime soon...

          Hoytman

          Comment

          • Mumbles0
            Junior Member
            • Jan 2009
            • 240

            #755
            INVALID_PRICE problems

            Hoytman999,

            I’m fairly sure floating-point rounding errors cause these problems. I prefer to use the Decimal data type (rather than Double) to hold price and amount values.

            Here's Function BFPrice. This will round any value to a valid Betfair price:

            Code:
            'Rounds to the nearest Betfair price value 
            
            Private OddsLim() As Decimal = {2, 3, 4, 6, 10, 20, 30, 50, 100}   'Odds range limits
            Private OddsInc() As Decimal = {0.01, 0.02, 0.05, 0.1, 0.2, 0.5, 1, 2, 5, 10} 'Odds increments
            
            Function BFPrice(ByVal Price As Decimal) As Decimal
              Dim i As Integer, p As Decimal
            
              For i = 0 To UBound(OddsLim)  'Determine price range
                If Price <= OddsLim(i) Then Exit For
              Next i
              p = Decimal.Round(Price / OddsInc(i), MidpointRounding.AwayFromZero) * OddsInc(i) 'Round to the nearest valid price
              Return Math.Min(Math.Max(p, 1.01D), 1000D)  'Keep within limits
            
            End Function

            Comment

            • Hoytman999
              Junior Member
              • Jun 2011
              • 3

              #756
              Reply to BigSprout and Mumbles0

              Thanks to both of you for the solutions. I've ammended my app now and it works fine.

              Thanks again,

              Hoytman

              Comment

              • Camper
                Junior Member
                • Jul 2011
                • 30

                #757
                I'm trying to place bets under 2 while greening.

                I get an error when I'm updating the size after making a bet with size 2.

                The code I'm using:
                Code:
                    Private Sub UpdateBet(ByVal Bet2Id As Long, ByVal NewPrice As Decimal, ByVal OldPrice As Decimal, ByVal NewSize As Decimal, ByVal OldSize As Decimal)
                        Dim oUpdateBetsReq As New BFUK.UpdateBetsReq
                        Dim oUpdateBetsResp As BFUK.UpdateBetsResp
                        Dim oUpdateBet As New BFUK.UpdateBets
                        With oUpdateBetsReq
                            .header = SessTok
                            With oUpdateBet
                                .betId = Bet2Id
                                .newBetPersistenceType = BFUK.BetPersistenceTypeEnum.IP
                                .oldBetPersistenceType = BFUK.BetPersistenceTypeEnum.IP
                                If stage = 1 Then
                                    .newSize = NewSize
                                    .oldSize = OldSize
                                End If
                                If stage = 2 Then
                                    .newPrice = NewPrice
                                    .oldPrice = OldPrice
                                End If
                            End With
                            ReDim .bets(0)
                            .bets(0) = oUpdateBet
                        End With
                        oUpdateBetsResp = BetFairUK.updateBets(oUpdateBetsReq)
                        With oUpdateBetsResp
                            CheckHeader(.header)
                            If .errorCode = BFUK.UpdateBetsErrorEnum.OK Then
                                For i = 0 To .betResults.Length - 1
                                    With .betResults(i)
                                        If .success Then
                                            If stage = 1 Then
                                                CancelBet2(Bet2Id)
                                                If .newBetId <> 0 Then newbetId = CLng(.newBetId)
                                            Else
                                                stage = 0
                                                TheBetId = Bet2Id
                                                GetBetStatus(markid)
                                                Checkbet.Enabled = True
                                            End If
                                        End If
                                    End With
                                Next
                            End If
                        End With
                    End Sub
                The error I'm getting:

                Comment

                • BigSprout
                  Junior Member
                  • Feb 2011
                  • 60

                  #758
                  Camper,
                  I think one of the problems may be caused by not entering all the data required in "oUpdateBet" -

                  Code:
                          If stage = 1 Then
                              .newSize = NewSize
                              .oldSize = OldSize
                             [B] .newPrice = OldPrice
                              .oldPrice = OldPrice[/B]
                          End If
                          If stage = 2 Then
                             [B] .newSize = OldSize
                              .oldSize = OldSize[/B]
                              .newPrice = NewPrice
                              .oldPrice = OldPrice
                          End If

                  Not quite sure what "CancelBet2(Bet2Id)" does, if it cancels the original bet then this is okay only if the size of the bet increases - if the new bet size is less than the original bet, then there is no new betId

                  Hope this is of some help,
                  cheers

                  Comment

                  • Camper
                    Junior Member
                    • Jul 2011
                    • 30

                    #759
                    Yes the size increases.

                    I'll try and see if your sugestion works. Thanks

                    Comment

                    • Harry Boas
                      Junior Member
                      • May 2011
                      • 2

                      #760
                      Specifying endpoint URL

                      I'm impressed by the knowledge and co-operation displayed on this thread. Perhaps somebody can help with a quick and perhaps naive question from a newbie (dinosaur) whose background lies in PL1/CICS and relational databases. VB 2010 is my first exposure to object oriented languages.

                      I am successfully accessing the free API and retrieving information but am mainly interested in the Tote API. To use that I have to specify a different endpoint URL to be used once I'm logged in. Could anybody tell me where the endpoint URL is specified ?

                      Comment

                      • ahn
                        Junior Member
                        • Jul 2011
                        • 12

                        #761
                        Time of a soccer match!!!!!

                        hi

                        Thnx for the whole vb tutorial is veryyyyyyy veryyyyyyy usefull...
                        with your help i have managed to create a trading bot... but for my strategy the time a match is needed (for example that the in-play everton-chealsea match is in its 36th minute. Do you have any idea how and if can I get this information?

                        Thanking zou in advance

                        Panos

                        Comment

                        • Harry Boas
                          Junior Member
                          • May 2011
                          • 2

                          #762
                          Originally posted by Harry Boas View Post
                          I am successfully accessing the free API and retrieving information but am mainly interested in the Tote API. To use that I have to specify a different endpoint URL to be used once I'm logged in. Could anybody tell me where the endpoint URL is specified ?
                          I found the answer by trial and error. An app.config entry was set to http://uktote-api.betfair.com/tote/v1/BFToteService rather than https://uktote-api.betfair.com/tote/v1/BFToteService

                          Comment

                          • gavvy
                            Junior Member
                            • Nov 2011
                            • 4

                            #763
                            100% cpu

                            Hello to all members of this community.

                            I read almost all the posts and i want to thank mubles0 for his excellent work.

                            I made a bot and it works fine, but there is one problem, it loads the CPU.

                            Not immediately, but after a few cycles of the search market and work on it.

                            Somehow, I think it's about timers.

                            I have two timers.First with a period of 2 seconds works inside market.Second

                            timer- with a period of 1 minute trying to find a market.

                            Аnyone encountered this problem?

                            Sorry for my google translate english.
                            Attached Files
                            Last edited by gavvy; 26-11-2011, 04:42 PM.

                            Comment

                            • gavvy
                              Junior Member
                              • Nov 2011
                              • 4

                              #764
                              Incidentally, the problem with the API and has no problems with CPU.May be thing is that I do write in a text file every 2 seconds.

                              Comment

                              • BigSprout
                                Junior Member
                                • Feb 2011
                                • 60

                                #765
                                gavvy,

                                as lines are added to a text file, it then takes a little longer to load the next time - so depending on the size, the files could be causing your problem.

                                This is easy to check by temporarily disabling the code that is calling the files then running your program again and seeing if the problem disappears

                                Code:
                                        [B][U]'Code for appending lines to file:[/U][/B]
                                        Dim sw As StreamWriter
                                        sw = File.AppendText("Path to folder\gavvy.Txt")
                                        sw.WriteLine("add a line to the end of the file")
                                        sw.Close()
                                
                                
                                        [B][U]'temporarily disable code so file is not accessed:[/U][/B]
                                
                                        'Dim sw As StreamWriter
                                        'sw = File.AppendText("Path to folder\gavvy.Txt")
                                        'sw.WriteLine("add a line to the end of the file")
                                        'sw.Close()
                                If the size of the files is the problem then you may have to look at limiting the size, alternatively you can put up your code for suggestions.

                                I am not sure of the advantages of having separate timers when one can do both tasks either.

                                cheers

                                Comment

                                Working...
                                X