|
16 | 16 | except ImportError: |
17 | 17 | compute_v1 = None |
18 | 18 |
|
| 19 | +from notifications.telegram import build_translator, send_telegram_message |
19 | 20 | from quant_platform_kit.common.models import OrderIntent |
20 | 21 | from quant_platform_kit.ibkr import ( |
21 | 22 | connect_ib as ibkr_connect_ib, |
@@ -164,79 +165,17 @@ def get_ib_port(): |
164 | 165 |
|
165 | 166 | SEPARATOR = "━━━━━━━━━━━━━━━━━━" |
166 | 167 |
|
167 | | -# --------------------------------------------------------------------------- |
168 | | -# i18n |
169 | | -# --------------------------------------------------------------------------- |
170 | | -I18N = { |
171 | | - "zh": { |
172 | | - "rebalance_title": "🔔 【调仓指令】", |
173 | | - "heartbeat_title": "💓 【心跳检测】", |
174 | | - "error_title": "🚨 【策略异常】", |
175 | | - "canary_title": "🐤 【金丝雀检查】", |
176 | | - "equity": "净值", |
177 | | - "buying_power": "购买力", |
178 | | - "signal_label": "信号", |
179 | | - "no_trades": "✅ 无需调仓", |
180 | | - "emergency": "🛡️ 金丝雀应急: {n_bad}/4 坏, 全部转入 {safe}", |
181 | | - "quarterly": "📊 季度调仓: Top {n} 轮动", |
182 | | - "daily_check": "📋 每日检查: 金丝雀正常, 持仓不变", |
183 | | - "hold": "💎 持仓不变", |
184 | | - "market_sell": "📉 [市价卖出] {symbol}: {qty}股", |
185 | | - "limit_buy": "📈 [限价买入] {symbol}: {qty}股 @ ${price}", |
186 | | - "submitted": "已下发 (ID: {order_id})", |
187 | | - "failed": "失败: {reason}", |
188 | | - "order_filled": "✅ 订单成交 | {symbol} {side} {qty}股 均价 ${price} (ID: {order_id})", |
189 | | - "order_partial": "⚠️ 部分成交 | {symbol} {side} {executed}/{qty}股 均价 ${price} (ID: {order_id})", |
190 | | - "order_rejected": "❌ 订单异常 | {symbol} {side} {qty}股 状态: {status} (ID: {order_id})", |
191 | | - }, |
192 | | - "en": { |
193 | | - "rebalance_title": "🔔 【Trade Execution Report】", |
194 | | - "heartbeat_title": "💓 【Heartbeat】", |
195 | | - "error_title": "🚨 【Strategy Error】", |
196 | | - "canary_title": "🐤 【Canary Check】", |
197 | | - "equity": "Equity", |
198 | | - "buying_power": "Buying Power", |
199 | | - "signal_label": "Signal", |
200 | | - "no_trades": "✅ No rebalance needed", |
201 | | - "emergency": "🛡️ Canary Emergency: {n_bad}/4 bad, rotating to {safe}", |
202 | | - "quarterly": "📊 Quarterly Rebalance: Top {n} rotation", |
203 | | - "daily_check": "📋 Daily Check: canary OK, holding", |
204 | | - "hold": "💎 Hold positions", |
205 | | - "market_sell": "📉 [Market sell] {symbol}: {qty} shares", |
206 | | - "limit_buy": "📈 [Limit buy] {symbol}: {qty} shares @ ${price}", |
207 | | - "submitted": "submitted (ID: {order_id})", |
208 | | - "failed": "failed: {reason}", |
209 | | - "order_filled": "✅ Filled | {symbol} {side} {qty} shares avg ${price} (ID: {order_id})", |
210 | | - "order_partial": "⚠️ Partial | {symbol} {side} {executed}/{qty} shares avg ${price} (ID: {order_id})", |
211 | | - "order_rejected": "❌ Rejected | {symbol} {side} {qty} shares status: {status} (ID: {order_id})", |
212 | | - }, |
213 | | -} |
214 | | - |
215 | | - |
216 | 168 | def t(key, **kwargs): |
217 | | - lang = NOTIFY_LANG if NOTIFY_LANG in I18N else "en" |
218 | | - template = I18N[lang].get(key, key) |
219 | | - return template.format(**kwargs) if kwargs else template |
| 169 | + return build_translator(NOTIFY_LANG)(key, **kwargs) |
220 | 170 |
|
221 | 171 |
|
222 | 172 | def send_tg_message(message): |
223 | | - if not TG_TOKEN or not TG_CHAT_ID: |
224 | | - return |
225 | | - url = f"https://api.telegram.org/bot{TG_TOKEN}/sendMessage" |
226 | | - try: |
227 | | - print(f"TG:\n{message}", flush=True) |
228 | | - response = requests.post( |
229 | | - url, |
230 | | - json={"chat_id": TG_CHAT_ID, "text": message}, |
231 | | - timeout=10, |
232 | | - ) |
233 | | - if not 200 <= response.status_code < 300: |
234 | | - print( |
235 | | - f"Telegram send failed with status {response.status_code}: {response.text}", |
236 | | - flush=True, |
237 | | - ) |
238 | | - except Exception as e: |
239 | | - print(f"Telegram send failed: {e}", flush=True) |
| 173 | + return send_telegram_message( |
| 174 | + message, |
| 175 | + token=TG_TOKEN, |
| 176 | + chat_id=TG_CHAT_ID, |
| 177 | + requests_module=requests, |
| 178 | + ) |
240 | 179 |
|
241 | 180 |
|
242 | 181 | def connect_ib(): |
|
0 commit comments