polymarket-scanner
Version, currently main branch1 version
- main branchlatestMay 22, 2026
github.com/krthr/polymarket-scanner
No description declared in shard.yml.
Installation
# Add this to your shard.yml
dependencies:
polymarket-scanner:
github: krthr/polymarket-scanner
branch: mainmain is a branch, not a release, so this tracks it rather than pinning a version.
Then run:
shards installshard.yml
- Crystal
>= 1.20.2- License
- MIT
- Author
- Codex
- Target
poly_scanfrom src/poly_scan.cr
Dependencies
Runtime Dependencies
README
Polymarket Inefficiency Scanner
Private, read-only Crystal scanner for real Polymarket market-relationship analysis.
Safety Defaults
- No real order placement.
- No wallet or private-key configuration.
- No authenticated trading endpoints.
- Dashboard/API binds to
127.0.0.1by default. - Production runtime uses public read-only Polymarket Gamma listings and CLOB books.
- Fixture data is limited to specs and explicitly injected test helpers.
- Trading-critical values use
PolyScan::Fixedfixed-point integer math.
Run
shards install
crystal spec
crystal build src/poly_scan.cr
./poly_scan --config config/app.example.yml --once
./poly_scan --config config/app.example.yml --serve
Then open:
http://127.0.0.1:8765/http://127.0.0.1:8765/api/healthhttp://127.0.0.1:8765/api/opportunitieshttp://127.0.0.1:8765/api/paper-trades
For a smaller real-data probe:
./poly_scan --config config/live.example.yml --serve
Then open http://127.0.0.1:8765/api/markets. The app uses public read-only Gamma market listings for discovery and public CLOB /book?token_id=... responses for executable book data. It does not configure a wallet, private key, auth token, or order-placement endpoint.
Migrations
Database schema changes are managed with Micrate. App startup automatically applies pending migrations from db/migrations before opening the configured SQLite database.
For manual migration work, install the official micrate CLI and pass the SQLite connection with DATABASE_URL:
DATABASE_URL=sqlite3://./data/poly_scan.example.db micrate status
DATABASE_URL=sqlite3://./data/poly_scan.example.db micrate up
DATABASE_URL=sqlite3://./data/poly_scan.example.db micrate down
Configuration
The app loads YAML from --config PATH, or from POLY_SCAN_CONFIG when no --config argument is provided. If neither is set, it uses config/app.example.yml.
Trading-critical decimal values must be quoted strings with up to six decimal places, for example "0.005000". They are parsed into fixed-point integer atoms by PolyScan::Fixed; do not write these values as YAML floats.
Unknown configuration keys are rejected at startup. This applies to both top-level options and nested sections such as http, paper_trading, and telegram.
Top-level options:
| Option | Default | Description |
|---|---|---|
bind_host | "127.0.0.1" | Dashboard/API bind host. Non-loopback binds are rejected unless POLY_SCAN_ALLOW_PUBLIC_BIND=true is set. |
port | 8765 | Dashboard/API TCP port. |
database_path | "data/poly_scan.db" | SQLite database file path. Parent directories are created automatically. |
gamma_base_url | "https://gamma-api.polymarket.com" | Base URL for the read-only Gamma listing client. |
clob_base_url | "https://clob.polymarket.com" | Base URL for the read-only CLOB book client. |
relationships_path | "config/relationships.example.yml" | Manual relationship-rule YAML file. |
market_limit | 25 | Maximum real Polymarket listings to fetch from Gamma market APIs. |
book_limit | 50 | Maximum real CLOB token books to fetch from /book. Binary markets can use two token books each. |
scan_size | "1.000000" | Fixed-point size used for executable VWAP checks and paper-trade legs. Must be positive. |
taker_fee_bps | 0 | Taker fee in basis points. Fee is computed on min(price, 1-price) * size. |
max_book_age_ms | 300000 | Maximum book age before stale-book risk and stale penalties apply. |
max_spread | "0.080000" | Spread threshold for wide-spread risk and SpreadAnomaly signals. |
min_depth | "1.000000" | Minimum ask depth used by spread anomaly checks. |
slippage_buffer | "0.005000" | Fixed-point buffer subtracted from gross edge. |
uncertainty_penalty | "0.003000" | Fixed-point penalty subtracted from gross edge. |
resolution_penalty | "0.002000" | Fixed-point resolution-risk penalty subtracted from gross edge. |
stale_book_penalty | "0.010000" | Fixed-point penalty applied when a book is stale. |
low_confidence_threshold | "0.600000" | Confidence below this threshold adds the low-confidence risk flag. |
high_fee_threshold | "0.010000" | Per-leg fee at or above this threshold adds the high-fees risk flag. |
imbalance_ratio | "3.000000" | Depth ratio threshold for BookImbalance supporting signals. |
HTTP options under http:
| Option | Default | Description |
|---|---|---|
timeout_ms | 5000 | Connect, read, and write timeout for read-only HTTP calls. |
max_retries | 2 | Number of retries after the first HTTP attempt. |
retry_backoff_ms | 250 | Base exponential backoff delay. |
retry_jitter_ms | 125 | Random jitter added to retry backoff. |
rate_limit_per_minute | 60 | Conservative per-client request pacing. Must be positive. |
Paper trading options under paper_trading:
| Option | Default | Description |
|---|---|---|
enabled | true | Creates local paper trades from generated opportunities. This never places real orders. |
Telegram options under telegram:
| Option | Default | Description |
|---|---|---|
enabled | false | Enables the alert scaffold. Current implementation logs readiness/skips and does not send network alerts. |
bot_token_env | unset | Name of the environment variable containing the bot token. The token itself is not stored in YAML. Example configs use "POLY_SCAN_TELEGRAM_BOT_TOKEN". |
chat_id_env | unset | Name of the environment variable containing the chat ID. The chat ID itself is not stored in YAML. Example configs use "POLY_SCAN_TELEGRAM_CHAT_ID". |
Environment overrides:
| Variable | Description |
|---|---|
POLY_SCAN_CONFIG | Config file path used when --config is not provided. |
POLY_SCAN_BIND_HOST | Overrides bind_host. Public binds still require POLY_SCAN_ALLOW_PUBLIC_BIND=true. |
POLY_SCAN_PORT | Overrides port. |
POLY_SCAN_DATABASE_PATH | Overrides database_path. |
POLY_SCAN_RELATIONSHIPS_PATH | Overrides relationships_path. |
POLY_SCAN_MARKET_LIMIT | Overrides market_limit. |
POLY_SCAN_BOOK_LIMIT | Overrides book_limit. |
POLY_SCAN_ALLOW_PUBLIC_BIND | Set to true to permit a non-127.0.0.1 bind. Leave unset for private local use. |
Legacy runtime fixture keys (data_source, gamma_fixture_path, and clob_books_path) are rejected in production config. Parser fixtures remain available to specs.
Example:
POLY_SCAN_DATABASE_PATH=tmp/dev.db \
POLY_SCAN_RELATIONSHIPS_PATH=config/relationships.example.yml \
./poly_scan --config config/app.example.yml --serve
Relationship Rules
Manual relationship rules live in config/relationships.example.yml and support:
implicationmutually_exclusiveexhaustive_groupcomplementcorrelated_group
Production rules must reference token IDs present in the loaded real Polymarket listings. The scanner does not infer exhaustiveness from market titles. Use verified_exhaustive: true only for manually checked exactly-one groups.
Rule fields:
| Field | Required | Applies To | Description |
|---|---|---|---|
id | Yes | All rules | Stable unique rule ID. Used in opportunity IDs and storage. |
type | Yes | All rules | One of the supported relationship types above. |
description | No | All rules | Human-readable note explaining the manual rule source or reasoning. |
from_token_id | Yes | implication | Antecedent YES token. In A implies B, this is A. |
to_token_id | Yes | implication | Consequent YES token. In A implies B, this is B. |
token_ids | Type-dependent | Group rules | YES token IDs for mutually_exclusive, exhaustive_group, complement, and correlated_group. |
confidence | No | All rules | Quoted fixed-point confidence factor. Defaults to "0.500000". |
quality | No | All rules | Quoted fixed-point rule-quality factor. Defaults to "0.500000". |
verified_exhaustive | No | exhaustive_group | Set true only after manual exactly-one verification. Defaults to false. |
Documentation
Built from the current release. The first visit to a release nobody has asked for starts its build.
Links
This branch
- Branch
main- Seen
- May 22, 2026
- Crystal
>= 1.20.2- Indexed
- yes
Dependents
No indexed shard depends on this one yet.
Repository
github.com/krthr/polymarket-scanner
Metadata
- Created
- Aug 12, 2026
- Updated
- Sep 26, 2026
- Synced
- Sep 26, 2026
- Versions
- 1