Automated Financial Alerts with Webhooks and LLMs
6 min read · Updated Jun 4, 2026
A good financial alert pipeline does two things and only two things: it watches a number, and it tells you when the number does something that matters. A bad one wakes you at 3 a.m. for a 0.4% wiggle in a price you do not care about. This guide builds the good kind — webhook trigger, LLM filter, Discord or Telegram delivery — with the four anti-noise filters that separate a system you keep running for a year from one you mute in week two.
Key takeaways
- Build the alert without the LLM first. Prove the trigger fires. Add intelligence second.
- The LLM’s job is to compress, not to predict. "Is this materially different from the last seven days, in two sentences" is the right prompt.
- Alert fatigue kills more alert systems than bugs do. Aim for fewer than 3 alerts per day per channel.
- Always deduplicate. The same news will trigger five providers in the same minute.
- Polygon.io free tier gives 5 API calls per minute (Polygon 2026 pricing page) — enough for one ticker every 12 seconds, which is plenty for swing-trade alerts.
The four moving parts of a usable alert pipeline
- Data source — Polygon.io, Alpha Vantage, Binance WebSocket, or a free RSS feed for news. Pick one with a free tier and well-documented rate limits.
- Trigger — a cron-style poll (every 1–5 minutes) or a webhook subscription if your provider pushes. Webhooks are nicer; polling is more universal.
- Filter — a deterministic rule (price move > 3%, volume > 2x 30-day average) plus an optional LLM second-pass that adds context.
- Delivery — Discord webhook, Telegram bot, or email. Pick one channel per alert class and never mix.
Picking a data source in 2026
| Source | Asset class | Free tier | Best for |
|---|---|---|---|
| Alpha Vantage | Stocks, FX, crypto | 25 calls/day, 5/min | Prototypes, light use |
| Polygon.io | Stocks, options, FX | 5 calls/min, 15-min delay | Equity alerts under 10 tickers |
| Binance API | Crypto spot + futures | 1,200 req/min weighted | Crypto, high-frequency |
| CoinGecko | Crypto | 30 calls/min demo | Cross-exchange crypto pricing |
| NewsAPI | News headlines | 100 req/day | Adding news context to price alerts |
The polling worker (Python, 40 lines)
import os, time, requests
from datetime import datetime
POLYGON_KEY = os.environ["POLYGON_API_KEY"]
DISCORD_WEBHOOK = os.environ["DISCORD_WEBHOOK_URL"]
TICKERS = ["AAPL", "MSFT", "NVDA"]
THRESHOLD_PCT = 3.0
SEEN = {}
def get_quote(ticker: str) -> dict:
url = f"https://api.polygon.io/v2/aggs/ticker/{ticker}/prev?apiKey={POLYGON_KEY}"
r = requests.get(url, timeout=5)
r.raise_for_status()
return r.json()["results"][0]
def post_alert(message: str) -> None:
requests.post(DISCORD_WEBHOOK, json={"content": message}, timeout=5)
while True:
for t in TICKERS:
try:
q = get_quote(t)
change_pct = ((q["c"] - q["o"]) / q["o"]) * 100
if abs(change_pct) >= THRESHOLD_PCT and SEEN.get(t) != q["c"]:
SEEN[t] = q["c"]
post_alert(f"{t}: {change_pct:+.2f}% (close ${q[\"c\"]:.2f})")
except Exception as err:
print(f"{t} failed: {err}")
time.sleep(15) # respect the 5/min free tier
time.sleep(60)This is the boring version. It works. It posts to Discord. It dedupes on closing price. It respects the Polygon 5-calls-per-minute limit. Run it for a week before adding the LLM — you will discover that 3% on AAPL almost never fires, while 3% on a small-cap fires three times an hour. The threshold is the actual product.
Adding the LLM filter (the part that earns its keep)
Once the dumb alert is firing reliably, add a second pass. Take the last 7 days of closing prices plus the top 3 news headlines for the ticker, and ask the LLM one question: "is today materially different from the last seven days, and in two sentences, why." The model writes the alert body, not the trigger condition. Keep the deterministic rule in front; the LLM is decoration.
from openai import OpenAI
client = OpenAI()
def summarise_move(ticker: str, history: list[float], headlines: list[str]) -> str:
prompt = f"""Ticker: {ticker}
Last 7 daily closes: {history}
Top headlines today:
- {chr(10).join(headlines)}
In at most two sentences, say whether today\u2019s move is
materially different from the prior 7 sessions and what the most
likely driver is. If you cannot tell, say \"unclear.\""""
resp = client.chat.completions.create(
model="gpt-4o-mini",
messages=[{"role": "user", "content": prompt}],
max_tokens=120,
temperature=0.2,
)
return resp.choices[0].message.content.strip()Delivery: Discord vs Telegram vs email
Discord webhooks are the easiest — paste a URL, POST a JSON body, done. Telegram needs a bot token but supports inline buttons for one-tap actions. Email is the most reliable but the least readable for high-frequency alerts. My rule: Discord for monitoring (high volume, scan past quickly), Telegram for the two or three alerts you actually act on, email for end-of-day digests. Mixing classes on one channel is how alert fatigue starts.
The four anti-noise filters that keep the system useful
- Dedupe window — once an alert fires for a ticker, suppress further alerts for that ticker for 60 minutes. Otherwise one volatile session becomes 40 messages.
- Time-of-day gate — do not alert outside your trading hours. A 4 a.m. notification you cannot act on is just bad sleep.
- Volume guard — a 5% move on 1,000 shares means nothing. Require volume > 2x the 30-day average before firing.
- Daily cap — cap the system at 5 alerts per channel per day. If the cap fires, your threshold is wrong, not the market.
The story that taught me to add the daily cap
March 2024, a Wednesday morning, two days after I shipped a crypto alert pipeline for a small trading group. The Bitcoin price did a normal 4% intraday wiggle. My pipeline had no daily cap, a 2.5% threshold, no dedupe window, and three different exchanges all sending the same event. Between 9:14 a.m. and 11:02 a.m. the Discord channel got 73 alerts. By alert 20 everyone had muted the channel. By alert 50 two people had left the group. The pipeline kept working perfectly for the next six months and nobody saw a single message because the channel stayed muted forever. The fix took an hour: a Redis sorted set with a 60-minute window per ticker, plus a hard daily cap. The lesson — your alert system is competing with the user’s attention, and you only get one chance to lose it.
The no-code path: n8n for the same pipeline
If writing the Python worker is more than you want, n8n ships every primitive you need: HTTP Request node (Polygon), IF node (threshold), Function node (dedupe), OpenAI node (LLM filter), Discord and Telegram nodes (delivery), and the Cron trigger. The whole pipeline is a 7-node workflow that runs on the n8n free tier or a $20/month cloud instance. See the deeper webhook patterns in webhook automation.
“Alerts are a UX problem with a data pipeline underneath. The trigger is the easy part — the discipline is in what you choose not to send.”
Always do your own research. This pipeline notifies you that something happened. It does not buy or sell, and it should not.
Frequently asked questions
Frequently asked questions
What is the best free API for stock market alerts?
For under 10 tickers and 15-minute delayed data, Polygon.io free tier is the cleanest. For tighter rate limits but global FX coverage, Alpha Vantage. For real-time crypto, Binance public REST and WebSocket APIs are both free and well documented.
How much does it cost to run an AI-filtered alert pipeline?
For 100 alerts a day going through GPT-4o-mini at ~500 tokens each, expect under $0.50 a month in LLM costs. Hosting on a $5 VPS or n8n free tier covers the trigger. Most personal alert setups run for under $10 a month all in.
Can I use AI alerts for automated trading?
This guide deliberately stops at the notification step. Automating trades adds a long tail of regulatory, risk-management, and broker-integration concerns that are outside the scope of an alert pipeline. Notifications are the safe entry point.
How do I stop my alert channel from getting spammed?
Three filters do most of the work: a 60-minute per-ticker dedupe window, a volume guard (only fire when volume is at least 2x the 30-day average), and a hard daily cap. Without all three, every volatile session becomes an unread channel.
Should the LLM decide whether to fire an alert?
No. The LLM writes the alert body once a deterministic rule has fired. Asking the model whether to fire makes the system non-debuggable, expensive per check, and prone to hallucinated alerts.
How do I add news context to a price alert?
On alert fire, hit NewsAPI or RSS for the top 3 headlines containing the ticker symbol, prepend them to the LLM prompt that summarises the move, and the model returns a two-sentence "what is going on" string for the alert body. The whole add-on is about 30 lines of code.