Eric’s LookUpBot bot implementation

So this is the source code for Eric’s LookUpBot bot, the project specification can be found in this article: My bot specification.

The bfexplorer pro implements two different approaches in running the bot scripts:

If you want to write your bot scripts which could be executed by the Bot Executor you need to implement your bot inheriting it from the class Bot, and override the method:

void DoYourJob()

To write a bot script for the Trade Opportunity Lookup Service you need to implement your bot inheriting it from the class LookUpBot, and override the method:

bool DoYourJob(MonitoredMarket monitoredMarket)

I will implement the Bot Executor version later just to show how it could be done in my next article.

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

namespace Bfexplorer.Scripting
{
  public class EricLookUpBot : LookUpBot
  {
    // Const
    private const byte SolutionId = 100;
    private const string SolutionName = "Eric Horse Racing Solution";
    private static string[] NotAllowedMarkets = { "Hcap", "Nursery" };
    private const double MinOddsToBack = 3.0;
    private const double MaxOddsToBack = 9.0;
    private const double MaxOddsToLay = 2.0;
    private const double Stake = 100;
    private const int StopAtLosingStreak = 4;
    private const int PlaceBetBeforeInMinutes = 1;

    // Data
    private MySolutionMarkets mySolutionMarkets;
    private RunnersSortedCollection runnersSortedCollection;

    public EricLookUpBot(IBetfairService betfairService)
      : base(betfairService)
    {
      mySolutionMarkets = betfairService.RegisterMySolution(SolutionId, SolutionName);

      runnersSortedCollection = new RunnersSortedCollection();
      runnersSortedCollection.SortByType = RunnersSortedCollection.SortType.ByLastPriceMatched;
    }

    public override bool DoYourJob(MonitoredMarket monitoredMarket)
    {
      if (GetIsMyMarket(monitoredMarket))
      {
        if (GetIsTheRaceXMinutesBeforeStart(monitoredMarket))
        {
          bool stopBetting;

          if (GetCanRunThisSolution(out stopBetting))
          {
            BetType betType;
            Runner runner = GetRunnerToBet(monitoredMarket, out betType);

            if (runner != null)
            {
              SetupMyBot(monitoredMarket, runner, betType);
            }

            return false;
          }
          else
          {
            return !stopBetting;
          }
        }

        return true;
      }

      return false;
    }

    private bool GetIsMyMarket(MonitoredMarket monitoredMarket)
    {
      string marketName = monitoredMarket.MarketInfo.Market.Name;

      foreach (string notAllowedMarket in NotAllowedMarkets)
      {
        if (marketName.Contains(notAllowedMarket))
        {
          return false;
        }
      }

      return true;
    }

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

    private bool GetCanRunThisSolution(out bool stopBetting)
    {
      stopBetting = false;

      if (mySolutionMarkets.ReadyForNextBet)
      {
        int total;
        bool isWinningStreak;

        mySolutionMarkets.GetBettingStreak(out total, out isWinningStreak);

        if (!isWinningStreak && total >= StopAtLosingStreak)
        {
          stopBetting = true;
        }
        else
        {
          return true;
        }
      }

      return false;
    }

    private Runner GetRunnerToBet(MonitoredMarket monitoredMarket, out BetType betType)
    {
      betType = BetType.Lay;

      runnersSortedCollection.Initialize(monitoredMarket);

      foreach (Runner runner in runnersSortedCollection.Data)
      {
        BetPrice betPrice = runner.BestPriceToBack;

        if (betPrice != null)
        {
          double odds = betPrice.Price;

          if (odds < MaxOddsToLay)
          {
            return runner;
          }
          else if (odds >= MinOddsToBack && odds <= MaxOddsToBack)
          {
            betType = BetType.Back;

            return runner;
          }
        }
        else
        {
          break;
        }
      }

      return null;
    }

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

      runnerProperty.BotType = BotType.PlaceBet;
      runnerProperty.BetType = betType;
      runnerProperty.Stake = Stake;
      runnerProperty.StakeIsMyLiability = betType == BetType.Lay;
      runnerProperty.MinimalOdds = betType == BetType.Back ? MinOddsToBack : OddsRange.MinOdds;
      runnerProperty.MaximalOdds = betType == BetType.Back ? MaxOddsToBack : MaxOddsToLay;
      runnerProperty.AllowPlacingBetInPlay = false;

      betfairService.StartMonitorThisMarket(monitoredMarket);
      betfairService.AddMarketToMoneyManagement(SolutionId, monitoredMarket);
      betfairService.StartBot(monitoredMarket, runner.Id);
    }
  }
}

Implementation details

When you run selected markets with the Trade Opportunity Lookup Service markets data are refreshed at preset refresh rate and depending on your settings your LookUpBot is executed for each market instantly or from the preset time relatively to the official market’s event start time. You can add more LookUpBots into the Trade Opportunity Lookup Service. The method DoYourJob is executed to evaluate markets data by your bot, if your want to continue with market evaluation the DoYourJob returns true, or false when you want to finish market’s evaluation, in such case the Trade Opportunity Lookup Service removes the market from monitoring.

DoYourJob

The method DoYourJob implements the algorithm of our bot, checking if the evaluated market is allowed market (GetIsMyMarket) otherwise returning false to remove the market from monitoring. If the race is x minutes before its official start (GetIsTheRaceXMinutesBeforeStart) and if the betting is allowed (GetCanRunThisSolution) the bot makes its selection (GetRunnerToBet) and places the bet (SetupMyBot).

public override bool DoYourJob(MonitoredMarket monitoredMarket)
{
  if (GetIsMyMarket(monitoredMarket))
  {
    if (GetIsTheRaceXMinutesBeforeStart(monitoredMarket))
    {
      bool stopBetting;

      if (GetCanRunThisSolution(out stopBetting))
      {
        BetType betType;
        Runner runner = GetRunnerToBet(monitoredMarket, out betType);

        if (runner != null)
        {
          SetupMyBot(monitoredMarket, runner, betType);
        }

        return false;
      }
      else
      {
        return !stopBetting;
      }
    }

    return true;
  }

  return false;
}

GetIsMyMarket

If the market name contains not allowed text false is returned so the market is not evaluated by the bot, otherwise returns true. You can change or add not allowed text in the market name in the array:

  • private static string[] NotAllowedMarkets = { "Hcap", "Nursery" };
private bool GetIsMyMarket(MonitoredMarket monitoredMarket)
{
  string marketName = monitoredMarket.MarketInfo.Market.Name;

  foreach (string notAllowedMarket in NotAllowedMarkets)
  {
    if (marketName.Contains(notAllowedMarket))
    {
      return false;
    }
  }

  return true;
}

GetIsTheRaceXMinutesBeforeStart

Returns true if the race is x minutes before the official start. You can change the time with this constant:

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

GetCanRunThisSolution

As our betting solution uses stop loss the bot have to keep track for results of previous betting. The money management feature is implemented by bfexplorer infrastructure, so all you need is just register our solution with the Money Management System.

If the result of previous betting is not known yet the bot will wait, when the result is know it checks if our losing streak is more or equal to the preset losing streak. You can change this parameter with this constant:

  • private const int StopAtLosingStreak = 4;
private bool GetCanRunThisSolution(out bool stopBetting)
{
  stopBetting = false;

  if (mySolutionMarkets.ReadyForNextBet)
  {
    int total;
    bool isWinningStreak;

    mySolutionMarkets.GetBettingStreak(out total, out isWinningStreak);

    if (!isWinningStreak && total >= StopAtLosingStreak)
    {
      stopBetting = true;
    }
    else
    {
      return true;
    }
  }

  return false;
}

GetRunnerToBet

The bot selection algorithm is to lay horse if its odds is lower the preset odds and back horse if its odds range is in preset range. You can change these parameters:

  • private const double MinOddsToBack = 3.0;
  • private const double MaxOddsToBack = 9.0;
  • private const double MaxOddsToLay = 2.0;
private Runner GetRunnerToBet(MonitoredMarket monitoredMarket, out BetType betType)
{
  betType = BetType.Lay;

  runnersSortedCollection.Initialize(monitoredMarket);

  foreach (Runner runner in runnersSortedCollection.Data)
  {
    BetPrice betPrice = runner.BestPriceToBack;

    if (betPrice != null)
    {
      double odds = betPrice.Price;

      if (odds < MaxOddsToLay)
      {
        return runner;
      }
      else if (odds >= MinOddsToBack && odds <= MaxOddsToBack)
      {
        betType = BetType.Back;

        return runner;
      }
    }
    else
    {
      break;
    }
  }

  return null;
}

SetupMyBot

After the bot selects its qualified horse for betting the bet have to be placed on this horse. Actually the bet is not placed by this LookUpBot but instead the PlaceBet bot is setup to do it. Our bot just starts monitoring the market and adds the market into the Money Management System and finally starts the PlaceBet bot execution. You can change the stake with this constant:

  • private const double Stake = 100;
private void SetupMyBot(MonitoredMarket monitoredMarket, Runner runner, BetType betType)
{
  RunnerProperty runnerProperty = runner.RunnerProperty;

  runnerProperty.BotType = BotType.PlaceBet;
  runnerProperty.BetType = betType;
  runnerProperty.Stake = Stake;
  runnerProperty.StakeIsMyLiability = betType == BetType.Lay;
  runnerProperty.MinimalOdds = betType == BetType.Back ? MinOddsToBack : OddsRange.MinOdds;
  runnerProperty.MaximalOdds = betType == BetType.Back ? MaxOddsToBack : MaxOddsToLay;
  runnerProperty.AllowPlacingBetInPlay = false;

  betfairService.StartMonitorThisMarket(monitoredMarket);
  betfairService.AddMarketToMoneyManagement(SolutionId, monitoredMarket);
  betfairService.StartBot(monitoredMarket, runner.Id);
}

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.EricLookUpBot

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 here.

Conclusion

Well, you can see that writing a bot is not so complicated, mainly when you use the bfexplorer pro infrastructure. What you will implement is just base algorithm of your bot, the market monitoring, bet operations, money management system and bot execution service that all is prepared for you to use.

Happy bot coding!

Comments (5)

  1. EricEllwood Says:
    Thursday, August 14, 2008

    Eric's LookUpBot implementation.

    Stefan, Thanks for all the work you have done for this project. As I have little experience with C# I have decided to key in all the code using the BOT SDK.This is now done & copied into the Bfexplorer directory.As I expected mistakes were made ....Have built the bot and debugged the code and now have a successful compilation. Will run the bot in the Bot Executor for to days racing.
  2. StefanBelo Says:
    Thursday, August 14, 2008

    Eric, having not enough time those days I put at least the source code for this bot. I will publish the article soon.

    If you want to run this bot by the Trade Opportunity Lookup Service you need to name the bot file: Bfexplorer.Scripting.EricLookUpBot.cs

  3. EricEllwood Says:
    Sunday, August 17, 2008

    Implementation details

    The information provided here is 1st class.The detail given is concise and to the point, and is very easy to understand.I am able to see how my specification is integrated into the bot code and can follow this process step by step....which is the object of the whole exercise.I feel that my bot knowledge is growing also step by step and in due course will be able to design and build bots which are both workable and useful.My first question is....To what extent can pertinant blocks of code be re-used in building new bots?....can existing bots be modified to give additional functionability? Incidently the bot is up and running and is performing to my specification.Looking forward to the next article in the series.All thanks must go to Stefan. 

     

  4. StefanBelo Says:
    Tuesday, August 19, 2008

    Yes Eric you can modify any part you want and actually if you have a look at on the DoYourJob method then you can reuse all the bot main logic here as the most of LookUpBots do require those four methods:

    • GetIsTheRaceXMinutesBeforeStart
    • GetCanRunThisSolution
    • GetRunnerToBet
    • SetupMyBot.

    If your bot implementation does not require a money management system you can remove GetCanRunThisSolution method as well as GetIsMyMarket, if you do not need additional market filtering.

  5. EricEllwood Says:
    Tuesday, September 02, 2008

    Progress report..Step by step bot.

    Using the detail and comments previously posted I have created a new bot by using code from existing bots, this was done within the BOT SDK. This I found to be much easier than I thought possible...taking in my very limited level of coding know how. This bot is now in my Bfexplorer root directory, after testing it in practice mode it is working OK and has produced a profit for the day.I must say that three weeks ago I could not have imagined that any of this would have been possible.

     


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