Build a custom OpenClaw skill that tells your agent exactly how much to bet. One SKILL.md file, zero dependencies beyond Python 3, and your agent can size positions using Kelly Criterion — the same formula used by professional bettors and hedge funds.
Why Your Agent Needs a Kelly Sizer
Finding a +EV bet is only half the problem. The other half — the half most bettors ignore — is knowing how much to stake.
Bet too much and a losing streak wipes you out. Bet too little and you leave growth on the table. Kelly Criterion solves this mathematically: it calculates the exact fraction of your bankroll that maximizes long-term growth given your edge and the offered odds.
Most betting agents skip position sizing entirely. They find a good line, bet a flat unit, and hope for the best. That’s leaving money on the table. A properly sized Kelly bet compounds edge over hundreds of wagers, and the difference between flat betting and Kelly betting over 1,000 bets is often the difference between a 10% return and a 40% return.
This guide builds kelly-sizer — a Layer 4 (Intelligence) skill that handles the position-sizing step of the Agent Betting Stack. It takes odds from odds-scanner and your edge estimate, then outputs the mathematically optimal stake.
What You’re Building
The kelly-sizer skill teaches your OpenClaw agent four operations:
- Single bet Kelly — Optimal stake for one bet given bankroll, odds, and true probability
- Fractional Kelly — Conservative variants (quarter, half, three-quarter Kelly) for lower variance
- Multi-bet Kelly — Simultaneous position sizing across multiple bets with exposure limits
- Max-bet enforcement — Hard caps on single-bet and total-exposure percentages
The skill uses inline Python 3 math — no pip packages, no API keys, no network calls. It runs entirely locally.
Prerequisites
- OpenClaw installed and running — Any channel (WhatsApp, Telegram, Discord, WebChat)
- Python 3 — Pre-installed on macOS and most Linux distributions
- Basic probability understanding — You need to estimate the true probability of outcomes (the skill does the rest)
The Math Behind Kelly Criterion
The Kelly formula calculates the optimal fraction of your bankroll to wager:
f* = (bp - q) / b
Where:
- f* = fraction of bankroll to bet
- b = net decimal odds (decimal odds minus 1). For American odds: positive = odds/100, negative = 100/|odds|
- p = your estimated true probability of winning
- q = probability of losing (1 - p)
Example: Lakers at +150, you estimate 45% win probability.
- b = 150/100 = 1.5
- p = 0.45, q = 0.55
- f* = (1.5 × 0.45 − 0.55) / 1.5 = (0.675 − 0.55) / 1.5 = 0.0833
Kelly says bet 8.33% of your bankroll. On a $1,000 bankroll, that’s $83.30.
Why fractional Kelly? Full Kelly maximizes growth rate but produces stomach-churning drawdowns. The standard deviation of your bankroll is proportional to the Kelly fraction. Half Kelly gives you 75% of the growth rate at 50% of the volatility. Most professionals use quarter to half Kelly.
| Variant | Multiplier | Growth Rate | Drawdown Risk |
|---|---|---|---|
| Quarter Kelly | 0.25 | ~44% of full | Very low |
| Half Kelly | 0.50 | ~75% of full | Moderate |
| Three-quarter Kelly | 0.75 | ~94% of full | High |
| Full Kelly | 1.00 | Maximum | Very high |
The Complete SKILL.md
Create the skill directory:
mkdir -p ~/.openclaw/skills/kelly-sizer
Create ~/.openclaw/skills/kelly-sizer/SKILL.md with this content:
---
name: kelly-sizer
description: "Calculate optimal bet sizes using Kelly Criterion. Supports single bets, fractional Kelly (quarter/half/three-quarter), multi-bet portfolio sizing, and max-bet enforcement. Use when asked about bet sizing, how much to bet, position sizing, Kelly Criterion, or bankroll allocation."
metadata:
openclaw:
emoji: "🎯"
requires:
bins: ["python3"]
---
# Kelly Criterion Bet Sizer
Calculate mathematically optimal bet sizes based on your edge and bankroll.
# When to Use
Use this skill when the user asks about:
- How much to bet on a specific wager
- Kelly Criterion or optimal bet sizing
- Position sizing for a bet with known edge
- Fractional Kelly or conservative bet sizing
- Sizing multiple simultaneous bets
- Maximum bet limits or bankroll allocation
# Odds Conversion Reference
Before computing Kelly, convert all odds to decimal probability format:
| Format | Example | To Decimal Odds | To Implied Prob |
|--------|---------|-----------------|-----------------|
| American (+) | +150 | 1 + odds/100 = 2.50 | 100/(odds+100) |
| American (-) | -200 | 1 + 100/|odds| = 1.50 | |odds|/(|odds|+100) |
| Decimal | 2.50 | Already decimal | 1/decimal |
| Probability | 40% | 1/prob | Already prob |
# Operations
### 1. Single Bet — Full Kelly
Calculate the optimal Kelly stake for a single bet. User must provide: bankroll, odds (any format), and their estimated true probability.
```bash
python3 -c "
import sys
bankroll = float(sys.argv[1])
odds_input = sys.argv[2]
true_prob = float(sys.argv[3])
## Convert odds to decimal
if odds_input.startswith('+'):
decimal_odds = 1 + int(odds_input[1:]) / 100
elif odds_input.startswith('-'):
decimal_odds = 1 + 100 / abs(int(odds_input[1:]))
else:
decimal_odds = float(odds_input)
b = decimal_odds - 1 # net odds
p = true_prob
q = 1 - p
## Kelly fraction
kelly_f = (b * p - q) / b if b > 0 else 0
kelly_f = max(kelly_f, 0) # never negative
implied_prob = 1 / decimal_odds
edge = true_prob - implied_prob
print(f'Odds: {odds_input} (decimal: {decimal_odds:.4f})')
print(f'Implied prob: {implied_prob:.2%} | Your estimate: {true_prob:.2%} | Edge: {edge:.2%}')
print(f'Kelly fraction: {kelly_f:.4f} ({kelly_f:.2%} of bankroll)')
print(f'Recommended stake: \${kelly_f * bankroll:.2f} of \${bankroll:.2f} bankroll')
if kelly_f <= 0:
print('⚠️ No edge detected — Kelly says do not bet')
elif kelly_f > 0.10:
print('⚠️ Kelly > 10% — consider fractional Kelly to reduce variance')
" BANKROLL ODDS TRUE_PROB
Replace BANKROLL with the dollar amount, ODDS with American (+150, -200) or decimal (2.50), and TRUE_PROB with the estimated probability as a decimal (0.45 for 45%).
2. Fractional Kelly — Conservative Sizing
Calculate quarter, half, and three-quarter Kelly for reduced variance:
python3 -c "
import sys
bankroll = float(sys.argv[1])
odds_input = sys.argv[2]
true_prob = float(sys.argv[3])
if odds_input.startswith('+'):
decimal_odds = 1 + int(odds_input[1:]) / 100
elif odds_input.startswith('-'):
decimal_odds = 1 + 100 / abs(int(odds_input[1:]))
else:
decimal_odds = float(odds_input)
b = decimal_odds - 1
p = true_prob
q = 1 - p
kelly_f = max((b * p - q) / b, 0) if b > 0 else 0
print(f'Odds: {odds_input} | True prob: {true_prob:.2%} | Full Kelly: {kelly_f:.4f}')
print(f'')
print(f'| Variant | Fraction | Stake | % of Bankroll |')
print(f'|-----------------|----------|--------------|---------------|')
for label, mult in [('Quarter Kelly', 0.25), ('Half Kelly', 0.50), ('Three-Quarter', 0.75), ('Full Kelly', 1.00)]:
f = kelly_f * mult
stake = f * bankroll
print(f'| {label:<15} | {f:.4f} | \${stake:>10.2f} | {f:>12.2%} |')
print(f'')
if kelly_f <= 0:
print('⚠️ No edge — Kelly says pass on this bet')
else:
half_stake = kelly_f * 0.5 * bankroll
print(f'💡 Recommended: Half Kelly = \${half_stake:.2f} (best risk/reward tradeoff)')
" BANKROLL ODDS TRUE_PROB
3. Multi-Bet Kelly — Portfolio Sizing
Size multiple simultaneous bets with total exposure limits. Pass bets as a semicolon-separated list of odds:prob pairs:
python3 -c "
import sys
bankroll = float(sys.argv[1])
max_exposure = float(sys.argv[2]) # max % of bankroll across all bets
kelly_mult = float(sys.argv[3]) # fractional kelly multiplier
bets_raw = sys.argv[4] # 'label,odds,prob;label,odds,prob;...'
bets = []
for entry in bets_raw.split(';'):
parts = entry.strip().split(',')
label = parts[0].strip()
odds_input = parts[1].strip()
true_prob = float(parts[2].strip())
if odds_input.startswith('+'):
decimal_odds = 1 + int(odds_input[1:]) / 100
elif odds_input.startswith('-'):
decimal_odds = 1 + 100 / abs(int(odds_input[1:]))
else:
decimal_odds = float(odds_input)
b = decimal_odds - 1
q = 1 - true_prob
kelly_f = max((b * true_prob - q) / b, 0) if b > 0 else 0
adj_f = kelly_f * kelly_mult
bets.append((label, odds_input, decimal_odds, true_prob, kelly_f, adj_f))
total_f = sum(b[5] for b in bets)
needs_scaling = total_f > max_exposure
if needs_scaling:
scale = max_exposure / total_f
else:
scale = 1.0
print(f'Bankroll: \${bankroll:.2f} | Kelly mult: {kelly_mult} | Max exposure: {max_exposure:.0%}')
print(f'')
print(f'| Bet | Odds | True P | Kelly | Adj Kelly | Stake |')
print(f'|------------------|--------|---------|--------|-----------|------------|')
for label, odds_str, dec, tp, kf, af in bets:
final_f = af * scale
stake = final_f * bankroll
print(f'| {label:<16} | {odds_str:>6} | {tp:>6.1%} | {kf:.4f} | {final_f:.4f} | \${stake:>8.2f} |')
final_total = total_f * scale
total_stake = final_total * bankroll
print(f'|------------------|--------|---------|--------|-----------|------------|')
print(f'| TOTAL | | | | {final_total:.4f} | \${total_stake:>8.2f} |')
print(f'')
if needs_scaling:
print(f'⚠️ Exposure scaled down from {total_f:.2%} to {max_exposure:.0%} cap')
print(f'Remaining bankroll: \${bankroll - total_stake:.2f} ({(1-final_total):.1%})')
" BANKROLL MAX_EXPOSURE KELLY_MULT "LABEL1,ODDS1,PROB1;LABEL2,ODDS2,PROB2"
Replace BANKROLL with your bankroll, MAX_EXPOSURE with max total allocation as decimal (0.20 for 20%), KELLY_MULT with fractional Kelly multiplier (0.5 for half Kelly), and the quoted bet string with semicolon-separated entries.
4. Max-Bet Enforcement Check
Validate a proposed bet against bankroll limits:
python3 -c "
import sys
bankroll = float(sys.argv[1])
proposed_stake = float(sys.argv[2])
max_single_pct = float(sys.argv[3]) # e.g., 0.05 for 5%
max_daily_pct = float(sys.argv[4]) # e.g., 0.15 for 15%
already_wagered = float(sys.argv[5]) # today's total wagers
max_single = bankroll * max_single_pct
max_daily = bankroll * max_daily_pct
remaining_daily = max_daily - already_wagered
approved = proposed_stake <= max_single and proposed_stake <= remaining_daily
final_stake = min(proposed_stake, max_single, remaining_daily)
print(f'Bankroll: \${bankroll:.2f}')
print(f'Proposed stake: \${proposed_stake:.2f} ({proposed_stake/bankroll:.1%} of bankroll)')
print(f'Max single bet: \${max_single:.2f} ({max_single_pct:.0%})')
print(f'Daily limit: \${max_daily:.2f} ({max_daily_pct:.0%}) | Used: \${already_wagered:.2f} | Remaining: \${remaining_daily:.2f}')
print(f'')
if approved:
print(f'✅ APPROVED: \${proposed_stake:.2f}')
else:
print(f'🚫 REDUCED: \${proposed_stake:.2f} → \${max(final_stake,0):.2f}')
if proposed_stake > max_single:
print(f' Reason: Exceeds single-bet limit of \${max_single:.2f}')
if proposed_stake > remaining_daily:
print(f' Reason: Exceeds remaining daily limit of \${remaining_daily:.2f}')
" BANKROLL PROPOSED_STAKE MAX_SINGLE_PCT MAX_DAILY_PCT ALREADY_WAGERED
Replace BANKROLL, PROPOSED_STAKE, MAX_SINGLE_PCT (0.05 for 5%), MAX_DAILY_PCT (0.15 for 15%), and ALREADY_WAGERED with today’s total wagered amount.
Output Rules
- Always show the Kelly fraction as both a decimal and a percentage
- Always show the dollar stake alongside the fraction
- For fractional Kelly, default to recommending half Kelly unless the user specifies otherwise
- When Kelly fraction is negative or zero, explicitly say “no edge — do not bet”
- When Kelly fraction exceeds 10%, warn about high variance and suggest fractional Kelly
- For multi-bet operations, always show total exposure and remaining bankroll
- All monetary amounts use two decimal places
Error Handling
- If the user provides no bankroll amount, ask for it before computing
- If the user provides no probability estimate, explain that Kelly requires a true probability estimate and cannot work from odds alone
- If the computed Kelly fraction is negative, the bet has negative expected value — advise against betting
- If Python 3 is not available, report the error and suggest installing Python
## Test It
Restart OpenClaw (or wait for hot-reload if your version supports it), then try these prompts:
| Prompt | Expected Behavior |
| --------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------- |
| "I have $5000 and want to bet on the Celtics at -150. I think they win 70% of the time. How much should I bet?" | Computes full Kelly and fractional variants, recommends half Kelly |
| "Kelly criterion for +200 odds, 40% true probability, $2000 bankroll" | Shows full Kelly = 10% of bankroll, flags as high and recommends fractional |
| "Size these bets: Lakers +150 at 45%, Celtics -130 at 60%, Nuggets +200 at 38%. Bankroll $10,000" | Multi-bet Kelly table with exposure limits |
| "Should I bet $500 on this game? My bankroll is $3000" | Max-bet enforcement check against default 5% single-bet limit |
| "What's the difference between half Kelly and full Kelly?" | Explains growth rate vs variance tradeoff with the fractional Kelly table |
Your agent reads the SKILL.md, identifies the relevant operation, plugs in your numbers, and runs the Python calculation.
## How It Works Under the Hood
OpenClaw skills are not plugins that execute code directly. The SKILL.md is a set of instructions that the LLM (Claude, GPT, etc.) reads and follows at runtime.
When you ask "how much should I bet on the Lakers at +150," this is what happens:
User message → OpenClaw Gateway → LLM reads system prompt + active skills → LLM matches “how much to bet” to kelly-sizer skill → LLM extracts bankroll, odds, and probability from context → LLM generates python3 -c command with substituted values → OpenClaw executes command via shell tool → Python outputs Kelly fraction and stake amount → LLM formats output for user with recommendation
The kelly-sizer skill uses explicit operations, exact Python commands, and strict output rules to minimize agent improvisation. The math is deterministic — given the same inputs, you always get the same Kelly fraction.
## Extending the Skill
### Add Cron-Based Portfolio Rebalancing
OpenClaw supports cron jobs. Add a scheduled task that recalculates Kelly stakes as your bankroll changes:
```json
{
"cron": "0 9 * * *",
"prompt": "My bankroll is now $X (check bankroll-manager for current balance). Recalculate Kelly stakes for all open position targets using half Kelly."
}
This ensures your position sizes stay proportional to your current bankroll — scaling up after wins and scaling down after losses, which is exactly how Kelly is designed to work.
Chain with Other Skills
The kelly-sizer consumes data from upstream skills and informs downstream decisions:
- odds-scanner → Provides the best available odds that kelly-sizer uses as input
- ev-calculator → Validates that a bet is +EV before kelly-sizer determines the stake
- vig-calculator → Helps estimate true probability by removing vig from market odds
- bankroll-manager → Tracks the current bankroll that kelly-sizer sizes against
- clv-tracker → Logs whether Kelly-sized bets outperform flat-unit bets over time
This is the power of the Agent Betting Stack — composable skills where each layer feeds the next.
Full Skill Series
This guide is part of the AgentBets OpenClaw Skills series. We’re building a complete library of betting-specific OpenClaw skills that map to the four layers of the Agent Betting Stack:
- Layer 1 — Identity: Agent reputation tracking via Moltbook
- Layer 2 — Wallet: Bankroll management, balance checking across platforms
- Layer 3 — Trading: Odds scanning, Polymarket monitoring, Kalshi tracking, arbitrage detection
- Layer 4 — Intelligence: EV calculation, Kelly sizing (this guide), CLV tracking, news sentiment
Each skill is a standalone SKILL.md you can install independently or compose into a full autonomous betting pipeline.
What’s Next
- Agent Betting Stack Overview — Understand the four-layer framework these skills map to
- Sharp Betting with Kelly Criterion — Deep dive into Kelly math and practical applications
- Odds Scanner Skill Guide — Get the odds data that feeds into Kelly sizing
- AgentBets Vig Index — Use vig-adjusted odds for more accurate true probability estimates
- Prediction Market API Reference — Size Polymarket and Kalshi positions with Kelly
