A sharp-money betting-line-move detector — and a hands-off, custody-safe agent that can act on it.
Sharp money is professional money. When a sharp bettor hits a line, the price moves before the rest of the market catches up. That early move is the edge. SharpWatch reads a live odds feed tick by tick, tracks every line's implied probability, and flags the moment one shifts past a threshold — telling you which book, which market, which outcome, how far, and which way the smart money went, as it happens.
It runs $0, offline, no key, no network by default (a deterministic recorded market), so you can see it work before wiring anything live.
python -m sharpwatch watch
What it is. A signal tool for sports-betting markets. The core is a pure, dependency-free detector: feed it successive odds snapshots and it emits a sharp move whenever a line's implied probability jumps past a configurable threshold (in percentage points). No model, no LLM, no black box — the trigger is legible and the output is a plain, explainable signal line.
Why it's a distinct tool. Most "trading agents" start from price candles and technical indicators. SharpWatch starts from the odds themselves — the line move is the alpha, because a moving line is the market revealing where informed money went. The detector is the product; everything else (feed, decision, wallet) is a thin edge around it.
The "& Agents" angle — acting on the signal, safely. Add --act and SharpWatch also shows
the bet a hands-off agent would place on each signal, sized within a risk policy and signed
only within a sandbox custody cap. The agent never holds keys and the wallet refuses any bet
that would breach what you authorized — so you get an agent that can act on the edge without ever
being able to exceed its leash. Two independent bounds hold: the risk policy sizes the bet, and
the custody wallet gates every signature.
How to run. See below — it is one command, and it is free.
Requires Python 3.11+. No runtime dependencies (pure standard library).
python -m sharpwatch watchStreams a deterministic recorded World Cup odds market through the detector and prints each flagged sharp move as a live signal line, then a short summary.
──────────────────────────────────────────────────────────────────────────
SharpWatch · sharp-money line-move detector
recorded market · $0 · no key · no network · threshold 3pp
──────────────────────────────────────────────────────────────────────────
SHARP ↑ [1x2] fixture 42 · Pinnacle · Home: 45.400% → 54.600% (+9.200 pp, up)
SHARP ↓ [1x2] fixture 77 · Betfair · Home: 38.600% → 30.800% (-7.800 pp, down)
SHARP ↑ [1x2] fixture 88 · Circa · Draw: 24.000% → 30.500% (+6.500 pp, up)
SHARP ↑ [1x2] fixture 91 · Pinnacle · Away: 39.400% → 50.200% (+10.800 pp, up)
──────────────────────────────────────────────────────────────────────────
4 sharp move(s) flagged from 24 reading(s)
python -m sharpwatch watch --actUnder each signal it also prints the policy-gated bet the agent would place — and shows the custody wallet refusing the bet that would breach the cap.
custody: agent stakes ≤ 10/bet, ≤ 25/fixture, ≤ 35 total (sandbox)
──────────────────────────────────────────────────────────────────────────
SHARP ↑ [1x2] fixture 42 · Pinnacle · Home: 45.400% → 54.600% (+9.200 pp, up)
└─ act · Yes 10 on 1x2:Home · signed within policy [sandbox:a7eecf2a509a1450]
SHARP ↓ [1x2] fixture 77 · Betfair · Home: 38.600% → 30.800% (-7.800 pp, down)
└─ act · No 10 on 1x2:Home · signed within policy [sandbox:ffa60455a8c7dc53]
SHARP ↑ [1x2] fixture 88 · Circa · Draw: 24.000% → 30.500% (+6.500 pp, up)
└─ act · Yes 10 on 1x2:Draw · signed within policy [sandbox:ef01c5bda34e018d]
SHARP ↑ [1x2] fixture 91 · Pinnacle · Away: 39.400% → 50.200% (+10.800 pp, up)
└─ act · refused Yes 10 — would exceed the 35 policy cap (custody held)
──────────────────────────────────────────────────────────────────────────
4 sharp move(s) flagged from 24 reading(s)
3 bet(s) signed within policy · 1 refused (custody held) · staked 30 of the 35 cap · exposure {42: 10.0, 77: 10.0, 88: 10.0}
| Flag | Meaning |
|---|---|
--act |
also show the policy-gated bet the agent would place (custody-capped) |
--threshold PP |
sharp-move threshold in percentage points (default 3.0) |
--live |
poll the real TxLINE feed instead of the recorded market (needs network + credentials) |
--fixture ID |
fixture id to poll in --live mode |
--polls N / --interval SEC |
live poll count and spacing |
--live reads the real odds endpoint over the network (the URL is derived from the checked-in
TxLINE OpenAPI spec, and the request is SSRF-guarded). It needs TxLINE credentials wired into the
feed's auth session; without them the upstream returns an authorization error, surfaced cleanly.
One direction of data, four small stages:
- Feed (
sharpwatch/txline_feed.py) — reads the TxLINE odds endpoint (or a recorded/replay market offline) and produces typedOddsSnapshots. Stdliburllib, SSRF-guarded, with an injectable transport so the live path is falsifiable offline. - Detector (
sharpwatch/detector.py) — the heart. Pure logic over odds snapshots: tracks each line's implied probability and emits aSharpMovewhen it crosses the threshold. No network, no feed dependency, no LLM. - Decision (
sharpwatch/decision.py) — turns aSharpMoveinto aBetIntent: back the direction of the sharp money, sized within aRiskPolicy(per-bet and per-fixture caps). - Wallet (
sharpwatch/wallet.py) — the custody gate. The user authorizes one policy (a spend cap + a purpose allow-list); the wallet signs only within it and refuses anything over the cap or off the list. The agent never holds keys.
The watch CLI (sharpwatch/watch.py) streams stages 1–2 as signals, and layers 3–4 under
--act. The agent loop that runs all four end-to-end lives in sharpwatch/agent.py.
- Signal-first. The detector is the product and is pure and dependency-free; the feed, decision, and wallet are a thin edge around it.
- One code path, two modes. Recorded ($0, offline, deterministic) and live differ only at the transport edge, so the whole thing is falsifiable without a network.
- Custody-safe by construction. The agent describes intent; the wallet holds the keys and the cap. An over-cap bet never produces a signature.
- Self-contained. Standard library only — a test fails the build if any external integration dependency is introduced.
uv run --group dev pytest # test suite
uv run --group dev ruff format # format
uv run --group dev ruff check # lint
uv run --group dev mypy sharpwatch # typesApache-2.0. See LICENSE.