问题描述
解决方案
在PTrade中,融券卖出(做空)的标准API接口是 marginsec_open,该接口仅支持按**数量(股数)**下单,不支持直接指定金额。
若需要按指定金额进行融券卖出,需要先获取标的当前价格,计算出对应的股数(通常需向下取整到100的倍数),然后再调用 marginsec_open。
以下是具体的实现逻辑和完整的策略代码示例。
实现逻辑
- 获取当前价格:使用
get_snapshot获取实时行情快照中的最新价(last_px),或者在回测中使用data[security]['close']。 - 计算股数:
下单数量 = 目标金额 / 当前价格。 - 取整处理:由于A股交易通常以100股(1手)为单位,需要将计算出的数量向下取整为100的倍数:
int(数量 / 100) * 100。 - 下单执行:将计算好的数量传入
marginsec_open函数。
策略代码示例
以下代码展示了一个封装好的自定义函数 marginsec_open_value,你可以在策略中直接调用它来实现按金额融券。
def initialize(context):
# 设置两融标的,此处以 600519.SS (贵州茅台) 为例
# 注意:实际交易中需确保该标的在券商处有融券额度
g.security = '600519.SS'
set_universe(g.security)
# 设置一个标志位,防止重复下单
g.traded = False
def handle_data(context, data):
# 如果已经交易过,则不再执行
if g.traded:
return
# 设定想要融券卖出的金额,例如 20万元
target_value = 200000
# 调用自定义的按金额融券函数
marginsec_open_value(g.security, target_value)
# 标记已交易
g.traded = True
def marginsec_open_value(security, value):
"""
自定义函数:按指定金额进行融券卖出
:param security: 标的代码
:param value: 计划卖出的金额
"""
# 1. 获取当前价格
# 在回测和实盘中,get_snapshot 都是获取最新行情的推荐方式
# 注意:回测模式下 get_snapshot 可能受限,回测建议用 data[security]['close']
# 这里为了兼容性,先尝试取快照,取不到则用 data
current_price = 0.0
# 尝试获取快照数据
snapshot = get_snapshot(security)
if snapshot and security in snapshot:
current_price = snapshot[security].get('last_px', 0)
# 如果快照没取到价格(例如回测环境某些阶段),尝试用 data 获取
if current_price <= 0:
# 注意:在 handle_data 中可以直接访问 data
# 但作为独立函数,这里无法直接访问 data,除非传入 context 或 data
# 为简化演示,此处假设是在实盘或支持快照的环境。
# 若在纯回测环境且不支持快照,请将计算逻辑写在 handle_data 内部
log.warning("无法获取 %s 的有效价格,取消下单" % security)
return
# 2. 计算数量
# 数量 = 金额 / 价格
raw_amount = value / current_price
# 3. 向下取整到100的倍数 (A股最小交易单位为1手=100股)
amount = int(raw_amount / 100) * 100
# 4. 检查数量是否有效
if amount < 100:
log.info("计算出的股数不足100股(金额 %.2f, 价格 %.2f),无法下单" % (value, current_price))
return
# 5. 执行融券卖出
log.info("执行按金额融券: 标的=%s, 目标金额=%.2f, 当前价=%.2f, 下单数量=%d" % (security, value, current_price, amount))
marginsec_open(security, amount)
注意事项
- 账户权限:此功能仅适用于信用账户(融资融券账户),普通账户无法调用
marginsec_open。 - 融券额度:融券卖出前,必须确保券商对该标的有足够的融券额度(券源)。如果券源不足,委托会失败。
- 价格波动:计算出的股数是基于下单瞬间的价格。如果下单后价格剧烈波动,实际成交金额可能会与预设金额有偏差。
- 回测限制:
get_snapshot在某些旧版本的回测引擎中可能不支持。如果在回测中报错,请改用get_history获取前一分钟收盘价,或者在handle_data中直接使用data[security]['close']来获取价格。
Q&A
Q: 为什么PTrade没有直接提供 marginsec_open_value 接口?
A: 融资融券交易涉及较为严格的额度管理和风险控制,且融券必须以“股”为单位向柜台申报。PTrade API 设计上更贴近柜台实盘逻辑,因此只提供了基础的按量下单接口,按金额下单属于策略层的逻辑,需要用户自行计算。
Q: 如何确保融券卖出一定能成交?
A: 融券卖出能否成交取决于两个因素:一是是否有券源(额度),二是委托价格是否满足市场撮合条件。为了提高成交率,可以在计算出数量后,使用 limit_price 参数指定一个稍优于对手价的价格,或者在支持的市场(如科创板)使用市价委托参数。
Q: 计算出的股数如果是0怎么办?
A: 如果目标金额除以股价后不足100股(例如只想卖出500元,但股价是100元,计算结果为5股),向下取整后数量为0。代码中应加入判断逻辑(如示例中的 if amount < 100),避免传入0或非法数量导致报错。