An edge is a small number
Worked examples
Read the claim, then run it and check the machine agrees. One at a time — nothing here is taken on trust.
def edge(p, win, loss):
return p * win - (1 - p) * loss
rows = [
("52% coin, even money", 0.52, 1.0, 1.0),
("40% win rate, 2:1 payoff", 0.40, 2.0, 1.0),
("60% win rate, 1:2 payoff", 0.60, 0.5, 1.0),
("55% coin, even money", 0.55, 1.0, 1.0),
]
for name, p, w, l in rows:
e = edge(p, w, l)
print(f"{name:26s}: edge {e:+.3f} per $1 risked -> {'profitable' if e > 0 else 'LOSING'}")
print(f"breakeven win rate at 2:1 payoff: {1 / (1 + 2):.1%}")
The one-line expectation, applied four times: the 40%-win-rate trader makes +$0.20 per bet while the 60%-win-rate trader bleeds −$0.10 — win rate and payoff can each veto the other. The breakeven line p* = L/(W+L) says a 2:1 trader only needs 33.3% — which is precisely how trend followers (m03) survive being wrong most of the time. Never quote a win rate without its payoff again.
import numpy as np
rng = np.random.default_rng(7)
edge_coin = np.where(rng.random(2500) < 0.52, 1, -1)
fair_a = np.where(rng.random(2500) < 0.50, 1, -1)
fair_b = np.where(rng.random(2500) < 0.50, 1, -1)
for name, coin in [("52% coin", edge_coin), ("fair A", fair_a), ("fair B", fair_b)]:
print(f"{name:8s}: final PnL {coin.sum():+5d}, win rate {(coin > 0).mean():.4f}")
# how often is the 52% coin DOWN, across alternate histories?
rng = np.random.default_rng(3)
after_100 = np.where(rng.random((100_000, 100)) < 0.52, 1, -1).sum(axis=1)
print(f"P(down after 100 flips): {(after_100 < 0).mean():.1%}")
after_2401 = np.where(rng.random((20_000, 2401)) < 0.52, 1, -1).sum(axis=1)
print(f"P(down after 2,401 flips): {(after_2401 < 0).mean():.1%}")
The slide's race, generated: the real edge finishes at +118 with a 52.36% sample win rate — and fair coin A finishes at +116 with 52.32%. Over 2,500 flips the luckier fair coin is statistically indistinguishable from the genuine article by eye. The alternate histories quantify the grind: a coin with a REAL 4-cent edge is still losing money 30.9% of the time after 100 flips, and 2.6% of the time even after 2,401. Real edges spend a lot of days underwater.
import numpy as np
rng = np.random.default_rng(3)
coins = np.where(rng.random((100, 250)) < 0.50, 1, -1) # 100 FAIR coins
win_rates = (coins > 0).mean(axis=1)
print("true win rate of every coin: 50.0%")
print(f"best of 100 after 250 flips: {win_rates.max():.1%}")
print(f"worst : {win_rates.min():.1%}")
print(f"coins above 52% : {(win_rates > 0.52).sum()} of 100")
One hundred coins with zero edge, and the scoreboard still crowns a 59.6% "winner" — nearly two full points beyond what our real 52% coin shows in the previous example. A quarter of the fair coins beat 52%. This is what a parameter sweep or a strategy leaderboard does to you: selection turns noise into a track record. The 2,401-flip arithmetic on the previous slide is priced for ONE pre-registered coin; test a hundred and the bar moves — m05-2 computes where it moves to.
Check the concept
One question at a time. Unsure? Revisit the lecture, then answer.
The challenge
Pass the quiz to unlock the challenge — your code will still be waiting here.