问题描述
解决方案
要在PTrade中实现同一套策略代码在不同账户类型(股票或期货)下自动切换交易逻辑,核心在于使用 get_business_type() 接口。
该接口会返回当前策略运行环境的业务类型(如 'stock' 代表股票,'future' 代表期货)。你可以根据返回值的不同,在 handle_data 中编写分支逻辑,分别调用股票的 order 系列函数或期货的 buy_open/sell_close 系列函数。
以下是具体的实现方案和代码示例。
核心思路
- 获取业务类型:在
before_trading_start或initialize中调用get_business_type()并存储到全局变量g中。 - 设置标的池:根据业务类型,设置对应的股票代码或期货合约代码为标的池 (
set_universe)。 - 分支交易逻辑:在
handle_data中使用if-elif判断业务类型,执行完全隔离的下单逻辑。
策略代码示例
def initialize(context):
# 定义我们要操作的标的
g.stock_security = '600570.SS' # 股票标的:恒生电子
g.future_security = 'IF2309.CCFX' # 期货标的:股指期货(示例代码,实盘请换主力合约)
# 初始化业务类型变量
g.biz_type = None
def before_trading_start(context, data):
# 获取当前策略运行的业务类型
# 返回值可能是: 'stock'(股票), 'future'(期货), 'rzrq'(两融) 等
g.biz_type = get_business_type()
log.info("当前策略运行环境为: %s" % g.biz_type)
# 根据业务类型设置不同的股票池
if g.biz_type == 'stock':
set_universe(g.stock_security)
log.info("已设置股票池: %s" % g.stock_security)
elif g.biz_type == 'future':
set_universe(g.future_security)
log.info("已设置期货合约: %s" % g.future_security)
else:
log.warn("未知的业务类型,未设置标的池")
def handle_data(context, data):
# ---------------------------------------------------
# 场景一:股票账户逻辑
# ---------------------------------------------------
if g.biz_type == 'stock':
security = g.stock_security
# 简单的股票逻辑:如果当前没有持仓,则买入100股
position = get_position(security)
if position.amount == 0:
log.info("【股票账户】触发买入逻辑")
# 股票下单使用 order / order_target / order_value 等接口
order(security, 100)
# ---------------------------------------------------
# 场景二:期货账户逻辑
# ---------------------------------------------------
elif g.biz_type == 'future':
security = g.future_security
# 简单的期货逻辑:如果当前没有多头持仓,则开多1手
position = get_position(security)
# 期货持仓字段与股票不同,有多头(long_amount)和空头(short_amount)之分
if position.long_amount == 0:
log.info("【期货账户】触发开多逻辑")
# 期货下单使用 buy_open / sell_close / sell_open / buy_close 接口
# 注意:期货通常需要按“手”交易
buy_open(security, 1)
# ---------------------------------------------------
# 其他场景
# ---------------------------------------------------
else:
log.info("当前业务类型暂无交易逻辑")
关键点解析
-
get_business_type():- 这是区分环境的唯一标准。
- 返回
'stock':对应普通股票账户。 - 返回
'future':对应期货账户。 - 返回
'rzrq':对应信用(融资融券)账户。
-
下单接口的区别:
- 股票:必须使用
order(code, amount),order_target等函数。买入amount为正,卖出为负。 - 期货:必须使用
buy_open(买开),sell_close(卖平),sell_open(卖开),buy_close(买平)。参数amount必须为正数。
- 股票:必须使用
-
持仓对象的区别 (
get_position):- 股票:主要关注
position.amount(总持仓) 和position.enable_amount(可用持仓)。 - 期货:必须区分方向,关注
position.long_amount(多头持仓) 和position.short_amount(空头持仓)。
- 股票:主要关注
-
兼容性建议:
- 虽然代码可以在一个文件中写完,但建议在回测时分别建立两个回测任务(一个选股票账户,一个选期货账户)来验证逻辑,因为PTrade的回测环境通常不支持单次回测同时模拟股票和期货的混合资金池(除非是多账户模式,但通常策略逻辑是隔离的)。
Q&A
Q: get_business_type() 可以在 initialize 中调用吗?
A: 可以。但在 before_trading_start 中调用通常更稳妥,因为它确保了每天交易开始前都会确认一次环境状态,且此时上下文数据加载更为完全。
Q: 如果我在股票账户里误用了 buy_open 会怎样?
A: 策略会报错或下单失败。PTrade 的交易网关会拦截不符合当前账户权限的指令。因此使用 if g.biz_type == ... 进行逻辑隔离是非常必要的。
Q: 如何在回测中模拟这种情况?
A: 你需要创建两个回测任务。
- 第一个回测任务:选择“股票”品种,设置初始资金,运行该策略。此时
g.biz_type为'stock',执行股票逻辑。 - 第二个回测任务:选择“期货”品种,设置初始资金,运行同一份策略代码。此时
g.biz_type为'future',执行期货逻辑。
Q: 这种写法支持融资融券账户吗?
A: 支持。你可以添加 elif g.biz_type == 'rzrq': 分支,并在其中使用 margincash_open (融资买入) 或 marginsec_open (融券卖出) 等两融专用接口。