问题描述
解决方案
在聚宽(JoinQuant)平台中,若要限制策略只在当前可融资(融资买入)或可融券(融券卖出)的标的中进行交易,主要使用以下两个API函数:
get_margincash_stocks(): 获取当前可融资(做多)的股票列表。get_marginsec_stocks(): 获取当前可融券(做空)的股票列表。
通常情况下,我们会在 before_trading_start 函数中调用这些接口,获取当天的两融标的列表,并将其与我们选定的股票池(如沪深300)取交集,从而过滤掉不可融资融券的股票。
以下是一个完整的策略示例。该策略选取沪深300成分股,并过滤出其中既可以融资也可以融券的股票作为最终交易股票池,然后随机买入其中5只。
# -*- coding: utf-8 -*-
import jqdata
import random
def initialize(context):
# 设定沪深300作为基准
set_benchmark('000300.XSHG')
# 开启动态复权模式(真实价格)
set_option('use_real_price', True)
# 过滤掉order系列API产生的比error级别低的log
log.set_level('order', 'error')
# 定义全局变量,用于存储每日筛选后的股票池
g.target_stocks = []
# 每天开盘前运行
run_daily(before_market_open, time='09:00')
# 每天开盘时运行
run_daily(market_open, time='09:30')
def before_market_open(context):
"""
开盘前筛选股票
"""
# 1. 获取基础股票池(例如:沪深300成分股)
base_pool = get_index_stocks('000300.XSHG')
# 2. 获取当前可融资(买入)的标的列表
margin_cash_stocks = get_margincash_stocks()
# 3. 获取当前可融券(卖出)的标的列表
# 如果你的策略只需要融资买入,可以只用上面的 margin_cash_stocks
# 如果你的策略涉及融券做空,建议同时检查 margin_sec_stocks
margin_sec_stocks = get_marginsec_stocks()
# 4. 筛选:取交集
# 逻辑:在沪深300中,且同时在融资列表和融券列表中的股票
# 注意:set操作可以提高查找效率
valid_stocks = set(base_pool) & set(margin_cash_stocks) & set(margin_sec_stocks)
g.target_stocks = list(valid_stocks)
log.info("今日符合条件的融资融券标的数量: %d" % len(g.target_stocks))
def market_open(context):
"""
开盘交易逻辑
"""
# 如果没有符合条件的股票,直接返回
if len(g.target_stocks) == 0:
return
# 卖出不在今日目标池中的持仓
for security in context.portfolio.positions:
if security not in g.target_stocks:
order_target(security, 0)
log.info("卖出不再是两融标的的股票: %s" % security)
# 简单的买入逻辑示例:随机买入目标池中的5只股票
# 实际策略中请替换为你的选股因子逻辑
buy_count = 5
# 资金分配
cash_per_stock = context.portfolio.available_cash / buy_count
# 随机选择
stocks_to_buy = random.sample(g.target_stocks, min(len(g.target_stocks), buy_count))
for stock in stocks_to_buy:
order_value(stock, cash_per_stock)
log.info("买入两融标的: %s" % stock)
代码逻辑解析
-
获取数据:
- 使用
get_margincash_stocks()获取交易所披露的最新可融资标的。 - 使用
get_marginsec_stocks()获取交易所披露的最新可融券标的。 - 这两个函数在回测模式下会自动获取回测当天的历史数据,在实盘/模拟交易中会获取最新数据,避免了未来函数。
- 使用
-
集合运算:
- 代码中使用
set(list_a) & set(list_b)的方式取交集。这确保了选出的股票既属于你的基础股票池(如沪深300),又是交易所规定的两融标的。
- 代码中使用
-
时机选择:
- 筛选逻辑放在
before_market_open(09:00) 中执行。这是因为两融标的名单通常在交易日开始前就已经确定,提前筛选可以提高盘中交易的效率。
- 筛选逻辑放在
常见问题 (Q&A)
Q: get_margincash_stocks 和 get_marginsec_stocks 有什么区别?
A: get_margincash_stocks 返回的是可以融资买入(借钱买股)的股票列表;get_marginsec_stocks 返回的是可以融券卖出(借股卖出)的股票列表。虽然大部分标的两者皆可,但仍有部分股票只允许融资不允许融券,或者相反。
Q: 为什么回测时获取不到当天的两融数据?
A: 交易所的数据通常在收盘后更新。在回测中,如果查询当天的两融列表,系统通常返回的是截止到前一个交易日的数据(或者当天盘前已知的数据),这是为了防止未来函数。在聚宽中,直接调用这两个函数即可获取策略当前时间点可用的最新名单。
Q: 如果我想开通融资融券账户进行杠杆交易,代码需要修改吗?
A: 需要。上面的代码仅限制了标的范围,但使用的是普通账户(自有资金)。如果要进行杠杆交易(融资买入或融券卖出),需要在 initialize 中使用 set_subportfolios 将账户类型设置为 'stock_margin',并使用 margincash_open (融资买入) 或 marginsec_open (融券卖出) 等专用接口下单。
Q: 如何判断单只股票是否可融资?
A: 可以直接判断股票代码是否在列表中,例如:
if '000001.XSHE' in get_margincash_stocks():
print("平安银行可融资")