OptionsBot Index

How we score

Every listed repo gets up to 100 points for public repo hygiene. The rubric, the scoring code and every pattern it uses are open source. Rubric version 1.1.

Hygiene, not performance. A grade says how well a repo is maintained and documented, and whether it has guardrails. It does not say a bot is profitable, safe, secure or suitable for you. We never look at returns, backtests, win rates, stars, sponsors or who wrote the code. Never inputs: stars, returns, backtests, win rates, sponsor status, author identity.

The 100 points

FactorMaxHow points are earned
Risk limits and kill switch2010 for position, loss or exposure limits in code or config (5 if only documented). 10 for a kill switch, trading-enabled flag, circuit breaker or human-approval gate in code or config (5 if only documented).
License1515 for an OSI-approved SPDX license. 7 for a custom or unrecognized license file. 0 for no license.
Last commit on default branch1515 within 30 days, 12 within 90, 8 within 180, 4 within 365, 0 older.
Tests1510 for at least 3 real test cases in test files (5 for 1 or 2). 5 more if a GitHub Actions workflow runs the tests.
Paper or dry-run mode158 if the README or docs describe paper, sandbox or dry-run use. 7 if code or config exposes a paper, sandbox or dry-run switch.
README quality10Install steps 2, config or env vars 2, what it does or its strategy 1, risk disclaimer 2, length over 1,500 characters 3 (500 to 1,500 characters 1).
Broker detection106 if a broker SDK or API host is found in dependency files or code. 4 if the README names the broker.

Grades and caps

A: 85 or more. B: 70. C: 55. D: 40. F: below 40.

Not applicable factors

Reviewed or automated

Scoring is automated, and automated scoring is noisy. Keyword matching finds a "max loss" in a comment or an example file as easily as in real code. So every seed repo was also read by a reviewer, and the review is shown next to the grade.

Honest limits: reviews are done by Grok Bot reading code and docs. Nothing is executed or tested, and a review is not a human audit or a security audit. A review is tied to the automated points it saw. If the automated evidence changes later, the review is marked out of date and the automated grade is shown until it is checked again. Reviewer notes sit in data/reviews in the repo.

Run it yourself

git clone https://github.com/tazopicus-cmyk/optionsbot-index.git
cd optionsbot-index && npm ci
npm run score -- owner/repo        # scores any public repo
npm test                           # scorer unit tests

The nightly refresh is a GitHub Action that uses only the built-in GITHUB_TOKEN. It reads public repo metadata and a shallow clone. It never reads sponsor data.

Patterns, verbatim

These regular expressions are copied from scorer/lib/patterns.mjs at build time. Comment-only lines are blanked before matching. Test files, docs, .github, vendor and build folders, lockfiles and files over 250 KB are skipped for code checks. Patterns use word boundaries so, for example, the word "future" can never match the broker Moomoo (whose SDK is called futu).

Risk limits (10 points)
max position\bmax(imum)?[_ -]?(open[_ -]?)?positions?\b
max loss\bmax(imum)?[_ -]?(daily[_ -]?|weekly[_ -]?|trade[_ -]?)?loss\w*
max drawdown\bmax(imum)?[_ -]?draw[_ -]?down\b|\bmax_dd\b
max contracts\bmax(imum)?[_ -]?contracts?\b(?![_ -]?dte)
max notional or exposure\bmax(imum)?[_ -]?(aggregate[_ -]|total[_ -]|open[_ -]|portfolio[_ -])?(notional|exposure|allocation|capital|margin|risk)\w*
max orders\bmax(imum)?[_ -]?(orders?|trades?)([_ -]?per[_ -]?\w+)?\b
daily loss limit\b(daily|weekly|portfolio)[_ -]?(loss|risk|drawdown)[_ -]?(limit|cap|max|stop)\w*
position limit\bposition[_ -]?(limits?|size[_ -]?limit|sizing)\b
risk limit\brisk[_ -]?(limits?|per[_ -]?trade|budget|cap|percent|pct)\b
stop loss\bstop[_ -]?loss\b
buying power cap\bbuying[_ -]?power[_ -]?(usage|limit|pct|percent|cap|reserve|ratio)\b|\bmargin[_ -]?(usage|limit|cap)\b
Kill switch, enable flag, circuit breaker, approval gate (10 points)
kill switch\bkill[_ -]?switch\b
emergency stop\bemergency[_ -]?(stop|shutdown|halt|exit)\b
circuit breaker\bcircuit[_ -]?breaker\b
trading enabled flag\btrading[_ -]?(enabled|disabled|halted|paused)\b|\b(enable|disable|allow)[_ -]?trading\b|\bTRADING_ENABLED\b|\bENABLE_TRADING\b|\bALLOW_TRADING\b
halt or pause\b(halt|pause)[_ -]?(trading|all|new|orders)\b
human approval\bhuman[_ -]?(in[_ -]the[_ -]loop|approval)\b|\b(require[sd]?|needs?)[_ -]?(manual[_ -]?|human[_ -]?|user[_ -]?)?(approval|confirmation)\b|\bapproval[_ -]required\b|\bmanual[_ -]approval\b|\bconfirm(ation)?[_ -]before\b|\bawait(s|ing)? (human |user )?approval\b
read-only mode\bread[_ -]?only[_ -]?mode\b|\bREAD_ONLY\b
Paper mode, documented (8 points)
README or docs\bpaper[ -](trading|account|accounts|mode|trade|trades|money|api|endpoint|environment|port|keys?)\b|\balpaca paper\b|\bdry[- ]?runs?\b|\bsandbox\b|\bsimulation mode\b|\bsimulated (orders|trading|mode)\b|--paper\b|\b\w*PAPER\w*\s*=|\bpaper\s*(=|:)\s*(true|false)\b|\bpaper (or|and|vs\.?) live\b|\blive (or|and) paper\b
Paper mode, in code or config (7 points)
dry-run flag\bdry[_-]?run\b|\bDRY_RUN\b|\bDryRun\b
paper-mode flag\bpaper[_-]?(trading|mode|account|trade|only|api)\b|\bis_paper\b|\bALPACA_PAPER\b|\bPAPER_TRADING\b|\bpaper\s*[=:]\s*(True|False|true|false)\b|["']paper["']\s*:
paper endpoint\bpaper-api\.alpaca\.markets\b|\bcert\.tastyworks\.com\b|\bapi\.cert\.tastyworks\b|\bsandbox\.tradier\.com\b
IBKR paper port\bport\W{0,8}(7497|4002)\b|\b(7497|4002)\b.{0,20}\bpaper\b|\bpaper\b.{0,20}\b(7497|4002)\b
sandbox flag\bsandbox\b|\bis_test\s*=\s*True\b|\bsimulat(e|ion)[_-]mode\b
Tests
Test file path(^|\/)(tests?|__tests__|spec|specs)\/|(^|\/)test_[^/]+\.py$|_test\.(py|go)$|\.(test|spec)\.(js|mjs|cjs|ts|tsx|jsx)$
Test case\bdef test_\w+|\b(it|test)\s*\(\s*['"`]|\bfunc Test\w+\(|#\[test\]|@Test\b|\bclass Test\w+|\bdescribe\s*\(
CI runs tests\b(pytest|python -m pytest|python -m unittest|unittest discover|npm (run )?test|npm t\b|pnpm (run )?test|yarn test|bun test|go test|cargo test|vitest|jest|tox\b|nox\b|make test|uv run pytest|mvn test|gradle test|ctest)\b
README checks
install\b(pip install|pip3 install|uv (sync|pip|add|run)|poetry install|npm (install|i)\b|pnpm (install|add)|yarn (add|install)|npx |bunx |docker (run|compose|build)|go install|cargo (install|build|run)|git clone|brew install|conda (install|env))\b|^#+\s*(install|installation|setup|getting started|quick ?start)\b
config\.env\b|environment variables?|\bconfig(uration)?[ _-]?(file|options)\b|\bconfig\.(ya?ml|toml|json|ini)\b|\b[A-Z][A-Z0-9]+_(KEY|SECRET|TOKEN|ID)\b|^#+\s*(config|configuration|settings|environment)\b
strategy\b(strateg(y|ies)|iron condors?|wheel|covered calls?|credit spreads?|cash[- ]secured puts?|straddles?|strangles?|calendar spreads?|0dte|vertical spreads?|theta|volatility)\b
toolsSection^#+\s*(tools|features|usage|available tools|what it does|how it works|overview)\b
disclaimer\bdisclaimer\b|\bnot (financial|investment|trading|tax) advice\b|\brisk of loss\b|\bat your own risk\b|\beducational (purposes|use|only)\b|\bsubstantial risk\b|\bno warranty\b|\bcan lose\b|\bfinancial risk\b|\bnot (a )?recommendation\b
Broker detection (word-bounded)
BrokerDependency filesCodeREADME
Alpaca\balpaca[-_]py\b|\balpaca[-_]trade[-_]api\b|@alpacahq\/|\balpaca[-_]mcp[-_]server\b|\balpaca[-_]trade\b^\s*(from|import)\s+alpaca\b|\balpaca\.markets\b|@alpacahq\/|require\(['"]@alpacahq\balpaca\b
tastytrade\btastytrade\b|\btastyworks\b^\s*(from|import)\s+tastytrade\b|\btastyworks\.com\b|\btastytrade\.com\b\btasty(trade|works)\b
Interactive Brokers\bib[-_]insync\b|\bib[-_]async\b|\bibapi\b|@stoqey\/ib\b|\bib_gateway\b^\s*(from|import)\s+(ib_insync|ib_async|ibapi)\b|\bclientportal\b|require\(['"]@stoqey\/ib\binteractive brokers\b|\bibkr\b|\bIB Gateway\b|\bTWS\b|\bib_insync\b|\bib_async\b
Charles Schwab\bschwab[-_]py\b|\bschwabdev\b|\bschwab[-_]api\b^\s*(from|import)\s+(schwab|schwabdev)\b|\bapi\.schwabapi\.com\b|\bschwabdev\b\bschwab\b|\bthinkorswim\b
Tradier\btradier\b\btradier\.com\b|\bapi\.tradier\b\btradier\b
Robinhood\brobin[-_]stocks\b|\brobinhood\b^\s*(from|import)\s+robin_stocks\b|\brobinhood\.com\b\brobinhood\b
Derive\bderive[-_]action[-_]signing\b|\bderive[-_]client\b\bapi\.lyra\.finance\b|\bderive\.xyz\b|\bderive_client\b\bderive\.xyz\b|\bderive_client\b|\blyra\.finance\b
Moomoo\bmoomoo[-_]api\b|\bfutu[-_]api\b^\s*(from|import)\s+(moomoo|futu)\b\bmoomoo\b|\bfutu\b|\bfutunn\b
Webull\bwebull\b\bwebull\.com\b|^\s*(from|import)\s+webull\b\bwebull\b
TradeStation\btradestation\b\bapi\.tradestation\.com\b\btradestation\b
E*TRADE\bpyetrade\b\bapi\.etrade\.com\b\be\*?trade\b
Deribit\bderibit\b\bderibit\.com\b\bderibit\b
License detection

OSI-approved SPDX ids that earn 15 points: MIT, Apache-2.0, GPL-2.0, GPL-3.0, LGPL-2.1, LGPL-3.0, AGPL-3.0, BSD-2-Clause, BSD-3-Clause, ISC, MPL-2.0, Unlicense, 0BSD, Zlib, EPL-2.0, BSL-1.0, CC0-1.0, GPL-2.0-only, GPL-3.0-only, GPL-2.0-or-later, GPL-3.0-or-later, AGPL-3.0-only, AGPL-3.0-or-later, LGPL-2.1-only, LGPL-3.0-only, Artistic-2.0, EUPL-1.2, OFL-1.1. GitHub's license detection is used first. Text sniffing is the fallback.

LicenseRef-Commons-Clause\bCommons Clause\b
LicenseRef-All-Rights-Reserved\ball rights reserved\b(?![\s\S]{0,400}Permission is hereby granted)
AGPL-3.0GNU AFFERO GENERAL PUBLIC LICENSE
LGPL-3.0GNU LESSER GENERAL PUBLIC LICENSE\s+Version 3
GPL-3.0GNU GENERAL PUBLIC LICENSE\s+Version 3
GPL-2.0GNU GENERAL PUBLIC LICENSE\s+Version 2
Apache-2.0Apache License\s+Version 2\.0
MPL-2.0Mozilla Public License,? (Version|v\.?) ?2\.0
MITPermission is hereby granted, free of charge
ISCPermission to use, copy, modify, and\/or distribute this software for any purpose
BSD-3-ClauseRedistribution and use in source and binary forms[\s\S]{0,600}Neither the name
BSD-2-ClauseRedistribution and use in source and binary forms
UnlicenseThis is free and unencumbered software released into the public domain

Questions and fixes

Think a factor is wrong? Open a correction. Think the rubric is wrong? Open an issue or a pull request on GitHub. Rubric changes are versioned and public.