How to use
- Copy the installation command and review the source package before installing it in your own agent environment.
- Check the source document for required tools, credentials and supported hosts.
- Describe your input and desired deliverable; review the output against the source material.
npx skills add https://github.com/eli-alvarado/us-watchlist-alerts --skill price-alertsBefore you start
- Installation does not include a model subscription, API allowance or permission to access your files.
- Repository stars and installation counts describe activity, not an independent quality or security test.
Rendered from the source repository. Headings, examples, code, tables, links, and referenced images are preserved.
Price Alerts (US markets)
Evaluates alert rules from the watchlist (see watchlist-manager) against fresh quotes and reports only new alerts. Not financial advice. Never place, modify or cancel orders - even if an alert fires, even if a broker tool is connected, unless the user explicitly confirms that specific order in this conversation.
scripts/ ships next to this SKILL.md (copied by npx skills add). Run from this skill folder, or from a git clone of the repo (root scripts/ is the same files).
Run it
python3 scripts/watchlist.py init # copy examples/watchlist.json if missing
python3 scripts/quickstart.py # offline fixture demo (labeled, not live)
python3 scripts/alerts.py --watchlist watchlist.json --state .alert_state.json # text output
python3 scripts/alerts.py --format json # machine-readable
python3 scripts/alerts.py --force-session # evaluate on weekends / holidays too
python3 scripts/alerts.py --dry-run # don't update cooldown state
python3 scripts/alerts.py --notify # also deliver via WATCHLIST_NOTIFY sinks
python3 scripts/market_calendar.py # current ET sessionOutput: ALERT <message> lines, or no new alerts, or market closed, showing last regular close after the bell (last regular print; no --force-session needed). Weekends and full-day holidays stay silent (market closed (weekend|holiday). Next session YYYY-MM-DD) unless --force-session. Data errors go to stderr as WARN (including earnings_error / iv_error). NOTIFY <sink> confirms delivery; sink failures are WARN notify … and must not abort the check. Never treat a notify sink as a broker.
Alert types
| type | value | fires when | kind |
|---|---|---|---|
price_above / price_below | price | last >= / <= value | level |
stop_hit | price (default: ticker stop) | long: last <= stop; short: last >= stop | level (implicit if stop set) |
target_hit | - | last crosses any targets entry | level (implicit if targets set) |
pct_change_up / pct_change_down / pct_move | % | last vs prior close (after hours: last regular close). A recovered session low does not fire | daily |
gap_up / gap_down | % (default 2) | open vs prior close | daily |
new_52w_high / new_52w_low | - | last beyond prior 252-session range | daily |
near_52w_high / near_52w_low | % (default settings.near52wpct) | within value% of 52w extreme | daily-ish (level latch) |
golden_cross / death_cross | fast, slow (50/200) | SMA fast crosses slow on latest bar | daily |
cross_above_ma / cross_below_ma | MA length (default 50) | last close crosses its SMA | daily |
rsi_above / rsi_below | RSI level; optional period (14) | Wilder RSI on daily closes | level |
iv_above / iv_below | IV percent | unofficial Yahoo ATM IV (nearest expiry); skip if missing/0 | level |
volume_spike | multiple (default 2.0) | today's volume >= value x 20-day avg | daily |
earnings_within | days (default 3) | next earnings date within N days | daily |
intraday_range_pct | % | (day_high-day_low)/prev_close; skip if high/low missing | daily |
intraday_low_pct / intraday_high_pct | % | opt-in session low/high vs prior close. Catches a −3% low that recovered into the close | daily |
intraday_extreme_pct | % | alias: expands to both intraday_low_pct and intraday_high_pct | daily |
Any rule may set cooldown_minutes to override settings.cooldown_minutes.
Default % checks use last print vs prior close (pct_change_* / pct_move). They do not look at the session high/low. If the user says “alert me if it drops 3% today” and they mean the print that traded through 3% even if it bounced, add intraday_low_pct (or intraday_extreme_pct). Do not add those unless they ask — they are opt-in.
Anti-spam rules (implemented in scripts/alerts.py, state in .alert_state.json)
- Level alerts latch: once fired they stay silent until price moves back through the level by
rearm_pct(default 0.5%). A stock hovering at $240 never pings repeatedly.iv_*rearms when ATM IV no longer breaches the threshold. - Daily-event alerts fire at most once per trading day per ticker/type.
- Cooldown (
cooldown_minutes, default 240) applies to every re-fire. - Cap of
max_alerts_per_run(default 20). Alerts past the cap are not written to state, so they can fire on the next run. If many fire, summarize ("7 alerts, 4 on TSLA") rather than dumping walls of text. - If the state file is missing or corrupt, start fresh but warn the user that duplicates are possible on this run.
- Each
targets[]level is its own latchedtarget_hit(T1 firing does not hide T2).
Market hours (America/NewYork, handled by `scripts/marketcalendar.py`)
- Pre-market 04:00-09:30, regular 09:30-16:00, after-hours 16:00-20:00 ET; early-close days (day after Thanksgiving, Christmas Eve, July 3 when a weekday) close 13:00 with after-hours to 17:00.
- NYSE holidays: New Year's (not observed when Saturday), MLK, Presidents', Good Friday, Memorial, Juneteenth, Independence, Labor, Thanksgiving, Christmas (Sat -> Fri, Sun -> Mon). Unscheduled closures: bundled
data/holidays_overrides.json,NYSE_EXTRA_CLOSURES/settings.extra_closures, and (with Alpaca keys) weekdays missing from the official calendar. Mention it if quotes look stale on a weekday the calendar thinks is open. settings.sessionscontrols when extended-hours quotes are treated as live. Default["regular"]. After the bell (or pre-open / overnight) on a trading day, the script still evaluates the last regular close and labelslast_close— you do not need--force-session. Add"pre"/"after"only if you want to treat extended-hours prints as the live session. Those quotes are thinner and free sources may lag.- Always state times in ET (add the user's local time if known, e.g. "10:05 ET / 9:05 CT").
Data sources (scripts/quotes.py, auto-fallback in this order)
--fixturepath, if given (tests/demos only).- Alpaca snapshot + daily bars, if
ALPACA_API_KEY_IDandALPACA_API_SECRET_KEYare set (official US feed). yfinanceif installed (pip install yfinance).- Yahoo public chart API (stdlib, unofficial, best-effort):
query1.finance.yahoo.com, thenquery2.prev_closeispreviousCloseor the prior aligned daily bar — after ~20:00 ET a today-row withclose: Noneis dropped, not treated as yesterday. - Finnhub quote + candles, if
FINNHUB_API_KEYis set. - Alpha Vantage daily, if
ALPHAVANTAGE_API_KEYis set.
Force one with --provider or WATCHLIST_PROVIDER. HTTP 429/5xx are retried; failures are tagged QuoteErrors (provider, HTTP status, hint). Free data can be delayed ~15 min; say so when precision matters.
Earnings dates are filled after the quote, first hit: existing field (yfinance/fixture) → Yahoo calendarEvents (cookie + crumb) → Yahoo quote HTML → Nasdaq analyst earnings-date (free, no key) → Finnhub / Alpha Vantage if keyed. earnings_source says which layer won; if none do, earnings_error prints a WARN.
Stale quotes: --stale-after / WATCHLIST_STALE_AFTER / settings.stale_after_seconds (default 900). During the regular session, warn if as_of is older than that. 0 disables.
ATM IV: only fetched for tickers with iv_above/iv_below. Unofficial Yahoo options chain (same crumb), then yfinance if installed. Nearest expiration, ATM call/put average as percent. Not IV rank. Failures set iv_error and print a WARN. python3 scripts/quotes.py AAPL --iv to inspect.
Notify (optional): WATCHLIST_NOTIFY=ntfy,slack,webhook,desktop,file and/or --notify. See README for env vars. Do not notify on empty/skipped/dry-run. Delivery errors stay warnings.
Known limits: unscheduled closures live in data/holidays_overrides.json (incomplete) plus env/settings plus an optional Alpaca official calendar overlay (day-cached). Yahoo endpoints are unofficial. See docs/LIMITATIONS.md.
MCP option: if an alpaca MCP server (alpacahq/alpaca-mcp-server) or tradingview MCP (atilaahmettaner/tradingview-mcp) is connected, you may use it for quotes/indicators instead of the scripts, then apply the exact same rules and anti-spam logic (read/write .alert_state.json in the same format). Use broker MCPs for read-only calls only.
Reporting format
🔔 3 new alerts (10:05 ET, regular session, data: yahoo, ~15m delayed)
- AAPL $241.50 is above $240.00 (thesis: services margin; stop $210, T1 $250)
- TSLA down -6.0% today, gapped down -5.0%, volume 3.0x avg
- TSLA reports earnings in 1 day (2026-10-16)Group by ticker, include the stored thesis/stop/target for context, no recommendations. If no alerts: one short line, or stay silent when running on a heartbeat (see HEARTBEAT.md).
Creating alerts from chat
"Alert me if AAPL drops below 200" -> python scripts/watchlist.py update AAPL --alert price_below:200 --append (add the ticker first if missing). Confirm the rule back in plain English.


