14. 监控与通知系统

14.监控与通知系统

实盘交易一旦启动,策略就开始在真实市场中自主决策。这时候,我们不可能一直盯着终端屏幕看每一笔交易。监控与通知系统就成了连接策略与我们的桥梁,它能在关键时刻把重要信息推送到手机上,让我们随时掌握策略的运行状态。Jesse 的通知系统设计得很实用,支持 Telegram、Discord 和 Slack 三大平台,还能在策略代码里自定义通知逻辑。

Telegram 机器人配置

Telegram 是国内量化交易者最常用的通知渠道。它免费、稳定,API 接口设计得相当友好。配置过程需要两步:创建一个机器人,然后获取用户 ID。

创建机器人并获取 Token

打开 Telegram,搜索 BotFather,这是官方提供的机器人管理工具。给 BotFather 发送 /newbot 命令,它会引导完成创建流程。需要给机器人起两个名字:一个是显示名称,可以包含中文和空格;另一个是用户名,必须是唯一的英文标识,以 bot 结尾。

创建成功后,BotFather 会返回一串 HTTP API Token,格式类似:

234325981:BBF5-H-FIdlfGVwXaSDfsAdy5A9_4uVsnH

这个 Token 就是机器人的身份凭证,务必保管好,不要泄露到公共代码仓库。拿到 Token 后,在 Jesse 项目根目录的 .env 文件里找到 GENERAL_TELEGRAM_BOT_TOKEN 字段,把 Token 粘贴进去。

GENERAL_TELEGRAM_BOT_TOKEN=234325981:BBF5-H-FIdlfGVwXaSDfsAdy5A9_4uVsnH

获取用户 ID 并授权

机器人创建好了,还需要告诉它把消息发给谁。这里需要的是用户 ID,不是用户名。用户 ID 是一串数字,每个 Telegram 账户都有唯一 ID。

获取方法很简单,搜索 getuseridbot,点击 /start,机器人会立刻返回用户 ID。把这串数字填到 .env 文件的 GENERAL_TELEGRAM_BOT_CHAT_ID 字段:

GENERAL_TELEGRAM_BOT_CHAT_ID=123456789

配置完成后,记得在 Telegram 里搜索刚才创建的机器人,点击 /start 按钮。这一步很关键,它授权机器人可以向我们的账户发送消息。如果没做这一步,机器人会因为没有权限而无法推送通知。

区分通用通知与错误通知

Jesse 的通知系统很贴心地把消息分成了两类:通用通知和错误通知。通用通知包括订单成交、策略信号等日常信息,错误通知专门处理异常、断线、API 错误等紧急情况。

在 .env 文件里可以配置两套独立的机器人:

# 通用通知
GENERAL_TELEGRAM_BOT_TOKEN=通用机器人Token
GENERAL_TELEGRAM_BOT_CHAT_ID=通用ChatID

# 错误通知(可选,但建议配置)
ERROR_TELEGRAM_BOT_TOKEN=错误机器人Token
ERROR_TELEGRAM_BOT_CHAT_ID=错误ChatID

分开配置的好处是,可以给错误通知设置更明显的提示音,或者把错误消息推送到另一个专门的群组,方便团队协作处理紧急情况。

Discord webhook 设置

Discord 在海外交易者中很流行,它的频道管理灵活,支持富文本格式,还能方便地组建团队讨论组。配置 Discord 通知不需要创建机器人,直接用 webhook 就能实现。

创建服务器和频道

如果还没有 Discord 服务器,先注册账号并创建一个。Discord 的服务器是免费的,创建过程很简单,按提示操作即可。

进入服务器后,创建一个新的文本频道,专门用来接收交易通知。右键点击频道名称,选择「编辑频道」,然后找到「集成」选项卡。在这里能看到「Webhooks」区域,点击「新建 Webhook」按钮。

配置 Webhook

给 webhook 起个名字,比如「Jesse 交易通知」,还可以上传一个图标方便识别。创建完成后,点击「复制 Webhook URL」按钮,得到类似这样的地址:

https://discord.com/api/webhooks/123456789012345678/abcdefghijklmnopqrstuvwxyz

这个 URL 就是 Discord 通知的入口,把它填到 .env 文件的 GENERAL_DISCORD_WEBHOOK 字段:

GENERAL_DISCORD_WEBHOOK=https://discord.com/api/webhooks/123456789012345678/abcdefghijklmnopqrstuvwxyz

和 Telegram 一样,Discord 也支持通用通知和错误通知分开配置:

GENERAL_DISCORD_WEBHOOK=通用通知Webhook
ERROR_DISCORD_WEBHOOK=错误通知Webhook

配置完成后,Jesse 会把通知以富文本格式发送到指定频道,订单信息、盈亏数据都会排版得很清晰。

Slack 集成

Slack 偏向企业级应用,如果团队已经在用 Slack 协作,把交易通知集成进来会很方便。它的配置比 Discord 稍微复杂一点,需要创建一个 App。

创建 Slack App

登录 Slack 工作区后,访问 Slack API 页面创建新应用。选择「从头开始创建」,给应用起个名字,比如「Jesse Trader」,然后选择要集成的工作区。

创建完成后,进入应用设置页面,找到「Incoming Webhooks」功能,把开关打开。页面会刷新,出现「Add New Webhook to Workspace」按钮,点击它。

授权并获取 Webhook URL

系统会提示选择要接收通知的频道,可以选择已有频道或新建一个。授权后,页面会生成一个 Webhook URL,格式如下:

https://hooks.slack.com/services/T00000000/B00000000/XXXXXXXXXXXXXXXXXXXXXXXX

把这个 URL 填到 .env 文件的 GENERAL_SLACK_WEBHOOK 字段:

GENERAL_SLACK_WEBHOOK=https://hooks.slack.com/services/T00000000/B00000000/XXXXXXXXXXXXXXXXXXXXXXXX

同样,错误通知可以单独配置:

ERROR_SLACK_WEBHOOK=https://hooks.slack.com/services/T00000000/B00000000/YYYYYYYYYYYYYYYYYYYYYYYY

Slack 的通知支持 Markdown 格式,可以显示更丰富的信息结构,适合需要详细数据分析的场景。

自定义通知渠道

预设的通知渠道覆盖了大多数需求,但有时候想在策略里发送更灵活的通知。比如,只在特定条件下报警,或者把不同策略的通知发到不同群组。Jesse 提供了 self.log() 方法,可以在策略代码里自由调用。

基础日志方法

在策略的 go() 方法或其他任何地方,都可以调用 self.log() 记录信息:

def go(self):
    # 策略逻辑...
    if self.position.is_open:
        self.log("当前持仓盈利: {}".format(self.position.pnl))

这段代码会在日志里记录持仓盈亏。默认情况下,self.log() 只在终端输出,不会发送通知。要启用通知推送,需要设置 send_notification=True:

self.log("突破信号出现,准备入场!", send_notification=True)

这样配置后,消息会发送到 .env 文件里配置的通用通知渠道。

区分日志级别

self.log() 支持两种日志级别:info 和 error。默认是 info,普通通知都归为此类。如果遇到严重问题,可以用 error 级别:

self.log("API连接失败,策略已暂停", log_type='error', send_notification=True)

错误日志会触发 .env 文件里配置的 ERROR_ 前缀的通知渠道,比如专门的错误处理机器人或频道。这种分级机制确保重要信息不会被日常通知淹没。

自定义 Webhook 地址

有时候想把不同策略的通知发到不同频道,而不是全部混在一起。self.log() 的 webhook 参数支持传入自定义 webhook 地址:

# 硬编码 webhook(不推荐,容易泄露)
self.log("策略A入场信号", send_notification=True, 
         webhook="https://discord.com/api/webhooks/...")

# 从环境变量读取(推荐)
self.log("策略B出场信号", send_notification=True, 
         webhook=self.env('STRATEGY_B_WEBHOOK'))

推荐把 webhook 地址写在 .env 文件里,通过 self.env() 读取。这样既安全又灵活,不同策略可以配置不同的通知目标:

# .env 文件
STRATEGY_A_TELEGRAM_TOKEN=...
STRATEGY_A_TELEGRAM_CHAT_ID=...
STRATEGY_B_DISCORD_WEBHOOK=...

然后在策略里这样使用:

def go(self):
    # 策略A的逻辑
    if self.some_entry_condition:
        self.log("策略A做多入场", send_notification=True,
                 webhook=self.env('STRATEGY_A_TELEGRAM_TOKEN'))
    
    # 策略B的逻辑
    if self.some_exit_condition:
        self.log("策略B止盈出场", send_notification=True,
                 webhook=self.env('STRATEGY_B_DISCORD_WEBHOOK'))

实际应用场景

自定义通知的典型用法是构建智能报警系统。比如,监控策略的回撤情况:

def before(self):
    # 在before里计算账户权益
    self.equity = self.balance + self.position.pnl

def go(self):
    # 检查是否从高点回撤超过10%
    if self.equity < self.vars.get('peak_equity', self.equity) * 0.9:
        self.log("警告:账户从高点回撤超过10%,当前权益:{}".format(self.equity),
                 log_type='error', send_notification=True)
    
    # 更新最高权益
    if self.equity > self.vars.get('peak_equity', 0):
        self.vars['peak_equity'] = self.equity

这段代码在策略里实现了简单的回撤监控,一旦触发阈值就发送错误级别的通知。由于是在 go() 方法里调用,每次 K 线更新都会检查,反应很及时。

另一个常见场景是跨策略通信。比如在配对交易策略中,一个策略开仓时通知另一个策略准备对冲:

def go(self):
    if self.pair_a_signal:
        self.log("配对A已开仓,准备对冲", send_notification=True,
                 webhook=self.env('PAIRS_TRADING_CHANNEL'))

这种机制让复杂的多策略协同变得可控,所有动作都有通知记录,方便事后复盘。

通知频率控制

要注意避免发送过多通知,特别是放在 go() 方法里的逻辑,每条 K 线都会执行一次。如果条件判断不严谨,可能会连续发送几十条相同消息。

好的做法是在 vars 里设置标志位,确保重要通知只发一次:

def go(self):
    # 检查重大事件
    if self.major_event_occurred and not self.vars.get('event_notified', False):
        self.log("重大事件发生!", send_notification=True)
        self.vars['event_notified'] = True  # 标记已通知

或者在 terminate() 方法里发送总结性通知,而不是在 go() 里频繁推送:

def terminate(self):
    # 策略结束时发送总结
    self.log("策略运行结束,总盈亏:{}".format(self.balance - self.initial_capital),
             send_notification=True)

terminate() 只在策略停止时调用一次,适合发送汇总信息,不会打扰到日常监控。

配置好通知系统后,实盘交易就有了「声音」。无论是日常成交记录,还是紧急错误报警,都能第一时间推送到眼前。下一章会讨论实盘环境的安全配置,通知系统让我们知道发生了什么,而安全措施能确保这些事情在受控的环境中发生。监控和安全,是实盘交易的两块基石。