prabalGaur commited on
Commit
eb1355a
Β·
verified Β·
1 Parent(s): 2fdcf6c

Upload community_contributions/chrys/agents/notifier.py with huggingface_hub

Browse files
community_contributions/chrys/agents/notifier.py ADDED
@@ -0,0 +1,98 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """NOTIFIER agent: format and send Pushover push."""
2
+ import time
3
+ from typing import List
4
+
5
+ import requests
6
+ from agents.base import AgentBase
7
+ from models import AlertPayload, TechResult, SentimentResult, DecisionRecord, AssetData
8
+
9
+ PUSHOVER_URL = "https://api.pushover.net/1/messages.json"
10
+
11
+
12
+ def _build_key_signals(tr: TechResult, asset_data: AssetData | None) -> List[str]:
13
+ signals = []
14
+ if tr.rsi and tr.rsi < 30:
15
+ signals.append(f"RSI at {tr.rsi} β€” deeply oversold")
16
+ elif tr.rsi and tr.rsi > 70:
17
+ signals.append(f"RSI at {tr.rsi} β€” overbought")
18
+ if tr.macd_signal == "BULLISH_CROSS":
19
+ signals.append("MACD bullish crossover confirmed")
20
+ elif tr.macd_signal == "BEARISH_CROSS":
21
+ signals.append("MACD bearish crossover")
22
+ if tr.bb_signal == "LOWER_BAND_BOUNCE":
23
+ signals.append("Price at lower Bollinger Band β€” bounce signal")
24
+ if tr.ema_cross == "GOLDEN_CROSS":
25
+ signals.append("9 EMA crossed above 21 EMA (golden cross)")
26
+ if tr.volume_spike and asset_data:
27
+ signals.append(f"Volume {asset_data.volume_ratio}x above 20-day average")
28
+ if not signals:
29
+ signals.append("Technical signals reviewed")
30
+ return signals[:5]
31
+
32
+
33
+ class NotifierAgent(AgentBase):
34
+ name = "NOTIFIER"
35
+ logger_name = "aria.notifier"
36
+
37
+ def __init__(self, user: str = "", token: str = ""):
38
+ super().__init__()
39
+ self.user = user
40
+ self.token = token
41
+
42
+ def build_payload(self, record: DecisionRecord, tech: TechResult, sent: SentimentResult | None, asset_data: AssetData | None) -> AlertPayload:
43
+ key_signals = _build_key_signals(tech, asset_data)
44
+ return AlertPayload(
45
+ asset=record.asset,
46
+ bias=tech.bias,
47
+ price=asset_data.price if asset_data else 0,
48
+ change_24h=asset_data.change_24h if asset_data else "",
49
+ tech_score=record.tech_score,
50
+ sentiment=record.sentiment,
51
+ narrative=sent.narrative if sent else "",
52
+ final_score=record.final_score,
53
+ key_signals=key_signals,
54
+ )
55
+
56
+ def send(self, payload: AlertPayload, priority: int) -> bool:
57
+ if not self.user or not self.token:
58
+ self.log("Pushover not configured; skipping send")
59
+ return False
60
+ title = f"🚨 {payload.bias} Alert: {payload.asset}"
61
+ body = (
62
+ f"πŸ“ˆ {payload.asset} is flashing a {payload.bias} signal.\n\n"
63
+ f"πŸ’° Price: ${payload.price:,.2f} ({payload.change_24h} in 24h)\n"
64
+ f"πŸ“Š Tech Score: {payload.tech_score}/100\n"
65
+ f"πŸ—žοΈ Sentiment: {payload.sentiment} β€” \"{payload.narrative}\"\n"
66
+ f"πŸ”’ Opportunity Score: {payload.final_score}/100\n\n"
67
+ "πŸ“‰ Key Signals:\n" + "\n".join(f"β€’ {s}" for s in payload.key_signals) + "\n\n"
68
+ "⚠️ This is a trend alert, not financial advice. Always apply your own judgment."
69
+ )
70
+ data = {
71
+ "token": self.token,
72
+ "user": self.user,
73
+ "title": title,
74
+ "message": body[:1024],
75
+ "priority": priority,
76
+ "sound": "cashregister",
77
+ }
78
+ if priority == 2:
79
+ data["retry"] = 30
80
+ data["expire"] = 300
81
+ for attempt in range(2):
82
+ try:
83
+ r = requests.post(PUSHOVER_URL, json=data, timeout=10)
84
+ if r.status_code == 200:
85
+ self.log("Push sent successfully")
86
+ return True
87
+ self.log(f"Pushover error {r.status_code}: {r.text}")
88
+ except Exception as e:
89
+ self.log(f"Push failed: {e}")
90
+ if attempt == 0:
91
+ time.sleep(5)
92
+ return False
93
+
94
+ def run(self, to_send: List[tuple[DecisionRecord, TechResult, SentimentResult | None, AssetData | None]]) -> None:
95
+ self.log(f"Sending {len(to_send)} alert(s)")
96
+ for record, tech, sent, asset_data in to_send:
97
+ payload = self.build_payload(record, tech, sent, asset_data)
98
+ self.send(payload, record.priority)