Open Net Worth
Open Net Worth is an open-source personal AI wealth assistant you run yourself: one ledger for your whole financial life, worked by an AI agent you control.
翻訳待ち
No updates detected yet. GitHub releases will appear here.
The maker's introduction consists of the line above. Read the repository README for more details. Repository README ↗
Loading the full README.
Read the full README ↗Runs automatically every morning. Scans open Polymarket events with a deadline inside a set window and looks for three separate kinds of mispriced positions, then lists them as ticket cards on a static dashboard.
Cost: $0, indefinitely. It runs on GitHub Actions (cron) and GitHub Pages (static hosting). No server to run, nothing to keep awake.
| Tag | What it finds | Riskless? |
|---|---|---|
| ARB | negRisk event groups where buying every mutually exclusive outcome at the current best ask costs less than $1.00 total | Mathematically yes, in practice no (fees, slippage, thin liquidity) |
| CAL | Price buckets where a statistically significant gap exists between price and outcome, measured across resolved markets (Wilson 95% CI, n≥30) | No — a tendency across many repeated positions, not a single-bet guarantee |
| MIS | Markets with ≥$5,000 in 24h volume where price differs from that bucket's historical resolution rate by 10+ points, with the same statistical significance test as CAL (required since Sep 3, 2026) | No |
None of this is investment advice.
GitHub Actions, every morning at 06:00 TR time
└─ scripts/fetch_arbitrage.py → scans the Polymarket Gamma API
├─ writes docs/results.json and commits it to the repo
└─ appends price snapshots to docs/price_log.jsonl (for calibration)
GitHub Actions, every Monday
└─ scripts/calibration_scan.py → checks which logged markets have
since closed, matches them against their real outcome, and
writes docs/calibration.json. Already-resolved markets are cached
in docs/resolution_cache.json so they're never re-checked via the
API again once known
GitHub Actions, every morning, right after fetch_arbitrage.py
└─ scripts/track_bets.py → paper-trades the signals from today's
results.json against a fixed $1,000 bankroll, and checks
whether previously placed bets have resolved, writing
docs/bet_log.json
GitHub Actions, every morning, right after track_bets.py
└─ scripts/check_scan_health.py → tracks scanned_events over time
in docs/scan_health.json and flags anomalies (zero events, a
suspiciously stuck count, or a sudden drop). Files or updates
a GitHub issue labeled scan-health when something looks wrong,
closes it automatically once things recover
GitHub Pages (Actions-based deploy)
└─ docs/index.html reads results.json/calibration.json/price_log.jsonl/
scan_health.json client-side and renders the ledger, filters,
calibration curve, and a signals-found-per-day trend
└─ docs/archive.html reads bet_log.json and renders the paper-trading
track record: bankroll over time, win rate by tag, bet-by-bet ledger
The calculation logic is documented at the top of each script. In short, for ARB: if an event has N mutually exclusive options and buying all of their "Yes" sides at the current best ask sums to under $1.00, it gets listed as a ticket.
CAL and MIS both need docs/calibration.json to exist before they
produce anything, which means the calibration scan has to complete at
least once. Since that scan is forward-looking (it waits for markets
logged today to close weeks later), expect the calibration curve to
stay empty for a while after first setup.
Every ARB/CAL/MIS signal gets a simulated bet, sized to its edge (bigger
edge, bigger stake, capped so no single bet can seriously damage the
bankroll) and drawn from a fixed $1,000 starting bankroll. docs/archive.html
shows the running track record: bankroll over time, win rate broken out
by tag, and every bet with its entry price, stake, and outcome.
ARB is close to a mathematically guaranteed win by construction, so its wins get a small random execution haircut (0-2 points off the edge, simulating real fees/slippage) applied at resolution — otherwise it would just read as a permanent win streak and tell you nothing. The headline win-rate stat on the archive page counts CAL and MIS only, since those are the signals actually worth validating; ARB is tracked separately alongside them. A market that resolves ambiguously or gets cancelled is marked void: the stake is returned and it's excluded from win-rate math.
The headline win rate is shown with a 95% Wilson confidence interval (e.g. "50% [15-85%] (n=4)"), not a bare percentage, so a handful of early bets doesn't read as more conclusive than it is. A "Predicted vs Realized" chart buckets resolved CAL/MIS bets by the win probability predicted at placement time and plots that against how often each bucket actually won — the real test of whether the signals are accurate or just optimistic, separate from whether the bankroll happens to be up. Max drawdown is tracked alongside the bankroll chart.
Because this reuses the same forward-looking pattern as calibration (log now, check back once the deadline passes), the archive fills in slowly and starts empty. It's meant to build an honest record over weeks and months, not simulate results for its own sake.
The scanner used to hit a hard, undocumented pagination ceiling on the
Gamma API (capped at exactly 2,100 events) for 44 consecutive daily
runs before anyone noticed, because a silently truncated result set
doesn't raise an error — it just returns a quietly wrong number, every
day, forever. scripts/check_scan_health.py exists so that failure
mode gets caught in days, not weeks.
It keeps a rolling history of scanned_events in docs/scan_health.json
and flags three patterns after each run: zero events scanned (the scan
produced nothing), a value stuck identically for several runs in a row
(the exact signature of a hard ceiling), or a sudden drop against the
trailing average. Any anomaly gets filed as a GitHub issue labeled
scan-health (or added as a comment if one's already open); the issue
closes itself automatically once a later run comes back healthy.
This is the beginning of the README. Read the rest at the original. Read the full README ↗