# 快速上手

# 编写策略

用户可参照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配置的费率。

手续费

  1. 买入订单费用计算 每笔成交手续费 = (手续费 + 过户费) * 成交额 + 印花税 * 成交额 默认买入订单印花税为0。

  2. 卖出订单费用计算 每笔成交手续费 = (手续费 + 过户费) * 成交额 + 印花税 * 成交额

  3. 最低手续费计算 订单在交易时段全部交易成功则检查该单关联的所有成交手续费之和, 如果该值小于最低手续费 , 则通过调整最后一笔成交成交费用以实施“最小手续费”规则

# 绩效回测指标解析

# 绩效概览页面指标

回测绩效

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

# 数据详情-每日绩效页指标

每日绩效

  1. 日期为回测的历史交易日
  2. 平仓盈亏=当日卖出持仓收益 - 对应持仓成本
  3. 浮动盈亏=当日总持仓市值 - 总持仓成本。持仓成本不包含手续费
  4. 累计手续费 = 累计至当日的手续费总和
  5. 动态权益 = 当日持仓市值+ 剩余现金

# 数据详情-持仓明细页指标

每日持仓

  1. 日期为回测的历史交易日
  2. 品种字段由市场.类型.代码组成,其中深市代码为SZE,沪市代码为SSE,类型包括ETFSTK(股票)
  3. 持仓数量为当日持仓股数
  4. 平仓盈亏 = 当日某支票的平仓收益- 对应持仓成本
  5. 浮动盈亏 = 当日某支票的市值 - 对应持仓成本

# 数据详情-回合明细页指标

买卖回合

  1. 品种字段由市场.类型.代码组成,其中深市代码为SZE,沪市代码为SSE,类型包括ETFSTK(股票)
  2. 开仓时间为买单成交时间
  3. 开仓价格为成交价格
  4. 开仓订单号为买单订单号
  5. 平仓时间为卖单成交时间
  6. 平仓价格为卖单成交价格,平仓订单为卖单订单号,开仓订单号与平仓订单号为多对多关系
  7. 数量为平仓的股数
  8. 潜在盈利 = (开仓时间至平仓时间内最高价- 开仓价格 )* 数量
  9. 潜在亏损= (开仓时间至平仓时间内最低价- 开仓价格 )* 数量

# 数据详情-成交页指标

每日成交

  1. 品种字段由市场.类型.代码组成,其中深市代码为SZE,沪市代码为SSE,类型包括ETFSTK(股票)
  2. 订单号为回测引擎模拟生成的柜台单号,不是功夫生成的下单编号
  3. 时间为订单每个成交的时间
  4. 动作表示买入还是卖出成交
  5. 成交价格为当次模拟撮合的成交价格
  6. 成交数量为当次模拟撮合的成交股数

# 数据详情-订单页指标

每日订单

  1. 品种字段由市场.类型.代码组成,其中深市代码为SZE,沪市代码为SSE,类型包括ETFSTK(股票)
  2. 订单号为回测引擎模拟生成的柜台单号,不是功夫生成的下单编号
  3. 时间为订单下单时的回测模拟时间
  4. 买卖方向表示买入还是卖出成交
  5. 订单价格为下单价格
  6. 订单数量为当次下单的数量
  7. 订单类型全部为限价单
  8. 下单状态提示订单是否下单成功,配合订单信息展示详细信息

# 实盘兼容接口

事件回调

  • on_init - Python策略运行环境初始完成后回调,为了保证程序正常,组件所有代码均在此之后执行
  • on_show - Python组件页面被激活展示时的回调,可以重新申请一些on_hide释放掉的资源
  • on_hide - Python组件页面被切走时的回调,可以释放一些不必要的资源
  • on_close - Python组件页面被关闭时回调,彻底释放掉组件所有资源

方法

属性

静态对象

  • Event - 所有事件的定义
  • Type - 所有数据类型的定义
  • utils 工具集合
  • cache 数据存储

Account实例

# 策略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)


1
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