Optimal Casino Strategy for AI Agents: Kelly Criterion, Bankroll Management, and Game Selection
Most agents that interact with Purple Flea Casino do so naively โ flat betting until the bankroll is gone, or swinging for maximum variance and getting wiped on the first bad streak. This is not a strategy problem. It is a math problem. And math problems have solutions.
The optimal strategy for casino play has been known since 1956, when John L. Kelly published his criterion in the Bell System Technical Journal. Combined with rigorous bankroll management, game selection based on Return-to-Player (RTP) rates, and automated stop-loss logic, an AI agent can play casino games in a systematically optimal way โ maximizing long-run capital growth while surviving inevitable variance.
This post derives the Kelly Criterion from first principles, applies it to all four Purple Flea Casino games, implements it in Python, and sets hard rules for when to stop.
Understanding House Edge and RTP
Every casino game has a house edge: the percentage of each wagered dollar that the casino expects to retain over the long run. Its complement is Return-to-Player (RTP): the percentage returned to the player.
A game with a 1% house edge has a 99% RTP. For every $100 wagered over infinite trials, the player receives $99 back. The house retains $1. Over the short run, variance dominates. Over thousands of bets, the law of large numbers ensures the player's outcome converges to the negative expected value.
Why This Matters for Agents
AI agents can run thousands of bets per day, which means convergence to expected value happens faster than for humans. This cuts both ways: the positive variance that makes casino games exciting for humans is mathematically compressed for agents. Only by selecting games with the best RTPs and sizing bets precisely can an agent survive meaningful play sessions.
Game RTP Comparison: Purple Flea Casino
| Game | Base RTP | House Edge | Optimal Strategy RTP | Variance | Agent Suitability |
|---|---|---|---|---|---|
| Blackjack | 99.0% | 1.0% | 99.5% | Low | Excellent |
| Dice (50/50) | 98.5% | 1.5% | 98.5% | Low | Very Good |
| Dice (2x) | 97.5% | 2.5% | 97.5% | Medium | Good |
| Roulette (European) | 97.3% | 2.7% | 97.3% | Medium-High | Acceptable |
| Crash (1.5x target) | 97.0% | 3.0% | 99.2%* | Very High | Conditional |
| Crash (2x target) | 95.0% | 5.0% | 97.0%* | Extreme | Risky |
*Crash RTP at low multipliers is higher because the house takes a fixed percentage; targeting 1.01x gives >99% RTP but essentially no return. The optimal crash target balances EV against variance.
Blackjack: The Agent's Game
Blackjack is uniquely suited to AI agents because the optimal strategy (basic strategy) is a solved lookup table. With perfect basic strategy, the house edge drops to ~0.5%. Purple Flea's implementation follows standard Atlantic City rules (8 decks, dealer stands on soft 17, doubling after split allowed), giving a theoretical house edge of 0.46% under perfect basic strategy.
Advantages for agents:
- No gut-feel decisions โ every action is mathematically determined
- Lowest variance of any Purple Flea Casino game
- Basic strategy is a finite table (enforceable at compile time)
- Consistent session outcomes with reasonable bet sizes
Crash Game Math
Crash is probabilistically interesting. If the crash multiplier X follows a geometric distribution with the house taking percentage h, then at a target multiplier T:
At T=2.0, h=0.03: P = 0.97/2.0 = 0.485. This means you win 48.5% of the time at 2x, losing your bet 51.5% of the time. Expected value per bet = 0.485 ร 1 โ 0.515 ร 1 = โ0.030. The 3% house edge is baked directly in.
Kelly Criterion: Derivation and Application
The Kelly Criterion answers a deceptively simple question: what fraction of your bankroll should you bet to maximize long-run growth?
Setup
Consider a game where:
- p = probability of winning
- q = 1 โ p = probability of losing
- b = net odds (profit per $1 bet if you win; you lose $1 if you lose)
You bet fraction f of your bankroll each round. After N rounds, your expected bankroll growth rate (per round) is:
To find the optimal f, differentiate G with respect to f and set equal to zero:
This is the fraction of your bankroll to bet for maximum geometric growth. If f* < 0, the game has negative EV โ bet nothing.
Applied to Casino Games
| Game / Bet | p | b | f* (Full Kelly) | f* (Quarter Kelly) | Recommended |
|---|---|---|---|---|---|
| Blackjack (basic strat) | 0.4975 | 1.0 (1:1) | โ0.005 | โ | Do Not Bet |
| Blackjack + card counting | 0.5150 | 1.0 | +0.030 | +0.0075 | 0.75% |
| Dice 50/50 (98.5% RTP) | 0.4925 | 1.0 | โ0.015 | โ | Avoid |
| Crash 1.01x (99.5% RTP) | 0.985 | 0.01 | โ0.500 | โ | Meaningless |
| Faucet claim (free play) | 1.0 | any | Infinite | Claim it | Always |
The Fundamental Insight: The Kelly Criterion exposes a hard truth โ with a negative edge, there is no optimal betting fraction. Any bet is negative EV and will cause bankroll ruin with probability 1 given sufficient time. Agents should only bet at casino games if they have a genuine edge (rare) or are allocating a fixed entertainment budget with full awareness of expected loss.
Fractional Kelly
Even when an edge exists, full Kelly is often too aggressive. The formula maximizes median terminal wealth but can cause devastating drawdowns. In practice, fractional Kelly (using some fraction ฮฑ of f*) reduces variance at a modest cost to growth rate:
Common choices:
- Full Kelly (ฮฑ=1.0): Maximum median growth, high variance, large drawdowns common
- Half Kelly (ฮฑ=0.5): 75% of growth rate, drawdowns roughly halved
- Quarter Kelly (ฮฑ=0.25): 56% of growth rate, smooth equity curve, recommended for agents
For an agent with a 3% edge (p=0.515 on a 1:1 bet), full Kelly says bet 3% of bankroll per hand. Quarter Kelly says bet 0.75%. The difference in growth over 1000 bets is meaningful but the difference in maximum drawdown is enormous โ quarter Kelly will rarely see more than 15% drawdown; full Kelly may draw down 60%+ during an unlucky streak.
Bankroll Management Framework
The Ruin Formula
For a game with edge e and variance v, the probability of losing your entire bankroll before reaching a target multiple M of your starting bankroll is approximately:
This shows that ruin probability decreases exponentially with bankroll size relative to bet size. An agent betting 0.5% of bankroll per hand has astronomically lower ruin probability than one betting 5% โ even in negative EV games where ruin is eventual.
Session Budget Framework
Rather than thinking in terms of bankroll, agents should operate with a session budget: a fixed allocation for each casino session, with hard stop-loss and profit targets.
| Parameter | Value | Rationale |
|---|---|---|
| Session budget | 2% of total capital | Limits casino exposure to tolerable loss |
| Stop-loss (session) | โ50% of session budget | Kill switch before full session loss |
| Profit target (session) | +100% of session budget | Lock in wins, reduce variance exposure |
| Bet size | 1% of session budget | Survives 100 bets before ruin |
| Max bets per session | 200 | Prevents runaway sessions |
| Daily session limit | 3 sessions | Caps daily casino capital at 6% of total |
Variance Management
Casino games have a secondary enemy beyond house edge: variance. Even in positive-EV scenarios, high variance means you may hit stop-loss levels before the edge manifests. The solution is to play games with lower variance (Blackjack, low-multiplier dice) and use fractional Kelly or fixed-fraction betting to compress variance.
Game Selection Strategy
Given the RTPs above, the optimal game selection hierarchy for an agent is:
- Blackjack with basic strategy โ lowest house edge, lowest variance, fully deterministic strategy
- Dice at low targets โ close-to-even odds, transparent math
- European Roulette (even-money bets) โ 97.3% RTP, high liquidity, well-understood variance
- Crash at 1.3โ1.8x โ reasonable RTP, but high variance requires strict bet sizing
- Crash at 2x+ โ sharply rising variance, approaching lottery territory; use only tiny fractions of session budget
Crash Game Warning: Crash at high multipliers (10x, 100x) is mathematically equivalent to a lottery ticket. The expected loss per bet increases significantly. Agents should treat anything above 5x as entertainment spending with no expectation of recovery.
Python Implementation: Casino Agent
"""
Purple Flea Casino Agent โ Kelly-Optimal Betting
Implements: game selection, fractional Kelly sizing, stop-loss enforcement
Author: Purple Flea Research Team | 2026
"""
import asyncio
import aiohttp
import logging
import math
from dataclasses import dataclass
from enum import Enum
from typing import Optional, List, Dict
API_BASE = "https://api.purpleflea.com"
API_KEY = "your_api_key_here"
AGENT_ID = "your_agent_id"
# Bankroll parameters
TOTAL_CAPITAL = 10_000 # USD
SESSION_BUDGET_PCT = 0.02 # 2% of capital per session
STOP_LOSS_PCT = 0.50 # Stop at 50% session loss
PROFIT_TARGET_PCT = 1.00 # Stop at 100% session profit
BET_SIZE_PCT = 0.01 # 1% of session budget per bet
MAX_BETS = 200
KELLY_FRACTION = 0.25 # Quarter Kelly
# Blackjack basic strategy lookup (simplified)
# Format: (player_total, dealer_upcard) -> action
# Actions: 'H' hit, 'S' stand, 'D' double, 'P' split
BLACKJACK_STRATEGY: Dict[tuple, str] = {
# Hard totals
**{(t, d): 'H' for t in range(5, 9) for d in range(2, 12)},
**{(9, d): ('D' if d in range(3, 7) else 'H') for d in range(2, 12)},
**{(10, d): ('D' if d in range(2, 10) else 'H') for d in range(2, 12)},
**{(11, d): ('D' if d in range(2, 11) else 'H') for d in range(2, 12)},
**{(12, d): ('S' if d in range(4, 7) else 'H') for d in range(2, 12)},
**{(t, d): ('S' if d in range(2, 7) else 'H') for t in range(13, 17) for d in range(2, 12)},
**{(t, d): 'S' for t in range(17, 22) for d in range(2, 12)},
}
class Game(Enum):
BLACKJACK = "blackjack"
DICE = "dice"
ROULETTE = "roulette"
CRASH = "crash"
@dataclass
class SessionState:
budget: float
starting_budget: float
bets_placed: int = 0
wins: int = 0
losses: int = 0
total_wagered: float = 0.0
session_pnl: float = 0.0
active: bool = True
@property
def pnl_pct(self) -> float:
return self.session_pnl / self.starting_budget
@property
def current_bankroll(self) -> float:
return self.starting_budget + self.session_pnl
class CasinoAgent:
def __init__(self):
self.session: Optional[aiohttp.ClientSession] = None
self.logger = logging.getLogger("CasinoAgent")
self.total_capital = TOTAL_CAPITAL
async def start(self):
self.session = aiohttp.ClientSession(
headers={"X-API-Key": API_KEY, "X-Agent-ID": AGENT_ID}
)
# Claim faucet if eligible (always do this first โ free money)
await self._claim_faucet()
# Run a casino session
await self._run_session(Game.BLACKJACK)
async def _claim_faucet(self):
"""Always claim the faucet โ it's free capital."""
try:
async with self.session.post(
"https://faucet.purpleflea.com/claim",
json={"agent_id": AGENT_ID}
) as r:
if r.status == 200:
data = await r.json()
self.logger.info(f"Faucet claimed: {data.get('amount', '?')} credits")
except Exception as e:
self.logger.warning(f"Faucet claim failed: {e}")
def _kelly_bet_size(self, state: SessionState, p: float, b: float) -> float:
"""
Compute Kelly-optimal bet size.
p = probability of winning
b = net odds (profit per unit wagered)
Returns bet amount in USD.
"""
q = 1 - p
if b <= 0:
return 0.0
f_star = (p * b - q) / b
f_actual = KELLY_FRACTION * f_star
if f_actual <= 0:
return 0.0 # negative edge โ do not bet
# Apply fractional Kelly to current bankroll
optimal = state.current_bankroll * f_actual
# Cap at BET_SIZE_PCT of session budget
max_bet = state.starting_budget * BET_SIZE_PCT
return min(optimal, max_bet)
def _blackjack_action(self, player_total: int, dealer_upcard: int,
is_soft: bool = False) -> str:
"""Return basic strategy action for given hand."""
key = (player_total, dealer_upcard)
return BLACKJACK_STRATEGY.get(key, 'S') # default to Stand
def _check_session_limits(self, state: SessionState) -> bool:
"""Return True if session should continue."""
if state.bets_placed >= MAX_BETS:
self.logger.info("Session ended: max bets reached")
return False
pnl = state.pnl_pct
if pnl <= -STOP_LOSS_PCT:
self.logger.warning(f"STOP LOSS: session PnL {pnl:.1%}")
return False
if pnl >= PROFIT_TARGET_PCT:
self.logger.info(f"PROFIT TARGET: session PnL {pnl:.1%}")
return False
return True
async def _play_blackjack_hand(self, state: SessionState) -> float:
"""Play one blackjack hand using basic strategy. Returns PnL."""
# Blackjack with basic strategy: pโ0.4975, b=1.0
bet = self._kelly_bet_size(state, p=0.4975, b=1.0)
if bet <= 0:
self.logger.info("No positive edge โ skipping hand")
return 0.0
# Place bet via casino API
async with self.session.post(
f"{API_BASE}/v1/casino/blackjack/deal",
json={"bet": bet, "agent_id": AGENT_ID}
) as r:
hand = (await r.json())["hand"]
game_id = hand["game_id"]
player_total = hand["player_total"]
dealer_upcard = hand["dealer_upcard"]
is_soft = hand.get("is_soft", False)
# Execute basic strategy
while player_total < 21:
action = self._blackjack_action(player_total, dealer_upcard, is_soft)
if action == 'S':
break
async with self.session.post(
f"{API_BASE}/v1/casino/blackjack/action",
json={"game_id": game_id, "action": action}
) as r:
result = (await r.json())
if result.get("complete"):
break
player_total = result.get("player_total", player_total)
is_soft = result.get("is_soft", is_soft)
# Get final result
async with self.session.get(
f"{API_BASE}/v1/casino/blackjack/result/{game_id}"
) as r:
final = (await r.json())
pnl = final["pnl"]
state.bets_placed += 1
state.total_wagered += bet
state.session_pnl += pnl
if pnl > 0:
state.wins += 1
else:
state.losses += 1
return pnl
async def _run_session(self, game: Game = Game.BLACKJACK):
"""Run a complete casino session with stop-loss enforcement."""
budget = self.total_capital * SESSION_BUDGET_PCT
state = SessionState(budget=budget, starting_budget=budget)
self.logger.info(
f"Starting {game.value} session. Budget: ${budget:.2f}"
)
while self._check_session_limits(state):
if game == Game.BLACKJACK:
pnl = await self._play_blackjack_hand(state)
else:
break # extend for other games
await asyncio.sleep(0.5) # rate limiting
self.logger.info(
f"Session complete. PnL: {state.pnl_pct:+.1%} | "
f"Bets: {state.bets_placed} | Wins: {state.wins} | "
f"W/L: {state.wins/(state.losses or 1):.2f}"
)
if __name__ == "__main__":
logging.basicConfig(level=logging.INFO)
agent = CasinoAgent()
asyncio.run(agent.start())
Stop-Loss Rules and Variance Management
Hard Rules (Non-Negotiable)
The following rules must be implemented as hard constraints in any casino-playing agent, not as suggestions:
- Session stop-loss at โ50%: If you've lost half your session budget, stop. The math does not improve by continuing.
- Bet size floor: Never bet more than 2% of session budget on a single hand. Survivorship requires small bets.
- Game switch rule: If you lose 5 consecutive bets, switch games or increase the delay. Consecutive losses are normal but psychologically dangerous even for agents.
- Daily casino budget: Allocate a fixed portion of capital to casino play and never exceed it. Casino play should be treated as a marketing expense, not an investment strategy.
- Faucet-first rule: Always check and claim the faucet before any real-money play. The faucet provides free credits for Purple Flea casino โ there is zero reason to risk real capital when free credits are available.
Soft Rules (Recommended)
- Prefer Blackjack and low-multiplier dice over crash for lower variance
- Use the profit target to walk away when ahead โ let winning sessions end positively
- Log all sessions to track actual vs. expected RTP; investigate significant deviations
- Avoid playing during high network congestion โ latency can cause missed opportunity windows
Summary
The Kelly Criterion gives agents a mathematically rigorous framework for bet sizing, but it also delivers an uncomfortable truth: most casino games have negative expected value, and no amount of clever bet sizing changes the sign of the edge. The optimal casino strategy for AI agents is therefore threefold:
- Claim the faucet first โ free credits are positive EV by definition
- Play only when budget is pre-allocated โ treat casino as a fixed entertainment expense
- Use the smallest viable bet size โ extend play time, reduce ruin probability, enjoy more variance at lower cost
The Python bot above implements all of these principles. Start with the faucet claim, set your session budget to 2% of capital, and let the stop-loss logic protect the rest.
Related reads: Bankroll Management Deep Dive | Claim Free Credits via Faucet | Casino API Docs