Configuration Reference
All configuration is via environment variables in ~/.config/edgeproof/.env
(the EdgeProof home; override its location with the EDGEPROOF_HOME
environment variable; EDGEPROOF_HOME itself must be set in your shell, not
in .env). Run edgeproof configure to create and edit it interactively.
The home directory also holds activated license tokens and the output/ directory (databases, logs, and PID files).
Broker
| Variable |
Default |
Description |
BROKER |
alpaca |
Broker to trade through: alpaca, robinhood, schwab, tastytrade or ibkr. |
Choosing a broker
| Broker |
Paper trading |
Setup |
| Alpaca (default) |
Yes (full paper environment) |
edgeproof configure |
| Robinhood |
No (every order is real money) |
edgeproof broker setup robinhood |
Robinhood has no practice account, so EdgeProof cannot rehearse a strategy against it,
and setup asks you to confirm that every order is real money. If you want to prove a
signal source before risking money, use Alpaca paper trading.
Schwab, tastytrade and Interactive Brokers also work with EdgeProof but are still in
early access: we haven't finished testing them ourselves. They're described under
Early-access brokers.
Alpaca
| Variable |
Default |
Description |
APCA_API_KEY_ID |
(required) |
Alpaca API key ID |
APCA_API_SECRET_KEY |
(required) |
Alpaca API secret key |
ALPACA_PAPER_TRADE |
True |
Set False for live trading (requires license) |
APCA_API_BASE_URL |
auto |
Override broker URL (paper or live) |
Robinhood
Required when BROKER=robinhood. Robinhood speaks MCP, not REST: EdgeProof
connects to Robinhood's agentic-trading endpoint. There are no API keys to copy: run
edgeproof broker setup robinhood, approve in the browser, and pick the account to
trade. It sets the variables below for you.
| Variable |
Default |
Description |
ROBINHOOD_ACCOUNT_NUMBER |
(required) |
Brokerage account to trade. Robinhood requires it explicitly and EdgeProof never defaults it. |
ROBINHOOD_LIVE_ONLY_ACKNOWLEDGED |
false |
Must be true to trade. Confirms you understand Robinhood has no paper mode. |
ROBINHOOD_MCP_URL |
Robinhood's endpoint |
Override the MCP server URL (testing only). |
Account requirements. Agentic trading runs in a dedicated Agentic account,
opened during the browser step of edgeproof broker setup robinhood (desktop browser
only); pick that account when asked. The account must be agentic-enabled and have options level 2
or higher; EdgeProof checks both at startup rather than failing on the first order.
Single-leg only. Robinhood's endpoint supports single-leg option orders, which is
what EdgeProof places. Spreads are not available through it.
Workflow note. Robinhood documents its trading tools for agents that confirm each
order with a human. EdgeProof runs unattended. The endpoint accepts the orders either
way, but you should be comfortable with that difference before enabling it.
Early-access brokers
These brokers work with EdgeProof, but we haven't finished testing them ourselves.
Use them at your own risk, and start small. Alpaca and Robinhood are the supported
brokers for now, and more will join them once we've finished testing.
Schwab
Required when BROKER=schwab. Set these with edgeproof broker setup schwab rather than
by hand: it validates them and runs the authorization flow.
| Variable |
Default |
Description |
SCHWAB_CLIENT_ID |
(required) |
App Key from your app at developer.schwab.com |
SCHWAB_CLIENT_SECRET |
(required) |
App Secret |
SCHWAB_ACCOUNT_HASH |
(required) |
Opaque account id from GET /trader/v1/accounts/accountNumbers. Check edgeproof doctor prints the account number you expect: a valid-looking hash can address a different account on the same login. |
SCHWAB_LIVE_ONLY_ACKNOWLEDGED |
false |
Must be true to trade. Confirms you understand Schwab has no paper mode and every order is real. EdgeProof refuses to place entries without it. |
SCHWAB_CALLBACK_URL |
https://127.0.0.1 |
OAuth redirect. Must match the callback registered on your Schwab app. |
tastytrade
Required when BROKER=tastytrade. Options-native and paper-capable: its
certification environment (api.cert.tastyworks.com) is a real sandbox, so EdgeProof's
normal paper-first discipline applies. Note the sandbox needs its own separate
tastytrade certification account; live credentials do not work against it.
| Variable |
Default |
Description |
TASTYTRADE_CLIENT_ID |
(required) |
OAuth client id, from your registered tastytrade OAuth client |
TASTYTRADE_CLIENT_SECRET |
(required) |
OAuth client secret |
TASTYTRADE_ACCOUNT_NUMBER |
(required) |
Account to trade (e.g. 5WX12345) |
TASTYTRADE_PAPER_TRADE |
true |
true uses the certification sandbox; false trades real money |
TASTYTRADE_API_BASE_URL |
auto |
Override the base URL (paper or live) |
Access tokens last 15 minutes and refresh automatically. Unlike Schwab there is no
fixed refresh-token cliff, so an always-on install should not need re-authorizing.
Interactive Brokers
Required when BROKER=ibkr. EdgeProof talks to IBKR's Client Portal Gateway, which
you run and log into yourself: EdgeProof never sees your IBKR password, and there are
no API keys.
| Variable |
Default |
Description |
IBKR_ACCOUNT_ID |
(required) |
Account to trade. Paper accounts are prefixed DU. |
IBKR_PAPER_TRADE |
true |
Must match the account: true requires a DU… account. |
IBKR_GATEWAY_URL |
gateway default |
Override if the gateway runs on another port. |
Paper and live share one gateway, so unlike every other broker the URL cannot tell
them apart: the account id is the boundary. EdgeProof refuses to start if
IBKR_PAPER_TRADE=true with a live account, or false with a DU… account, and it
makes no API call before that check. Keep the gateway logged into the account matching
your setting.
Schwab token expiry
Schwab tokens expire after 7 days. Schwab does not allow programmatic renewal. While
EdgeProof is running it refreshes itself; if it stays offline longer than 7 days, run
edgeproof broker auth schwab again. edgeproof doctor warns 24 hours ahead.
Discord Source
| Variable |
Default |
Description |
DISCORD_SOURCE_MODE |
auto |
puppeteer (browser scraping) or bot (Gateway API). If unset, auto-detects: bot when DISCORD_BOT_TOKEN is present, otherwise puppeteer. Set explicitly to override. |
DISCORD_CHANNEL_URL |
(empty) |
Single channel URL (puppeteer mode) |
DISCORD_CHANNEL_URLS |
(empty) |
Comma-separated channel URLs (puppeteer mode) |
DISCORD_BOT_TOKEN |
(optional) |
Discord bot token (bot mode) |
DISCORD_CHANNEL_IDS |
(empty) |
Comma-separated channel IDs (bot mode) |
DISCORD_CHANNEL_FILTERS |
(empty) |
Only process messages matching these keywords |
DISCORD_MAX_MESSAGE_LENGTH |
500 |
Skip messages longer than this |
CHROME_DEBUGGING_URL |
http://localhost:9222 |
Chrome DevTools endpoint (puppeteer mode). Change the port here: CHROME_DEBUGGING_PORT is parsed but not used by the scraper, so setting it alone has no effect. Use http://127.0.0.1:9222 if your machine resolves localhost to IPv6 and the connection is refused. |
LLM
edgeproof configure sets these for you. The default and recommended path is openai-compatible, which works with any hosted provider and requires no local hardware.
Hosted providers (openai-compatible)
Set LLM_PROVIDER=openai-compatible and fill in the three keys below. edgeproof configure writes these automatically when you choose a hosted provider.
| Variable |
Default |
Description |
LLM_PROVIDER |
ollama |
Provider mode. openai-compatible, ollama, or lmstudio. edgeproof configure writes openai-compatible when you pick a hosted provider (the recommended path). |
LLM_API_BASE_URL |
https://api.openai.com/v1 |
Base URL for the OpenAI-compatible endpoint |
LLM_API_KEY |
(required) |
API key for the hosted endpoint |
LLM_MODEL |
(required) |
Model name (e.g. gpt-4o-mini, claude-haiku-4-5, gemini-3.5-flash) |
LLM_API_COMPAT_MODE |
openai-responses |
Wire format for the endpoint. edgeproof configure writes openai-chat-compatible for the hosted providers (OpenAI, Anthropic, Gemini); leave it as init set it unless your endpoint requires otherwise. |
Common base URLs set by edgeproof configure:
| Provider |
LLM_API_BASE_URL |
| OpenAI |
https://api.openai.com/v1 |
| Anthropic (Claude) |
https://api.anthropic.com/v1/ |
| Gemini |
https://generativelanguage.googleapis.com/v1beta/openai/ |
Local models (Ollama / LM Studio)
Use these if you prefer to keep data on your machine. See Installation -- local model path for hardware requirements.
| Variable |
Default |
Description |
OLLAMA_BASE_URL |
http://localhost:11434/v1 |
Ollama endpoint |
OLLAMA_MODEL |
gemma4:latest |
Ollama model name |
LMSTUDIO_BASE_URL |
http://localhost:1234/v1 |
LM Studio endpoint |
LMSTUDIO_MODEL |
gemma-4-26b-a4b-it |
LM Studio model name |
LMSTUDIO_TIMEOUT_MS |
180000 |
Per-completion timeout for slow local models |
Trading Guardrails
These keys control what trades the system will take. All of them have safe defaults; adjust only what you understand.
Position sizing
| Variable |
Default |
Description |
TRADING_POSITION_SIZE_USD |
500 |
Dollar budget per position; qty = floor(budget / (price x 100)) |
TRADING_MAX_CONTRACTS_PER_UNDERLYING |
2 |
Max open contracts on a single underlying |
TRADING_FOLLOW_CHANNEL_EXITS |
false |
Let a channel's own exit calls close or trim the positions it opened. See Guardrails. |
TRADING_VAGUE_TRIM_FRACTION |
0 |
Fraction sold when a followed channel trims without stating a size ("taking a trim here"). 0 = notify only, never execute. Must be below 1. |
TRADING_MAX_OPEN_POSITIONS |
10 |
Global cap on concurrent open positions across all underlyings |
TRADING_ADD_ON_CAP |
3 |
Max contracts allowed when adding to an existing position |
TRADING_MAX_CONTRACTS_PER_TRADE |
0 |
Optional liquidity ceiling on contracts per single trade (0 = uncapped, the default; dollar budget remains the sizing control) |
TRADING_LOTTO_SIZE_FRACTION |
0.25 |
Fraction of the budget a lotto signal may size against (its "lane") |
TRADING_STARTER_SIZE_FRACTION |
0.33 |
Fraction of the budget a starter signal may size against (its "lane") |
Entry filters
| Variable |
Default |
Description |
TRADING_ALLOW_0DTE |
false |
Allow entries on options expiring the same trading day |
TRADING_ALLOW_LOTTOS |
false |
Allow lotto / low-conviction long-shot entries |
TRADING_ALLOW_LOW_CONVICTION |
false |
Allow entries flagged as low-conviction by the signal extractor |
TRADING_REQUIRE_ENTRY_PRICE |
true |
Skip entries with no stated entry price: without one, the sanity ratio and hard cap below have nothing to anchor to |
TRADING_ENTRY_SANITY_RATIO |
3 |
Reject a signal if its price is more than this multiple above or below the current market price (e.g. 3 rejects anything >3x or <1/3 of market) |
TRADING_SLIPPAGE_PCT |
0.07 |
Max slippage tolerance (7%) for limit order placement |
TRADING_HARD_CAP_PCT |
0.10 |
Skip buy if market price is >10% above signal entry |
TRADING_MAX_SIGNAL_AGE_MINUTES |
60 |
Discard signals older than this |
TRADING_LOOKBACK_DAYS |
14 |
Lookback window for dedup and P&L queries |
MONITOR_INTERVAL_MINUTES |
0.5 |
How often the monitor checks for new signals |
Position Exit Rules
| Variable |
Default |
Description |
POSITION_TAKE_PROFIT_PCT |
75 |
Close at +75% gain |
POSITION_STOP_LOSS_PCT |
-50 |
Close at −50% loss |
POSITION_TRAILING_STOP_PCT |
40 |
Trailing stop: close if price falls 40% from peak |
POSITION_TRAILING_STOP_ACTIVATION_PCT |
30 |
Trailing stop activates after +30% gain |
POSITION_POLL_INTERVAL_MS |
10000 |
How often positions are polled |
POSITION_OPEN_BLACKOUT_SECONDS |
300 |
Suppress stop-loss/exit evaluation for this many seconds after the 8:30 CT market open: quotes at the open gap and settle |
Notifications
| Variable |
Default |
Description |
TELEGRAM_BOT_TOKEN |
(optional) |
Telegram bot token for trade alerts |
TELEGRAM_CHAT_ID |
(optional) |
Telegram chat/channel ID |
Licensing
| Variable |
Default |
Description |
EDGEPROOF_WORKER_BASE_URL |
https://api.edgeproof.net |
License/worker API base URL. Override for testing. |
Output
| Variable |
Default |
Description |
OUTPUT_DIRECTORY |
~/.config/edgeproof/output |
Directory for logs, trade database, PID file. A relative value resolves against the EdgeProof home, not the current directory. |
| Variable |
Default |
Description |
EXTRACTION_CHANNEL_HINTS |
(optional) |
JSON blob describing your channel's signal format. Normally leave this unset: on the first monitor run EdgeProof learns the format from live messages and persists it to <output>/channel-hints.json, reused automatically afterward. Set this env var only to pin a format explicitly (it overrides the learned file). To re-learn, delete <output>/channel-hints.json. |
Privacy
| Variable |
Default |
Description |
EDGEPROOF_NO_UPDATE_CHECK |
(unset) |
Set to 1 to disable the daily version check |
Tunable Settings (generated)
The table below is generated from the settings registry by edgeproof configure docs. Do not edit it by hand.
LLM / model
| Variable |
Default |
Description |
LLM_PROVIDER |
ollama |
LLM provider mode. |
LLM_MODEL |
(empty) |
Model name the extractor calls (openai-compatible path). |
LLM_API_BASE_URL |
https://api.openai.com/v1 |
Base URL for the OpenAI-compatible endpoint. |
LLM_API_KEY |
(empty) |
API key for the hosted endpoint. |
LMSTUDIO_TIMEOUT_MS |
180000 |
Per-completion timeout for a local LM Studio server. |
Trading limits
| Variable |
Default |
Description |
TRADING_POSITION_SIZE_USD |
500 |
Dollar budget per position. |
TRADING_POSITION_SIZE_PCT |
0 |
Ceiling on one position as a share of your account (0.06 = 6%). The smaller of this and the dollar budget wins, so a fixed dollar amount can never outgrow the account. 0 turns it off and sizing stays purely by dollars. |
TRADING_MAX_UNDERLYING_PCT |
0 |
Ceiling on everything you hold in one ticker, as a share of your account (0.10 = 10%). Counts what you paid, so a losing position never frees up room to buy more of it. An entry that would breach the ceiling is trimmed to fit, or skipped when nothing fits. 0 turns it off. |
TRADING_MAX_OPEN_POSITIONS |
10 |
Cap on concurrent open positions. |
TRADING_HARD_CAP_PCT |
0.10 |
Skip a buy if market price is already this fraction above the alert (0.10 = +10%). |
TRADING_MAX_CONTRACTS_PER_UNDERLYING |
2 |
Cap on contracts held per underlying symbol. |
TRADING_ALLOW_0DTE |
false |
Allow same-day-expiry options. |
TRADING_ALLOW_LOTTOS |
false |
Allow low-cost long-shot options flagged as lottos. |
TRADING_DAILY_LOSS_LIMIT_USD |
0 |
Halt new entries when intraday P/L drops below this dollar amount. 0 = disabled. |
TRADING_SOURCE_WEIGHTING_ENABLED |
false |
Scale position size by source win rate (requires ≥ min trips of history). |
TRADING_SOURCE_WEIGHTING_MIN_TRIPS |
10 |
Minimum closed round trips before win-rate sizing applies to a source. |
Exit rules
| Variable |
Default |
Description |
POSITION_TAKE_PROFIT_PCT |
75 |
Take-profit target, percent gain. |
POSITION_STOP_LOSS_PCT |
-50 |
Stop-loss threshold, percent (negative). |
POSITION_TRAILING_STOP_PCT |
40 |
Trailing-stop giveback, percent from peak. |
POSITION_TRAILING_STOP_ACTIVATION_PCT |
30 |
Gain at which the trailing stop activates. |
TRADING_FOLLOW_CHANNEL_EXITS |
false |
Let a channel's own exit calls close or trim the positions it opened. Your take-profit/stop still apply to what remains. |
TRADING_VAGUE_TRIM_FRACTION |
0 |
Fraction sold when a followed channel trims without stating a size ("taking a trim here"). 0 = notify only, never execute. Applies to sizeless trims only; runners calls still sell down to the runner count. |
TRADING_RUNNER_CONTRACTS |
1 |
Contracts kept when a followed channel goes to runners ("leave a few to run"). 0 = close fully on a runners call. |
TRADING_EXIT_CHASE_PCT |
0.10 |
Withhold an author-priced exit when the bid is this fraction below the author's stated exit price; stops are tightened instead. 0 = guard off. |
TRADING_SOURCE_EXIT_CALIBRATION |
false |
Tighten trailing stops per source toward where that source's winners actually exit (from your ledger history). Tighten-only; needs min closed trips. |
POSITION_LADDER_ENABLED |
true |
Scale out of winners in stages instead of one all or nothing take profit. Positions of one contract are unaffected. |
POSITION_LADDER_LEVELS |
50:0.33,100:0.33 |
Gain percent and fraction sold per stage, comma separated. Example: 50:0.33,100:0.33 sells a third at +50% and a third at +100%, leaving a runner. |
POSITION_RUNNER_TRAIL_PCT |
45 |
Trailing stop width for the runner left after the ladder has banked profit. Wider than the normal trail so the runner can catch a big move. |
POSITION_TIME_STOP_MINUTES |
120 |
Close a losing position that has never worked after this many market minutes. Only fires below breakeven and only when the trade never reached the arm threshold. 0 turns it off. |
POSITION_TIME_STOP_ARM_PCT |
15 |
A trade that reaches this peak gain is considered to have worked, so the time stop leaves it alone for good. |
POSITION_TIME_STOP_MAX_DTE |
2 |
Only apply the time stop to positions with this many days to expiry or fewer, so multi-day swings are left alone. 0 means same-day only. |
QUOTES_RECORD_ENABLED |
true |
Save quotes for held contracts to disk so exit rules can be tested against your own trade history with the simulator. |
QUOTES_RETENTION_DAYS |
30 |
Days of recorded quotes to keep before old files are deleted. |
STREAMING_ENABLED |
true |
Watch positions on a live quote feed instead of checking every few seconds. Exits then react to the bid, the price a sale would actually fetch, and quote recording only happens with this on. |
STREAMING_OPTIONS_FEED |
indicative |
Which options quote feed to subscribe to. OPRA is the full exchange feed and needs a paid data subscription; indicative works on the free tier. |
LEDGER_PORT |
3030 |
Port for the local dashboard. It always binds to 127.0.0.1 and has no login, so it stays reachable only from this machine. |
LEDGER_SOURCES |
(empty) |
Comma-separated signal sources the dashboard scoreboard should record, for example discord:my-channel. Leave it empty to record every source found in your broker history. Set it after you stop following a channel, otherwise the old fills are pulled back in from the broker on the next sync. Sells that cannot be matched to a listed source are skipped. |
Discord channels
| Variable |
Default |
Description |
DISCORD_READ_START |
03:00 |
Time of day the reader starts watching your channels, in US Central time. Earlier than the market opens on purpose, so a premarket alert is captured when it is posted instead of arriving hours later already too old to act on. Reading is not trading: every entry rule still applies. |
DISCORD_READ_END |
19:00 |
Time of day the reader stops watching, in US Central time. Later than the close so after-hours calls land in your record. |
DISCORD_CHANNEL_URLS |
(empty) |
Comma-separated channel URLs (puppeteer mode). |
DISCORD_CHANNEL_NAMES |
(empty) |
Comma-separated channelId:label pairs for leaderboard attribution. |
Notifications
| Variable |
Default |
Description |
TELEGRAM_BOT_TOKEN |
(empty) |
Telegram bot token for trade notifications. |
TELEGRAM_CHAT_ID |
(empty) |
Telegram chat ID to notify. |
Privacy
| Variable |
Default |
Description |
EDGEPROOF_TELEMETRY |
false |
Opt in to sending version, uptime and open-position counts so silent failures are visible. Never includes trading data. Run edgeproof telemetry --show to see the exact payload. |