SnG Luck Analyzer (Beta)
01-27-2008
, 07:13 PM
Join Date: Jun 2005
Posts: 15
Any chance we can get this to work with tourney manager please.... I dont use poker tracker and from the looks of things it doesn't work properly with pokerstars anyway. I had a quick look at importing my hand historys to poker tracker but I don't have the summarys so I can't fix the buyin problem.
01-27-2008
, 08:55 PM
centurion
Join Date: Jan 2008
Posts: 132
In Poker Tracker under File | T results you can auto-request tourney summaries.
01-28-2008
, 08:45 AM
Thanks Juk, looks nice. I exported these from pokertracker, no errors except 92 tourneys that I had only imported the summary for, those tourneys didn't work at all. 11s and 22s are March-July 07, 33s and 55s July-December 07. Seems kinda strange to have that big of a difference or maybe it's something different with the way the games play? FWIW, I actually ran hot in the 33s. Google docs didn't wanna import the file with all tourneys together and oo freezes when I try to resize the graph. Total for the 3,768 tourneys (11,578 data points) is +579.063% and -t21,841 (the csv file says it's -2.18414e+006 ?).
450 11s

1357 33s

1040 33s

921 55s
450 11s

1357 33s

1040 33s

921 55s

01-28-2008
, 11:29 AM
Join Date: Aug 2007
Posts: 2,000
I am too lazy to read the whole thread, but I get this error: "invalid Pokertracker database". I get that by all the databases I try to select.
01-28-2008
, 02:07 PM
Carpal \'Tunnel
Join Date: Sep 2004
Posts: 11,749
Quote:
11s and 22s are March-July 07, 33s and 55s July-December 07. Seems kinda strange to have that big of a difference or maybe it's something different with the way the games play?
It's surprising though how much variance you can get from even a fairly large sub-sample: 50% of 1.3M data-points came out at anything from +10000% to -10000% after a few different runs.
Perhaps one other idea would be to plot the $EV luck graph with a scaled version of your actual winnings. When I compared my PT graph with the $EV luck graph for last year, then the places where I had very big downswings and long break-even stretches matched up quite well with the $EV luck graph (another reason to believe that it is working correctly).
Quote:
FWIW, I actually ran hot in the 33s.
Quote:
Google docs didn't wanna import the file with all tourneys together and oo freezes when I try to resize the graph.
Quote:
Total for the 3,768 tourneys (11,578 data points) is +579.063% and -t21,841 (the csv file says it's -2.18414e+006 ?).
Juk
PS: ImageShack is being a real pain again and your 11s graph is not showing up for me for some reason?
01-28-2008
, 04:13 PM
Quote:
Perhaps one other idea would be to plot the $EV luck graph with a scaled version of your actual winnings. When I compared my PT graph with the $EV luck graph for last year, then the places where I had very big downswings and long break-even stretches matched up quite well with the $EV luck graph (another reason to believe that it is working correctly).

Quote:
PS: ImageShack is being a real pain again and your 11s graph is not showing up for me for some reason?


And sngla graph for 55s

01-28-2008
, 04:41 PM
Carpal \'Tunnel
Join Date: Sep 2004
Posts: 11,749
Quote:
Ya my graphs for 11s, 22s and 55s match up with the EV graphs. 33s are weird, I actually won during the drop at the end while at 55s I had a 30+ bi drop
So ya showdown luck isn't everything

Will post the updated version sometime later today.
Juk
01-28-2008
, 10:12 PM
Carpal \'Tunnel
Join Date: Sep 2004
Posts: 11,749
New version: http://www.jukofyork.com/Juks_BackTestAllInLuck.rar
Instructions
1) Download it and unrar it to a folder somewhere.
2) Copy some of your 10-man Party HH files into the same folder.
3) Run the batch file called "RunMe.bat" and leave it to do it's work
4) After it's finished it will tell you your total $EV (and cEV) luck differences along with actual/adjusted winnings and ROI.
5) It will also create a file called "luck_results.csv" which you can load into Excel to plot your cumulative winnings and luck.
NOTE: It doesn't work with anything other than Party 10-man SNGs.
New for this version
a) We now work out and print at the end both actual and adjusted winnings (+ actual and adjusted ROI).
b) Any SNGs where we didn't see the hero bust or the SNG end are ignored (for ROI and adjusted calculations).
c) We now save cumulative: real winnings, adjusted winnings, $EV luck and cEV luck to the ".csv" file.
d) Fixed a bug where cEV was being scaled by 100 in the ".csv" file.
e) All hands are now sorted based on tournament number (hand number is used as secondary key) for the ".csv" output file.
NOTE: Your ROI might not quite be the same as PT if you have had any crashes where the end of the final hand(s) gets cut off, etc.
NOTE: Your graph might not look the same as the previous version, as I don't think ordering based on filename was working as expected... Your final $EV luck value should be almost the same (depending on how many SNGs get skipped dues to missing Hero's final hand), as it's not dependant on ordering.
Here is an example of plotting real winnings, adjusted winnings and $EV luck:

It looks like $EV luck is definitely capturing some of the variance as the adjusted line is much smoother. It's even smoothed out those 3 big humps at the start of my graph. These correspond to last last Feb/March where I had 3 big downswings/break-even patches... Man I wish I had this back then!
NOTE: If you are new to SNGs and have improved your game over time (I played alot at Pacific before Party) or have systematically moved up levels (I've had about the same ROI for 11s, 22s and 33s and move up/down quite alot depending on the time of day and/or if I have a new Party/Empire nick to exploit), then don't expect your adjusted line to look like mine! It should still look "smoother" though...
Juk
Instructions
1) Download it and unrar it to a folder somewhere.
2) Copy some of your 10-man Party HH files into the same folder.
3) Run the batch file called "RunMe.bat" and leave it to do it's work
4) After it's finished it will tell you your total $EV (and cEV) luck differences along with actual/adjusted winnings and ROI.
5) It will also create a file called "luck_results.csv" which you can load into Excel to plot your cumulative winnings and luck.
NOTE: It doesn't work with anything other than Party 10-man SNGs.
Code:
// *************************************************************************** // * INCLUDES * // *************************************************************************** #include <vector> #include <map> #include <string> #include <algorithm> #include "../core/misc.h" #include "../core/random_number_generator.h" #include "../holdem_game_state.h" #include "../holdem_game_state_with_history.h" #include "../holdem_hole_card_ranking.h" #include "../sng_icm_calculator.h" #include "../holdem_parser.h" #include "../party_nl_holdem_sng_parser.h" // *************************************************************************** // * CONSTANTS * // *************************************************************************** // This the the fee we pay to enter in terms of prize pool. #define ENTRY_FEE_PERCENTAGE 11.0 // 11% for Party 10-man. // *************************************************************************** // * STRUCTURES * // *************************************************************************** // Used to hold a single data-point (for sort based on hand # at end). typedef struct DataPoint { char TournamentNumber[MAX_HAND_NUMBER_CHARS+1]; // Used to index into our own prize. char HandNumber[MAX_HAND_NUMBER_CHARS+1]; // Used as sort key. double PrizeEquityDifference; // $EV_actual-$EV_expected (in %) double ChipEquityDifference; // cEV_actual-cEV_expected (in t) } DataPoint; // Order based using Tournament number as primary key and Hand number as secondary. // NOTE: This won't be quite right if we multi-table, but can't just use hand #... bool operator<(const DataPoint& D1,const DataPoint& D2) { if (strcmp(D1.TournamentNumber,D2.TournamentNumber)==0) return (strcmp(D1.HandNumber,D2.HandNumber)<0?true:false); else return (strcmp(D1.TournamentNumber,D2.TournamentNumber)<0?true:false); } // =========================================================================== void BackTestAllInLuck(const char** Folders,const int NumFolders) { // The parser we are going to use. PartyNLHoldemSNGParser Parser; // The vector of hands we get from the parser. vector<HoldemGameStateWithHistory> Hands; // The vector of data-points (so we can sort at the end). vector<DataPoint> DataPoints; // This holds the result of each tournament. typedef pair<string,double> TournamentResultPair; map<string,double> TournamentResultMap; // This is what we use to get the EV at the end of the hand. SNG_ICM_Calculator ICM; // The number of 2-way, 3-way and multi-way data-points seperately. int Num2WayAllIns=0; int Num3WayAllIns=0; int NumMultiWayAllIns=0; // We don't deal with these atm. // These are the possible finish rankings for each outcome. const int TwoWayFinishRanking[3][2] = {{1,1}, {1,2}, {2,1}}; const int ThreeWayFinishRanking[13][3] = {{1,1,1},{1,1,2},{1,2,1}, {1,2,2},{1,2,3},{1,3,2}, {2,1,2},{2,2,1},{2,1,3}, {2,3,1},{2,1,1},{3,1,2}, {3,2,1}}; // These hold the outcomes for each 2-way and 3-way hand matchup. // NOTE: Use floats to reduce memory consumption. static float TwoWayOutcomeChances[3][169][169]; static float ThreeWayOutcomeChances[13][169][169][169]; // ************************************************************************* // ************** LOAD THE LOOKUP AND/OR CREATE BINARY VERSIONS ************ // ************************************************************************* // Have to use two different once because C++ messes up on 2nd use... ifstream InFile1,InFile2; // This flag gets unset if we failed to loaded either of the (fast) binary versions ok. bool LoadedBinary=true; // Lets first try and open the binary versions. InFile1.open("2WAY_HandEval_binary.dat",ios::binary); InFile2.open("3WAY_HandEval_binary.dat",ios::binary); // If all ok, then read these instead. if (!InFile1.fail() && !InFile2.fail()) { InFile1.read((char*)&TwoWayOutcomeChances,sizeof(TwoWayOutcomeChances)); InFile2.read((char*)&ThreeWayOutcomeChances,sizeof(ThreeWayOutcomeChances)); } else { LoadedBinary=false; } // Close the input files. InFile1.close(); InFile2.close(); // if we couldn't open the binary versions, lets load from the test and then save the binary again. if (LoadedBinary==false) { // Have to use two different once because C++ messes up on 2nd use... ifstream InFileT1,InFileT2; // Have to use two different once because C++ messes up on 2nd use... ofstream OutFile1,OutFile2; // Use for reading in the outcome look files. int H1,H2,H3; double Outcome; // Tell the user what's going on. cout << "Failed to load binary equity lookup tables. Re-creating them now... "; cout.flush(); // Open and read each line of the test data files. // NOTE: Inversed as HoldemHoleCardRanking::GetIndex() uses AA in top left, A2s top right, etc. InFileT1.open("2WAY_HandEval.dat"); InFileT2.open("3WAY_HandEval.dat"); // If all ok, then read these in. if (InFileT1.fail() || InFileT2.fail()) Error(FATAL,"Could not load the (text) equity lookups."); while (InFileT1 >> H1 >> H2) { for (int I=0;I<3;I++) InFileT1 >> TwoWayOutcomeChances[I][168-H1][168-H2]; } while (InFileT2 >> H1 >> H2 >> H3) { for (int I=0;I<13;I++) InFileT2 >> ThreeWayOutcomeChances[I][168-H1][168-H2][168-H3]; } // Close the input files. InFileT1.close(); InFileT2.close(); // Lets save the binary versions for use next time. OutFile1.open("2WAY_HandEval_binary.dat",ios::binary); OutFile2.open("3WAY_HandEval_binary.dat",ios::binary); // If all OK, save them out. if (OutFile1.fail() || OutFile2.fail()) Error(FATAL,"Could not save the (binary) equity lookups."); OutFile1.write((char*)&TwoWayOutcomeChances,sizeof(TwoWayOutcomeChances)); OutFile2.write((char*)&ThreeWayOutcomeChances,sizeof(ThreeWayOutcomeChances)); // Close the output files. OutFile1.close(); OutFile2.close(); // All done creating them now. cout << "Done." << endl; } // ************************************************************************* // ************************************************************************* // Lets do it on each folder. for (int Folder=0;Folder<NumFolders;Folder++) { // Lets try and get the first vector of hands. Parser.InitHandHistorySearcher(Folders[Folder]); while (Parser.SearchForAndParseNextHandHistoryFile(Hands,true)==true) { // Lets keep going until we get no more. for (int I=0;I<Hands.size();I++) { // The stacks for each player at the start and end of hand. int StackAtStartOfHand[10]; int StackAtEndOfHand[10]; // The number of players left at the end of the hand (used to test for game over). int NumPlayersLeftAtEndOfHand; // If we're not here or not all-in, then skip it (data-mined or after we busted). if (Hands[I].GetOurSeatIndex()==NO_SEAT || Hands[I].IsInHandCurrently(Hands[I].GetOurSeatIndex())==false) { continue; } // Lets work out the stacks at the start/end of the hand. NumPlayersLeftAtEndOfHand=0; for (int K=0;K<10;K++) { StackAtStartOfHand[K]=0; StackAtEndOfHand[K]=0; } for (int K=0;K<10;K++) { if (Hands[I].WasInHandAtStartOfHand(K)==true) { StackAtStartOfHand[K]=Hands[I].GetStackAtStartOFHand(K); StackAtEndOfHand[K]=Hands[I].GetCurrentStack(K)+Hands[I].GetUnCalledBets(K)+Hands[I].GetAmountWon(K); if (StackAtEndOfHand[K]>0) NumPlayersLeftAtEndOfHand++; } } // Check we have not lost any chips. // #### NOTE: This happens for truncated HH files where their is no "wins" line... int TotalChipsStart=0; int TotalChipsEnd=0; for (int K=0;K<10;K++) { TotalChipsStart+=StackAtStartOfHand[K]; TotalChipsEnd+=StackAtEndOfHand[K]; } if (TotalChipsStart!=TotalChipsEnd) { Error(WARNING,Hands[I].GetHandNumber(),"Chips at end of hand != start of hand. Ignoreing hand..."); continue; } // If we just busted out or the game is over, we need to calculate and store the tournament result for us. // @@@ We re-caluclate this below, but prolly won't slow down too much... if (ICM.TestBustout(StackAtStartOfHand,StackAtEndOfHand,Hands[I].GetOurSeatIndex())==true) { TournamentResultMap.insert(TournamentResultPair(Hands[I].GetTournamentNumber(), ICM.CalculateBustoutPrizeEV(StackAtStartOfHand,StackAtEndOfHand,Hands[I].GetOurSeatIndex()) *100.0)); } else if (NumPlayersLeftAtEndOfHand==1) { TournamentResultMap.insert(TournamentResultPair(Hands[I].GetTournamentNumber(), ICM.CalculatePrizeEV(StackAtEndOfHand,Hands[I].GetOurSeatIndex())*100.0)); } // If we have gone from pre-flop to river, then this is an all-in hand. if (Hands[I].GetNumStates()>=2 && Hands[I].GetCurrentGameStage()==RIVER && Hands[I][Hands[I].GetNumStates()-2].GetCurrentGameStage()==PRE_FLOP && Hands[I].GetTotalInHandCurrently()>=2) { // This is the number of all-in players we are dealing with here. int NumAllInPlayers=Hands[I].GetTotalInHandCurrently(); // This is the index of each of the players who are left. int PlayerIndex[10]; // ### Only use the first 3, but need 10 incase we start to sim for 4+ players... int NumValidShowdownHands=0; // The (temp) "finishing rank" assigned depending on outcome. int PlayersFinishingRank[10]; // The chance of each outcome (retrived from the lookup table). double ChanceOfOutcome; // This holds the rank indexes (0..168) for the player's hand. int PlayerHandType[10]; // These are used to temporailty sim the outcomes. int CurrentStacks[10]; int CurrentStakes[10]; bool InHandCurrently[10]; // The actaul EV from the start to end of hand. double ActualPrizeEquity,ActualChipEquity; // Expected average EV based on the hand matchup. double ExpectedPrizeEquity; double ExpectedChipEquity; // @@@@@@@@@@@@@@ Don't really need this @@@@@@@@@@@@@@@@@@@@@ // Lets make sure that 1 or both players are all-in. int NumNonAllInPlayers=0; for (int J=0;J<10;J++) { if (Hands[I].IsInHandCurrently(J)==true && Hands[I].GetCurrentStack(J)!=0) NumNonAllInPlayers++; } if (NumNonAllInPlayers>1) { Error(WARNING,"Non all-in hand (should not get here...)."); continue; } // @@@@@@@@@@@@@@ Don't really need this @@@@@@@@@@@@@@@@@@@@@ // If the player is in the hand currently and his cards are known, then lets count him and get his seat index. for (int J=0;J<10;J++) { if (Hands[I].IsInHandCurrently(J)==true && Hands[I].GetShowdownHoleCard(J,0).Rank!=RANK_NONE) { PlayerIndex[NumValidShowdownHands]=J; PlayerHandType[J]=HoldemHoleCardRanking::GetIndex((Hands[I].GetShowdownHoleCard(J,0).Suit*13)+Hands[I].GetShowdownHoleCard(J,0).Rank, (Hands[I].GetShowdownHoleCard(J,1).Suit*13)+Hands[I].GetShowdownHoleCard(J,1).Rank); NumValidShowdownHands++; // One more. } } // If we don't have cards for all the players at the end then skip this hand. if (NumValidShowdownHands!=NumAllInPlayers) continue; // At the moment we can only deal with 2-way and 3-way all-in, but we will count the rest. if (NumAllInPlayers>3) { NumMultiWayAllIns++; continue; } else if (NumAllInPlayers==3) { Num3WayAllIns++; } else { Num2WayAllIns++; } // We must make sure that player's indexes are ordered based on their cards (for lookup into the outcome tables). // NOTE: Bubble-sort is fine for this... for (int J=0;J<(NumAllInPlayers-1);J++) { for (int K=J+1;K<NumAllInPlayers;K++) { if (PlayerHandType[PlayerIndex[J]]>PlayerHandType[PlayerIndex[K]]) { int Temp=PlayerIndex[J]; PlayerIndex[J]=PlayerIndex[K]; PlayerIndex[K]=Temp; } } } // Now lets do the calculation for each of the players. for (int Player=0;Player<NumAllInPlayers;Player++) { // Looks at the hands from our perspective only. if (Hands[I].GetOurSeatIndex()!=PlayerIndex[Player]) continue; // Lets print the hand number first. @@@ DEBUG ONLY @@@ //cerr << Hands[I].GetHandNumber() << ", "; // If we didn't just bust out we need to calculate the real EV using ICM. // NOTE: Also store here the reult of the SNG (if we busted or won). if (ICM.TestBustout(StackAtStartOfHand,StackAtEndOfHand,PlayerIndex[Player])==true) ActualPrizeEquity=ICM.CalculateBustoutPrizeEV(StackAtStartOfHand,StackAtEndOfHand,PlayerIndex[Player]); else ActualPrizeEquity=ICM.CalculatePrizeEV(StackAtEndOfHand,PlayerIndex[Player]); // Get the cEV too. ActualChipEquity=StackAtEndOfHand[PlayerIndex[Player]]; // Init ready to sum for each outcome. ExpectedPrizeEquity=0.0; ExpectedChipEquity=0.0; // Lets go through the three possible outcomes. for (int OutCome=0;OutCome<(NumAllInPlayers==2?3:13);OutCome++) { // We can share the pot much faster if only 2 players. if (NumAllInPlayers==2) { // Lets assign a finishing rank to each player based on the current outcome index. for (int J=0;J<2;J++) PlayersFinishingRank[PlayerIndex[J]]=TwoWayFinishRanking[OutCome][J]; // Get the chance of outcome from the lookup table. ChanceOfOutcome=TwoWayOutcomeChances[OutCome][PlayerHandType[PlayerIndex[0]]][PlayerHandType[PlayerIndex[1]]]; // Lets make a copy of the current stacks and amounts staked. // NOTE: For the 2-way code we need to take off the amount staked AFTER we have equalized the stakes below. for (int J=0;J<10;J++) { CurrentStacks[J]=Hands[I].GetStackAtStartOFHand(J); CurrentStakes[J]=Hands[I].GetStackAtStartOFHand(J)-Hands[I].GetCurrentStack(J); } // Get the chance of outcome from the lookup table. ChanceOfOutcome=TwoWayOutcomeChances[OutCome][PlayerHandType[PlayerIndex[0]]][PlayerHandType[PlayerIndex[1]]]; // Lets return any uncalled bets so they have both staked the same. CurrentStakes[PlayerIndex[0]]=Min(CurrentStakes[PlayerIndex[0]],CurrentStakes[PlayerIndex[1]]); CurrentStakes[PlayerIndex[1]]=CurrentStakes[PlayerIndex[0]]; // Now work out the size of the pot available to each left in the hand. int CurrentPot=0; for (int J=0;J<10;J++) { CurrentPot+=CurrentStakes[J]; CurrentStacks[J]-=CurrentStakes[J]; // Take off now. } // Lets work out the chance dependig on the outcome type. // NOTE: We assign any odd chips to an aribtary player. if (PlayersFinishingRank[PlayerIndex[0]]<PlayersFinishingRank[PlayerIndex[1]]) { CurrentStacks[PlayerIndex[0]]+=CurrentPot; } else if (PlayersFinishingRank[PlayerIndex[1]]<PlayersFinishingRank[PlayerIndex[0]]) { CurrentStacks[PlayerIndex[1]]+=CurrentPot; } else { CurrentStacks[PlayerIndex[0]]+=(CurrentPot/2)+(CurrentPot%2); CurrentStacks[PlayerIndex[1]]+=(CurrentPot/2); } } // End 2-way pot shareout. // Will have to do the slower way for 3 players them. else { // Lets assign a finishing rank to each player based on the current outcome index. for (int J=0;J<3;J++) PlayersFinishingRank[PlayerIndex[J]]=ThreeWayFinishRanking[OutCome][J]; // Get the chance of outcome from the lookup table. ChanceOfOutcome=ThreeWayOutcomeChances[OutCome][PlayerHandType[PlayerIndex[0]]][PlayerHandType[PlayerIndex[1]]][PlayerHandType[PlayerIndex[2]]]; // Lets make a copy of the current stacks, amounts staked and Inhand flags. // NOTE: For the 3-way code we need to take off the amount staked BEFORE. for (int J=0;J<10;J++) { CurrentStacks[J]=Hands[I].GetCurrentStack(J); CurrentStakes[J]=Hands[I].GetStackAtStartOFHand(J)-Hands[I].GetCurrentStack(J); InHandCurrently[J]=Hands[I].IsInHandCurrently(J); } // Lets share out all the side-pots. for (;;) { // Lets set any player who has nothing staked anymore to not be in the hand. for (int J=0;J<10;J++) if (CurrentStakes[J]==0) InHandCurrently[J]=false; // Not in hand now. // Find he smallest amount staked. int MinAmountStaked=0x7fffffff; for (int J=0;J<10;J++) if (InHandCurrently[J]==true) MinAmountStaked=Min(MinAmountStaked,CurrentStakes[J]); // Create the side-pot and subtract from the staked amounts. int CurrentPot=0; for (int J=0;J<10;J++) { CurrentPot+=Min(CurrentStakes[J],MinAmountStaked); CurrentStakes[J]-=Min(CurrentStakes[J],MinAmountStaked); } // Test if we are done. // NOTE: The last side-pot will just be the biggest stack geting his excess chips returned. if (CurrentPot==0) break; // Share out the pot based on the hand rank of each player. int NumHandWinners=0; int BestHand=0x7fffffff; for (int J=0;J<10;J++) { if (InHandCurrently[J]==true) { if (PlayersFinishingRank[J]<BestHand) { NumHandWinners=1; BestHand=PlayersFinishingRank[J]; } else if (PlayersFinishingRank[J]==BestHand) { NumHandWinners++; } } } // Now lets take off the smount they put into the vurrent pot and give them any pot they might need. // NOTE: We assign any odd chips to an aribtary player. int OddChips=(CurrentPot%NumHandWinners); for (int J=0;J<10;J++) { if (InHandCurrently[J]==true && PlayersFinishingRank[J]==BestHand) { CurrentStacks[J]+=(CurrentPot/NumHandWinners)+OddChips; OddChips=0; // If there were any, they have been assigned now. } } } } // End 3-way pot shareout. double TempExpectedPrizeEquity,TempExpectedChipEquity,TempPLoseDiff; // Work out our $EV for this outcome. if (ICM.TestBustout(StackAtStartOfHand,CurrentStacks,PlayerIndex[Player])==true) TempExpectedPrizeEquity=ICM.CalculateBustoutPrizeEV(StackAtStartOfHand,CurrentStacks,PlayerIndex[Player]); else TempExpectedPrizeEquity=ICM.CalculatePrizeEV(CurrentStacks,PlayerIndex[Player]); // Work out the cEV for this outcome. TempExpectedChipEquity=CurrentStacks[PlayerIndex[Player]]; // Lets add to the sums. ExpectedPrizeEquity+=TempExpectedPrizeEquity*ChanceOfOutcome; ExpectedChipEquity+=TempExpectedChipEquity*ChanceOfOutcome; // Lets print the EVs and the outcomes. @@@ DEBUG ONLY @@@ // @@@ This file is gonna be a nightmare to read, as it will have different numbers of feilds for 2-way and 3-way lines... //cerr << ChanceOfOutcome << ',' << TempExpectedPrizeEquity << ',' << TempExpectedChipEquity << ", "; } // End for each outcome. // Lets create and save the reultant data-point. DataPoint TempDataPoint; strcpy(TempDataPoint.TournamentNumber,Hands[I].GetTournamentNumber()); strcpy(TempDataPoint.HandNumber,Hands[I].GetHandNumber()); TempDataPoint.PrizeEquityDifference=(ActualPrizeEquity-ExpectedPrizeEquity)*100.0; // As %. TempDataPoint.ChipEquityDifference=ActualChipEquity-ExpectedChipEquity; // As t. DataPoints.push_back(TempDataPoint); // Lets print the EV for this hand. @@@ DEBUG ONLY @@@ //cerr << ExpectedPrizeEquity << ',' << ActualPrizeEquity << ',' << ActualPrizeEquity-ExpectedPrizeEquity << ", " // << ExpectedChipEquity << ',' << ActualChipEquity << ',' << ActualChipEquity-ExpectedChipEquity << ", "; } // End for each player. } // End if valid all-in hand. } // End for each hand in hand history. } // End for each hand history in folder. } // For each folder. // ************************************************************************* // ************************************************************************* // The number of SNGs we have played. int NumValidSNGs=0; int NumSNGsSkipped=0; // Invalid. // The number of all-in we have been involved in. int NumValidDataPoints=0; int NumDataPointsSkipped=0; // Invalid. // The sum of prizes we have won (as %). double SumPrizes=0.0; // The sum of differences from our predicted EV. double SumPrizeEquityDifferences=0.0; double SumChipEquityDifferences=0.0; // The last tourney number. char LastTournamentNumber[MAX_HAND_NUMBER_CHARS+1]={'\0'}; // The ".csv" file for results to plot. ofstream Outfile; // Lets sort the DataPoints vector based on tournament (and hand) number. sort(DataPoints.begin(),DataPoints.end()); // Open the output file. Outfile.open("luck_results.csv"); if (Outfile.fail()) Error(FATAL,"Could not open 'luck_results.csv'"); // Print the csv headers. Outfile << "HandNumber,ActualWinnings,AjustedWinnings,$EV_Luck,cEV_Luck" << endl; // Save out each data-point we have. int I=0; for (map<string,double>::iterator T=TournamentResultMap.begin();T!=TournamentResultMap.end();T++) { // One more (valid) SNG. NumValidSNGs++; // Add to the sum of prizes (seems more sensible to do before each SNG for graphing purposes...). SumPrizes+=T->second; // If the data-point doesn't have a valid corresponding result, we must skip it. if (TournamentResultMap.find(DataPoints[I].TournamentNumber)==TournamentResultMap.end()) { Error(WARNING,DataPoints[I].TournamentNumber,"Hero's final hand missing... Ignoreing SNG."); NumSNGsSkipped++; } for (;I<DataPoints.size() && TournamentResultMap.find(DataPoints[I].TournamentNumber)==TournamentResultMap.end();I++) NumDataPointsSkipped++; // Output all the data-points that correspond to this tournament number. for (;I<DataPoints.size() && strcmp((T->first).c_str(),DataPoints[I].TournamentNumber)==0;I++) { // One more (valid) data-point. NumValidDataPoints++; // Add to the cumulative sum of differenes. SumPrizeEquityDifferences+=DataPoints[I].PrizeEquityDifference; SumChipEquityDifferences+=DataPoints[I].ChipEquityDifference; // Lets print each data-point. // NOTE: Remeber to take off the 11% fee. Outfile << DataPoints[I].HandNumber << ',' << SumPrizes-((double)NumValidSNGs*ENTRY_FEE_PERCENTAGE) << ',' << (SumPrizes-SumPrizeEquityDifferences)-((double)NumValidSNGs*ENTRY_FEE_PERCENTAGE) << ',' << SumPrizeEquityDifferences << ',' << SumChipEquityDifferences << endl; } } // Close the output file. Outfile.close(); // Print the difference between expected and real. cout << endl << "NumSNGs : " << NumValidSNGs << " (NumAllIns[2,3,4+]=" << Num2WayAllIns << ',' << Num3WayAllIns << ',' << NumMultiWayAllIns << " / NumDataPoints=" << NumValidDataPoints << ")" << endl << "Actual Won : " << (int)(SumPrizes-((double)NumValidSNGs*ENTRY_FEE_PERCENTAGE)) << "% (Actual ROI=" << ((SumPrizes-((double)NumValidSNGs*ENTRY_FEE_PERCENTAGE))/((double)NumValidSNGs*ENTRY_FEE_PERCENTAGE))*100.0 << "%)" << endl << "Adjusted Won : " << (int)((SumPrizes-SumPrizeEquityDifferences)-((double)NumValidSNGs*ENTRY_FEE_PERCENTAGE)) << "% (Adjusted ROI=" << (((SumPrizes-SumPrizeEquityDifferences)-((double)NumValidSNGs*ENTRY_FEE_PERCENTAGE)) /((double)NumValidSNGs*ENTRY_FEE_PERCENTAGE))*100.0 << "%)" << endl << "$EV Luck : " << (int)SumPrizeEquityDifferences << "% (" << SumPrizeEquityDifferences/(double)(NumValidDataPoints>0?NumValidDataPoints:1) << "% per all-in)" << endl << "cEV Luck : " << (int)SumChipEquityDifferences << "t (" << SumChipEquityDifferences/(double)(NumValidDataPoints>0?NumValidDataPoints:1) << "t per all-in)" << endl << endl; // Report how many we skipped. cout << "NOTE: " << NumSNGsSkipped << " SNGs (" << NumDataPointsSkipped << " data-points) with missing final hands were ignored." << endl; } // End BackTestAllInLuck.
a) We now work out and print at the end both actual and adjusted winnings (+ actual and adjusted ROI).
b) Any SNGs where we didn't see the hero bust or the SNG end are ignored (for ROI and adjusted calculations).
c) We now save cumulative: real winnings, adjusted winnings, $EV luck and cEV luck to the ".csv" file.
d) Fixed a bug where cEV was being scaled by 100 in the ".csv" file.
e) All hands are now sorted based on tournament number (hand number is used as secondary key) for the ".csv" output file.
NOTE: Your ROI might not quite be the same as PT if you have had any crashes where the end of the final hand(s) gets cut off, etc.
NOTE: Your graph might not look the same as the previous version, as I don't think ordering based on filename was working as expected... Your final $EV luck value should be almost the same (depending on how many SNGs get skipped dues to missing Hero's final hand), as it's not dependant on ordering.
Here is an example of plotting real winnings, adjusted winnings and $EV luck:

It looks like $EV luck is definitely capturing some of the variance as the adjusted line is much smoother. It's even smoothed out those 3 big humps at the start of my graph. These correspond to last last Feb/March where I had 3 big downswings/break-even patches... Man I wish I had this back then!
NOTE: If you are new to SNGs and have improved your game over time (I played alot at Pacific before Party) or have systematically moved up levels (I've had about the same ROI for 11s, 22s and 33s and move up/down quite alot depending on the time of day and/or if I have a new Party/Empire nick to exploit), then don't expect your adjusted line to look like mine! It should still look "smoother" though...
Juk
01-29-2008
, 05:04 AM
It would be sooooooooo good if I could use the analyser with PostRegDb or (stars) raw HH.
RLY.
RLY.
01-29-2008
, 09:11 AM
That graph is awesome, I can't believe how much variance it has cut out. Please make it work with stars hhs Juk.
01-29-2008
, 10:23 AM
Join Date: Jul 2006
Posts: 432
Nice graph! It would be awesome if it could be made to work with stars.
I tried using this for 3 party $11s, and in the ActualWin column it gives -11 for a loss, 8 for a 3rd and 17 for a 2nd. Is this normal? I thought it should be 100*.2-11=9 for 3rd and 100*.3-11=19 for 2nd?
I tried using this for 3 party $11s, and in the ActualWin column it gives -11 for a loss, 8 for a 3rd and 17 for a 2nd. Is this normal? I thought it should be 100*.2-11=9 for 3rd and 100*.3-11=19 for 2nd?
01-29-2008
, 12:36 PM
Thanks Juk, now it's even better 
For some reason it only took a second for Oo to resize this graph with 3 lines. It's about 3750 tourneys total.
For some reason it only took a second for Oo to resize this graph with 3 lines. It's about 3750 tourneys total.

01-29-2008
, 01:40 PM
Carpal \'Tunnel
Join Date: Sep 2004
Posts: 11,749
Quote:
Nice graph! It would be awesome if it could be made to work with stars.
I tried using this for 3 party $11s, and in the ActualWin column it gives -11 for a loss, 8 for a 3rd and 17 for a 2nd. Is this normal? I thought it should be 100*.2-11=9 for 3rd and 100*.3-11=19 for 2nd?
I tried using this for 3 party $11s, and in the ActualWin column it gives -11 for a loss, 8 for a 3rd and 17 for a 2nd. Is this normal? I thought it should be 100*.2-11=9 for 3rd and 100*.3-11=19 for 2nd?
Juk
01-29-2008
, 02:40 PM
Join Date: Jul 2006
Posts: 432
The hand history I used may have been from FreePHG rather than being written by partypoker software. Could this be the problem?
One file contains 3 hand histories and I wondered if this was the problem so split it up into seperate files. Now if only 1 of the 3 files are in the folder it gives the expected results for each individual tournament seperately, but if I put all 3 files in the folder the same error occurs.
Here is 1 hand, let me know if you want more.
I were trying this with some party hand histories I had because I am considering attempting to make stars->party hand history converter with AHK. As far as I can tell the only difficulty is in making the "finished in 3 place and won $20 USD." line as the rest is all in the stars HH.
Does your program read the blinds and antes from the hand history directly, or by just reading the level and looking it up? If so the different levels on stars will be a problem.
Also... would it be possible for you to compile a version that takes "ENTRY_FEE_PERCENTAGE" as an input, so that it can be adjusted for the different rake 9 mans on stars?
Thanks!
One file contains 3 hand histories and I wondered if this was the problem so split it up into seperate files. Now if only 1 of the 3 files are in the folder it gives the expected results for each individual tournament seperately, but if I put all 3 files in the folder the same error occurs.
Code:
HandNumber,ActualWinnings,AjustedWinnings,$EV_Luck,cEV_Luck 6040550851,-11,-8.80256,-2.19744,-446.138 6040557901,-11,-5.25522,-5.74478,-1199.63 6040558744,-11,-13.3458,2.34577,200.854 6040574231,-11,-12.7628,1.76284,71.1461 6040575328,-11,-7.36836,-3.63164,-876.318 6040882819,8,13.8302,-5.83023,-1335.55 6040909054,8,5.13661,2.86339,298.475 6040924365,8,11.9489,-3.94891,-1270.5 6040930531,8,14.0074,-6.00743,-3329.02 6041004085,17,23.6648,-6.66475,-3573.56 6041010825,17,14.8753,2.12468,-1909.59 6041022064,17,17.6244,-0.624366,-2619.19 6041036672,17,10.4297,6.57035,456.627 6041037816,17,19.0518,-2.05181,-3445.7
Code:
#Game No : 6041037816 ***** Hand History for Game 6041037816 ***** NL Texas Hold'em $11 USD Buy-in Trny:33838244 Level:7 Blinds-Antes(400/800 -25) - Thursday, June 07, 11:12:27 ET 2007 Table Speed #1330206 (Real Money) Seat 10 is the button Total number of players : 3 Seat 7: TargetChamp ( 4,585 ) Seat 6: davew422 ( 3,805 ) Seat 10: twentyfive80 ( 11,610 ) Trny:33838244 Level:7 Blinds-Antes(400/800 -25) davew422 posts ante [25] TargetChamp posts ante [25] twentyfive80 posts ante [25] ** Dealing down cards ** Dealt to davew422 [ 5c 5h ] twentyfive80 folds davew422 is all-In [3,380] >You have options at Speed #1330013 Table!. TargetChamp calls [2,980] ** Dealing Flop ** [ 3c, Kd, 3s ] ** Dealing Turn ** [ Qh ] ** Dealing River ** [ 8s ] davew422 shows [ 5c, 5h ]two pairs, Fives and Threes. TargetChamp shows [ Td, Qs ]two pairs, Queens and Threes. TargetChamp wins 7,635 chips from the main pot with two pairs, Queens and Threes. davew422 finished in 3 place and won $20 USD.
Does your program read the blinds and antes from the hand history directly, or by just reading the level and looking it up? If so the different levels on stars will be a problem.
Also... would it be possible for you to compile a version that takes "ENTRY_FEE_PERCENTAGE" as an input, so that it can be adjusted for the different rake 9 mans on stars?
Thanks!
01-29-2008
, 03:16 PM
Carpal \'Tunnel
Join Date: Sep 2004
Posts: 11,749
Quote:
The hand history I used may have been from FreePHG rather than being written by partypoker software. Could this be the problem?
One file contains 3 hand histories and I wondered if this was the problem so split it up into seperate files. Now if only 1 of the 3 files are in the folder it gives the expected results for each individual tournament seperately, but if I put all 3 files in the folder the same error occurs.
One file contains 3 hand histories and I wondered if this was the problem so split it up into seperate files. Now if only 1 of the 3 files are in the folder it gives the expected results for each individual tournament seperately, but if I put all 3 files in the folder the same error occurs.
Code:
HandNumber,ActualWinnings,AjustedWinnings,$EV_Luck,cEV_Luck 6040550851,-11,-8.80256,-2.19744,-446.138 6040557901,-11,-5.25522,-5.74478,-1199.63 6040558744,-11,-13.3458,2.34577,200.854 6040574231,-11,-12.7628,1.76284,71.1461 6040575328,-11,-7.36836,-3.63164,-876.318 6040882819,8,13.8302,-5.83023,-1335.55 6040909054,8,5.13661,2.86339,298.475 6040924365,8,11.9489,-3.94891,-1270.5 6040930531,8,14.0074,-6.00743,-3329.02 6041004085,17,23.6648,-6.66475,-3573.56 6041010825,17,14.8753,2.12468,-1909.59 6041022064,17,17.6244,-0.624366,-2619.19 6041036672,17,10.4297,6.57035,456.627 6041037816,17,19.0518,-2.05181,-3445.7
Quote:
I were trying this with some party hand histories I had because I am considering attempting to make stars->party hand history converter with AHK. As far as I can tell the only difficulty is in making the "finished in 3 place and won $20 USD." line as the rest is all in the stars HH.
Quote:
Does your program read the blinds and antes from the hand history directly, or by just reading the level and looking it up? If so the different levels on stars will be a problem.
Code:
#Game No : 5735787875 ***** Hand History for Game 5735787875 ***** NL Texas Hold'em $33 Buy-in Trny: 32104297 Level: 4 Blinds(100/200) - Monday, March 05, 03:25:07 ET 2007 Table Speed #1329890 (Real Money) Seat 10 is the button Total number of players : 7 Seat 2: Babay101 ( $4560 ) Seat 4: zoissi ( $1440 ) Seat 5: nilez77 ( $1680 ) Seat 6: DrawingDeadAgain ( $3730 ) Seat 7: flopdrop29 ( $3960 ) Seat 8: BOSSMAN_80 ( $2910 ) Seat 10: BiggieHB ( $1720 ) Trny: 32104297 Level: 4 Blinds(100/200) There is no Small Blind in this hand as the Big Blind of the previous hand left the table. ** Dealing down cards ** zoissi folds nilez77 calls [200] DrawingDeadAgain folds flopdrop29 folds BOSSMAN_80 folds BiggieHB folds Babay101 checks ** Dealing Flop ** [ 4c, Th, 8c ] Babay101 checks nilez77 bets [400] Babay101 folds nilez77 does not show cards. nilez77 wins 800 chips Game #5735788356 starts.
Quote:
Also... would it be possible for you to compile a version that takes "ENTRY_FEE_PERCENTAGE" as an input, so that it can be adjusted for the different rake 9 mans on stars?
Thanks for this and if you get a working converter then post it here and I'll make another batch file that first converts the hands, then show examples of using a different "ENTRY_FEE_PERCENTAGE" (high limit Party SNGs need this to be variable too) and/or prize structure in the batch file. I can't really do any testing though as I have no Stars hands to work with.
Juk
01-29-2008
, 04:15 PM
Join Date: Jul 2006
Posts: 432
Quote:
I can see why you thought there was a problem here, but it is working as it should: the value stored is the "cumulative sum of profit so far" and if you came 2nd in the 2nd SNG -11+19=8, and if you came 3rd in the 3rd SNG 8+9=17. It's just bad luck that you picked those 3 exact HHs which didn't make the cumulative nature of the column apparent...

Quote:
My app doesn't actually use that line at all. I detect when a player busts (or when the SNG is over) simply by looking at their stack at the start of the hand and the end of the hand, so there is no need to add that line to the converted HH files.
Quote:
I read the SB, BB and ante directly, so there shouldn't be any problems if you just make "fake" levels for the converted hand (I don't read the level at all). I don't know how Stars treats a "dead SB", but for Party I detect it by looking for the line which looks like this:
Yep, I can re-compile so that it's taken on the command line and I can also re-compile so that the prize structure is taken on the command line too (atm it's just fixed to 50/30/20). My ICM class can't handle more than 3 prizes though (ie: for MTTs) as the prizes awarded for busting out get generated using a function that only works with <=3 players.
Thanks for this and if you get a working converter then post it here and I'll make another batch file that first converts the hands, then show examples of using a different "ENTRY_FEE_PERCENTAGE" (high limit Party SNGs need this to be variable too) and/or prize structure in the batch file. I can't really do any testing though as I have no Stars hands to work with.
Juk
Yep, I can re-compile so that it's taken on the command line and I can also re-compile so that the prize structure is taken on the command line too (atm it's just fixed to 50/30/20). My ICM class can't handle more than 3 prizes though (ie: for MTTs) as the prizes awarded for busting out get generated using a function that only works with <=3 players.
Thanks for this and if you get a working converter then post it here and I'll make another batch file that first converts the hands, then show examples of using a different "ENTRY_FEE_PERCENTAGE" (high limit Party SNGs need this to be variable too) and/or prize structure in the batch file. I can't really do any testing though as I have no Stars hands to work with.
Juk
Thanks! It won't be for a couple of days as I have exams but I've made other AHK scripts that go through stars hand histories bit by bit for other reasons that I should be able to edit so it hopefully won't take long. I'm not sure how fast it will be but I don't suppose it matters massively for a 1 time thing like this.
01-29-2008
, 06:18 PM
Carpal \'Tunnel
Join Date: Sep 2004
Posts: 11,749
Quote:
Thanks! It won't be for a couple of days as I have exams but I've made other AHK scripts that go through stars hand histories bit by bit for other reasons that I should be able to edit so it hopefully won't take long. I'm not sure how fast it will be but I don't suppose it matters massively for a 1 time thing like this.
Juk
PS: If anybody had problems running the old version of my app, then it turns out it had some SSE2 instruction-set stuff still turned on. I updated the RAR file with the fixed version now.
01-29-2008
, 08:48 PM
Join Date: Oct 2005
Posts: 1,126
Juk, sure I'm doing something dumb here. I keep getting this error message.

01-29-2008
, 09:04 PM
Carpal \'Tunnel
Join Date: Sep 2004
Posts: 11,749
Make sure that you have all the files are extracted from the RAR first (ie: don't try and run it from within the RAR).
I think this error is something to do with Windows 2000 not having the right stuff installed to run stuff from the command prompt (google for that error comes up with alot of stuff). If that is the case then you need to make a shortcut and add a single dot to the end of the shortcut's command line, eg: "C:\temp\BackTestAllInLuck.exe" "." (assuming all the files have been unrared into "C:\temp"). This will let your create the csv file, but the results at the end will flash up too quick too see, so it's prolly worth reading up about that error and finding the fix.
Juk
01-29-2008
, 09:16 PM
Carpal \'Tunnel
Join Date: Sep 2004
Posts: 11,749
I must say this really does make you feel ALOT better when you're running like total ****... These last two days I've been dishing out my hard earned cash to every donk going, but in actual fact I've earned a ton of Sklansky bucks:
NumSNGs : 333 (NumAllIns[2,3,4+]=963,55,6 / NumDataPoints=1018)
Actual Won : -153% (Actual ROI=-4.1769%)
Adjusted Won : 253% (Adjusted ROI=6.92258%)
$EV Luck : -406% (-0.399385% per all-in)
cEV Luck : -192278t (-188.878t per all-in)
Just need to work out how to cash them in now...
Juk
NumSNGs : 333 (NumAllIns[2,3,4+]=963,55,6 / NumDataPoints=1018)
Actual Won : -153% (Actual ROI=-4.1769%)
Adjusted Won : 253% (Adjusted ROI=6.92258%)
$EV Luck : -406% (-0.399385% per all-in)
cEV Luck : -192278t (-188.878t per all-in)
Just need to work out how to cash them in now...
Juk
01-30-2008
, 12:39 AM
I have been following this thread since its inception but i am confused as to which version to install...
I run pokerstars and have PT
I run pokerstars and have PT
01-30-2008
, 05:15 AM
Join Date: Oct 2005
Posts: 1,126
So I'm supposed to be getting a file called BackTestAllinLuck.exe?
After I extract from the RAR, I have the following files only:
2WAY_HandEval_binary.dat
3WAY_HandEval_binary.dat
README.DOC
RunMe.bat
SNG_helper.exe
After I extract from the RAR, I have the following files only:
2WAY_HandEval_binary.dat
3WAY_HandEval_binary.dat
README.DOC
RunMe.bat
SNG_helper.exe
01-30-2008
, 08:25 AM
Can you do something ?
TY
01-30-2008
, 02:02 PM
Carpal \'Tunnel
Join Date: Sep 2004
Posts: 11,749
Juk
01-30-2008
, 03:04 PM
Join Date: Oct 2005
Posts: 1,126
OK, I changed SNG_Helper.exe to BackTestAllinLuck.exe and tried to run RunMe.bat. Now I get this one:

I'm running this on one of my old Party HH's (a Speed SNG from 06) which was exported from PT.

I'm running this on one of my old Party HH's (a Speed SNG from 06) which was exported from PT.
Feedback is used for internal purposes. LEARN MORE
Powered by:
Hand2Note
Copyright ©2008-2022, Hand2Note Interactive LTD