How to use a horse form in betfair bot script

The bfexplorer shows for UK and Irish horse racing and data about each selection including:

  • Silks description
  • Trainer name
  • Age and Weight
  • Form
  • Days since last run
  • Jockey claim
  • Wearing text
  • Saddle cloth
  • Stall draw

Any of this information can be used by a bot script, in this article I will show you how to show the horse form and sort horses by the form and how to use the horse form information in a simple betting strategy on which I will show you how to build LookUp bot script running a trading bot.

You can see on the picture that moving the cursor over the horse name a tooltip is displayed with all that information but it would be useful to show all horses sorted by the horse form in the output window too. If a market supports additional information about each selection the SelectionData property of the selection/runner is set to the object inherited form ISelectionData interface. In the case of the horse racing market this object is represented by the class: HorseRacingSelectionData

using BeloSoft.Betfair.Data;
using BeloSoft.Betfair.Trading;
using System.Collections.Generic;

/*
 * Used parameters:
 * 
 * PlaceBetOnRunners - Show the form from last x races, if 0 sorted by all race results
 */

namespace Bfexplorer.Scripting
{
  class ShowHorsesForm : Bot
  {
    private class HorseSortedCollection : List
    {
      // Data
      private byte sortByLastRaces;

      public HorseSortedCollection(MonitoredMarket monitoredMarket)
      {
        AddRange(monitoredMarket.MarketDetails.Runners);
      }

      public void SortByForm()
      {
        Sort(SortByFormValue);
      }

      public void SortByFormFromLastRaces(byte lastRaces)
      {
        sortByLastRaces = lastRaces;

        Sort(SortByFormValueOfLastRaces);
      }

      private static int SortByFormValue(Runner x, Runner y)
      {
        float xData = GetFormValue(((HorseRacingSelectionData)x.SelectionData).HorseFormFigures);
        float yData = GetFormValue(((HorseRacingSelectionData)y.SelectionData).HorseFormFigures);

        return xData > yData ? -1 : (xData < yData ? 1 : 0);
      }

      private int SortByFormValueOfLastRaces(Runner x, Runner y)
      {
        float xData = GetFormValue(GetLastRaces(((HorseRacingSelectionData)x.SelectionData).HorseFormFigures, sortByLastRaces));
        float yData = GetFormValue(GetLastRaces(((HorseRacingSelectionData)y.SelectionData).HorseFormFigures, sortByLastRaces));

        return xData > yData ? -1 : (xData < yData ? 1 : 0);
      }

      private static string GetLastRaces(string formText, byte lastRaces)
      {
        if (!string.IsNullOrEmpty(formText))
        {
          if (formText.Length > lastRaces)
          {
            formText = formText.Substring(formText.Length - lastRaces, lastRaces);
          }
        }

        return formText;
      }

      private static float GetFormValue(string formText)
      {
        float formValue = 0.0f;

        if (!string.IsNullOrEmpty(formText))
        {
          foreach (char result in formText.ToCharArray())
          {
            if (char.IsDigit(result))
            {
              int place = (int)(result - '0');

              if (place > 0)
              {
                formValue += 9.0f / place;
              }
            }
          }
        }

        return formValue;
      }
    }

    // Const
    private const int HorseRacingEventId = 7;

    public ShowHorsesForm(IBetfairService betfairService, MonitoredMarket monitoredMarket, Runner runner)
      : base(betfairService, monitoredMarket, runner)
    {
    }

    public override void DoYourJob()
    {
      base.DoYourJob();

      if (GetHaveHorseRacingSelectionData())
      {
        HorseSortedCollection horses = new HorseSortedCollection(monitoredMarket);

        byte formForLastRaces = RunnerProperty.PlaceBetOnRunners;

        if (formForLastRaces > 0)
        {
          horses.SortByFormFromLastRaces(formForLastRaces);
        }
        else
        {
          horses.SortByForm();
        }

        horses.Reverse();

        int place = horses.Count;

        foreach (Runner horse in horses)
        {
          HorseRacingSelectionData horseRacingSelectionData = horse.SelectionData as HorseRacingSelectionData;

          AddMessage(string.Format("{0}.{1}: {2}", place--, horse.Name, horseRacingSelectionData.HorseFormFigures));
        }
      }
      else
      {
        AddMessage("No form inforamtion!");
      }

      Stop();
    }

    private bool GetHaveHorseRacingSelectionData()
    {
      MarketDetails marketDetails = monitoredMarket.MarketDetails;

      return marketDetails.EventTypeId == HorseRacingEventId && marketDetails.Runners[0].SelectionData is HorseRacingSelectionData;
    }
  }
}

If you run this bot script on a horse racing market the bot will show you sorted list of horses by the last 3 races form.

So now we can use the horse form in a simple LookUp bot script which will lay the horse with the best form from last 3 races and trade it out with 2% profit or 20% loss. This is just sample showing how to use the horse form.

using System;
using BeloSoft.Betfair.Data;
using BeloSoft.Betfair.Data.Betting;
using BeloSoft.Betfair.Data.Statistics;
using BeloSoft.Betfair.Trading;
using System.Collections.Generic;

namespace Bfexplorer.Scripting
{
  public class HorseFormSampleLookUpBot : LookUpBot
  {
    private class HorseSortedCollection : List
    {
      // Data
      private byte sortByLastRaces;

      public HorseSortedCollection(MonitoredMarket monitoredMarket)
      {
        AddRange(monitoredMarket.MarketDetails.Runners);
      }

      public void SortByForm()
      {
        Sort(SortByFormValue);
      }

      public void SortByFormFromLastRaces(byte lastRaces)
      {
        sortByLastRaces = lastRaces;

        Sort(SortByFormValueOfLastRaces);
      }

      private static int SortByFormValue(Runner x, Runner y)
      {
        float xData = GetFormValue(((HorseRacingSelectionData)x.SelectionData).HorseFormFigures);
        float yData = GetFormValue(((HorseRacingSelectionData)y.SelectionData).HorseFormFigures);

        return xData > yData ? -1 : (xData < yData ? 1 : 0);
      }

      private int SortByFormValueOfLastRaces(Runner x, Runner y)
      {
        float xData = GetFormValue(GetLastRaces(((HorseRacingSelectionData)x.SelectionData).HorseFormFigures, sortByLastRaces));
        float yData = GetFormValue(GetLastRaces(((HorseRacingSelectionData)y.SelectionData).HorseFormFigures, sortByLastRaces));

        return xData > yData ? -1 : (xData < yData ? 1 : 0);
      }

      private static string GetLastRaces(string formText, byte lastRaces)
      {
        if (!string.IsNullOrEmpty(formText))
        {
          if (formText.Length > lastRaces)
          {
            formText = formText.Substring(formText.Length - lastRaces, lastRaces);
          }
        }

        return formText;
      }

      private static float GetFormValue(string formText)
      {
        float formValue = 0.0f;

        if (!string.IsNullOrEmpty(formText))
        {
          foreach (char result in formText.ToCharArray())
          {
            if (char.IsDigit(result))
            {
              int place = (int)(result - '0');

              if (place > 0)
              {
                formValue += 9.0f / place;
              }
            }
          }
        }

        return formValue;
      }
    }

    // Const
    private const double Stake = 100;
    private const float Profit = 2.0f;
    private const float Loss = 20.0f;
    private const int PlaceBetBeforeInMinutes = 5;
    private const byte FormForLastRaces = 3;

    public HorseFormSampleLookUpBot(IBetfairService betfairService)
      : base(betfairService)
    {
    }

    public override bool DoYourJob(MonitoredMarket monitoredMarket)
    {
      if (GetIsMyMarket(monitoredMarket))
      {
        if (GetIsTheRaceXMinutesBeforeStart(monitoredMarket))
        {
          bool startMonitoring = true;
          MonitoredMarket myMonitoredMarket = betfairService.GetMonitoredMarket(monitoredMarket.MarketId);

          if (myMonitoredMarket == null)
          {
            myMonitoredMarket = monitoredMarket;
          }
          else
          {
            startMonitoring = !myMonitoredMarket.Enabled;
          }

          Runner runner = GetRunnerToBet(myMonitoredMarket);

          if (runner != null)
          {
            SetupMyBot(myMonitoredMarket, runner);

            if (startMonitoring)
            {
              betfairService.StartMonitorThisMarket(myMonitoredMarket);
            }

            betfairService.StartBot(myMonitoredMarket, runner.Id);
          }

          return false;
        }

        return true;
      }

      return false;
    }

    private bool GetIsMyMarket(MonitoredMarket monitoredMarket)
    {
      return monitoredMarket.MarketDetails.Runners[0].SelectionData is HorseRacingSelectionData;
    }

    private bool GetIsTheRaceXMinutesBeforeStart(MonitoredMarket monitoredMarket)
    {
      return DateTime.Now >= monitoredMarket.MarketDetails.MarketTime.AddMinutes(-PlaceBetBeforeInMinutes);
    }

    private Runner GetRunnerToBet(MonitoredMarket monitoredMarket)
    {
      HorseSortedCollection horses = new HorseSortedCollection(monitoredMarket);

      horses.SortByFormFromLastRaces(FormForLastRaces);

      return horses[0];
    }

    private void SetupMyBot(MonitoredMarket monitoredMarket, Runner runner)
    {
      RunnerProperty runnerProperty = runner.RunnerProperty;

      runnerProperty.BotType = BotType.PlaceBetClosePosition;
      runnerProperty.BetType = BetType.Lay;
      runnerProperty.Stake = Stake;
      //runnerProperty.StakeIsMyLiability = true;
      runnerProperty.MinimalOdds = OddsRange.MinOdds;
      runnerProperty.MaximalOdds = OddsRange.MaxOdds;
      runnerProperty.AllowPlacingBetInPlay = true;
      runnerProperty.PlaceBetAtBetterOdds = true;
      runnerProperty.MinReturnOnInvestment = Profit;
      runnerProperty.StopLossOnPercentageLiability = Loss;
    }
  }
}

How to run the bot

You can run this bot only with the Trade Opportunity Lookup Service. Your bot full class name is:

  • Bfexplorer.Scripting.HorseFormSampleLookUpBot

When writing your own bot script you need to follow these rules:

  • Your bot script must be in the MyBots directory
  • The file name of the bot script must be the same as the full class name adding the .cs extension if the bot script is written in C# or .vb for Visual Basic

You can download the source code for both bot scripts here.

Testing the bot

Comments (3)

  1. EricEllwood Says:
    Sunday, December 07, 2008

    "Horse form in bots" Posted by Eric

    I am truly amazed !...after a short question to Stefan ("Can the form figures for a race be shown and used in a bot" ?) I get an E mail saying "Yes" it can be done......and overnight an article appears in the blog explaining what can be done,how it could be done plus a fully coded bot to run and show the information,..and...a further fully coded bot giving a working example of how to use the detail for trading the Horse Racing Markets.  Needless to say the code has been  downloaded and installed on my computer and is ready to go !

  2. StefanBelo Says:
    Tuesday, December 09, 2008

    Testing

    Eric, just today I run some tests and they are quite surprising at least for today. You know that this bot is just a sample showing how to use the horse form in a bot script. This idea has maybe some profitability potential but needs to be tested couple weeks and qualifying parameters should be narrowed.

  3. EricEllwood Says:
    Sunday, December 21, 2008

    Testing and feedbck

    Have been running these bots both in practice and live mode for the past week.I have been pleasantly surprised by the results,Have run bots with small stakes yesterday and today.

    Yesterday  in live mode with small stakes bet in 13 races with profit in each race and today bet in 11 races with profit in each race.


Do you want to comment this article? Sign up here or login.