模拟仿真
模拟交易
新建模拟交易(客户端:菜单路径:量化交易-模拟交易-新建模拟交易)
选择策略名称和回测名称:
(确保新建模拟交易之前 有策略,并确保有回测结果)
您可以选择从当前日开始模拟 或 在已有的回测基础上继续模拟。
暂停模拟交易
点击模拟交易卡片的 右下方的暂停按钮:
删除模拟交易
当显示提示“策略删除成功” 表明策略已经删除。
模拟交易收益走势
点击收益走势 标签:
可以查看收益走势曲线,可以选择特定时间段的收益曲线。
模拟交易交易明细
点击交易明细 可以查看 交易时间、证券代码、证券名称、操作、交易价格、交易数量、交易金额:
点击右侧的导出可以导出选定时间范围内的交易明细文件。
模拟交易持仓情况
点击持仓状况 可以查看特定日期下的持仓状况。
您可以选择日期查看其他日期的持仓情况:
模拟交易策略代码
点击策略代码 查看当前模拟交易使用的策略代码:
模拟交易运行日志
点击运行日志 可以查看系统日志:
模拟交易更换代码
前提:更换代码前,请先暂停模拟交易。
点击更换代码可以切换代码,需要选择一个策略和一个成功的回测,点击确认后,代码会切换到选择策略下的 选择的回测对应的代码:
模拟交易查看更换记录
点击更换记录 按钮 可以查看代码更换记录:
以上截图为客户端的截图 但是 网页的使用方式基本雷同,也可以参考。
模拟交易机制
策略运行时间
开盘前(9:00)运行
- init(该函数只在策略第一次启动时运行一次,但get_iwencai每天开盘前均会运行一次。 )
- before_trading
盘中运行
- handle_bar
- 日级策略(9:31:00)运行一次
- 分钟级策略(9:31:00-11:30,13:01:00-15:00:00),每分钟运行一次
收盘后(15:30)运行
- after_trading
模拟交易中订单撮合机制
针对日级策略和分钟级策略,订单撮合机制略有不同。
日级策略
以9:30-9:31之间成交量做判断,如果该段时间成交量为0,则股票不予下单;如果成交量不为0,则全部下单。
分钟策略
-
模拟交易采用交易所level-1实时行情数据,每分钟获取一次。
-
撮合方式:(默认为市价单)
- 市价单:以涨停价/跌停价下单,下单函数触发时点下单,即时匹配5档盘口数据,之后每分钟匹配一次5档盘口数据,不成交或未成交部分顺延至下一分钟进行撮合,直到完全成交或者当天收盘为止。
- 限价单:以限定价格下单,策略下单函数触发点下单,即时匹配5档盘口数据,之后每分钟匹配一次5档盘口数据,不成交或未成交部分顺延至下一分钟进行撮合,直到完全成交或者当天收盘为止。
- 一天结束后, 所有未完成的订单会被取消。
- 每次订单完成(完全成交)或者取消后。我们会根据成交量计算手续费,减少您的现金。
- 模拟交易成交数量会根据策略里set_volume_limit 设置的最大成交比例进行限制,默认25%。如果您的策略买卖标的涉及到低流动性标的,由于其本身的流动性较差,你的订单并不会及时成交,甚至一天都不会成交!
分红送股机制
当股票发生拆分,合并或者分红时,股价会出现跳空缺口,为了消除这种价格变化对模拟交易结果的影响,我们会根据个股除权除息信息对账户中的现金或持股数量进行相应的调整修正,并自动更新到您的account信息中。
为了使模拟交易结果更加准确,我们做了如下处理:
- 模拟交易所用价格数据与下单所用价格数据是独立的。即在模拟交易过程中,您可采用前复权/不复权或后复权价格来计算交易下单信号,模拟交易均采用真实价格(即不复权价格)下单。
- 模拟交易会在除权除息当日,调用before_trading函数之前,自动处理并更新您的账户信息。
前复权数据
前复权数据采用动态复权模式,即在模拟交易过程中,轮循至某个股除权除息日,则按除权后价格对之前的价格数据进行调整。
股指期货交易机制
- 股指期货交易手续费规则:投资者在进行期货合约交易时,交易所根据投资者买卖期货成交合约的总价值,向投资者收取一定比例的手续费。
- 计算公式:手续费 = 成交点位 交易手数 合约乘数 手续费率
- 合约乘数:IF(300元/点),IH(300元/点),IC(200元/点)
- 股指期货交易保证金规则:投资者在进行期货合约交易时,不需要支付合约价值的全额资金,只需要支付一定比例的保证金就可以进行期货合约交易,由此可见,股指期货交易具有杠杆性。
- 计算公式:保证金 = 成交点位 交易手数 合约乘数 保证金比例
- 股指期货合约强制平仓规则:投资者在进行期货合约交易时,当投资者账户内的保证金低于交易所规定保证金比例时,交易所会对投资者的持仓进行强制平仓,从持仓中亏损最多的合约开始平仓,直至保证金再次高于规定保证金比例。
- 股指期货合约交割与结算规则:股指期货合约实行现金交割制度,遇到交割日时,会在收盘时清仓,以交割日结算价作为成交价。交割结算价是当日现货盘面指数最后2小时的算术平均价。正常交易日结算价作为计算当日盈亏的依据,是当日期货盘面交易最后一个小时的成交价格按照交易量的加权平均价。合约最后一小时无成交的,以前一小时成交价格按照成交量的加权平均价作为当日结算价,以此类推。
- 完整股指期货交易细则请参考中金所交易细则。
模拟交易消息推送
模拟交易消息推送。
什么是Webhook?
webhook 是一种基于 HTTP 的回调函数,可在 2 个应用编程接口之间实现轻量级的事件驱动通信。许多种类的应用使用 webhook 来从其他应用接收少量数据。因为他十分的灵活便捷所以被广泛应用,如企业微信、飞书、钉钉都开放了webhook的调用方式。
Webhook如何填写?
先获取您接受消息的软件的webhook地址。
再进入这里填写地址:消息推送
如何获取企业微信Webhook地址
为群机器人添加基本的头像和名称信息后,点击“添加机器人”,会获得一个 webhooks 地址,请复制这个地址。(注:请妥善保管好此 webhooks 地址,不要公布在公开查阅的网址上,避免地址泄露后被恶意调用。)
然后填写到Supermind的webhook填写地址内。
获取飞书Webhook地址
为群机器人添加基本的头像、名称及描述信息后,点击“添加”,会获得一个 webhooks 地址,请复制这个地址。
获取钉钉Webhook地址
首先选择需要添加机器人的群聊,然后依次单击“群设置”-“智能群助手“。
在“机器人管理”界面“添加机器人”,可以搜索“自定义”,添加自定义机器人。
添加后,输入机器人名字,可以为机器人设置机器人头像,完成必要的安全设置,勾选我已阅读并同意《自定义机器人服务及免责条款》,然后单击完成后,复制出 webhooks 地址。
仿真柜台
仿真柜台介绍
模拟交易在撮合机制上和回测没有很大的区别,和真正的实盘相比,存在以下问题:
- 回测时不考虑代码本身的计算耗时,而实际上在实盘中,代码的运行耗时会带来延时成本
- 由于网络延迟和订单撮合时间,实盘中委托不会立即成交;而在回测中,可以成交的委托时立即成交的。
- 回测的资金账号永远不存在初始持仓已经手动操作的干扰,而实际上实盘中这种外部的干扰会对策略运行造成影响
而仿真柜台就是完全仿照实盘柜台的环境,可以测试出以上这些问题给策略带来的影响。因此,相比于模拟交易,仿真柜台交易是一种和实盘更接近的方式
使用流程
- 首先需要下载安装SuperMind客户端:SuperMind终端
- 打开SuperMind客户端,并确保需要使用交易接口的账户处于已登录状态
- 进入量化交易标签下的研究环境,并创建一个python笔记本文件(ipynb文件)
- 初始化交易接口
from tick_trade_api.api import TradeAPI
trade_api = TradeAPI(account_id='84728199') #填入已登录的资金账号
- 将策略代码以字符串的形式传入
research_trade
函数,并执行,具体可以参考研究环境-模拟仿真
回测代码直接 仿真/实盘交易 只需一分钟!
背景与目的
之前我们有了策略回测代码,到实盘要经过熟悉实盘API、写代码、调试代码的环节,大概还需要1-2周的时间才能实盘,有非常多的用户到这一步 会束手无策,甚至放弃!
现在,有了回测代码直接实盘的功能,可以省去这个步骤,让刚入门的朋友也可以直接拿回测代码进行实盘了。很棒!为我们的工程师点赞!
此外还新增了一些接口,方便实盘交易。
不断降低实盘的门槛是我们的目标,如果您有任何好的想法意见请随时留言!
本功能需要重启研究环境才能生效!
策略实盘交易(回测代码1分钟实盘)
- ?调用方法:
research_trade( name, source_code, capital_base=100000, frequency='DAILY', stock_market='STOCK', benchmark=None, trade_api=None, signal_mode=True, dry_run=False, recover_dt=False, )
- ?参数说明:
- name:str,策略名称,会在./persist/下生成一个同名目录,用于存放持久化的策略信息
- source_code:str,策略代码,可从策略研究模块中直接复制,代码置于"""..."""中
- capital_base: float,初始资金量
- 如果接入了TradeAPI对象,且
signal_mode=False
,那么此参数无意义
- 如果接入了TradeAPI对象,且
- frequency: str,策略频率,'DAILY'或'MINUTE'
- stock_market: str,策略类型,默认'STOCK'
- benchmark: str,基准指数
- trade_api: TradeAPI对象,绑定需要仿真交易的资金账号
- signal_mode: bool,(新增)默认为
True
signal_mode=True
,此时策略实际上运行的时初始资金为capital_base的模拟交易,context、get_orders等方法返回的结果均为模拟交易中计算的数据,与资金账号的数据无关;策略下单在模拟交易撮合成交后,才会通过trade_api下单至柜台signal_mode=False
,此时策略中context、get_orders等方法返回的结果均为从 柜台查询,策略下单也会直接下至柜台
- dry_run: bool,试运行,立即返回,默认为
False
- recover_dt: bool或 str,(新增)是否断点运行,默认为
False
recover_dt=False
,从当前时点开始执行,不从断定运行recover_dt=True
,从上次策略结束时点开始运行recover_dt='today'
,从当日开始运行,此模式下只会补执行before_trading
与open_auction
,handle_bar
依旧从当前时间开始执行recover_dt='yyyyMMdd HH:mm'
,从指定时间开始运行
- ?️ 返回值:
- ?作用:
- 模拟交易:撮合机制与回测相同
- 仿真交易:通过仿真柜台撮合,更贴近真实交易环境
- ❗注意事项:
- 策略需在9:00前开启运行,否则在未设置recover_dt的情况下,会跳过before_trading等步骤
- 初始化TradeAPI时需要指定下单策略order_policy,MarketPolicy为市价下单;LimitPolicy为限价下单。如未指定,由于策略下单时使用均价,可能存在多位小数,最终实盘账户下单的时候可能产生废单
signal_mode=True
时,如想在context中获得仿真账号的持仓、资金等数据,可以使用同步函数sync_trade_api()
- ?示例:
from tick_trade_api import TradeAPI #初始化TradeAPI时需要指定下单策略,MarketPolicy为市价下单;LimitPolicy为限价下单 trade_api=TradeAPI('69271711',order_policy=MarketPolicy) source_code=""" # 股票策略模版 def init(context): pass # 盘前执行 def before_trading(context): pass # 开盘时运行函数 def handle_bar(context, bar_dict): order_id = order('000001.SZ', 100) print(get_orders()) try: cancel_order(order_id) except: print('撤单失败') print(get_open_orders()) print(get_tradelogs()) print(context.portfolio.stock_account) print(context.portfolio.positions) """ rtrade = research_trade( '研究环境策略', source_code, frequency='MINUTE', trade_api=trade_api, signal_mode=False, recover_dt='today' )
trade_api=TradeAPI('69271711',order_policy=MarketPolicy) 中的账号是模拟资金账号或者是实盘资金账号。
其他更新
这次还增加了几个功能
策略框架中增加 :
- cancel_order_all() 全撤
- get_tradelogs()获取当日全部成交订单
- get_orders() 获取委托,和get_order()一致,主要时和tradeapi中函数名对齐
tradeapi增加:
- get_open_orders() 获取当日未成订单
- cancel_order_all() 全撤
策略仿真/实盘与策略回测中的差异问题以及解决方案
汇总一下目前实盘遇到比较多的问题、产生的原因以及如何解决问题。首先得从回测环境和实盘环境的一些区别开始说起
回测(模拟)与仿真柜台的区别?️
回测(模拟)环境和柜台环境(仿真、实盘)会有部分差异,如果在策略中不考虑这些差异并做对应处置,可能会导致策略在回测中正常运行,导致策略在仿真、实盘中出现bug。
梳理了一下目前主要有6个不同点(如有遗漏请补充):
回测 | 仿真 | |
---|---|---|
1️⃣ | 一般没有初始持股 | 可能有初始持股 |
2️⃣ | 委托通常会立刻成交 | 委托不会立刻成交 |
3️⃣ | 持仓数据中有持仓天数position_days | position_days一直等于0 |
4️⃣ | 不存在策略外交易 | 策略外交易会影响策略内 |
5️⃣ | 很少有撤单的场景 | 最好需要考虑撤单 |
6️⃣ | 回报没有延迟 | 回报有延迟 |
可能导致的问题与解决方案?️
问题一:资金账号内有初始持仓
策略在回测/模拟中,在不设置的情况下是不会有初始持仓的,而在实际交易中,资金账号通常会有初始持仓。
- 可能导致的问题:
- 部分策略内部存在内部记录持仓信息的逻辑,在资金账号有初始持仓时,使用research_trade运行策略时,如果有加入同步函数sync_trade_api()或者策略的 signal_mode=False,策略内部无初始持仓的信息,可能导致冲突报错
- 案例:策略库中的问财分钟模板
在以上策略中,策略会将买入股票的信息记录在字典 context.information
中。当资金账户有初始持仓时,卖出这部分股票的时候,策略会将 context.information
中的持仓信息删除,但由于 context.information
字典没有这部分股票代码的key(因为不在策略内买入,没有记录),使用del方法删除持仓信息时导致报错:
- 解决方案(用户侧,具体方案需视策略实际情况而定):
- 初始化时在
context.information
中记录初始持仓信息 - 策略运行时不要在策略外部进行交易
- 使用dict.pop()删除字典中的key,而不是del方法
- 初始化时在
- 长期解决方案(SuperMind功能优化):
- 以策略为单位构建资产单元(类似分仓功能),将策略内外部资金、持仓、委托、成交数据隔离(预计7月-8月)
问题二:实盘中委托通常不会立即成交
- 可能导致的问题:
- 策略内部存在内部记录持仓信息的逻辑,在委托后立即记录买入,实际上委托后不会立刻成交(等待时间视委托价格和当前行情走势而定)。此时就有可能导致信息被漏记/多记
- 案例:示例代码
import time
def init(context):
g.information = {}
g.symbols = ['000001.SZ','600519.SH']
def handle_bar(context):
for symbol in g.symbols:
order(symbol,100)
for symbol in list(context.portfolio.positions):
g.information[symbol] = 1
time.sleep(3)
for symbol in list(context.portfolio.positions):
print(g.infomation[symbol])
以上代码在回测中通常不会出现问题,因为撮合是在策略内部串行且市价单通常可以成交。但是在实盘中,股票下单后汇报和撮合不会像回测中那样进行,订单的撮合和策略时同步进行的,此时,按示例代码的方式,就可能会由于订单未成交,导致信息未被记录进g.information
,而在三秒之后订单成交,再使用持仓代码去读g.information
的数据时,导致策略出错。
- 解决方案(用户侧,具体方案需视策略实际情况而定):
- 优化记录持仓信息的代码,比如在收盘后根据持仓、成交等信息统一进行计算,减少漏记、多记的发生
- 考虑使用dict.get()函数获取字典内的数据
- 长期解决方案(SuperMind功能优化):
- 增加成交回报事件、委托状态更新事件推送(计划6月底前)
问题三:券商/仿真柜台返回的持仓数据中没有position_days数据
- 可能导致的问题:
- 策略内使用此数据来进行控制最大持仓天数部分代码可能失效
- 案例:示例代码
from datetime import timedelta as td
def init(context):
g.symbols = ['000001.SZ','600519.SH']
g.status = True
def handle_bar(context):
if g.status:
for symbol in g.symbols:
order(symbol,100)
g.status = False
else:
for k,v in context.portfolio.positions:
trade_days = get_datetime() - td(v.positions_days)
tdays = len(get_trade_days(
trade_days.strftime('%Y%m%d'),
get_datetime().strftime('%Y%m%d')
))
if tdays>5:
order_target(k,0)
此示例代码希望实现的是买入股票池后持有5天后卖出,在回测中没有问题,但是在仿真/实盘中,由于柜台没有positions_days的数据,因此v.positions_days一直会等于0,导致此部分代码无法实现预期效果。
- 解决方案(用户侧,具体方案需视策略实际情况而定):
- 增加记录持股天数的数据,但需要注意避免问题一和问题二
- 长期解决方案(SuperMind功能优化):
- 以策略为单位构建资产单元(类似分仓功能),将策略内外部资金、持仓、委托、成交数据隔离(预计7-8月),并根据此计算出position_days数据
问题四:策略外交易会影响策略内
- 可能导致的问题:
- 手动买入的持仓被策略卖出,手动卖出的持仓被策略买回
- 策略代码报错
- 解决方案(用户侧,具体方案需视策略实际情况而定):
- 处理起来比较麻烦,改动比较多,代码能弱的同学暂时尽可能不要在策略外做手动交易
- 长期解决方案(SuperMind功能优化):
- 以策略为单位构建资产单元(类似分仓功能),将策略内外部资金、持仓、委托、成交数据隔离(预计7-8月)
问题五/问题六:实盘中需要考虑更复杂的场景
- 策略回测及模拟交易时,策略可以说实在相对静态的环境下运行的,并且时不考虑延迟的。而在实际的交易中,市场瞬息万变,无论是数据获取、计算耗时这种,还是下单与回报的延迟(不可控),都会导致实盘中产生更复杂的情景
- 可能导致的问题:
- 考虑订单长期未成交情况下的处理方式,回测中对手价/市价单通常可以立刻成交,而实际交易中则相对来说有较大概率不会立刻成交
- 例如:价格变动剧烈时,下单后未成交,又未及时撤单、追单,降低资金效率。可能会影响策略调仓,造成策略表现变差
- 在策略逻辑上充分考虑到订单生成、下单到券商柜台、券商柜台回报所产生的延迟,避免策略出现异常
- 例如:在下单后立刻撤销订单,此订单刚生成,未完成初始化,处于不可撤销的状态,从而导致报错
- 尽可能减少在handle_bar中获取任何数据,提高计算效率,避免策略本身产生较高的延时
- 例如:handle_bar在9.31分被触发,从触发到下单中间计算耗时五分钟,在回测中,订单仍然会以9.31分的行情数据进行撮合。而在实盘中,订单会在9.36分被发出,从而产生延时成本。
- 考虑订单长期未成交情况下的处理方式,回测中对手价/市价单通常可以立刻成交,而实际交易中则相对来说有较大概率不会立刻成交
- 解决方案(用户侧,具体方案需视策略实际情况而定):
- 考虑复杂场景,并增加相对于的策略代码
- 解决方案(SuperMind功能优化):
- 增加成交回报事件、委托状态更新事件推送(计划6月底前)
总结
目前遇到的主要就是这些问题,如果在交易过程中有其他问题,也可以在本贴留言,最好可以提供测试代码复现问题便于我们查找原因。