summaryrefslogtreecommitdiff
path: root/main.py
diff options
context:
space:
mode:
authorBen Sima <ben@bensima.com>2026-05-18 13:54:55 -0400
committerBen Sima <ben@bensima.com>2026-05-18 13:54:55 -0400
commit06b08dbbcb4b234a94be189f855ce5fec4c5c37b (patch)
treea42f84919ca1e3ba7e19be634e3fd2e10d0d5bc6 /main.py
init: slopbot scaffold
Diffstat (limited to 'main.py')
-rw-r--r--main.py67
1 files changed, 67 insertions, 0 deletions
diff --git a/main.py b/main.py
new file mode 100644
index 0000000..8fe9d24
--- /dev/null
+++ b/main.py
@@ -0,0 +1,67 @@
+#!/usr/bin/env python3
+"""
+slopbot - Zulip bot that replies with stock prices when it sees $TICKER patterns.
+
+Usage:
+ python main.py
+
+Requires a .zuliprc file in the same directory (see .zuliprc.example).
+"""
+
+import re
+import zulip
+import yfinance as yf
+
+# Regex to match stock tickers like $NVDA, $AAPL, $BRK
+TICKER_RE = re.compile(r'\$([A-Z]{1,5})')
+
+
+def fetch_price(ticker: str) -> str:
+ """Return a formatted price string for a ticker, or an error message."""
+ try:
+ info = yf.Ticker(ticker).fast_info
+ price = info["lastPrice"]
+ return f"${ticker}: ${price:,.2f}"
+ except Exception as e:
+ return f"${ticker}: couldn't fetch price ({e})"
+
+
+def handle_event(event: dict, client: zulip.Client) -> None:
+ """Process a Zulip event and reply if tickers are found."""
+ if event.get("type") != "message":
+ return
+
+ msg = event["message"]
+
+ # Don't reply to ourselves
+ if msg["sender_email"] == client.email:
+ return
+
+ content = msg.get("content", "")
+ tickers = TICKER_RE.findall(content.upper())
+
+ if not tickers:
+ return
+
+ lines = [fetch_price(t) for t in dict.fromkeys(tickers)] # dedup, preserve order
+ reply = "\n".join(lines)
+
+ client.send_message({
+ "type": msg["type"], # "stream" or "private"
+ "to": msg["stream_id"] if msg["type"] == "stream" else msg["sender_email"],
+ "topic": msg.get("subject", ""),
+ "content": reply,
+ })
+
+
+def main():
+ client = zulip.Client(config_file=".zuliprc")
+ print(f"slopbot running as {client.email} ...")
+ client.call_on_each_event(
+ lambda event: handle_event(event, client),
+ event_types=["message"],
+ )
+
+
+if __name__ == "__main__":
+ main()