Disclaimer: I am not an investment advisor. When I describe my own trading activities, it is not intended as advice or solicitation of any kind.

30 October 2010

Collaboration is Good

NeighborTrader has been making some comments lately about a trade he has been backtesting.  At first, he was trying to work out a way to make it an intraday trade so that he could run it at the office as part of his job.  A fairly new trader like him tends to prefer that route, because he has a lot more resources to throw at it sooner if it goes well than if he has to save his money to cover the margin.  Unfortunately for him, after playing with a lot of different variables he came to the conclusion that the trade worked best on daily charts, which means long-term holding times.  Since our firm has a day-trading culture and isn't really set up from a risk-management standpoint to hold trades for more than a few hours, that pretty much precludes him running it as part of his job.

Knowing that I've been running long-term trades in paperMoney, he chatted with me yesterday about his trade and the methodology he was using to backtest it.  I have to admit, I'm pretty impressed at how rigorous he's being with it considering: (a) he has no academic or professional experience with formal backtesting; and (b) it's something he's doing for himself on the weekends and committing very little capital to.  He even went so far as to buy historical data, something most of the guys at the office don't do for their big trades.  He also bought a book to learn proper backtesting methods to minimize the chance of sample bias and curve-fitting.

Since it's his trade, I don't think it's right for me to go into it in detail on a public blog.  He gave me all the information I need to run it myself, and suggested some products to run it in, and I plan to do so, although I can't think of a good name for it right now.  But I'll leave the parameters a little hazy to protect his intellectual property.  Suffice to say that it is pretty similar to CS|MACO in that it looks to enter positions contrary to market consensus, but only to do so when it isn't fighting a strong trend.  It seeks to buy dips and sell spikes, and it's purely technical, using indicators widely available on most charting packages.  It also trades very infrequently, so I might have to run it on more than one product just to avoid being bored.

He's been running it in S&P-500 Futures (it needs a lot of leverage to succeed, and he understands futures very well since that's his job) and a couple of other products.  He just exited a trade in it today for a nice fat profit.  Since I already have CS|MACO running on SPY (the S&P-500 ETF), and I have other trades running on other equity indexes (Iron Condors on Russell, Collars on Nasdaq-100), I think I'll run it against US Treasury 10-year Note Futures.  This trades at the CME since they merged with CBOT, and it's available in paperMoney. 

Speaking of CS|MACO, it's been quiet for a while now.  Individual investors have stayed bullish (they've been right for once), and SPY has stayed above its 25-day moving average.  Long+short = flat, so I've been watching this whole move from the sidelines.  The last couple of weeks haven't been good for any trade except iron condors, with the stock market going pretty much sideways.  Something has to give with CS|MACO soon, though, because the 25-day moving average and the closing price are converging.

29 October 2010

Arms Race, Part 4

In Part 3, I went all the way down the pixel level to describe how my automatic Bejeweled player detects the color and type of the gems on the screen.  Today, we'll use that information to get ridiculously high scores in Bejeweled Blitz.

Detecting all the colors was pretty tough, and detecting the type of gem in each cell was even tougher; but now we need the software to make a decision and act on it.  Specifically, of all the possible trigger/target combinations available on the board at the moment, which one is the best one to do next?  I chose to go a pretty simplistic route on this, since I was, after all, writing this for the heck of it.

I do not have the software attempt to predict combos or other more advanced plays to maximize points.  This is something that humans playing the game do to some extent without even thinking about it, but it becomes more challenging for software.  Consider the picture below.  I have highlighted the 4 possible moves by drawing a red blobby line between the trigger and target gems.  Which move will generate the most points?  If you said "the bottom-right one", you would be correct, because both the green and red gems would be removed, not to mention the bonus you get from doing a combo move like that.  By the way, the software would call that move "6,5-7,5".  The best move that the software sees from this board is "4,6-3,6" - swapping the white and yellow gems in the bottom-middle of the board.  I'll explain why this is chosen shortly.

Which move is best?
So skipping the combos and any other move in which you choose things based on secondary effects, I can define some scoring rules by decreasing order of weight:
  1. Always use paths with multipliers in them first - this is a no-brainer, because that has long-term positive effects on the entire game.
  2. If a path has a crosshair in it, it will destroy more gems than any other move on the board - except maybe a hypercube, but the software doesn't detect those, so that's moot.
  3. If a path has a flaming gem in it, its explosion will take out a 3x3 square of gems as well as the path gems themselves, yielding 9-10 gems destroyed on a 3-gem path.
  4. Longer paths are better than shorter ones, because they destroy more gems.  Plus, they generate crosshairs, hypercubes, and flaming gems, so that's goodness too.
  5. Paths lower on the board have more opportunities to create combos than paths near the top.  All else being equal, pick the lowest path on the board.
Going back to our picture and following these rules, we can see that there are no multipliers, no crosshairs or flames, and no 4-gem or greater paths.  That gets us all the way to rule #5, where we pick "4,6-3,6" because its highest gem (all of them) is lower than the highest gem of any other path on the board.

OK, great, we have rules of how to pick a path, but we've gotten a little ahead of ourselves.  How do we find the damn things?  In the software, I have a Grid object with 8x8 GridItem objects (aka Gems) in it.  During the detection phase, I set the color and type of each of those gem objects.  When I'm done, I have a software representation of the board as of the last screen capture.  Then I look at each gem and check to see if it is the leading edge gem of one of the following patterns:

The four path patterns in their basic form
In the first pattern, the gray squares are optional.  Readers familiar with Bejeweled will notice that adding one or both optional squares on will cause the path to generate a flaming gem or a hypercube, respectively.  The first case also has a special sub-case where the mirror-image is also possible, with the trigger below the target rather than above, but only the first of the two optional gems is present.  In this special sub-case, we move the trigger to the optional gem position to form a "T" when the path is completed; this generates a crosshair, so it is obviously more desirable.  If both optional gems are present, however, we leave the trigger where it is because hypercubes are awesome - even if the software doesn't know how to use them right now.

Anyway, in examining each gem to see if it is the leading edge of one of the patterns above, I actually examine it 4 times for each of the 4 patterns above - once with each possible 90-degree rotation of the pattern.  Mirror-images are included as well, but they are done within each rotation, so it's only 16 (4x4) checks on each gem instead of 32 (4x4x2).

Once all the processing above is done, we have a full list of every path available for activating.  For each path, we generate a score based on the 5 rules discussed above, and then sort them by score in descending order.  Then we pick the best possible path and execute it by moving the mouse to the trigger, clicking, moving the mouse to the target, and clicking again.  I do the mouse movement and clicking using the XLib API again: XSetInputFocus, XSync, XWarpPointer, XQueryPointer, and XSendEvent in various combinations that I worked out primarily through internet searching and a lot of trial and error.

As I was coding all of this, I went with the most expedient code possible, rather than the highest-performing.  Again, it was a project being done for the heck of it, so spending a lot of time designing around performance was too much like work.  Nevertheless, as I reached code completion, I started being concerned that the image processing and path detection would take so long that the software wouldn't even outscore me.  After all, I can hit 350k pretty reliably every week, and my highest human score was 652k.  Besides speed, I also have the human judgment that lets me pick the combo path automatically as we saw at the start of the post.

I needn't have worried: the screenshot, the origin detection, the color and state detection, the Grid-building, the path detection, and the scoring and decision process all takes 9 milliseconds to finish.  In fact, this thing is so fast that it finds matches as gems fall that don't really exist.  This causes it to have a high mistake rate, so I actually have it sleep (do nothing) for 50 milliseconds between passes to give Bejeweled a little time to catch up.  Even so, it's still mighty fast.

Below are two videos, neither one using boosts.  The first was captured while I was manually playing, and while it's not exactly a stellar run, it's a fairly representative game, finishing with a score of 166k.  The second is a run using my software.  It gets confused a couple of times, pausing for a full second while it reacquires the origin; and notice how it just ignores the hypercubes and makes a lot of stupid plays.  And yet the score speaks for itself.

Playing by hand, for 166k


Playing by program, for 698k

Yeah, that'll do.

28 October 2010

Arms Race, Part 3

In Part 1, I explained my motives for writing software to play Bejeweled Blitz.  In Part 2, I defined the terms and general outline of a program to automatically play Bejeweled Blitz.  In Part 3, I'll start at the screen level and work all the way down to the pixel, showing how I detect the color and state of each gem on the grid.

Where to Begin
I run 64-bit Ubuntu at home, and my browser is Firefox.  To capture and analyze the contents of the screen, I used XLib API calls.  In X, every window is laid out in a hierarchy starting with the root window that holds the desktop, taskbars, and all the top-level application windows.  So first I open my display with XOpenDisplay and store it for the life of the capture job, since it gets used throughout the process.  Next, I wrote a function to search a given window for the word "Bejeweled" in its menu text (using XGetWMName).  If found, it returns a handle to the window.  Otherwise it uses XQueryTree to get an array of all the immediate children and recursively calls itself with each of them.  Then it is just a simple matter of calling that function initially with the result of RootWindow(disp, DefaultScreen(disp)).

Now we drop down a level from screen to window: specifically, the Firefox browser in which Bejeweled is running.  To get an image of that window, it is as easy as calling XGetWindowAttributes to see how big it is, and then XGetImage to get an XImage pointer that we can analyze pixel by pixel.  To get a pixel, I use XGetPixel, passing the XImage that resulted from XGetImage, and the X/Y coordinates of the pixel I want.  This returns me the RGB value of the pixel as a long integer, which I can break into separate color levels with a little ANDing and shifting.

The next problem is finding the grid origin.  There are a lot of better ways to do this, but I chose the simple brute-force method.  In the picture on the right, I've put a red box around the group of pixels that I search for to find the top-left corner of the grid.  To do this, I simply examine every pixel until I find one that matches the first pixel in the red box.  Then I check to see if every other pixel in my test section also matches.  If so, I offset to where the grid origin is and proceed.  Otherwise, I move to the next pixel and do it all over again.  Not especially efficient, but it gets the job done.  This spot on the board is key, because it is only there during game play, and it never changes color except for short time periods during hypercube and crosshair detonation.

Once I know the grid origin, I can divide the grid into an 8x8 array of cells, with each cell 40x40 pixels in size.  At this point I had to get a little more creative, because of the dynamic nature of the gems and the board.  The background changes color frequently in response to multiplier changes, power-ups, and game mode.  The gems also spin when they're clicked on, making pixel-by-pixel identification impossible.  The key here is to focus on what matters, and to eliminate that which doesn't.

Special Multiplier Processing
First I test each cell to see if it is a multiplier.  Through a great deal of manual playing and taking screenshots, I discovered that the x2, x3, and x5 multipliers all had the exact same X shape on the gems, but the x4 was a little different - I haven't analyzed anything higher than x5.  I decided the best way to handle this was to look for a set of pixels that were white, forming the X shape, but examine only those pixels that were common to both shapes.  What I ended up with was the set of pixels depicted to the right, where the gray pixels are white only in x4 or only in x2/3/5.  Then it was a simple matter of checking each pixel in the gem in the right positions to see if it was white.  Anything else that wasn't in the must-be-white list could be ignored.

If the previous step determined that the cell is a multiplier, then I do a special color test on it, different from other gems.  I check the color of a single pixel just above the "X".  Based on that color, I know the color of the multiplier cell and I stop processing it further for color.  In the picture on the right you can see the pixelated shape of the white X, as well as a red dot where I check the multiplier for color.

Sensing the Aura
The next bit of special processing is to determine whether the cell is flaming or is a crosshair.  These are almost as important to detect as multipliers, because using them increases the chance of getting a multiplier: especially crosshairs, which will generate a multiplier on every use, so long as the multiplier time limit has expired.  Crosshairs also require some special color processing later, so we need to know if the current cell is a crosshair before we start looking at color.

The way I detect crosshairs and flames is to look at the top-middle of the cell, actually bleeding over into the cell above it by one pixel and extending down two pixels into the current cell.  This area is never occupied by gems at rest, so it is a good place to search for auras.  Based on the average color in this region, I determine if we have a crosshair, a flame, or a normal gem in this cell.

Finally, I check the color.  To do this, I only look at the middle 12x12 square of pixels, because this area is all gem (no background) for all colors and shapes, and never is corrupted by flaming aura.  I take the simple average of each of the RGB values in the pixels to come up with the average color.  For non-crosshair gems, I can be pretty precise because there is seldom any variation.  Crosshairs pulsate, though, so I started by examining a bunch of frames of crosshairs and finding optimum RGB values.  Then the program works outward from these values until the calculated average value fits into the range of one of the colors.  In the picture on the right, we can see a flaming blue gem with a red border around its aura zone and its color zone.

Once I know the color and state, I can move on to the next cell, repeating the process until all 64 cells have been identified.  If falling gems, hypercubes, or other temporary embellishments cause a cell to be undetected or mis-detected, it usually has little to no effect on the outcome of the game.  There is enough going on at any given time that little pockets of misinformation can be absorbed.

The conclusion is in Part 4: Playing the Game

26 October 2010

Arms Race, Part 2

In Part 1, I explained my motives for writing software to play Bejeweled Blitz.  In Part 2, I define some terminology and lay some groundwork for the first step of actual programming.  I assume that readers of this blog have played Bejeweled Blitz before; if not, go to Facebook and waste some time.  When you're done "researching", come on back and read the rest of this post.  Since it's a visual game, I'll need to define some terminology so when I describe a gem type we'll all know what I'm talking about.

The board of Bejeweled Blitz is the entire Flash application, including the non-game screens and the artwork behind and around the actual playing area, which I call the grid.  The grid holds all the gems and other playing pieces in an 8x8 array of cells.  The top-left corner cell's top-left corner is the grid origin.  The X values of cells and pixels increase as we travel to the right, and the Y values of cells and pixels increase as we travel down.  The top-left cell is (0,0), and the bottom-right is (7,7).

Gems can be any of the following colors: Blue, Green, Orange, Purple, Red, White, or Yellow.  The majority of gems are in a normal state, but they can also be explosive (aka flaming), crosshairs, or multipliers.  There is also a non-gem piece called a hypercube (PopCap's term).  These are nearly impossible for my software to identify in a moving board, so I gave up on them and let them be.  Yellow gems can also be in coin form; they still work as yellow gems, but add 100 coins that can be used for boosts between games.  Coins collected during the game count the same as coins left on the board at the end, so in practice yellow gems and yellow coins are equivalent.

Normal
Flaming
Coin
Crosshair
Multiplier
Hypercube

Points are generated by removing the gems from the board, which is done by forming paths of matching gems by swapping two adjacent gems.  Paths can be 3, 4, or 5 gems long.  Depending on the shape and length of the path, flames, crosshairs, or hypercubes can be created from the path.  Since gems fall into the empty spaces left by paths after gem removal, it is possible to get a combo bonus when falling gems fill the holes of a new path.  Multipliers are generated when enough gems are removed in a single move; I think that number is 10-12, but I'm not sure.  There is also a no-multiplier time limit after one is generated, which my software doesn't account for.

Normal gems, coins, and multipliers remove only themselves when matched in a path.  Flames remove a 3x3 square with themselves in the center.  Crosshairs remove the entire row and column upon which they reside.  Hypercubes do not get used in a path: instead, they remove all gems of the same color as whatever gem they are swapped with.

The user must continually look for opportunities to create paths by swapping adjacent gems.  I refer to gems that form a path as path members.  Since only two gems can be swapped per move, we can define the trigger gem as the one which is out of place.  We can likewise define the target gem as the non-matching gem in the trigger's way.  Swapping trigger and target forms the path, removing the gems and activating any special properties in that path.

Speed is of the essence, as mentioned before.  If paths are formed fast enough, a speed bonus is built up; if this is maintained long enough, the game switches into Blazing Speed mode for a few seconds (10, maybe?).  In this mode, all normal trigger gems and coins are treated like explosive flames.  Note that not all members of the path explode - just the one involved directly in the swapping operation.  Thus combos do not get more explosive than normal, either.

A general outline of a working program to play Bejeweled, then, might look like this:
  1. Locate the origin of the grid on the screen
  2. Detect all the gem colors and properties
  3. Build potential paths with triggers and targets
  4. Choose the optimum path and swap its trigger and target gems
  5. Loop back to 2 until the game is over
I felt that the hardest part of the program was detecting the gem colors and properties, so I tackled that first.

Stay tuned for Part 3: Gem Color Detection

24 October 2010

Arms Race, Part 1

Like many of us, I'm on Facebook.  I try to stay away from the social games, since most of them are poorly veiled attempts to hook your brain on electronic crack until you're willing to pay for it (I'm looking at you, Farmville), and some of them are out-and-out information pirates.  But one that I succumbed to completely was Bejeweled Blitz, created by PopCap.  PopCap is truly the master of simple little games that will suck your life away, and I have had my brain claimed by Bejeweled variants from PopCap and other developers before.  In fact, I share this weakness with one of my online poker friends, Missy; I convinced her to sign up for Facebook by telling her about Bejeweled Blitz.  Full disclosure, she was thinking about it anyway, but I think hearing there was a cool new (to her) Bejeweled variant free on Facebook was the final straw.

A quick note about how Bejeweled Blitz differs from normal Bejeweled: it's a 60-second game, so speed is of the essence; there is a personalized high-score board where all of your Bejeweled-playing Facebook friends automatically show up; and they reset the scores every week so that everyone is trying to beat each others' scores all the time.  Here are the top 5 from this weeks' high score board for my group of friends, which I am coincidentally dominating.

Missy and I are both very competitive, and we're used to facing off against each other at the poker table.  It wasn't long - like 3 games, maybe - before she had beaten my high score and I was grimly playing for all I was worth, trying to stay in the #1 spot.  Sixty seconds at a time, I watched hours disappear.  I think it was Missy who coined the phrase "stuck in a Bejeweled loop"; ironically, she was referring to her husband Todd when she first said it, but it easily applied to both of us as well.  Missy became my nemesis, my baby-with-one-eyebrow, my standard against whom my scores were judged.  We both waged psychological warfare, purposely getting semi-OK scores early in the week intending to re-up them when the other person beat the first round.  Sometimes others on my list would set higher scores, and I did my best to beat them, but failing to do so was never as infuriating as allowing Missy to win.

As we both practiced for literally hours per day, we got to be pretty good at it.  In the spirit of competition, Missy would occasionally accuse me of cheating when I set a particularly high score for a week.  In one conversation, she commented that Todd had semi-jokingly suggested that I had written a program to play Bejeweled for me.  I was flattered that he gave me so much credit - I thought that writing such a program would be so tough as to not be worth the effort.  But it got me thinking: could it be done?

Playing Bejeweled for hours a day, 60 seconds at a time, is a great way to waste your life.  But I found that my mind would wander while I played, letting me muse on the activities of the day and look at them from many different perspectives than I usually would.  When I started playing I was coping with a very unpleasant work situation that I hadn't decided how best to change.  As things came to a head about a year ago, I think my time playing Bejeweled after work was therapeutic and productive, letting me find creative ways to deal with some of the less technology-related problems (i.e. politics) that I would not have considered if my mind weren't idle anyway.

Fast forward 8 months or so, and I had no major problems to work out while I played Bejeweled.  My work-related stresses were greatly diminished, and I once more felt like I was contributing my best to a company that appreciated my strengths and gracefully accepted my weaknesses.  That left me with a problem-solving technique in search of a problem.  When Todd commented about writing a program to play Bejeweled automatically, I found my problem.

Stay tuned for Part 2: Defining the Game

21 October 2010

So Much For That Plan

Gold for Cash
In my last post, just two days ago, I briefly outlined my plan for disposing of my GLD Dec calls.  I said that I wanted to hit a price or time target, and when either thing happened I was out.  Of course the very next day gold prices dropped 3%, and then another 2% today, wiping out 20% of the value of my calls.  I'm not quite sure what's going on, but that was outside my comfort zone, and I dumped the calls today for quite a lot less than I planned.  Now that I'm out, I'll detail my price/time limits a little more.

I bought the then-ATM calls over the summer for $5/share of GLD, believing that gold would appreciate in the fall.  Boy did it, and it wasn't long before I was able to sell less than half of them for about $11/share.  That took my initial investment off the table, and I kept the rest riding.  I saw them reach somewhere around $17/share at their high, and I had a price target of $25/share to get out of the rest.  That was pretty aggressive, but I also had a time limit.

Uncomfortable, as I said on Tuesday, with the many small indications of a coming correction in gold, I wanted out soon.  I think most people are idiots (see the CS part of the CS+MACO trade), and when everyone's bullish, it's time to sell.  Worse, literally the whole world is hanging on QE2-related verbiage expected in the minutes from the FOMC's meeting on November 2 & 3.  That economic release is doomed: QE2 is already fully priced in, and all the Fed can do now is disappoint.  At the very least, all the IV comes out of the options after the announcement because the inflection point will have passed.  I definitely wanted out by Nov 2.

I have assumed for quite some time that I am riding a bubble forming in gold, and I swore that unlike the turn-of-the-century tech bubble, I would neither miss the run-up nor hang on for dear life during the pop.  That's why I have been in and out of leveraged gold positions via calls for the last year or so, and that's why I'll get back in after the mid-bubble correction makes everyone hate gold again.  I'm pretty bummed that I gave up so much of my profits by dumping today, but I still made about 150% on the trade since August, so I have no major complaints.

Speaking of CS+MACO...
Adding to the bearish signals this week, AAII published its survey results yesterday after the close: more people are bullish again.  With the CS portion screaming "sell!" and the MACO portion insisting "buy!", CS+MACO is still flat and will stay there for at least another week.

18 October 2010

Assorted Trades

Iron Condor
On Friday, I decided to add a little up-side protection to my December Iron Condor.  I'm trying to act when delta starts getting out of whack, and after a few days of stock market rallies the Dec IC was looking at a delta of about -20.  Sadly I can't be more precise on this because I forgot to jot it down (mental hand-slap).  Anyway, I decided the adjustment that made the most sense was to buy a Dec 760 call.  With my IC strikes at 610/620/770/780, this puts the naked-long call just one strike below my short call.  This adjustment brought my delta up to about +4 as of now, and didn't hurt the theta too much - still nearly 21.  It cost me 9.50, which is a big chunk of change, but I expect it to be the only upside adjustment I'll need to make to this position.

Until I come up with a better solution than Excel, unfortunately I can only display value-at-expiry.  Trust me when I say that current portfolio value is a lot curvier and much more attractive than this.

QQQQ Collar
Also on Friday, my October covered call on QQQQ as part of the collar trade expired in the money and I was assigned on the call.  Pursuant to the rules I set forth in September, I bought QQQQ back this morning at 51.50 and sold calls against it with a strike price of 53 for 56c.  Here are those rules again, since I keep having to search Facebook Notes for the numbers:

1. Monthly calls to be about 3%, and no less than 2.5%, out of the money.
2. 6-month put to be 8% out of the money.
3. No rolling prior to expiry.

Gold Leverage
I am still long-term bullish on gold, and I express that by being long GLD, GDX, and AEM.  I also currently have some Dec calls on GLD that are so profitable that I have sold off enough to cover my original investment and the remainder are worth almost twice what I paid for the whole stack.  Nevertheless, I'm becoming concerned with the borderline irrational expectations for QE2 lately, so I'm ready to take some profits.  I started working a fairly distant sell order on the rest of my GLD calls this morning.  Hopefully it will reach my target price and I'll exit there, but I also have a time limit on this trade; I'll exit when that time limit expires regardless of the price action.