# 快速上手
# 编写策略
用户可参照Python组件开发指南编写、调试策略程序,正常运行后即可进行回测。
备注:Python组件回测功能只能在模拟环境中使用,并需要响应权限,用户需联系客户经理开通。
# 下载数据
Python组件回测运行在客户端中,所需数据需下载到当前计算机。客户端提供了客户端数据管理和回测运行时动态下载功能,为保证回测速度,请提前下载所需的数据。 客户端数据管理界面主要包括两部分,左侧为可下载数据管理页,右侧为已下载数据管理页面。

可下载数据管理页提供了多种字段筛选,用户可根据市场、品种、代码、数据类型筛选产品,选择需要回测的时间段选中下载。 同一品种的回测数据需要时间段连续,若用户选择下载的时间段和已存在数据时间段不连续,客户端会自动填充为连续时间段。 用户选择的时间段和已存在数据的时间段重复的,客户端会下载最新数据覆盖已下载数据。

已下载数据管理页提供了数据目录变更,数据查看、筛选、删除等功能,数据筛选与可下载数据管理页类似。 选择变更数据目录后客户端会自动将原目录下his文件拷贝到新目录下,若拷贝失败,需要用户手动完成his文件夹的拷贝。

# 启动回测
点击启动回测按钮进入参数设置页,设置回测的起止时间、初始资金、交易费用、无风险利率、滑点、使用的回测数据周期。页面也会记录最近一次回测的参数设置,便于用户微调回测。回测过程中打印日志非常损耗性能,为快速回测,用户可选择关闭日志。

# 查看回测结果
回测运行完成后客户端会展示回测的绩效概览和每日详细数据,方便用户评价量化策略有效性,优化提升量化策略盈利能力、抗风险能力。

绩效概览界面对回测结果进行了统计计算,使用了最大回撤、最大盈利、夏普比率、索提诺比率、卡尔玛比率等常用指标度量量化策略的收益和风险。

详细数据页面展示了每一个回测交易日量化策略的当日收益、持仓、买卖回合、成交等信息。
# 回测交易规则
# 支持品种
| 品种 | 回测数据周期 | 特性说明 | 数据更新时间 |
|---|---|---|---|
| 股票、ETF | 日线 | 使用level1 日线数据回测用户策略程序,支持买卖交易,跨日订单不撤销,不支持混合快照数据回测 | 每日盘前更新前前日数据 |
| 股票、ETF | 1分钟线 | 使用level1 1分钟线数据回测用户策略程序,支持买卖交易,跨日订单撤销,支持混合快照数据回测 | 每日盘前更新前前日数据 |
| 股票、ETF | 5分钟线 | 使用level1 5分钟线数据回测用户策略程序,支持买卖交易,跨日订单撤销,支持混合快照数据回测 | 每日盘前更新前前日数据 |
| 股票、ETF | 快照 | 使用level1 快照数据回测用户策略程序,支持买卖交易,跨日订单撤销,支持对手盘、现价撮合模式 | 每日盘前更新前前日数据 |
# 撮合逻辑
日线撮合: 若存在订单,则按照高开低收四个价格分四次撮合订单,当日结束后未成交订单保留 分钟线撮合: 若存在订单,则按照高开低收四个价格分四次撮合订单,当日结束后未成交订单取消 纯tick撮合(对手盘撮合模式): 若存在订单,则按照对手盘价格撮合,例如卖单按照买盘价格撮合,当日结束后未成交订单取消。对手盘撮合存在一个时间差,例如回放10:30:03秒的行情时,对订单应使用10:30:00秒行情的对手盘数据进行撮合。 纯tick撮合(现价撮合模式): 若存在订单,则按照最新价撮合,当日结束后未成交订单取消 分钟线+tick撮合 若存在订单,则按照对手盘价格撮合,当日结束后未成交订单取消
# 滑点处理逻辑
若配置滑点,则模拟撮合时买单成交价格上涨滑点比例,卖单成交价格下跌滑点比例。
# 交易费用
回测交易费用主要包括手续费、最低手续费、印花税、过户费,费率默认使用客户在SmartX配置的费率。

买入订单费用计算 每笔成交手续费 = (手续费 + 过户费) * 成交额 + 印花税 * 成交额 默认买入订单印花税为0。
卖出订单费用计算 每笔成交手续费 = (手续费 + 过户费) * 成交额 + 印花税 * 成交额
最低手续费计算 订单在交易时段全部交易成功则检查该单关联的所有成交手续费之和, 如果该值小于最低手续费 , 则通过调整最后一笔成交成交费用以实施“最小手续费”规则
# 绩效回测指标解析
# 绩效概览页面指标

- 总收益率 = 期末动态权益/初始资金 - 1
- 年化收益率=(期末动态权益/初始资金)^(240/回测天数)-1,其中240是一年的交易日数
- 胜率 = 盈利回合次数 / 总回合次数
- 年化标准差=每日收益率标准差*√240
- 下行标准差=每日亏损收益率标准差*根号下(240)
- 最大回撤=净值曲线的任一高点到其后续最低点的下跌幅度的最大值
- 最大盈利=净值曲线的任一低点到其后续最高点的上涨幅度的最大值
- Sharpe比率 = (年化收益率 - 无风险利率)/ 年化标准差
- Sortino比率 = (年化收益率 - 无风险利率)/ 年化下行标准差
- Calmar比率 = 年化收益率 / 最大回撤
# 数据详情-每日绩效页指标

- 日期为回测的历史交易日
- 平仓盈亏=当日卖出持仓收益 - 对应持仓成本
- 浮动盈亏=当日总持仓市值 - 总持仓成本。持仓成本不包含手续费
- 累计手续费 = 累计至当日的手续费总和
- 动态权益 = 当日持仓市值+ 剩余现金
# 数据详情-持仓明细页指标

- 日期为回测的历史交易日
- 品种字段由
市场.类型.代码组成,其中深市代码为SZE,沪市代码为SSE,类型包括ETF和STK(股票) - 持仓数量为当日持仓股数
- 平仓盈亏 = 当日某支票的平仓收益- 对应持仓成本
- 浮动盈亏 = 当日某支票的市值 - 对应持仓成本
# 数据详情-回合明细页指标

- 品种字段由
市场.类型.代码组成,其中深市代码为SZE,沪市代码为SSE,类型包括ETF和STK(股票) - 开仓时间为买单成交时间
- 开仓价格为成交价格
- 开仓订单号为买单订单号
- 平仓时间为卖单成交时间
- 平仓价格为卖单成交价格,平仓订单为卖单订单号,开仓订单号与平仓订单号为多对多关系
- 数量为平仓的股数
- 潜在盈利 = (开仓时间至平仓时间内最高价- 开仓价格 )* 数量
- 潜在亏损= (开仓时间至平仓时间内最低价- 开仓价格 )* 数量
# 数据详情-成交页指标

- 品种字段由
市场.类型.代码组成,其中深市代码为SZE,沪市代码为SSE,类型包括ETF和STK(股票) - 订单号为回测引擎模拟生成的柜台单号,不是功夫生成的下单编号
- 时间为订单每个成交的时间
- 动作表示买入还是卖出成交
- 成交价格为当次模拟撮合的成交价格
- 成交数量为当次模拟撮合的成交股数
# 数据详情-订单页指标

- 品种字段由
市场.类型.代码组成,其中深市代码为SZE,沪市代码为SSE,类型包括ETF和STK(股票) - 订单号为回测引擎模拟生成的柜台单号,不是功夫生成的下单编号
- 时间为订单下单时的回测模拟时间
- 买卖方向表示买入还是卖出成交
- 订单价格为下单价格
- 订单数量为当次下单的数量
- 订单类型全部为限价单
- 下单状态提示订单是否下单成功,配合订单信息展示详细信息
# 实盘兼容接口
事件回调
- on_init - Python策略运行环境初始完成后回调,为了保证程序正常,组件所有代码均在此之后执行
- on_show - Python组件页面被激活展示时的回调,可以重新申请一些on_hide释放掉的资源
- on_hide - Python组件页面被切走时的回调,可以释放一些不必要的资源
- on_close - Python组件页面被关闭时回调,彻底释放掉组件所有资源
方法
- insert_order 全局方法下单
- cancel_order 全局方法撤单
- subscribe 全局方法订阅行情
- unsubscribe 全局方法取消订阅
- add_timer 添加单次定时
- clear_timer 清除单次定时
- add_time_interval 添加轮询定时
- clear_time_interval 清除轮询定时
- getInstrument 查找一个证券
- getETFList 获取可交易的ETF列表
- getETFBasket 获取ETF的成分股列表
- subscribe_bar 全局方法订阅bar行情
- unsubscribe_bar 全局方法取消订阅bar行情
属性
- current_account 当前客户端登录的主资金账号
- instrument_list 所有证券列表
- instrument_map key为证券代码_市场,方便查找证券
- instrument_map_by_type 按证券类型进行区分的证券map列表
- etf_map 可交易etf集合
静态对象
Account实例
- account.subscribe - 所有事件的定义
- account.unsubscribe - 所有数据类型的定义
- account.insert_order 工具集合
- account.cancel_order 数据存储
- account.on_order - 所有事件的定义
- account.on_trade - 所有数据类型的定义
- account.on_quote 工具集合
- account.on_cancel_fail 数据存储
# 策略Demo
# Python策略Demo
from smart import *
import time
from datetime import datetime
import logging
from smart.type import AccountType
logger = logging.getLogger()from smart import *
import time
from datetime import datetime
import logging
from smart.type import AccountType
logger = logging.getLogger()
def init():
#接收委托推送
def callback1(order):
logger.debug("get on_order: %s",smart.utils.toString(order))
smart.current_account.on_order(callback1)
def callback2(trade):
logger.debug("get on_trade: %s",smart.utils.toString(trade))
smart.current_account.on_trade(callback2)
def callback4(position):
logger.debug("get on_position: %s",smart.utils.toString(position))
smart.current_account.on_position(callback4)
account_id = None
side = smart.Type.Side.Buy
#下委托单
def insert_callback(order,err):
logger.debug("get insert_order: %s",smart.utils.toString(order))
#code参数下单
smart.insert_order(code="600918.SH",limit_price = 7.03,volume = 200,side=side,callback = insert_callback)
#批量订阅股票
smart.subscribe(codes= ["600000.SH","000001.SZ"])
instruments= ['000001','000002']
smart.subscribe(account_id,instruments, exchange_id,False)
def callback(quote):
logger.debug("subscribeTest【OK】:%s",smart.utils.toString(quote))
smart.insert_order(instrument_id = quote.instrument_id ,exchange_id = quote.exchange_id ,limit_price = quote.last_price,volume = 600,side=side,callback = insert_callback)
smart.on(smart.Event.ON_QUOTE,callback)
def show():
logger.debug("show")
def hide():
logger.debug("hide")
def close():
logger.debug("close")
smart.on_init(init)
smart.on_show(show)
smart.on_hide(hide)
smart.on_close(close)
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62