summaryrefslogtreecommitdiff
path: root/main.py
blob: ae862a32cce0007cf3bf53a5965ccd255c3e0d66 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
#!/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})')

client = zulip.Client(config_file='.zuliprc')


def fetch_price(ticker: str) -> str:
    """Return a formatted price string for a ticker, or an error message."""
    try:
        price = yf.Ticker(ticker).fast_info['lastPrice']
        return f"${ticker}: ${price:,.2f}"
    except Exception as e:
        return f"${ticker}: unavailable ({e})"


def handle_event(event: dict) -> 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"],
        "to": msg["stream_id"] if msg["type"] == "stream" else msg["sender_email"],
        "topic": msg.get("subject", ""),
        "content": reply,
    })


client.call_on_each_event(handle_event, event_types=["message"])