US Watchlist Alerts
US Stock Watchlist & Price Alerts: Agent Skills for Claude Code, Codex, Gemini CLI, and Cursor
Featured in: awesome-gemini-cli
Free, open-source agent skills (SKILL.md format) for a US stock watchlist, stock price alerts, a daily market brief, movers / gappers, and price charts, with alerts that know NYSE market hours and holidays. Works in Claude Code, Codex, Gemini CLI, Cursor, and any agent that reads SKILL.md. An optional stdio MCP server is included (no extra packages). Track tickers with a thesis, entry, targets, and stop. Get de-duplicated alerts on price levels, daily % moves, gaps, 52-week highs and lows, moving-average crosses, RSI, ATM IV, volume spikes, intraday range, and earnings, then a morning or close brief. No API key. Default path is Python 3 stdlib + the unofficial Yahoo Finance chart. Optional: yfinance, Alpaca, Finnhub, Alpha Vantage.
Not financial advice. These skills never place, modify, or cancel a trade. Free quotes may be delayed ~15 minutes. Use at your own risk.

About 15 seconds, fixture / replayed sample quotes (not a live feed). Same story as python3 scripts/quickstart.py after install.
Longer after-hours fixture walkthrough: docs/demo.gif.
Install
Claude Code plugin
This repo is a Claude Code marketplace (skills + a stdio MCP server):
/plugin marketplace add eli-alvarado/us-watchlist-alerts
/plugin install us-watchlist-alerts@us-watchlist-alertsThen ask in Claude Code the way you would talk to a coworker. Other agents: Quick start (npx skills add). MCP-only clients: MCP server.
Related MCP server: Apple Stocks Watchlist MCP Server
Try these prompts
Copy-paste after install. Informational only — it never places a trade.
Add NVDA with a stop at 110 and alert me on a 5% drop
What's on my watchlist?
Give me my morning brief
Any new alerts?
What moved on my list today?
Which names gapped more than 2% vs yesterday's close?
Is the NYSE open right now?
Chart AAPL with my stop and targets
Watch TSLA and tell me if it drops below 200
Set up phone alerts even when the agent is closed
FAQ
Do I need an API key? No. The default path is Python 3 stdlib + the unofficial Yahoo Finance chart. Optional Alpaca / Finnhub / Alpha Vantage keys are only if you want those feeds.
Is the data delayed? Free quotes may be delayed ~15 minutes. Say so when precision matters. US-listed stocks and ETFs only.
Will it trade? Never. There is no broker submit path. Every SKILL.md and SECURITY.md say the agent must never place, modify, or cancel an order without your explicit confirmation of that specific order.
Does it run when my agent is closed? A Claude/Cursor session does not. For always-on weekday checks, python3 scripts/schedule.py installs cron (or prints a Task Scheduler line) plus a notify sink such as ntfy. See Get alerts on your phone.
Does it work in ChatGPT or Grok Bot? Grok Bot works today (live Yahoo, no API key). ChatGPT can load this SKILL.md format on Business / Enterprise / Edu; we have not tested it there, and its sandbox may block live lookups (the bundled fixture still works offline).
What does it cost? Free.
Where does my data go? $WATCHLIST_FILE if set, else ./watchlist.json in your project directory (the same file if you cd into .claude/skills/<name> or .agents/skills/<name> — the scripts walk up to the project root), else ~/.config/us-watchlist-alerts/watchlist.json (Windows: %APPDATA%\us-watchlist-alerts\). Alert state defaults to .alert_state.json next to that file. watchlist.py init / add / list print using <path>. That location is shared by all three skills and is not inside the skill folder, so npx skills add cannot delete it. See SECURITY.md.
Why did I get fewer alerts with the skill? That is the point. Same distinct events, no duplicate pings — see With vs. without.
Claude Code install landed in .agents/skills? You used bare -y. Use -a claude-code so it writes .claude/skills/. Or use the plugin commands above.
Windows: ZoneInfoNotFoundError? pip install tzdata. Linux CI does not need it.
How it works
flowchart LR
You["You or a 15-min HEARTBEAT"] --> WL["watchlist.json"]
WL --> Q["quotes.py"]
Q --> A["alerts.py"]
CAL["market_calendar.py<br/>NYSE hours / holidays"] --> A
A --> ST[".alert_state.json<br/>latch · once-per-day · cooldown"]
A --> OUT["ALERT lines · ntfy · Slack · webhook"]
WL --> B["brief.py<br/>morning / close"]You own the list. The scripts fetch a quote, evaluate only new conditions, and stay quiet when nothing changed — including after the bell and on Saturday.
Get alerts on your phone, even with your agent closed
A Claude/Cursor session only runs while it is open. For always-on NYSE-hours checks on a machine that stays on:
export WATCHLIST_NOTIFY=ntfy
export NTFY_TOPIC=my-watchlist # install the ntfy app and subscribe to this topic
python3 scripts/schedule.py # or: python3 scripts/quickstart.py scheduleThat installs a weekday cron job (every 5 minutes, Mon–Fri) whose working directory is the watchlist data dir (project ./ or ~/.config/us-watchlist-alerts/), not the skill folder. alerts.py already stays silent on NYSE holidays, weekends, and empty checks, so off-hours ticks do not ping you. Daily events are de-duplicated by the session date of the last close, so a 00:05 run does not re-fire yesterday as “today.” --dry-run prints the job without installing or sending a test ping. python3 scripts/schedule.py uninstall removes it. On Windows the same command prints a Task Scheduler line that cds into that data dir (it does not create the task).
No always-on computer? In a private fork, copy examples/alerts-cron.yml to .github/workflows/alerts.yml and set NTFY_TOPIC (or Slack/webhook) as Actions secrets. Do not put notify secrets on this public repo — .github/workflows/live.yml is a no-secrets public snapshot, not your phone.
Never places trades.
With vs. without the skill
Same 3 important moves caught. 58 duplicate pings avoided.
Fewer alerts here is the point. The skill is not “worse at finding news” — it found every distinct event on the tape and then stayed quiet. A check that has no memory re-sends the same two headlines every 15 minutes, including after the close and on Saturday.
One trading day, checked every 15 minutes (replayed)
Replayed Yahoo 15-minute prices for Thursday 2026-10-15 (not live), plus one Saturday tick. Same watch list both sides: tell me if AAPL is over $340, or if NVDA/SPY drops 3% (last print or the session low). Offline: python3 docs/demo/heartbeat/replay.py.

When | What was actually new | With the skill | Without (no memory) |
09:30 | AAPL over $340. NVDA already −3.7% on the low | 2 pings (the news) | 2 pings |
09:45 | NVDA’s last print also −3.3% | 1 ping (the news) | 3 pings (2 of them repeats) |
10:00–15:45 | Nothing new. Same two conditions still true | quiet | 50 more pings |
After 4:00 PM | Market closed | quiet | 6 more pings |
Saturday | Market closed | quiet | 2 more pings |
All day | 3 real events | 3 pings | 61 pings (3 news + 58 repeats) |
The skill did not miss a real event. NVDA’s low ticked from −3.70% to −3.82% at 09:45; that is the same “down 3% on the low” headline, not a fourth event. 8 of the 58 repeats arrived after the bell or on Saturday.
Default “down 3% today” still means last price vs yesterday’s close. The session-low rule is opt-in (intraday_low_pct). Full audit: docs/demo/heartbeat/.
One-shot questions (same day, ~6:50 PM ET, Cursor Grok 4.6)
On a single question, a capable agent without the skill is fine — live prices, official NYSE calendar. Unedited transcripts: docs/demo/. The skill’s edge is the next 20 checks, not the first one.
What's inside
Skill | What it does |
Add, remove, update, list and validate tickers with thesis, entry, targets, stop, tags and alert rules (JSON/YAML schema) | |
26 alert types + 1 alias ( | |
Morning or close summary: table, movers, distance to stop/target, upcoming earnings; optional | |
Checklist for a scheduled check that stays silent unless something new happens |
Scripts (scripts/, stdlib only): quotes.py (multi-provider quote fetcher with fallback), alerts.py (rule evaluator + .alert_state.json cooldown state), notify.py (webhook / Slack / ntfy / desktop / file), watchlist.py (CRUD + validation + init / presets + Yahoo ticker check on add), brief.py, movers.py (biggest % moves on your list), gappers.py (open vs prior close, --threshold), chart.py (ASCII sparkline / grid; PNG when matplotlib is installed), market_calendar.py, indicators.py, quickstart.py (offline fixture demo after install), schedule.py (weekday cron / Task Scheduler for always-on checks), mcp_server.py (stdio MCP; no extra packages).
Quick start
Pick one installer line. Bare -y is not Claude Code — it writes .agents/skills/ (Cursor / Codex). Claude Code needs -a claude-code.
Agent | Command (copy exactly) | Lands in |
Claude Code |
|
|
Cursor |
|
|
Codex |
|
|
Gemini CLI |
|
|
Every agent in this folder |
|
|
Run scripts from the project root by path (do not cd into the skill folder — npx skills add replaces that directory and would delete a watchlist stored there):
# Claude Code
python3 .claude/skills/price-alerts/scripts/quickstart.py
python3 .claude/skills/price-alerts/scripts/quotes.py AAPL
# Cursor / Codex / Gemini CLI: .agents/skills/price-alerts/scripts/...quickstart.py reads the bundled example in place for the fixture demo and never writes watchlist.json. watchlist.py init writes an empty list at the shared default path so a first add NVDA succeeds. All three skills use the same file: $WATCHLIST_FILE, else ./watchlist.json in this project (also when cwd is .claude/skills/<name> or .agents/skills/<name>), else ~/.config/us-watchlist-alerts/watchlist.json. Pass --example only if you want the sample book (a live ~$342 AAPL print will fire those fixture-era levels once):
python3 .claude/skills/watchlist-manager/scripts/watchlist.py init
python3 .claude/skills/watchlist-manager/scripts/watchlist.py init --list-presets
python3 .claude/skills/watchlist-manager/scripts/watchlist.py init --preset mega-cap-tech
python3 .claude/skills/watchlist-manager/scripts/watchlist.py add AAPL --alert pct_change_down:3 --no-verify
python3 .claude/skills/price-alerts/scripts/alerts.pyadd checks the symbol on the Yahoo chart (same default quote path). Unknown tickers are rejected with a short message. --no-verify (or WATCHLIST_NO_VERIFY=1) skips the lookup for offline / air-gapped use. If Yahoo is unreachable (timeout, DNS, connection reset, 5xx), the CLI prints a WARN and adds the ticker anyway so a network blip does not block you. WATCHLIST_FIXTURE / --fixture verifies against sample quotes instead of the network — presets work in that sample mode because the bundled fixture’s _default alias (AAPL’s quote) covers built-in preset symbols.
--file can sit before or after the subcommand. If alerts.py has no watchlist file, it tells you to run init instead of printing a silent “no new alerts.”
Built-in presets (init --list-presets): mega-cap-tech (AAPL/MSFT/GOOGL/AMZN/META/NVDA/TSLA), index-etfs (SPY/QQQ/DIA/IWM), sector-etfs (XLK/XLF/XLE/XLV/XLI/XLY/XLP/XLU/XLB/XLRE/XLC), dividend-staples (JNJ/PG/KO/PEP/WMT/MCD/XOM). Presets are symbol lists with a tag — no fixture-era price levels — so they are safe to use with --fixture / quickstart.py sample mode.
Or clone the repo and use the same files at the root:
git clone --depth 1 https://github.com/eli-alvarado/us-watchlist-alerts && cd us-watchlist-alerts
python3 scripts/quickstart.py # fixture demo
python3 scripts/quotes.py AAPL NVDA # live
python3 -m unittest discover -s tests # offline, fixtures onlyOn Windows, if that raises ZoneInfoNotFoundError for America/New_York, run pip install tzdata. Do not add tzdata to Linux CI or requirements.txt.
After the bell you do not need --force-session. alerts.py evaluates the last regular close and prints market closed, showing last regular close. Weekends and full-day holidays stay silent (with the next session date).
Offline demo (no network, same output as the GIF — after-hours last-close mode):
WATCHLIST_NOTIFY_FILE=/tmp/alerts.jsonl python3 scripts/alerts.py \
--watchlist tests/fixtures/watchlist.json --fixture tests/fixtures/quotes.json \
--now 2026-10-15T18:30:00-04:00 --state /tmp/wl-state.json --notify file
python3 scripts/brief.py --watchlist tests/fixtures/watchlist.json \
--fixture tests/fixtures/quotes.json --kind close --now 2026-10-15T16:15:00-04:00
python3 scripts/brief.py --watchlist tests/fixtures/watchlist.json \
--fixture tests/fixtures/quotes.json --kind morning --now 2026-10-15T08:30:00-04:00 --format json
python3 scripts/chart.py AAPL --watchlist tests/fixtures/watchlist.json \
--fixture tests/fixtures/quotes.json
python3 scripts/movers.py --watchlist tests/fixtures/watchlist.json \
--fixture tests/fixtures/quotes.json --now 2026-10-15T10:00:00-04:00
python3 scripts/gappers.py --watchlist tests/fixtures/watchlist.json \
--fixture tests/fixtures/quotes.json --threshold 2 --now 2026-10-15T10:00:00-04:00Use it in ChatGPT, Grok Bot, or other chat agents
You don't need a terminal if your chat assistant can load skills and has its own computer to run code. Grok Bot works today: we tested the skills there, and on Python 3.10+ they pull live Yahoo prices, keep your watchlist, fire alerts and write briefs, with nothing extra to install and no API key. ChatGPT supports uploading skills in this same format on Business, Enterprise and Edu plans, but we haven't tested it there, and its sandbox may block the live price lookups (the bundled sample data still works offline). Once the skill is added, just chat normally, for example "watch NVDA and tell me if it drops below 140" or "give me my morning brief." It's for information only: it never places trades.
Example output
Price alerts (fixture, after hours — last regular close)
[2026-10-15 18:30 ET] session=after — market closed, showing last regular close
ALERT AAPL $241.50 is above $240.00
ALERT AAPL within 0.0% of 52w high $241.50
ALERT AAPL reports earnings in 14 day(s) (2026-10-29)
ALERT TSLA down -6.00% today
ALERT TSLA gapped down -5.00% (open $212.55)
ALERT TSLA volume 3.0x 20-day avg
ALERT TSLA RSI 28.8 <= 30
ALERT TSLA reports earnings in 1 day(s) (2026-10-16)
ALERT NVDA golden cross: SMA50 vs SMA200
NOTIFY file /tmp/alerts.jsonlA second run in the same session prints no new alerts until a level re-arms or the next trading day (daily events). Agents running HEARTBEAT.md stay silent when the list is empty. --notify / WATCHLIST_NOTIFY also stay silent on empty, skipped, and --dry-run runs.
Live after hours (2026-10-15 ~18:45 ET, yahoo-chart)
Last regular close vs Wednesday 2026-10-14 prior close (AAPL $342.96, NVDA $221.30, SPY $769.60). Source: delayed Yahoo chart, no --force-session. Same last prints as the weekday Action at 20:09 ET; that first snapshot used Tuesday 2026-10-13 as prev_close because a trailing today-bar with close: None was treated as “today” (fixed in 0.4.1).
Crumb worked: AAPL earnings 2026-11-02 (yahoo-calendar), ATM IV 22.4% (yahoo-options). Nasdaq agreed on AAPL (2026-11-02) when Yahoo layers were forced off. SPY (an ETF) has no earnings date — the CLI now says so in one line instead of dumping a Yahoo 404 body.
[2026-10-15 18:45 ET] session=after — market closed, showing last regular close
ALERT AAPL $342.00 is above $240.00
ALERT AAPL within 1.8% of 52w high $348.15
ALERT AAPL $342.00 reached target $250.00
ALERT AAPL $342.00 reached target $270.00
ALERT NVDA $217.23 reached target $190.00AAPL $342.00 −0.28% vs prev_close $342.96 earnings 2026-11-02 (yahoo-calendar) ATM IV 22.4% exp 2026-10-16
SPY $771.79 +0.28% earnings unavailable (ETF) ATM IV 1.8% exp 2026-10-15 (0DTE)
NVDA $217.23 −1.84% earnings 2026-11-17 (yahoo-calendar) ATM IV 34.8% exp 2026-10-16prev_close is yesterday, not the 1y chart range start (that bug was v0.3.1). SPY's 1.8% IV is nearest-expiry on expiration day after the bell — a remaining limitation, not a crumb failure.
Watchlist brief (fixture, morning)
# Watchlist morning brief - Thu Oct 15, 2026 08:30 AM ET
| Ticker | Price | Chg | RSI14 | Trend | To stop | To target 1 |
|---|---|---|---|---|---|---|
| AAPL | $241.50 | +1.76% | 73 | up (50>200) | +13.0% | +3.5% |
| TSLA | $210.32 | -6.00% | 29 | down (50<200) | - | - |
| NVDA | $169.80 | +1.31% | 99 | up (50>200) | +17.6% | +11.9% |
**Biggest movers:** TSLA -6.0%, AAPL +1.8%, NVDA +1.3%
**Earnings dates:** TSLA (2026-10-16), AAPL (2026-10-29)
_Data: fixture. Informational only - not financial advice._Use --format json to get the same ticker rows, biggest movers, earnings dates, and quote source as a machine-readable object.
"To stop" is remaining cushion (positive = room left). Live runs label the data source (yahoo-chart, yfinance, …) instead of fixture.
What does the bundled example do on live quotes? It is a fixture-era book (AAPL above $240). A live AAPL ~$342 will fire those level alerts once. Default init is an empty live list; init --example is the sample.
Install per agent
Python 3.10+ is tested in CI. Each skill folder includes scripts/ (same files as the repo root). Use the exact -a line from Quick start — do not use bare -y for Claude Code. Windows only: pip install tzdata if zoneinfo cannot find America/New_York.
Claude Code
Plugin install is at the top of this README (/plugin marketplace add then /plugin install us-watchlist-alerts@us-watchlist-alerts).
Or symlink into the user skills dir:
git clone https://github.com/eli-alvarado/us-watchlist-alerts ~/.claude/us-watchlist-alerts
mkdir -p ~/.claude/skills
for s in watchlist-manager price-alerts watchlist-brief; do
ln -sfn ~/.claude/us-watchlist-alerts/skills/$s ~/.claude/skills/$s
doneFor one project, the installer line above already writes .claude/skills/. Then ask: add NVDA to my watchlist with a stop at 140.
Codex CLI
Project install (verified): npx skills add eli-alvarado/us-watchlist-alerts -y -a codex → .agents/skills/.
User-wide symlink if you prefer ~/.codex/skills:
git clone https://github.com/eli-alvarado/us-watchlist-alerts ~/.codex/us-watchlist-alerts
mkdir -p ~/.codex/skills
for s in watchlist-manager price-alerts watchlist-brief; do
ln -sfn ~/.codex/us-watchlist-alerts/skills/$s ~/.codex/skills/$s
doneOr point the project's AGENTS.md at skills/*/SKILL.md and run scripts from the clone.
Cursor
Project install (verified): npx skills add eli-alvarado/us-watchlist-alerts -y -a cursor → .agents/skills/.
To also commit a .cursor/skills/ copy in the repo you work in:
mkdir -p .cursor/skills
for s in watchlist-manager price-alerts watchlist-brief; do
ln -sfn /path/to/us-watchlist-alerts/skills/$s .cursor/skills/$s
doneUser-wide: the same loop into ~/.cursor/skills/. Older Cursor versions can use a rule in .cursor/rules/ that points at the SKILL.md files.
Gemini CLI
Project install (verified): npx skills add eli-alvarado/us-watchlist-alerts -y -a gemini-cli → .agents/skills/.
User-wide symlink if you prefer ~/.gemini/skills:
git clone https://github.com/eli-alvarado/us-watchlist-alerts ~/.gemini/us-watchlist-alerts
mkdir -p ~/.gemini/skills
for s in watchlist-manager price-alerts watchlist-brief; do
ln -sfn ~/.gemini/us-watchlist-alerts/skills/$s ~/.gemini/skills/$s
doneOr add @skills/price-alerts/SKILL.md (and the sibling skills) to GEMINI.md.
Any other agent
Load the three SKILL.md files as instructions, give the agent shell access to python3 scripts/... from the repo root, and run HEARTBEAT.md on your scheduler.
MCP server
Optional. The skill is still the primary interface. scripts/mcp_server.py is a stdlib JSON-RPC server over stdio (no pip packages, no API key). Tools: get_quotes, watchlist_list / watchlist_add / watchlist_remove, run_alerts, morning_brief, market_status, movers, gappers. Claude Code plugin users get it automatically via mcpServers in .claude-plugin/plugin.json.
The stdio transport is newline-delimited JSON: one compact JSON-RPC message per line, no Content-Length headers. Replies go to stdout; logs go to stderr. Claude Desktop, Cursor, and Codex speak that dialect — the snippets below are enough (no extra framing flags).
Claude Desktop (claude_desktop_config.json) and Cursor (.cursor/mcp.json or Settings → MCP):
{
"mcpServers": {
"us-watchlist-alerts": {
"command": "python3",
"args": ["/path/to/us-watchlist-alerts/scripts/mcp_server.py"]
}
}
}Codex (~/.codex/config.toml):
[mcp_servers.us-watchlist-alerts]
command = "python3"
args = ["/path/to/us-watchlist-alerts/scripts/mcp_server.py"]Registry metadata: smithery.yaml, server.json, glama.json. Never places trades.
Docker
Glama builds the repo-root Dockerfile and speaks MCP over stdin to run initialize and tools/list. Those two methods are catalog-only — they do not fetch quotes and work offline. Locally:
docker build -t us-watchlist-alerts-mcp .
docker run -i us-watchlist-alerts-mcpSame stdio NDJSON as python3 scripts/mcp_server.py. No extra packages; the image is python:3.12-slim plus this repo.
Scheduling
This repo also runs a public sample on weekdays via .github/workflows/live.yml — session-aware, no secrets. Every run writes the job summary. Dated files go to the live-snapshots branch (never main), at most one per ET weekday. Index: docs/live/.
One-command always-on: python3 scripts/schedule.py (see Get alerts on your phone). That is weekday cron every 5 minutes plus a notify sink. HEARTBEAT.md is the same loop if an agent session is open.
Manual cron (times in ET) if you would rather write the lines yourself:
CRON_TZ=America/New_York
*/5 * * * 1-5 cd ~/us-watchlist-alerts && python3 scripts/alerts.py --notify >> alerts.log
45 8 * * 1-5 cd ~/us-watchlist-alerts && python3 scripts/brief.py --kind morning
10 16 * * 1-5 cd ~/us-watchlist-alerts && python3 scripts/brief.py --kind closealerts.py skips weekends, regular NYSE holidays, dates in data/holidays_overrides.json, settings.extra_closures / NYSE_EXTRA_CLOSURES, and (when Alpaca keys are set) weekdays missing from Alpaca's official calendar. That overlay is disk-cached for the ET day (.nyse_calendar_cache.json) so a 15-minute cron does not call /v2/calendar every tick.
Alert delivery (no auto-trade)
Push new alerts off-box without involving a broker:
export WATCHLIST_NOTIFY=ntfy,slack # any of: webhook, slack, ntfy, desktop, file
export NTFY_TOPIC=my-watchlist # default host https://ntfy.sh ; optional NTFY_URL / NTFY_TOKEN
export SLACK_WEBHOOK_URL=https://hooks.slack.com/services/...
python3 scripts/alerts.py --notify # or pass --notify ntfySink | Env | Notes |
|
| JSON POST |
|
| Incoming webhook |
|
| Phone / desktop via ntfy |
| — | Linux |
|
| JSONL, good for tests and local logs |
A downed sink prints WARN notify … and the rest still run. This is not order routing.
Multiple watchlists
WATCHLIST_FILE already picks the list; give each profile its own state file so latches do not collide:
WATCHLIST_FILE=swing.json ALERT_STATE_FILE=.alert_state_swing.json python3 scripts/alerts.py --notify
WATCHLIST_FILE=long.json ALERT_STATE_FILE=.alert_state_long.json python3 scripts/alerts.py --notifyConfiguration
Env var | Purpose |
| Watchlist path. Default: |
| Cooldown state (default: |
| Quote fixture path (same as |
| Set to |
|
|
| Seconds before a regular-session quote is flagged stale (default |
| HTTP timeout seconds (default |
| Comma-separated ISO dates for unscheduled full-day closures |
| Official calendar cache path (default |
| Comma-separated sinks: |
| Generic JSON webhook |
| Slack incoming webhook |
| ntfy topic, server (default |
| JSONL path for the |
| Official Alpaca snapshot + daily bars + trading calendar |
| Trading API host for the calendar (default |
| Optional Finnhub quotes, candles, and earnings calendar |
| Optional Alpha Vantage daily history and earnings calendar |
Watchlist settings: cooldown_minutes, rearm_pct, sessions (regular/pre/after), volume_spike_multiple, near_52w_pct, earnings_days, max_alerts_per_run, extra_closures, stale_after_seconds.
Quote fallback order
For provider=auto, first success wins:
--fixture/$WATCHLIST_FIXTURE(tests and the demo GIF)Alpaca snapshot + daily bars if both API keys are set (official US feed; history included)
yfinance if installed
Yahoo public chart API (
query1, thenquery2) — unofficial, stdlib, best-effortFinnhub quote + candles if
FINNHUB_API_KEYis setAlpha Vantage daily if
ALPHAVANTAGE_API_KEYis set
Earnings dates are filled separately (Yahoo calendarEvents with crumb/cookie, then quote HTML, then Nasdaq analyst earnings-date, then Finnhub/AV if keyed) so earnings_within works without yfinance. ATM IV uses the same crumb, then yfinance if installed. Failures set earnings_error / iv_error and print a WARN — they do not invent values. HTTP calls retry 429/5xx; quote failures are QuoteErrors with a provider and hint.
Details: docs/LIMITATIONS.md.
How the anti-spam works
Level alerts (price, stop, target, RSI, ATM IV) latch after firing and re-arm only after the condition clears (price/IV hysteresis via
rearm_pctfor price levels).Each target is its own latch, so hitting T1 does not hide T2.
Event alerts (gaps, % moves, volume, crosses, 52-week highs/lows, earnings, intraday range / opt-in session extremes) fire at most once per session date of the data shown. Overnight and pre-open ticks (last-close mode) key on the previous session, so they do not re-fire yesterday’s daily events as “today.”
Default % checks are last vs prior close.
pct_change_down: 3ignores a session low that recovered. Opt-inintraday_low_pct/intraday_extreme_pctif you want the extreme.A cooldown applies to every re-fire.
max_alerts_per_runcaps what is printed; omitted alerts are not latched, so the next run can emit them.
Limitations
Unscheduled closures use a bundled list (
data/holidays_overrides.json, incomplete), plus env/settings overrides, plus an optional Alpaca official calendar overlay (day-cached). The rule-based table still does not invent mourning days on its own.Earnings dates no longer require yfinance, but Yahoo/Finnhub/AV calendars can be wrong or empty. Confirm against issuer IR.
The Yahoo chart / quoteSummary / options endpoints are unofficial and best-effort. They can change, rate-limit, or return delayed quotes (~15 minutes). ATM IV is nearest-expiry only; there is no IV rank.
intraday_range_pctandintraday_*_pctneed providerday_high/day_low. They will not fake a range from the daily close series.pct_change_*still uses last vs prior close only.Alpaca/Finnhub history depends on bars/candles succeeding; if those calls fail, MA/RSI/52-week rules will not fire even though the last price is present.
US-listed equities and ETFs only. No order routing.
notify-sendis Linux-only; use ntfy on macOS/Windows.
Full write-up: docs/LIMITATIONS.md. Changelog: CHANGELOG.md. Keys and notify URLs: SECURITY.md. Weekday public sample: docs/live/ (dated files on live-snapshots).
Comparison
This repo is a watchlist heartbeat: schema + NYSE session gate + anti-spam alerts + briefs. The projects below overlap on "finance + agents" but solve different jobs.
us-watchlist-alerts | |||||
Job | Watchlist, price alerts, morning/close brief | ~70 research, screening, journal, backtest skills | ~25 analysis skills (valuation, earnings, social, yfinance) | Per-source data skills and broker execution | Monitor daemon with 7 alert rules |
Markets | US listed stocks/ETFs | Mostly US research | Global analysis | US + Argentina + global data | China A-shares, futures, gold |
Default data | Stdlib Yahoo chart; Alpaca official if keyed; optional yfinance / Finnhub / AV | Many screeners want FMP or FinViz Elite | yfinance + various APIs | One skill per vendor; keys vary | A-share feeds |
Auto-trade | Never (hard rule in every skill) | Research / discipline, not a 15-min alerter | Analysis, not latching alerts | Places Alpaca orders | Alerts only |
Session logic | NYSE hours, early closes, holidays, extra closures | Not this repo's job | Not this repo's job | Alpaca calendar inside the trading skill | Beijing time, A-share sessions |
Anti-spam | Latch + rearm + once-per-day + cooldown | n/a | n/a | n/a | Severity tiers + polling |
China / A-shares | No | No | No | No | Yes (this US repo was inspired by that shape) |
Use tradermonty or himself65 for research. Use gauss314 when you intentionally want a broker skill. Use chjm-ai for A-shares. Use this when you want a tiny, keyed-optional US list that an agent can check on a timer without spamming you or firing orders.
Tests and CI
python3 -m unittest discover -s testsNo network, no extra pip packages. GitHub Actions runs that command on Python 3.10, 3.11, 3.12 and 3.13, plus a Docker job that builds the image and pipes initialize + tools/list into an isolated docker run -i.
Contributing and growth
CONTRIBUTING.md — tests, PR bar, good first issues
GROWTH_PLAN.md — marketplaces, awesome-lists, launch posts, v0.4
MIT © 2026 Eli Alvarado
This server cannot be deployed
Maintenance
Related MCP Connectors
TradeOS MCP: ticker search, My Agent, chart TA, macro news. npm stdio or HTTP.
Stock watchlist alerts: 8-K filings, volume spikes, big moves, gaps, upcoming earnings. Read-only.
MCP for Tradewink trading signals and watchlists. Not financial advice.
Query SEC EDGAR filings, XBRL financials, and company data via MCP. STDIO or Streamable HTTP.
Related MCP Servers
AlicenseNot gradedqualityFmaintenanceMCP server exposing the Haruspex stock-analysis API, headline scores (0-100), score history, batched watchlist scores, stock search, and recent news for US-listed1MIT- AlicenseAqualityCmaintenanceAn MCP server that lets an AI assistant read your pre-installed macOS Apple Stocks app — its watchlist and its cached quotes — and open symbols in the app to add them.135 npm2MIT
- AlicenseAqualityAmaintenanceGlobal stock search, preset screens, price history and technicals, dated company news, UCITS ETF/ISIN research, company risk and macro. Public research needs no API key; sign in for personal portfolios. Coverage and freshness are explicit.48MIT
- FlicenseNot gradedqualityDmaintenanceProvides live US stock quotes and historical price data via MCP tools.-