尚未检测到更新。GitHub 发布版本后会显示在这里。
个人 GitHub 账号下公开仓库的所有者可以登录并验证所有权,自行管理介绍,无需管理员批准。
登录并生成验证文件,在 30 分钟内将其提交到此仓库的默认分支。其他分支或分叉仓库中的文件无效。然后在下方检查文件,即可无需管理员批准直接管理项目。请保留文件以维持管理权限。
如需登录,将前往登录页面。登录后请回到此处,再次点击所选的验证按钮。
在项目文件夹中运行 /nomorevibe verify,即可验证所有权并自行管理介绍。
一分钟完成验证制作者的介绍仅有上面的一句话。 更多详情请阅读仓库 README。 仓库 README ↗
正在加载完整 README。
查看完整 README ↗Local dashboard that scans upcoming sports games on Polymarket for pricing signals: risk-free arbitrage (both outcomes of a game summing to under $1) and, optionally, mispricing vs. a sportsbook-odds consensus. Read-only — it never holds a private key and never places a trade. Every opportunity links out to the real market on polymarket.com for you to act on manually.
Leagues covered: NFL, NBA, MLB, NHL, CFB, CBB.
pip install -r requirements.txt
python3 app.py
Copy .env.example to .env and set ODDS_API_KEY (free tier at
https://the-odds-api.com). Without it, the arbitrage scanner still works —
only the "value vs. sportsbooks" panel is disabled.
A separate panel from the one below — polymarket.us is a different product/backend from
the original Polymarket, with no shared wallet or address space, so it needed its own
integration. Set these in .env (generate/rotate at polymarket.us/developer, never paste
the values anywhere but .env):
POLYMARKET_KEY_ID=
POLYMARKET_SECRET_KEY=
us_api.py talks to api.polymarket.us directly over plain requests with Ed25519-signed
headers (see docs.polymarket.us/api-reference/authentication) — no third-party SDK dependency,
just the well-established cryptography package (pip install cryptography in the venv).
The panel stays hidden until both env vars are set.
Paste your public Polymarket wallet address (not a private key — this is public on-chain data, the same thing anyone can look up from your profile) into the "Your positions & P/L" box. Nothing else to connect — no OAuth, no API key, no wallet signer. The address is only ever stored in your own browser's localStorage; the server never persists it.
This shows:
First load for an active account can take a few seconds (it pages through up to 3,000 activity entries); results are cached 5 minutes so reloading right after is instant.
app.py), buying one share of every outcome locks in a
$1.00 payout for less than $1.00 — a risk-free edge before Polymarket's
trading fees and gas. Fees aren't netted out here, so treat small edges
as a flag to double-check manually, not a guaranteed profit.None of these signals are investment advice — they're mechanical calculations you should sanity-check (injuries, bullpen/rotation news, liquidity, fees) before betting, and no formula here is tuned or proven to maximize returns.
Three independent simulated $100 bankrolls — underdogs (only "Smart
underdog" signals), locks (only "Lock" signals), and combined (both
signal types, with stake sizing that learns from this account's own
settled history — see below) — that automatically bet on this app's own
signals, settle each bet against the real Polymarket market resolution,
and report P/L plus a calibration table: for bets the model called
"80-90% confidence," did they actually win 80-90% of the time? That's the
real test of whether the confidence percentages mean anything. No real
money, no real orders — purely reading public market data.
When more eligible signals exist than an account can act on (the per-league
pending cap), the games that actually get bet on are the ones starting
soonest (paper_trading._soonest_first) — results come back fast instead
of sitting on far-future games.
How combined and locks learn from losses: every account already
pauses a (signal_type, league) segment outright once it's lost money
across 10+ of its own settled bets (_segment_performance's paused
flag — a real pattern, not one bad beat). combined's stake, and
locks's pregame stake, go further: below that pause threshold, stake
for a segment scales continuously with that segment's own win rate so far
(_adaptive_stake) — a segment that's been winning gets up to 1.75x the
flat stake, one that's been losing gets as low as 0.4x, before ever
reaching the hard pause. underdogs stays flat-staked on purpose, as a
control the other two are actually being compared against.
locks's live dip-buying: a lock-caliber team is still bet
immediately when it first qualifies pregame, at the learned adaptive
size above — unchanged default behavior. But once a game goes live,
locks holds off and only bets once the price has dropped at least 3
cents (LOCKS_LIVE_DIP_THRESHOLD) from the earliest price ever observed
for that exact outcome (update_price_watch/_locks_live_entry_gate) —
the same team, cheaper than it opened, for a better payout at the same
win probability. That live dip entry is deliberately a flat $5
(_locks_stake), not the learned size — a more conservative, opportunistic
bet, kept separate from the pregame "base bet." A lightweight price-watch
cache (data/locks_price_watch.json locally,
polymarket-bet-calculator:locks_price_watch on Redis) tracks the
earliest price for every outcome in every paper-trading-league game, not
just ones that are already locks, so there's a real "before" price to
compare against even for a team that only becomes a lock once live.
underdogs and combined are unaffected — they still bet the moment a
signal qualifies, live or not.
Runs two ways: while the app is open (page polls /api/paper every
30s), and independently via a scheduled GitHub Actions workflow
(.github/workflows/paper-trading-cron.yml, runs every 5 minutes — GitHub's
shortest supported interval) so it keeps advancing even with the laptop
closed or off — both paths call the exact same paper_trading.run_all_strategies,
are idempotent, and write to the same state files, so it's safe for both to
run at once.
To turn on the scheduled run: push this repo to GitHub, then add these as
encrypted repo secrets (Settings → Secrets and variables → Actions → New
repository secret) with the same values as your local .env:
POLYMARKET_KEY_IDPOLYMARKET_SECRET_KEYODDS_API_KEY (optional — only if you have one)This repo is public (deliberately, per Connor's own choice): GitHub Actions minutes are unlimited/free on public repos at any frequency, unlike a private repo's ~2,000 min/month free tier, which 5-minute cadence would blow through fast (every run is a genuinely cold scan, no warm cache carries over between runs — real compute, not a cheap no-op). Nothing secret has ever lived in this repo's history (verified before flipping visibility) — real credentials only ever exist as GitHub/Vercel encrypted env vars, never committed. You can also trigger a run manually anytime from the repo's Actions tab ("Run workflow") instead of waiting.
The three accounts (see paper_trading.py's STRATEGIES) run side by
side. Bets are placed from an all-leagues scan (independent of whatever
league filter you have checked in the UI), then filtered down to
paper_trading.PAPER_TRADING_LEAGUES (NFL/CFB/NBA/CBB — Connor's own
predominant sports) before any paper-trading signal is derived — the rest
of the app (Smart bets, Games grid, etc.) still covers every league; only
new paper-trading placements are scoped narrower. Existing pending bets
already placed in other leagues before this scoping aren't cancelled, they
just settle out normally over time. State lives in
data/paper_trades_<strategy_id>.json; delete one (and its matching
polymarket-bet-calculator:paper_trades:<strategy_id> Redis key, if
deployed) to reset that account's bankroll back to $100.
Not deployed yet by default — this runs the real .us API scan which is
too expensive (hundreds of games, ~50s cold) to recompute on every page
load on a serverless host, so deploying isn't just "point Vercel at it"
like the sibling apps. The architecture: the GitHub Actions cron
(.github/workflows/paper-trading-cron.yml, running every 5 minutes — see
above) does the expensive scan and writes the result plus paper-trading
state to Upstash Redis; the deployed dashboard only ever reads that
cache (fast, well inside a serverless function's time limit) rather than
recomputing it. This means the deployed dashboard is only as fresh as
the last cron run — up to ~5 minutes behind, not truly
live/second-by-second like running it locally, but close. The "Live
tracker" and "Smart" sections will feel slightly less real-time once
deployed; that's the actual tradeoff of making this reachable without your
computer on, not a bug.
To set it up:
UPSTASH_REDIS_REST_URL / UPSTASH_REDIS_REST_TOKEN as secrets on
this GitHub repo (Settings → Secrets and variables → Actions) — reusing
the same free Upstash database as portfolio-dashboard/
financial-growth-analyzer is fine, this project namespaces its own
keys under polymarket-bet-calculator:. The next cron run (or a manual
"Run workflow" from the Actions tab) starts populating the cache.vercel.json, no
config needed) — same altos team as the other apps keeps billing/auth
in one place, but any account works.POLYMARKET_KEY_ID/POLYMARKET_SECRET_KEY are
only needed there too if you want the "My account" panel to work on the
deployed version — paper trading itself never needs them.portfolio-dashboard's README).If the Upstash env vars aren't set, both the local app and
paper_trade_cron.py fall back to local data/*.json files exactly as
before — nothing about local-only usage changes.
polymarket.py — Gamma API for game schedule/metadata, CLOB /books
(batched) for live best bid/ask per outcome, data-api for positions.oddsapi.py — The Odds API client + no-vig probability math.stats.py — ESPN public API client (teams/schedule/scoreboard), the
log5 + scoring-margin confidence model, and the live win-probability
heuristic.confidence.py — wires stats.py into each game row: pregame model
confidence, live estimate, and the underdog-value signal.matcher.py — fuzzy team-name + time-window matching between Polymarket
and the odds-API data (separate from stats.py's own ESPN team matching).performance.py — reconstructs the realized-P/L time series from a
wallet's Polymarket activity feed (trades, redemptions, rebates).paper_trading.py — three independent simulated bankrolls (STRATEGIES),
each placing/settling/reporting on the underdog/lock signals under its own
rules. polymarket.fetch_event_resolution reads the real winner once
Polymarket closes a market.store.py — Redis-or-local-file persistence, shared by paper_trading.py
(bankroll state) and app.py (cached scan results) — see "Deploy" above.paper_trade_cron.py — standalone entrypoint (no Flask) for the scheduled
job: one scan + paper-trading cycle, no HTTP request involved.app.py — Flask routes (/api/scan, /api/positions, /api/paper) +
dashboard.Port 5007, registered in ~/Downloads/.claude/launch.json as
polymarket-bet-calculator.