Build a custom OpenClaw skill that calculates the vig (juice/overround) on any sportsbook market. One SKILL.md file, basic math, and your agent can rank every book by how much they charge you.
Why Your Agent Needs a Vig Calculator
Every sportsbook takes a cut. That cut — the vig, juice, or overround — is the difference between winning long-term and slowly bleeding money. A -110/-110 market has ~4.5% vig. A -105/-105 market has ~2.4%. Over thousands of bets, that gap is the difference between profitability and ruin.
Most bettors never calculate vig. They eyeball odds and pick the best number. An autonomous betting agent can do better — it can quantify the exact cost of every market at every book, every time, and always trade at the sharpest price.
The vig-calculator skill is the quality layer of the Agent Betting Stack. While odds-scanner handles price discovery (what are the odds?), vig-calculator handles price evaluation (how good are these odds?). Together, they give your agent the foundation for intelligent line shopping.
What You’re Building
The vig-calculator skill teaches your OpenClaw agent four operations:
- Calculate vig for a market — Input two-way or multi-way odds, get hold percentage
- Convert odds to no-vig fair odds — Remove the vig to find the true implied probability
- Rank sportsbooks by hold — Compare efficiency across books for a given sport
- Generate vig index snapshot — Aggregate hold data across markets for daily tracking
The skill uses Python 3 for math — no external packages, no API keys required. It optionally chains with odds-scanner for live data.
Prerequisites
- OpenClaw installed and running — Any channel (WhatsApp, Telegram, Discord, WebChat)
- Python 3 — Pre-installed on macOS and most Linux distributions
- odds-scanner skill (optional) — For live odds ingestion. See the odds-scanner guide
The Math Behind Vig
Before building the skill, here’s the math it implements:
American Odds → Implied Probability
For negative odds (favorites):
implied_prob = |odds| / (|odds| + 100)
Example: -150 → 150 / 250 = 0.600 (60.0%)
For positive odds (underdogs):
implied_prob = 100 / (odds + 100)
Example: +130 → 100 / 230 = 0.4348 (43.48%)
Vig Calculation
Sum the implied probabilities for all outcomes in a market:
vig = (sum of implied probabilities) - 1
Example: -150/+130 → 0.600 + 0.4348 = 1.0348 → 3.48% vig
No-Vig Fair Odds
Remove the overround proportionally:
fair_prob = implied_prob / sum_of_implied_probs
Example: -150 side → 0.600 / 1.0348 = 0.5799 → fair odds of -138
Hold Percentage
Hold is vig expressed as a percentage of total handle:
hold% = 1 - (1 / sum_of_implied_probs) × 100
A 3.48% vig translates to approximately 3.36% hold — the percentage of every dollar wagered the book expects to keep.
The Complete SKILL.md
Create the skill directory:
mkdir -p ~/.openclaw/skills/vig-calculator
Create ~/.openclaw/skills/vig-calculator/SKILL.md with this content:
---
name: vig-calculator
description: "Calculate vig (juice/overround/hold) for any sportsbook market. Convert odds to no-vig fair lines. Rank books by efficiency. Use when asked about vig, juice, hold percentage, overround, or sportsbook sharpness."
metadata:
openclaw:
emoji: "🧮"
requires:
bins: ["python3"]
---
# Vig Calculator
Calculate the vig (juice/overround) for any sportsbook market and rank books by efficiency.
# When to Use
Use this skill when the user asks about:
- Vig, juice, or overround on a market
- Hold percentage for a sportsbook
- Removing vig to find fair/true odds
- Ranking sportsbooks by efficiency or sharpness
- Which book has the lowest juice
- The AgentBets Vig Index
# Operations
### 1. Calculate Vig for a Two-Way Market
Given American odds for both sides:
```python
python3 -c "
import sys
odds = [int(x) for x in sys.argv[1:]]
probs = []
for o in odds:
if o < 0:
probs.append(abs(o) / (abs(o) + 100))
else:
probs.append(100 / (o + 100))
total = sum(probs)
vig = (total - 1) * 100
hold = (1 - 1/total) * 100
print(f'Implied probs: {[round(p*100,2) for p in probs]}%')
print(f'Sum: {round(total*100,2)}%')
print(f'Vig (overround): {round(vig,2)}%')
print(f'Hold: {round(hold,2)}%')
fair = [round(p/total*100,2) for p in probs]
print(f'No-vig fair probs: {fair}%')
" ODDS_SIDE_A ODDS_SIDE_B
```
Replace ODDS_SIDE_A and ODDS_SIDE_B with the American odds (e.g., -110 -110, or -150 +130).
For multi-way markets (3+ outcomes like moneyline in a 3-way soccer match), add more odds as arguments.
### 2. Convert to No-Vig Fair Odds
Remove the vig and return fair American odds:
```python
python3 -c "
import sys
odds = [int(x) for x in sys.argv[1:]]
probs = []
for o in odds:
if o < 0:
probs.append(abs(o) / (abs(o) + 100))
else:
probs.append(100 / (o + 100))
total = sum(probs)
print('Fair odds (vig removed):')
for i, p in enumerate(probs):
fair_p = p / total
if fair_p >= 0.5:
fair_american = round(-100 * fair_p / (1 - fair_p))
else:
fair_american = round(100 * (1 - fair_p) / fair_p)
print(f' Side {i+1}: {odds[i]} -> fair {fair_american:+d} (true prob {round(fair_p*100,1)}%)')
" ODDS_SIDE_A ODDS_SIDE_B
```
### 3. Rank Sportsbooks by Hold (Requires odds-scanner)
When the user has odds data from odds-scanner, calculate hold per book:
```python
python3 -c "
import json, sys
data = json.loads(sys.stdin.read())
book_vigs = {}
for game in data:
for book in game.get('books', []):
name = book['name']
h2h = book.get('h2h', {})
if h2h and len(h2h) >= 2:
odds = list(h2h.values())
probs = []
for o in odds:
if o < 0:
probs.append(abs(o) / (abs(o) + 100))
else:
probs.append(100 / (o + 100))
total = sum(probs)
hold = (1 - 1/total) * 100
book_vigs.setdefault(name, []).append(hold)
print('Sportsbook Rankings (lowest hold = sharpest):')
print('-' * 50)
rankings = []
for name, holds in book_vigs.items():
avg = sum(holds) / len(holds)
rankings.append((name, avg, len(holds)))
for rank, (name, avg, n) in enumerate(sorted(rankings, key=lambda x: x[1]), 1):
print(f'{rank}. {name}: {avg:.2f}% avg hold ({n} markets)')
"
```
Pipe odds-scanner JSON output into this command.
### 4. Generate Vig Index Snapshot
Summarize the current vig landscape for a sport:
```python
python3 -c "
import json, sys
from datetime import datetime
data = json.loads(sys.stdin.read())
book_vigs = {}
for game in data:
for book in game.get('books', []):
name = book['name']
h2h = book.get('h2h', {})
if h2h and len(h2h) >= 2:
odds = list(h2h.values())
probs = [abs(o)/(abs(o)+100) if o < 0 else 100/(o+100) for o in odds]
total = sum(probs)
hold = (1 - 1/total) * 100
book_vigs.setdefault(name, []).append(hold)
print(f'=== VIG INDEX SNAPSHOT — {datetime.now().strftime(\"%Y-%m-%d %H:%M\")} ===')
print()
rankings = sorted(
[(n, sum(h)/len(h), min(h), max(h), len(h)) for n, h in book_vigs.items()],
key=lambda x: x[1]
)
for name, avg, low, high, n in rankings:
bar = '█' * int(avg * 4)
print(f'{name:<20} avg {avg:5.2f}% range [{low:.1f}%-{high:.1f}%] {bar} ({n} mkts)')
print()
market_avg = sum(r[1] for r in rankings) / len(rankings) if rankings else 0
print(f'Market average hold: {market_avg:.2f}%')
sharpest = rankings[0][0] if rankings else 'N/A'
print(f'Sharpest book today: {sharpest}')
"
```
# Output Rules
1. Always show vig as a percentage with two decimal places
2. Show both vig (overround) and hold percentage — they differ slightly
3. When ranking books, sort from lowest hold (sharpest) to highest
4. Include the number of markets sampled per book
5. For no-vig fair odds, show original → fair with true probability
6. Flag any market with vig > 8% as "high juice — consider another book"
# Error Handling
- If the user provides only one side of odds, ask for the other side
- If odds are in decimal or fractional format, convert to American first
- If hold comes out negative (which shouldn't happen with real odds), flag as likely data error
- If chaining with odds-scanner and no data is returned, the sport may be out of season
Test It
Restart OpenClaw and try these prompts:
| Prompt | Expected Behavior |
|---|---|
| “What’s the vig on -110/-110?” | Calculates 4.55% vig, 4.35% hold, shows fair odds |
| “Remove the vig from -150/+130” | Shows fair probabilities and no-vig American odds |
| “Rank NBA sportsbooks by vig” | Chains with odds-scanner, ranks books by avg hold |
| “Generate a vig index for NFL” | Produces vig index snapshot with all books ranked |
| “Is -105/-105 better than -110/-110?” | Compares vig: 2.38% vs 4.55%, recommends the lower |
How It Works Under the Hood
The vig-calculator follows the same pattern as every OpenClaw skill — it’s a set of instructions the LLM reads and follows at runtime:
User message → OpenClaw Gateway
→ LLM reads system prompt + active skills
→ LLM matches "vig" / "juice" / "hold" to vig-calculator skill
→ LLM generates python3 command with user's odds
→ OpenClaw executes command via shell tool
→ Output returned to LLM
→ LLM formats response with context
The skill uses inline Python (python3 -c "...") rather than a standalone script. This keeps it portable — no files to manage, no imports beyond the standard library, and it runs on any system with Python 3.
Why Vig Matters More Than You Think
Here’s a quick table showing how vig compounds over 1,000 bets at $100/bet with a 53% win rate:
| Vig Level | Odds | Profit/1,000 bets | Annual Edge |
|---|---|---|---|
| 4.55% | -110/-110 | +$600 | 0.6% ROI |
| 2.38% | -105/-105 | +$2,850 | 2.85% ROI |
| 1.00% | -102/-102 | +$4,100 | 4.1% ROI |
The difference between trading at -110 and -105 is $2,250 per thousand bets. For an autonomous agent placing bets 24/7, vig is the single biggest determinant of profitability.
This is why sharp bettors obsess over line shopping — and why your agent needs a vig calculator as a core skill.
Extending the Skill
Historical Vig Tracking
Add a logging layer that tracks vig over time:
{
"cron": "0 */6 * * *",
"prompt": "Run the vig index snapshot for NFL, NBA, and MLB. Append results to ~/openclaw-data/vig-history.jsonl with today's date."
}
Over weeks, this builds a dataset showing which books tighten lines for primetime games and which maintain consistent hold. That data feeds directly into the AgentBets Vig Index.
Low-Vig Alerts
Set up threshold alerts:
{
"cron": "*/15 * * * *",
"prompt": "Check NBA odds. If any sportsbook's average hold drops below 2%, alert me on Telegram with the book name and current hold."
}
When a book drops its hold (often during promotional periods), your agent catches it in real time.
Chain with Other Skills
The vig-calculator outputs feed directly into other Agent Betting Stack skills:
- odds-scanner → vig-calculator — Fetch odds, then evaluate their quality
- vig-calculator → arb-finder — Low-vig books are more likely to offer arb opportunities
- vig-calculator → kelly-sizer — Factor vig into edge estimates before sizing positions
- vig-calculator → clv-tracker — Track whether you consistently beat the vig-adjusted closing line
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, vig calculation (this guide), Polymarket monitoring, Kalshi tracking, arbitrage detection
- Layer 4 — Intelligence: EV calculation, Kelly sizing, 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
- Odds Scanner Skill — Fetch live odds that feed into this vig calculator
- Agent Betting Stack Overview — Understand the four-layer framework these skills map to
- AgentBets Vig Index — See our daily sportsbook efficiency rankings powered by this skill
- Sharp Betting Guide — Why vig matters for long-term profitability
- Kelly Criterion Guide — Size your bets after accounting for vig
