问题描述
解决方案
在 JoinQuant 聚宽平台上,对一个股票列表里的所有股票进行下单,主要有两种常见的方法:
- 使用循环遍历(推荐):通过
for循环遍历股票列表,逐个调用下单函数(如order_value或order_target_value)。这种方法最灵活,适合资金分配和调仓。 - 使用篮子下单 API:使用
batch_submit_orders函数。这种方法适合需要批量委托且对执行效率有特定要求的场景(如一篮子股票同时买入)。
以下是具体的代码实现示例:
方法一:使用循环遍历(最常用)
这种方法适合大多数策略,特别是需要根据资金等比例分配(Equal Weight)或调整仓位时。
# -*- coding: utf-8 -*-
def initialize(context):
# 定义股票列表
g.stock_list = ['000001.XSHE', '600000.XSHG', '000002.XSHE']
# 设定基准
set_benchmark('000300.XSHG')
# 开启动态复权
set_option('use_real_price', True)
# 每天开盘时运行
run_daily(market_open, time='09:30')
def market_open(context):
# 获取当前可用资金
cash = context.portfolio.available_cash
# 计算每只股票分配的资金(例如:等权重分配)
# 注意:实际交易中可能需要考虑手续费预留
if len(g.stock_list) > 0:
cash_per_stock = cash / len(g.stock_list)
else:
return
# 遍历股票列表进行下单
for stock in g.stock_list:
# 过滤掉停牌的股票(可选,但推荐)
current_data = get_current_data()
if current_data[stock].paused:
log.info(f"股票 {stock} 停牌,跳过下单")
continue
# 下单:按价值买入
# order_value 会自动计算股数(向下取整到100股)
order_value(stock, cash_per_stock)
# 或者使用 order_target_value 进行调仓(调整到目标价值)
# order_target_value(stock, cash_per_stock)
log.info(f"对 {stock} 下单,金额: {cash_per_stock}")
方法二:使用 batch_submit_orders 批量下单
如果你已经计算好了每只股票需要买入的股数(amount),可以使用此 API 进行批量提交。注意,此函数需要传入具体的股数,而不是金额。
# -*- coding: utf-8 -*-
def initialize(context):
g.stock_list = ['000001.XSHE', '600000.XSHG']
set_benchmark('000300.XSHG')
set_option('use_real_price', True)
run_daily(trade_batch, time='09:30')
def trade_batch(context):
orders_info = []
# 假设我们要对列表里的每只股票买入 100 股
for stock in g.stock_list:
# 构建订单字典
order_dict = {
'security': stock,
'amount': 100, # 正数买入,负数卖出
'style': MarketOrderStyle(), # 市价单,也可以用 LimitOrderStyle(price)
'side': 'long' # 多单
}
orders_info.append(order_dict)
# 批量提交订单
# 注意:会对每一个委托进行验资验券,若其中任一个委托校验失败,则整个委托将会失败
if len(orders_info) > 0:
batch_submit_orders(orders_info)
log.info("批量订单已提交")
关键区别与建议
-
资金计算:
- 循环法:可以使用
order_value(按金额下单)或order_target_value(按目标市值调仓),系统会自动根据当前股价计算需要买卖多少股,非常方便。 - 批量法:
batch_submit_orders需要传入具体的amount(股数)。如果你只知道要买多少钱,你需要自己先获取股价,计算出股数,再构建订单字典。
- 循环法:可以使用
-
容错性:
- 循环法:如果列表里某一只股票下单失败(例如资金不足或停牌),不会影响循环中后续股票的下单。
- 批量法:根据文档,若其中任一个委托校验失败(如验资验券失败),则整个委托将会失败。
总结:对于大多数趋势跟踪、轮动或多因子策略,建议使用 方法一(循环遍历 + order_value/order_target_value),因为它处理资金分配更简单,且容错率更高。
Q&A
Q: 使用循环下单时,如何避免资金不足导致排在后面的股票买不进去?
A: 在计算 cash_per_stock 时,不要简单地用 available_cash / count。建议预留一小部分资金(例如乘以 0.98)用于支付手续费和滑点成本。即 cash_per_stock = (cash * 0.98) / len(g.stock_list)。
Q: order_target_value 和 order_value 有什么区别?
A: order_value(stock, 10000) 是买入价值 10000 元的股票(在现有持仓基础上增加)。order_target_value(stock, 10000) 是将该股票的持仓调整到 10000 元。如果当前持仓 0 元,它买入 10000;如果当前持仓 15000 元,它会卖出 5000 元。做定期调仓策略时,通常使用 order_target_value。
Q: 批量下单 batch_submit_orders 支持限价单吗?
A: 支持。在构建订单字典时,将 'style' 字段设置为 LimitOrderStyle(price) 即可,其中 price 是你指定的限价价格。