nothing-ever-happens-polymarket-bot
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseNothing Ever Happens Polymarket Bot
无事件发生Polymarket机器人
Skill by ara.so — Daily 2026 Skills collection.
An async Python bot that scans Polymarket standalone non-sports yes/no markets and buys the "No" outcome on any market where the NO price is below a configured cap. Designed for paper trading by default with explicit opt-in to live order transmission.
由ara.so开发的Skill — 属于Daily 2026 Skills合集。
一款异步Python机器人,可扫描Polymarket平台上的独立非体育类是/否市场,当“否”选项的价格低于配置上限时买入该选项。默认采用模拟交易模式,需明确开启才能进行实盘订单传输。
What It Does
功能介绍
- Scans Polymarket for standalone (non-grouped) yes/no markets
- Filters out sports markets
- Buys NO positions when NO price is below threshold
max_no_price - Tracks open positions and persists recovery state to a database
- Exposes a live dashboard (HTTP) showing portfolio and activity
- Uses unless all three live-mode env vars are set
PaperExchangeClient
- 扫描Polymarket平台上的独立(非分组)是/否市场
- 过滤掉体育类市场
- 当“否”选项价格低于阈值时买入该头寸
max_no_price - 跟踪未平仓头寸,并将恢复状态持久化到数据库
- 提供实时仪表盘(HTTP)展示投资组合和交易活动
- 除非设置了全部三个实盘模式环境变量,否则默认使用
PaperExchangeClient
Installation
安装步骤
bash
git clone https://github.com/sterlingcrispin/nothing-ever-happens.git
cd nothing-ever-happens
pip install -r requirements.txt
cp config.example.json config.json
cp .env.example .envbash
git clone https://github.com/sterlingcrispin/nothing-ever-happens.git
cd nothing-ever-happens
pip install -r requirements.txt
cp config.example.json config.json
cp .env.example .envConfiguration
配置说明
config.json
(non-secret runtime settings)
config.jsonconfig.json
(非机密运行时设置)
config.jsonEdit the block:
strategies.nothing_happensjson
{
"strategies": {
"nothing_happens": {
"max_no_price": 0.08,
"order_size_usdc": 1.0,
"max_open_positions": 50,
"scan_interval_seconds": 60,
"min_liquidity_usdc": 100,
"exclude_keywords": ["sport", "nfl", "nba", "mlb", "nhl", "soccer", "tennis"]
}
}
}Point to a different config file:
bash
CONFIG_PATH=/path/to/other_config.json python -m bot.main编辑区块:
strategies.nothing_happensjson
{
"strategies": {
"nothing_happens": {
"max_no_price": 0.08,
"order_size_usdc": 1.0,
"max_open_positions": 50,
"scan_interval_seconds": 60,
"min_liquidity_usdc": 100,
"exclude_keywords": ["sport", "nfl", "nba", "mlb", "nhl", "soccer", "tennis"]
}
}
}指定其他配置文件:
bash
CONFIG_PATH=/path/to/other_config.json python -m bot.main.env
(secrets and runtime flags)
.env.env
(机密信息与运行时标志)
.envdotenv
undefineddotenv
undefinedSafety flags — ALL three required for live order transmission
安全标志 — 全部三个都设置才能进行实盘订单传输
BOT_MODE=paper # set to "live" for real orders
DRY_RUN=true # set to "false" for real orders
LIVE_TRADING_ENABLED=false # set to "true" for real orders
BOT_MODE=paper # 设置为"live"以启用实盘交易
DRY_RUN=true # 设置为"false"以启用实盘交易
LIVE_TRADING_ENABLED=false # 设置为"true"以启用实盘交易
Required only in live mode
仅实盘模式下需要
PRIVATE_KEY=$PRIVATE_KEY
FUNDER_ADDRESS=$FUNDER_ADDRESS
DATABASE_URL=$DATABASE_URL
POLYGON_RPC_URL=$POLYGON_RPC_URL
PRIVATE_KEY=$PRIVATE_KEY
FUNDER_ADDRESS=$FUNDER_ADDRESS
DATABASE_URL=$DATABASE_URL
POLYGON_RPC_URL=$POLYGON_RPC_URL
Optional
可选配置
PORT=8080
DASHBOARD_PORT=8080
> **Never hardcode secrets.** Always use environment variable references.
---PORT=8080
DASHBOARD_PORT=8080
> **切勿硬编码机密信息**,始终使用环境变量引用。
---Running Locally
本地运行
bash
undefinedbash
undefinedPaper trading (default — safe, no real orders)
模拟交易(默认模式 — 安全,无真实订单)
python -m bot.main
python -m bot.main
Enable live trading (requires all three flags)
启用实盘交易(需设置全部三个标志)
BOT_MODE=live DRY_RUN=false LIVE_TRADING_ENABLED=true python -m bot.main
The dashboard will bind to `$PORT` or `$DASHBOARD_PORT` when set.
---BOT_MODE=live DRY_RUN=false LIVE_TRADING_ENABLED=true python -m bot.main
仪表盘将绑定到`$PORT`或`$DASHBOARD_PORT`(若已设置)。
---Project Structure
项目结构
bot/
main.py # Entry point — starts the runtime loop
strategies/
nothing_happens.py # Core strategy: scan, filter, buy NO
exchange/
client.py # Live exchange client (Polymarket CLOB API)
paper_client.py # PaperExchangeClient for safe simulation
dashboard.py # HTTP dashboard server
recovery.py # Persist and restore open positions
scripts/
db_stats.py # Inspect DB table counts and recent activity
export_db.py # Export live DB tables
wallet_history.py # Positions, trades, balances for configured wallet
parse_logs.py # Convert Heroku JSON logs to readable output
tests/ # Unit and regression testsbot/
main.py # 入口文件 — 启动运行循环
strategies/
nothing_happens.py # 核心策略:扫描、过滤、买入“否”选项
exchange/
client.py # 实盘交易所客户端(Polymarket CLOB API)
paper_client.py # PaperExchangeClient用于安全模拟交易
dashboard.py # HTTP仪表盘服务器
recovery.py # 持久化和恢复未平仓头寸
scripts/
db_stats.py # 查看数据库表计数和近期活动
export_db.py # 导出实盘数据库表
wallet_history.py # 查看配置钱包的头寸、交易和余额
parse_logs.py # 将Heroku JSON日志转换为可读格式
tests/ # 单元测试和回归测试Key Commands
关键命令
Run Tests
运行测试
bash
python -m pytest -qbash
python -m pytest -qOperational Scripts
运维脚本
bash
undefinedbash
undefinedInspect live database
查看实盘数据库
python scripts/db_stats.py
python scripts/db_stats.py
Export database tables (uses DATABASE_URL or Heroku app)
导出数据库表(使用DATABASE_URL或Heroku应用)
python scripts/export_db.py
python scripts/export_db.py
Pull wallet history
获取钱包历史记录
python scripts/wallet_history.py
python scripts/wallet_history.py
Parse Heroku JSON logs into readable output
将Heroku JSON日志解析为可读格式
python scripts/parse_logs.py
---python scripts/parse_logs.py
---Heroku Deployment
Heroku部署
One-time setup
一次性设置
bash
export HEROKU_APP_NAME=my-polymarket-botbash
export HEROKU_APP_NAME=my-polymarket-botSet runtime flags
设置运行时标志
heroku config:set BOT_MODE=live DRY_RUN=false LIVE_TRADING_ENABLED=true
-a "$HEROKU_APP_NAME"
-a "$HEROKU_APP_NAME"
heroku config:set BOT_MODE=live DRY_RUN=false LIVE_TRADING_ENABLED=true
-a "$HEROKU_APP_NAME"
-a "$HEROKU_APP_NAME"
Set secrets
设置机密信息
heroku config:set
PRIVATE_KEY="$PRIVATE_KEY"
FUNDER_ADDRESS="$FUNDER_ADDRESS"
POLYGON_RPC_URL="$POLYGON_RPC_URL"
DATABASE_URL="$DATABASE_URL"
-a "$HEROKU_APP_NAME"
PRIVATE_KEY="$PRIVATE_KEY"
FUNDER_ADDRESS="$FUNDER_ADDRESS"
POLYGON_RPC_URL="$POLYGON_RPC_URL"
DATABASE_URL="$DATABASE_URL"
-a "$HEROKU_APP_NAME"
heroku config:set
PRIVATE_KEY="$PRIVATE_KEY"
FUNDER_ADDRESS="$FUNDER_ADDRESS"
POLYGON_RPC_URL="$POLYGON_RPC_URL"
DATABASE_URL="$DATABASE_URL"
-a "$HEROKU_APP_NAME"
PRIVATE_KEY="$PRIVATE_KEY"
FUNDER_ADDRESS="$FUNDER_ADDRESS"
POLYGON_RPC_URL="$POLYGON_RPC_URL"
DATABASE_URL="$DATABASE_URL"
-a "$HEROKU_APP_NAME"
Deploy
部署
git push heroku main:main
git push heroku main:main
Scale — ONLY the web dyno
调整实例数 — 仅运行web dyno
heroku ps:scale web=1 worker=0 -a "$HEROKU_APP_NAME"
> Do **not** run the `worker` dyno. It exists only to fail fast if started accidentally.heroku ps:scale web=1 worker=0 -a "$HEROKU_APP_NAME"
> 请勿运行`worker` dyno,它仅用于在意外启动时快速失败。Shell helpers
Shell辅助脚本
bash
./alive.sh # Check if the app is alive
./logs.sh # Tail logs
./live_enabled.sh # Enable live trading
./live_disabled.sh # Disable live trading (back to paper)
./kill.sh # Stop the botAll helpers use or accept an app name as an argument:
$HEROKU_APP_NAMEbash
./logs.sh my-polymarket-botbash
./alive.sh # 检查应用是否运行
./logs.sh # 查看实时日志
./live_enabled.sh # 启用实盘交易
./live_disabled.sh # 禁用实盘交易(切换回模拟模式)
./kill.sh # 停止机器人所有辅助脚本使用,或接受应用名称作为参数:
$HEROKU_APP_NAMEbash
./logs.sh my-polymarket-botSafety Model
安全模型
The bot defaults to (simulated orders, no real money) unless all three of these are set:
PaperExchangeClient| Variable | Required value |
|---|---|
| |
| |
| |
If any one is missing or wrong, paper mode is used. This is intentional — it makes accidental live trading very hard.
Additional live-mode requirements:
- — wallet private key
PRIVATE_KEY - — required for signature types
FUNDER_ADDRESSand12 - — for recovery state persistence
DATABASE_URL - — for proxy-wallet approvals and redemption
POLYGON_RPC_URL
机器人默认使用(模拟订单,无真实资金),除非同时设置以下全部三个变量:
PaperExchangeClient| 变量 | 必填值 |
|---|---|
| |
| |
| |
若任一变量缺失或设置错误,将使用模拟模式。这是有意设计的,可大幅降低意外实盘交易的风险。
实盘模式额外要求:
- — 钱包私钥
PRIVATE_KEY - — 签名类型
FUNDER_ADDRESS和1所需2 - — 用于持久化恢复状态
DATABASE_URL - — 用于代理钱包授权和赎回
POLYGON_RPC_URL
Code Examples
代码示例
Check if bot will use live or paper mode
检查机器人将使用实盘还是模拟模式
python
import os
def is_live_mode() -> bool:
return (
os.getenv("BOT_MODE") == "live"
and os.getenv("LIVE_TRADING_ENABLED", "").lower() == "true"
and os.getenv("DRY_RUN", "true").lower() == "false"
)
print("Live mode:", is_live_mode())python
import os
def is_live_mode() -> bool:
return (
os.getenv("BOT_MODE") == "live"
and os.getenv("LIVE_TRADING_ENABLED", "").lower() == "true"
and os.getenv("DRY_RUN", "true").lower() == "false"
)
print("Live mode:", is_live_mode())Load strategy config
加载策略配置
python
import json, os
config_path = os.getenv("CONFIG_PATH", "config.json")
with open(config_path) as f:
config = json.load(f)
strategy_cfg = config["strategies"]["nothing_happens"]
max_no_price = strategy_cfg["max_no_price"] # e.g. 0.08
order_size = strategy_cfg["order_size_usdc"] # e.g. 1.0
print(f"Will buy NO when price <= {max_no_price} USDC, size={order_size} USDC")python
import json, os
config_path = os.getenv("CONFIG_PATH", "config.json")
with open(config_path) as f:
config = json.load(f)
strategy_cfg = config["strategies"]["nothing_happens"]
max_no_price = strategy_cfg["max_no_price"] # 示例:0.08
order_size = strategy_cfg["order_size_usdc"] # 示例:1.0
print(f"当价格 <= {max_no_price} USDC时买入‘否’选项,订单规模={order_size} USDC")Run the bot programmatically
以编程方式运行机器人
python
import asyncio
from bot.main import main
asyncio.run(main())python
import asyncio
from bot.main import main
asyncio.run(main())Inspect DB stats
查看数据库统计信息
bash
DATABASE_URL=$DATABASE_URL python scripts/db_stats.pybash
DATABASE_URL=$DATABASE_URL python scripts/db_stats.pyParse Heroku logs to HTML
将Heroku日志解析为HTML格式
bash
heroku logs --num=1500 -a "$HEROKU_APP_NAME" | python scripts/parse_logs.py --html > report.htmlbash
heroku logs --num=1500 -a "$HEROKU_APP_NAME" | python scripts/parse_logs.py --html > report.htmlExport DB from a Heroku app
从Heroku应用导出数据库
bash
python scripts/export_db.py --app "$HEROKU_APP_NAME"bash
python scripts/export_db.py --app "$HEROKU_APP_NAME"Common Patterns
常见模式
Disabling live trading quickly (kill switch)
快速禁用实盘交易(紧急开关)
bash
heroku config:set LIVE_TRADING_ENABLED=false -a "$HEROKU_APP_NAME"bash
heroku config:set LIVE_TRADING_ENABLED=false -a "$HEROKU_APP_NAME"or use the helper:
或使用辅助脚本:
./live_disabled.sh
The bot will immediately fall back to paper mode on next cycle without a restart../live_disabled.sh
机器人将在下一个循环中立即切换回模拟模式,无需重启。Adjusting the NO price cap without redeploying
无需重新部署即可调整“否”选项价格上限
Edit , commit, and push:
config.jsonbash
undefined编辑,提交并推送:
config.jsonbash
undefinedLower the cap to only buy very cheap NOs
降低上限,仅买入价格极低的“否”选项
jq '.strategies.nothing_happens.max_no_price = 0.05' config.json > tmp.json && mv tmp.json config.json
git add config.json && git commit -m "lower max_no_price to 0.05"
git push heroku main:main
undefinedjq '.strategies.nothing_happens.max_no_price = 0.05' config.json > tmp.json && mv tmp.json config.json
git add config.json && git commit -m "lower max_no_price to 0.05"
git push heroku main:main
undefinedAdding more keyword exclusions
添加更多排除关键词
json
{
"strategies": {
"nothing_happens": {
"exclude_keywords": ["sport", "nfl", "nba", "mlb", "nhl", "soccer", "tennis", "golf", "ufc", "esport"]
}
}
}json
{
"strategies": {
"nothing_happens": {
"exclude_keywords": ["sport", "nfl", "nba", "mlb", "nhl", "soccer", "tennis", "golf", "ufc", "esport"]
}
}
}Troubleshooting
故障排查
| Symptom | Likely Cause | Fix |
|---|---|---|
| Bot uses paper mode unexpectedly | One of the three live flags is missing/wrong | Check all three: |
| Postgres not provisioned | |
| Orders never transmit | | |
| Dashboard not accessible | | |
| Worker dyno crashes immediately | Don't run worker dyno | |
| Bot buys sports markets | Keywords not in | Add sport/league names to config |
| Logs unreadable (JSON) | Heroku structured logging | Pipe through |
| 症状 | 可能原因 | 解决方法 |
|---|---|---|
| 机器人意外使用模拟模式 | 三个实盘标志中有一个缺失或设置错误 | 检查全部三个标志: |
实盘模式下出现 | 未配置Postgres | |
| 订单始终无法传输 | | |
| 仪表盘无法访问 | 未设置 | |
| Worker dyno立即崩溃 | 请勿运行worker dyno | |
| 机器人买入体育类市场 | 排除关键词列表中缺少相关词汇 | 将体育/联赛名称添加到配置中 |
| 日志不可读(JSON格式) | Heroku使用结构化日志 | 通过 |
Disclaimer
免责声明
FOR ENTERTAINMENT ONLY. PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED. USE AT YOUR OWN RISK. NOT FINANCIAL ADVICE.
仅供娱乐使用。按“原样”提供,不提供任何明示或暗示的担保。风险自负。非财务建议。