🚀 AI 一键生成 joinquant 策略代码

JoinQuant API 深度解析:如何使用 get_trades 和 Trade 对象分析交易执行效果?

joinquant | 发布时间: 2025/12/16
以下内容由 EasyQuant 生成。

问题描述

如何获取每一笔成交的详细信息,并计算实际的交易滑点?

解决方案

在 JoinQuant 聚宽平台中,要获取每一笔成交的详细信息,主要使用 get_trades() 函数。该函数返回当日所有的成交记录。

要计算“实际交易滑点”,我们需要定义滑点的概念:通常指 “实际成交价”与“下单时的预期价(或基准价)”之间的差额

由于系统自动撮合时不会自动记录你心目中的“预期价”,因此在策略代码中,我们需要分两步走:

  1. 下单时:记录当时的基准价格(例如当时的最新价 last_price)作为预期价。
  2. 收盘后:通过 get_trades() 获取实际成交价,并与记录的预期价进行对比计算。

以下是完整的策略代码示例,展示了如何获取成交详情并计算滑点。

策略代码实现

# -*- coding: utf-8 -*-
# 导入函数库
from jqdata import *

def initialize(context):
    # 1. 设置基准
    set_benchmark('000300.XSHG')
    # 2. 开启真实价格模式(动态复权)
    set_option('use_real_price', True)
    # 3. 设置日志级别
    log.set_level('order', 'error')
    
    # 4. 设置滑点:为了演示计算效果,这里设置一个较大的固定滑点(双边各0.02元)
    # 这意味着买入价比市价高0.01,卖出价比市价低0.01
    set_slippage(FixedSlippage(0.02))
    
    # 5. 定义一个全局字典,用于记录下单时的“预期价格”
    # 格式: {order_id: expected_price}
    g.order_expectations = {}
    
    # 每天运行
    run_daily(market_open, time='every_bar')
    # 收盘后进行统计
    run_daily(after_trading_end, time='15:30')

def market_open(context):
    # 示例:每天买入一只股票,卖出一只股票
    stock_to_buy = '000001.XSHE' # 平安银行
    
    # 获取当前时刻的最新数据
    current_data = get_current_data()
    
    # --- 模拟买入操作 ---
    if stock_to_buy not in context.portfolio.positions:
        # 1. 获取下单前的最新价作为“预期价格”
        expected_price = current_data[stock_to_buy].last_price
        
        # 2. 下单
        order_obj = order(stock_to_buy, 1000)
        
        # 3. 如果下单成功(返回了Order对象),记录预期价格
        if order_obj:
            g.order_expectations[order_obj.order_id] = expected_price
            log.info("【下单买入】标的:%s,预期价格:%.2f" % (stock_to_buy, expected_price))

def after_trading_end(context):
    log.info("================ 每日成交详情与滑点统计 ================")
    
    # 1. 获取当日所有成交记录
    # get_trades() 返回一个dict,key是trade_id,value是Trade对象
    trades = get_trades()
    
    if not trades:
        log.info("今日无成交。")
        return

    # 2. 遍历每一笔成交
    for trade_id, trade in trades.items():
        # Trade对象包含:time, security, amount, price, trade_id, order_id
        
        # 获取对应的订单ID
        order_id = trade.order_id
        
        # 获取实际成交信息
        actual_price = trade.price
        amount = trade.amount
        security = trade.security
        
        # 获取我们之前记录的预期价格
        expected_price = g.order_expectations.get(order_id)
        
        # 开始计算滑点
        if expected_price:
            # 滑点金额 = (实际价格 - 预期价格) * 数量
            # 注意:
            # 买入时(amount>0),实际价格通常高于预期,差值为正代表成本增加(滑点损失)
            # 卖出时(amount<0),实际价格通常低于预期,差值为负代表收入减少(滑点损失)
            # 为了统一表示“滑点造成的每股价差”,我们通常取绝对值或者根据方向计算
            
            price_diff = actual_price - expected_price
            
            # 计算总滑点成本(金额)
            # 如果是买入:(实际 - 预期) * 正数量 = 正数 (代表多花的钱)
            # 如果是卖出:(实际 - 预期) * 负数量 = 正数 (代表少赚的钱,即损失)
            # 所以直接相乘即可得到滑点带来的“不利影响金额”
            slippage_cost = price_diff * amount
            
            log.info(f"【成交记录】ID: {trade_id}")
            log.info(f"  标的: {security}")
            log.info(f"  时间: {trade.time}")
            log.info(f"  方向: {'买入' if amount > 0 else '卖出'}")
            log.info(f"  数量: {amount}")
            log.info(f"  预期价格: {expected_price:.4f}")
            log.info(f"  实际成交价: {actual_price:.4f}")
            log.info(f"  每股滑点: {abs(price_diff):.4f}")
            log.info(f"  总滑点成本: {slippage_cost:.4f} 元")
            log.info("-" * 30)
        else:
            log.info(f"【成交记录】{trade_id} (未找到预期价格记录,可能是非策略自动单)")

    # 清理旧数据(可选,视策略逻辑而定)
    g.order_expectations.clear()

关键点解析

  1. get_trades() 函数

    • 这是获取成交详情的核心 API。
    • 它返回一个字典,Key 是 trade_id,Value 是 Trade 对象。
    • Trade 对象包含属性:
      • trade.time: 交易时间
      • trade.security: 标的代码
      • trade.amount: 交易数量(正数为买,负数为卖)
      • trade.price: 实际成交均价(已包含滑点)
      • trade.order_id: 对应的订单 ID
  2. 滑点计算逻辑

    • 预期价:API 不会自动记录你“想”以多少钱买入。对于市价单,通常以“下单瞬间的最新价”作为预期;对于限价单,通常以“限价价格”作为预期。
    • 全局变量 g:代码中使用 g.order_expectations 字典,在下单瞬间记录 order_id 和当时的 last_price
    • 对比:在收盘后(after_trading_end),通过 trade.order_id 找回当时的预期价,与 trade.price 做减法即可得出滑点。
  3. set_slippage

    • 为了在回测中看到滑点效果,必须在 initialize 中设置滑点模型。代码中使用了 FixedSlippage(0.02),这会导致买入价比基准价高 0.01,卖出价低 0.01(双边合计0.02,单边0.01),从而产生可计算的滑点。

Q&A

Q: 为什么 get_trades() 返回的 price 和我在行情软件上看到的 K 线收盘价不一样?
A: get_trades() 返回的是您的策略在回测引擎中撮合的实际成交价。这个价格受您设置的滑点模型set_slippage)影响。如果您设置了滑点,成交价会比当时的行情价更差(买得更贵,卖得更便宜)。

Q: 如何区分这笔成交是买入还是卖出?
A: 查看 trade.amount 属性。如果 amount > 0,表示买入(做多);如果 amount < 0,表示卖出(做空或平仓)。

Q: 如果一个订单分多次成交(分笔成交),get_trades() 会怎么显示?
A: get_trades() 会返回多个 Trade 对象。每个 Trade 对象代表一次撮合结果,它们会有不同的 trade_id,但可能拥有相同的 order_id。您需要遍历所有 Trade 来获取完整的成交细节。