Using VB2008 to acccess the Betfair API: A tutorial

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • JayBee
    Junior Member
    • Oct 2010
    • 114

    #511
    Casting types in datagridview cells

    I would like to be able to pass the value of a datagridview cell to your PlaceBet function for speed rather than fiddling with nudges and text boxes.

    However, as Betfair require odds to be decimals, I am finding it impossible to pass the value in a cell to the PlaceBet function.

    eg. layOdds = SelectedGrid.Item("Back", e.RowIndex)

    Attempts I make at type casting gives me errors.

    Any ideas?

    Comment

    • Mumbles0
      Junior Member
      • Jan 2009
      • 240

      #512
      JayBee,
      Try:
      Dim layOdds as Decimal

      layOdds = SelectedGrid.Item("Back", e.RowIndex).Value

      Comment

      • JayBee
        Junior Member
        • Oct 2010
        • 114

        #513
        I'm such a bonehead. I left .Value off the end.

        I need a rest. I've been working on this project for two months.

        Comment

        • Mumbles0
          Junior Member
          • Jan 2009
          • 240

          #514
          It never ends..

          Comment

          • sandstormed
            Junior Member
            • Dec 2010
            • 2

            #515
            Exception error with C#

            Hi, love the sample, but I'm stuck when I run it in C#.
            Print("*** Logout ***");
            BFGlobal.LogoutReq oLogoutReq;
            oLogoutReq = new BFGlobal.LogoutReq();
            BFGlobal.LogoutResp oLogoutResp;
            oLogoutResp = new BFGlobal.LogoutResp();
            oLogoutReq.header = oHeaderGL;
            oLogoutResp = BetfairGL.logout(oLogoutReq);//Call the API

            When calling the API I get
            Nullreference exception
            Object reference not set to an instance of an object.
            The header has a session token in it, so I don't know what the problem is.

            Oops, my bad, ignore this message, I forgot to put in:
            BetfairGL = new BetFair.BFGlobal.BFGlobalService();

            For anyone else who might be using C#, I found the following code handy during this tutorial (because you can't use ReDim in C#):
            int?[] tempReDim = new int?[1];
            //For horse racing
            tempReDim[0] = 7;
            string[] tempReDim2 = new string[2];
            tempReDim2[0] = "GBR";
            tempReDim2[1] = "ZAF";
            oMarketsReq.eventTypeIds = tempReDim;
            oMarketsReq.countries = tempReDim2;

            As a final point to anyone programming this in C#:
            private void bPrices_Click(object sender, EventArgs e)
            {
            Print("*** Prices ***");
            BetFairUK = new BetFair.BFUK.BFExchangeService();
            BFUK.GetMarketPricesReq MpricesReq2;
            MpricesReq2 = new BFUK.GetMarketPricesReq();
            MpricesReq2 = MpricesReq();
            ShowMprices(BetFairUK.getMarketPrices(MpricesReq2) );
            }

            Also see http://forum.bdp.betfair.com/showthread.php?t=173
            Last edited by sandstormed; 17-12-2010, 12:50 AM. Reason: added some notes

            Comment

            • JayBee
              Junior Member
              • Oct 2010
              • 114

              #516
              How would you go about passing a whole CompleteMarketPrices array for a single selectionId to another Class that I have built to handle a ladder price grid.

              I think I need to send Lgrid.update(oMarketPrices.runnerInfo)

              but because the RunnerInfoType is in Unpack2 I can't see it in my LadderGrid class.

              Comment

              • Mumbles0
                Junior Member
                • Jan 2009
                • 240

                #517
                Passing an array element

                JayBee,

                To pass the an element of the oRunnerPrices.runnerInfo array into the update method of your LadderGrid class you declare a parameter, say runnerData as RunnerInfoType like this:

                Code:
                Class LadderGrid
                    ..........
                
                    Sub update(ByVal runnerData As RunnerInfoType)
                      ..........
                
                    End Sub
                    ..........
                
                  End Class
                You can call this method like this:

                Code:
                Dim Lgrid As New LadderGrid
                ........
                
                Lgrid.update(oMarketPrices.runnerInfo(r))
                with r = the index within the runnerInfo array for your selection of interest. This passes the array element into the method where it is represented by the variable runnerData.

                Depending on where you put class LadderGrid you may get this compiler error:

                'runnerData' cannot expose type 'Unpack2.RunnerInfoType' outside the project through class 'LadderGrid'.
                You can fix this by declaring module Unpack2 as Public:

                Public Module Unpack2

                Comment

                • JayBee
                  Junior Member
                  • Oct 2010
                  • 114

                  #518
                  Thanks for the help Mumbles. Everything works fine.

                  Though I did discover that VB2010 does not know that 1 + (count * 0.01) = 1.14 where count = 14.

                  I use that algorithm to build the odds column of my ladder grids.

                  For hours I could not understand why the 1.14 odds was not being updated with the latest amount available.

                  Eventually, I tried checking if the cell whose odds were >1.13 and <1.15 needed updating and it worked.

                  I now use rounding to ensure that 1.14 on a datagrid actually is 1.14 and not 1.1400000000000000000000000000000000001 or whatever the computer thought it was.

                  Everything works but being the Free API I am not so happy with the speed for trading close to the off. Also, there are quite a few API errors now and the ladder grids go blank too. I guess I am trying to do things afore the response comes back from the Async requests.

                  I will use what I have coded through your excellent series for earlier algorithmic trading and stick to something like The Geeks Toy should I be foolhardy enough to trade closer to the off.

                  Thanks for everything.

                  Originally posted by Mumbles0 View Post
                  JayBee,

                  To pass the an element of the oRunnerPrices.runnerInfo array into the update method of your LadderGrid class you declare a parameter, say runnerData as RunnerInfoType like this:

                  Code:
                  Class LadderGrid
                      ..........
                  
                      Sub update(ByVal runnerData As RunnerInfoType)
                        ..........
                  
                      End Sub
                      ..........
                  
                    End Class
                  You can call this method like this:

                  Code:
                  Dim Lgrid As New LadderGrid
                  ........
                  
                  Lgrid.update(oMarketPrices.runnerInfo(r))
                  with r = the index within the runnerInfo array for your selection of interest. This passes the array element into the method where it is represented by the variable runnerData.

                  Depending on where you put class LadderGrid you may get this compiler error:

                  'runnerData' cannot expose type 'Unpack2.RunnerInfoType' outside the project through class 'LadderGrid'.
                  You can fix this by declaring module Unpack2 as Public:

                  Public Module Unpack2

                  Comment

                  • Mumbles0
                    Junior Member
                    • Jan 2009
                    • 240

                    #519
                    Price increments and rounding

                    Rounding is often required after an arithmetic calculation. For price data I prefer to use type Decimal, rather than Double, because it is less prone to round off error.

                    This may be of interest. A function to return the nominal Betfair price for a given increment number. For example, 1 returns 1.01, 2 returns 1.02, ... 117 returns 2.34, ... 350 returns 1000.

                    Code:
                    Friend Const Nfpi = 1     'First price increment (for 1.01)
                    Friend Const Nlpi = 350   'Last price increment (for 1000)
                    
                    Function IncToPrice(ByVal Inc As Integer) As Decimal
                    
                      Select Case Inc
                        Case Is < 100
                          Return 1 + Inc * 0.01
                        Case Is < 150
                          Return 2 + (Inc - 100) * 0.02
                        Case Is < 170
                          Return 3 + (Inc - 150) * 0.05
                        Case Is < 190
                          Return 4 + (Inc - 170) * 0.1
                        Case Is < 210
                          Return 6 + (Inc - 190) * 0.2
                        Case Is < 230
                          Return 10 + (Inc - 210) * 0.5
                        Case Is < 240
                          Return 20 + (Inc - 230)
                        Case Is < 250
                          Return 30 + (Inc - 240) * 2
                        Case Is < 260
                          Return 50 + (Inc - 250) * 5
                        Case Else
                          Return 100 + (Inc - 260) * 10
                      End Select
                    
                    End Function
                    And the inverse function to return the increment number for a given price:

                    Code:
                    Function PriceToInc(ByVal Price As Decimal) As Integer
                    
                      Select Case Price
                        Case Is < 1D
                          Return 0
                        Case Is < 2D
                          Return (Price - 1D) * 100    
                        Case Is < 3D
                          Return 100 + (Price - 2D) * 50  
                        Case Is < 4D
                          Return 150 + (Price - 3D) * 20   
                        Case Is < 6D
                          Return 170 + (Price - 4D) * 10   
                        Case Is < 10D
                          Return 190 + (Price - 6D) * 5  
                        Case Is < 20D
                          Return 210 + (Price - 10D) * 2   
                        Case Is < 30D
                          Return 230 + (Price - 20D)       
                        Case Is < 50D
                          Return 240 + (Price - 30D) \ 2
                        Case Is < 100
                          Return 250 + (Price - 50D) \ 5
                        Case Else
                          Return 260 + (Price - 100D) \ 10
                      End Select
                    
                    End Function
                    These functions are useful when building ladders or plotting.

                    Comment

                    • Monairda
                      Junior Member
                      • Jan 2009
                      • 32

                      #520
                      How to remove from collection one market suspended or closed?

                      Originally posted by Monairda View Post
                      Thank you very much Mumbles0

                      If I understand correctly, what you do is select the varialbe MarketNo market position within the collection, right?

                      And if you want to refresh 6 markets every second?
                      Do not give me the solution I will try it and you wonder if the solution is correct!



                      Another question, how I can remove from the collection a market that has been closed?

                      Let me explain:
                      When the application is monitoring the market is removed from the collection (mymarkets) if the last matched price of any horse has reached 1.01, but sometimes the last matched price does not reach the 1.01 and remains at 1.05 or 1.03 or 1.10 etc ...

                      I use this code, when the market is closed, but the .marketid is equals to zero and I do not know how to identify the market to close

                      Code:
                      [COLOR="Gray"]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
                                          [COLOR="Black"]ElseIf .errorCode = BFUK.GetMarketTradedVolumeCompressedErrorEnum.EVENT_CLOSED Then
                                              If MyMarkets.Contains(.marketId) Then            'The MarketForm is open
                                                  MyMarkets.Remove(.marketId)
                                              End If[/COLOR]
                                         Else
                                              Print("ErrorCode = " & .errorCode.ToString)
                                          End If
                                      End With
                                  End If
                              Catch ex As ApplicationException  'If problem
                                  Print(ex.Message)
                              End Try
                      
                          End Sub[/COLOR]

                      Any suggestions?

                      Thank you very much for your help

                      Good morning

                      Mumbles, sorry but I can not find the solution. When I am monitoring the market and the market is suspended or closed, the value of .marketid is zero and I can not remove it from the collection (mymarkets)

                      Any suggestions?


                      Thanks!

                      Comment

                      • Mumbles0
                        Junior Member
                        • Jan 2009
                        • 240

                        #521
                        Your Trading App

                        Monkeymagix,

                        Partial matches

                        You are writing the book on this subject. Keep up the good work.

                        You’ve introduced a new term: “partial cancellation”. Isn't this when you cancel the unmatched portion of a partially-matched bet?

                        As I see it you can view a partially matched bet as being a single compound bet with one unmatched part, and one or more matched parts. You could devise a bet object, possibly containing a list to hold the components. How you hold this in a database I will leave up to you.

                        Alternatively you could consider each portion as being a separate bet. You could extend the betId to provide a unique identifier (i.e. key).

                        Market Status

                        To monitor prices you are possibly calling getMarketPricesCompressed or getCompleteMarketPricesCompressed. These calls both return a marketStatus parameter which will tell you if your market is currently active, closed, or whatever.

                        Comment

                        • Mumbles0
                          Junior Member
                          • Jan 2009
                          • 240

                          #522
                          Identifying the target market

                          Monairda,

                          To determine a response’s market it might be better to use some other market identifier, rather than rely on the marketId parameter in the response object because, as you’ve observed, the marketId may sometimes be zero (or non-existent). We can use the UserState object in the async call for this.

                          For this we require the class UserState:

                          Code:
                          Class UserState
                            Property Param As Object
                            Sub New(ByVal Value As Object)
                              Param = Value
                            End Sub
                          End Class
                          Because we may use this class for other purposes, I suggest you put it in a module, say Module Unpack2.

                          Change sub GetMarketData so that we send a reference to the target MarketForm in the UserState object of the async calls (instead of StateCount):

                          Code:
                          [COLOR="Gray"]Private Sub GetMarketData()
                            Dim Market As MarketForm
                          
                            If MyMarkets.Count > 0 Then  'There are markets selected
                          
                              MarketNo += 1   'Next market 
                              If MarketNo > MyMarkets.Count Then MarketNo = 1 'All markets done, start again
                              Market = MyMarkets(MarketNo)
                              Market.CallCount = 0  'Clear the call counter
                          
                              Dim oMPCreq As New BFUK.GetMarketPricesCompressedReq
                              With oMPCreq
                                .header = oHeaderUK()
                                .marketId = Market.MarketId
                              End With
                              BetFairUK.getMarketPricesCompressedAsync(oMPCreq, [COLOR="Black"]New UserState(Market)[/COLOR])  'Call the API
                          
                              Dim oMTVCReq As New BFUK.GetMarketTradedVolumeCompressedReq      'The request object
                              With oMTVCReq
                                .header = oHeaderUK()
                                .marketId = Market.MarketId
                              End With
                              BetFairUK.getMarketTradedVolumeCompressedAsync(oMTVCReq, [COLOR="Black"]New UserState(Market)[/COLOR])    'Call the API
                          
                            End If
                          
                          End Sub[/COLOR]
                          In the callback event handlers we reconstruct the MarketForm reference from the UserState object and, using this reference, update the price and volume data as before:

                          Code:
                          [COLOR="Gray"]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)
                                  [COLOR="Black"]Dim Market As MarketForm = e.UserState.Param   'A reference to the form for this market[/COLOR]
                                  If .errorCode = BFUK.GetMarketPricesErrorEnum.OK Then
                          
                                    Dim oMarketPrices As New UnpackMarketPricesCompressed(.marketPrices)  'Unpack the prices
                                    [COLOR="Black"]Dim Key As String = Market.MarketId    'The key for this market[/COLOR]
                                    If MyMarkets.Contains(Key) Then             'The MarketForm is open
                                      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)
                                  [COLOR="Black"]Dim Market As MarketForm = e.UserState.Param   'A reference to the form for this market
                                  Dim Key As String = Market.MarketId      'The collection key for this market[/COLOR]
                                  If .errorCode = BFUK.GetMarketTradedVolumeCompressedErrorEnum.OK Then
                          
                                    Dim oTradedVolume As New UnpackMarketTradedVolumeCompressed(.tradedVolume)  'Unpack the traded volumes
                                    If MyMarkets.Contains(Key) Then            'The MarketForm is open
                                      Market.TradedVolumeReceived(oTradedVolume)  'Process the volume response
                                    End If
                          
                                  [COLOR="Black"]ElseIf .errorCode = BFUK.GetMarketTradedVolumeCompressedErrorEnum.EVENT_CLOSED Then
                                    If MyMarkets.Contains(Key) Then Market.Close() 'Close the form for this market[/COLOR]
                          
                                  Else
                                    Print("ErrorCode = " & .errorCode.ToString)
                                  End If
                                End With
                              End If
                            Catch ex As ApplicationException  'If problem
                              Print(ex.Message)
                            End Try
                          
                          End Sub[/COLOR]
                          When the market closes, getMarketTradedVolumeCompressed returns the EVENT_CLOSED status in errorCode. When this occurs the corresponding MarketForm is closed. The MarketForm_FormClosing event now fires, removing the form’s reference from the MyMarkets collection.

                          Comment

                          • John_The_Greek
                            Junior Member
                            • Nov 2010
                            • 6

                            #523
                            Multiple selections

                            Hello to all members of this community.

                            I'm absolutelly new to vb.net programming (i used vba until now) and it is amazing how much knoledge i get from this forum.

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

                            Mubles0 i want your opinion for a project i want to build.

                            I'm looking to build a bot that takes horse selections (from different races) from a table early in the morning and then place bets if all conditions apply.

                            The bots starts in the morning and checks lets say every 30 minutes if conditions for every selection apply. If so then places a bet and forgets the specific selections. The prices in every check must recorded to a DB table.
                            This procedure continues until all bets are placed or the markets are closed.

                            If it is not much trouble for you i'd like your opinion about the approach i sould use to implement this project.

                            Should i use timers for every selection? Is it possible to build timers dynamically every day?


                            Regards

                            John

                            Comment

                            • Monairda
                              Junior Member
                              • Jan 2009
                              • 32

                              #524
                              Identifying the target market

                              Thank you very much Mumbles0

                              You are a great help to us.

                              Comment

                              • Mumbles0
                                Junior Member
                                • Jan 2009
                                • 240

                                #525
                                Reply to John_The_Greek

                                John,

                                I don't really know what you've got in mind. I keep saying this: it’s up to you to devise you own strategy. It’s your app!

                                To monitor markets every 30 minutes seems fairly slow to me. A typical app would look at market info far more frequently than this. But if that’s what you want then do it by all means.

                                A project can have any number of timers which can be individually controlled as you wish. I prefer having a single sample timer which looks at the current time day (using the Now method) at regular intervals, initiating tasks according to some type of schedule.

                                Comment

                                Working...
                                X