diff --git a/app/crawlers/openinsider_top.py b/app/crawlers/openinsider_top.py index 51a5608..a0f6e86 100644 --- a/app/crawlers/openinsider_top.py +++ b/app/crawlers/openinsider_top.py @@ -161,14 +161,21 @@ class OpenInsiderTopCrawler(BaseCrawler): amount = self._parse_money(value_text) if amount is None or amount < self.min_amount: continue + # Normalize trade type tag for notification clarity + tag = self._trade_tag(trans_type) - title = f"{ticker} {trans_type} - {insider} qty {qty} @ {price} value ${amount:,} on {trade_date}" + title = f"[{tag}] {ticker} - {insider} qty {qty} @ {price} value ${amount:,} on {trade_date}" hash_src = f"{ticker}|{insider}|{trans_type}|{qty}|{price}|{trade_date}|{amount}|{url}" items.append({ 'title': title, 'link': url, 'scraped_at': datetime.now().isoformat(), 'hash': hashlib.md5(hash_src.encode('utf-8')).hexdigest()[:12], + 'trade_type': trans_type, + 'trade_tag': tag, + 'ticker': ticker, + 'amount': amount, + 'trade_date': trade_date, }) return items @@ -234,9 +241,30 @@ class OpenInsiderTopCrawler(BaseCrawler): subject = f"OpenInsider 當日大額內部人交易(≥${self.min_amount:,}) - {len(items)} 筆" lines = [] for it in items[:10]: - lines.append(f"• {it.get('title','')}") + tag = it.get('trade_tag') or 'TRADE' + ticker = it.get('ticker') or '' + amount = it.get('amount') + tdate = it.get('trade_date') or '' + if isinstance(amount, int): + line = f"• [{tag}] {ticker} ${amount:,} on {tdate}" + else: + line = f"• [{tag}] {it.get('title','')}" + lines.append(line) body = ( f"發現 {len(items)} 筆符合金額門檻的內部人交易(OpenInsider):\n\n" + "\n".join(lines) + "\n\n" f"抓取時間:{datetime.now().isoformat()}\n來源:\n- " + "\n- ".join(self.urls) ) return subject, body + + @staticmethod + def _trade_tag(trans_type: str) -> str: + t = (trans_type or '').lower() + if 'sale' in t or 'sell' in t: + return 'SALE' + if 'purchase' in t or 'buy' in t: + return 'BUY' + if 'option' in t: + return 'OPTION' + if 'gift' in t: + return 'GIFT' + return (trans_type or 'TRADE').upper()[:20]