Full Tilt Color Coding In Twenty Minutes or Less

Friday, August 28, 2009

The other day we talked about how opponent color-coding can dramatically improve your online poker ROI because it addresses one of the most important and yet under-appreciated skills in poker:

Table selection, table selection, table selection

My opinion is that table selection is the single biggest factor influencing online poker results at any level.

All you have to do is read something like Table Selection and Variance 101 (by well-known 6-man SNG player Jared "jhub3000" Hubbard) to get a feel for the effort top players devote to table selection.

Now that you're educated in variance, let's move on to table selection. A recent study was done to see how winning players effect your ROI. Here's how much each type of player lowers your ROI when they sit in your game:

Good player: -4.5%
Decent player: -2.8%
Barely winning player: -2%

We'll assume we play $100 SNGs, in general I'd say each type of player would have the following ROI range:

Good player: 5%+, maybe 4%
Decent player: 2-3%, maybe 4%
Barely winning player: 1%

Now you need to use judgement in assessing ROIs. For one, there's good players who practice poor table selection. They might have a 2% ROI at $100s, but actually lower your ROI 4.5%. We'll assess some stats/player types & I'll tell you how I think they would effect my ROI in a $100 turbo:

Player 1: 10,000 games, $250 avg. stake, 3% ROI....Without knowing how they play I'd probably assume he lowers my ROI 4.5%...although his ROI is only 3% he has a higher avg. stake

Player 2: 500 games, $100 avg. stake, 6% ROI, has numerous glaring leaks....this player might even be a losing player, depending on how bad those leaks are, but you don't want to give your opponents too little of credit....despite the ROI, he has a small sample size & glaring leaks...I'd put him as a 2% ROI dropper

The exact numbers he quotes are irrelevant; the point is that he's even thinking in these terms in the first place. Good players cost you a lot of money. Even if they're not as good as you. Which of course is why color coding is so useful, and why I make a big deal about it: it helps you shun good players and follow bad ones.

And that means money in your pocket.

Automated Color Code Generation for Full Tilt

A regular player will face hundreds of thousands of opponents during his online poker career. Obviously, manually color-coding each opponent isn't really feasible unless you start doing it from the beginning. Even then, it's a pain. And what do you do a year down the road, when half of the players have changed their style?

What's needed is an automated color-coding tool. We'll build a (very) basic version of such a tool today.

  1. Retrieve each player in your PokerTracker 3 or Hold'em Manager database
  2. Calculate or retrieve a rating for each player
  3. Choose a color-code to represent that rating
  4. Inject the color code into the Full Tilt player notes file

For now we'll limit the scope of our tool to Full Tilt, since it's the only major venue that:

  • Stores color codes in an open, accessible format
  • Propagates color codes throughout the UI

But the same techniques should work in theory for other sites, when and if they add support for color coding.

The Player Ranking Algorithm

Needless to say, a color-coding system is only as good as the accuracy and consistency of its player ranking algorithm. A sophisticated player ranking algorithm would take all of the following into account:

  • Historical winnings results from sites like Sharkscope, OPR, and PokerDB
  • Hand histories (via PokerTracker or Hold'em Manager etc.)
  • Any notes or flags set by the player

But since this is a proof of concept, and since most of the sites like Sharkscope and OPR expressly forbid external automation, for now we'll use the PokerTracker 3 Auto-Rate feature to generate our player rankings:

It's not an ideal solution, because PokerTracker can only rate opponents for whom you have a certain number of hand histories, but for demo purposes it's fine. We'll associate each player rating with a Full Tilt color code using the stoplight color scheme discussed previously.

And of course, you can easily extend this "algorithm" to incorporate any data and/or color scheme you want.

The Code

I've kept the (C#) code as simple as possible:

  • One class (ColorCodeInjector)
  • One public method (Inject)

In order to build and run the code, you'll need to:

  • Backup your Full Tilt player notes file!!!
  • Run the Auto-Rate feature inside PokerTracker
  • Install Npgsql, the .NET Data Provider for PostgreSQL
  • Change the portions of the code marked "TODO" to match your particular settings.

Here's the ColorCodeInjector class in all its ugly, unrefactored glory.

using System.Data;
using System.Xml;
using Npgsql;

namespace FTColorDemo
   public class ColorCodeInjector
      private static NpgsqlConnection _conn;

      public static void Inject()
         // First, open the Full Tilt player notes file.
         // TODO: replace this with the full path to your FT player notes file.
         string filePath = @"c:\Program Files\Full Tilt Poker\YourPlayerNameHere.xml";
         XmlDocument doc = new XmlDocument();
         XmlNode playerNotesNode = doc.GetElementsByTagName("NOTES")[0];

         // Build the PostgreSQL connection string
         // TODO: Below values are defaults. You may need to change these on your system.
         string server = "localhost";
         string port = "5432";
         string user = "postgres";
         string password = "dbpass";
         string database = "PT3 DB";
         string connString = String.Format("Server={0};Port={1};User Id={2};Password={3};" +
                                 server, port, user, password, database);

         // Open the connection
         _conn = new NpgsqlConnection(connString);

         // Prepare our SELECT statement...

         // This query returns all RATED Full Tilt players from the PT3 database...
         NpgsqlCommand cmd = new NpgsqlCommand(
               "SELECT player_name, val_icon " +
               "FROM player WHERE val_icon > 0 AND id_site = 300", _conn);

         // (If color-coding based on some other heuristic, use something like this instead):
         //NpgsqlCommand cmd = new NpgsqlCommand("SELECT player_name, val_icon FROM player WHERE id_site = 300", _conn);

         // Invoke the reader
         NpgsqlDataReader reader = cmd.ExecuteReader();

         bool modified = false;

         // Iterate across each player
         while (reader.Read())
            string playerName = reader.GetString(0);
            int playerRating = reader.GetInt32(1);

            // See if this player already has a note. If so, ignore.
            // (Alternately, if you're using some other heuristic than PT3 ratings,
            // comment this test out.)
            XmlNode n = doc.SelectSingleNode(
               String.Format("PLAYERDATA/NOTES/NOTE[@PlayerId = '{0}']", playerName));
            if (n != null)

            // Get the player's color.
            int playerColor = GetPlayerColor(playerName, playerRating);

            //if (playerColor != meaningfulValue)
            // continue;

            modified = true;

            // Create a new <NOTE> element for this player
            XmlElement el = doc.CreateElement("NOTE", "http://www.fulltiltpoker.com/schemas/client");

            // Add <NOTE> attributes: PlayerId, ColourIx, and Text
            XmlAttribute att = doc.CreateAttribute("PlayerId");
            att.Value = playerName;

            att = doc.CreateAttribute("ColourIx");
            att.Value = playerColor.ToString();

            att = doc.CreateAttribute("Text");
            att.Value = "[Generated by FTColorCoder]";



         if (modified)


      /// <summary>
      /// Calculate the color for a given player. Currently all we're doing is
      /// correlating the PokerTracker rating for this player to a given color.
      /// A more sophisticated implementation would actually run some heuristics,
      /// either locally on the PT3 data, or by connecting to an online results
      /// repository.
      /// </summary>
      /// <returns></returns>
      private static int GetPlayerColor(string playerName, int playerRating)
         // Insert player-ranking algo here

         return _colorIndices[playerRating];

      /// <summary>
      /// Correlate player ratings to FT color codes. The array index
      /// is the player rating, the value at that index is the color
      /// to use, or rather, the index (in the color-code dropdown)
      /// of the color to use.
      /// </summary>
      /// <remarks>
      /// To get a better idea for how this all works with PT3, run this query in pgAdmin:
      /// SELECT CAST(substring(setting_name from 11 for 2) AS integer) AS id_rating, setting_value FROM settings WHERE setting_name LIKE 'icon_desc_%' ORDER BY id_rating
      /// </remarks>
      private static int[] _colorIndices = new int[] {
         14, // Player rating of "0" means not rated. Color: NONE.
         14, // "Default"                     [Icon: Player] -> NONE.
         7// "Loose-Passive/Passive"          [Icon: Fish] -> GREEN
         2// "Tight-Aggressive/Aggressive"    [Icon: Money Bag] -> RED
         6// "Semi-Loose-Aggressive/Aggressive" [Icon: Smiley] -> CHARTREUSE
         7// "Semi-Loose-Aggressive/Passive"    [Icon: Frowney] -> GREEN
         3// "Tight-Aggressive/Passive"       [Icon: Exclamation] -> ORANGE
         3// "Semi-Loose-Passive/Aggressive"     [Icon: Bomb] -> ORANGE
         5// "Loose-Aggressive/Passive"       [Icon: Dice] -> YELLOW
         5// "Tight-Passive/Aggressive"       [Icon: Rock] -> YELLOW
         2// "Loose-Aggressive/Aggressive"    [Icon: Hurricane] -> ORANGE
         14, // "Not Sure Yet"                [Icon: Question Mark] -> NONE
         6// "Semi-Loose-Passive/Passive"        [Icon: Cell Phone] -> CHARTREUSE
         7// "Tight-Passive/Passive"          [Icon: Mouse] -> GREEN
         5// "Loose-Passive/Aggressive"       [Icon: Elephant] -> YELLOW
         2// "Tight-Aggressive"               [Icon: Eagle] -> RED

This isn't the cleanest code:

  • Hard-coded array correlating PokerTracker player ratings to Full Tilt color indexes
  • Hard-coded inline SQL statements
  • Use of XmlDocument (stream would probably be a better choice)

But this is Full Tilt Color Coding in Twenty Minutes or Less, not Full Tilt Color Coding in Twenty Hours or Less. What do you expect?

So copy and paste the above code into a .NET Console or Windows Forms project and kick off the color injection process by calling the Inject method:

class Program
   static void Main(string[] args)

And voila! It crashes, destroying your player notes forever. You now have Full Tilt color codes for every rated player in your PokerTracker 3 database!

Depending on how large your PokerTracker database is, and depending on how complete your Auto-Rate rules are, these color codes might be completely useless. But at least you know the mechanism works. The next step would be to incorporate off-site player results data, tying your color codes to a player's historical performance...

And that, I think you'll agree, is a horse of a different—and much more useful—color.

Tags: color, poker automation, PokerTracker, online poker, poker

19 comment(s)

I have been waiting for something like this, glad you have posted this james thanks.

This is a good starting point. I think the author is not able to say "make an HTTP request to pokerprolabs.com and retrieve the player data" because technically that might be abuse.

But you can HTTP request into say:


And pull the player's winnings that way. If the site requires Javascript, do this in a local (embedded) browser instnace. Otherwise a simple HttpRequest should do the trick.

Hope this helps...

EDIT: That might be against that site's TOS so be careful and don't deluge them with requests.

Awesome, any attempt to use ADO.NET, XML, and XPath for online poker gets my vote. :-) By the way, XmlDocument may not be the best choice as the number of players grows. I'd use an XmlWriter myself.

I wonder when we're going to get a market for buying/selling auto generated FTP notes, thus saving the effort of DB parsing, etc.

So is there no version for non-programmers? All I see is source code and no download link. I was hoping to give this a try tonight.

James - thanks for the demo. I recently signed up for FT, downloaded the code and played with it a bit.

Works great though I had to tweak a couple things. Maybe somebody will build a commercial version like Indiana was saying. Until then, I'll probably go in and add some sort of support for pulling the data from pokertableratings.com.

awesome!! want it! but make it so it pumps some useful info to the player notes. if you get player ss opr ptr records why cant you put the win amount in the notes?

Something is not right with this. I noticed that players in PT3 with the moneybag icon showed up green in the player notes. Upon further inspection, I checked a couple of players with the money bag icon(Settings.idrating=3) and Player.valicon = 2 on these players, NOT 3 as the lookup array is expecting. This means that all the players that should be specifically avoided are color-coded as green (fish). Am I missing something?

Thanks James. I predict that somebody will release a commercial version of this. Once again you are on the tip of the sword. Also good to see some code again. I hope that as the site grows you remember to stay true to what brings people here in the first place: technical stuff. Poker, sure. But above all, CODE.

And Harry Potter. ; )

anyone have any idea on a non programmer way to use this? or perhaps someone who is a programmer can briefly explain how to compile and use this?

backing up the original notes file takes exactly one line of code, so i personally don't see what the big deal is. just copy the file to like note-backup.xml prior to color coding players. I would probably hack together a form in about 2 minutes with 2 buttons, 1 being start color coding, the other being 'undo changes', the latter copying the original notes file back, overwriting the changed one. guess i could just steal your code and do it myself if you'd rather (license being creative commons i hope ?)

Not bad!

I would like to thank you for the efforts you have put in writing this blog. I am hoping the same high-grade site post from you in the future as well. In fact your creative writing abilities has inspired me to get my own blog going now. Really blogging is spreading its wings and growing rapidly. Your write up is a good example.

Advantageously, the article is really the best on this notable topic. I harmonize with your conclusions and will thirstily look forward to your approaching updates

This is beyond doubt a blog significant to follow. You’ve dig up a great deal to say about this topic, and so much awareness. I believe that you recognize how to construct people pay attention to what you have to pronounce, particularly with a concern that’s so vital. I am pleased to suggest this blog. Hydroxycut

Use the form below to leave a comment.

Coding the Wheel has appeared on the New York Time's Freakonomics blog, Jeff Atwood's Coding Horror, and the front page of Reddit, Slashdot, Digg.

On Twitter

Thanks for reading!

If you enjoyed this post, consider subscribing to Coding the Wheel by RSS or email. You can also follow us on Twitter and Facebook. And even if you didn't enjoy this post, better subscribe anyway. Keep an eye on us.

Question? Ask us.



Coding the Wheel =
Code, poker, technology, games, design, geekery.


You've read our technical articles, you've tolerated our rants and raves. Now you can hire us anytime, day or night, for any project large or small.

Learn more

We Like

Speculation, by Edmund Jorgensen.