A single-file Python watcher that polls SEC EDGAR for new Strategy Inc
(formerly MicroStrategy, ticker MSTR, CIK 0001050446) 8-K filings, parses
the weekly Bitcoin-treasury update out of them, and fires alerts — with special
emphasis on detecting BTC sales (vs the usual purchases).
Strategy files a weekly 8-K (usually Monday) with a table of BTC bought/sold, average price, and total holdings. Historically these were all purchases; the first sale appeared in mid-2026 with a new table layout. This tool is built to catch any future sale fast and reliably, through several independent detection layers plus an optional LLM second opinion.
Disclaimer: This is an informational tool, not financial advice. It tells you what a filing says, not whether to trade. SEC filings are public-domain government records. Use at your own risk; see the MIT
LICENSE.
- Multi-layer sale detection — fires a
🚨 SALE SIGNALif any layer trips:- Header text — table header says "BTC Sold" / "BTC Disposed" / "Average Sale Price".
- Negative delta — a negative value in the BTC-acquired column (handles
(535),-535,−535). - Prose scan — past-tense sale language ("sold 1,500 bitcoin"); forward-looking funding language is noted but doesn't sound the alarm.
- Holdings delta — any decrease vs the last known holdings baseline (the most layout-robust layer).
- Optional LLM second opinion (Groq Llama 3.3 70B) — runs on every BTC update, non-blocking. If it flags a sale the regex missed, you get a separate alert. Catch-all for novel layouts.
- Two SEC feeds (
--feed):submissions(per-CIK JSON, never misses) orgetcurrent(global firehose, often lower latency). - Telegram broadcast — auto-discovers subscribers (anyone who sends
/start) and broadcasts alerts to all of them. - Health monitoring — degraded/recovered alerts after consecutive poll failures, plus periodic heartbeat so a dead process is visible.
- Stdlib +
requestsonly.
pip install -r requirements.txtcp config.env.example config.env # Windows: copy config.env.example config.envThen edit config.env. The only required key is SEC_UA — set it to your
own contact email (SEC rate-limits/blocks generic User-Agents). Telegram and
Groq are optional. config.env is gitignored — never commit real secrets.
# Sanity check: parse a past filing through the full pipeline (no state change)
python mstr_btc_poller.py --backtest 0001193125-26-249768
# Verify Telegram delivery end-to-end (no filing needed)
python mstr_btc_poller.py --test-telegram
# Prime once before going live: mark existing 8-Ks as seen + set holdings baseline
python mstr_btc_poller.py --prime
# Go live
python mstr_btc_poller.py--feed, --interval, --prime, --once, --backtest, --test-telegram,
--open, --open-only-btc, --no-audible, --groq-api-key, --llm-timeout,
--telegram-token, --telegram-chat-id, --health-fail-threshold,
--heartbeat-secs, --log-file, --user-agent.
Precedence: CLI flag > environment variable > config.env > built-in default.
State persists in your home directory (not in the repo):
~/.mstr_btc_poller_state.json— seen filings + holdings baseline.~/.mstr_btc_poller_subscribers.json— Telegram subscribers (kept separate so deleting the state file to re-prime does not wipe your subscribers).
- SEC permits up to 10 req/sec for automated access — always send a descriptive User-Agent with a contact email. Default interval is ~5 req/sec.
- The poller does not survive laptop sleep, lid-close, or a closed terminal. For 24/7 reliability run it on an always-on machine or a VPS.
- The parser is positional/regex-based and assumes specific column orders and header strings; Strategy has changed their layout before. The holdings-delta layer and the LLM are the format-robust backstops.
MIT — see LICENSE.