Jikipedia
第 03 篇

使用 JoinQuant 编写一个策略

第 1 章之后的平台展开篇:把聚宽写策略要用的数据获取、股票池、下单、止盈止损 API 逐个过一遍,最后用「双均线」与「多股票追涨」两个官方示例演示完整策略怎么写。素材见 raw/collections/jq-getting-started/03-21-使用joinquant编写一个策略md.md。

量化聚宽行情数据股票池下单止盈止损

这是什么

JQ 策略 API 手册式的实操页。它回答四个问题:行情/财务数据怎么取、股票池怎么设、买卖怎么下、止盈止损怎么写,并给出 API 文档里的两个示例策略。原素材标注为个人整理,多处代码有笔误(见「不确定 / 待验证」),适合当概念地图,不适合照抄运行。

核心要点

数据:行情与财务

  • 行情数据存在 SecurityUnitData 里,基本属性:open/close/low/high(开收低高)、volume/money(成交量/额)、factor(前复权因子)、high_limit/low_limit(涨停价/跌停价)、price(段内均价)、pre_close(前收)、paused(是否停牌)。
  • 行情获取五种方式(对比表):
    1. 回测里从 data 直接读:只能在策略中用,只能取当期数据,只能在 handle_data 里用;好处是能拿额外属性(security、returns、isnan、vwap 等)。
    2. attribute_history(证券, n, 单位, 字段, ...):只能在策略中用;取当前时间前 n 个单位;一次一只股票、可多字段;可选跳过停牌日。
    3. history(n, 单位, 字段, 股票列表):只能在策略中用;取前 n 个单位;可多只股票但只能同一个字段;不能跳停牌日。
    4. get_current_data:只能取当期数据;只能拿涨跌停价、是否停牌、开盘价等;可多股票多字段;只能在策略中用。
    5. get_price:使用较难;策略与研究中都能用;可取任意时间段;可多股票多字段;不能跳停牌日。原素材说会单独讲,但本篇未展开 → 见「待验证」。
  • 财务数据用 get_fundamentals:返回基本面数据(含股票财务数据、市值数据)。链式写法: query(查询字段).filter(筛选条件).order_by(排序).limit(数量),最后带 date='2015-10-15' 指定取哪一天。 示例字段:valuation.code(市值表.代码)、valuation.market_cap(市值)、valuation.pe_ratio(动态市盈率)、income.total_operation_revenue(利润表.营业总收入);示例条件:市值 > 1000、PE < 10、营业总收入 > 2e10、按市值降序、limit 100。

股票池

  • 三种设池方式,都要 set_universe(stocks) 落地:
    • 按指数:get_index_stocks('000300.XSHG') 取沪深 300 成分(raw 示例代码里误写成 0003000,见待验证)。
    • 按行业:get_industry_stocks('I64')(I64 = 计算机/互联网行业)。
    • 自定义:stocks = ['000009.XSHE', '002222.XSHE', '000005.XSHE', '000002.XSHE']
  • 注意:raw 说 API 文档里 set_universe 被称为「老函数」,用法是否仍正确需要验证。

下单与订单

  • 四种下单:order(按股数)、order_target(调整到目标股数)、order_value(按金额)、order_target_value(调整到目标金额)。
  • 订单相关操作:cancel_order(撤单)、get_open_orders(当天未完成订单)、get_orders(当天所有订单)、get_trades(当天成交记录)。
  • 下单成功返回 Order 对象(属性:add_time 添加时间、is_buy 买/卖、amount 下单数量恒正、filled 已成交数量、security 代码、order_id、price 平均成交价、status 状态——未成交/部分成交/已撤销/交易所拒绝/全部成交)。
  • 成交返回 Trade 对象(time、amount、price、trade_id)。

止盈止损写法

  • 持仓信息在 context.portfolio.positions[股票]avg_cost = 持仓成本、price = 现价。
  • 用「现价/成本」比例判断:price/avg_cost >= 1.5 → 收益 50% 止盈,order_target(stock, 0) 清仓;price/avg_cost <= 0.9 → 亏损 10% 止损清仓。

示例一:双均线策略(最基础的策略)

  • 规则:5 日均线高于 10 日均线买入;低于且有空头可卖则卖出。
  • 初始化:g.security='000001.XSHE'(平安银行);set_benchmark('000300.XSHG')(以沪深 300 为基准);set_option('use_real_price', True)(开启动态复权,即用真实价格)。
  • 每周期:attribute_history(security, 10, 'ld', ['close'], df=False) 取过去 10 天收盘;ma5 = ...[-5].mean()ma10 = 全部.mean()cash = context.portfolio.cash
  • 买卖:ma5 > ma10order_value(security, cash)log.info 记录;ma5 < ma10positions[security].closeable_amount > 0order_target(security, 0)
  • record(ma5=ma5) 把均线画到回测图上。
  • initialize 还能配置:set_commission(PerTrade(buy_cost=0.0001, sell_cost=0.001, min_cost=5)) 设手续费;set_slippage(PriceRelatedSlippage(0.002)) 设滑点。

示例二:多股票追涨策略(按分钟回测)

  • 规则:当日收盘前 30 分钟内涨幅到 9.5%–9.9% 的股票买入(最多 5 只),第二天开盘全卖。逻辑是追接近涨停但没封板的强势股。
  • initialize:set_option('use_real_price', True)g.daily_buy_count = 5g.stocks = get_industry_stocks('I64') + get_industry_stocks('I65')(计算机 + 信息技术板块)后 set(...) 去重;run_daily(morning_sell_all, 'open') 注册开盘卖光函数。
  • morning_sell_all(自定义函数):开盘遍历 positions,每只 order_target(security, 0) 全卖。
  • before_trading_start:每个交易日开盘前被调用一次。这里重置 g.today_bought_stocks = set(),并取 g.last_df = history(1, 'ld', 'close', g.stocks)(全部股票昨日收盘价,每天只取一次)。
  • handle_datacontext.current_dt.hour < 13 直接 return(只做最后两小时);已买满 daily_buy_count 也 return;对未买股票判断 price/last_close > 1.095 且 < 1.099high_limit - last_close >= 1.0(涨停区间大于 1 元,还有上冲空间)→ 现金分成 need_count 份,order_value(security, buy_cash) 买入并记入 g.today_bought_stocks

机制 / 论证

  • 五个入口的职责划分(本篇对框架的增量):
    • initialize:整个回测/模拟盘开始时执行一次——设基准、手续费、滑点、股票池、调 run_daily
    • before_trading_start:每个交易日开盘前执行一次,开盘后当天不再执行;适合放「每天取一次的昨日数据」。
    • handle_data:每个周期执行(按天=每天 9:30 后,按分钟=每分钟);实时决策都在这。
    • run_daily(函数, 'open'):把自定义函数挂到指定时点(如开盘)循环执行——追涨示例用它做「开盘卖光」,卖出动作不必挤在 handle_data 里。
  • 为什么追涨只做最后两小时:只有接近收盘仍接近涨停的才算强势确认,避免盘中假信号;为什么每天只买 5 只:控制当日敞口。这是把「规则」翻译成「代码里能表达的约束」(时间窗口、数量上限、涨幅区间)。
  • 双均线示例用 closeable_amount > 0 判断「有没有可卖头寸」,避免空仓时也触发卖出——是「卖出前先查持仓」的标准姿势。

可操作

  • 取数选型口诀:策略内要「当期单股多字段」用 data;「历史单股多字段」用 attribute_history;「历史多股单字段」用 history;「只看停牌/涨跌停」用 get_current_data;「研究环境或任意区间」用 get_price。
  • get_fundamentals 模板(提炼参数与逻辑):query(valuation.code, valuation.market_cap, valuation.pe_ratio, income.total_operation_revenue).filter(市值>1000, PE<10, 营收>2e10).order_by(市值降序).limit(100) + date='2015-10-15'
  • 股票池:指数 get_index_stocks('000300.XSHG')、行业 get_industry_stocks('I64')、自定义 list,最后 set_universe(stocks);行业板块编号(I64、I65)从平台取。
  • 止盈止损一行式price/avg_cost >= 1.5 清仓(止盈 50%);<= 0.9 清仓(止损 10%);比例可改。
  • 追涨策略可复用参数:涨幅区间 9.5%–9.9%;涨停空间 high_limit - last_close >= 1.0 元;每天 5 只;下午 13:00 后才进 handle_data;按分钟回测;run_daily(morning_sell_all, 'open') 开盘卖光。
  • 可配置项:基准 set_benchmark、手续费 set_commission(PerTrade(buy_cost=…, sell_cost=…, min_cost=…))、滑点 set_slippage(PriceRelatedSlippage(0.002))、动态复权 set_option('use_real_price', True)

术语

  • SecurityUnitData:行情数据对象;前复权因子 factor。
  • attribute_history / history / get_current_data / get_price:四种行情取数。
  • get_fundamentals:财务/基本面取数;valuation / income 表(市值表 / 利润表)。
  • set_universe / get_index_stocks / get_industry_stocks:股票池。
  • order 系列、Order / Trade 对象、closeable_amount(可卖数量)。
  • avg_cost、set_benchmark、set_commission、set_slippage、run_daily、before_trading_start。

不确定 / 待验证

  • 大量代码笔误:沪深 300 写成 '0003000.XSHG'(多一个 0);Python 判断里出现 AND(应为 and);示例一用 close_data 但前面变量名是 close_price(会 NameError);context.protfolio 拼错。→ 全部按语义修正后理解,落地前必须对照官方 API。
  • set_universe 在 API 文档被称「老函数」,raw 自问用法是否正确 → [需要验证] 现行推荐写法(可能已改为在 initialize 里直接 get_index_stocks 等,无需 set_universe)。
  • raw 承诺「get_price 会单独列出来介绍」但本篇没有展开 → [需要验证] 具体用法,见后续股票数据篇。
  • 示例一里 record(ma5=ma5) 之后画图用的是 close_data——同上为笔误。
  • 手续费示例 buy_cost 0.0001 / sell_cost 0.001 / min_cost 5 是文档示例值,不是推荐值。

相关

更新 2026-09-06

检索知识库

按标题、类型或正文检索