3 分钟快速生成代码
输入想法,AI 即刻生成可运行代码
针对您在 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() 检查标的是否在可融资/可融券列表中。int(value / price / 100) * 100 的向下取整逻辑,避免下单失败。