There is a very good school of thought that says that in order to concentrate your mind on a particular issue, it is best to ignore it for a bit. To that end, I'm spending this afternoon on a few Gamblotron updates, amongst other things.
Prototype 3
In the last part, I layed out my vision for what the next incarnation of Gamblotron would look like. In particular, there were three things:
- Persistence - if Gamblotron crashes, or the network is interrupted, it should be able to pick-up more or less exactly where it left off.
- Market-wide risk modeling - previously it treated a market as a collection of individual events, it wouldn't (for example) use the profits on one selection to fund a bet on another.
- Optimisation - each strategy script has between six to twelve parameters, these need to be fine tuned.
The issue of market wide risk management is more tricky, mostly due to a design decision that needs to be made: what's the best way of limiting exposure on a single event, but still making decisions for the whole market; for example, a simple limit on maximum exposure would prevent a hedging bet being placed on that same event, depending on how it's built.
In the long run, it shouldn't matter if bets are determined on an individual selection or market-as-a-whole basis, they should average each other out. Theoretically, the overall risk profile should be lower by examining the whole market, depending on how it's done; but because there's no immediate need, I have bravely postponed this decision until a later date, retaining the simple
AutoHedging stake plan, until I have implemented those features which ought to have a bigger effect.Optimisation
Which leads me on to the change with the single biggest impact: Optimization.
The problem is easy to explain: The strategy script, even though it has certain assumptions locked in - like the use of RSI as an indicator - still has many parameters. The value of these parameters can mean the difference between profit and loss. If they're set low the indicators will be too sensitive, and generate too many false positives; or if they're set too high they'll just ignore all the trading opportunities.
There are too many parameters to tune them by hand, at the moment the best settings have been guessed by me by examining a graph after the event, but I may be barking up completely the wrong tree. The RSI strategy script has eleven parameters:
params = {
'RSI_OVERBOUGHT': 80,
'RSI_OVERSOLD': 20,
'RSI_WINDOW': 1,
'RSI_NUM_WINDOWS': 10,
'RSI_SMOOTH_PERIOD': 2 / 3.0,
'VOLUME_WINDOW': 1,
'ACTIVITY_SMOOTH_PERIOD': 10,
'ACTIVITY_THRESHOLD': 0.025,
'ACTIVITY_RANK_THRESHOLD': 4,
'STAKE_EXP_PCT': 50,
'STAKE_VARIABILITY': 2
}
And modifying them is difficult to achieve because there is a certain amount of implicit relationships between them; for example, lengthening the RSI window would almost certainly requiring changing the overbought and oversold thresholds. But this exact relationship is unknown.
For each of those parameters there are hundreds of values, and when you calculate every possible combination, it's a very, very big number. Far too many to test by hand.
But here's the crucial thing, far too many to test by machine either. Each test of Gamblotron takes about five minutes to complete; multiply that by the number of combinations and you have a ridiculously large number. Very, very large. So large that the Universe isn't old enough; even if I'd started it off at the beginning of time itself, it would still not finish until well after the Earth has ceased to be.
This is where Optimisation comes in. There are various techniques that can be used to try and find the optimal settings for any given sport. The first that I'm going to try is Simulated Annealing.
How this works, is quite simple; it's based on the theory of annealing in metalurgy. But, I think it's even easier to think about it another way: What I have is an twelve-dimensional space; eleven dimensions are the parameters, the twelvth is the result of the simulation. In this space you have a drunk person, who doesn't care where he's going; he moves at random in the eleven dimensions, but has to climb whatever twelvth dimensional hill is put in front of him, or he turns around and goes in another direction. At the beginning, he doesn't care, he'll climb any hill; as time goes on, he gets tired, and only climbs small hills; until the very end when he'll only go downhill. By the time he's completely knackered, he should be at the lowest part of the landscape.
In other words: Simulated Annealing will random change the value of one of those eleven parameters, and run the test; if the new result is better, or worse by a certain amount it moves in that new direction and starts again; but if it's much worse, it doesn't, and it changes another parameter. As time goes on, the probability of it choosing to climb a hill falls.
It should result in a set of parameters which produce much better results than simple guess work.
The next step is to define the limits of the parameters, for example none of them accept negative numbers, the range needs to be limited to what's possible:
domain = {
'RSI_OVERBOUGHT': (0, 100, 0.5),
'RSI_OVERSOLD': (0, 100, 0.5),
'RSI_WINDOW': (0.1, 90, 0.1),
'RSI_NUM_WINDOWS': (0.1, 100, 0.1),
'RSI_SMOOTH_PERIOD': (0, 100, 0.25),
'VOLUME_WINDOW': (0.1, 30, 0.1),
'ACTIVITY_SMOOTH_PERIOD': (0.1, 10, 0.1),
'ACTIVITY_THRESHOLD': (0, 100, 0.025),
'ACTIVITY_RANK_THRESHOLD': (1, 20, 1),
'STAKE_EXP_PCT': (0, 66.6666, 0.3333),
'STAKE_VARIABILITY': (0, 100, 0.1)
}
Each of these represent the lower bound, upper bound, and step for each parameter.
Fitness function
The entire simulation of a sporting event needs to be encapsulated within one function, which is only allowed to return a number. It is this number that is optimised, the optimisation will find the set of parameters which makes this number low.
So what is this magic number? Well that depends on what I'm trying to do. Should it be the Profit/Loss of the eventual winner? Or should it be the worst-case scenario? In other words am I trying to minimise loss or maximise the payout? Or, should it even be both?
Because of occasional freak results, or events finishing with stewards still ass-clowning (ahem), the only sensible option will be to use the worst-case scenario. Or rather the opposite of the worst case, we want the worst case to be as small as possible and therefore the projection for the worst case needs to be large.
Results
On my calculations, this is going to take 11 days to complete! But still that's better then 11 times the known age of the universe.
Actually, I'd better be more sensible and change it so that is converges earlier; the result will be less accurate, but I can at least test the test. Then I will put the settings back and let it go again.
O.K., it's running now, this one should only take three hours. I'll post the results later...

0 comments:
Post a Comment