3 分钟快速生成代码
输入想法,AI 即刻生成可运行代码
在量化交易中,滑点(Slippage)是影响实盘表现的关键交易成本之一,尤其是对于流动性各有差异的 ETF 标的。在聚宽(JoinQuant)平台上,我们可以通过在研究环境中使用 create_backtest API,或者在策略代码中动态调整滑点参数,来对同一策略进行滑点敏感性分析。
以下是进行 ETF 策略滑点敏感性分析的具体方案和 Python 代码实现。
在聚宽中,我们主要使用 set_slippage 函数来设定滑点:
FixedSlippage(0.02)(买入时在均价上加 0.01 元,卖出时减 0.01 元)。PriceRelatedSlippage(0.002)(买卖时加减当时价格的 0.1%)。为了比较不同滑点对同一策略的影响,最有效的方法是在**聚宽研究环境(Notebook)**中,利用 create_backtest 传入不同的 extras 参数(将滑点系数作为全局变量传入),批量启动回测,最后使用 get_backtest 获取各回测的交易次数、收益、夏普比率和最大回撤进行横向对比。
etf_ma_strategy)# -*- coding: utf-8 -*-
from jqdata import *
def initialize(context):
set_benchmark('000300.XSHG')
set_option('use_real_price', True)
# 核心:从外部传入的 extras 中读取滑点类型和滑点值
# 默认使用百分比滑点 0.00246
slippage_type = g.run_params.get('extras', {}).get('slippage_type', 'percent')
slippage_val = g.run_params.get('extras', {}).get('slippage_val', 0.00246)
if slippage_type == 'fixed':
set_slippage(FixedSlippage(slippage_val), type='fund')
else:
set_slippage(PriceRelatedSlippage(slippage_val), type='fund')
g.security = '510300.XSHG' # 沪深300ETF
# 设定手续费
set_order_cost(OrderCost(open_commission=0.0003, close_commission=0.0003, min_commission=5), type='fund')
run_daily(market_open, time='09:30')
def market_open(context):
security = g.security
# 简单的双均线金叉死叉策略作为测试基准
close_data = attribute_history(security, 20, '1d', ['close'])
ma5 = close_data['close'][-5:].mean()
ma20 = close_data['close'][-20:].mean()
cash = context.portfolio.available_cash
if ma5 > ma20 and context.portfolio.positions[security].total_amount == 0:
order_value(security, cash)
log.info("买入 ETF")
elif ma5 < ma20 and context.portfolio.positions[security].closeable_amount > 0:
order_target(security, 0)
log.info("卖出 ETF")
在 Notebook 中运行以下 Python 代码,它将自动提交 4 个不同滑点参数的回测任务,并在完成后拉取数据进行对比:
import pandas as pd
import time
from kuanke.user_space_api import *
# 1. 定义要测试的滑点参数列表
slippage_tests = [
{'name': '无滑点', 'type': 'percent', 'val': 0.0},
{'name': '低滑点(0.1%)', 'type': 'percent', 'val': 0.001},
{'name': '默认滑点(0.246%)', 'type': 'percent', 'val': 0.00246},
{'name': '高滑点(0.5%)', 'type': 'percent', 'val': 0.005}
]
backtest_ids = {}
# 假设你的策略在聚宽编辑器的算法ID为 'your_algorithm_id_here' (从策略编辑页URL获取)
algorithm_id = "your_algorithm_id_here"
# 2. 批量创建回测
for test in slippage_tests:
params = {
"algorithm_id": algorithm_id,
"start_date": "2022-01-01",
"end_date": "2023-12-31",
"frequency": "day",
"initial_cash": "1000000",
"extras": {
"slippage_type": test['type'],
"slippage_val": test['val']
},
"name": f"ETF滑点测试_{test['name']}"
}
bt_id = create_backtest(**params)
backtest_ids[test['name']] = bt_id
print(f"已创建回测: {test['name']}, ID: {bt_id}")
# 3. 等待所有回测运行完毕并收集结果
print("等待回测完成...")
results = []
for name, bt_id in backtest_ids.items():
gt = get_backtest(bt_id)
while True:
status = gt.get_status()
if status in ['done', 'failed', 'canceled']:
break
time.sleep(5) # 每5秒轮询一次
if status == 'done':
# 获取风险指标
risk = gt.get_risk()
# 获取交易详情计算交易次数
orders = gt.get_orders()
trade_count = len(orders)
results.append({
'滑点参数': name,
'交易次数': trade_count,
'总收益率': risk.get('algorithm_return', 0),
'年化收益率': risk.get('annual_ized_return', 0),
'夏普比率': risk.get('sharpe', 0),
'最大回撤': risk.get('max_drawdown', 0)
})
print(f"{name} 回测完成。")
else:
print(f"{name} 回测运行失败。")
# 4. 转换为 DataFrame 展示对比表格
df_compare = pd.DataFrame(results)
print("\n===== ETF 策略滑点敏感性分析对比表 =====")
print(df_compare.to_string(index=False))
运行上述分析后,您将获得类似下表的对比数据:
| 滑点参数 | 交易次数 | 总收益率 | 年化收益率 | 夏普比率 | 最大回撤 |
|---|---|---|---|---|---|
| 无滑点 | 48 | 15.2% | 7.3% | 0.85 | -12.4% |
| 低滑点(0.1%) | 48 | 12.8% | 6.1% | 0.72 | -13.1% |
| 默认滑点(0.246%) | 48 | 9.5% | 4.6% | 0.55 | -14.2% |
| 高滑点(0.5%) | 48 | 4.1% | 2.0% | 0.21 | -16.5% |
关键结论与优化方向: