Sunday, 31 August 2008

How I'm building a (working) sports betting bot, part 8

My busy (not to mention hectic) lifestyle - or should I say: my complete chaotic manner of planning - has opened up a brief window for me to do a bit of thinking on what's next for Gamblotron.  On the grand plan it's only third on my list of software that needs building (first is Plan A, second is my decision making app that I think I need), but still, it's the most interesting of the three!  Plus there is the outside chance that it might actually work!

The last major change I made was a bit of restructuring to allow essentially all important settings, logic, etc., to be controlled in a script rather than be embedded deep in the application.  This works really quite well actually.  I'm building a library of Functions (as opposed to functions) that can be simply called by the script.  These functions have a few assumptions built-in, to make higher-level tasks easier, for example they assume that each statistic being monitored will be on a per-selection basis (this assumption won't always be true, and is one of the many things I need to change - I'll make a note of that before I forget).

The simplest of these Functions is Window.  As the name suggests it provides a window into the past of a given statistic.  It works as follows: if, for example, you want to keep twenty minutes worth of derived probabilities from the "last price matched" data provided by betfair:

   window = Window(app, 20, lambda runner_info: runner_info.last_probability_matched)

The app is a reference to the main Gamblotron application object, the Window Function then registers itself with it, and everytime more data is available it updates the window using the provided lambda expression to extract the required data.  To then get access to the data for a particular selection:

   data = window[selection_id]

Data will then contain a list of probabilities for the given selection.  Building higher-level functions is then easy, just by composing lower level Functions, for example the moving average Function looks like:

class MA(Function):
   """Simple moving average"""
   
   #
   def __init__(self, app, period, data_fn):
      Function.__init__(self, app)
      self.__window = Window(app, period, data_fn)
      
   #
   def __getitem__(self, key):
      return statsutils.mean(self.__window[key])

And is used in a similar way: current_average = mov_avg[selection_id].  Complex indicators are just as easy, for example MACD consists of different moving averages:

class MACD(Function):
   """MACD"""
   
   #
   def __init__(self, app, slow_mav_p, fast_mav_p, signal_mav_p):
      Function.__init__(self, app)
      self.__slow_ema = EMA(app, slow_mav_p, lambda runner_info: runner_info.last_probability_matched)
      self.__fast_ema = EMA(app, fast_mav_p, lambda runner_info: runner_info.last_probability_matched)
      self.__signal = EMA(app, signal_mav_p, lambda runner_info: self.__macd(runner_info.selection_id))
      
   #
   def __macd(self, selection_id):
      slow_ema = self.__slow_ema[selection_id]
      fast_ema = self.__fast_ema[selection_id]
      return fast_ema - slow_ema
      
   #
   def __getitem__(self, selection_id):
      slow_ema = self.__slow_ema[selection_id]
      fast_ema = self.__fast_ema[selection_id]
      themacd = self.__macd(selection_id)
      signal = self.__signal[selection_id]
      return (slow_ema, fast_ema, themacd, signal)

It's all really quite good, very flexible, it's incredibly easy to make a change or add new functions.

What that upgrade didn't fix, however, is the staking plan.  It still uses the simplistic "auto hedging" plan I had originally.  The combination of signals fires back or lay signals, the plan then decides whether to take a speculative position or hedge an existing position depending on the current exposure.  This is a bit simplistic, in reality you'd want to make those descisions based on other factors, like volume or time remaining; which, in turn, raises the question: what kind of API do I need for that sort of thing, or should I instead expose a series of objects and allow each strategy to build it's own staking plan?

I'm nearly running out of my self-imposed time for this update, so I shall make a list of further areas of research/improvement; I'll keep prioritising this list until a future date:
  1. Re-engineer Function library into per-market and per-runner Functions.
  2. Allow MACD to work on more than just probability (I have a theory of using MACD of volume for a selection to be the difference between speculative betting and just hedging).
  3. Decide how to re-implement the staking plan.  (Some kind of percentage parameter, or something; flexible...)
  4. Continue to implement various Technical Analysis indicators/functions - RSI, Pivot Points, etc.
  5. Various platform improvements - multiple threads updating each selection simultaneously then grouping bets into a single call to the API.
  6. Other logging, error handling improvements - reset connections cause issues sometimes.
  7. I've been reading a lot recently about AI techniques, and in particular how neural networks and genetic algorithms have been used in financial markets.  I last studied such things at university, and something doesn't add up, I can't see how there is anywhere near enough data available to train a neural net.  It would be even worse for betting markets.  But still, it would be fun to find out!
  8. Persistence - so that Gamblotron can pick-up where it left off in the event of it being shutdown.  This would be particularly useful for markets which last weeks to months.
At some point, probably next week, I'll have enough time to pick off one of those eight; by that time I will have decided which one.  Perhaps I should turn this into a feature, I'll add a voting widget "making a fortune from the blogosphere".  There's no particular rush to get any of this stuff built, the next Grand Prix is Belgium, which despite being a historic track, etc., produced an eternally dull race last year; this year will probably be the same.

We shall see.

1 comments:

  1. For info, you've been linked to from the diybetfairbots forum.

    ReplyDelete