策略编写必要基础

知识&技能储备

  • 证券知识:需要了解证券的交易规则、证券分析基本原理
  • 计算机编程:熟悉至少一门计算机语言,熟悉数据结构、能够处理数据、能够编写运算公式和逻辑
  • 数学知识:统计学、高等数学、金融时序数据处理等知识

编写环境准备

  • 量化策略的编写,通常在程序开发环境中结合策略接口完成,因此首先要准备合适的
    • 程序开发环境
    • 策略接口

策略开发环境

  • 比如
    • python 策略可使用 pycharm 集成开发环境
    • matlab 策略需要 matlab 开发环境

策略接口

  • 策略接口可以比作是策略的承载容器
  • 比如
    • pythonSDK
      • 处理许多繁琐的逻辑
      • 包括处理数据、切换运行模式、连接终端等
  • 示例
    • 策略可能要面对的问题
      • 历史数据
      • 实时行情
      • 执行交易
      • 逻辑被调用
      • 回测or实时
      • 下单到哪里
      • 回测参数设置
      • ......
    • 无策略(弱策略)
      • 功能需要自主在策略中编程实现(或部分实现)
    • SDK
      • 声明即可获取功能或结果
        • 终端监控和管理
        • 数据服务
        • 交易通道服务
        • ......

策略基本要素

  • 获取数据
    • 数据包括
      • 行情数据
      • 基本面数据
    • 知识点
      • 有效市场假说
        • 在弱有效市场下,历史数据有助于获取超额利润
  • 分析决策
    • 主流决策
      • 择时(选择最佳买卖时机)
      • 择股(选择最优价值的投资组合)
  • 执行交易
    • 仓位管理
    • 止损
    • 止盈
  • 其他功能
    • 风险控制
    • 标的黑白名单
    • 人工干预因子
  • 策略状态控制
    • 回测参数
    • 异常情况处理
    • 日志信息输出
    • 初始化

用掘金编写策略

  • 将一个投资决策思路以代码的形式组织,使之在计算机上自动执行
  • 能够高效执行投资思路
  • 框架
    • 策略结构
      • 初始化 init
        • 定时接口 schedule()
        • 订阅接口 subscribe()
        • 常量定义 context()
      • 逻辑事件函数 on_xxx(事件附带数据推送功能)
        • 定时事件 on_time()
        • 数据事件 on_bar、on_tick()
        • 交易事件 on_order_status()
        • 其他时间 ......
      • 自定义函数 algo
        • 自定义编写出发条件
    • 策略功能
      • 数据获取
        • 数据接口
          • 历史行情 history()
          • 行情快照 current()
          • 基本面数据 get_fundamentals()
          • 业务数据 get_instruments()
          • 其他数据
      • 分析决策
      • 执行交易
        • 交易接口 order_volume()
        • 目标交易 order_target_volume()
        • 获取信息 get_position、get_cash()
        • 其他交易接口

获取数据

  • 订阅数据,获取实时数据
  • 接口,直通获取历史数据

通过订阅获取高频行情数据

  • 预先订阅数据
    • 用对应的事件函数接收数据
  • 数据发生更新时返回
    • 能够返回指定格式的时间序列划窗数据
  • 伪代码
    • 第一步:订阅数据(参数规格)
      • subscribe(标的列表,数据频率,数据序列长度)
    • 第二步:接收函数标识(全局变量,指定数据返回)
      • on_event(全局变量,指定数据返回)
      • print(指定数据集)
      • print(全局变量)
  • 伪代码说明
    • 模式说明
      • 返回结果跟随策略模式
    • 处理原理
      1. 预先将需要的数据参数,通过 subscribe 订阅接口传至服务器
      2. 服务器建立一个持久的订阅服务
      3. 数据更新时将数据主推返回,并在本地组织成预先设定的数据格式
      4. 返回的数据存放在 context.data 中,并按照频率、品种、字段分类存放
    • 优点
      • 高频方式下,数据返回延时低
      • 本地预先取到全量历史数据
      • 数据格式规整,可获取指定长度的时间序列数据
    • 缺点
      • 只有日频以内的行情数据支持订阅模式
      • 使用方式不如接口方式灵活,只能按固定频率向后递推
    • 适用场景
      • 高频次、规则行情数据的处理
      • 在高频实时行情接收、策略回测时性能高
    • 示例
  • 订阅 平安银行 10个长度1分钟的 bar数据,然后求收盘价均值
  • 通过订阅,将需要的数据申明

    • subscribe(symbols='SZSE.000001', frequency='60s', count=10)
  • 通过 on_bar 函数接收 bar数据事件,并在该函数中求均值

    • on_bar(context,bar)
    • mean(context.data(symbols='SZSE.000001', frequency='60s', fields='close'))

通过接口获取数据

  • 功能
    • 财务数据(收录了上市公司各季度财务报表数据)
    • 历史行情数据(最近的tick数据,较长时间的bar数据
    • 证券基本信息(涨跌停停复牌最小变动价位保证金比例等)
    • 指数成分
    • 交易日历
  • 描述
    • 通过接口返回值获取数据,数据仅返回一次
      • 数据返回=请求函数(参数规格)
      • 查询历史行情数据:获取指定时间段内的历史数据
        • history(标的,频率,开始时间,结束时间,是否复权)
      • 查询基本面数据:获取指定时间段内的历史数据
        • get_fundamentals(表名,字段名,标的,开始时间,结束时间)
      • 查询成分股:获取指数成分股
        • get_consituents(指数代码)
      • 查询业务数据:获取交易日期列表
        • get_trading_dates(交易所,开始时间,结束时间)
  • 处理方式
    • 函数、参数、直连服务器,服务器响应后将数据返回
  • 模式
    • 直连服务器,无模式
  • 结果保存
    • 订阅后的数据滑窗储存在 context.data
      • 提取数据需要调用 context.data() 接口
    • 可以在自定义函数algo()中调取或是在on_xxx()事件驱动函数中调取
    • 调取格式为
      • data = context.data(标的,频率,滑窗大小,字段)
  • 优点
    • 可获取的数据种类多,使用场景灵活
    • 一次性返回较大数据量
    • 可直接获取指定数据
  • 缺点
    • 和服务器往返交互,高频调用时对网络和服务器状态依赖大,效率不高
    • 策略历史模式运行时容易引入未来数据,导致回测失真
  • 适用场景
    • 低频次,大数据量的数据获取
  • 示例
    • 查询行情快照
      • current_data = current(symbols='SZSE.000001')
    • 查询历史行情数据,并以结构方式返回
      • history_data = history(symbol='SHSE.000300', frequency='1d', start_time='2010-07-28', end_time='2017-07-30', df=True)
    • 查询财务数据,在股票交易衍生表中查询几个字段的值
      • get_fundamentals(table='trading_derivative_indicator', symbols='SHSE.600000, SZSE.000001', start_date='2017-01-01', end_date='2017-01-01', fields='TCLOSE,PETTMNPAAEI')

分析决策

  • 需要处理的问题
    • 策略中决策的类型有哪些?
    • 不同类型的决策逻辑如何被自动的调用
    • 怎么更快速的让决策逻辑介入待决策事件
    • 决策逻辑如何获取待决策数据
  • 决策分类为几类事件
    • 数据分析决策
    • 交易回报决策
    • 定时接口
  • 当事件发生时,对应的事件函数会被自动调用
    • 数据到达时
    • 交易回报返回时
    • 定时被调用
  • 调用方式通过专有程序监控,及时执行对应事件函数,并将事件内容当做参数传入

定时决策

  • 处理方式
    • 预先通过schedule()配置定时任务函数
    • 配置的定时函数将在指定的时间被执行
  • 模式
    • 跟随策略模式
  • 优点
    • 直接指定运行时间,使用场景灵活
  • 缺点
    • 行情的更新时间和本地时间是不一致的,容易错失重要行情的信息
  • 适用场景
    • 一般用于低频定时执行,比如盘前选股尾盘定时交易
  • 示例
    • 定时每天早上9:30执行algo函数
      • 启动定时
        • schedule(schedule_func=algo, date_rule='1d', time_rule='9:30:00')
    • 执行定时
      • algo(context):
        • 定时执行的函数内容

事件发生时决策

  • 处理方式
    • 指定事件发生时触发专用事件函数
    • 事件类型由SDK提供
    • 事件的内容作为入参传入
    • 函数包括:
      • 行情更新事件 bar(tick)
      • 成交回报事件 execrpt
      • 处理委托 order
      • 系统连接异常事件
  • 模式
    • 跟随策略模式
  • 优点
    • 响应速度快,方便设置专门逻辑对事件进行处理
  • 缺点
    • 事件的类型为预先设定,类型有限;
    • 过高频的触发可能导致拥堵,需要预先考虑事件的处理速度量级
  • 适用场景
    • 要求及时处理的事件,比如
      • 行情更新
      • 订单成交
  • 示例
    • 下单
      • order_volume()
    • 回报事件函数
      • on_execution_report(成交回报)
    • 撤单
      • order_concel(cl_ord_id)

执行交易

  • 包含基本的自动交易功能
  • 支持策略完成订单管理资金管理持仓管理功能

交易接口

  • 处理方式
    • 将不同品种、多种场景统一的交易接口
    • 返回统一格式的委托信息
    • 委托通过系统主键cl_ord_id唯一标识,可直接用于查询和撤单入参
  • 模式
    • 跟随策略模式
    • 自动接入不同交易通道
      • 回测
      • 仿真
      • 实盘
  • 优点
    • 下单格式统一(跨品种,跨模式,跨柜台)
  • 适用场景
    • 关于交易的所有功能:
      • 下单
      • 撤单
      • 委托查询
      • 回报查询
  • 示例
    • 定量委托(依次解释为:标的,委托量,委托方向,委托类型(市价/限价),仓位类型(多仓/空仓),价格)
      • order_volume(symbol='SHSE.600000', volume=10000, side=OrderSide_Buy, order_type=OrderType_Limit, position_effect=PositionEffect_Open, price=11)
    • 定价值委托
      • order_value(symbol='SHSE.600000', value=10000, side=OrderSide_Buy, order_type=OrderType_Limit, position_effect=PositionEffect_Open, price=11)
    • 目标持仓委托
      • order_target_volume(symbol='SHSE.600000', volume=10000, order_type=OrderType_Limit, position_effect=PositionEffect_Open, price=11)
    • 查询委托
      • get_orders()
    • 撤单(cl_ord_id唯一标识)
      • order_cancel(cl_ord_id)

账户查询

  • 处理方式
    • 提供账户查询、资金查询、持仓查询接口
  • 模式
    • 跟随策略模式
    • 自动接入不同交易通道账户:回测、仿真、实盘
  • 优点
    • 提供统一的策略查询接口
  • 适用场景
    • 查询可用资金:总资产、可用金、保证金、冻结资金……
    • 查询持仓:持仓成本、持仓价格、可用持仓……
  • 示例
    • 查询资金
      • cash = cash()
      • 查询持仓
      • positions = positions()

策略范式

  • 策略平台约定的一些规则
  • 在尽量遵照交易所规定、行业规范、约定俗成的基础上,使平台更加简化、通用和灵活
  • 熟悉这些规则能够帮助 QUANT 了解平台的逻辑架构,快速在平台上完成量化策略
名称 类型 说明
run 函数 策略启动入口函数
main 函数 用于策略编写的主文件名,可通过 run 函数中的 filename 指定
strategy_id 参数 策略id,用于终端识别策略身份的唯一标识
token 参数 登录身份信息的标识,服务器通过该标识识别账户
mode 参数 策略运行参数,通过在 run 函数指定 mode:MODE_LIVE(实时)=1,MODE_BACKTEST(回测) =2
init 函数 策略初始化函数
context 全局变量 系统默认的全局变量名,可用于:获取订阅的时序数据、系统参数、自定义全局变量
log 函数 实时运行时可以将日志输出到终端监控页面
on_xxx 函数 xxx表示事件名,系统提供多种常用的决策事件共策略调用:数据事件定时事件交易事件异常事件
symbol 参数 标的参数,标的格式为:交易所.代码,如深交所平安银行,‘SZSE.000001’
frequence 参数 数据频率,支持格式为:‘60s’,‘300s’,‘900s’,‘1d’
fields 参数 数据字段,用于选定返回数据的字段
adjust 参数 复权模式,用于指定历史行情数据的复权模式
bar 数据结构 对应K线的 Bar (一根蜡烛节点,是该段时间内 tick 的统计),其中包含开高低收量等统计信息
tick 数据结构 对应交易所的 tick 数据(推送频率取决于交易所),不同交易所的 tick 数据流解析为相同规格的数据
cl_ord_id 参数 订单数据的主键,通过该主键撤单和识别订单,在下单函数调用成功时自动生成

策略的一般组织形式

策略运行函数 run

  • 策略运行函数的作用是策略运行控制
  • 可看做是无关策略逻辑内容系统功能设置
参数 作用
strategy_id 策略id,用于终端识别策略身份的唯一标识
filename 指定策略主函数的名称
mode 策略运行模式,MODE_LIVE(实时)=1,MODE_BACKTEST(回测) =2
token 登录身份信息的标识,服务器通过该标识识别账户
backtest_start_time 回测开始时间
backtest_end_time 回测结束时间
backtest_initial_cash 回测初始资金
backtest_transaction_ratio 成交比率,最大成交量占比,用于防止不切实际的成交量
backtest_commission_ratio 回测交易手续费,仿真的在终端设置
backtest_slippage_ratio 回测滑点,用于模拟冲击成本
backtest_adjust 复权方式,采用复权撮合可以不用盘后结算,速度更快,但是价格和当时价格不一致,ADJUST_NONE(不复权),ADJUST_PREV(前复权),ADJUST_POST(后复权)
backtest_check_cache 回测缓存,回测一次后数据就会被缓存起来,重复回测更快
serv_addr 终端地址,默认情况下无需设置,SDK运行无法脱离终端(很多动态资源是终端在管),需要指定一个登陆状态的终端

策略主体函数

  • 策略主体函数是由自己编写,一般策略的组成结构如下
    • 策略结构
      • 初始化 init
        • 定时接口 schedule()
        • 订阅接口 subscribe()
        • 常量定义 context()
      • 逻辑事件函数 on_xxx(事件附带数据推送功能)
        • 定时事件 on_time()
        • 数据事件 on_bar、on_tick()
        • 交易事件 on_order_status()
        • 其他时间 ......
      • 自定义函数 algo
        • 自定义编写出发条件
  • 示例:以均线突破指标策略为例,组织一个五脏俱全的简单策略
  • 文件名:main.xxx
description
- 1. %% main 函数作为默认的策略编辑函数
- 2. function [Context] = main(Context,Event)
- 4. %% 首行注释一般用于说明该段策略代码的功能、逻辑等
- 5. % 策略名:均线突破策略
- 6. % 第一步:设定交易股票池,订阅股票池数据,分别针对个股做以下决策
- 7. % 第二步:60分钟均线突破3日均线作为指标
- 8. % 如果向上突破,且无持仓,则按一定资金比例买入
- 9. % 如果向下突破,且有持仓,则卖出所有持仓
- 10. % 第三步:止损指标,判断持仓时间,如果超过两天,就平仓了结
- 12. if Event.初始化 % 初始化操作
- 13. 股票池 = 'xxxxx' % 设定股票池
- 14. subscribe(symbols, '1分钟数据',长度20); % 订阅数据
- 15. subscribe(symbols, '1天数据',长度10);
- 16. Context.周期1 = 20; % 设定均线周期
- 17. Context.周期2 = 10;
- 18. end
- 20. 周期1=Context.周期1;
- 21. 周期2=Context.周期2;
- 22. 1分钟时序数据 = Context.data.1分钟数据.收盘价(周期1);
- 23. 1天时序数据 = Context.data.1天数据.收盘价(周期2);
- 25. if Event.1分钟数据更新时
- 26. % 计算突破因子
- 27. 突破因子 = mean(1分钟时序数据)-mean(1天时序数据 );
- 28. 资金= get_cash();
- 29. 仓位 = get_position();
- 30. for i = 所有股票循环
- 31. % 60分钟均线突破3日均线作为指标
- 32. if 突破因子(i)>0
- 33. if 持仓.数量==0 %没有仓位则开仓
- 34. 订单对象=order_value(标的, 资金*0.1, 买入, 市价,开仓,价格);
- 35. end
- 36. else
- 37. if 持仓.数量~=0 % 有仓位则平仓
- 38. 订单对象=order_value(标的, 持仓.数量, 卖出, 市价,平仓,价格);
- 39. end
- 40. end
- 41. % 止损指标
- 42. if Context.now-仓位.时间>2天 且 持仓.数量~=0
- 43. 订单对象=order_value(标的, 持仓.数量, 卖出, 市价,平仓,价格);
- 44. end
- 45. end
- 47. end

用掘金优化策略

  • 提高策略的交易绩效
  • 通过历史回测实时仿真结合绩效分析手段反复优化策略模型,达到提高策略决策能力的目的
  • 萌生 idea
    • 策略idea萌生时,一般是模糊、带有主观经验的概念
    • 需要理清思路,运用建模技巧、数学知识组织成一个完整的推理过程
    • 且会是一个反复推到重建的优化过程
  • 构思模型
    • 思路-模型化过程,模型的构建就是要尽可能的完整的表示思路
    • 将模型思路转化为计算机逻辑的过程,和人的一般思维有区别
      • 计算机局限于顺序、判断、循环组成的逻辑流,需要一定的编程实现能力
  • 编写/调试
    • 策略编写和调试一般在回测模式下进行,反复调试,直到策略能够完整的实现模型内容且能够顺畅运行
  • 回测
    • 将历史数据按时间切片模拟真实数据返回给策略
    • 策略获取数据、分析决策、执行交易后,经回测柜台进行模拟撮合和结算,再将结果返回给策略,模拟一个完整的投资行为
    • 最终的交易信息会输出到绩效服务,得到历史区间内的交易绩效报告
  • 仿真交易
  • 实盘交易
  • 绩效分析
    • 根据交易绩效报告,了解策略的交易详情收益变化资金利用风险敞口风格偏向等特征作为策略优化的方向
  • 构思模型
  • ......
  • 备注:
    • 历史数据的效果不能完全代表未来
    • 回测优化中经常存在过拟合未来函数(数据)等干扰因素
    • 回测中速度和精度难以共存粗精度回测结果失准
    • 回测中冲击成本(滑点)流动性等问题无法模拟

仿真-分析过程

  • 策略实盘前精度最高的策略有效性检验
  • 策略仿真运行需要切换策略运行模式并绑定仿真账户
  • 仿真交易使用实时行情盘口撮合,撮合更加精确
  • 备注
    • 仿真数据同步实时数据,数据样本小,模型优化耗时
    • 仍然不能解决冲击成本和流动性问题

实盘-分析过程

  • 会承受真实损失