#!/usr/bin/env python3 # -*- coding: utf-8 -*- """ Chiffres des articles de stratégie du 14 au 20 septembre 2026. python3 sims/strategy-2026-09.py Tout ce qui est publié dans ces articles sort d'ici. Deux règles : • quand une formule exacte existe, c'est elle qui est publiée ; la simulation ne sert qu'à la contrôler. Si les deux divergent, c'est le code qui est faux, pas la formule ; • graine fixe et nombre de tirages annoncé : n'importe qui doit retrouver les mêmes nombres en relançant ce fichier. """ import bisect import random from fractions import Fraction random.seed(20260914) P_EUR = Fraction(18, 37) # chance simple, roulette européenne P_AME = Fraction(18, 38) # roulette américaine, double zéro # ── 1. Roulette : ruine du joueur, formules exactes de Feller ────────── def p_atteindre(p, i, n): """Probabilité exacte d'atteindre n avant 0, en misant 1 unité.""" q = 1 - p if p == q: return Fraction(i, n) r = q / p return (1 - r ** i) / (1 - r ** n) def duree(p, i, n): """Nombre moyen de coups avant d'atteindre 0 ou n.""" q = 1 - p if p == q: return i * (n - i) return float(i) / float(q - p) - (float(n) / float(q - p)) * float(p_atteindre(p, i, n)) def sim_paliers(p, i, n, mise, tirages): """Contrôle par simulation de p_atteindre, en unités de `mise`.""" p, gagne = float(p), 0 u_dep, u_obj = i // mise, n // mise for _ in range(tirages): c = u_dep while 0 < c < u_obj: c += 1 if random.random() < p else -1 gagne += c >= u_obj return gagne / tirages print("=" * 70) print("1. ROULETTE — doubler 100 € : seule la taille de mise change quelque chose") print("=" * 70) print("Roulette européenne, chance simple, p = 18/37 = %.6f" % float(P_EUR)) print("Objectif : passer de 100 € à 200 €, ou tout perdre.\n") print(" %-18s %-14s %-12s %s" % ("mise par coup", "probabilité", "coups moyens", "contrôle simulé")) for mise, tirages in ((1, 0), (5, 0), (10, 20_000), (25, 40_000), (50, 100_000), (100, 200_000)): ex = float(p_atteindre(P_EUR, 100 // mise, 200 // mise)) d = duree(P_EUR, 100 // mise, 200 // mise) si = "%.2f %%" % (sim_paliers(P_EUR, 100, 200, mise, tirages) * 100) if tirages else "—" aff = "%.4f %%" % (ex * 100) if ex < 0.01 else "%.2f %%" % (ex * 100) print(" %-18s %-14s %-12.0f %s" % ("%d €" % mise, aff, d, si)) pire = float(p_atteindre(P_EUR, 100, 200)) print("\n Du pire au meilleur : %.2f %% → %.2f %%, soit %.0f fois plus de chances." % (pire * 100, float(P_EUR) * 100, float(P_EUR) / pire)) print(" Espérance de gain, dans TOUS les cas : −2,70 % de chaque euro misé.") print(" Ce n'est pas l'espérance qui change, c'est la forme de la distribution.") print("\n Roulette américaine (double zéro), même objectif :") print(" 1 € par coup : %.5f %%" % (float(p_atteindre(P_AME, 100, 200)) * 100)) print(" 100 € d'un coup: %.2f %%" % (float(P_AME) * 100)) print(" → le double zéro divise les chances par %.0f en petite mise." % (float(p_atteindre(P_EUR, 100, 200)) / float(p_atteindre(P_AME, 100, 200)))) print("\n Objectifs plus modestes, mise de 1 € (européenne) :") for obj in (110, 125, 150, 200, 300): print(" 100 € → %-6s : %6.2f %% (%5.0f coups en moyenne)" % ("%d €" % obj, float(p_atteindre(P_EUR, 100, obj)) * 100, duree(P_EUR, 100, obj))) # ── 2. Slots : modèle de rouleau, calé sur des tables publiées ───────── def slot(rtp=0.96, volat="haute"): if volat == "haute": lots = [(0.21, 0.5), (0.09, 1.5), (0.035, 4.0), (0.010, 15.0), (0.0025, 60.0), (0.0004, 400.0)] else: lots = [(0.42, 0.6), (0.15, 1.4), (0.05, 3.0), (0.008, 12.0), (0.0012, 40.0), (0.00008, 250.0)] k = rtp / sum(pr * m for pr, m in lots) lots = [(pr, m * k) for pr, m in lots] seuils, mults, c = [], [], 0.0 for pr, m in lots: c += pr seuils.append(c) mults.append(m) seuils.append(1.0) mults.append(0.0) return seuils, mults, sum(pr * m for pr, m in lots), lots[0][0] + sum(p for p, _ in lots[1:]) def faire_tourner(seuils, mults): return mults[bisect.bisect_right(seuils, random.random())] def duree_session(seuils, mults, bankroll, mise, cap): c, n = bankroll, 0 while c >= mise and n < cap: c += mise * (faire_tourner(seuils, mults) - 1.0) n += 1 return n, c def double_ou_ruine(seuils, mults, bankroll, mise, cap=400_000): c, n, obj = bankroll, 0, bankroll * 2 while mise <= c < obj and n < cap: c += mise * (faire_tourner(seuils, mults) - 1.0) n += 1 return c >= obj print("\n" + "=" * 70) print("2. SLOTS — la mise décide de la durée, pas du résultat") print("=" * 70) for volat in ("haute", "basse"): seuils, mults, rtp, hits = slot(0.96, volat) print("\n Volatilité %s — RTP du modèle %.2f %%, %.0f %% de tours gagnants" % (volat, rtp * 100, hits * 100)) print(" Bankroll 200 €, cadence 600 tours/heure") print(" %-9s %-15s %-14s %-14s %s" % ("mise", "tours médians", "durée", "survie 1 h", "double avant ruine")) for mise in (0.20, 0.50, 1.00, 2.00, 5.00): tours = [] survie = 0 for _ in range(3_000): n, _ = duree_session(seuils, mults, 200.0, mise, 20_000) tours.append(n) survie += n >= 600 tours.sort() med = tours[1_500] dbl = sum(double_ou_ruine(seuils, mults, 200.0, mise) for _ in range(2_000)) / 2_000 print(" %-9s %-15d %-14s %-14s %s" % ("%.2f €" % mise, med, "%.0f min" % (med / 600 * 60), "%.1f %%" % (survie / 3_000 * 100), "%.1f %%" % (dbl * 100))) print("\n Espérance sur 600 tours à 1 € : %.2f € quelle que soit la volatilité." % (600 * 1 * -0.04)) print(" Ce que la volatilité change : la haute double 27 fois plus souvent") print(" en petite mise, la basse fait durer 2 fois plus longtemps.") # ── 3. Règles de session ─────────────────────────────────────────────── print("\n" + "=" * 70) print("3. RÈGLES DE SESSION — ce qu'un stop-loss change vraiment") print("=" * 70) seuils, mults, rtp, _ = slot(0.96, "haute") TIRAGES = 60_000 print(" Slot 96 % haute volatilité, bankroll 200 €, mise 1 €, 600 tours au plus") print(" %s sessions par règle\n" % format(TIRAGES, ",d").replace(",", " ")) print(" La moyenne PUBLIÉE est l'identité de Wald : espérance = tours joués") print(" × (−0,04 €). Elle ne se simule pas, elle se calcule. La colonne") print(" « simulé » n'est là que pour vérifier qu'elle tombe dans l'intervalle.\n") print(" %-30s %-9s %-12s %-19s %-11s %s" % ("règle", "tours", "exact (Wald)", "simulé ± 2σ", "médiane", "sessions +")) for nom, sl, tp in [("aucune (600 tours)", None, None), ("stop-loss −50 €", -50, None), ("objectif +50 €", None, 50), ("stop-loss −50 / objectif +50", -50, 50), ("objectif +200 €", None, 200)]: tot, tot2, pos, res, nt = 0.0, 0.0, 0, [], 0 for _ in range(TIRAGES): c, n = 200.0, 0 while n < 600 and c >= 1.0: c += faire_tourner(seuils, mults) - 1.0 n += 1 d = c - 200.0 if (sl is not None and d <= sl) or (tp is not None and d >= tp): break g = c - 200.0 tot += g tot2 += g * g pos += g > 0 nt += n res.append(g) res.sort() moy = tot / TIRAGES var = tot2 / TIRAGES - moy * moy err = 2 * (var / TIRAGES) ** 0.5 tours = nt / TIRAGES print(" %-30s %-9.0f %-12s %-19s %-11s %s" % (nom, tours, "%+.2f €" % (tours * -0.04), "%+.2f ± %.2f €" % (moy, err), "%+.2f €" % res[TIRAGES // 2], "%.1f %%" % (pos / TIRAGES * 100))) print("\n Le prix ne bouge pas : 4 centimes par tour, quelle que soit la règle.") print(" Une règle de session n'achète pas un meilleur résultat — elle achète") print(" moins de tours, donc une facture plus petite, et elle déplace la") print(" proportion de sessions qui se terminent dans le vert.") # ── 4. Vitesse de jeu ────────────────────────────────────────────────── print("\n" + "=" * 70) print("4. VITESSE DE JEU — le multiplicateur que personne ne regarde") print("=" * 70) print(" Coût horaire = mise × coups par heure × avantage de la maison\n") print(" %-28s %-9s %-10s %-9s %s" % ("jeu", "edge", "coups/h", "mise", "coût/heure")) jeux = [("Blackjack, table pleine", 0.005, 60, 10), ("Blackjack, en tête à tête", 0.005, 200, 10), ("Video poker 9/6 Jacks or Better", 0.0046, 600, 1.25), ("Baccarat, banque", 0.0106, 70, 10), ("Roulette européenne", 0.027, 45, 10), ("Roulette américaine", 0.0526, 45, 10), ("Crash / Limbo (1 % edge)", 0.01, 500, 1), ("Slot en ligne", 0.04, 600, 1), ("Slot, tours rapides", 0.04, 900, 1)] couts = {} for nom, edge, ch, mise in jeux: c = mise * ch * edge couts[nom] = c print(" %-28s %-9s %-10d %-9s %.2f €" % (nom, "%.2f %%" % (edge * 100), ch, "%.2f €" % mise, c)) print("\n Même jeu, même mise, même avantage :") print(" blackjack en tête à tête coûte %.1f fois une table pleine." % (couts["Blackjack, en tête à tête"] / couts["Blackjack, table pleine"])) print(" Mise 10 fois plus petite, heure %.1f fois plus chère :" % (couts["Slot en ligne"] / couts["Roulette européenne"])) print(" slot à 1 € = %.0f €/h, roulette européenne à 10 € = %.0f €/h." % (couts["Slot en ligne"], couts["Roulette européenne"])) print(" Le meilleur avantage du casino ne suffit pas :") print(" video poker 9/6 (%.2f %% d'edge) coûte %.2f €/h," % (0.46, couts["Video poker 9/6 Jacks or Better"])) print(" blackjack table pleine (%.2f %%) coûte %.2f €/h." % (0.50, couts["Blackjack, table pleine"]))