Using VB2008 to acccess the Betfair API: A tutorial

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

  • Mumbles0
    replied
    Your Trading App

    Monkeymagix,

    Problem: Missing bet status.

    I have followed your suggestion about leaving bets on the market rather than having a stab and then cancelling straight after however I have noticed that on a number of occasions my bet doesn't get accepted even with a status of unmatched (U). I haven't found any kind of pattern to this and sometimes my bets will get matched and I get a status of M and a BetID, sometimes they get taken as unmatched e.g I get a BetID and a status code of U and sometimes I won't get anything e.g no status and no BetID. The code I am using is exactly the same so I am a little unsure as why this is occurring as I am not experiencing any errors during the placement of the bet.
    If I can have a guess: Perhaps you are sending the status request too soon after placing a bet. A finite amount of time is required for the exchange to process the bet and for the resulting status to be sent to the server which handles your bet status request.

    If you request the status too early, the info for the bet you have just placed might not appear in the bet status response.

    Leave a comment:


  • davecon
    replied
    Bet Change

    Update WIN BET Status for BetID: 13154626462 - Skippers Brig - Leopardstown - Dec 29 2010 2:30PM; Bet Status: M; System Status: BET PLACED; Matched Amount: 2.80; Matched Price: 12.50; Liability: 0.00; 2010-12-29 09:37:03.370


    Update WIN BET Status for BetID: 13154626462 - Skippers Brig - Leopardstown - Dec 29 2010 2:30PM; Bet Status: M; System Status: BET PLACED; Matched Amount: 2.80; Matched Price: 11.80; Liability: 0.00; 2010-12-29 11:00:03.463

    Am I missing something?[/QUOTE]

    Hi Monkey
    As your bet is showing Odds of 11.80 (Not allowable odds) then this must have been subject to the Dreaded Reduction Factor after a Non-Runner - Were any other unmatched bets you had in this Market also Cancelled? - You will have to look into this regarding your Program as well because all these prices must also be subject to the Reduction Factor if not
    It makes matters worse when Betfair do not even meter this reduction factor - Timeform do it apparently
    I cant help you with the Programming I'm afraid as I am just working through this great course from Mumbles
    (I will certainly have to later)
    Hope this Helps
    Dave

    Leave a comment:


  • monkeymagix
    replied
    Change in match price

    I had something odd happen today with one of my bets that I am trying to find an explaination for.

    I placed a To WIN bet on a horse at 9.37 am and it was matched at a price of 12.80.

    My bot then checks the status of all open bets every half hour in case their status changes, they are pulled out or the meeting is cancelled etc.

    However at 11.00am when I checked the status of this bet the matched price had changed from 12.80 to 11.80.

    I could understand if the bet had been given a betPersistenceType of SP and the price changed at the race time but it wasn't and the matched price changed well over 3 hours before the race. Also the full desired amount was matched so it wasn't as if the bet was matched in chunks e.g multiple partial matches.

    I haven't seen this happen before and it messed up my LAY as the the Max LAY Price was set to high to offset the WIN bet.

    Can anyone think of a possible reason why the matched price would change like this and how I could find out what had happened now that the bet has been settled.

    The details from my log file are blow

    Update WIN BET Status for BetID: 13154626462 - Skippers Brig - Leopardstown - Dec 29 2010 2:30PM; Bet Status: M; System Status: BET PLACED; Matched Amount: 2.80; Matched Price: 12.50; Liability: 0.00; 2010-12-29 09:37:03.370


    Update WIN BET Status for BetID: 13154626462 - Skippers Brig - Leopardstown - Dec 29 2010 2:30PM; Bet Status: M; System Status: BET PLACED; Matched Amount: 2.80; Matched Price: 11.80; Liability: 0.00; 2010-12-29 11:00:03.463

    Am I missing something?

    Leave a comment:


  • monkeymagix
    replied
    Unmatched bets

    Hi Mumbles

    Hope you had a nice Xmas and a break from coding / betting for a while due to all the abandoned race meetings.

    Your correct in that my term "partial cancellation" just means that I went to cancel an unmatched bet only for part of the bet to be matched in that split second. Therefore only a portion of the total amount I wanted to cancel was actually cancelled. The issue lies in the fact that Betfair uses the same BetID to refer to all parts of a bet rather than having say a Parent ID and then Bet Segment IDs for each matched, unmatched, settled or cancelled portion. This makes identifying the exact status of a bet quite tricky from the BetID alone.

    I have a couple of questions

    I have followed your suggestion about leaving bets on the market rather than having a stab and then cancelling straight after however I have noticed that on a number of occasions my bet doesn't get accepted even with a status of unmatched (U). I haven't found any kind of pattern to this and sometimes my bets will get matched and I get a status of M and a BetID, sometimes they get taken as unmatched e.g I get a BetID and a status code of U and sometimes I won't get anything e.g no status and no BetID. The code I am using is exactly the same so I am a little unsure as why this is occurring as I am not experiencing any errors during the placement of the bet.

    Also I noticed today that a load of my bets were not placed due to Ffos Las not being in the Timeform racecourse abbreviation CSV file. I have tried looking on the web for the code but cannot find anything and I am guessing at the moment that it is either Ffos or Ffl however I cannot test this out as there are no races at that course tomorrow and the compressed market data only contains races in the future. I don't suppose you know the code?

    Thanks

    Leave a comment:


  • John_The_Greek
    replied
    Thanks mubles0

    Leave a comment:


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

    Leave a comment:


  • Monairda
    replied
    Identifying the target market

    Thank you very much Mumbles0

    You are a great help to us.

    Leave a comment:


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

    Leave a comment:


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

    Leave a comment:


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

    Leave a comment:


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

    Leave a comment:


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

    Leave a comment:


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

    Leave a comment:


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

    Leave a comment:


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

    Leave a comment:

Working...
X