Using VB2008 to acccess the Betfair API: A tutorial

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

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

    Leave a comment:


  • Mumbles0
    replied
    It never ends..

    Leave a comment:


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

    Leave a comment:


  • Mumbles0
    replied
    JayBee,
    Try:
    Dim layOdds as Decimal

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

    Leave a comment:


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

    Leave a comment:


  • monkeymagix
    replied
    Fixed

    Also just to let you know I have fixed the session issue.

    It was purely because I was calling the Logout function when I shouldn't have been!

    Thanks

    Leave a comment:


  • monkeymagix
    replied
    Backend Logic

    Okay cheers for your help I will debug the session values some more as it must just be a bug somewhere.

    Regarding the "ideal solution" I know there is never going to be a one size fits all solution and the API is so big that you can do so many actions in any order and I am not expecting you to provide me with one.

    What would be nice though (and this might be pie in the sky thinking as well) but obviously betfairs own website has a certain logical order to the actions that are needed to be carried out when you say place a bet or cancel a bet and it would be nice to find out the correct steps for each somehow.

    For example my bot placed a bet earlier today which was unmatched however as it got nearer to the race my logic decreed that it would cancel the bet and then reset the price so that it had more chance of being taken.

    On cancelling the bet the size matched was > 0 which meant that only a partial cancellation was carried out. This is a similar issue to partial matches and it would be nice to know how to handle these types of situations as with partial matches both the Cancelled part of the bet and the Matched part have the same BetID (same with settled and cancelled).

    I have found that using a GetBetStatus function and passing in the betID will return a status of Settled once the race is over but I have not managed to find the status returned with a partial cancellation before the race ( although I expect it was C as my database record had that status code stored)

    I guess I am not really asking for help with the front end logic as your API tutorial does a good job of explaining all those parts but I am wondering if you know of any guides or documentation that have been written or publicly available that specifically look at the backend database structure that would be ideal for a betfair application.

    Something that would detail the entity relationships between bet objects e.g ONE BET can have MANY BET PARTS and so on.

    Also on another point a lot of UK races were abandoned today (like the last couple of weeks) due to frozen ground and I had a lot of voided bets.

    As I am storing the selectionID and marketID in my DB on the earliest possible opportunity so that I don't have to keep unpacking markets it means I have lots of pending bets that are trying to be placed on cancelled markets. I know that once a market has been cancelled the marketID will be 0 but I don't want to have to look up selections and markets on each job as 99% of the time it will just be pointless requests that mean I keep reaching the API throttle limit.

    I am thinking about having a new job just to check the market is still active that would be run once an hour or so but I was wondering if there was another quicker way to check whether a market was still available which I could use by passing in my existing market ID.

    Thanks for all your help

    Leave a comment:


  • Mumbles0
    replied
    Your Trading App

    MonkeyMagix,

    Looks like I’m the only one who will talk to you, but I’m still not exactly sure what you are seeking.

    Bet placement is an important part of your strategy. The API provides the tools to place, modify, monitor and delete bets. It’s up to you to decide how to go about this. There is no “standard”, or “ideal” procedure. It’s your call!

    Your thoughts on session token persistence seem to be a bit wide of the mark. I (and presumably other users) have no problem with this. If I don’t log out, my session token usually remains current for a day or so. It looks like you’ve got a classic bug.

    Leave a comment:


  • monkeymagix
    replied
    Market Stabs, Sessions and Security

    Hi Mumbles

    Sorry for posting c# code here but I have tried starting a couple of C# threads but haven't received a single reply e.g

    http://forum.bdp.betfair.com/showthread.php?t=1056
    http://forum.bdp.betfair.com/showthread.php?t=1038

    You are correct in that I am having "stabs" at the market and maybe I don't need to when placing the LAY part of a trade bet. The reason I cancel after the WIN part is so that I set the LAY bets boundaries up correctly as there is no point in trading if both parts don't cover each over and I have been stung a couple of times because of partial matches on the WIN bet which meant the corresponding LAY bet boundaries (e.g size) was set incorrectly.

    I am trying to make my front end console app into a "dumb" front end as all the business logic that handles selections, bet types and prices is done in the back end. I just want the front end to literally pick up a list of bets to either check the status of or place and then do the job correctly updating the DB once the action is complete. In this regards it would be very nice to come up with an ideal logical flow for placing, cancelling and managing bets and it does seem that Betfair is lacking slightly in this regards which is why your tutorial is really my only port of call.


    Regarding the Session issue I am using the following test harness.


    Code:
    public void TestSession()
    {
    
         // this will load up the session value from the text file
         BetfairBot betfair = new BetfairBot();
    
         // using your standard keep alive function (see code I attached last time)
         betfair.KeepAlive();
    
         try
         {
    	 double balance = betfair.GetAccountBalance();
    
    	 Program.ShowMsg("Got Account Balance using last session value: " + balance.ToString());
         }
         catch (Exception e)
         {
    	 Program.ShowMsg("Failed to get Account Balance with last session value - login now");
    
    	 string betfairPassword = GetPassword("myencrypedpassword");
    	 string betfairLogon = DecodeFrom64("myencrypedlogin");
    
    	 Program.ShowMsg("Login for account: " + betfairLogon + " - password: " + betfairPassword);
    
    	 // login
    	 if (betfair.Login(betfairLogon, betfairPassword))
    	 {
    	     Program.ShowMsg("Logged In");
    	 }
    	 else
    	 {
    	     Program.ShowMsg("Not Logged In");
    
    	     return;
    	 }
         }
         finally
         {
    	 Program.ShowMsg("Save Session and Logout");
    
    	 betfair.SaveSession();
    
    	 betfair.Logout();
         }
    
         Program.ShowMsg("Completed Test");             
    }
    
    public double GetAccountBalance()
    {
        double AccountBalance = 0;
    
        BFUK.GetAccountFundsReq AccountReq = new BFUK.GetAccountFundsReq();
        BFUK.GetAccountFundsResp AccountResp = new BFUK.GetAccountFundsResp();
    	
        // check header is still valid
        AccountReq.header = oHeaderUK();
    
        AccountResp = BetfairUK.getAccountFunds(AccountReq);
    
        // check for valid response (fails without a session)
        CheckHeader(AccountResp.header);
    
        // this doesnt run with no session
        if (AccountResp.errorCode == BFUK.GetAccountFundsErrorEnum.OK)
        {
    	AccountBalance = AccountResp.availBalance;
    
    	Program.ShowMsg("Successfully got available balance: " + AccountBalance.ToString());
        }
    
        return AccountBalance;
    }
    And I get this debug

    Start BetfairBot
    Start Betfair Bot Job: TEST
    Test Session
    Set session value to U2q6Hx/Bvz+U8is3lu9WJL/rREdrUEDWbyuH6rrZSos= saved from last visit
    KeepAlive
    HeaderCode = NO_SESSION
    Got Account Balance using last session value: 0
    Save Session and Logout
    Error saving session value to text file: Object reference not set to an instance of an object.
    Logout
    HeaderCode = NO_SESSION
    ErrorCode = API_ERROR
    Completed Test
    Test Session Complete
    End BetfairBot


    Note that the Catch in the Try/Catch doesn't actually get run as no error is raised in the GetAccountBalance method. However as there is no session the amount returned is 0 and you can see the HeaderCode = NO_SESSION error message that is returned by the API when I try to check the AccountReq.header value.

    Also notice the Object reference not set error which happens when I try to save the session value back to the text file.

    I guess I am going wrong somewhere but cannot spot where at the moment.

    Just thinking aloud here >> It wouldn't be some kind of internal security Betfair has implemented to prevent XSS hacks and session hijacking would it? Maybe they can spot that I am using a console application and not a browser and preventing session re-use for those reasons? If you can literally take a string and then use it to re-open a previous session then there could be serious issues regarding security as if I could obtain someone else's session value somehow I could access their betfair account without their knowledge.

    Thanks for your help.

    Leave a comment:


  • Monairda
    replied
    Limiting Data Request

    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

    Leave a comment:


  • Mumbles0
    replied
    Limiting data requests

    Monairda,

    Putting the main thread to sleep is no good. I think it’s better to do it this way.

    I have made a few changes to Sub GetMarketData. Instead of updating all markets every 5 sec, try updating each market in turn every 1 sec. Change your timer’s Interval to 1000 to call Sub GetMarketData every second.

    Code:
    [COLOR="Gray"]Friend MyMarkets As New Collection  'The markets of interest
    [COLOR="Black"]Private MarketNo As Integer    'The market index[/COLOR]
    
    Private Sub GetMarketData()
      Dim Market As MarketForm
    
      [COLOR="Black"]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)[/COLOR]
    
        Market.CallCount = 0  'Clear the call counter
    
        Dim oMPCreq As New BFUK.GetMarketPricesCompressedReq
        With oMPCreq
          .header = oHeaderUK()
          .marketId = Market.MarketId
        End With
        StateCount += 1
        BetFairUK.getMarketPricesCompressedAsync(oMPCreq, StateCount)  'Call the API
    
        Dim oMTVCReq As New BFUK.GetMarketTradedVolumeCompressedReq      'The request object
        With oMTVCReq
          .header = oHeaderUK()
          .marketId = Market.MarketId
        End With
        StateCount += 1
        BetFairUK.getMarketTradedVolumeCompressedAsync(oMTVCReq, StateCount)    'Call the API
    
      [COLOR="Black"]End If[/COLOR]
    
    End Sub[/COLOR]
    This Sub now makes the API calls for each market in turn. When all markets are done the cycle repeats. This means that if, for example, 3 markets are selected, each market is updated every 3 sec.

    Doing it this way means that getMarketPricesCompressed and getMarketTradedVolumeCompressed are each called 60 time per sec, so you shouldn’t get EXCEEDED_THROTTLE. Also, only 2 API calls are made each second, well within the 20 calls/sec limit.

    Leave a comment:


  • Monairda
    replied
    Originally posted by Mumbles0 View Post
    Monairda,

    That's a very brutal approach. You are freezing your program for 1 sec if you open more than 15 markets. Does this work?

    I would be interested to know a bit more about your project:
    • Are you using the Free or Full API?
    • Is the code you've posted being called from a timer Tick? If so, what is the time interval?
    Hi Mumbles0

    I use the free API, I followed all the steps you've taken in the tutorial and there is a timer that has a refresh interval of 5 seconds. I am understanding what I do is to distribute the calls in those 5 seconds, right?

    Code:
    Friend MyMarkets As New Collection 'The Markets of Interest
    What makes the application is to cover the entire collection mymarkets every 5 seconds, but the problem is that if the collection has more than 10 markets over the limit of 20 calls per second.

    Thanks!!

    Leave a comment:


  • Mumbles0
    replied
    Limiting data requests

    Monairda,

    That's a very brutal approach. You are freezing your program for 1 sec if you open more than 15 markets. Does this work?

    I would be interested to know a bit more about your project:
    • Are you using the Free or Full API?
    • Is the code you've posted being called from a timer Tick? If so, what is the time interval?

    Leave a comment:


  • Monairda
    replied
    How to control the number of data requests ?

    As always thank you very much Mumbles0

    So not to exceed the limit of 20 calls per second, could put a counter between calls, and if it reaches 15 wait a second?


    Code:
    Dim Market As MarketForm
    Dim counter As Int16 = 0
    
    For Each Market In MyMarkets
                counter + = 1
                If counter > 15 Then
                    System.Threading.Thread.Sleep(1000)
                    counter= 0
                End If
    
    
                Market.CallCount = 0  'Clear the call counter
    
                Dim oMPCreq As New BFUK.GetMarketPricesCompressedReq
                With oMPCreq
                    .header = oHeaderUK()
                    .marketId = Market.MarketId
                End With
                StateCount += 1
                BetFairUk.getMarketPricesCompressedAsync(oMPCreq, StateCount)  'Call the API
                
    
                Dim oMTVCReq As New BFUK.GetMarketTradedVolumeCompressedReq      'The request object
                With oMTVCReq
                    .header = oHeaderUK()
                    .marketId = Market.MarketId
                End With
                StateCount += 1
                BetFairUk.getMarketTradedVolumeCompressedAsync(oMTVCReq, StateCount)    'Call the API
                
            Next
    Sorry if this solution is not good
    Thanks!

    Leave a comment:


  • Mumbles0
    replied
    Data request charges

    Monairda,

    While it is possible to exceed the 20 calls/second limit with the Free API, the problem mainly affects users of the Full Access API. The charges are explained here if you can understand this.

    The main point is you may be charged if you exceed 20 API calls per second, also if you place or edit more than 1000 bets in an hour. If you don’t like this it’s up to you to ensure that your application stays below these limits.

    Let’s say you have a multi-market app and, for each market, you make calls to getMarketPricesCompressed and getMarketTradedVolumeCompressed at regular intervals from a timer Tick event, i.e. 2 API calls per market.

    If your sampling time interval is 1 sec, then you can look at up to 10 markets at once
    i.e. 10 markets x 2 calls each = 20 calls in 1 sec

    If your sampling time interval is 2 sec, then you can look at up to 20 markets at once
    i.e. 20 markets x 2 calls each = 40 calls in 2 sec
    etc...

    If you are operating close to the limit you should also leave a bit of headroom for other calls (placeBets, etc).

    The StateCount variable is used for something else (it prevents an async call error). You could implement a simple call limiting scheme using a call counter, but I don’t think it would be very satisfactory.

    Leave a comment:

Working...
X