问题描述
解决方案
在PTrade中,处理融资融券(两融)业务主要涉及两个步骤:查询负债(查询欠了多少钱或多少券)和执行偿还(直接还款、卖券还款、直接还券、买券还券)。
以下是针对您需求的详细解答,包括核心API说明和一个完整的自动化策略代码。
核心API说明
1. 查询负债
要获取当前的融资融券资产和负债情况,主要使用 get_margin_assert() 函数。
fin_compact_balance: 融资合约金额(欠的现金)。fin_compact_interest: 融资合约利息。total_debit: 负债总额。
要获取具体的融券(空头)持仓,通常通过 get_positions() 查看 short_amount(空头持仓数量)。
2. 偿还方式
- 融资还款(还钱):
margincash_direct_refund(value): 直接还款。使用账户里的可用资金直接归还融资负债。margincash_close(security, amount): 卖券还款。卖出持仓股票,资金用于还款。
- 融券还券(还券):
marginsec_direct_refund(security, amount): 直接还券。如果您账户里已经持有该股票(现券),可以直接将其归还给券商。marginsec_close(security, amount): 买券还券。使用资金买入股票并归还。
自动还款还券策略
下面的策略逻辑如下:
- 每天收盘前(如14:50)自动运行。
- 自动还钱:检查是否有融资负债。如果有,且账户有可用资金,则使用可用资金进行直接还款。
- 自动还券:遍历所有持仓,检查是否有融券负债(空头持仓)。
- 如果账户内有对应的普通持仓(多头),则优先执行直接还券(用现券还融券)。
- 如果账户内没有现券,则执行买券还券(从市场买入归还)。
策略代码
def initialize(context):
"""
初始化函数
"""
# 设置股票池(示例),两融交易需要设置标的
g.security = '600570.SS'
set_universe(g.security)
# 设定每天 14:50 执行自动还款还券检查
run_daily(context, auto_repay_debt, time='14:50')
def handle_data(context, data):
"""
盘中运行函数(此处留空,逻辑在定时任务中)
"""
pass
def auto_repay_debt(context):
"""
自动还款还券逻辑主函数
"""
log.info("开始执行自动还款还券检查...")
# 1. 处理融资负债 (还钱)
repay_cash(context)
# 2. 处理融券负债 (还券)
repay_securities(context)
log.info("自动还款还券检查结束。")
def repay_cash(context):
"""
偿还融资负债逻辑
"""
# 获取信用资产信息
margin_assets = get_margin_assert()
if not margin_assets:
log.info("未获取到信用资产信息,跳过融资还款检查。")
return
# 获取融资合约金额 (本金) 和 利息
# 注意:不同券商返回字段可能略有差异,通常关注 fin_compact_balance
debt_balance = margin_assets.get('fin_compact_balance', 0.0)
debt_interest = margin_assets.get('fin_compact_interest', 0.0)
total_debt = debt_balance + debt_interest
if total_debt <= 0:
log.info("当前无融资负债。")
return
# 获取当前账户可用资金
available_cash = context.portfolio.cash
log.info("当前融资负债: %.2f, 可用资金: %.2f" % (total_debt, available_cash))
# 如果有负债且有现金
if available_cash > 0:
# 决定还款金额:取负债总额和可用资金的较小值
# 也就是有多少钱还多少,或者还清为止
repay_amount = min(total_debt, available_cash)
# 保留一点资金防止手续费不足(可选,此处保留100元)
if available_cash - repay_amount < 100:
repay_amount = max(0, repay_amount - 100)
if repay_amount > 0:
log.info("执行直接还款,金额: %.2f" % repay_amount)
# 调用直接还款接口
margincash_direct_refund(repay_amount)
else:
log.info("可用资金不足以支付预留额度,暂不还款。")
else:
log.info("可用资金不足,无法归还融资负债。")
def repay_securities(context):
"""
偿还融券负债逻辑
"""
# 获取所有持仓
positions = get_positions()
if not positions:
return
# 遍历持仓,寻找空头头寸
for code, pos in positions.items():
# short_amount 为空头持仓数量(融券卖出数量)
short_qty = pos.short_amount
if short_qty > 0:
log.info("发现融券负债: %s, 数量: %d" % (code, short_qty))
# 检查是否有对应的多头持仓(现券)
# amount 通常包含多头持仓,long_amount 是明确的多头
long_qty = pos.long_amount
# 场景 A: 有现券,执行直接还券
if long_qty > 0:
# 还券数量取 空头数量 和 多头数量 的较小值
return_qty = min(short_qty, long_qty)
log.info("持有现券,执行直接还券: %s, 数量: %d" % (code, return_qty))
# 直接还券接口
marginsec_direct_refund(code, return_qty)
# 如果还完后还有剩余空头,继续执行买券还券逻辑
short_qty -= return_qty
# 场景 B: 没有现券(或现券不够),执行买券还券
if short_qty > 0:
log.info("现券不足,执行买券还券: %s, 数量: %d" % (code, short_qty))
# 买券还券接口 (注意:这会消耗资金)
# 这里的 limit_price=None 表示市价或最新价,具体视回测/实盘配置而定
# 建议实盘中根据盘口价格指定 limit_price
marginsec_close(code, short_qty)
注意事项
- 资金预留:在
repay_cash函数中,我添加了一个简单的逻辑保留100元资金。这是为了防止全额还款后账户没有资金支付可能产生的交易手续费或其他费用。 - 交易时间:策略设定在
14:50执行。这是为了确保在收盘前完成操作,避免产生过夜利息(如果您的目的是日内回转)。 - 买券还券风险:
marginsec_close(买券还券)本质上是一笔买入交易,会消耗您的可用资金。如果资金不足,委托会失败。 - API 权限:请确保您的PTrade终端登录的是信用账户(两融账户),普通账户无法调用上述两融接口。
- Python版本:代码兼容 Python 3.5 及以上版本。
Q&A
Q: margincash_direct_refund 和 margincash_close 有什么区别?
A: margincash_direct_refund 是直接还款,它使用您账户里现有的现金余额来偿还负债,不涉及股票买卖。margincash_close 是卖券还款,它会卖出您持有的股票,用卖出股票获得的资金来偿还负债。
Q: 为什么我的 get_margin_assert() 返回是空的?
A: 这通常是因为您在回测模式下没有开启两融权限,或者在实盘中登录的是普通账户而非信用账户。请检查您的账户类型。
Q: 自动还款策略能处理利息吗?
A: 可以。fin_compact_balance 通常指本金,fin_compact_interest 指利息。在计算 total_debt 时将两者相加即可覆盖利息。券商结算时通常优先偿还利息。