问题描述
解决方案
在PTrade中,想要在触发交易信号或完成订单后主动发送邮件通知,主要有两种方式。
特别注意:
- 实盘环境限制:邮件发送功能通常仅在**交易(实盘/模拟盘)**模式下可用,回测模式下通常不支持。
- 券商权限:PTrade是部署在券商内网的,出于安全考虑,券商通常会限制外网访问。因此,能否发送邮件取决于券商是否开通了邮件服务端口或是否允许访问外部SMTP服务器。
- API支持:PTrade提供了内置的邮件API,但部分券商版本可能仅支持报错时自动发送,不支持主动调用发送自定义内容。
以下是两种实现方案的代码示例:
方案一:使用 PTrade 内置 API(推荐尝试)
PTrade 提供了 set_email_info 用于配置发件箱,以及 send_email 用于发送内容。
- 优点:集成在框架内,如果券商支持,配置最简单。
- 缺点:文档中提到
set_email_info主要用于“交易异常终止提醒”,部分券商可能未开放主动调用send_email的权限。且通常仅支持QQ邮箱。
def initialize(context):
g.security = '600570.SS'
set_universe(g.security)
# 1. 配置邮件信息
# 参数1: 邮箱地址 (通常仅支持QQ邮箱,且发件人和收件人一致)
# 参数2: 邮箱SMTP授权码 (不是QQ密码,需在QQ邮箱设置中开启SMTP获取)
# 参数3: 邮件默认主题
# 注意:需咨询券商是否支持此功能
set_email_info("[email protected]", "your_smtp_auth_code", "【PTrade策略通知】")
def handle_data(context, data):
# 示例:简单的均线策略触发交易
# 获取收盘价
close_price = data[g.security]['close']
# 假设触发买入信号
if close_price > 0:
# 下单
order(g.security, 100)
# 2. 尝试主动发送邮件通知
# 注意:send_email 接口在部分券商版本中可能不可用或仅在tick_data中可用
# 如果直接调用报错,说明券商未开放此接口
try:
msg = "触发买入信号: %s, 价格: %f, 时间: %s" % (
g.security,
close_price,
context.blotter.current_dt
)
# 调用内置发送接口
send_email(msg)
log.info("邮件发送指令已发出")
except Exception as e:
log.info("发送邮件失败,可能是券商未开放权限: %s" % e)
# 也可以在成交回报中发送邮件(速度更快)
def on_trade_response(context, trade_list):
if trade_list:
try:
content = "订单已成交: %s" % str(trade_list)
send_email(content)
except:
pass
方案二:使用 Python 标准库 smtplib(通用方案)
如果内置API无法使用,可以尝试使用Python原生的 smtplib 库。
- 优点:完全自定义,不依赖PTrade特定API接口。
- 缺点:极大概率被防火墙拦截。因为PTrade服务器通常在内网,无法连接
smtp.qq.com等外部服务器的25或465端口。如果你的PTrade环境允许访问外网,此方法才有效。
import smtplib
from email.mime.text import MIMEText
from email.header import Header
def initialize(context):
g.security = '600570.SS'
set_universe(g.security)
# 配置邮箱信息
g.mail_host = "smtp.qq.com" # SMTP服务器
g.mail_user = "[email protected]" # 用户名
g.mail_pass = "your_auth_code" # 授权码
g.sender = "[email protected]"
g.receivers = ["[email protected]"]
def send_custom_email(subject, content):
"""
自定义发送邮件函数
"""
message = MIMEText(content, 'plain', 'utf-8')
message['From'] = Header("PTrade策略", 'utf-8')
message['To'] = Header("交易员", 'utf-8')
message['Subject'] = Header(subject, 'utf-8')
try:
# 尝试连接SMTP服务器
# 注意:很多券商环境封锁了外部端口,这里可能会超时或报错
smtpObj = smtplib.SMTP_SSL(g.mail_host, 465)
smtpObj.login(g.mail_user, g.mail_pass)
smtpObj.sendmail(g.sender, g.receivers, message.as_string())
smtpObj.quit()
log.info("邮件发送成功")
except Exception as e:
log.error("邮件发送失败: %s" % e)
def handle_data(context, data):
# 示例交易逻辑
if True: # 模拟触发
order(g.security, 100)
# 调用自定义发送函数
send_custom_email("【成交提醒】买入通知", "策略已触发买入:%s,数量100" % g.security)
替代方案:企业微信/钉钉通知
由于邮件协议(SMTP)常被防火墙封锁,在PTrade中更推荐使用 企业微信 (send_qywx) 接口(如果券商支持)。
在 tick_data 或 handle_data 中,部分券商支持直接调用:
# 仅在部分支持的券商环境中有效
send_qywx("交易信号触发:买入 600570.SS")
总结建议
- 首选方案:先尝试使用
set_email_info配合send_email。 - 环境确认:如果代码运行不报错但收不到邮件,或者直接报错连接超时,请联系你的券商客户经理,询问:“PTrade实盘环境是否开放了SMTP端口或邮件发送权限?”
- 替代渠道:如果邮件无法打通,建议咨询券商是否支持推送到手机APP(PTrade手机端)或企业微信,这通常比邮件更容易实现。
Q&A
Q: 为什么我在回测中收不到邮件?
A: PTrade的回测环境是完全隔离的沙箱环境,不支持任何形式的对外网络请求(包括邮件、HTTP请求等),以防止回测数据泄露或滥用资源。邮件功能仅在“交易”(实盘/模拟盘)模式下可能可用。
Q: set_email_info 中的授权码是什么?
A: 授权码不是你的QQ邮箱登录密码。你需要登录网页版QQ邮箱,进入“设置” -> “账户”,开启“POP3/SMTP服务”,系统会生成一串随机字符,那个才是授权码。
Q: 如果券商封锁了网络,还有办法通知吗?
A: 如果券商彻底封锁了外网且未提供内部通知接口,策略端无法直接发送通知。此时只能依赖PTrade客户端本身的弹窗提示,或者通过券商提供的手机APP查看成交推送。