Using Custom Reports and Statistics

PokerTracker 3 version 3.10
October 25, 2013
  • Making a new version of a Statistic

    For how to make a new version of a statistic please see this tutorial.

  • Introduction

    PT3 allows you to create your own Custom Reports and Statistics{*} to extend the functionality already built in even further.

    • You can build your own reports which you can name and save for future use, or to share with other PT3 users.
    • Reports can display built-in and/or custom statistics and can be filtered using the normal Filters or more complex filters based on any appropriate statistic.
    • Reports can also be structured in ways that the built-in reports don't allow.
    • Statistics can be built to retrieve and display information from the database which isn't available in existing stats.
    • Stats can be formatted to display their values as you choose, including different number formats, money, checkboxes or text.
    • Stats can have different colours based on their own or other stats' values.
    • Stats can be Exported and shared with other PT3 users, or for backup purposes.

    {*} Custom statistics are not available during the trial period - you must be registered to use them.

    This tutorial is additional information to be used in conjuction with the main Custom Statistics and Reports documentation - it does not replace the documentation, and does not attempt to detail every function.
    It is intended to give practical help and examples of how to create and use your own (or other people's) reports and statistics.

    In addition this guide will primarily discuss cash reports and statistics but most things apply to tournaments too and the ideas should translate pretty directly.
    For example, see the Tutorial on Converting a Cash Stat to Tournament use.

    For a complete walkthrough of how to build a statistic see this tutorial.

  • Sections

    Every report and statistic in PT3 is in a specific section.

    Only statistics from the same section can be used in a report - e.g. if the report is in the Holdem Cash Player Statistics section then only stats from the Holdem Cash Player Statistics section can be displayed in that report.

    The sections are:

    • Holdem Cash Hand – Single Hand Details
    • Holdem Cash Player Statistics – Player Statistics
    • Holdem Cash Session – Single Session Details
    • Holdem Cash Sessions – Summary of Sessions
    • Holdem Tournament Hand – Single Tournament Hand Details
    • Holdem Tournament Player Statistics – Tournament Player Statistics
    • Holdem Tournament Tournament – Single Tournament Details
    • Holdem Tournament Tournaments – Summary of Tournaments

    Note: The only statistics you can display in the HUD are in the Holdem Cash Player Statistics section - or Holdem Tournament Player Statistics for tournament tables.

    Note: There are also the same set of sections for Omaha, and these work exactly the same as for Holdem.

    From now on I'm only going to refer to the holdem cash sections, but the same applies to the equivalent omaha and tournament sections.

    • Holdem Cash Hands
      • Reports which will list individual hands.
        Generally each row of a report will show information about a single hand from a single player's point of view. This can include the player's hole cards, actions and amount won or lost; as well as general hand information like the time and date, board cards, pot size, etc.
        e.g. You could filter a report like this to list every hand a player played in a certain way, or which had a certain pot size, etc.
      • Stats about individual hands.
        Stats in this section refer to individual hands, so can relate to specific single actions or series of actions, hole or board cards, bet or pot sizes, etc.
        e.g. You could add a stat to display a checkbox to indicate whether or not the player made a continuation bet on the flop in a hand (but a stat to show how often the player c-bet across all hands would be in the next section, HCPS).

      Built-in reports

      • Hands > Known Starting Hands Detail
      • Hands > Known Final Hands Detail
      • Sessions > Session Hands
      • Positions > Position Hands Detail
      • Winnings > Daily Hands
    • Holdem Cash Player Statistics
      • This is the section you will probably use the most as it is the one which holds statistics based on all of a player's hands. These are generally totals or percentages of actions a player made across all the hands they played.
      • All HUD statistics are in the Holdem Cash Player Statistics section.
      • Reports in this section can be filtered on a by-hand basis, so you can see stats for just those hands which meet certain criteria.
        e.g. If you apply a filter for hands which the player made a preflop raise then reports in this section would only show stats from hands where the player raised preflop. This would mean that PFR (and VP$IP) would both show as 100% - every hand where you PFR you also VP$IP, but you could then see (for instance) what your BB/100 is like for just those hands.
      • Stats in this section are built from totals across all of a player's hands.
        e.g. You could add a stat to calculate the percentage of times a player raised preflop, checked the flop then folded the turn when they faced a bet.

      Built-in reports

      • General > Player Statistics
      • Hands > Known Starting Hands Summary
      • Hands > Known Final Hands Summary
      • Positions > Position Statistics
      • Positions > Position Hands
      • Summary > Player Summary
    • Holdem Cash Session
      • This section contains information about individual sessions from a single player's point of view.
        e.g. Number of hands played, amount won/lost, time played, site, limit, etc.
        It does NOT allow access to stats based on play of individual hands.
        If you apply a filter based on player actions then reports in this section will NOT be filtered. Filters which filter out whole sessions (such as site, limit, date filters) will work.
        In reports in this section you will only ever see complete session totals.

      Built-in reports

      • Sessions > Sessions By Time/Table
    • Holdem Cash Sessions
      • This section contains total summary information of all sessions played by a player.

      Built-in reports

      • General > Player Summary
      • Winnings > Winnings By Month
      • Winnings > Winnings For Month
    • Report Types

      General Tab -> Top report = Sessions stats
      General Tab -> Bottom report = Player Statistics stats
      Hands tab -> Top report = Player Statistics stats
      Hands tab -> Bottom report = Hand stats
      Sessions tab -> Top report = Session stats
      Sessions tab -> Hands report = Hand stats
      Positions tab -> Top report = Player Statistics stats
      Positions tab -> Middle report = Player Statistics stats
      Positions tab -> Bottom report = Hand stats
      Winnings tab -> Top report = Sessions stats
      Winnings tab -> Middle report = Sessions stats
      Winnings tab -> Bottom report (when showing Hands) = Hand stats
      Summary tab -> Bottom report = Player Statistics stats

  • Creating a Custom Report

    Creating a custom report is simple - the Custom Reports guide explains all the elements of custom reports so I'll just explain the steps you need to take to create your own report, and then in the next section I'll create an example report with detailed steps and images to walk you through it.

    Select the Cash Games > Reports tab.

    The first thing to do is decide which section the report will be in and select it from the Section dropdown list.
    You should then see the Available Stats list populate with stats from the selected section.

    Now you need to give your report a name (by typing in the Name field) to allow you to identify it in future - you cannot run a report until you have named it.

    To add statistics to your report double click them in the list of Available Stats and they will appear in the Report Stats list above.
    You can filter the available stats by selecting a Category to make it easier to find the stats you want.
    When you have added your stats you can change they order they will be shown in the report by selecting a stat in the Report Stats list and using the up and down arrows to move them.

    That's all you really need to do, but there are further options to allow you to tweak your report contents, sorting order, etc., should you want to.

    • Filters

      The blue Filters link allows you to filter your report in three ways.

      These three methods can be combined, so for instance you can apply both simple and custom filters together. Any report filters that you apply will override any filters already active (or applied) via the main Filters button, though.

      1. The most basic is the Filter on Active Player option.

      This determines whether the report will show information for just the player currently selected in the Player List or for all players.

      Be aware that if you uncheck this option then your report will show information for all players - this can lead to very large reports which can take a very long time to genarate. In particular you need to be really careful with reports in the Holdem Cash Hands section - showing every hand in the database from every player's point of view will mean a very big report!
      However, if you want a Holdem Cash Player Statistics report (for instance) to show stats for more than one player you must uncheck this option.

      2. The Simple Filters button is exactly the same as the main Filters window but filters applied here will only apply to, and will be saved with, this report.

      If you have any Simple Filters applied the button text will go blue.

      Note: Filtering rules apply here as described in "Sections" - if you filter for specific actions or types of hands it will only affect reports in the Holdem Cash Hands and Holdem Cash Player Statistics sections - Holdem Cash Session and Holdem Cash Sessions reports will NOT be filtered to show results from only a few hands; these will always show results from whole sessions.

      3. You can also enter your own Custom Filters for situations not covered by the Simple Filters window using statistics or columns in the same section as the report.

      To do this enter a Filter Expression.
      The easiest way to do this is to use the Insert link to select your chosen column, statistic or operator but once you are used to the format you can just type in the expression.
      This allows some quite advanced filters, but it doesn't need to be complicated.

      For example, to filter a Holdem Cash Player Statistics report to only show players who have played more than 100 hands you could enter this expression:
      #Hands# > 100
      Statistic names are identified using # either side. To enter this same filter using the Column instead of the Statistic you would enter:
      cnt_hands > 100

      The above expressions for the number of hands are equivalent whether you use the statistic or column, but let's say you want to filter to only show players who have 3-bet on the river a certain number of times. The "3Bet River" stat is a percentage of times they bet when they had the opportunity (not a count of how many times they 3-bet) so we need to use the column "cnt_r_3bet" in the filter expression:
      cnt_r_3bet > 10.

      Note: This will only filter the report to show those players who 3-bet on the river more than 10 times - it will NOT filter their stats to only those hands where they 3-bet, it will still show their overall stats.
      To see only stats from the hands where they 3-bet the river you need to use the Simple Filters button.

    • Sorting

      The Sorting window allows you to define the order in which your report will be sorted.
      You can sort by more than one stat and the sorting will be applied in the order defined on the right.

      For instance if you want to sort a Holdem Cash Hands report by limit then by amount won so that you see all hands from the same limit together but sorted by amount won within each limit you would double click Limit and Amount Won on the left and then make sure that Limit was listed first on the right hand side (using the up/down arrows).

      Double click a stat on the right hand side to change the sort order between ascending and descending.

    • Advanced

      The Advanced link allows you to specify whether or not the report has a summary (totals) line at the bottom, and to define colours for rows within the report based on the value of a statistic or column in the same way you define filter expressions.
      See the window for an example expression.

      To see what RGB values to use for different colours open the Windows colour-chooser window and note the RGB values for your chosen colour - for instance you can access this by double clicking one of the colour blocks in the Settings Window.

    • Running Reports

      When you are happy with your report click the Save button.

      You can then run your report by clicking the Run Report button and the results will be shown in the main part of the report window.
      This can take a while to populate if there is a lot of information to be retrieved for your report.

      Tip! If you click Run Report before saving PT3 will ask you if you want to save - you must save in order for your changes to be used when you run the report.

    • Managing Reports

      Now that you have saved your report it will be available for use any time you visit the Reports tab.
      To access it again select the appropriate section then choose your report name from the Report dropdown list.

      You can also click the Export button to save your report as a file outside PT3 for backup or to copy to another computer or share with other PT3 users via the Repository.
      If you download a report from the Repository, or want to import one of your own reports that you removed from PT3, use the Import button.

      If you have a report that you no longer want to keep in PT3 click the Remove button to delete it.
      If you previously exported this report then the file you exported it to will not be affected so you can re-import it later.

      If you want to start over with a new empty report click the New button - if you hadn't saved the current report you will be asked whether you want to save it. As long as you have saved it you can get back to your previous report at any time by selecting it from the dropdown list but you can only have one report open at once.

  • Report Walkthrough

    The previous post explains the process of creating a custom report, and how to use the various options.

    This post will walk through the steps needed to create a very simple report in the Holdem Cash Player Statistics section, with screenshots to illustrate.

    This is just a basic report to show some stats for all players with more than 100 hands in the database, sorted by VP$IP.

    1. Click the Reports tab.

    2. Select Holdem Cash Player Statistics from the Section dropdown list.

    3. Give your report a Name - my unimaginative name is "Example HCPS Report", but I'm sure you can do better than that..

    4. Scroll the Available Stats list up and down to find and double-click the stats you want to see in your report.
    I've added Player, Hands, VP$IP, PFR, Amount Won and BB/100.

    5. These stats will then be shown in the Report Stats section above.

    6. Stats will be listed in the order you add them but you can change the order using the up and down buttons.


    You could save and run the report now, but it will currently only show stats for the current selected player and will sort by the player name, so we need to set Filters and Sorting information.

    7. Click the blue Filters link to open the Edit Report Filter window.


    7a. Untick the Filter on Active Player option so that the report will show stats for all players.

    7b. Click the blue Insert link and go to the Statistics tab.
    Scroll down the list to find "Hands" and select it then click OK.

    This will enter into the Filter Expression field:


    7c. After this type " > 100" so that the expression now says:

    #Hands# > 100


    This will filter players based on the value of their "Hands" stat (which is also in the Holdem Cash Player Statistics section).

    Tip! You can type the whole expression yourself but Insert is particularly useful when you don't know the exact name of the Statistic or Column that you want to use.

    7d. Click the Save button and you should see the filter expression appear in the Filters list in the top section of the window.

    Tip! At this point you could click New and enter another filter expression.
    You could also click the Simple Filters button to restrict which hands are used to generate the stats.

    7e. This report only needs this one filter so click OK to store the filters and return to the main report window.

    8. Click the blue Sorting link to open the Edit Report Sorting window.


    8a. To sort the report by VP$IP select it in the list on the left and click the right arrow in the centre.
    VP$IP will move to the list on the right.
    The Sort Method will be 'Ascending' by default - if you prefer to see the highest VP$IP values at the top of the report instead then double click the stat on the right hand side to change to 'Descending'.

    Tip! If you want to sort by more than one column then add more and use the up and down arrows to change the priority order for sorting.

    8b. Click OK to store the sorting preferences and return to the main report window.

    9. The report is now ready so click Save to store it.

    10. Click Run Report to populate the report.


  • How Statistics are structured

    Statistics are the values that are displayed in Reports and the HUD.
    They display information taken from the Database Tables, but they cannot access this information directly - that is the job of Columns.
    Statistics are usually built using one or more Columns or Variables.
    They can be formatted to display information in many ways.

    Columns can access the Database Tables directly and generally calculate a single (unformatted) piece of information (whereas a Statistic might use multiple pieces of information combined together to form their displayed value).
    To display the value calculated by a Column you need to use a Statistic.

    Variables can be used to do calculations using Columns, and then these can be used in a Statistic as well.

    Database Tables >> Columns [ >> Variables ] >> Statistic

    For instance, a typical stat which can be displayed in the HUD displays the percentage of times that a player did some action "A" out of the opportunites they had to do "A". (e.g. "A" might be "bet the flop" - you can only bet the flop if you see the flop and no-one bets before the action gets to you.)

    Stat "A" is constructed using two columns:

    • cnt_a - how often A happened
    • cnt_a_opp - how often there was an opportunity to do A

    These columns look up their information from the relevant tables in the database.

    The Value Expression of A is then:

    • (cnt_a / cnt_a_opp) * 100
    • Example

      The statistic "3Bet Preflop" is calculated as the number of times the player 3-bet preflop divided by the number of times they had the chance to 3-bet preflop (and multiplied by 100 to give a percentage).

      The Value Expression is:

      (cnt_p_3bet / cnt_p_3bet_opp) * 100



      This uses two columns to count the two numbers needed.

      "cnt_p_3bet" counts the number of times the player 3-bet preflop, using the database table and field "holdem_hand_player_statistics.flg_p_3bet".

      The Expression is:

      sum(if[holdem_hand_player_statistics.flg_p_3bet, 1, 0])

      I'll explain how to use the sum(if[...]]) construct later.



      "cnt_p_3bet_opp" counts the number of times the player had an opportunity to 3-bet preflop, using the database table and field "holdem_hand_player_statistics.flg_p_3bet_opp".

      The Expression is:

      sum(if[holdem_hand_player_statistics.flg_p_3bet_opp, 1, 0])



  • Elements of a Statistic

    The information about a Statistic is split across four tabs.
    This section defines each field in the Edit Stat Info section.

    • Definition

      The Definition tab is the main information about a stat - its name, description and value.

      • Name - The name of the stat.
      • Description - A text description of the stat.
      • Value Expression - The calculated value of the stat. This is not necessarily the same as the information displayed by the stat - that is defined in the Format tab (see below).



    • Format

      The Format tab defines how the stat will appear when it is used in reports or the HUD.
      You must fill in the Title and Width fields in order to be able to use the stat in reports.

      • Title - The information shown in the column header of a report.
      • Width - The width the column will have in a report.
      • Alignment - The dropdown list to the right allows you to define how the stat will be aligned in reports.
      • Format Expression - This is where the main work of displaying the stat is done. You can choose to display the statistic's plain value, or format it in some way.
      • This is used for both reports and the HUD, but note that the number of decimal places specified in the HUD's Statistic Properties will override what is specified here (for normal numeric values).
      • If you leave this field blank then the value of the Value Expression will be displayed with no formatting. For numeric values this means that lots of decimal places will be shown, which are usually unnecessary and look messy.
      • Therefore the most common Format Expression you will see is "/%.2f" (as illustrated), which formats a number to 2 decimal places.
      • There are many other ways to format stats, which are detailed later in this tutorial. See the built-in stats for examples.
      • Format Summary Expression - Defined in the same way at the Format Expression, but defines how the summary/total row at the bottom of a report will appear, so sometimes has a different format.



    • Categories

      The Categories tab is simply to make finding stats easier when adding them to reports or the HUD - you can filter the list of stats to any of the available categories. Categories are different in each Section.

      To add or remove a category, select it and use the < or > button to move it from one side to the other.



    • Colors

      The Colors tab allows you to color the stat based on the value of any Column, Variable or Statistic (from the same Section), or on the value of a calculation involving combinations of these.

      Color Conditions are applied in order - the first Condition Expression which is true is applied.
      Each color condition can be specified to be used in either the HUD, the Tracker (reports) or both.

      Change the color by double-clicking the Color block, then click Save.
      For examples, please see the How To: Advanced HUD Configuration.



    • Additional Elements

      The blue Insert and Validate links are to help you construct valid expressions.

      • Insert - If you do not know the exact name of the item you want to use, this allows you to select a Column, Variable, Statistic, Function or Operator.
      • Validate - Click this to check that what you have entered is a valid expression.

      The option and buttons at the bottom of the window are used to manage statistics.

      • Protected - This is checked for built-in stats, which cannot be edited, and unchecked for custom stats.
      • New - Creates a new, blank, statistic.
      • Dup - Duplicates the current statistic, making a copy which can be re-named and changed. If you want to build a similar stat to one which already exists then this saves you recreating it from scratch.
      • Save - Saves the statistic within PT3.
      • Remove - Deletes the statistic from within PT3.
      • Export - Saves the statistic to a file outside PT3. You can share your statistic with other PT3 users via the Repository, send it to someone via email, or just keep it as a backup or to import to PT3 on another computer.
      • Import - Loads a previously Exported stat, or one that you downloaded from the Repository or elsewhere.
  • Format Expressions

    The Format Expression for a Statistic defines how the stat will be displayed in reports and the HUD.

    If you leave this field blank then the value calculated in the Value Expression will be displayed.
    This is OK, but most stats are calculated numeric values which will have a lot of decimal places, so if you leave the Format Expression blank then the value will be displayed to say 6 decimal places. e.g. "3.000000"

    • Basic Numeric Formatting

      In most cases you won't want to see that many decimal places and the simplest way to format the value is to use the old 'c' [programming language] format expression of, for example:


      This formats a float, or floating point (decimal) number, to 2 decimal places.
      Should you wish to display 1 decimal place instead you can change this to /%.1f - other numbers can be used too, including 0 (zero).

    • format_number

      Another way to format numbers is with the format_number function.

      format_number( value, decimals, commas, color )

      • value - the value you want to display, typically copied from the Value Expression
      • decimals - the number of decimal places to display
      • commas - true if you want commas separators for thousands (e.g. 1,000 instead of 1000)
      • color - true if you want positive values to be green and negative to be red. If you want the stat to be default color or if you want to define your own color ranges then you should set this to false.


      format_number( (cnt_p_3bet / cnt_p_3bet_opp) * 100, 2, false, false )
      ..would display as:

    • format_money

      The format_money function will format a numeric value as a currency amount.

      format_money( value, color )

      • value - the value you want to display, typically copied from the Value Expression
      • color - true if you want positive values to be green and negative to be red. If you want the stat to be default color or if you want to define your own color ranges then you should set this to false.


      format_money( amt_won, true )
      ..would display as:

    • format_date

      The format_date function displays a date and time.

      format_date( date, format )

      • date - the date you want to display.
      • format - one of a set of options:
        - 'date' shows just the date
        - 'datetime' shows the date and time
        - 'datetimes' shows the date and time including seconds
        - 'datetimesm' shows the date and time including seconds and milliseconds


      format_date( date_played, 'datetime' )
      ..would display as:
      2009/10/27 15:24

    • format_bool

      The format_bool function will display a boolean (true/false) value either as a checkbox, Yes/No or Y/N.

      format_bool( value, format )

      • value - the boolean value you want to display
      • format - one of a set of options:
        - 'check' shows a checkbox; checked for 'true' and unchecked for 'false'
        - 'yesno' shows either "Yes" or "No"
        - 'yn' shows either "Y" or "N"


      format_bool( flg_f_saw, 'check' )
      ..would display as:

    • format

      The format function is a more general formatting function which allows you to combine values together into a formatted string.

      format( format_str, ... )

      • format_str - the formatting string. This can contain plain text and 'placeholders' labelled as {1}, {2}, {3} etc.
        ... - the values to be displayed by the placeholders {1}, {2}, {3} etc in order.

      Example 1 (Holdem Cash Hand section)

      format( 'The hand was played at {1} and the player won {2} big blinds.', format_date(date_played,'datetime'), format_number(amt_bb_won,1,false,false) )
      ..would display:
      The hand was played at 2009/10/27 15:24 and the player won 5.5 big blinds.

      Example 2 (Holdem Cash Player Statistics section)

      format( '{1} had {2} steal opportunities and raised {3} times', str_player_name, format_number(cnt_steal_opp,0,false,false), format_number(cnt_steal_att,0,false,false) )
      ..would display as:
      Player1 had 20 steal opportunities and raised 12 times

      More realistically, you might use this format expression:

      format( '{1}% ({2}/{3})', (cnt_steal_att / cnt_steal_opp) * 100, format_number(cnt_steal_opp,0,false,false), format_number(cnt_steal_att,0,false,false) )
      ..which would display as:
      60% (12/20)

      Note: this sort of thing is not necessary for use in the HUD as you can display times/opportunities in the HUD using the Statistic Properties.

    • trim

      The trim function can be used to shorten text (string) values, such as the player name.
      This is normally used in conjuction with ignore_formatting so that the HUD does not alter the text.


      ..would display the first 5 characters of the player name.
      See the "Player Short" stat available for download from the "Get More" section.

    • if

      The if function is used to display one thing or the other based on some criteria.

      if( epxr, then, else )

      • expr - the expression to be evaluated. This must evaluate to a boolean (true/false) value.
      • then - if the expression is true this value is used
      • else - if the expression is false this value is used

      Example 1

      if( cnt_hands > 100, format_money(amt_won,true), '--' )
      ..would display -- for any players who have not played more than 100 hands.
      (See above for help with format_money)

      Example 2

      One way I use the if function is to extend the use of format_bool (see above) to only show the checkbox if an opportunity arose, and have the tick indicate whether or not the opportunity was taken.
      For instance, in the Holdem Cash Hand section I have a "Steal Attempted" stat which indicates whether or not the player made an open raise from a steal position but the checkbox is only shown for hands where the player had an opportunity to attempt a steal.
      * No steal opportunity - nothing is shown
      * Steal opportunity, no raise - empty checkbox shown
      * Steal opportunity, raised - ticked checkbox is shown

      The format expression for this is:
      if ( flg_steal_opp, format_bool(flg_steal_attempt,'check'), '' )

      What this does is check whether there was a steal opportunity; if so it displays a checkbox to show the value of flg_steal_attempt; if not it displays an empty string ('') which will result in nothing being shown.

      Example 3

      You can also use if to hide stat information until certain conditions are met, such as a minimum number of opportunites.

      For instance, if you want to display the 4-bet preflop stat but censor the information until the player has had the opportunity to 4-bet 10 times (to stop you acting on information which doesn't have a significant sample) you could use an expression like:

      if ( cnt_p_4bet_opp < 10, 'X', format_number( (cnt_p_4bet / cnt_p_4bet_opp) * 100, 2, false, false ) )

    • lookup_ functions

      There are several lookup_ functions available, which allow you to access string representations of things like limits, sites and card values, amongst other things.
      I am not going to detail all of the lookup functions here, but I will list a few stats that you can look at to see how they are used.

      All of these are in the Holdem Cash Hands section:

      • Final Hand - lookup_handrank
      • Flop1/Flop2/Flop3/Turn/River - lookup_from_id (using 'card')
      • Hand - lookup_from_id (using 'cardpair')
      • Limit - lookup_limit_desc
      • Made Hand - lookup_from_id (using 'finalgroup')
      • Site - lookup_from_id (using 'siteabbr')
  • How Columns are built

    Columns are used to retrieve information directly from the database and generate information to be shown in Statistics.
    For information on how Statistics and Columns fit together see this section.

    Exactly how this works depends on which section the column is in.

    For instance the Holdem Cash Hand (HCH) section retrieves information about individual hands so the column will have a value related to a single hand – for instance it might have a boolean (true/false) value to indicate whether the player saw the flop in the hand, or a numeric value to show the size of a bet made on the flop.


    • holdem_hand_player_statistics.flg_f_saw
    • holdem_hand_player_detail.amt_f_bet_made

    The Holdem Cash Player Statistics (HCPS) section has information from all of a player’s hands. The column effectively iterates through every hand for the player, so rather than recording whether or not the player saw the flop in a specific hand you might have a column to count the hands where the player saw the flop.


    • sum(if[holdem_hand_player_statistics.flg_f_saw, 1, 0])

    This expression uses the same database field as the HCH stat, but it references it for every hand, and adds up (sum) the result of the if statement for each hand.

    The expression works like this:

    ‘SUM’ adds up the values from all the hands.
    ‘IF’ checks each hand.

    The format is:

    sum( if[ expression, then, else ] )

    For each hand it evaluates the expression, and if it is true it returns the ‘then’ value, otherwise it returns the ‘else’ value.
    Here ‘then’ is 1 and ‘else’ is 0 – this has the effect of counting the hands where the player saw the flop.
    In English: if [ the player saw the flop, return 1, else return 0 ].

    These 1s and 0s are then added up by the SUM to give the number of times the player saw the flop.

    For instance, if the player played 5 hands and saw the flop in the first and third, then you would effectively have: sum( 1, 0, 1, 0, 0 ) = 1 + 0 + 1 + 0 + 0 = 2.

    The values returned do not have to be 1s and 0s, but that is the most common usage.
    As an example of how else it might be used the following expression will return the total amount bet on the flop as continuation bets, across all of a player’s hands, but will not count bets made when the player was not the preflop aggressor.


    • sum( if[holdem_hand_player_statistics.flg_f_cbet, holdem_hand_player_detail.val_f_bet_made, 0] )

    The Holdem Cash Session section works in the same way as Holdem Cash Hand – it refers to individual sessions.

    The Holdem Cash Sessions section works in the same way as Holdem Cash Player Statistics – it iterates through all sessions to calculate total values.

    The tournament sections work in the same way.

    • Naming conventions

      We use conventional names for columns in PT3 to aid understanding and to make it easier to find things. This is not required, but is recommended.

      We normally construct a name like this:


      The first part (cnt_) means ‘count’ – how often something happened (this is in the HCPS section).
      The second part (p_) means ‘preflop’.
      The third part (3bet) is the situation we’re counting – so this column counts preflop 3-bets.
      We may also add a 4th part (or more) - if we were counting preflop 3-bet opportunities, for instance, we’d call it cnt_p_3bet_opp.

      Common types are:

      • amt_ - an amount of something, often money
      • cnt_ - a count of how often something happened
      • date_ - a date
      • enum_ - an enumerator – one of a known set of values, such as a character P, F, T or R to identify Preflop, Flop, Turn or River
      • flg_ - a flag, or boolean (true/false) value
      • id_ - an identifier (e.g. for a hand or card, etc)
      • str_ - a string
      • val_ - a numeric value

      p_ for preflop, f_, t_ and r_ for flop, turn or river or ttl_ for total.

  • Constructing column expressions

    This section describew some of the common elements that make up an expression in a Column.

    All of the elements described here can be extended and combined to give more complex expressions, should the Statistic that you are building need that.

    Expressions can consist of database fields, functions and operators, including some PostgreSQL functions.

    The best ways to explore the options are to examine existing columns' Expressions and to use the blue insert link above and to the right of the Expression field.

    • Simple Expressions

      An Expression can be as simple as retrieving a single value from a field in the database.
      For instance, in the Holdem Cash Hand section you might want a stat to display a checkbox to indicate whether or not the player limped preflop in a hand.
      The expression for this would just be:


      Because this is already a boolean (true/false) value we don't need to do anything else with it.

      Similarly, you might want a stat to display the total amount the player bet in a hand.
      The expression for this would be:


    • Use of IF

      The IF function is used to determine whether a condition is true or false, and return a different value based on the outcome.
      The structure of the IF function is described above, but it is basically:

        IF[ expression, then, else ]

      If the expression evaluates to true the then value is used, otherwise the else value is used.

      For instance, if you want a stat in the Holdem Cash Hand section to show the size of a continuation bet on the flop but to show zero for non-continuation bets you could use an expression like this:

        if[ holdem_hand_player_statistics.flg_f_cbet, holdem_hand_player_detail.amt_f_bet_made, 0 ]

      This expression says: if the player made a continuation bet (holdem_hand_player_statistics.flg_f_cbet is true) then return the size of the bet (holdem_hand_player_detail.amt_f_bet_made), else return 0.

      The IF function is also commonly used in combination with SUM to generate a count of how many times a certain situation occurs across all hands - for instance in the Holdem Cash Player Statistics section.

      I will describe the use of SUM next, but for now let's see how IF can be used to turn a boolean value into a 1 (true) or 0 (false).
      Using the preflop limp example from above:

      if[ holdem_hand_player_statistics.flg_p_limp, 1, 0 ]

      If the player limped preflop this returns a value of 1, else it returns 0.

      So now let's move on to the SUM function to see how we can count the number of hands where the player limped preflop.

    • Use of SUM

      The SUM function is used to add up a set of values.

      It is therefore only useful is sections where we are dealing with more than one item, such as Holdem Cash Player Statistics which generates statistics based on all of a player's hands.

      Before we get back to counting the number of hands where a player limped preflop, here is a simple expression of the use of SUM.
      To calculate the total amount of money a player bet across all hands, we could use an expression in the Holdem Cash Player Statistics section:

      sum( holdem_hand_player_detail.amt_bet_ttl )

      This goes through every hand the player played and adds up the total amount bet in that hand.
      Compare that with the expression we saw in the Simple Expressions section above which just retrieved the amount bet in a single hand, and which would be used in the Holdem Cash Hand section.

    • Combining SUM and IF

      So now we know how to use SUM and IF we can combine them to write a column expression to count the number of times a player limped preflop.
      Again, this would be in the Holdem Cash Player Statistics section:

      sum( if[holdem_hand_player_statistics.flg_p_limp, 1, 0] )

      For each hand the IF statement returns a 1 if the player limped and a 0 if they did not.
      The SUM statement then adds up these 1s and 0s to give us a count.

    • Nested IFs

      You can combine IF statements if you have more than 2 outcomes to generate.
      As a simple example let's say we want a column to determine whether the player bet more or less than the pot size on the flop or didn't bet at all, which gives us 3 outcomes. You would normally do this sort of thing in the Format Expression of the Statistic, rather than in the Column itself, but it should illustrate the point..

      if[ holdem_hand_player_detail.val_f_bet_made_pct = 0, 'Did not bet', if[ holdem_hand_player_detail.val_f_bet_made_pct > 100, 'Bet more than the pot', 'Bet less than the pot' ] ]

    • Mathematical operators

      You can use the normal mathematical operators in expressions:

      + - / * = < > >= <=
      != (not equal: <> also works)

      For example if we want to check whether the player bet more than the size of the pot (as in the Nested IFs example) we could use:

      holdem_hand_player_detail.val_f_bet_made_pct > 100

      There are also several other operators which are useful from time to time. Here are a few which may be useful, please see the documentation linked below for a complete list:

      % - modulo (remainder) 5 % 4 = 1
      ^ - exponentiation (power) 2 ^ 3 = 8
      abs - absolute value. abs(-5) = 5
      round - round to the nearest integer (whole number) round(42.7) = 43; or you can specify the number of decimal places: round( 66.66666, 2 ) = 66.67
      trunc - truncate towards zero. trunc(42.7) = 42; or you can specify the number of decimal places: trunc( 66.666666, 1 ) = 66.6

      For a full list please see the PostgreSQL Documentation.

    • Boolean operators

      You can use the normal boolean operators in expressions:

      AND OR NOT

      For instance, to see if a player made a continuation bet on the flop and turn we could use the expression:

      holdem_hand_player_statistics.flg_f_cbet AND holdem_hand_player_statistics.flg_t_cbet

      To see if they c-bet the flop but not the turn we could use:

      holdem_hand_player_statistics.flg_f_cbet AND NOT holdem_hand_player_statistics.flg_t_cbet

      To see if a player made a normal bet on the flop or the turn we could use:

      holdem_hand_player_statistics.flg_f_bet OR holdem_hand_player_statistics.flg_t_bet

      PostgreSQL documentation.

    • Operator precedence

      Normal operator precedence applies in expressions in PT3.
      Some operators have higher precedence than others so will always be calculated first, regardless of the order they are written in.
      For example:

      2 + 3 * 4 = 14

      This is because multiplication has higher precedence than addition. If you want to multiply 2 + 3 by 4, you need to write (2 + 3) * 4.
      Brackets over-ride precendence, and you should use them to clarify exactly what you are trying to do.


      • 2 + 3 * 4 = 14
        (2 + 3) * 4 = 20
      • 5 + 4 / 2 + 1 = 5 + (4 / 2) + 1 = 7
        (5 + 4) / (2 + 1) = 3

      See Table 4-1. Operator Precedence at the bottom of this page for a full list of the order operators are applied in, but when in doubt please use brackets.

      For example, if you want to see if a player bet the flop and then bet the turn or river, you could use:

      holdem_hand_player_statistics.flg_f_bet AND (holdem_hand_player_statistics.flg_t_bet OR holdem_hand_player_statistics.flg_r_bet)

      "holdem_hand_player_statistics.flg_f_bet AND holdem_hand_player_statistics.flg_t_bet OR holdem_hand_player_statistics.flg_r_bet" would not give us what we want.

      If you want to see whether a player bet and then folded on the flop, or bet and then folded on the turn, you could use:

        (holdem_hand_player_statistics.flg_f_bet AND holdem_hand_player_statistics.flg_f_fold) OR (holdem_hand_player_statistics.flg_t_bet AND holdem_hand_player_statistics.flg_t_fold)

      Again, the brackets are needed to make sure we get the result we want.

    • String expressions and functions

      The PT3 database contains some string (text) fields, and these can be read and analysed in Column Expressions.
      Some typical string fields are:

      • Player names - player.player_name
      • Limit names - holdem_limit.limit_name
      • Player actions by street - lookup_actions_p.action (see below)
      • Player action in specific situations - holdem_hand_player_statistics.enum_f_cbet_action (the action a player took when facing a flop continuation bet)
      • Street on which something occurred - holdem_hand_player_statistics.enum_allin (the street on which a player went all-in)

      Player actions are the most commonly used of these, so I'll describe them in more detail, and use them for the examples here.
      Every action is represented by a single uppercase letter.
      X = Check, F = Fold, C = Call, B = Bet, R = Raise

      The enum_ fields consist of a single character; either one of the above action characters or a character to represent a street, depending on the type of field.
      P = Preflop, F = Flop, T = Turn, R = River, N = None (e.g. if the player did not go all in then holdem_hand_player_statistics.enum_allin = 'N')

      The player actions by street strings (like lookup_actions_p.action) consist of a series of characters to represent all of a player's actions on a single street.
      For example, if a player limps then folds to a raise preflop the action string would be 'CF'.
      If they check-raised the flop then called a 3-bet their action string would be 'XRC'.

    • Exact string comparisons

      We can compare whole strings using the normal = operator.
      For example, if we want to see if a player's only action preflop was to call we could use:

      lookup_actions_p.action = 'C'

      Tip! Strings are always written inside single quote marks like this.

      If instead of just calling once, the player called and then faced a raise and called again then their action string would be 'CC' and lookup_actions_p.action = 'C' would be false.

      To check just certain parts of a string we need to use Pattern Matching functions.

    • Pattern matching - LIKE

      To compare just part of a string the normal = operator does not work, as mentioned above.
      If we want to check whether the player's first action preflop was to call, but we don't care what they did after that, then we could use the LIKE function:

      lookup_actions_p.action LIKE 'C%'

      This expression compares the player's preflop action string (lookup_actions_p.action) with the actions we're interested in - in this case a call ('C') followed by any other actions, including no action ('%').

      The % is a token which makes up part of a pattern. % specifically represents any (zero or more) characters, which can be anything.
      If we want to check for the player calling and then making exactly one more action (but we don't care what that second action is) then we would use the _ (underscore) token which represents exactly one character, which can be anything.

      lookup_actions_p.action LIKE 'C_'

      We can also combine tokens:

      lookup_actions_p.action LIKE 'C_%'

      ..would match any action string which starts with a call and has at least one more action (e.g. 'CF', 'CC', 'CCF', 'CRC', etc.), but would NOT match just a call ('C').

      You can use these tokens at any point in the string, so you could check for a player being the preflop aggressor by checking for their preflop action string ending with a raise:

      lookup_actions_p.action LIKE '%R'

      As another example, you could check whether the hand was played at a 6-max table like this:

      holdem_limit.limit_name LIKE '%(6 max)'

      LIKE is pretty good for this sort of thing, and can be used for virtually all cases, but there are some comparisons which can be simplified by using another pattern matching function; SIMILAR TO.
      This gets a bit more complicated now, so if you find LIKE confusing enough, you might want to skip the next section for now..

    • Pattern matching - SIMILAR TO

      If we want to check for a player's action when facing a flop bet being a call, but we don't care whether they checked before that or not (i.e. whether the call is made in or out of position) or what actions, if any, they made after calling we could do this with LIKE, but we would need two checks, like this: lookup_actions_f.action LIKE 'C%' OR lookup_actions_f.action LIKE 'XC%'

      Alternatively we could use a single SIMILAR TO expression:

      lookup_actions_f.action SIMILAR TO '(X|XC)%'

      The brackets define a separate part of the pattern, and the | means 'OR', so this expression matches any string which starts with 'X' OR 'XC' and then has zero or more characters after that.

      Please see the PostgreSQL documentation on Pattern Matching for more information.

    • Using SUBSTRING

      Another way of working with strings is the SUBSTRING function.
      This allows you to access any part of a string - its format is this:

      SUBSTRING( string FROM x FOR y )

      This returns y characters, starting from character number x.

      SUBSTRING( 'abcdefg' from 2 for 3 ) = 'bcd'

      This can be used to compare strings, for instance to see if the first two preflop actions were both calls you could use:

      SUBSTRING( lookup_actions_p.action from 1 for 2 ) = 'CC'

      This checks whether 1 character, starting from the first character, is 'C'; in the same way that you could use lookup_actions_p.action LIKE 'C%'.

      In general LIKE is easier to use than SUBSTRING for comparisons, but SUBSTRING can also be used to return part of a string.
      For instance, if you want to retrieve the first character of a limit name to display the currency you could use:

      SUBSTRING( holdem_limit.limit_name from 1 for 1 )

  • Statistic Creation Walkthrough

    For a walkthrough of how to create a custom statistic see this tutorial.

  • How to convert a Statistic to another Section

    If you have a statistic for one game type that you'd like to use for another game type you can convert it using the Convert To option on the Statistics tab.

    For instance, if you want to use the "Preflop Limp Fold" Holdem Cash Player Statistics stat from the previous post for holdem tournaments you could convert it to the Holdem Tournament Player Statistics section, like this:


    Select the section you want to convert to from the dropdown list and then click the Convert To button.

    You can convert a stat to the relevant section of any of the other 3 game types, but not to a different type of section.
    For instance, you can convert a stat from Holdem Cash Hands to Holdem Tournament Hands, Omaha Cash Hands or Omaha Tournament Hands, but not to Omaha Cash Player Statistics or Holdem Cash Sessions.

  • Building a pair of stats for Player and Hand

    Most stats that we build are in the Holdem Cash Player Statistics (HCPS) section as these are the stats that can be used in the HUD and in reports about players' overall stats.

    All of the following applies to the appropriate Omaha and Tournament sections too, but I will just describe the holdem cash case for simplicity.

    When you build one of these stats you will want to check that it is giving you the correct results and I find the best way to do this is to create a matching stat in the Holdem Cash Hands (HCH) section.
    This pair of stats will be based on the same expression, but the way they are constructed is slightly different.

    HCPS stats are often based on the number of times a certain action or event occurred, out of the number of times it could have happened, across all of the player's hands. This is normally displayed as a percentage. (You can build other types of stats here too, but these are most common.)
    The construction of these 'percentage' stats is described in detail earlier in this tutorial.

    HCH stats are based on individual hands and indicate whether the action or event occurred in each specific hand. This is normally displayed as a checkbox to indicate true or false.

    As an example I'm going to build a HCH stat to go with the built in HCPS "Steal Success" stat.

    The HCPS stat shows the percentage of times the player's steal raises "succeeded", by which I mean the raise won with no further action.
    So if the player made 10 steal raises and won immediately 3 times the stat will show "30".

    You can add this statistic to the built-in reports on the Positions tab, for instance - either or both the Position Statistics and Position Hands reports.
    This will show how often the steal raises succeeded, but to see which 10 specific hands were the steal raises, and which 3 succeeded we need to create a stat we can show in the Position Hands Detail report.

    The HCH stat will show a checkbox if the player made a steal raise; the checkbox will be checked if the steal succeeded and unchecked if it didn't.

    The HCPS "Steal Success" stat is constructed like this:
    ( cnt_steal_success / cnt_steal_att ) * 100

    The column expressions are:

    cnt_steal_success =

    sum(if[holdem_hand_player_statistics.flg_steal_att AND NOT(holdem_hand_player_statistics.flg_f_saw) AND NOT(holdem_hand_player_statistics.flg_p_face_raise), 1, 0])

    cnt_steal_att =

    sum(if[holdem_hand_player_statistics.flg_steal_att, 1, 0])

    To build the HCH stat we need to recreate these columns in the Holdem Cash Hands section, but with one crucial difference.
    The HCPS stats uses the sum(if[...]) construct to count how often the steal raise occurred and how often it succeeded across all the player's hands.
    The HCH section works on individual hands so we don't need the sum(if[...]) part, but the rest is the same, so we create new columns:

    flg_steal_success =

    holdem_hand_player_statistics.flg_steal_att AND NOT(holdem_hand_player_statistics.flg_f_saw) AND NOT(holdem_hand_player_statistics.flg_p_face_raise)

    flg_steal_att =


    Note that I change the names slightly too - they are now boolean (true/false) values so by convention we name them flg_ which indicates a 'flag'.

    Now to construct the actual HCH statistic we go to the Statistics tab and click New.
    Enter your stat name "Steal Success".
    The Value Expression can be flg_steal_success - i.e. did the steal succeed or not.

    The Format tab is where the real work is done. To make it really clear which hands are the ones where a steal was attempted we're only going to show the checkbox at all if a steal was attempted (i.e. when flg_steal_att is true).

    So the Format Expression is:

    if ( flg_steal_att, format_bool( flg_steal_success, 'check' ), '' )

    This says if flg_steal_att is true then show a checkbox based on the true/false value flg_steal_success otherwise show nothing (''=empty string). See earlier in this tutorial for more information.
    Make sure you fill in the Title and Width fields as well, or the stat won't show in your reports.

    The Positions tab then looks like this when I add the stats to all 3 reports:


    Here you can easily see which hands were steal attempts and which succeeded.
    I have included the similar "Steal Attempted" stats for clarity - you will notice that there is one hand where a steal could have been attempted but wasn't, and this isn't included in the steal success stat.

    I have also added "x/y" versions of the HCPS "Steal Success" and "Steal Attempted" stats to the top two reports so that you can easily see how many attempts and successes there were.
    These are built by duplicating the built in stats and just changing the Format Expression. For example the Format Expression for "Steal Success (x/y)" is:

    format( '{1}% ({2}/{3})', format_number(100* cnt_steal_success / cnt_steal_att, 0, false, false), format_number(cnt_steal_success,0,false,false), format_number(cnt_steal_att,0,false,false) )
  • Using live HUD Stats

    For information about "live" HUD stats click here.