The first minute the board was actually live, it printed a 120% edge.
Half a point on a spread. Pinnacle had that side at -374. A soft book still showed +195. If that were real, it would be the best bet anyone has ever placed. It was a dead line, or two different games that had been married by accident.
On the same screen, in the same second, Real Betis against Real Madrid showed a 1.7% edge on the draw. Match score 1.00. Game still 0-0 in La Liga. That one is a candidate.
Nobody needs help distrusting the 120%. The hard part is that both numbers came out of the same code and arrive looking like the same kind of thing. A printed edge is a claim, and it is really three claims stacked under one number. The sharp price is current. The fair probability was built from a whole market. The two prices are quoting the same market. When an edge is fake, one of those is broken, and the job is finding out which while the match is still in play.
I built the engine as one process. Pinnacle is the sharp. The bets live on soft books. The trades live on three prediction markets: Polymarket, Polymarket US, and Kalshi. It covers soccer, baseball, basketball, tennis, football, and hockey, across moneylines, spreads, totals, and the periods, team totals, and corner markets that look like the main game until you read which period they are. It links games and it prices them. A bet or a trade is a later decision.
The code stays private. What I want to be asked about is the part that took the longest: how a fair probability comes out of a sharp market, and which printed edges I refuse.
0s · 0 linked · 0 sharp · 0 soft
Norway, Eliteserien · 0-0 · names 1.00
Draw +186
Spain, La Liga · 0-0 · names 1.00
Draw +285
WTA · names 0.92
Home -133
MLB, game 1 · names 1.00
Away -138 · Dead line, or a wrong number
Same screen, same second · names 1.00
Home +195 · Dead line, or a wrong number
The first six seconds are just the sharp catalog waking up: 118 live matchups, 83 of them with a moneyline, and the sharp line already publishing. By nineteen seconds the soft book has joined and 442 games sit on the Pinnacle axis. Then the rows start disagreeing with each other.
Betis against Madrid is a small number on a complete three-way with names matched at 1.00. Navarro against Muchova is the row people scroll past, because the best price on the board is negative. Guardians against Tigers is the one that should worry you. The names matched perfectly, and the away price is still garbage at +52%. The half-point spread at +120% is that same failure with the volume turned up. One book has a huge favorite and the other has a dog, on one number.
A perfect name match does not rescue a dead price. Match score and price quality are different checks, and a row has to pass both.
The board draws a line at 1.2%, and from there up to 18% a row is marked as an edge. Above 18% it is marked stale, so a 120% number can never wear the same color as a 1.7% number. The gate in front of a print is stricter, and the rest of this post is how it got that way.
Claim one: the sharp price is current
An edge compares two prices at one moment. If either price is old, it compares two different moments, and the difference is just the line moving. The sharp price on a row has to be the live line. A number I saved earlier is not that line.
Pinnacle is the reference. The bets sit on soft books. The trades sit on Polymarket, Polymarket US, and Kalshi. A soft book can have a game up that the sharp book is not dealing, and that game stays off the board. College football on a soft book does not get a row if the sharp book has no live football. With no sharp price there is no edge, and with no edge there is nothing to bet or trade. A hole in the board is cheaper than a fair probability I invented.
The failure that looks healthy is a book that stays up while its prices stop. I watched the odds go quiet on a feed that still looked connected, while the sharp line kept moving. That gap is not an edge. It is a stale book, and a stale book manufactures edges. When the sharp session dies, the last price does not stay in the market. The desk waits.
Claim two: the fair price is a fair price
Pinnacle's raw prices are not probabilities yet. They still carry the vig.
American odds convert the usual way. Plus-money is 100 over (price + 100). Minus-money is the absolute price over (absolute price + 100). That implied probability is still inflated, so I sum a complete market and divide each side by the sum.
fair = implied / sum(implied)
The word doing the work there is complete. A missing side voids the market. Soccer's main moneyline is a three-way, so a draw that failed to parse leaves the whole market blank. Two-way sports drop the draw on purpose, and basketball does not grow a fake draw just so home and away can be normalized. The same rule kills NaNs and zeros. A blank row is a better report than a fair price built from a broken side.
Spreads and totals de-vig at the exact point. A -0.5 and a -0.25 are different bets, and I do not borrow a fair price from the neighboring number when the sharp book did not post the one I am looking at.
Then the edge, which is where bets and trades split.
bet on a soft book: decimal times fair, minus 1. Trade on a contract: fair / (ask + fee), minus 1.
On a contract the fee sits inside the cost. It is the rate times p times (1 - p), with p the price you actually pay. Crypto Polymarket's sports taker uses 0.05. Polymarket US uses 0.06. Kalshi's taker is 0.07, and its maker fee is a quarter of that, 0.0175. The curve peaks at a coin flip and falls to zero as the contract becomes a certainty. That is why a two-cent discount at 50 cents and a two-cent discount at 15 cents are different trades. At 5%, the fee on a 50-cent contract is 1.25 cents. On a 15-cent contract it is a bit over half a cent.
At this point a row has a fresh sharp price, a fair probability, and an edge. That makes it a candidate and nothing more. What separates the 1.7% from the 120% is a set of gates.
The bench
1.893 × fair 54.1% − 1 = +2.5%
- Complete marketevery side has a price
- Width19¢ on the sharp market, cut at 25
- Edge band+2.5%, inside 1.2% to 18%
- Price band-112 is inside the band
- Shade3.7¢ gap, cut at 4.0¢
Clears the gate.
Size 0.7% of bankroll. Quarter-Kelly is 0.7%, width cap 3%.
Small edge, tight sharp market, shade still inside 4 cents.
Start on Clean. Pinnacle is at -130 / +270 / +380, which gives raw implieds of 56.5%, 27.0%, and 20.8%. They sum to 1.044, so the hold is 4.4% and the width comes out at 19. Fair home is 54.1%. The soft book at -112 is decimal 1.893, and 1.893 times 0.541, minus one, is +2.5%. The shade, the gap between Pinnacle's raw implied and the soft book's, is 3.7 cents of probability. That row clears.
Now drag the soft price to -105, which is the Shaded preset. The edge swells to 5.7%, and the gap crosses 4 cents. The bigger number is the one that dies. Pinnacle has already shortened that side. The juice moved before the number fully turned, and the soft book is still showing the earlier price. De-vig keeps printing a positive edge, because the vig came out of a book that is mid-move. The gap is what says the print is late.
That row is the whole argument for gating on more than the edge.
What gets thrown out
Each gate below exists because it catches something the others miss. Some refuse a huge number. Some refuse a pretty one.
Over 18%. The log already did this in public, with +52% on a perfectly matched MLB moneyline and +120% on a half-point where one book has a huge favorite and the other has a dog. I have never seen a real 40% edge survive the next tick. A pulled line, a wrong point, a scope mismatch, and a bad join all look exactly like that, so the stale stamp goes on first. I can miss a freak number. I will not bet or trade one that is probably a bug.
Width. This measures how sharp Pinnacle itself is, in the cents a betting screen uses. When both sides are minus, add the absolute prices and subtract 200, so -110 / -110 is 20 and -107 / -107 is 14. When one side is plus and one is minus, subtract the plus from the minus. A three-way is scaled so a 4.545% hold lands on that same 20. The cut is 25.
Past 25 the sharp book is unsure, and the fair probability inherits that doubt. The Wide preset is a three-way at +110 / +180 / +200. You can still show a small positive edge on the draw, but the hold is about 17% and the width is 73. A market that wide can still pay over a long enough run. The fair price inside it is noisy, and I do not treat that noise as a number I am ready to bet or trade.
Sandefjord's draw from the log is the quieter version, and it is the row that looked best on that screen. On the prices printed next to that +5.5%, the three-way hold is about 6.3%, which is a width of 28. The edge can print. The gate still throws the market out.
The long dog. Plus-money at +400 or longer is out at any edge. From +200 to +400 a row survives only when the edge is under 2%. A fat edge on a long number is how a bad map disguises itself. It can also be a real edge with brutal variance, and a few thousand bets will not tell those apart. The modest prices are where an edge can show itself before the sample gets large. The Long dog preset is +500 against a Pinnacle away price of +420. Width is exactly 25, so width is not the excuse. The edge is +9.2%, and the price band ends it.
Shade. This is raw Pinnacle implied minus raw soft implied on the side being bought, and at 4 cents of probability I stop. Width measures the juice in the whole market. Shade measures whether this one side has already been leaned on. Clean passes at 3.7 cents with a 2.5% edge. Shaded fails at 5.3 cents with a better-looking 5.7%. Both gates exist because they fail on different rows.
The same game, again. Scopes of one match share a root: full game, first half, team total, a period. I cap how many times that root can be on, and I cap repeats of one market. Home and away are opposites, so a second bet or trade on the other side of a market I already hold is blocked. The draw is neutral against both. Five angles on one soccer match are one position, and that count sits on the root id. It is not a report I run after the damage.
Fees, and what a contract pays. The Fee preset is a -110 / -110 sharp, which is a coin flip once the vig is out, against a 49 cent ask. Before the fee the edge is about 2%. Polymarket's 5% taker charge on that contract is 1.25 cents, which makes the cost 50.25 cents, and the edge goes negative. Kalshi's taker rate is 7%, so the same quote is worse. There is also a cap on the payout multiple. A contract that returns several times its cost is the long-dog problem in another unit.
Size, last. Quarter-Kelly is the size, and only after every gate above has passed. A second cap then comes from the width: 5% of bankroll when the sharp market is 15 cents or tighter, and 3% when it is wider, up to the 25-cent cut. On the Clean row the quarter-Kelly fraction is the one that binds, under 1% of bankroll. A 2.5% edge at -112 is supposed to be a small fraction. The width cap is there for the day an edge looks bigger than the sharp market deserves.
These cuts stand on a few thousand bets. That is a small sample, and the cuts should be adjusted and tested again as it grows. The law of large numbers still applies to the rows that get thrown out. A long dog, a wide market, or a fat printed edge can be profitable over enough trials, when the price was real and the sample was just too short to show it. The gates keep the variance down and hold out for the more consistent edge.
Every gate above quietly assumes that the two prices belong to the same market. That assumption is where most of my time went.
Claim three: it is the same market
Most of the fake edges I have chased were never about the odds. Two strings were not the same match, or two markets shared a number and not a meaning.
The matcher folds accents, strips the legal prefixes (FC, SC, CD, and the rest), and scores whatever tokens remain. Noisy words come out with the prefixes: athletic, atletico, sporting, racing. Without that, every Athletic glues itself to every Atletico. United stays, because Manchester United and Manchester City still have to come out different.
Containment scores high, which is why Inter against Inter Milan lands at 0.94. Tennis needs its own function, because the books cannot agree on a full name. Paul against Tommy Paul scores 0.92 as a single token that equals the other player's last name, and two different last names do not earn that. The link threshold is 0.70, greedy and one to one. One soft-book game cannot be married to two Pinnacle games just because it was vaguely close to both.
Nicknames are a directory problem, not a scoring problem. Man Utd against Manchester United scores 0. PSG against Paris Saint-Germain scores 0. Wolves against Wolverhampton scores 0. Those become the same club only as an alias after the pair has been confirmed, or as a directory entry keyed by the names each book actually posts. A similarity score does not get to invent a club. The alias list is full of things fuzzy matching will never settle: a sponsor rename, a city suffix one book appends, a reserve side the other calls "II", a transliteration. Each entry got in because the pairing had already been seen.
Home and away are an axis, and it can be crossed. The score is computed both ways, and if the crossed pairing beats the straight one by more than 0.05, the soft book flips onto Pinnacle's home. Spreads negate the point and swap the sides. Totals never flip, because over is over. The Betis-Madrid row in the log is in Pinnacle's order, and a book that lists Madrid first is the same match only after that flip. Forget the flip and the edge is a bet or a trade on the wrong team.
Scope is the same bug, only quieter. Pinnacle period 0 is the full game. In soccer, period 1 is the first half. Baseball has a first-five, then innings. Tennis periods are sets. Hockey's game moneyline includes overtime and the shootout, while the 60-minute regulation price is a different period and a three-way. A soft book posting a regulation 1x2 is not offering Pinnacle's full-game two-way. Hockey stayed in a link-only mode until those two objects were shown to be the same bet. Linking is cheap. Betting the wrong period is a donation, and so is trading it.
Alternate lines are worse, because a set spread and a match spread can wear the same label. Map the set onto the full game and the edge looks wonderful, and it is a different market. An alternate attaches only after that market has been verified as the full game for that sport. Soccer alternates stayed off, because a first-half total and a full-game alternate can print the same number, and a shared number is not an identity.
Corners, team totals, and goal bands each get their own scope and are compared only to that scope. If there is no soft-book equivalent, the sharp market is skipped while it is being parsed. It never becomes a candidate the gate has to remember to refuse.
What I would ask
If someone told me they bet soft books and trade prediction markets off Pinnacle, the green rows are not the first thing I would ask about. I would ask about the refusals.
- Is a fair price refused when any side of the market is missing?
- When the sharp session dies, does the last price stay in the market?
- Is a cut here because the row is bad, or because the sample is a few thousand bets and the variance is still too high?
- Is the width of the sharp market a gate, or only the edge?
- On a contract, is the fee inside the cost, and does that fee peak at 50 cents?
- If a feed looks connected and the odds go quiet, does it notice?
The 1.7% draw and the 120% spread sat on the screen together, printed by the same code in the same second. The work is knowing which number is a price.



