{"id":50314364,"url":"https://github.com/calesthio/optionscanvas","last_synced_at":"2026-06-01T02:00:46.460Z","repository":{"id":360299318,"uuid":"1249528417","full_name":"calesthio/OptionsCanvas","owner":"calesthio","description":"Stop getting your stops hunted. SL/TP never touch your broker - only fires when the underlying actually breaches your level. And skip the options chain: drag your levels on the chart, we auto-pick the strike + DTE + contracts. The first open-source platform that does both.","archived":false,"fork":false,"pushed_at":"2026-05-28T21:18:49.000Z","size":635,"stargazers_count":29,"open_issues_count":1,"forks_count":4,"subscribers_count":1,"default_branch":"main","last_synced_at":"2026-05-30T00:03:30.903Z","etag":null,"topics":["0dte","algorithmic-trading","alpaca","charting","day-trading","fintech","flask","lightweight-charts","local-first","open-source","options","options-trading","python","self-hosted","trading-platform","vanilla-js"],"latest_commit_sha":null,"homepage":"https://github.com/calesthio/OptionsCanvas","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/calesthio.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-05-25T19:52:40.000Z","updated_at":"2026-05-29T05:37:06.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/calesthio/OptionsCanvas","commit_stats":null,"previous_names":["calesthio/optionscanvas"],"tags_count":11,"template":false,"template_full_name":null,"purl":"pkg:github/calesthio/OptionsCanvas","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/calesthio%2FOptionsCanvas","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/calesthio%2FOptionsCanvas/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/calesthio%2FOptionsCanvas/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/calesthio%2FOptionsCanvas/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/calesthio","download_url":"https://codeload.github.com/calesthio/OptionsCanvas/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/calesthio%2FOptionsCanvas/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33715211,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-05-30T02:00:06.278Z","response_time":92,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["0dte","algorithmic-trading","alpaca","charting","day-trading","fintech","flask","lightweight-charts","local-first","open-source","options","options-trading","python","self-hosted","trading-platform","vanilla-js"],"created_at":"2026-05-28T23:00:32.996Z","updated_at":"2026-05-31T01:00:32.196Z","avatar_url":"https://github.com/calesthio.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# OptionsCanvas\n\n[![License: AGPL v3](https://img.shields.io/badge/License-AGPL_v3-blue.svg)](./LICENSE)\n\n\n## Stop getting your stops hunted.\n\nYou see the setup forming on the SPY chart. You know exactly where you want to enter, exactly where you're wrong, exactly where you'll take profit — **all in SPY dollars, the chart you actually understand.**\n\nThen you tab over to your broker. Pick an expiration. Scroll the strike ladder. Compute how many contracts $1,000 buys. Set the stop in *option premium* dollars (not the SPY level you actually understand). Submit. Watch a market-maker tap your stop on a wick fifteen seconds after the open.\n\n**OptionsCanvas fixes both halves of that.**\n\n- **Your stops live locally.** Not on the broker order book. Not visible to the HFTs that profit from hunting them. We only send a market order at the moment the underlying actually breaches your level.\n- **You never touch the options chain.** You drag your entry, SL, and TP directly on the underlying's chart — we pick the strike, the DTE, the contract count, and project the option premium and P\u0026L in real time as you drag.\n\nTwo-keystroke execution. Runs 100% on your machine. **The first open-source options platform that does this.**\n\nhttps://github.com/user-attachments/assets/ebae0480-6214-45ae-9435-1231a1a855fb\n\n![Overview](docs/screenshots/01-overview.png)\n\n---\n\n## Built for the active options trader who…\n\n- Trades **short-dated options** — whether that's **0 DTE on SPY** or **a month out on AAPL** — directly off the underlying chart\n- Wants to think in **underlying price** (the chart you actually read), not in option premium\n- Has been **stop-hunted** one too many times and never wants a resting stop in the broker's book again\n- Refuses to **click 7 times** to get a trade on\n- Needs **hotkeys, flatten-all, and one-gesture brackets** — not modal dialogs\n\nWorks on any optionable US equity or ETF your broker supports — index ETFs, single names, leveraged ETFs, whatever. Configure your watchlist and the platform pulls expirations + strike increments straight from the broker.\n\nIf that's you, keep reading.\n\n---\n\n## What makes it different\n\n### 🎯 Your chart is your order ticket\nDrag the **Buy**, **SL**, and **TP** pills directly on the underlying chart. No ticket window. No popups. The price line *is* the control.\n- Drag **Buy** away from live price → flips into a limit-trigger with an anchored `ENTRY` line\n- Drag **TP** or **SL** up or down → level updates live, projected premium and P\u0026L update with it\n\n\u003ctable align=\"center\" border=\"0\"\u003e\n  \u003ctr\u003e\n    \u003ctd width=\"50%\"\u003e\u003cimg src=\"docs/screenshots/02-drag-tp-sl.png\" alt=\"Drag SL/TP pills on the underlying chart\"\u003e\u003c/td\u003e\n    \u003ctd width=\"50%\"\u003e\u003cimg src=\"docs/screenshots/03-buy-limit-trigger.png\" alt=\"Drag Buy off live price — limit-trigger with anchored ENTRY line\"\u003e\u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd align=\"center\"\u003e\u003ci\u003eDrag SL/TP on the underlying — premium + P\u0026amp;L recompute as you drag.\u003c/i\u003e\u003c/td\u003e\n    \u003ctd align=\"center\"\u003e\u003ci\u003eDrag Buy off live price — becomes a limit-trigger with an anchored ENTRY line.\u003c/i\u003e\u003c/td\u003e\n  \u003c/tr\u003e\n\u003c/table\u003e\n\n\n### 🛡️ Stops your broker can't see — and can't hunt\nStops and targets do **not** sit in your broker's order book. They live in your local machine and only become a real market order at the instant the underlying actually breaches your level.\n- No resting stop for HFTs to sweep\n- No \"stop tag + reverse\" 15 seconds after the open\n- The broker sees a market order *after* the breach, never before\n- You stop providing free liquidity to the venue\n\n```\n   You set SL @ 449.50\n            │\n            ▼\n  ┌───────────────────────┐\n  │    trading_engine     │   ← stop lives here, in memory + SQLite\n  │   holds SL locally    │     (broker never sees it)\n  └───────────┬───────────┘\n              │\n              │  polls underlying quote\n              ▼\n      underlying ≤ 449.50 ?\n              │\n              │  yes\n              ▼\n  ┌───────────────────────┐\n  │   market SELL fires   │   → broker (first time the\n  │       to broker       │     order book sees anything)\n  └───────────────────────┘\n```\n\n### 🧠 Think in the underlying. Trade in options.\nYou set levels on the **underlying chart** (e.g. your ticker at 449.50). OptionsCanvas does the contract math.\n- **Auto-picks the contract** — DTE from your configured presets (0 DTE, weeklies, monthlies — whatever you list), ATM strike from the live chain, both pulled fresh from the broker\n- **Black-Scholes overlay** projects the option premium and your P\u0026L *while you drag*, so you see \"if the underlying hits 451, this call is worth $2.40 and you make $640\"\n- Strike increments and expirations come from the **broker as source of truth** — no manual contract config, no stale chains\n\n\u003cp align=\"center\"\u003e\u003cimg src=\"docs/screenshots/04-side-panel-lower.png\" alt=\"Side panel: underlying-priced SL/TP, Smart auto-SL button, auto-picked contract and quantity\" width=\"380\"\u003e\u003c/p\u003e\n\n*One screenshot, the whole pitch: SL and TP labeled in **underlying dollars** (not option premium). One-tap **Smart** button auto-sets stops from ATR. The contract `SPY260526C00746000`, the **3-contract** size, and the **$823.50** cost — all computed for you. Hit the big green button, you're in. Hit \"Close All Positions\", you're flat.*\n\n### ⚡ Speed of execution\nBuilt so a trade is **two keystrokes**, not seven clicks.\n- `B` → Buy CALL at market (ATM, auto-sized)\n- `S` → Buy PUT at market\n- `F` → Flatten **all** positions, instantly\n- `Shift+B` → Bracket draw mode: click entry, drag to TP, release — done\n- `C` → Toggle CALL/PUT  •  `↑`/`↓` → strike up/down\n- `1`–`5` → preset position sizes ($500 / $1k / $2k / $5k / $10k)\n- `Alt + 1..6` → 1m / 5m / 15m / 30m / 1h / 1d timeframe\n- `Alt + ←/→` → previous/next symbol  •  `?` → cheatsheet\n\n### 🎨 One-gesture bracket orders\nHit `Shift+B`, click entry, drag to where you want profit. Direction of drag picks CALL vs PUT. Default **2:1 R:R** is auto-applied. Release to send. That's the whole interaction.\n\n### 🤖 Smart defaults that aren't dumb\n- **ATR-based SL** (1.5× ATR-14) reconciled against **swing high/low** lookback — picks the more conservative\n- **2:1 R:R TP** by default, override per trade\n- **Smart sizing presets** so you stop fat-fingering 100 contracts at 3:59pm\n\n### 📊 The chart you'd actually use\nTradingView Lightweight Charts under the hood. Multi-symbol, multi-timeframe.\n- **Indicators**: VWAP, SMA, EMA, RSI, Volume — toggle per chart\n- **Drawing tools**: trend lines, rectangles, horizontals\n- Dark theme, 60fps, no garbage\n- **Right-click context menu** with everything one click away\n\n*(The hero image at the top of this page is exactly this — chart, indicators, draggable Buy/SL/TP pills, side panel, broker pill, Day P\u0026L — all rendered live.)*\n\n### 🔒 Local. Private. Yours.\n- Runs 100% on your machine — Flask on `127.0.0.1:5001`\n- Your keys live in `config/config.json`, your state in `assisted_trading/state/trading.db`\n- **Zero telemetry.** The only outbound traffic is to your broker.\n- No SaaS, no login, no \"free tier\", no one watching your levels\n\n### 🧱 Risk controls that actually fire\n- **Per-symbol position caps** and **max simultaneous positions**\n- Configurable **trading hours** (auto-blocks orders outside the window)\n- **Auto-sell on SL breach** (toggle off if you prefer manual)\n- **Daily trade limits** and accept-partial-fill behavior, all in JSON config\n\n### 📓 Every trade journaled — automatically\nStop maintaining your trading journal in a spreadsheet. OptionsCanvas writes every fill, every close, every realized P\u0026L to your local SQLite DB as it happens.\n- **Per-trade row** — option symbol, contracts closed, exit price, exit time, realized P\u0026L\n- **Daily aggregate** — total trades, win/loss count, gross profit/loss, net P\u0026L, largest win/loss\n- **Plain SQLite** at `assisted_trading/state/trading.db` — query with `pandas.read_sql`, DuckDB, Datasette, Jupyter, whatever you already use for analysis\n- **JSON snapshots** under `assisted_trading/journal/\u003cdate\u003e/trades.json` for human-readable review\n- **REST endpoint** `GET /api/journal?start_date=...\u0026end_date=...` for building your own dashboards\n- It's your data, on your disk — nothing leaves the machine\n\n### 🔌 Broker-agnostic by design\nCurrently two brokers ship out of the box:\n- **Alpaca** — production-tested. The reference implementation used during development.\n- **Tradier** — *implementation complete but not yet validated end-to-end against a live Tradier sandbox account. Working through that now — see [Broker support status](#broker-support-status) below.*\n\nThe broker layer is an abstract interface (`broker_interface.py`) with a declarative registry (`broker_registry.py`) — adding IBKR, Tastytrade etc. is one new file in `backend/` and one entry in the registry. The wizard UI renders dynamically from the registry, so a new broker shows up without any frontend edits.\n\n---\n\n## Setup\n\n**Prereqs:** Python 3.10+ (or Docker) and a free paper-trading account from a supported broker — [Alpaca](https://alpaca.markets) (recommended) or [Tradier](https://tradier.com) (experimental — see [Broker support status](#broker-support-status)). Both take ~2 minutes to create and don't risk real money.\n\n### The whole thing, in 3 steps:\n\n1. **Download** — [grab the latest ZIP](https://github.com/calesthio/OptionsCanvas/archive/refs/heads/main.zip) (or `git clone`) and unzip it.\n2. **Launch** — pick whichever is easiest:\n   - **Windows**: double-click `OptionsCanvas.bat`\n   - **macOS / Linux**: `./optionscanvas.sh` *(first time: `chmod +x optionscanvas.sh`)*\n   - **Docker (any OS)**: `docker compose up -d` — see [Docker](#docker) below\n\n   On the first native run it creates a Python venv and installs deps (~2 min). Subsequent launches are instant.\n3. **Follow the wizard** — your browser opens to the setup wizard:\n   - Pick a broker (Alpaca recommended; Tradier supported but [not yet end-to-end tested](#broker-support-status)) → paste keys → \"Test connection\"\n   - Pick a trading universe: **Recommended 30** (default), **Full 110**, or your own custom watchlist\n   - Click **\"Start trading\"**\n\nThat's it. The trading UI takes over and you're live on paper money.\n\nThe wizard also runs idempotently — you can revisit `http://localhost:5001/setup` later to re-onboard symbols or rotate keys.\n\n\u003ca id=\"docker\"\u003e\u003c/a\u003e\n\u003cdetails\u003e\n\u003csummary\u003e\u003cb\u003eDocker\u003c/b\u003e\u003c/summary\u003e\n\nSingle command, any OS:\n\n```bash\ndocker compose up -d        # build + start\n# open http://localhost:5001/setup\ndocker compose logs -f      # tail logs\ndocker compose down         # stop\n```\n\n`config/` and `assisted_trading/state/` are bind-mounted, so your broker keys and trading DB live in the repo dir and survive container rebuilds.\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cb\u003ePower-user / manual setup\u003c/b\u003e\u003c/summary\u003e\n\nIf you'd rather skip the launcher and do it by hand:\n\n```bash\ngit clone https://github.com/calesthio/OptionsCanvas.git\ncd OptionsCanvas\npython -m venv .venv \u0026\u0026 source .venv/bin/activate   # Windows: .venv\\Scripts\\activate\npip install -r requirements.txt\npython assisted_trading/run_platform.py             # opens browser to /setup wizard\n```\n\nOr skip the wizard entirely (Alpaca-only path — Tradier users should use the wizard):\n\n```bash\ncp config/config.example.json config/config.json    # then paste your Alpaca keys\npython scripts/onboard_symbol.py                    # default: 30 Tier-1 names\npython scripts/onboard_symbol.py --all              # full 110-name universe\npython scripts/onboard_symbol.py AAPL MSFT NVDA     # custom tickers\npython assisted_trading/run_platform.py\n```\n\nThe Tier-1 default covers SPY, QQQ, NVDA, TSLA, IWM, the Mag-7, top semis (AMD, MU, INTC, AVGO, SOXL/SOXS), high-flow retail names (PLTR, HOOD, MSTR, COIN, F, AAL), sector ETFs (XLE, XLF), and leveraged QQQ (TQQQ/SQQQ). `--all` adds 80 more across financials, pharma, energy, consumer, China, vol, and bonds.\n\n**Optional — browser tests (Playwright):**\n```bash\nnpm install \u0026\u0026 npx playwright install chromium\n```\n\n\u003c/details\u003e\n\n---\n\n## Hotkeys cheatsheet\n\n| Key | Action |\n|---|---|\n| `B` / `S` | Buy CALL / Buy PUT at market |\n| `F` | **Flatten all positions** |\n| `Shift+B` | Bracket-draw mode (click entry, drag to TP) |\n| `C` | Toggle CALL ↔ PUT |\n| `↑` / `↓` | Strike up / down |\n| `1`–`5` | Position size: $500 / $1k / $2k / $5k / $10k |\n| `Alt + 1..6` | 1m / 5m / 15m / 30m / 1h / 1d |\n| `Alt + ← / →` | Previous / next symbol |\n| `D` / `T` | Draw horizontal / trend line |\n| `Esc` | Cancel drawing / bracket mode |\n| `?` | Show full shortcuts modal |\n\n---\n\n## Broker support status\n\n| Broker | Status | Notes |\n|---|---|---|\n| **Alpaca** | ✅ Production-tested | The reference broker used during development. All flows (validate, chart data, option chains, place/cancel orders, positions, server-side stops) exercised continuously against a paper account. |\n| **Tradier** | 🧪 Implementation complete, end-to-end testing in progress | All `BrokerInterface` methods implemented against Tradier's documented REST API. Verified against the sandbox endpoint at a unit level (auth, error handling, response parsing) but not yet validated through a full sandbox trading session. Use at your own risk until this row turns green; please file issues if you see anything off. |\n\nAdding a new broker requires one file in `assisted_trading/backend/\u003cname\u003e_broker.py` (implementing `BrokerInterface`) and one entry in `broker_registry.py` — no frontend or trading-engine edits. Contributions welcome.\n\n---\n\n## Configuration\n\n- **`config/config.json`** — broker credentials + paper/live mode + global defaults (gitignored, never commit). Written by the setup wizard; you almost never need to edit it by hand.\n- **`assisted_trading/config/assisted_trading_config.json`** — enabled symbols, DTE presets, position-size presets, max positions, trading hours, auto-sell, entry-order type\n- **Broker accounts** — free paper accounts at [Alpaca](https://alpaca.markets) or [Tradier](https://tradier.com). Paper and live use separate API keys on both brokers — generate the right pair from each broker's API settings page.\n\n---\n\n## Architecture\n\n- **Frontend (vanilla JS)** — `ChartManager` owns Lightweight Charts. `OrderPanelOnChart` renders draggable pills. `ChartTradingController` bridges chart ↔ side panel. `BlackScholesCalculator` projects premium + P\u0026L. `BracketOrderDrawer` handles one-gesture brackets. `KeyboardShortcutManager` for hotkeys. `SmartDefaults` for ATR-based SL/TP. The setup wizard (`setup.html`) renders dynamically from `/api/setup/brokers`.\n- **Backend (Flask + SocketIO)** — `chart_api_server.py` exposes REST + WS. `trading_engine.py` runs the loop: entries, fill monitoring, SL/TP breach checks, with a TTL cache + graceful fallback on transient broker errors. `order_manager.py` + `position_manager_v2.py` persist to SQLite. `state_machine.py` enforces invariants. `setup_routes.py` powers the first-run wizard.\n- **Broker layer** — `broker_interface.py` (abstract base) + `broker_registry.py` (declarative metadata, drives wizard UI) + `broker_factory.py` (builds instances) + `alpaca_broker.py` and `tradier_broker.py` (concrete impls). Add a broker: drop one file in `backend/`, add one entry in the registry.\n- **State** — SQLite at `assisted_trading/state/trading.db`, auto-migrates on boot.\n\nMore: [`docs/ARCHITECTURE.md`](docs/ARCHITECTURE.md).\n\n---\n\n## Testing\n\n```bash\npip install -r requirements-test.txt                 # one-time\npytest -q                                            # ~190 unit + property + integration tests\npython assisted_trading/run_platform.py \u0026            # then, in another shell:\nnpx playwright test tests/browser/chart_trading.spec.js\n```\n\nScreenshots in this README are captured by `tests/browser/_screenshots.spec.js` against the live app.\n\n---\n\n## Contributing\n\nPRs welcome — see [`CONTRIBUTING.md`](CONTRIBUTING.md). Keep changes focused, run the suites, respect the broker abstraction and state machine.\n\n---\n\n## If this is useful to you\n\nA star on the repo genuinely helps — it's how other options traders find it. Solo dev project with no marketing budget, so word-of-mouth is all there is. If you end up using OptionsCanvas day-to-day, opening an issue with what's working / not working is even more valuable than a star.\n\n---\n\n## License\n\nAGPL-3.0-or-later. © 2026 calesthio. See [`LICENSE`](LICENSE).\n**Plain English**: run a modified version as a network service → you must share the modified source. Fork it privately for your own trading → you're fine.\n\nThird-party components and their licenses (TradingView Lightweight Charts™, Alpaca-py, Flask, Socket.IO, etc.) are catalogued in [`THIRD_PARTY_NOTICES.md`](THIRD_PARTY_NOTICES.md).\n\n---\n\n## Disclaimer\n\n- **Paper trading is the default** — the setup wizard's mode selector defaults to \"Paper\" on every supported broker. Live trading is supported (switch the toggle to \"Live\" in the wizard, or edit `config/config.json`'s `broker.mode`), but the launcher, server, and trading UI all surface loud warnings (terminal banner, server log, red broker pill, app-wide red border, `[LIVE]` browser-tab prefix) so you can't end up there by accident.\n- **Options trading involves substantial risk of loss.** You can lose 100% of premium; in some configurations more.\n- **Not financial advice.** A tool, not a recommendation. Indicators, projected P\u0026L, defaults — none of it is advice.\n- **No warranty.** Authors and contributors are not liable for losses, missed fills, slippage, broker outages, software bugs, or stops that fail to trigger — paper or live.\n- **If you don't understand exactly what an order will do before you place it — don't place it.**\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcalesthio%2Foptionscanvas","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcalesthio%2Foptionscanvas","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcalesthio%2Foptionscanvas/lists"}