问题描述
写了一个策略可能需要融券融资,但仔细看了聚宽里的API,找不到类似普通交易中的target_value函数,请问是否能够根据通过给定目标价格自动购买至指定仓位。我目前想到的一个方法就是先平仓再交易,但这好像会亏手续费。
然后请问一下有什么代码可以看到当期自己账户的融券仓位情况吗?
或者是否有这种功能,当我的target_value大于我的流动资金时自动融资,当我的target_value为负的时候自动融券?
解决方案
针对您在 JoinQuant(聚宽)平台上编写融资融券策略时遇到的问题,以下是详细的解答和解决方案:
一、 融资融券是否有类似 target_value 的函数?
目前聚宽的官方 API 中,融资融券专用 API 并没有直接提供类似 order_target_value 的函数。官方提供的融资融券函数主要是按数量(股数)下单的,例如:
margincash_open(融资买入)margincash_close(卖券还款)marginsec_open(融券卖出)marginsec_close(买券还券)
您想到的“先平仓再交易”确实会产生不必要的手续费。正确的做法是自己编写一个逻辑函数,计算当前持仓价值与目标价值的差额,然后根据差额调用对应的融资或融券函数。下文第三部分会提供一个现成的自定义函数供您参考。
二、 如何查看当期自己账户的融券仓位情况?
在聚宽中,融券卖出属于空头仓位。您可以通过 context.portfolio.short_positions 来查看当前账户的所有空单(融券)持仓情况。
这是一个字典,键是标的代码,值是 Position 对象。您可以使用以下代码在策略中打印或获取融券仓位信息:
def check_short_positions(context):
short_positions = context.portfolio.short_positions
if not short_positions:
log.info("当前无融券空头仓位")
else:
for security, position in short_positions.items():
log.info(f"标的: {security}, 融券空仓数量: {position.total_amount}, 仓位价值: {position.value}, 建仓均价: {position.avg_cost}")
(注:如果是多头/融资买入的仓位,则在 context.portfolio.long_positions 中)
三、 能否实现自动融资融券(超出资金自动融资,目标为负自动融券)?
聚宽原生的 order_target_value 不会自动触发融资融券。如果您直接使用普通下单函数,当资金不足时订单会被拒,当目标为负时股票不支持直接做空。
为了实现您的需求,您可以自己封装一个 margin_order_target_value 函数。以下是一个实现该逻辑的参考代码:
def margin_order_target_value(context, security, target_value):
"""
自定义融资融券目标价值下单函数
:param context: 策略上下文
:param security: 标的代码
:param target_value: 目标价值(正数表示做多/融资做多,负数表示做空/融券做空,0表示清仓)
"""
# 获取当前价格用于计算需要交易的数量
current_data = get_current_data()
price = current_data[security].last_price
if price == 0 or math.isnan(price):
return
# 获取当前多头和空头持仓价值
long_pos = context.portfolio.long_positions.get(security)
short_pos = context.portfolio.short_positions.get(security)
current_long_value = long_pos.value if long_pos else 0
current_short_value = short_pos.value if short_pos else 0
# 1. 目标是清仓
if target_value == 0:
if current_long_value > 0:
order_target(security, 0) # 普通卖出平多
if current_short_value > 0:
marginsec_close(security, short_pos.total_amount) # 买券还券平空
return
# 2. 目标是做多 (target_value > 0)
if target_value > 0:
# 如果有空头仓位,先平空
if current_short_value > 0:
marginsec_close(security, short_pos.total_amount)
# 计算需要增加或减少的价值
diff_value = target_value - current_long_value
if diff_value > 0: # 需要加仓
available_cash = context.portfolio.available_cash
if diff_value <= available_cash:
# 现金充足,普通买入
order_value(security, diff_value)
else:
# 现金不足,先用光现金普通买入,剩余部分融资买入
if available_cash > 0:
order_value(security, available_cash)
# 计算需要融资的金额并转换为股数 (注意聚宽A股必须是100的整数倍)
margin_need_value = diff_value - max(available_cash, 0)
margin_amount = int(margin_need_value / price / 100) * 100
if margin_amount > 0:
margincash_open(security, margin_amount)
elif diff_value < 0: # 需要减仓
order_value(security, diff_value) # 普通卖出即可
# 3. 目标是做空/融券 (target_value < 0)
elif target_value < 0:
target_short_value = abs(target_value)
# 如果有多头仓位,先平多
if current_long_value > 0:
order_target(security, 0)
# 计算需要增加或减少的空头价值
diff_short_value = target_short_value - current_short_value
if diff_short_value > 0: # 需要增加融券仓位
margin_amount = int(diff_short_value / price / 100) * 100
if margin_amount > 0:
marginsec_open(security, margin_amount)
elif diff_short_value < 0: # 需要减少融券仓位 (买券还券)
reduce_amount = int(abs(diff_short_value) / price / 100) * 100
if reduce_amount > 0:
marginsec_close(security, reduce_amount)
使用注意事项:
- 初始化账户类型:要使用融资融券,必须在
initialize中将账户类型设置为stock_margin:set_subportfolios([SubPortfolioConfig(cash=context.portfolio.starting_cash, type='stock_margin')]) - 标的限制:并非所有股票都可以融资融券。在调用融资融券下单前,建议使用
get_margincash_stocks()和get_marginsec_stocks()检查标的是否在可融资/可融券列表中。 - 整数倍限制:A股交易必须是100股的整数倍,上述自定义函数中已经包含了
int(value / price / 100) * 100的向下取整逻辑,避免下单失败。