├── 1_before-your-start ├── 1.1-chose-a-stable-os.md ├── 1.2-openquant-product-family.md ├── 1.3-download-and-install-openquant.md ├── 1.4-gui-of-openquant.md ├── 1.5-config-plugins.md ├── 1.6-import-instruments.md ├── 1.7-import-historical.md ├── 1.8-run-a-demo-strategy.md └── README.md ├── 2_manage_your_work ├── README.md └── manage-your-coding-by-svn.md ├── 3_structure_of_openquant_solution ├── README.md └── structure-of-openquant-solution.md ├── 4_hello_world ├── 41-design-an-openquant-helloworld.md ├── 42-new-a-solution.md ├── 43-code-the-baketest-scenario.md ├── 44-code-mystrategy-for-helloworld.md ├── 45-code-the-realtime-scenario.md ├── 46-let-us-run-helloworld.md ├── README.md ├── code-an-openquant-helloworld.md ├── design-an-openquant-helloworld.md └── hello-world.md ├── 8_a-basic-strategy ├── 81-linescrossover-strategy.md └── README.md ├── README.md ├── SUMMARY.md ├── assets ├── 42_NewSolutionExploer.png ├── 42_New_Solution_HelloWorld.png ├── 46_SetAsStartupProject.png ├── ConfigPlugIns_Conn.png ├── ConfigPlugin_CTPAcct.png ├── ConfigPlugins_Servers.png ├── HelloWorldOutput01.png ├── ImportInstruments.png ├── ScenarioCodeDemoBacktest.png ├── SolutionExplorer_Demo.png ├── StepbyStepGuide.png ├── StrategyRunControl.png ├── configuration_CTP.png ├── design_helloworld.png ├── gui_openquant_note.png ├── importHistoricalData.png ├── importInstrumentsGUI03.png ├── importInstumentsGUI02.png ├── menu_view.png ├── openquanthelloworldrunning.png ├── providers.png ├── providers_CTPon.png ├── smacrossovercodemap.png ├── smacrossoversolutionexplorer.png └── viewHistoricalData.png ├── build_empty_template.md ├── drive-mechanism-of-OpenQuant-running.md ├── flashorder_v1.md ├── icons ├── icon_book.png ├── icon_bookbig.png ├── icon_labtubeOrg.ico ├── icon_labtubeblue.ico ├── icon_paw.png └── icon_text.png ├── place-an-order ├── 7.1-jian-li-yi-ge-fa-chu-jiao-yi-zhi-ling-de-ce-lve-flashorder.md ├── 7.2-flashorder-de-ce-lve-luo-ji.md ├── 82-using-drawing-pad.md ├── README.md ├── buildemptytemplate.md ├── flashorderver_v1.md ├── flashorderver_v2.md └── log-order-information-using-mysql-db.md └── the-events-in-openquant.md /1_before-your-start/1.1-chose-a-stable-os.md: -------------------------------------------------------------------------------- 1 | # 1.1 操作系统的选择 2 | 3 | 目前的OpenQuant需要微软Windows运行环境,支持微软最新版本的OpenQuant支持Windows7,Windows8,Windows10及Windows Server 2008,Windows Server 2012等主流的Windows 64位操作系统。 4 | 5 | 安装OpenQuant软件时,OpenQuant安装程序会自动检测是否有合适的.NET Framework基础软件,如果需要安装程序会自动进行升级安装。 6 | 7 | ![](../.gitbook/assets/icon_paw.png) 建议采用Windows Server 2012以上的面向服务器的操作系统软件。 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /1_before-your-start/1.2-openquant-product-family.md: -------------------------------------------------------------------------------- 1 | # 1.2 OpenQuant商业版与国内天风版 2 | 3 | OpenQuant是由美国SmartQuant公司研发,面向金融机构的专业量化交易系统,OpenQuant产品服务众多金融机构及对冲基金客户,经历了10年以上的发展历程及全球金融市场的实际验证,具有可以承载工业强度的系统性能和系统稳定性。系统提供包括证券、期货、期权等各类金融资产交易,提供量化策略的研究,开发,调试,回测,仿真,优化和自动化运行等众多功能及优异特性。 4 | 5 | OpenQuant产品自推出以来,不断进行升级,产品功能一直在发展中,形成了完整的OpenQuant的产品家族: 6 | 7 | ![](/.gitbook/assets/openquantframework.jpg) 8 | 9 | 所有的产品都是基于底层的复杂事件处理系统,基于此框架各类复杂的任务可以在整体上进行无缝的集成。开发者可以利用丰富的程序接口编写各种策略,执行交易任务,数据管理及模型的优化。我们这里讨论的就是基于SmartQuant基础框架的主产品OpenQuant,在该产品中具备策略开发、模拟、优化、实盘交易全部功能,同时支持第三方库和插件。 10 | 11 | OpenQuant并不是开源软件,也不是免费软件, "Open"是指软件构架上的是开放自由。"Freedom is Not Free" 12 | 13 | * **商业版OpenQuant**---指SmartQuant公司推出的标准版商业软件,该软件资料及报价可以通过www.smartquant.com或者www.smartquant.cn中文网站获得详细资料。 14 | 15 | * **天风版OpenQuant**---是指天风证券、天风期货与SmartQuant合作推出的面向国内证券、期货交易,集成了证券、期货、期权交易及历史数据插件的增强版本,天风版保留所有商业版的功能,同时大大简化了交易通道插件安装、配置工作。后面我们主要以天风版OpenQuant来说明其各项功能,天风版OpenQuant的详细信息可以通过www.thanf.com获得资料与帮助。 16 | 17 | ![](/.gitbook/assets/icon_paw.png)我推荐您使用面向国内用户、容易安装、配置的OpenQuant天风版软件。 18 | 19 | -------------------------------------------------------------------------------- /1_before-your-start/1.3-download-and-install-openquant.md: -------------------------------------------------------------------------------- 1 | # 1.3 安装OpenQuant软件及插件 2 | 3 | ## 1.3.1 下载软件 4 | 5 | * **OpenQuant商业版下载地址:** 6 | 7 | [http://www.smartquant.com](http://www.smartquant.com) 英文官方网站 8 | 9 | [http://www.smartquant.cn](http://www.smartquant.cn) 中文服务网站 10 | 11 | * **OpenQuant国内市场插件下载地址:** 12 | 13 | [http://www.smartquant.cn](http://www.smartquant.cn) 14 | 15 | [http://www.quantbox.cn/download](http://www.quantbox.cn/download) 16 | 17 | * **OpenQuant天风版下载地址:** 18 | 19 | [http://www.thanf.com](http://www.thanf.com) 20 | 21 | ## 1.3.2 商业版OpenQuant软件及国内插件的安装步骤 22 | 23 | * **OpenQuant商业版软件安装** 24 | 25 | 运行OpenQuant安装程序,按照默认步骤进行安装即可轻松完成安装过程。OpenQuant 应用程序会被安装在标准的 Program Files \(x86\)\SmartQuant Ltd\OpenQuant 2014 目录中。 26 | 27 | * 系统的数据文件\(data.quant 和 instruments.quant\)在 AppData\Roaming SmartQuant Ltd\OpenQuant 2014\data 目录中 28 | * 系统的配置文件在 AppData\Roaming\SmartQuant Ltd\OpenQuant 2014 目录中。 29 | * 系统的示例策略项目在 Documents\OpenQuant 2014\Solutions 目录中。 30 | 31 | OpenQuant的安装过程详见[http://www.smartquant.cn/book/installing.html](http://www.smartquant.cn/book/installing.html) 32 | 33 | * **国内市场插件的下载及安装** 34 | 35 | 常用的插件包括国内期货CTP柜台的插件, 国内证券、期货市场历史数据的插件,国内股票行情插件等等,我们先从上述的网站分别下载这些插件的安装文件,启动安装程序后即可开始安装。 36 | 37 | * 安装QuantBox CTP插件:该插件可以连接CTP柜台,获取行情及交易报单 38 | * 安装天风历史数据插件:该插件可以从天风期货数据中心获取大量的证券/期货历史数据 39 | * 安装天风行情插件:该插件可以获得实时的证券行情数据 40 | 41 | 这些插件均按照默认步骤进行安装即可。 42 | 43 | ## 1.3.3 OpenQuant天风版软件及国内插件的安装步骤 {#openquant软件的卸载} 44 | 45 | * **OpenQuant天风版软件及插件的自动化安装** 46 | 47 | ![](/icons/icon_labtubeBlue.ico)下载天风版OpenQuant安装包,直接启动安装程序,按照默认的提示即可安装OpenQuant同时自动化安装各类国内市场插件,包括天风CTP插件,天风历史数据插件及天风的证券行情插件。 48 | 49 | ## 1.3.4 OpenQuant软件及插件的卸载 {#openquant软件的卸载} 50 | 51 | 卸载软件可以通过运行控制面板或软件自带的 Uninstall 工具即可卸载。 52 | 53 | ![](/.gitbook/assets/Uninstall.png) 54 | 55 | 如果希望彻底删除以往安装和使用OpenQuant的用户信息,除了运行Uninstall工具进行OpenQuant.exe程序卸载 以外,还需要手动删除系统盘 Users 目录下两个路径的文件夹: 56 | 57 | ...\AppData\Roaming\SmartQuant Ltd 数据和配置文件 58 | ...\Documents\OpenQuant 2014 策略的项目代码 59 | 60 | ![](/icons/icon_paw.png) 下载并安装OpenQuant完成,接下来我们开始进入到OpenQuant的配置工作中,如无特殊说明,文中所有程序界面都来自天风版OpenQuant软件。 61 | 62 | -------------------------------------------------------------------------------- /1_before-your-start/1.4-gui-of-openquant.md: -------------------------------------------------------------------------------- 1 | # 1.4 OpenQuant的界面说明 2 | 3 | 当我们安装完成OpenQuant后,启动软件进入主界面如下: 4 | 5 | ![](/assets/gui_openquant_note.png) 6 | 7 | 正如上图所示,openquant的界面通常是分为这样几类窗口: 8 | 9 | * 合约/交易通道/属性相关的管理窗口 10 | * 策略代码相关的工程文件浏览、代码编辑窗口 11 | * 行情图表、策略输出、定单管理的窗口 12 | 13 | 在菜单View中,我们可以找到并打开更多的窗口:图表 14 | 15 | OpenQuant的这些窗口可以让用户按照自己的习惯自己安排,我通常会在两个屏幕上设定这些窗口。 16 | 17 | ![](/assets/menu_view.png) 18 | 19 | 。 20 | 21 | -------------------------------------------------------------------------------- /1_before-your-start/1.5-config-plugins.md: -------------------------------------------------------------------------------- 1 | # 1.5 配置交易通道,让OpenQuant接通期货市场 2 | 3 | 安装好OpenQuant和国内市场插件后,在OpenQuant的Providers窗口,我们可以看到如下图一样的插件: 4 | 5 | ![](/assets/providers.png) 6 | 7 | ## 1.5.1 期货CTP的配置 8 | 9 | 以配置天风CTP的交易报单及行情通道为例。在“Providers”窗口中的“Excution”分组下,鼠标右键点击“天风CTP”,在弹出菜单中选择打开属性窗口(Properties), 在Properties的Configuration项目中,点击右侧“三个点”的按钮,打开详细配置界面: 10 | 11 | ![](/assets/configuration_CTP.png) 12 | 13 | 在这里可以配置CTP的账户、密码、CTP前置IP地址、端口及CTP客户端认证串,界面如下: 14 | 15 | * **Users:**这里保存用户密码的配置信息列表,可以配置很多个,例如,设置一个SimNow的模拟账户,一个实盘账户。信息包括:账户、密码和这个账号的标志,建议明确标记,以便分别交易通道中,用的是什么账户。 16 | 17 | ![](/assets/ConfigPlugin_CTPAcct.png) 18 | 19 | * **Servers: **这里配置CTP系统的前置IP地址与端口号, 天风版的OpenQuant中已经内置配置完成,其他CTP系统需要与开户公司联系获得相关的信息。随着中国证监会进一步要求各类交易客户端的信息报备,CTP系统需要外部连接客户端填写客户端认证码,在Servers的AuthCode中,可以配置OpenQuant的认证码,具体信息可以向期货公司的服务人员咨询。 20 | 21 | ![](/assets/ConfigPlugins_Servers.png) 22 | 23 | * **Conections: **这里配置CTP通道中使用哪个前置Server地址,并采用哪个用户账号, CTP的Connections要配置两个信息,一个行情连接,一个交易连接。图中的Connections窗口中,LogPrefix=M64,UseType=MarketData的记录为行情连接,而LogPrefix=T64;UseType=Trade,Instument的记录为交易报单连接。 24 | 25 | ![](/assets/ConfigPlugIns_Conn.png) 26 | 27 | #### ![](/icons/icon_labtubeBlue.ico)开启连接 28 | 29 | 在配置完成后,关闭CTP配置窗口,OpenQuant会自动保存信息。这时如果是在交易时段,CTP系统允许登录;我们用鼠标右键点击Providers窗口中的天风CTP,选择“Connet”进行连接,OpenQuant即刻发起CTP的连接,连接成功后,应该能看见小小的绿色通道灯亮起。 30 | 31 | ![](/assets/providers_CTPon.png) 32 | 33 | ![](../.gitbook/assets/icon_paw.png)现在,我们已经下载并安装了OpenQuant最新版本及国内市场插件,或者安装了集成各类插件的天风版OpenQuant。插件正确配置后可以正常连接至交易通道了。 34 | 35 | -------------------------------------------------------------------------------- /1_before-your-start/1.6-import-instruments.md: -------------------------------------------------------------------------------- 1 | # 1.6 导入合约信息 2 | 3 | 当我们已经可以配置账户信息接入CTP后,首先面临的工作是让OpenQuant导入国内市场当前的期货合约信息; 4 | 5 | ## 1.6.1 导入当前有效的合约信息 6 | 7 | 首先,我们可以在盘中时段,连接上CTP交易通道,在OpenQuant中的Providers窗口中,选择CTP交易通道并连接成功。 8 | 9 | 然后,我们在OpenQuant菜单中选择数据Data-引入Import-合约Instruments-选择通过CTP通道进行导入合约信息。 10 | 11 | ![](/.gitbook/assets/icon_labtubeblue.ico)菜单中依次选择 **Data**--**Import**--**Instruments**--**天风CTP** 12 | 13 | ![](/assets/ImportInstruments.png) 14 | 15 | 打开导入合约的界面如下: 16 | 17 | ![](/assets/importInstumentsGUI02.png) 18 | 19 | 点击“Request”按钮即可获取到当前的有效合约,选择需要导入的合约信息后,选择引入“Import”即可导入。例如我们导入当前的股指期货合约: 20 | 21 | ![](/assets/importInstrumentsGUI03.png)在按钮Import下面有个update选择,如果即将导入的合约,以前曾经导入过,选择这个选择后,可以更新已经存在的合约信息。 22 | 23 | ![](/.gitbook/assets/icon_labtubeorg.ico)导入并保存的合约信息可以从Instuments窗口中查看,Instuments窗口可以从菜单View--Instuments打开查看。 24 | 25 | ## 1.6.2 查看当前活跃合约的即时行情 26 | 27 | 导入期货合约代码后,在市场开盘时段,打开OpenQuant中的QuoteMonitor界面,从Instruments窗口拖拽当前合约到QuoteMonitor界面中,可以看到该合约的当前市场报价。如果你看到跳跃的行情即说明OpenQuant已经连入市场并获取了即时行情数据。 28 | 29 | ## 1.6.3 导入历史合约信息 30 | 31 | 为了进行历史市场研究和策略开发,我们也需要导入历史数据,包括已经退市的历史合约及历史行情数据。如果使用的是天风版OpenQuant,这里已经集成了专用的历史数据插件,可以十分方便地导入历史合约和历史数据。如果您使用的是商业版OpenQuant,您可以下载并天风数据插件,连接天风的数据中心,获取大量历史数据进行研究。 32 | 33 | 首先,我们可以在任何时段连接“天风数据”通道,在OpenQuant中的Providers窗口中,选择“天风数据”通道并连接成功。 34 | 35 | 然后,我们在OpenQuant菜单中选择数据,引入,合约,天风数据 36 | 37 | ![](/.gitbook/assets/icon_labtubeblue.ico)菜单中依次选择 **Data**--**Import**--**Instruments**--**天风数据** 38 | 39 | 这时,可以打开导入合约的界面,导入历史合约方法和导入活跃合约信息一样操作即可。 40 | 41 | -------------------------------------------------------------------------------- /1_before-your-start/1.7-import-historical.md: -------------------------------------------------------------------------------- 1 | # 1.7 导入历史数据 2 | 3 | 导入了合约的信息(Instruments)后,OpenQuant可以从天风数据中心导入这些合约的历史行情数据。首先,我们可以在任何时段连接“天风数据”通道,在OpenQuant中的Providers窗口中,选择“天风数据”通道并连接成功。然后,我们在OpenQuant菜单中选择数据,引入,历史数据,天风数据,打开导入历史数据的界面。 4 | 5 | ![](/icons/icon_labtubeBlue.ico)菜单中依次选择 **Data**--**Import**--**Historical**--**天风数据** 6 | 7 | 从Instruments窗口中拖拽某个合约进入到导入历史数据的窗口,选择导入的数据类型,起始时间,结束时间,如果是导入Bar数据(即K线数据),需要选择BarSize(K线的时间周期,比如60,这里的单位是秒,即1分钟周期的K线),然后按开始导入的三角按钮,即可开始导入。导入成功后, 界面上显示导入数据的数量Count。 8 | 9 | ![](/assets/importHistoricalData.png) 10 | 11 | ![](/.gitbook/assets/icon_labtubeorg.ico)数据导入后,可以在Instruments窗口中,鼠标双击合约名字,即可查看到在OpenQuant中已经获取的合约历史数据 12 | 13 | ![](/assets/viewHistoricalData.png) 14 | 15 | -------------------------------------------------------------------------------- /1_before-your-start/1.8-run-a-demo-strategy.md: -------------------------------------------------------------------------------- 1 | # 1.8 运行一个OpenQuant的示例策略 2 | 3 | 现在我们来从OpenQuant自带的策略库中,运行一个示例的策略,来熟悉一下OpenQuant运行策略的过程。 4 | 5 | ## 1.8.1 打开策略工程 6 | 7 | OpenQuant启动后,在主窗口中显示的Start Page页面中显示最近打开的策略列表,我们选择SMACrossover这个策略,用鼠标点击即可打开。或者通过**File**菜单中的**Open--Solution... **菜单打开存在硬盘相应SMACrossover路径下的**SMACrossover.sln**文件,以打开这个工程。对于C\#程序员来说,这一切都是那么的熟悉,因为一个OpenQuant的策略就是一个标准的C\#程序。 8 | 9 | 打开工程后,可以在Solution Explorer窗口中看到这个策略工程的代码如下图所示: 10 | 11 | ![](/assets/SolutionExplorer_Demo.png) 12 | 13 | 这个策略程序(Solution)由4个工程(Project)组成: 14 | 15 | Backtest---回测场景工程,定义了回测的合约,行情类别,周期等细节 16 | 17 | MyStrategy---我的策略,就是我们的策略核心逻辑代码,如何处理行情,什么情况下报单,成交了如何处理,如何止盈止损等等情况 18 | 19 | Optimiztion---优化场景工程,定义优化参数的优化范围和参数步长等内容 20 | 21 | Realtime---实盘场景工程,定义了实盘交易通道,行情源,交易的合约,行情类别,周期,类似回测的场景。 22 | 23 | 有经验的C\#程序员知道一个Solution工程中,其中必须有一个工程作为整个程序的启动入口,在OpenQuant中,通常是场景定义工程作为启动入口,如果进行回测运行,Backtest就应该被定义为启动项。如果是实盘交易,Realtime就应该被定义为启动项目。如果对上述这些不了解,请查阅相关C\#编程的手册。现在我们在解决方案目录树中的Backtest工程名字上右键点击鼠标,定义这个工程为启动项目(Set as Startup Project),被定义为启动入口的项目名字已粗体黑字以和其他工程名字区分。 24 | 25 | ## 1.8.2 查看回测场景的定义 26 | 27 | 在工程目录树的窗口(Solution Explorer)中,双击Backtest目录下的Scenario.cs文件,我们打开回测场景定义文件, 我们可以看到回测场景的代码如下: 28 | 29 | ![](/assets/ScenarioCodeDemoBacktest.png)我们可以看到这个场景中定义的合约和测试起始和结束时间,请确保你的OpenQuant环境中已经引入了这些合约代码,并且导入了相关时间段的数据。默认安装的OpenQuant天风版软件已经配置好了这些合约和数据,当然,您也可以换一些新的合约和测试时间段不同的数据,方法就是前面介绍的导入合约信息和导入历史数据。这样就可以开始运行这个策略了。 30 | 31 | ## 1.8.3 用“回测”模式运行策略并查看结果 32 | 33 | 在OpenQuant主窗口的上部,有策略运行状态选择和运行控制按钮: 34 | 35 | ![](/assets/StrategyRunControl.png) 36 | 37 | ![](/icons/icon_labtubeBlue.ico)我们选择Backtest回测模式,同时启动策略的运行。点击运行按钮后,策略开始运行。 38 | 39 | 40 | 41 | ![](/icons/icon_labtubeOrg.ico)在OpenQuant的主窗口下方,我们可以看到策略运行的进度条。在运行完成后,我们在output窗口中,可以看到OpenQuant策略运行了处理了多少个数据,每秒处理了多少个事件的统计。 42 | 43 | 在View菜单中打开Chart图形窗口,这里会显示策略运行中定义或者绘制的图表,主要是行情图表。Chart和Chart(Gapless)的区别是Chart会以图表的横轴严格表达时间,而Gapless图表就是省略没有数据的时间段,例如,盘中休息,隔夜停盘等情况,这样画出的图形使得数据看起来更紧凑。 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /1_before-your-start/README.md: -------------------------------------------------------------------------------- 1 | # 1. 在开始之前的准备 2 | 3 | 我们在开始工作之前,首先要为长期稳定运行OpenQuant准备一个专用环境,下载并安装好OpenQuant软件,配置好相应的交易通道连接参数,让OpenQuant可以接通中国市场。获得市场合约及历史数据,测试运行一个示例策略。 4 | 5 | ### **使用OpenQuant进行量化交易之前的准备工作:** 6 | 7 | * 选择、安装一个稳定的Windows环境 8 | 9 | * 了解OpenQuant软件产品家族并选择正确的版本 10 | 11 | * 下载OpenQuant及相关插件并安装 12 | 13 | * 配置账户参数接入市场 14 | 15 | * 导入合约及历史数据 16 | 17 | * 测试一个示例策略 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /2_manage_your_work/README.md: -------------------------------------------------------------------------------- 1 | # 2. 需要涉及的工作 2 | 3 | ## 2.1 管理未来所有的代码... 4 | 5 | 在正式进行量化交易工作前,应该先着手规划如何管理你未来所有的策略代码。构建起一个明确的工作流程及管理体系,能让你的策略设计文档、策略程序代码及配置信息等诸多文件井井有条,这将极大的帮助你形成轻松高效并且稳定的开发管理体系。毕竟,稳定的过程导致稳定的质量。 6 | 7 | ![](/.gitbook/assets/icon_paw.png)建立程序化交易开发管理体系,用SVN或者Git这样的版本控制系统管理你所有的代码及文档。相关内容请参考相关资料。 8 | 9 | ## 2.2 建立一个适用的IT构架 10 | 11 | 量化交易需要一个即稳固又便于扩展的IT构建,因为很多量化交易所需要的功能模块、数据来源、处理方式、运算能力及未来的机器学习和人工智能,这些都不是一个产品能够全部完成的,就量化交易中的数据源一项就有可能涉及Wind,Bloomberg数据终端,也有可能涉及各种各样的商业数据库。而模型建立很多交易员和研究员又有着不同的工具使用偏好,比如Matlab 或者Python。这就需要通过IT构架从全局的高度来进行设计,采用分层、模块化的构架来解决我们面临的复杂问题,而OpenQuant可以很好地在嵌入各种IT构架中。这也是专业金融交易机构的解决方案。为此,我们未来的量化交易构架未来很有可能会涉及多台服务器及较为复杂的运维工作。 12 | 13 | 14 | 15 | 我们这里给出一个能担负数据管理、策略研发、策略回测及优化及策略执行的IT构架示例,总体结构如下图所示: 16 | 17 | -------------------------------------------------------------------------------- /2_manage_your_work/manage-your-coding-by-svn.md: -------------------------------------------------------------------------------- 1 | # 2. 需要涉及的工作 2 | 3 | ## 2.1 管理未来所有的代码... 4 | 5 | 在正式进行量化交易工作前,应该先着手规划如何管理你未来所有的策略代码。构建起一个明确的工作流程及管理体系,能让你的策略设计文档、策略程序代码及配置信息等诸多文件井井有条,这将极大的帮助你形成轻松高效并且稳定的开发管理体系。毕竟,稳定的过程导致稳定的质量。 6 | 7 | ![](/.gitbook/assets/icon_paw.png)建立程序化交易开发管理体系,用SVN或者Git这样的版本控制系统管理你所有的代码及文档。相关内容请参考相关资料。 8 | 9 | ## 2.2 建立一个适用的IT构架 10 | 11 | 量化交易需要一个即稳固又便于扩展的IT构建,因为很多量化交易所需要的功能模块、数据来源、处理方式、运算能力及未来的机器学习和人工智能,这些都不是一个产品能够全部完成的,就量化交易中的数据源一项就有可能涉及Wind,Bloomberg数据终端,也有可能涉及各种各样的商业数据库。而模型建立很多交易员和研究员又有着不同的工具使用偏好,比如Matlab 或者Python。这就需要通过IT构架从全局的高度来进行设计,采用分层、模块化的构架来解决我们面临的复杂问题,而OpenQuant可以很好地在嵌入各种IT构架中。这也是专业金融交易机构的解决方案。为此,我们未来的量化交易构架未来很有可能会涉及多台服务器及较为复杂的运维工作。 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /3_structure_of_openquant_solution/README.md: -------------------------------------------------------------------------------- 1 | # 3. 了解OpenQuant策略代码的结构 2 | 3 | OpenQuant软件附带策略示例,这为我们展示了典型的策略代码,我们可以通过这些示例了解OpenQuant策略编程中代码应该具备的基础结构。 4 | 5 | ![](/icons/icon_labtubeBlue.ico)打开OpenQuant中的SMACrossover示例策略,这是一个经典的SMA交叉策略,打开后可以直接运行看到回测结果。这里我们着重看一下这个例子的代码结构和调用关系。 6 | 7 | ![](/assets/smacrossoversolutionexplorer.png) 8 | 9 | 在这个解决方案(Solution)中,包含如下四个工程: 10 | 11 | **Backtest** :回测,定义回测时的场景,引入的数据,回测的起始及结束日期,构造K线生成要素 12 | **MyStrategy** :策略逻辑主体,定义均线,绘制K线及均线的主要图表,处理交易逻辑,处理成交事件,处理持仓等等 13 | **Optimization** :策略优化参数定义,及策略优化的起始及结束日期 14 | **Realtime** :实盘交易的场景,引入的合约,行情源及交易通道定义 15 | 16 | 如果您熟悉C\#语言开发,很快就可以发现OpenQuant的策略代码就是一个完全标准的C\#语言的解决方案。我们稍后章节会描述用微软的VisualStudio开发环境加载这些OpenQuant策略、开发、编译并调试。这个特性为我们的工作提供了极大的方便。 17 | 18 | 策略代码的结构如图所示: 19 | 20 | ![](/assets/smacrossovercodemap.png) 21 | 22 | 图:OpenQuant策略示例SMACrossover的代码结构。 23 | 24 | -------------------------------------------------------------------------------- /3_structure_of_openquant_solution/structure-of-openquant-solution.md: -------------------------------------------------------------------------------- 1 | # 3. 了解OpenQuant策略代码的结构 2 | 3 | OpenQuant软件附带的策略示例为我们展示了典型的策略代码,我们可以通过这些示例了解OpenQuant策略编程中代码应该具备的基础结构。 4 | 5 | ![](/icons/icon_labtubeBlue.ico)打开OpenQuant中的SMACrossover示例策略,这是一个经典的SMA交叉策略,打开后可以直接运行看到回测结果。这里我们着重看一下这个例子的代码结构和调用关系。 6 | 7 | ![](/assets/smacrossoversolutionexplorer.png) 8 | 9 | 在这个解决方案(Solution)中,包含如下四个工程: 10 | 11 | **Backtest** :回测,定义回测时的场景,引入的数据,回测的起始及结束日期,构造K线生成要素 12 | **MyStrategy** :策略逻辑主体,定义均线,绘制K线及均线的主要图表,处理交易逻辑,处理成交事件,处理持仓等等 13 | **Optimization** :策略优化参数定义,及策略优化的起始及结束日期 14 | **Realtime** :实盘交易的场景,引入的合约,行情源及交易通道定义 15 | 16 | 如果您熟悉C\#语言开发,很快就可以发现OpenQuant的策略代码就是一个完全标准的C\#语言的解决方案。我们稍后章节会描述用微软的VisualStudio开发环境加载这些OpenQuant策略、开发、编译并调试。这个特性为我们的工作提供了极大的方便。 17 | 18 | 策略代码的结构如图所示: 19 | 20 | ![](/assets/smacrossovercodemap.png) 21 | 22 | 图:OpenQuant策略示例SMACrossover的代码结构。 23 | 24 | -------------------------------------------------------------------------------- /4_hello_world/41-design-an-openquant-helloworld.md: -------------------------------------------------------------------------------- 1 | # 4.1 设计OpenQuant的HelloWorld 2 | 3 | 在开始编码工作前,都应该先设计一下软件的构架,即便是一个简单的功能。HelloWorld 也需要设计一下,这个HelloWorld程序就是最基础的OpenQuant策略代码。虽然简单,但具备最核心的结构,未来可以扩展出我们需要的更多的解决方案。 4 | 5 | 策略的总体结构应该是这样: 6 | 7 | ![](/assets/design_helloworld.png) 8 | 9 | 整个解决方案由三个工程组成: 10 | 11 | 1. 回测场景定义的**Backtest**:主要定义用于回测的合约,及其历史数据的回测时间段; 12 | 2. 实盘场景定义的**Realtime**:主要定义交易通道,实盘交易的合约。 13 | 3. 策略主体的**MyStrategy**:主要编写策略逻辑,我们的Hellow World代码就会出现在这里。 14 | 15 | 而优化(Optimization)的部分,目前先忽略。现在就来创建这个HelloWorld吧! 16 | 17 | -------------------------------------------------------------------------------- /4_hello_world/42-new-a-solution.md: -------------------------------------------------------------------------------- 1 | ## 4.2创建一个新的解决方案 2 | 3 | 首先,我们用OpenQuant创建一个新的解决方案。 4 | 5 | ![](/icons/icon_labtubeBlue.ico)打开OpenQuant中的**File**菜单,**New**一个新的**solution**, 这里有一些解决方案类别选项,这个例子中,我们选择第一种“SmartQuant Instrument Strategy Solution”, 命名为_HelloWorld,_ 6 | 7 | ### 新建Solution,对类型的选择: 8 | 9 | ![](/assets/42_New_Solution_HelloWorld.png) 10 | 11 | 这里我们选择第一种“SmartQuant Instrument Strategy Solution”, 12 | 13 | > OpenQuant Solution的类别: 14 | > 15 | > SmartQuant Instrument Strategy Solution: 16 | > 17 | > SmartQuant Strategy Solution: 18 | > 19 | > SmartQuant Sell Side Strategy Solution: 20 | 21 | 22 | 23 | 在OpenQuant的Solution Explorer窗口中,我们可以发现当前有两个工程,**Backtest**和**MyStratey**.这就是最基础的代码框架了,一个回测场景定义工程(Backtest),一个策略主体工程(MyStrategy)。 24 | 25 | ### 新建的Solution结构如下: 26 | 27 | ![](/assets/42_NewSolutionExploer.png) 28 | 29 | 接下来,让我们先来编写Backtest场景模块。 30 | 31 | -------------------------------------------------------------------------------- /4_hello_world/43-code-the-baketest-scenario.md: -------------------------------------------------------------------------------- 1 | ## 4.3 编写回测场景Backtest 2 | 3 | ![](/icons/icon_labtubeBlue.ico) 4 | 5 | 在这个场景模块中,我们增加回测场景的定义,包括测试的合约,我们引入螺纹钢期货rb1709合约,我们假设你已经在OpenQuant中引入了rb1709合约,同时使用历史数据插件导入了2017年1月1日至2017年3月1日的Tick级别的历史数据。 6 | 7 | 在**Backtest**工程的**MyScenario.cs**文件中,编写的代码如下, 8 | 9 | ```text 10 | using System; 11 | 12 | using SmartQuant; 13 | 14 | namespace OpenQuant 15 | { 16 | public partial class Backtest : Scenario 17 | { 18 | //定义K线时间周期为barSize秒 19 | private long barSize = 60; 20 | 21 | public Backtest(Framework framework) 22 | : base(framework) 23 | { 24 | } 25 | 26 | public override void Run() 27 | { 28 | //定义要引入的合约名字 29 | Instrument instrument1 = InstrumentManager.Instruments["rb1709"]; 30 | 31 | 32 | strategy = new MyStrategy(framework, "HelloWorld"); 33 | 34 | //引入合约 35 | strategy.AddInstrument(instrument1); 36 | 37 | //定义数据回测的起止日期 38 | DataSimulator.SubscribeBar = false; 39 | DataSimulator.DateTime1 = new DateTime(2017, 01, 01); 40 | DataSimulator.DateTime2 = new DateTime(2017, 03, 01); 41 | 42 | //定义一个时间类型的K线 43 | BarFactory.Clear(); 44 | BarFactory.Add(instrument1, BarType.Time, barSize); 45 | 46 | 47 | Initialize(); 48 | 49 | StartStrategy(); 50 | } 51 | } 52 | } 53 | ``` 54 | 55 | 在回测场景工程(Backtest)中,我们将场景类的名字从MyScenario改为Backtest,以便能和即将增加的Realtime场景类更为明确地加以区别。修改这个类名会涉及MyScenarios.cs,MySenario.Designer.cs,Program.cs 这3个文件中所有该类定义及调用的代码。如果用微软的Visual Studio工具将非常的自动化完成这类代码编写工作。 56 | 57 | 上面的代码public partial class **Backtest**:Scenario 修改了原来OpenQuant自动生成的public partial class **MyScenario**:Scenario 。 58 | 59 | 为此我们也要修改这个工程的MyScenario.Designer.cs文件中这个“类”的名字, 把public partial class MyScenario改为public partial class Backtest,在Backtest工程中的**MyScenario.Designer.cs**文件中,编写代码如下 60 | 61 | ```text 62 | using System; 63 | 64 | using SmartQuant; 65 | 66 | namespace OpenQuant 67 | { 68 | public partial class Backtest 69 | { 70 | public void Initialize() 71 | { 72 | } 73 | } 74 | } 75 | ``` 76 | 77 | 在Backtest工程中的**Program.cs**文件中,编写代码如下,同样将原有的MyScenario改为Backtest 78 | 79 | ```text 80 | using System; 81 | 82 | using SmartQuant; 83 | 84 | namespace OpenQuant 85 | { 86 | class Program 87 | { 88 | static void Main(string[] args) 89 | { 90 | Scenario scenario = new Backtest(Framework.Current); 91 | 92 | scenario.Run(); 93 | } 94 | } 95 | } 96 | ``` 97 | 98 | 我们从这个工程的入口程序中,我们可以看到,程序开始运行后,就从一个叫做Backtest的场景类初始化,并开始让场景运行。 99 | 100 | -------------------------------------------------------------------------------- /4_hello_world/44-code-mystrategy-for-helloworld.md: -------------------------------------------------------------------------------- 1 | **开始编写核心策略逻辑MyStrategy** 2 | 3 | 我们在这个核心逻辑中,当行情数据产生了K线中新的Bar时,我们在信息输出窗口中向外输出期待已久的HelloWorld,同时显示合约名字和当前行情形成K的Bar的平均价格。 4 | 5 | ![](/icons/icon_labtubeBlue.ico)在**MyStrategy**工程中的**MyStrategy.cs**文件中,编写代码如下 6 | 7 | ```text 8 | using System; 9 | 10 | using SmartQuant; 11 | 12 | namespace OpenQuant 13 | { 14 | public class MyStrategy : InstrumentStrategy 15 | { 16 | public MyStrategy(Framework framework, string name) 17 | : base(framework, name) 18 | { 19 | } 20 | 21 | protected override void OnStrategyStart() 22 | { 23 | //定义K线的画布,编码0号 24 | Group("myK-Chart", "Pad", 1); 25 | } 26 | 27 | protected override void OnBar(Instrument instrument, Bar bar) 28 | { 29 | //当Bar形成时,增加bar数据到K线序列 30 | Bars.Add(bar); 31 | 32 | //在Bars画布上画出K线 33 | Log(bar, "myK-Chart"); 34 | 35 | //就是这句期待已久的HelloWorld!同时显示bar时间,合约代码,bar中的均价 36 | Console.WriteLine("HelloWorld! "+bar.DateTime.ToString()+ " "+instrument.Symbol + " ="+bar.Average.ToString()); 37 | } 38 | } 39 | } 40 | ``` 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /4_hello_world/45-code-the-realtime-scenario.md: -------------------------------------------------------------------------------- 1 | ## 编写实盘场景模块-Realtime 2 | 3 | ## 增加一个场景工程-Realtime 4 | 5 | ![](/icons/icon_labtubeBlue.ico)现在,我们按照设计,再增加一个实盘交易场景工程Realtime。在OpenQuant的Solution Explorer中找到刚刚建立的解决方案HelloWorld,在HelloWorld上鼠标右键,**Add**一个**New Project...** 我们增加一个场景工程, 选择SmartQuant Scenario Project, 命名为 _**Realtime**_ 6 | 7 | ![](/icons/icon_labtubeOrg.ico)现在我们按照设计,这个解决方案(Solution)中已经有了三个工程:一个回测场景,一个实盘场景,一个策略主体; 让我们来在这三个工程中加入代码。 8 | 9 | ## **引入MyStrategy工程类** 10 | 11 | 在接入实盘收行情时,我们会将解决方案中的Realtime作为启动工程,在这个工程中将实例化一个主逻辑MyStrategy类,**为此,我们先要在Realtime工程中,引入MyStrategy工程类。**正如OpenQuant生成的Backtest中已经引入了Mystrategy工程类一样。 12 | 13 | ![](/icons/icon_labtubeBlue.ico)在OpenQuant的Solution Explorer中的Realtime工程的References中,鼠标右键Add,选择Solution后,选择添加MyStrategy工程。 14 | 15 | ## **编写实盘场景Realtime的代码** 16 | 17 | 接入实时到动态行情数据,我们要定义实盘接入场景,在Realtime工程中的**Scenario.cs**文件中,编写代码如下: 18 | 19 | ```c\# 20 | using System; 21 | using System.Collections.Generic; 22 | using System.Linq; 23 | using System.Text; 24 | using System.Threading.Tasks; 25 | 26 | using SmartQuant; 27 | 28 | namespace OpenQuant 29 | { 30 | public partial class Realtime : Scenario 31 | { 32 | //定义K线时间周期为barSize秒 33 | private long barSize = 3; 34 | 35 | public Realtime(Framework framework) 36 | : base(framework) 37 | { 38 | } 39 | 40 | public override void Run() 41 | { 42 | //定义合约 43 | Instrument instrument1 = InstrumentManager.Instruments["ag1712"]; 44 | 45 | strategy = new MyStrategy(framework, "HelloWorld"); 46 | 47 | //引入合约到主策略工程 48 | strategy.AddInstrument(instrument1); 49 | 50 | //定义主策略中使用的合约的数据源和交易通道 51 | strategy.DataProvider = ProviderManager.GetDataProvider("QuantBoxCTP"); 52 | strategy.ExecutionProvider = ProviderManager.GetExecutionProvider("QuantBoxCTP"); 53 | 54 | //定义K线类型:时间型K线,barSize秒生成一个Bar 55 | BarFactory.Clear(); 56 | BarFactory.Add(instrument1, BarType.Time, barSize); 57 | 58 | Initialize(); 59 | 60 | //Run the strategy 61 | StartStrategy(); 62 | 63 | } 64 | } 65 | } 66 | ``` 67 | 68 | 上面代码中,对交易通道的定义,需要注意交易通道名字需要和安装的通道插件名字一致。 69 | 70 | HelloWolrd解决方案的Realtime工程中的Scenario.Designer.cs及Program.cs均不需要改动代码。这样就完成了Realtime工程代码的编写。 71 | 72 | -------------------------------------------------------------------------------- /4_hello_world/46-let-us-run-helloworld.md: -------------------------------------------------------------------------------- 1 | # 4.6 运行Hello World 2 | 3 | HelloWorld编写完成,我们有了一个OpenQuant策略代码的基础框架,现在我们可以基于历史数据的回测模式(Backtest)下运行,也可以接入实盘交易通道,用Live模式运行。 4 | 5 | ## 4.6.1以回测模式(Backtest)运行HelloWorld 6 | 7 | 在Solution Exploer窗口中,我们确认Backtest作为程序的启动工程,这是Backtest是加粗的字体显示。如果不是这样,我们鼠标右击Backtest工程,在菜单中选择Set as StartUp Project,然后我们以Backtest模式运行 8 | 9 | ![](/assets/46_SetAsStartupProject.png) 10 | 11 | 我们直接以运行结果如下: 12 | 13 | ![](/assets/openquanthelloworldrunning.png) 14 | 15 | ## 4.6.2以实盘模式(Live)运行HelloWorld 16 | 17 | 同样,我们在Solution Exploer窗口中,我们确认Realtime作为程序的启动工程,这时Realtime是加粗的字体显示。如果不是这样,我们鼠标右击Realtime工程,在菜单中选择Set as StartUp Project,然后我们以Live模式运行。 18 | 19 | 在实盘运行时,随着行情数据的到来,我们可以看见output窗口中HelloWorld的逐行信息输出和Chart窗口中动态的K线显示。 20 | 21 | 22 | 23 | 24 | 25 | ![](/icons/icon_paw.png)现在我们已经有了一个HelloWorld解决方案,该方案已经让我们完成一个主体逻辑后,可以进行回测状态和实盘状态的定义和切换。如果需要回测,我们就将Backtest工程设置为启动项,如果进行实盘接入,我们就将Realtime工程设置为启动项。 26 | 27 | 完整的代码应该存在版本控制系统中进行管理。上述完整HelloWorld代码可以从如下地址获得: 28 | 29 | ![](/icons/icon_bookbig.png) [https://github.com/omnistep/OpenQuantHelloWorld](https://github.com/omnistep/OpenQuantHelloWorld) 获得。 30 | 31 | -------------------------------------------------------------------------------- /4_hello_world/README.md: -------------------------------------------------------------------------------- 1 | # 4.构建一个OpenQuant的HelloWorld策略 2 | 3 | 在对OpenQuant的代码结构有了大致的了解后,让我们来开始构建一个OpenQuant的HelloWorld系统吧... 4 | 5 | ## Hello World的需求描述 6 | 7 | 我们需要建立一个OpenQuant的代码基础构架——**HelloWorld策略**,该策略要提供历史数据回测结构,也要可以实盘连接到CTP交易柜台,还可以订阅一个全市场最热的合约,当收到每一笔Tick行情时,在输出窗口写一句HelloWorld及所订阅合约的当前报价! 8 | 9 | ## Hello World策略的构建过程 10 | 11 | * 设计总体构架 12 | * 新建解决方案 13 | * 编写回测场景模块 14 | * 编写核心策略模块 15 | * 编写实盘场景模块 16 | * 运行HelloWorld 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /4_hello_world/code-an-openquant-helloworld.md: -------------------------------------------------------------------------------- 1 | # 6. 开始编写OpenQuant的HelloWorld! 2 | 3 | ## 用OpenQuant创建一个基础代码框架 4 | 5 | ![](.gitbook/assets/icon_labtubeblue%20%285%29.ico)打开OpenQuant中的**File**菜单,**New**一个新的**solution**, 这里有一些解决方案类别选项,这个例子中,我们选择第一种“SmartQuant Instrument Strategy Solution”, 命名为_HelloWorld,_在OpenQuant的Solution Explorer窗口中,我们可以发现当前有两个工程,**Backtest**和**MyStratey**.这就是最基础的代码框架了,一个回测场景定义工程,一个策略主体工程。 6 | 7 | ## 增加一个场景工程-Realtime 8 | 9 | ![](.gitbook/assets/icon_labtubeblue.ico)现在,我们按照设计,再增加一个实盘交易场景工程Realtime。在OpenQuant的Solution Explorer中找到刚刚建立的解决方案HelloWorld,在HelloWorld上鼠标右键,**Add**一个**New Project...** 我们增加一个场景工程, 选择SmartQuant Scenario Project, 命名为 _**Realtime**_ 10 | 11 | 现在我们按照设计,这个解决方案(Solution)中已经有了三个工程:一个回测场景,一个实盘场景,一个策略主体; 让我们来在这三个工程中加入代码。 12 | 13 | ## 开始编写回测场景Backtest 14 | 15 | ![](.gitbook/assets/icon_labtubeblue%20%284%29.ico)在回测场景工程(Backtest)中,将场景类的名字从MyScenario改为Backtest,以便能和Realtime场景类更为明确地加以区别。修改这个类名会涉及MyScenarios.cs,MySenario.Designer.cs,Program.cs 文件中所有该类定义及调用的代码。如果用微软的Vistual Studio工具将非常的自动化完成这类代码编写工作。 16 | 17 | 然后,我们增加回测场景的定义,包括测试的合约,我们引入螺纹钢期货rb1709合约,我们假设你已经在OpenQuant中引入了rb1709合约,同时使用历史数据插件导入了2017年1月1日至2017年3月1日的Tick级别的历史数据。 18 | 19 | ![](.gitbook/assets/icon_bookbig%20%281%29.png)OpenQuant引入合约代码及导入历史数据,请参考如下资料: 20 | 21 | [http://www.smartquant.cn/book/domestic\_market\_data.html](http://www.smartquant.cn/book/domestic_market_data.html) 22 | 23 | 1. 在**Backtest**工程的**MyScenario.cs**文件中,编写代码如下 24 | 25 | ```text 26 | using System; 27 | 28 | using SmartQuant; 29 | 30 | namespace OpenQuant 31 | { 32 | public partial class Backtest : Scenario 33 | { 34 | //定义K线时间周期为barSize秒 35 | private long barSize = 60; 36 | 37 | public Backtest(Framework framework) 38 | : base(framework) 39 | { 40 | } 41 | 42 | public override void Run() 43 | { 44 | //定义要引入的合约名字 45 | Instrument instrument1 = InstrumentManager.Instruments["rb1709"]; 46 | 47 | 48 | strategy = new MyStrategy(framework, "HelloWorld"); 49 | 50 | //引入合约 51 | strategy.AddInstrument(instrument1); 52 | 53 | //定义数据回测的起止日期 54 | DataSimulator.SubscribeBar = false; 55 | DataSimulator.DateTime1 = new DateTime(2017, 01, 01); 56 | DataSimulator.DateTime2 = new DateTime(2017, 03, 01); 57 | 58 | //定义一个时间类型的K线 59 | BarFactory.Clear(); 60 | BarFactory.Add(instrument1, BarType.Time, barSize); 61 | 62 | 63 | Initialize(); 64 | 65 | StartStrategy(); 66 | } 67 | } 68 | } 69 | ``` 70 | 71 | 上面的代码public partial class **Backtest**:Scenario 修改了原来OpenQuant自动生成的public partial class **MyScenario**:Scenario , 为此我们也要修改这个工程中的MyScenario.Designer.cs中这个“类”的名字, 把自动生成的public partial class MyScenario改为public partial class Backtest 72 | 73 | 在Backtest工程中的**MyScenario.Designer.cs**文件中,编写代码如下 74 | 75 | ```text 76 | using System; 77 | 78 | using SmartQuant; 79 | 80 | namespace OpenQuant 81 | { 82 | public partial class Backtest 83 | { 84 | public void Initialize() 85 | { 86 | } 87 | } 88 | } 89 | ``` 90 | 91 | 在Backtest工程中的**Program.cs**文件中,编写代码如下,同样将原有的MyScenario改为Backtest 92 | 93 | ```text 94 | using System; 95 | 96 | using SmartQuant; 97 | 98 | namespace OpenQuant 99 | { 100 | class Program 101 | { 102 | static void Main(string[] args) 103 | { 104 | Scenario scenario = new Backtest(Framework.Current); 105 | 106 | scenario.Run(); 107 | } 108 | } 109 | } 110 | ``` 111 | 112 | 我们从这个工程的入口程序中,我们可以看到,程序开始运行后,就从一个叫做Backtest的场景类初始化,并开始让场景运行。 113 | 114 | 1. **开始编写核心策略逻辑MyStrategy** 115 | 116 | 我们在这个核心逻辑中,当行情数据产生了K线中新的Bar时,我们在信息输出窗口中向外输出期待已久的HelloWorld,同时显示合约名字和当前行情形成K的Bar的平均价格。 117 | 118 | ![](.gitbook/assets/icon_labtubeblue%20%288%29.ico)在**MyStrategy**工程中的**MyStrategy.cs**文件中,编写代码如下 119 | 120 | ```text 121 | using System; 122 | 123 | using SmartQuant; 124 | 125 | namespace OpenQuant 126 | { 127 | public class MyStrategy : InstrumentStrategy 128 | { 129 | public MyStrategy(Framework framework, string name) 130 | : base(framework, name) 131 | { 132 | } 133 | 134 | protected override void OnStrategyStart() 135 | { 136 | //定义K线的画布,编码0号 137 | Group("myK-Chart", "Pad", 1); 138 | } 139 | 140 | protected override void OnBar(Instrument instrument, Bar bar) 141 | { 142 | //当Bar形成时,增加bar数据到K线序列 143 | Bars.Add(bar); 144 | 145 | //在Bars画布上画出K线 146 | Log(bar, "myK-Chart"); 147 | 148 | //就是这句期待已久的HelloWorld!同时显示bar时间,合约代码,bar中的均价 149 | Console.WriteLine("HelloWorld! "+bar.DateTime.ToString()+ " "+instrument.Symbol + " ="+bar.Average.ToString()); 150 | } 151 | } 152 | } 153 | ``` 154 | 155 | ![](.gitbook/assets/icon_paw%20%281%29.png)这时你有了一个可以回测合约的历史数据,基础框架,运行结果如下: 156 | 157 | ![](.gitbook/assets/openquanthelloworldrunning.png) 158 | 159 | ## 开始编写实盘接入场景Realtime 160 | 161 | 1. **引入MyStrategy工程类** 162 | 163 | 在接入实盘收行情时,我们会将解决方案中的Realtime作为启动工程,在这个工程中将实例化一个主逻辑MyStrategy类,**为此,我们先要在Realtime工程中,引入MyStrategy工程类。**正如OpenQuant生成的Backtest中已经引入了Mystrategy工程类一样。 164 | 165 | ![](.gitbook/assets/icon_labtubeblue%20%287%29.ico)在OpenQuant的Solution Explorer中的Realtime工程的References中,鼠标右键Add,选择Solution后,选择添加MyStrategy工程。 166 | 167 | 1. **编写实盘场景Realtime的代码** 168 | 169 | 接入实时到动态行情数据,我们要定义实盘接入场景,在Realtime工程中的**Scenario.cs**文件中,编写代码如下: 170 | 171 | ```text 172 | using System; 173 | using System.Collections.Generic; 174 | using System.Linq; 175 | using System.Text; 176 | using System.Threading.Tasks; 177 | 178 | using SmartQuant; 179 | 180 | namespace OpenQuant 181 | { 182 | public partial class Realtime : Scenario 183 | { 184 | //定义K线时间周期为barSize秒 185 | private long barSize = 3; 186 | 187 | public Realtime(Framework framework) 188 | : base(framework) 189 | { 190 | } 191 | 192 | public override void Run() 193 | { 194 | //定义合约 195 | Instrument instrument1 = InstrumentManager.Instruments["ag1712"]; 196 | 197 | strategy = new MyStrategy(framework, "HelloWorld"); 198 | 199 | //引入合约到主策略工程 200 | strategy.AddInstrument(instrument1); 201 | 202 | //定义主策略中使用的合约的数据源和交易通道 203 | strategy.DataProvider = ProviderManager.GetDataProvider("QuantBoxCTP"); 204 | strategy.ExecutionProvider = ProviderManager.GetExecutionProvider("QuantBoxCTP"); 205 | 206 | //定义K线类型:时间型K线,barSize秒生成一个Bar 207 | BarFactory.Clear(); 208 | BarFactory.Add(instrument1, BarType.Time, barSize); 209 | 210 | Initialize(); 211 | 212 | //Run the strategy 213 | StartStrategy(); 214 | 215 | } 216 | } 217 | } 218 | ``` 219 | 220 | 这里HelloWolrd解决方案的Realtime工程中的Scenario.Designer.cs及Program.cs均不需要改动代码。 221 | 222 | ![](.gitbook/assets/icon_labtubeorg.ico)在OpenQuant的Solution Explorer中,将Realtime工程设置为启动工程(Set as StartUp Project),然后把OpenQuant切换为实盘模式(Live)后,运行HelloWorld解决方案,并观察输出: 223 | 224 | ![](.gitbook/assets/icon_paw%20%286%29.png)现在我们已经有了一个HelloWorld解决方案,该方案已经让我们完成一个主体逻辑后,可以进行回测状态和实盘状态的定义和切换。如果需要回测,我们就将Backtest工程设置为启动项,如果进行实盘接入,我们就将Realtime工程设置为启动项。 225 | 226 | 完整的代码应该存在版本控制系统中进行管理。 227 | 228 | 上述完整HelloWorld代码可以从如下地址获得: 229 | 230 | ![](.gitbook/assets/icon_book%20%282%29.png) [https://github.com/omnistep/OpenQuantHelloWorld](https://github.com/omnistep/OpenQuantHelloWorld) 获得。 231 | 232 | -------------------------------------------------------------------------------- /4_hello_world/design-an-openquant-helloworld.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/omnistep/OpenQuantCoding/e7d3858a5cabb55bae55965b5fef6b99eb265fd9/4_hello_world/design-an-openquant-helloworld.md -------------------------------------------------------------------------------- /4_hello_world/hello-world.md: -------------------------------------------------------------------------------- 1 | # 开始一个HelloWorld 2 | 3 | --- 4 | 5 | OpenQuant的开发体系是基于标准的微软C\#编程语言及.NET开发框架。 6 | 7 | 为了避免文字内容过于冗长,我们认为读者已经可以使用C\#编程语言并使用过Visual Studio开发工具。 8 | 9 | ## 创建第一个解决方案(C\# solution) 10 | 11 | ![](/icons/icon_labtubeBlue.ico)打开OpenQuant中的**File**菜单,**New**一个新的**solution**, 这里有一些解决方案类别选项,这个例子中,我们选择第一种“SmartQuant Instrument Strategy Solution”, 命名为_myFirstStrategy_, 保持目录应该保存在你的SVN代码版本管理体系中, 生成的解决方案(Solution)结构如下: 12 | 13 | ![](/assets/myFirstStrategyTreeDos.png) ![](/assets/myFirstStrategyFilesTreeOQ.png) 14 | 15 | 图:一个默认解决方案包含的文件结构 16 | 17 | 在Instrument Strategy Solution类型默认代码中,主要有3个核心文件: 18 | 19 | -**Backtest目录中的** 20 | 21 | -Program.cs -------------------------- 整个solution的入口文件,其中有整个策略代码的入口 Main函数 22 | 23 | -MyScenario.cs --------------------- 场景定义文件,可以定义合约订阅,定义回测起始结束日期或者定义实盘的交易通道 24 | 25 | -**MyStrategy目录中的** 26 | 27 | -MyStrategy.cs -----------------------策略核心文件,编写所有的核心策略逻辑 28 | 29 | ## OpenQuant的解决方案中代码的运行关系 30 | 31 | 这是一个标准的微软C\#解决方案,在这个**myFirstStrategy**解决方案(Solution)中有两个项目(Project):Backtest,MyStrategy,Backtest项目是默认的启动项目。代码关系如下图的所示: 32 | 33 | ![](/assets/myFirstStrategyCodeMap.png) `图: OpenQuant生成的策略代码的结构及调用关系` 34 | 35 | ![](/icons/icon_labtubeBlue.ico)为了掌握OpenQuant解决方案代码运行中的调用关系,我们在该项目文件中增加输出信息,使得程序运行时,可以呈现代码运行顺序和调用过程。 36 | 37 | 在**Program.cs **中添加代码: 38 | 39 | ``` 40 | using System; 41 | 42 | using SmartQuant; 43 | 44 | namespace OpenQuant 45 | { 46 | class Program 47 | { 48 | static void Main(string[] args) 49 | { 50 | System.Console.WriteLine("Program.cs程序主入口: Main()"); 51 | 52 | System.Console.WriteLine("Program.cs程序主入口中, 实例化MyScenario()"); 53 | Scenario scenario = new MyScenario(Framework.Current); 54 | 55 | System.Console.WriteLine("Program.cs程序主入口中, 运行Run()"); 56 | scenario.Run(); 57 | } 58 | } 59 | } 60 | ``` 61 | 62 | 在**MyScenario.cs **中添加代码: 63 | 64 | ``` 65 | using System; 66 | 67 | using SmartQuant; 68 | 69 | namespace OpenQuant 70 | { 71 | public partial class MyScenario : Scenario 72 | { 73 | public MyScenario(Framework framework) 74 | : base(framework) 75 | { 76 | System.Console.WriteLine("MyScenario.cs 我的场景开始定义"); 77 | } 78 | 79 | public override void Run() 80 | { 81 | strategy = new MyStrategy(framework, "Backtest"); 82 | System.Console.WriteLine("MyScenario.cs 我的场景MyScenario.Run()中, 实例化我的策略 new MyStrategy() "); 83 | 84 | System.Console.WriteLine("MyScenario.cs 我的场景MyScenario.Run()中, 开始初始化过程Initialize() "); 85 | Initialize(); 86 | 87 | System.Console.WriteLine("MyScenario.cs 我的场景MyScenario.Run()中, 开始策略StartStrategy()"); 88 | StartStrategy(); 89 | } 90 | } 91 | } 92 | ``` 93 | 94 | 在**MyStrategy.cs **中添加代码: 95 | 96 | ``` 97 | using System; 98 | 99 | using SmartQuant; 100 | 101 | namespace OpenQuant 102 | { 103 | public class MyStrategy : InstrumentStrategy 104 | { 105 | public MyStrategy(Framework framework, string name) 106 | : base(framework, name) 107 | { 108 | } 109 | 110 | protected override void OnStrategyStart() 111 | { 112 | System.Console.WriteLine("MyStrategy.cs 我的策略MyStrategy中OnStrategyStart()"); 113 | } 114 | 115 | protected override void OnBar(Instrument instrument, Bar bar) 116 | { 117 | System.Console.WriteLine("MyStrategy.cs 我的策略MyStrategy中OnBar()事件"); 118 | } 119 | } 120 | } 121 | ``` 122 | 123 | ![](/icons/icon_labtubeOrg.ico)添加完成后,直接运行策略,我们可以中OpenQuant的Output窗口中看到如下输出: 124 | 125 | ![](/assets/HelloWorldOutput01.png) 126 | 127 | 这样,我们很清楚地看出OpenQuant的策略运行过程,先是场景定义和初始化过程,然后实例化我的策略并运行。但策略中由于没有数据请求(data requests), OpenQuant的回测模式就即可运行完成了整个策略过程。如果将运行模式切换至仿真Paper或实盘Live模式,策略就会一直处于等待市场数据状态,并不会自动退出,直到手动停止。 128 | 129 | 对于一个完整的程序化交易策略中,只有一个Backtest部分和一个策略逻辑主体部分,这显然是有问题的。让我们先把要做的Hello World策略放在一旁,我们进入下一章,来看看一个稍微完整的OpenQuant策略示例代码的结构。 130 | 131 | -------------------------------------------------------------------------------- /8_a-basic-strategy/81-linescrossover-strategy.md: -------------------------------------------------------------------------------- 1 | # 10.1 三均线穿越系统 2 | 3 | 使用OpenQuant开发策略一般可以分为:数据或交易思路研究,策略结构设计,策略编码,策略回测,策略优化,交易监控等环节。 4 | 5 | 现在我们开始编写一个基于均线穿越场景的策略: 6 | 7 | ## 策略的假说 8 | 9 | 在一段行情的数据中,均线排列和行情走势有着明显的特征。当行情趋势明显上升时,均线呈现多头排列。即快速均线>慢速均线>更慢速的均线。当行情趋势明显下降时,均线呈现空头排列。即快速均线<慢速均线<更慢速的均线。 10 | 11 | ## 策略的逻辑 12 | 13 | 策略基于K线行情数据运行,并计算3条不同周期的价格均线, 当呈现多头排列时,入场做多。当呈现空头排列时,入场做空。入场后记录当前价格为监控水线,当价格想有利方向移动时,水线值也同样移动, 当价格向亏损方向移动时,水线不移动,当水线和当前价格差超过止损阈值时出场止损。 14 | 15 | ## 策略的代码 16 | 17 | 上述完整LinesCrossover代码可以从如下地址获得: 18 | 19 | ![](../.gitbook/assets/icon_book.png) [https://github.com/omnistep/](https://github.com/omnistep/OpenQuantHelloWorld)LinesCrossover 获得。 20 | 21 | ## 策略的运行 22 | 23 | 策略运行效果如下图所示,可以看出策略是现金绞肉机。 24 | 25 | ![](../.gitbook/assets/linescrossovershow.png)ComingSoon... 26 | 27 | -------------------------------------------------------------------------------- /8_a-basic-strategy/README.md: -------------------------------------------------------------------------------- 1 | # 10.一个基础的策略 2 | 3 | ## 从基础代码生成新的OpenQuant策略代码(Solutions) 4 | 5 | 通常C\#语言开发过程中,我们会从一个我们已经开发的基础应用解决方案\(Solutions\),形成一个新的程序(解决方案)。这时,我们可以先把原有的Solutions代码目录,完整的复制一份并把目录名定义为未来新的名字,然后用Visual Studio打开,在解决方案资源管理器中,进行重命名操作。 6 | 7 | ![](../.gitbook/assets/renameyoursolutions.png) 8 | 9 | 在Visual Studio中,可以方便地对,Solutions,Project,类库等等代码文件方便地进行重命名。 10 | 11 | ![](../.gitbook/assets/icon_labtubeblue%20%286%29.ico)现在我们以FlashOrder为基础,形成一个新的策略LinesCrossover,开始尝试开发一个真正的交易策略。注意修改主策略代码中的日志标识,以便在未来交易日志中区分新的策略命名和原有的策略命名。 12 | 13 | ```text 14 | //定义策略名字 StrategyName,将被记录在日志中 15 | String StrategyName="FlashOrder要改成LinesCrossover"; 16 | ``` 17 | 18 | ![](../.gitbook/assets/icon_paw%20%287%29.png)借助Vistual Studio工具,可以快速地基于一个基础的C\#解决方案代码,生成一个新的解决方案。 19 | 20 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # A Step by Step Guide to OpenQuant... 2 | 3 | # ![](assets/StepbyStepGuide.png) 4 | 5 | # 6 | 7 | # 序言 Introduction 8 | 9 | ver. 0160 2017/10/23 10 | ver. 0171 2018/08/31 11 | ver. 0256 2018/10/16 12 | 13 | ### 14 | 15 | * ##### 图标说明 16 | 17 | | 图标 | 代表含义 | 18 | | :---: | :--- | 19 | | ![](icons/icon_paw.png) | 一个爪印,代表你已经实现了这一步的结果 | 20 | | ![](icons/icon_bookbig.png) | 一本手册,代表外部参考资料或者资源 | 21 | | ![](icons/icon_labtubeblue.ico) | 一个蓝色实验瓶,代表这里要进行的操作和反复的操作 | 22 | | ![](icons/icon_labtubeOrg.ico) | 一个桔色实验瓶,代表这里查看运行的结果、状态或数据 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /SUMMARY.md: -------------------------------------------------------------------------------- 1 | # Summary 2 | 3 | * [序言Introduction](README.md) 4 | * [1. 在开始之前的准备](1_before-your-start/README.md) 5 | * [1.1 操作系统的选择](1_before-your-start/1.1-chose-a-stable-os.md) 6 | * [1.2 OpenQuant商业版与国内天风版](1_before-your-start/1.2-openquant-product-family.md) 7 | * [1.3 安装OpenQuant软件及插件](1_before-your-start/1.3-download-and-install-openquant.md) 8 | * [1.4 OpenQuant的界面和菜单说明](1_before-your-start/1.4-gui-of-openquant.md) 9 | * [1.5 配置通道并接入市场](1_before-your-start/1.5-config-plugins.md) 10 | * [1.6 导入合约信息](1_before-your-start/1.6-import-instruments.md) 11 | * [1.7 导入历史数据](1_before-your-start/1.7-import-historical.md) 12 | * [1.8 运行一个OpenQuant的示例策略](1_before-your-start/1.8-run-a-demo-strategy.md) 13 | * [2. 管理未来所有的代码...](2_manage_your_work/manage-your-coding-by-svn.md) 14 | * [3. 了解OpenQuant策略代码的结构](3_structure_of_openquant_solution/README.md) 15 | * [4. Hello World](4_hello_world/README.md) 16 | * [4.1 设计HelloWorld的构架](4_hello_world/41-design-an-openquant-helloworld.md) 17 | * [4.2 新创建解决方案](4_hello_world/42-new-a-solution.md) 18 | * [4.3 编写回测场景模块-Backtest](4_hello_world/43-code-the-baketest-scenario.md) 19 | * [4.4 编写核心策略模块myStrategy](4_hello_world/44-code-mystrategy-for-helloworld.md) 20 | * [4.5 编写实盘场景模块-Realtime](4_hello_world/45-code-the-realtime-scenario.md) 21 | * [4.6 运行HelloWorld](4_hello_world/46-let-us-run-helloworld.md) 22 | * [7. 发出交易指令](place-an-order/README.md) 23 | * [7.1 建立一个发出交易指令的策略FlashOrder](place-an-order/7.1-jian-li-yi-ge-fa-chu-jiao-yi-zhi-ling-de-ce-lve-flashorder.md) 24 | * [7.2 FlashOrder的策略逻辑](place-an-order/7.2-flashorder-de-ce-lve-luo-ji.md) 25 | * [7.3 FlashOrder的代码 v1](place-an-order/flashorderver_v1.md) 26 | * [7.4 将交易记录存入MySQL](place-an-order/log-order-information-using-mysql-db.md) 27 | * [7.5 同时处理多个合约 FlashOrder v2](place-an-order/flashorderver_v2.md) 28 | * [8 构建一个策略的空模板](place-an-order/buildemptytemplate.md) 29 | * [9. 使用OpenQuant的画图功能](place-an-order/82-using-drawing-pad.md) 30 | * [10.一个基础的策略](8_a-basic-strategy/README.md) 31 | * [10.1 三均线穿越系统](8_a-basic-strategy/81-linescrossover-strategy.md) 32 | 33 | -------------------------------------------------------------------------------- /assets/42_NewSolutionExploer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/omnistep/OpenQuantCoding/e7d3858a5cabb55bae55965b5fef6b99eb265fd9/assets/42_NewSolutionExploer.png -------------------------------------------------------------------------------- /assets/42_New_Solution_HelloWorld.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/omnistep/OpenQuantCoding/e7d3858a5cabb55bae55965b5fef6b99eb265fd9/assets/42_New_Solution_HelloWorld.png -------------------------------------------------------------------------------- /assets/46_SetAsStartupProject.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/omnistep/OpenQuantCoding/e7d3858a5cabb55bae55965b5fef6b99eb265fd9/assets/46_SetAsStartupProject.png -------------------------------------------------------------------------------- /assets/ConfigPlugIns_Conn.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/omnistep/OpenQuantCoding/e7d3858a5cabb55bae55965b5fef6b99eb265fd9/assets/ConfigPlugIns_Conn.png -------------------------------------------------------------------------------- /assets/ConfigPlugin_CTPAcct.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/omnistep/OpenQuantCoding/e7d3858a5cabb55bae55965b5fef6b99eb265fd9/assets/ConfigPlugin_CTPAcct.png -------------------------------------------------------------------------------- /assets/ConfigPlugins_Servers.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/omnistep/OpenQuantCoding/e7d3858a5cabb55bae55965b5fef6b99eb265fd9/assets/ConfigPlugins_Servers.png -------------------------------------------------------------------------------- /assets/HelloWorldOutput01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/omnistep/OpenQuantCoding/e7d3858a5cabb55bae55965b5fef6b99eb265fd9/assets/HelloWorldOutput01.png -------------------------------------------------------------------------------- /assets/ImportInstruments.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/omnistep/OpenQuantCoding/e7d3858a5cabb55bae55965b5fef6b99eb265fd9/assets/ImportInstruments.png -------------------------------------------------------------------------------- /assets/ScenarioCodeDemoBacktest.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/omnistep/OpenQuantCoding/e7d3858a5cabb55bae55965b5fef6b99eb265fd9/assets/ScenarioCodeDemoBacktest.png -------------------------------------------------------------------------------- /assets/SolutionExplorer_Demo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/omnistep/OpenQuantCoding/e7d3858a5cabb55bae55965b5fef6b99eb265fd9/assets/SolutionExplorer_Demo.png -------------------------------------------------------------------------------- /assets/StepbyStepGuide.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/omnistep/OpenQuantCoding/e7d3858a5cabb55bae55965b5fef6b99eb265fd9/assets/StepbyStepGuide.png -------------------------------------------------------------------------------- /assets/StrategyRunControl.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/omnistep/OpenQuantCoding/e7d3858a5cabb55bae55965b5fef6b99eb265fd9/assets/StrategyRunControl.png -------------------------------------------------------------------------------- /assets/configuration_CTP.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/omnistep/OpenQuantCoding/e7d3858a5cabb55bae55965b5fef6b99eb265fd9/assets/configuration_CTP.png -------------------------------------------------------------------------------- /assets/design_helloworld.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/omnistep/OpenQuantCoding/e7d3858a5cabb55bae55965b5fef6b99eb265fd9/assets/design_helloworld.png -------------------------------------------------------------------------------- /assets/gui_openquant_note.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/omnistep/OpenQuantCoding/e7d3858a5cabb55bae55965b5fef6b99eb265fd9/assets/gui_openquant_note.png -------------------------------------------------------------------------------- /assets/importHistoricalData.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/omnistep/OpenQuantCoding/e7d3858a5cabb55bae55965b5fef6b99eb265fd9/assets/importHistoricalData.png -------------------------------------------------------------------------------- /assets/importInstrumentsGUI03.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/omnistep/OpenQuantCoding/e7d3858a5cabb55bae55965b5fef6b99eb265fd9/assets/importInstrumentsGUI03.png -------------------------------------------------------------------------------- /assets/importInstumentsGUI02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/omnistep/OpenQuantCoding/e7d3858a5cabb55bae55965b5fef6b99eb265fd9/assets/importInstumentsGUI02.png -------------------------------------------------------------------------------- /assets/menu_view.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/omnistep/OpenQuantCoding/e7d3858a5cabb55bae55965b5fef6b99eb265fd9/assets/menu_view.png -------------------------------------------------------------------------------- /assets/openquanthelloworldrunning.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/omnistep/OpenQuantCoding/e7d3858a5cabb55bae55965b5fef6b99eb265fd9/assets/openquanthelloworldrunning.png -------------------------------------------------------------------------------- /assets/providers.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/omnistep/OpenQuantCoding/e7d3858a5cabb55bae55965b5fef6b99eb265fd9/assets/providers.png -------------------------------------------------------------------------------- /assets/providers_CTPon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/omnistep/OpenQuantCoding/e7d3858a5cabb55bae55965b5fef6b99eb265fd9/assets/providers_CTPon.png -------------------------------------------------------------------------------- /assets/smacrossovercodemap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/omnistep/OpenQuantCoding/e7d3858a5cabb55bae55965b5fef6b99eb265fd9/assets/smacrossovercodemap.png -------------------------------------------------------------------------------- /assets/smacrossoversolutionexplorer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/omnistep/OpenQuantCoding/e7d3858a5cabb55bae55965b5fef6b99eb265fd9/assets/smacrossoversolutionexplorer.png -------------------------------------------------------------------------------- /assets/viewHistoricalData.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/omnistep/OpenQuantCoding/e7d3858a5cabb55bae55965b5fef6b99eb265fd9/assets/viewHistoricalData.png -------------------------------------------------------------------------------- /build_empty_template.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/omnistep/OpenQuantCoding/e7d3858a5cabb55bae55965b5fef6b99eb265fd9/build_empty_template.md -------------------------------------------------------------------------------- /drive-mechanism-of-OpenQuant-running.md: -------------------------------------------------------------------------------- 1 | ## OpenQuant策略运行的事件驱动机制 2 | 3 | OpenQuant的策略运行机制主要是构造出扑捉市场数据的处理逻辑后,静静地等待各种事件发生,来驱动整体逻辑的运行。例如:当订阅的合约有最新报价变动时,或当行情的变动幅度超过定义时,当下单部分成交时,或发出的撤单指令成功时等等,当然有的时候也需要自己依据定时间隔去进行驱动。由于这种处理机制,可以让量化交易者精细地定义逻辑并清晰地执行。 4 | 5 | 下面就是一个成交事件处理的代码,你可以在SMACrossover策略解决方案中的MyStrategy工程的MyStrategy.cs代码中找到: 6 | 7 | ``` 8 | protected override void OnFill(SmartQuant.Fill fill) 9 | { 10 | // 在画布上绘制成交记录 11 | Log(fill, "Fills"); 12 | 13 | 14 | // 在Output窗口中输出fill对象的当前数据... 15 | System.Console.WriteLine("fill.DateTime=" + fill.DateTime.ToString()); 16 | System.Console.WriteLine("fill.CashFlow=" + fill.CashFlow.ToString()); 17 | System.Console.WriteLine("fill.Commission=" + fill.Commission.ToString()); 18 | 19 | System.Console.WriteLine("fill.Instrument.Symbol=" + fill.Instrument.Symbol.ToString()); 20 | System.Console.WriteLine("fill.Instrument.Description=" + fill.Instrument.Description.ToString()); 21 | System.Console.WriteLine("fill.Instrument.Trade=" + fill.Instrument.Trade.ToString()); 22 | 23 | System.Console.WriteLine("fill.Text=" + fill.Text.ToString()); 24 | 25 | } 26 | ``` 27 | 28 | ## OpenQuant策略运行的时间驱动机制 29 | 30 | 往往很多原因,我们不能只是让策略在被动等待事件,有时候需要进行主动地进行运行某些逻辑,例如,我们需要定时对系统状态及交易进行状态检查,所以我们还需要构造按照时间定时去运行的驱动机制。 31 | 32 | 使用上述的Reminder事件构造一个循环的定时器即可完成这个功能: 33 | 34 | ``` 35 | protected override void OnReminder(DateTime dateTime, object data) 36 | { 37 | CheckMyBoxStatus(); 38 | CheckMyAccountInfo(); 39 | 40 | AddReminder(Clock.DateTime.AddSeconds(3)); 41 | } 42 | ``` 43 | 44 | ##### 45 | 46 | ![](/icons/icon_book.png)[附:OpenQuant中的事件类型](/the-events-in-openquant.md) 47 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /flashorder_v1.md: -------------------------------------------------------------------------------- 1 | ## 7.3 FlashOrder的代码 v1 2 | 3 | FlashOrder策略还是由3个工程组成,Backtest,MyStrategy和Realtime。 4 | 5 | 其中Backtest工程中的MyScenario.cs代码为: 6 | 7 | ``` 8 | using System; 9 | 10 | using SmartQuant; 11 | 12 | namespace OpenQuant 13 | { 14 | public partial class Backtest : Scenario 15 | { 16 | 17 | //定义K线时间周期为barSize秒 18 | private long barSize = 60; 19 | 20 | 21 | public Backtest(Framework framework) 22 | : base(framework) 23 | { 24 | } 25 | 26 | public override void Run() 27 | { 28 | 29 | //定义要引入的合约名字 30 | Instrument instrument1 = InstrumentManager.Instruments["rb1709"]; 31 | 32 | 33 | strategy = new MyStrategy(framework, "Backtest"); 34 | 35 | 36 | //引入合约 37 | strategy.AddInstrument(instrument1); 38 | 39 | //定义数据回测的起止日期 40 | DataSimulator.SubscribeBar = false; 41 | DataSimulator.DateTime1 = new DateTime(2017, 08, 01); 42 | DataSimulator.DateTime2 = new DateTime(2017, 09, 02); 43 | 44 | //定义一个时间类型的K线 45 | BarFactory.Clear(); 46 | BarFactory.Add(instrument1, BarType.Time, barSize); 47 | 48 | Initialize(); 49 | 50 | StartStrategy(); 51 | } 52 | } 53 | } 54 | ``` 55 | 56 | Realtime工程中的Scenario.cs代码为: 57 | 58 | ``` 59 | using System; 60 | using System.Collections.Generic; 61 | using System.Linq; 62 | using System.Text; 63 | using System.Threading.Tasks; 64 | 65 | using SmartQuant; 66 | 67 | namespace OpenQuant 68 | { 69 | public partial class Realtime : Scenario 70 | { 71 | 72 | //定义K线时间周期为barSize秒 73 | private long barSize = 3; 74 | 75 | 76 | public Realtime(Framework framework) 77 | : base(framework) 78 | { 79 | } 80 | 81 | public override void Run() 82 | { 83 | 84 | //定义合约 85 | Instrument instrument1 = InstrumentManager.Instruments["au1712"]; 86 | 87 | strategy = new MyStrategy(framework, "HelloWorld"); 88 | 89 | //引入合约到主策略工程 90 | strategy.AddInstrument(instrument1); 91 | 92 | //定义主策略中使用的合约的数据源和交易通道 93 | strategy.DataProvider = ProviderManager.GetDataProvider("QuantBoxCTP"); 94 | strategy.ExecutionProvider = ProviderManager.GetExecutionProvider("QuantBoxCTP"); 95 | 96 | //定义K线类型:时间型K线,barSize秒生成一个Bar 97 | BarFactory.Clear(); 98 | BarFactory.Add(instrument1, BarType.Time, barSize); 99 | 100 | 101 | Initialize(); 102 | 103 | //Run the strategy 104 | StartStrategy(); 105 | } 106 | } 107 | } 108 | ``` 109 | 110 | 而MyStrategy工程中先要引入QuantBox.OQ.dll, 该文件安装QuantBoxCTP插件后,可以在OpenQuant默认安装路径中找到。MyStrategy.cs代码为: 111 | 112 | ``` 113 | using System; 114 | using System.Drawing; 115 | using SmartQuant; 116 | using QuantBox; 117 | 118 | namespace OpenQuant 119 | { 120 | public class MyStrategy : InstrumentStrategy 121 | { 122 | 123 | 124 | int orderQty = 1; //定义交易定单的发单量多少手 125 | int swLongEnable = 1; //定义做多交易许可开关,0:禁止,1:允许 126 | int swShortEnable = 1; //定义做空交易许可开关,0:禁止,1:允许 127 | 128 | int theOrdBOid = 0 ; //定义做多△买入开仓定单id 129 | int theOrdSCid = 0 ; //定义做多 ▼卖出平仓定单id 130 | string theOrdSCstatus = ""; //定义做多 ▼卖出平仓定单状态 131 | 132 | int theOrdSSid = 0 ; //定义做空▽卖出开仓定单id 133 | int theOrdBCid = 0 ; //定义做空 ▲买入平仓定单id 134 | 135 | int myCentOpen = 1 ; //定义开仓追价成本是多少TickSize; 136 | int myCentClose = 0 ; //定义平仓追价成本是多少TickSize; 137 | //默认1:代表盈利1个TickSize挂单 138 | // 0:代表市场平价报单; 139 | // -1:代表1个TickSize的成本报单 140 | 141 | public MyStrategy(Framework framework, string name) 142 | : base(framework, name) 143 | { 144 | } 145 | 146 | protected override void OnStrategyStart() 147 | { 148 | //定义K线的画布,编码0号 149 | Group("myK_Chart", "Pad", 0); 150 | Group("myK_Chart", "CandleWhiteColor", Color.Red); 151 | Group("myK_Chart", "CandleBlackColor", Color.Lime); 152 | Group("Fills", "Pad", 0); 153 | Group("Equity", "Pad", 1); 154 | 155 | } 156 | 157 | protected override void OnBar(Instrument instrument, Bar bar) 158 | { 159 | //当Bar形成时,增加bar数据到K线序列 160 | Bars.Add(bar); 161 | 162 | //在Bars画布上画出K线 163 | Log(bar, "myK_Chart"); 164 | 165 | // Calculate performance. 166 | Portfolio.Performance.Update(); 167 | // 在画布上绘制权益曲线 168 | Log(Portfolio.Value, "Equity"); 169 | 170 | 171 | 172 | //就是这句期待已久的HelloWorld!同时显示bar时间,合约代码,bar中的均价 173 | Console.WriteLine("OnBar------HelloWorld! "+bar.DateTime.ToString()+ " "+instrument.Symbol + " ="+bar.Average.ToString()); 174 | Console.WriteLine("swLongEnable= "+swLongEnable.ToString()+ "; swShortEnable ="+swShortEnable.ToString()); 175 | //显示平仓单状态 176 | System.Console.WriteLine("theOrdSCstatus = " + theOrdSCstatus); 177 | 178 | if(swLongEnable==1) 179 | { 180 | //买入-开仓 181 | Order orderBO = BuyLimitOrder(Instrument, orderQty, bar.Close - myCentOpen*Instrument.TickSize, "△"); 182 | //orderBO.Open(); 183 | Send(orderBO); 184 | 185 | swLongEnable = 0; 186 | theOrdBOid = orderBO.Id; 187 | System.Console.WriteLine("▓ orderBO.Id=" + orderBO.Id.ToString()); 188 | } 189 | 190 | 191 | if(swShortEnable==1) 192 | { 193 | //卖出-开仓 194 | Order orderSS = SellLimitOrder(Instrument, orderQty, bar.Close + myCentOpen*Instrument.TickSize, "▽"); 195 | //orderSS.Open(); 196 | Send(orderSS); 197 | 198 | swShortEnable = 0; 199 | theOrdSSid = orderSS.Id; 200 | System.Console.WriteLine("▓ orderSS.Id=" + orderSS.Id.ToString()); 201 | } 202 | 203 | /* 204 | 205 | 206 | 207 | */ 208 | } 209 | 210 | protected override void OnFill(SmartQuant.Fill fill) 211 | { 212 | // 在画布上绘制成交记录 213 | Log(fill, "Fills"); 214 | 215 | 216 | // 在Output窗口中输出fill对象的当前数据... 217 | System.Console.WriteLine("fill.DateTime=" + fill.DateTime.ToString()); 218 | System.Console.WriteLine("fill.CashFlow=" + fill.CashFlow.ToString()); 219 | System.Console.WriteLine("fill.Commission=" + fill.Commission.ToString()); 220 | System.Console.WriteLine("fill.Instrument.Symbol=" + fill.Instrument.Symbol.ToString()); 221 | System.Console.WriteLine("fill.Instrument.Description=" + fill.Instrument.Description.ToString()); 222 | System.Console.WriteLine("fill.Instrument.Trade=" + fill.Instrument.Trade.ToString()); 223 | System.Console.WriteLine("fill.Text=" + fill.Text.ToString()); 224 | 225 | 226 | 227 | if(fill.Order.Id == theOrdBOid) 228 | { 229 | System.Console.WriteLine("▓▓▓▓▓ --> 卖出-平仓"); 230 | //卖出-平仓 231 | Order orderSC = SellLimitOrder(Instrument, orderQty, fill.Price + myCentClose*Instrument.TickSize, "▼"); 232 | orderSC.CloseToday() ; 233 | Send(orderSC); 234 | 235 | theOrdSCid = orderSC.Id; 236 | theOrdSCstatus = orderSC.Status.ToString(); 237 | System.Console.WriteLine("▓▓▓▓▓ theOrdSCstatus = " + theOrdSCstatus); 238 | 239 | swLongEnable = 1; 240 | } 241 | 242 | if(fill.Order.Id == theOrdSSid) 243 | { 244 | System.Console.WriteLine("▓▓▓▓▓ --> 买入-平仓"); 245 | //买入-平仓 246 | Order orderBC = BuyLimitOrder(Instrument, orderQty, fill.Price - myCentClose*Instrument.TickSize, "▲"); 247 | orderBC.CloseToday(); 248 | Send(orderBC); 249 | System.Console.WriteLine("▓orderBC.SubSide=" + orderBC.SubSide.ToString()); 250 | 251 | theOrdBCid = orderBC.Id; 252 | 253 | swShortEnable = 1; 254 | } 255 | 256 | 257 | 258 | if(fill.Order.Id == theOrdSCid) 259 | { 260 | swLongEnable = 1; 261 | } 262 | 263 | if(fill.Order.Id == theOrdBCid) 264 | { 265 | swShortEnable = 1; 266 | } 267 | 268 | } 269 | 270 | 271 | } 272 | } 273 | ``` 274 | 275 | ![](/icons/icon_labtubeOrg.ico)运行策略后,应该通过OpenQuant自己的OrderManager及CTP通用交易客户终端查看到报单状况。 276 | 277 | ![](/assets/FlashOrderFilled.png) 278 | 279 | FlashOrder完整代码可以从 280 | 281 | ![](/icons/icon_book.png)[https://github.com/omnistep/](#)FlashOrder获得。 282 | 283 | -------------------------------------------------------------------------------- /icons/icon_book.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/omnistep/OpenQuantCoding/e7d3858a5cabb55bae55965b5fef6b99eb265fd9/icons/icon_book.png -------------------------------------------------------------------------------- /icons/icon_bookbig.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/omnistep/OpenQuantCoding/e7d3858a5cabb55bae55965b5fef6b99eb265fd9/icons/icon_bookbig.png -------------------------------------------------------------------------------- /icons/icon_labtubeOrg.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/omnistep/OpenQuantCoding/e7d3858a5cabb55bae55965b5fef6b99eb265fd9/icons/icon_labtubeOrg.ico -------------------------------------------------------------------------------- /icons/icon_labtubeblue.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/omnistep/OpenQuantCoding/e7d3858a5cabb55bae55965b5fef6b99eb265fd9/icons/icon_labtubeblue.ico -------------------------------------------------------------------------------- /icons/icon_paw.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/omnistep/OpenQuantCoding/e7d3858a5cabb55bae55965b5fef6b99eb265fd9/icons/icon_paw.png -------------------------------------------------------------------------------- /icons/icon_text.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/omnistep/OpenQuantCoding/e7d3858a5cabb55bae55965b5fef6b99eb265fd9/icons/icon_text.png -------------------------------------------------------------------------------- /place-an-order/7.1-jian-li-yi-ge-fa-chu-jiao-yi-zhi-ling-de-ce-lve-flashorder.md: -------------------------------------------------------------------------------- 1 | # 7.1 建立一个发出交易指令的策略FlashOrder 2 | 3 | -------------------------------------------------------------------------------- /place-an-order/7.2-flashorder-de-ce-lve-luo-ji.md: -------------------------------------------------------------------------------- 1 | # 7.2 FlashOrder的策略逻辑 2 | 3 | -------------------------------------------------------------------------------- /place-an-order/82-using-drawing-pad.md: -------------------------------------------------------------------------------- 1 | # 9. 使用OpenQuant的画图功能 2 | 3 | 在使用OpenQuant系统时, 我们通常要吧行情数据、指标数据、交易执行信息等在图中展示出来。OpenQuant系统菜单中打开view-chart, 或者view-chart\(gapless\)就可以看到OpenQuant的绘图板。Chart(gapless)是不考虑无数据时间的情况,例如盘后时间,或盘中休息、暂停交易等情况,绘制的是全连续的行情数据图形。 4 | 5 | 现在我们先绘制从画K线和均线开始。 6 | 7 | ## 绘制K线和均线并分区域绘制个性化指标数据 8 | 9 | 在场景文件中,先定义行情数据的K线属性,什么合约、什么周期,什么K线类型等等, OpenQuant不仅支持价格K线,同时也支持交易量K线,涨跌幅K线,Tick型K线等等其他类型。我们以时间型K线为例,场景scenario.cs代码为: 10 | 11 | ```text 12 | using System; 13 | 14 | using SmartQuant; 15 | 16 | namespace OpenQuant 17 | { 18 | public partial class Backtest : Scenario 19 | { 20 | 21 | //定义K线时间周期为barSize秒 22 | private long secBarSize =3; 23 | private long min1BarSize=60; 24 | 25 | 26 | public Backtest(Framework framework) 27 | : base(framework) 28 | { 29 | } 30 | 31 | public override void Run() 32 | { 33 | 34 | //定义要引入的合约名字 35 | Instrument instrument1 = InstrumentManager.Instruments["i1801"]; 36 | 37 | 38 | strategy = new MyStrategy(framework, "Backtest"); 39 | 40 | 41 | //引入合约 42 | strategy.AddInstrument(instrument1); 43 | 44 | //定义数据回测的起止日期 45 | DataSimulator.SubscribeBar = false; 46 | DataSimulator.DateTime1 = new DateTime(2017, 10, 13); 47 | DataSimulator.DateTime2 = new DateTime(2017, 10, 15); // data from 09-01 to 09-30 48 | 49 | //定义一个时间类型的K线 50 | BarFactory.Clear(); 51 | BarFactory.Add(instrument1, BarType.Time, secBarSize); 52 | 53 | BarFactory.Add(instrument1, BarType.Time, min1BarSize); 54 | 55 | Initialize(); 56 | 57 | StartStrategy(); 58 | } 59 | } 60 | } 61 | ``` 62 | 63 | 然后在主策略文件中的定义画布的参数和绘制,MyStrategy.cs的代码片段如下: 64 | 65 | ```text 66 | ... ... 67 | public class MyStrategy : InstrumentStrategy 68 | { 69 | //定义策略名字 StrategyName,将被记录在日志中 70 | String StrategyName="LinesCrossover"; 71 | 72 | //定义SMA对象 73 | private SMA sma1; 74 | private SMA sma2; 75 | private SMA sma3; 76 | 77 | public int sma1Length = 20; 78 | public int sma2Length = 60; 79 | public int sma3Length = 80; 80 | 81 | ... 82 | 83 | 84 | 85 | protected override void OnStrategyStart() 86 | { 87 | // Set up indicators. 88 | sma1 = new SMA(Bars, sma1Length); 89 | sma2 = new SMA(Bars, sma2Length); 90 | sma3 = new SMA(Bars, sma3Length); 91 | 92 | 93 | //定义K线的画布,编码0号 94 | //颜色变量-------------------------------------------- 95 | //Azure:天蓝色; Aquamarine:蓝晶色; Bisque:浓汤; 96 | //Beige:米色; BlanchedAlmond:杏仁白;BlueViolet:蓝紫; 97 | 98 | Group("myK_Chart", "Pad", 0); 99 | Group("myK_Chart", "CandleWhiteColor", Color.Red); 100 | Group("myK_Chart", "CandleBlackColor", Color.Lime); 101 | Group("Fills", "Pad", 0); 102 | 103 | 104 | Group("SMA1", "Pad", 0); 105 | Group("SMA1", "Color", Color.DodgerBlue); 106 | 107 | Group("SMA2", "Pad", 0); 108 | Group("SMA2","Width",2); 109 | Group("SMA2", "Color", Color.Red); 110 | 111 | Group("SMA3", "Pad", 0); 112 | Group("SMA3","Width",2); 113 | Group("SMA3", "Color", Color.DarkRed); 114 | 115 | //定义指标的画布,编码1、2号 116 | Group("IndicatorCross", "Pad", 1); 117 | Group("IndicatorCross","Width",2); 118 | Group("IndicatorCross", "Color", Color.DarkOrange); 119 | 120 | Group("IndicatorTrend", "Pad", 2); 121 | Group("IndicatorTrend","Width",2); 122 | Group("IndicatorTrend", "Color", Color.DodgerBlue); 123 | 124 | 125 | 126 | //定义权益曲线的画布,编码3号 127 | Group("Equity", "Pad", 3); 128 | 129 | //定义分钟K线,使用编码4的画布 130 | Group("minK_Chart", "Pad", 4); 131 | Group("minK_Chart", "CandleWhiteColor", Color.Red); 132 | Group("minK_Chart", "CandleBlackColor", Color.Lime); 133 | } 134 | ``` 135 | 136 | 在OnBar事件发生时,我们绘制K线和三条不同周期的均线 ,代码片段如下: 137 | 138 | ```text 139 | protected override void OnBar(Instrument instrument, Bar bar) 140 | { 141 | 142 | //当Bar形成时,增加bar数据到K线序列 143 | Bars.Add(bar); 144 | 145 | //在Bars画布上画出K线 146 | Log(bar, "myK_Chart"); 147 | 148 | // Calculate performance. 149 | Portfolio.Performance.Update(); 150 | // 在画布上绘制权益曲线 151 | Log(Portfolio.Value, "Equity"); 152 | 153 | 154 | // Log sma.在画布上画出三条均线,如果尚未产生SMA数据时,跳出事件过程,不做处理 155 | if (sma1.Count == 0 || sma2.Count == 0 || sma3.Count == 0) 156 | return; 157 | 158 | Log(sma1.Last, "SMA1"); 159 | Log(sma2.Last, "SMA2"); 160 | Log(sma3.Last, "SMA3"); 161 | 162 | 163 | ... ... 164 | (... 略去一段指标计算代码,结果是计算indicatorCross数值) 165 | 166 | //绘制指标indicatorCross 167 | Log(indicatorCross, "IndicatorCross"); 168 | 169 | (... 略去一段指标计算代码,结果是计算indicatorTrend数值) 170 | 171 | //绘制指标indicatorTrend 172 | Log(indicatorTrend, "IndicatorTrend"); 173 | 174 | ... 其他逻辑 175 | 176 | } 177 | ``` 178 | 179 | 这样我们绘制的图像如下: 180 | 181 | ![](../.gitbook/assets/usingdrawingpad01.png) 182 | 183 | 上述完整LinesCrossover代码可以从如下地址获得: 184 | 185 | ![](../.gitbook/assets/icon_book%20%281%29.png) [https://github.com/omnistep/](https://github.com/omnistep/OpenQuantHelloWorld)LinesCrossover 获得。 186 | 187 | -------------------------------------------------------------------------------- /place-an-order/README.md: -------------------------------------------------------------------------------- 1 | # 7. 发出交易指令 2 | 3 | ## 7.1建立一个发出交易指令的策略FlashOrder {#flashorder} 4 | 5 | 在OpenQuant中,基础的交易指令代码如下: 6 | 7 | ... ... 8 | 9 | ```text 10 | using QuantBox; 11 | ``` 12 | 13 | ... ... 14 | 15 | ```text 16 | //定义报单数量myOrdQty, 定义报单价格 myOrdPxU:当前价格加3跳; myOrdPxL:当前价格减3跳 17 | int myOrdQty = 1; 18 | double myOrdPxU = bar.Close + instrument.TickSize*3; 19 | double myOrdPxU = bar.Close - instrument.TickSize*3; 20 | ``` 21 | 22 | ```text 23 | 24 | 25 | //限价买入开仓-△ 26 | Order myBuyLimitOrder = BuyLimitOrder(instrument, myOrdQty, myOrdPxU,"买开△"); 27 | Send(myBuyLimitOrder); 28 | 29 | //限价卖出平仓-▼ 30 | Order mySellLimitOrder = SellLimitOrder(instrument, myOrdQty, myOrdPxU , "卖平▼"); 31 | mySellLimitOrder.Close(); 32 | Send(myBuyLimitOrder); 33 | 34 | //限价卖出开仓-▽ 35 | Order mySellLimitOrder = SellLimitOrder(instrument, myOrdQty, myOrdPxU , "卖开▽"); 36 | mySellLimitOrder.SubSide = SubSide.SellShort; 37 | Send(myBuyLimitOrder); 38 | 39 | //限价买入平仓-▲ 40 | Order myBuyLimitOrder = BuyLimitOrder(instrument, myOrdQty, myOrdPxU,"买开▲"); 41 | myBuyLimitOrder.SubSide = SubSide.BuyCover; 42 | myBuyLimitOrder.Close(); 43 | Send(myBuyLimitOrder); 44 | ``` 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 现在我们来构建一个新的交易策略代码。在这个策略中我们将实现: 65 | 66 | * [x] 发出期货交易中限价定单的交易指令:做多交易的买入开仓、卖出平仓;做空交易的卖出开仓、买入平仓。 67 | * [x] 在OpenQuant 行情数据图表中标识开仓记号,在OpenQuant图表中显示账户的权益曲线。 68 | * [x] 新增加一个日志功能,将所有的交易记录存入MySQL数据库。 69 | 70 | 我们把这个交易策略命名为FlashOrder 71 | 72 | ![](../.gitbook/assets/icon_labtubeblue%20%2810%29.ico)使用OpenQuant系统建立一个新的策略,并命名为FlashOrder 73 | 74 | ## 7.2 FlashOrder的策略逻辑 {#typeoforder} 75 | 76 | 这里的逻辑仅仅是为了使用让OpenQuant高速地发出开仓及平仓单,进行交易功能的验证。 77 | 78 | 在交易执行层面,我们只要处理四种定单的场景,即: 79 | 1. 买入开仓定单,简记符号为 △ 80 | 2. 卖出平仓定单,简记符号为 ▼ 81 | 3. 卖出开仓定单,简记符号为 ▽ 82 | 4. 买入平仓定单,简介符号为 ▲ 83 | 84 | ![](../.gitbook/assets/icon_paw%20%283%29.png)使用定单简记符号将使得研究交易策略,或输出运行日志时有很好的可阅读性。而且这组符号很容易识别和记忆。 85 | 86 | 在这个策略中,我们还需要处理两个事件:行情进入时的OnBar事件,和报单成交时的OnFill事件。为了测试上述4种定单,我们在OnBar事件发生时,将报出买入开仓△,和卖出开仓▽,当定单成交后,马上发出平仓单,为了控制每次OnBar事件发生时候,都发出开仓定单,导致资金消耗过多,我们用全局变量控制是否允许开仓进场,swLongEnable控制做多方向,swShortEnable控制做空方向。FlashOrder的总体策略逻辑如下图所示: 87 | 88 | ![](../.gitbook/assets/flashorderstrategydiagram.png) 89 | 90 | -------------------------------------------------------------------------------- /place-an-order/buildemptytemplate.md: -------------------------------------------------------------------------------- 1 | # 8 构建一个策略的空模板 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /place-an-order/flashorderver_v1.md: -------------------------------------------------------------------------------- 1 | # 7.3 FlashOrder的代码 v1 2 | 3 | FlashOrder策略还是由3个工程组成,Backtest,MyStrategy和Realtime。 4 | 5 | 其中Backtest工程中的MyScenario.cs代码为: 6 | 7 | ```text 8 | using System; 9 | 10 | using SmartQuant; 11 | 12 | namespace OpenQuant 13 | { 14 | public partial class Backtest : Scenario 15 | { 16 | 17 | //定义K线时间周期为barSize秒 18 | private long barSize = 60; 19 | 20 | 21 | public Backtest(Framework framework) 22 | : base(framework) 23 | { 24 | } 25 | 26 | public override void Run() 27 | { 28 | 29 | //定义要引入的合约名字 30 | Instrument instrument1 = InstrumentManager.Instruments["rb1709"]; 31 | 32 | 33 | strategy = new MyStrategy(framework, "Backtest"); 34 | 35 | 36 | //引入合约 37 | strategy.AddInstrument(instrument1); 38 | 39 | //定义数据回测的起止日期 40 | DataSimulator.SubscribeBar = false; 41 | DataSimulator.DateTime1 = new DateTime(2017, 08, 01); 42 | DataSimulator.DateTime2 = new DateTime(2017, 09, 02); 43 | 44 | //定义一个时间类型的K线 45 | BarFactory.Clear(); 46 | BarFactory.Add(instrument1, BarType.Time, barSize); 47 | 48 | Initialize(); 49 | 50 | StartStrategy(); 51 | } 52 | } 53 | } 54 | ``` 55 | 56 | Realtime工程中的Scenario.cs代码为: 57 | 58 | ```text 59 | using System; 60 | using System.Collections.Generic; 61 | using System.Linq; 62 | using System.Text; 63 | using System.Threading.Tasks; 64 | 65 | using SmartQuant; 66 | 67 | namespace OpenQuant 68 | { 69 | public partial class Realtime : Scenario 70 | { 71 | 72 | //定义K线时间周期为barSize秒 73 | private long barSize = 3; 74 | 75 | 76 | public Realtime(Framework framework) 77 | : base(framework) 78 | { 79 | } 80 | 81 | public override void Run() 82 | { 83 | 84 | //定义合约 85 | Instrument instrument1 = InstrumentManager.Instruments["au1712"]; 86 | 87 | strategy = new MyStrategy(framework, "HelloWorld"); 88 | 89 | //引入合约到主策略工程 90 | strategy.AddInstrument(instrument1); 91 | 92 | //定义主策略中使用的合约的数据源和交易通道 93 | strategy.DataProvider = ProviderManager.GetDataProvider("QuantBoxCTP"); 94 | strategy.ExecutionProvider = ProviderManager.GetExecutionProvider("QuantBoxCTP"); 95 | 96 | //定义K线类型:时间型K线,barSize秒生成一个Bar 97 | BarFactory.Clear(); 98 | BarFactory.Add(instrument1, BarType.Time, barSize); 99 | 100 | 101 | Initialize(); 102 | 103 | //Run the strategy 104 | StartStrategy(); 105 | } 106 | } 107 | } 108 | ``` 109 | 110 | 而MyStrategy工程中先要引入QuantBox.OQ.dll, 该文件安装QuantBoxCTP插件后,可以在OpenQuant默认安装路径中找到。MyStrategy.cs代码为: 111 | 112 | ```text 113 | using System; 114 | using System.Drawing; 115 | using SmartQuant; 116 | using QuantBox; 117 | 118 | namespace OpenQuant 119 | { 120 | public class MyStrategy : InstrumentStrategy 121 | { 122 | 123 | 124 | int orderQty = 1; //定义交易定单的发单量多少手 125 | int swLongEnable = 1; //定义做多交易许可开关,0:禁止,1:允许 126 | int swShortEnable = 1; //定义做空交易许可开关,0:禁止,1:允许 127 | 128 | int theOrdBOid = 0 ; //定义做多△买入开仓定单id 129 | int theOrdSCid = 0 ; //定义做多 ▼卖出平仓定单id 130 | string theOrdSCstatus = ""; //定义做多 ▼卖出平仓定单状态 131 | 132 | int theOrdSSid = 0 ; //定义做空▽卖出开仓定单id 133 | int theOrdBCid = 0 ; //定义做空 ▲买入平仓定单id 134 | 135 | int myCentOpen = 1 ; //定义开仓追价成本是多少TickSize; 136 | int myCentClose = 0 ; //定义平仓追价成本是多少TickSize; 137 | //默认1:代表盈利1个TickSize挂单 138 | // 0:代表市场平价报单; 139 | // -1:代表1个TickSize的成本报单 140 | 141 | public MyStrategy(Framework framework, string name) 142 | : base(framework, name) 143 | { 144 | } 145 | 146 | protected override void OnStrategyStart() 147 | { 148 | //定义K线的画布,编码0号 149 | Group("myK_Chart", "Pad", 0); 150 | Group("myK_Chart", "CandleWhiteColor", Color.Red); 151 | Group("myK_Chart", "CandleBlackColor", Color.Lime); 152 | Group("Fills", "Pad", 0); 153 | Group("Equity", "Pad", 1); 154 | 155 | } 156 | 157 | protected override void OnBar(Instrument instrument, Bar bar) 158 | { 159 | //当Bar形成时,增加bar数据到K线序列 160 | Bars.Add(bar); 161 | 162 | //在Bars画布上画出K线 163 | Log(bar, "myK_Chart"); 164 | 165 | // Calculate performance. 166 | Portfolio.Performance.Update(); 167 | // 在画布上绘制权益曲线 168 | Log(Portfolio.Value, "Equity"); 169 | 170 | 171 | 172 | //就是这句期待已久的HelloWorld!同时显示bar时间,合约代码,bar中的均价 173 | Console.WriteLine("OnBar------HelloWorld! "+bar.DateTime.ToString()+ " "+instrument.Symbol + " ="+bar.Average.ToString()); 174 | Console.WriteLine("swLongEnable= "+swLongEnable.ToString()+ "; swShortEnable ="+swShortEnable.ToString()); 175 | //显示平仓单状态 176 | System.Console.WriteLine("theOrdSCstatus = " + theOrdSCstatus); 177 | 178 | if(swLongEnable==1) 179 | { 180 | //买入-开仓 181 | Order orderBO = BuyLimitOrder(Instrument, orderQty, bar.Close - myCentOpen*Instrument.TickSize, "△"); 182 | //orderBO.Open(); 183 | Send(orderBO); 184 | 185 | swLongEnable = 0; 186 | theOrdBOid = orderBO.Id; 187 | System.Console.WriteLine("▓ orderBO.Id=" + orderBO.Id.ToString()); 188 | } 189 | 190 | 191 | if(swShortEnable==1) 192 | { 193 | //卖出-开仓 194 | Order orderSS = SellLimitOrder(Instrument, orderQty, bar.Close + myCentOpen*Instrument.TickSize, "▽"); 195 | //orderSS.Open(); 196 | Send(orderSS); 197 | 198 | swShortEnable = 0; 199 | theOrdSSid = orderSS.Id; 200 | System.Console.WriteLine("▓ orderSS.Id=" + orderSS.Id.ToString()); 201 | } 202 | 203 | /* 204 | 205 | 206 | 207 | */ 208 | } 209 | 210 | protected override void OnFill(SmartQuant.Fill fill) 211 | { 212 | // 在画布上绘制成交记录 213 | Log(fill, "Fills"); 214 | 215 | 216 | // 在Output窗口中输出fill对象的当前数据... 217 | System.Console.WriteLine("fill.DateTime=" + fill.DateTime.ToString()); 218 | System.Console.WriteLine("fill.CashFlow=" + fill.CashFlow.ToString()); 219 | System.Console.WriteLine("fill.Commission=" + fill.Commission.ToString()); 220 | System.Console.WriteLine("fill.Instrument.Symbol=" + fill.Instrument.Symbol.ToString()); 221 | System.Console.WriteLine("fill.Instrument.Description=" + fill.Instrument.Description.ToString()); 222 | System.Console.WriteLine("fill.Instrument.Trade=" + fill.Instrument.Trade.ToString()); 223 | System.Console.WriteLine("fill.Text=" + fill.Text.ToString()); 224 | 225 | 226 | 227 | if(fill.Order.Id == theOrdBOid) 228 | { 229 | System.Console.WriteLine("▓▓▓▓▓ --> 卖出-平仓"); 230 | //卖出-平仓 231 | Order orderSC = SellLimitOrder(Instrument, orderQty, fill.Price + myCentClose*Instrument.TickSize, "▼"); 232 | orderSC.CloseToday() ; 233 | Send(orderSC); 234 | 235 | theOrdSCid = orderSC.Id; 236 | theOrdSCstatus = orderSC.Status.ToString(); 237 | System.Console.WriteLine("▓▓▓▓▓ theOrdSCstatus = " + theOrdSCstatus); 238 | 239 | swLongEnable = 1; 240 | } 241 | 242 | if(fill.Order.Id == theOrdSSid) 243 | { 244 | System.Console.WriteLine("▓▓▓▓▓ --> 买入-平仓"); 245 | //买入-平仓 246 | Order orderBC = BuyLimitOrder(Instrument, orderQty, fill.Price - myCentClose*Instrument.TickSize, "▲"); 247 | orderBC.CloseToday(); 248 | Send(orderBC); 249 | System.Console.WriteLine("▓orderBC.SubSide=" + orderBC.SubSide.ToString()); 250 | 251 | theOrdBCid = orderBC.Id; 252 | 253 | swShortEnable = 1; 254 | } 255 | 256 | 257 | 258 | if(fill.Order.Id == theOrdSCid) 259 | { 260 | swLongEnable = 1; 261 | } 262 | 263 | if(fill.Order.Id == theOrdBCid) 264 | { 265 | swShortEnable = 1; 266 | } 267 | 268 | } 269 | 270 | 271 | } 272 | } 273 | ``` 274 | 275 | ![](../.gitbook/assets/icon_labtubeorg%20%282%29.ico)运行策略后,应该通过OpenQuant自己的OrderManager及CTP通用交易客户终端查看到报单状况。 276 | 277 | ![](../.gitbook/assets/flashorderfilled.png) 278 | 279 | -------------------------------------------------------------------------------- /place-an-order/flashorderver_v2.md: -------------------------------------------------------------------------------- 1 | # 7.5 同时处理多个合约 FlashOrder v2 2 | 3 | 通常我们需要相同的策略同时处理多个合约,根据实际情况,我们选择几种方法来管理多个合约的信息。 4 | 5 | * **最简单的方法** 6 | 7 | 简单的方法就是在场景文件Scenario.cs中,直接定义新的合约变量,复制相关代码即可, 主策略代码不用改变,策略运行时,你会发现一个合约就是策略的一个实例,它们都在并行的运行。 8 | 9 | ```text 10 | //定义合约 11 | Instrument instrument1 = InstrumentManager.Instruments["au1712"]; 12 | Instrument instrument2 = InstrumentManager.Instruments["rb1801"]; 13 | Instrument instrument3 = InstrumentManager.Instruments["c1801"]; 14 | ... ... 15 | 16 | 17 | //引入合约到主策略工程 18 | strategy.AddInstrument(instrument1); 19 | strategy.AddInstrument(instrument2); 20 | strategy.AddInstrument(instrument3); 21 | ... ... 22 | 23 | //定义K线类型:时间型K线,barSize秒生成一个Bar 24 | BarFactory.Clear(); 25 | BarFactory.Add(instrument1, BarType.Time, barSize); 26 | BarFactory.Add(instrument2, BarType.Time, barSize); 27 | BarFactory.Add(instrument3, BarType.Time, barSize); 28 | ... ... 29 | ``` 30 | 31 | * **优雅的方法,使用数组字符串** 32 | 33 | 在场景文件Scenario.cs中,可以定义一个变量数组, 采用循环代码进行加载,但这个方法中, 会出现你想加入的合约信息并没有在OpenQuant引入过,代码会报出提示, 如果有这样的情况,你应该先在OpenQuant中手动引入相关的合约信息(过程详见1.5 导入合约信息),场景文件中的相关代码如下: 34 | 35 | ```text 36 | public override void Run() 37 | { 38 | 39 | //定义合约 40 | string[] myInstruments = {"au1712", "rb1801","c1801","m1801","p1801","TA801","i1801","MA801","ru1801", 41 | "hc1801","ni1801","IF1710","IC1710","IH1710","fb1801","jm1801","RM801","ZC801", 42 | "SR801","al1712","ag1712","cu1711","OI801"}; 43 | 44 | 45 | ... ... 46 | 47 | 48 | //引入合约到主策略工程 49 | foreach (string symbol in myInstruments) 50 | { 51 | Instrument i = InstrumentManager.Get(symbol); //检查合约的信息是否已经在OpenQuant中引入 52 | if (i == null) 53 | { 54 | Console.Write("【"+symbol+"】该合约信息尚未引入OpenQuant!"); 55 | } 56 | strategy.Instruments.Add(i);//引入合约到主策略工程 57 | } 58 | 59 | 60 | ... ... 61 | 62 | 63 | //定义主策略中使用的合约的数据源和交易通道 64 | strategy.DataProvider = ProviderManager.GetDataProvider("QuantBoxCTP"); 65 | strategy.ExecutionProvider = ProviderManager.GetExecutionProvider("QuantBoxCTP"); 66 | 67 | //定义K线类型:时间型K线,barSize秒生成一个Bar 68 | BarFactory.Clear(); 69 | 70 | foreach (string symbol in myInstruments) 71 | { 72 | Instrument i = InstrumentManager.Get(symbol); 73 | BarFactory.Add( i, BarType.Time, barSize); 74 | } 75 | 76 | //定义一个TickBar 77 | BarFactory.Add(InstrumentManager.Get("IF1711"), BarType.Tick,1); 78 | 79 | Initialize(); 80 | 81 | ... ... 82 | ``` 83 | 84 | * **更好的方式,使用数据库** 85 | 86 | Coming soon... ... 87 | 88 | -------------------------------------------------------------------------------- /place-an-order/log-order-information-using-mysql-db.md: -------------------------------------------------------------------------------- 1 | # 7.4 将交易记录存入MySQL 2 | 3 | 对于一个完善的IT系统,无论是交易系统,还是业务管理系统,我们都会按照层次结构来规划。作为一个交易系统,我们需要将交易日志存入数据,以提供业务监控、问题排查、数据统计分析。 4 | 5 | 现在我们就将FlashOrder下单的记录全部存入Mysql数据库。 6 | 7 | ![](../.gitbook/assets/icon_labtubeblue%20%289%29.ico)大致过程分为五步,第一步建立数据库及日志表;第二步在FlashOrder中引入相关的MySQL动态链接库;第三步编写一个日志存储功能的方法,让主策略代码可以调用日志功能。这个文件我们命名为OmniLog.cs,这个文件我们和主策略代码放在一个工程代码中; 第四步,我们在主策略的下单代码后面,插入调用日志存储的方法;第五步,使用MySQL工具及性能工具进行日志存储的查看和监控。 8 | 9 | * **第一步-安装MySQL数据库及建立交易日志表** 10 | 11 | 第一步,我们安装好MySQL数据库,并建立交易报单日志表LogOrder表,建表SQL如下: 12 | 13 | ```text 14 | CREATE TABLE `logorder` ( 15 | `id` INT(11) NOT NULL AUTO_INCREMENT, 16 | `logdatetime` DATETIME(6) NULL DEFAULT NULL COMMENT 'log记录时间', 17 | `StrategyName` VARCHAR(20) NULL DEFAULT NULL COMMENT '策略名字' COLLATE 'utf8mb4_unicode_ci', 18 | `OrdId` INT(11) NULL DEFAULT NULL, 19 | `OrdDateTime` DATETIME(6) NULL DEFAULT NULL, 20 | `Symbol` VARCHAR(10) NULL DEFAULT NULL COLLATE 'latin1_swedish_ci', 21 | `TradeDay` DATE NULL DEFAULT NULL, 22 | `Side` VARCHAR(10) NULL DEFAULT NULL COLLATE 'latin1_swedish_ci', 23 | `Type` VARCHAR(10) NULL DEFAULT NULL COLLATE 'latin1_swedish_ci', 24 | `Qty` INT(11) NULL DEFAULT NULL, 25 | `Price` FLOAT NULL DEFAULT NULL, 26 | `Status` VARCHAR(16) NULL DEFAULT NULL COLLATE 'latin1_swedish_ci', 27 | `note` VARCHAR(50) NULL DEFAULT NULL COMMENT '备注' COLLATE 'utf8mb4_unicode_ci', 28 | PRIMARY KEY (`id`) 29 | ) 30 | COMMENT='定单日志表,存储所有交易记录' 31 | COLLATE='utf8mb4_unicode_ci' 32 | ENGINE=InnoDB 33 | AUTO_INCREMENT=72969 34 | ; 35 | ``` 36 | 37 | * **第二步-在策略工程中引入MySQL的DLL库及建立MySQL访问代码** 38 | 39 | 在FlashOrder解决方案的在MyStrategy工程中,先引入Mysql的.NET驱动库:**MySql.Data.dll** 。这个动态链接库文件你可以在MySQL的安装目录中也可以找到。 40 | 41 | 再在MyStrategy工程中增加MySQL访问功能的公共方法代码,文件名MysqlMan.cs ,该文件代码如下: 42 | 43 | ```text 44 | /* 45 | * Purpose: MySQL DB Access 46 | * 47 | * Created: 2017/09/12 48 | * 49 | * 50 | */ 51 | 52 | using System; 53 | using System.Collections.Generic; 54 | using System.Linq; 55 | using System.Text; 56 | using System.Threading.Tasks; 57 | 58 | using MySql.Data.MySqlClient; 59 | 60 | 61 | namespace OpenQuant 62 | { 63 | class MysqlMan 64 | { 65 | 66 | 67 | /// 68 | /// 建立mysql数据库链接 69 | /// 70 | /// 71 | public static MySqlConnection getMySqlCon() 72 | { 73 | String mysqlStrQBMD = ""; 74 | //Mysql Server at Lab 75 | mysqlStrQBMD = "Database=MySQL01;Data Source=127.0.0.1;User Id=root;Password=yourPassword;pooling=false;CharSet=utf8;port=3306;Allow Zero Datetime=True"; 76 | //MySQL Server at Home 77 | //mysqlStrQBMD = "Database=MySQL02;Data Source=127.0.0.1;User Id=root;Password=yourPassword;pooling=false;CharSet=utf8;port=3306;Allow Zero Datetime=True"; 78 | 79 | 80 | 81 | MySqlConnection mysql = new MySqlConnection(mysqlStrQBMD); 82 | return mysql; 83 | } 84 | 85 | /// 86 | /// 建立执行命令语句对象 87 | /// 88 | /// 89 | /// 90 | /// 91 | public static MySqlCommand getSqlCommand(String sql, MySqlConnection mysql) 92 | { 93 | MySqlCommand mySqlCommand = new MySqlCommand(sql, mysql); 94 | return mySqlCommand; 95 | } 96 | 97 | /// 98 | /// 添加数据 99 | /// 100 | /// 101 | public static void getInsert(MySqlCommand mySqlCommand) 102 | { 103 | try 104 | { 105 | mySqlCommand.ExecuteNonQuery(); 106 | } 107 | catch (Exception ex) 108 | { 109 | String message = ex.Message; 110 | Console.WriteLine("插入数据失败了!" + message); 111 | 112 | } 113 | 114 | } 115 | 116 | /// 117 | /// 删除数据 118 | /// 119 | /// 120 | public static void getDel(MySqlCommand mySqlCommand) 121 | { 122 | try 123 | { 124 | mySqlCommand.ExecuteNonQuery(); 125 | } 126 | catch (Exception ex) 127 | { 128 | String message = ex.Message; 129 | Console.WriteLine("删除数据失败了!" + message); 130 | } 131 | } 132 | 133 | /// 134 | /// 修改数据 135 | /// 136 | /// 137 | public static void getUpdate(MySqlCommand mySqlCommand) 138 | { 139 | try 140 | { 141 | mySqlCommand.ExecuteNonQuery(); 142 | } 143 | catch (Exception ex) 144 | { 145 | 146 | String message = ex.Message; 147 | Console.WriteLine("修改数据失败了!" + message); 148 | } 149 | } 150 | 151 | 152 | 153 | public static int ExecuteNonQuery(string sql) 154 | { 155 | MySqlConnection mysql = null; 156 | try 157 | { 158 | mysql = getMySqlCon(); 159 | mysql.Open(); 160 | MySqlCommand mySqlCommand = new MySqlCommand(sql, mysql); 161 | int result = mySqlCommand.ExecuteNonQuery(); 162 | mysql.Close(); 163 | return result; 164 | } 165 | catch (Exception ex) 166 | { 167 | if (mysql != null && mysql.State != System.Data.ConnectionState.Closed) 168 | mysql.Close(); 169 | String message = ex.Message; 170 | Console.WriteLine("ExecuteNonQuery失败了!" + message); 171 | return 0; 172 | } 173 | } 174 | 175 | public static object ExecuteScalar(string sql) 176 | { 177 | MySqlConnection mysql=null; 178 | try 179 | { 180 | mysql = getMySqlCon(); 181 | MySqlCommand mySqlCommand = new MySqlCommand(sql, mysql); 182 | mysql.Open(); 183 | object result = mySqlCommand.ExecuteScalar(); 184 | mysql.Close(); 185 | return result; 186 | 187 | } 188 | catch (Exception ex) 189 | { 190 | if(mysql!=null && mysql.State != System.Data.ConnectionState.Closed) 191 | mysql.Close(); 192 | String message = ex.Message; 193 | Console.WriteLine("ExecuteNonQuery失败了!" + message); 194 | return null; 195 | } 196 | } 197 | } 198 | } 199 | ``` 200 | 201 | * **第三步-编写日志存储功能OmniLog.cs** 202 | 203 | 在FlashOrder解决方案的MyStrategy工程中,增加日志存储功能OmniLog.cs文件,该文件负责提供报单日志存储方法,以便策略中可以方便地调用,保存报单日志,OmniLog.cs的代码如下: 204 | 205 | ```text 206 | /* 207 | * Purpose: OmniLog 208 | * 209 | * version: 1.0.0 210 | * create : 2017/09/19 211 | * by : ww 212 | * 213 | * //▓▓记录日志 OmniLog.logOrder(StrategyName,OrdId, DateTime.Now,OrdDateTime,Symbol,Side,Type,Qty,Price,Status,Note) 214 | * 215 | * select id,date_format(logdatetime,'%Y-%m-%d %H:%i:%s:%f'),strategyname,ordid,date_format(orddatetime,'%Y-%m-%d %H:%i:%s:%f'),symbol,tradeday,side,type,qty,price,status,note from logorder order by id desc 216 | * 217 | */ 218 | 219 | using System; 220 | using System.Collections.Generic; 221 | using System.Linq; 222 | using System.Text; 223 | using System.Threading.Tasks; 224 | 225 | using SmartQuant; 226 | 227 | namespace OpenQuant 228 | { 229 | public class OmniLog 230 | { 231 | 232 | /// 233 | /// 记录定单 logOrder 234 | /// 235 | /// 236 | public static void logOrder(String StrategyName,int OrdId,DateTime OrdDateTime,String Symbol,String Side,String Type,double Qty,double Price,String Status,String Note) 237 | { 238 | try 239 | { 240 | 241 | string sqlInsert = string.Format("insert into LogOrder(LogDateTime,StrategyName,OrdId,OrdDateTime,Symbol,side,type,qty,price,status,note) values('{0:yyyy-MM-dd HH:mm:ss.fff}','{1}','{2}','{3:yyyy-MM-dd HH:mm:ss.fff}','{4}','{5}','{6}','{7}','{8}','{9}','{10}')", 242 | DateTime.Now,StrategyName,OrdId,OrdDateTime,Symbol,Side,Type,Qty,Price,Status,Note); 243 | int row = MysqlMan.ExecuteNonQuery(sqlInsert); 244 | 245 | 246 | } 247 | catch (Exception ex) 248 | { 249 | String message = ex.Message; 250 | Console.WriteLine("数据保存失败了!" + message); 251 | 252 | } 253 | 254 | } 255 | 256 | 257 | 258 | } 259 | } 260 | ``` 261 | 262 | * **第四步-在主策略逻辑中增加日志存储代码** 263 | 264 | 现在我们可以在主策略逻辑中保存报单日志了,报单日志保存的调用方法是: 265 | 266 | ```text 267 | OmniLog.logOrder(StrategyName,OrdId, DateTime.Now,OrdDateTime,Symbol,Side,Type,Qty,Price,Status,Note) 268 | ``` 269 | 270 | FlashOrder的主策略代码改为: 271 | 272 | ```text 273 | using System; 274 | using System.Drawing; 275 | using SmartQuant; 276 | using QuantBox; 277 | 278 | namespace OpenQuant 279 | { 280 | public class MyStrategy : InstrumentStrategy 281 | { 282 | //定义策略名字 StrategyName,将被记录在日志中 283 | String StrategyName="FlashOrder"; 284 | 285 | int orderQty = 1; //定义交易定单的发单量多少手 286 | int swLongEnable = 1; //定义做多交易许可开关,0:禁止,1:允许 287 | int swShortEnable = 1; //定义做空交易许可开关,0:禁止,1:允许 288 | 289 | int theOrdBOid = 0 ; //定义做多△买入开仓定单id 290 | int theOrdSCid = 0 ; //定义做多 ▼卖出平仓定单id 291 | string theOrdSCstatus = ""; //定义做多 ▼卖出平仓定单状态 292 | 293 | int theOrdSSid = 0 ; //定义做空▽卖出开仓定单id 294 | int theOrdBCid = 0 ; //定义做空 ▲买入平仓定单id 295 | 296 | int myCentOpen = -1 ; //定义开仓追价成本是多少TickSize; 297 | int myCentClose = -1 ; //定义平仓追价成本是多少TickSize; 298 | //默认1:代表盈利1个TickSize挂单 299 | // 0:代表市场平价报单; 300 | // -1:代表1个TickSize的成本报单 301 | 302 | public MyStrategy(Framework framework, string name) 303 | : base(framework, name) 304 | { 305 | } 306 | 307 | protected override void OnStrategyStart() 308 | { 309 | //定义K线的画布,编码0号 310 | Group("myK_Chart", "Pad", 0); 311 | Group("myK_Chart", "CandleWhiteColor", Color.Red); 312 | Group("myK_Chart", "CandleBlackColor", Color.Lime); 313 | Group("Fills", "Pad", 0); 314 | Group("Equity", "Pad", 1); 315 | 316 | } 317 | 318 | protected override void OnBar(Instrument instrument, Bar bar) 319 | { 320 | //当Bar形成时,增加bar数据到K线序列 321 | Bars.Add(bar); 322 | 323 | //在Bars画布上画出K线 324 | Log(bar, "myK_Chart"); 325 | 326 | // Calculate performance. 327 | Portfolio.Performance.Update(); 328 | // 在画布上绘制权益曲线 329 | Log(Portfolio.Value, "Equity"); 330 | 331 | 332 | 333 | //就是这句期待已久的HelloWorld!同时显示bar时间,合约代码,bar中的均价 334 | Console.WriteLine("OnBar------HelloWorld! "+bar.DateTime.ToString()+ " "+instrument.Symbol + " ="+bar.Average.ToString()); 335 | Console.WriteLine("swLongEnable= "+swLongEnable.ToString()+ "; swShortEnable ="+swShortEnable.ToString()); 336 | //显示平仓单状态 337 | System.Console.WriteLine("theOrdSCstatus = " + theOrdSCstatus); 338 | 339 | if(swLongEnable==1) 340 | { 341 | //买入-开仓 342 | Order orderBO = BuyLimitOrder(Instrument, orderQty, bar.Close - myCentOpen*Instrument.TickSize, "△"); 343 | //orderBO.Open(); 344 | Send(orderBO); 345 | 346 | //▓▓记录日志OmniLog.logOrder(StrategyName,OrdId,DateTime.Now,OrdDateTime,Symbol,Side,Type,Qty,Price,Status,Note) 347 | OmniLog.logOrder(StrategyName,orderBO.Id,orderBO.DateTime,orderBO.Instrument.Symbol,orderBO.Side.ToString() ,orderBO.Type.ToString() ,orderBO.Qty,orderBO.Price,orderBO.Status.ToString() ,"△"); 348 | 349 | 350 | swLongEnable = 0; 351 | theOrdBOid = orderBO.Id; 352 | 353 | } 354 | 355 | 356 | if(swShortEnable==1) 357 | { 358 | //卖出-开仓 359 | Order orderSS = SellLimitOrder(Instrument, orderQty, bar.Close + myCentOpen*Instrument.TickSize, "▽"); 360 | //orderSS.Open(); 361 | Send(orderSS); 362 | 363 | //▓▓记录日志OmniLog.logOrder(StrategyName,OrdId,DateTime.Now,OrdDateTime,Symbol,Side,Type,Qty,Price,Status,Note) 364 | OmniLog.logOrder(StrategyName,orderSS.Id ,orderSS.DateTime,orderSS.Instrument.Symbol,orderSS.Side.ToString() ,orderSS.Type.ToString() ,orderSS.Qty,orderSS.Price,orderSS.Status.ToString() ,"▽"); 365 | 366 | 367 | swShortEnable = 0; 368 | theOrdSSid = orderSS.Id; 369 | 370 | } 371 | 372 | 373 | } 374 | 375 | protected override void OnFill(SmartQuant.Fill fill) 376 | { 377 | // 在画布上绘制成交记录 378 | Log(fill, "Fills"); 379 | 380 | 381 | // 在Output窗口中输出fill对象的当前数据... 382 | System.Console.WriteLine("fill.DateTime=" + fill.DateTime.ToString()); 383 | System.Console.WriteLine("fill.CashFlow=" + fill.CashFlow.ToString()); 384 | System.Console.WriteLine("fill.Commission=" + fill.Commission.ToString()); 385 | System.Console.WriteLine("fill.Instrument.Symbol=" + fill.Instrument.Symbol.ToString()); 386 | System.Console.WriteLine("fill.Instrument.Description=" + fill.Instrument.Description.ToString()); 387 | System.Console.WriteLine("fill.Instrument.Trade=" + fill.Instrument.Trade.ToString()); 388 | System.Console.WriteLine("fill.Text=" + fill.Text.ToString()); 389 | 390 | //▓▓记录日志OmniLog.logOrder(StrategyName,OrdId, DateTime.Now,OrdDateTime,Symbol,Side,Type,Qty,Price,Status,Note) 391 | OmniLog.logOrder(StrategyName,fill.Order.Id ,fill.DateTime,fill.Instrument.Symbol,fill.Side.ToString() ,fill.Order.Type.ToString() ,fill.Qty,fill.Price,fill.Order.Status.ToString() ,"挂单成交"); 392 | 393 | 394 | 395 | if(fill.Order.Id == theOrdBOid) 396 | { 397 | //卖出-平仓 398 | Order orderSC = SellLimitOrder(Instrument, orderQty, fill.Price + myCentClose*Instrument.TickSize, "▼"); 399 | orderSC.CloseToday() ; 400 | Send(orderSC); 401 | 402 | theOrdSCid = orderSC.Id; 403 | theOrdSCstatus = orderSC.Status.ToString(); 404 | 405 | swLongEnable = 1; 406 | 407 | //▓▓记录日志OmniLog.logOrder(StrategyName,OrdId, DateTime.Now,OrdDateTime,Symbol,Side,Type,Qty,Price,Status,Note) 408 | OmniLog.logOrder(StrategyName,orderSC.Id ,orderSC.DateTime,orderSC.Instrument.Symbol,orderSC.Side.ToString() ,orderSC.Type.ToString() ,orderSC.Qty,orderSC.Price,orderSC.Status.ToString() ,"▼"); 409 | 410 | } 411 | 412 | if(fill.Order.Id == theOrdSSid) 413 | { 414 | //买入-平仓 415 | Order orderBC = BuyLimitOrder(Instrument, orderQty, fill.Price - myCentClose*Instrument.TickSize, "▲"); 416 | orderBC.CloseToday(); 417 | Send(orderBC); 418 | System.Console.WriteLine("▓orderBC.SubSide=" + orderBC.SubSide.ToString()); 419 | 420 | theOrdBCid = orderBC.Id; 421 | 422 | swShortEnable = 1; 423 | 424 | //▓▓记录日志OmniLog.logOrder(StrategyName,OrdId, DateTime.Now,OrdDateTime,Symbol,Side,Type,Qty,Price,Status,Note) 425 | OmniLog.logOrder(StrategyName,orderBC.Id ,orderBC.DateTime,orderBC.Instrument.Symbol,orderBC.Side.ToString() ,orderBC.Type.ToString() ,orderBC.Qty,orderBC.Price,orderBC.Status.ToString() ,"▲"); 426 | 427 | } 428 | 429 | 430 | 431 | if(fill.Order.Id == theOrdSCid) 432 | { 433 | swLongEnable = 1; 434 | } 435 | 436 | if(fill.Order.Id == theOrdBCid) 437 | { 438 | swShortEnable = 1; 439 | } 440 | 441 | } 442 | 443 | 444 | } 445 | 446 | } 447 | ``` 448 | 449 | * **第五步-使用MySQL工具进行查看及监控** 450 | 451 | ![](../.gitbook/assets/icon_labtubeorg%20%283%29.ico)这时运行策略FlashOrder,当有报单时,OmniLog会将所有报单记录存入数据库的表LogOrder 452 | 453 | 在MySQL中记录定单日志如下: 454 | 455 | ![](../.gitbook/assets/table_logorder.png) 456 | 457 | 通过Mysql的Workbench工具可以监控数据库的状态,Dashboard工具如下图所示: 458 | 459 | ![](../.gitbook/assets/mysqldashboard01.png)我们会发现这样写日志的效率还是有些慢,但对于没有做高频交易(HFT)的情况,这些工具是适用的。 460 | 461 | -------------------------------------------------------------------------------- /the-events-in-openquant.md: -------------------------------------------------------------------------------- 1 | # .策略运行的事件驱动和定时驱动机制 2 | 3 | # OpenQuant的常用事件 4 | 5 | 在OpenQuant接入金融交易市场收到订阅合约的行情数据及策略运行时常见的事件有: 6 | 7 | **OnStrategyStart** – 在策略启动时调用,在第一笔行情到达之前 8 | 9 | **OnStrategyStop** – 在策略结束时调用,在最后一笔行情之后 10 | 11 | **OnBarOpen** – 在Bar行情最前沿调用(如,在日线数据开盘时买入) 12 | 13 | **OnBar** – 在所有行情的后沿调用(如,在日线数据收盘时买入) 14 | 15 | **OnPositionOpened** – 当一个新的交易开仓确认后调用 16 | 17 | **OnPositionChanged** – 当仓位增加或减少时调用 18 | 19 | **OnTrade** – 当市场中有成交时调用 20 | 21 | **OnAsk** – 当盘口ask有变化时调用 22 | 23 | **OnBid** – 当盘口bid有变化时调用 24 | 25 | **OnOrderCancelled**– 当撤单确认后调用 26 | 27 | **OnOrderFilled**– 当报单全部成交后调用 28 | 29 | **OnOrderPartiallyFilled**– 当报单部分成交后调用 30 | 31 | **OnFill** – 当报单后有成交时调用OnStopExecuted 32 | 33 | **OnReminder**– 当到达指定时间时调用(定时器) 34 | 35 | **OnStopExecuted**– 当到达指定止损条件时调用 36 | 37 | 在策略代码编辑环境下输入override on...会有智能提示,可以看到更多事件处理函数 38 | 39 | ![](../.gitbook/assets/commonly_strategy_event01.png) 40 | 41 | ## **OnStrategyStart** 42 | 43 | 策略启动前OnStrategyStart方法被调用,整个策略运行期只会被调用一次。OnStrategyStart事件处理中可以创建新对象,并赋值给类中声明的变量。 44 | 45 | 例如为默认Bars创建SMA对象的例子 46 | 47 | ```text 48 | using System; 49 | using SmartQuant; 50 | using SmartQuant.Indicators; 51 | namespace OpenQuant 52 | { 53 | public class MyStrategy : InstrumentStrategy 54 | { 55 | private SMA sma1; 56 | private SMA sma2; 57 | private int Length1 = 5; 58 | private int Length2 = 10; 59 | protected override void OnStrategyStart() 60 | { 61 | sma1 = new SMA(Bars, Length1); 62 | sma2 = new SMA(Bars, Length2); 63 | } 64 | } 65 | } 66 | ``` 67 | 68 | ## **OnBar** 69 | 70 | OnBar是在有新的完整bar到来后被触发的。每个行情包括过去一个时间段的OHLCV(开盘价、最高价、最低价、收盘价、成交量)数据。因此OnBar事件是在行情后延触发的。如果需要在行情到来前处理一些动作则需要使用OnBarOpen事件。 71 | 72 | 例如交易从9:00开始,5分钟bar。OnBar会在9:05、9:10...触发,如果用的是日线数据,那么不能在OnBar中报单,因为触发OnBar的时候已经收盘了。 73 | 74 | ```text 75 | protected override void OnBar(Instrument instrument, Bar bar) 76 | { 77 | //把最新的bar添加到Bars序列 78 | Bars.Add(bar); 79 | } 80 | ``` 81 | 82 | ## **OnPositionOpened** 83 | 84 | OnPositionOpened是在交易完成时有新的头寸建立时触发的。只有交易订单被执行后才会有新头寸生成。所有的持仓数据都是大于0的。当仓位减到0时(被平仓),头寸对象被销毁。剩下的只有开仓(包括尝试开仓)的交易记录以及平仓的交易记录。 85 | 86 | 这里是一个以新开仓位持仓数量、按照5个最小价格变动单位止盈下平仓单的例子。 87 | 88 | ```text 89 | protected override void OnPositionOpened(SmartQuant.Position position) 90 | { 91 | if(position.Side == PositionSide.Long) 92 | {//持有多头仓位 93 | Order sellOrder = SellLimitOrder(position.Instrument,position.Qty,position.Price+position.Instrument.TickSize*5); 94 | Send(sellOrder); 95 | } 96 | else 97 | {//持有空头仓位 98 | Order buyOrder = BuyLimitOrder(position.Instrument,position.Qty,position.Price-position.Instrument.TickSize*5); 99 | Send(buyOrder ); 100 | } 101 | } 102 | ``` 103 | 104 | ## **OnPositionChanged** 105 | 106 | OnPositionChanged是在持仓发生变化时触发的。比如当有部分成交导致持仓变化时该事件会被触发。OnPositionChanged是一个需要必须跟踪部分成交后调整止损单数量的好地方。每当新的部分成交确认到来时,你可以添加未完成止损单的数量,这样,你的止损单会更准确的反映原始订单状态。 107 | 108 | ```text 109 | protected override void OnPositionChanged(SmartQuant.Position position) 110 | { 111 | } 112 | ``` 113 | 114 | ## **OnTrade** 115 | 116 | OnTrade是在市场中有成交就会触发。例如国内普通期货行情是1秒2个行情数据包,在每次接受到行情后,如果有成交数据就会触发OnTrade。 117 | 118 | ```text 119 | protected override void OnTrade(SmartQuant.Instrument instrument, SmartQuant.Trade trade) 120 | { 121 | string symbol = instrument.Symbol;//成交的合约代码 122 | string time = trade.DateTime.ToString("yyyy-MM-dd HH:mm:ss.fff");//成交时间 123 | double price = trade.Price;//成交价格 124 | int size = trade.Size;//成交数量 125 | } 126 | ``` 127 | 128 | ## **OnAsk** 129 | 130 | OnAsk是盘口ask数据发生变化就会触发。比较适用于对于需要监控盘口数据的策略。 131 | 132 | ```text 133 | protected override void OnAsk(SmartQuant.Instrument instrument, SmartQuant.Ask ask) 134 | { 135 | double askPrice = ask.Price;//盘口卖盘价格 136 | int askSize = ask.Size;//卖盘挂单量 137 | } 138 | ``` 139 | 140 | ## **OnBid** 141 | 142 | OnBid是盘口bid数据发生变化就会触发。比较适用于对于需要监控盘口数据的策略。 143 | 144 | ```text 145 | protected override void OnBid(SmartQuant.Instrument instrument, SmartQuant.Bid bid) 146 | { 147 | double bidPrice = bid.Price;//盘口买盘价格 148 | int bidSize = bid.Size;//盘口买盘挂单量 149 | } 150 | ``` 151 | 152 | ## **OnReminder** 153 | 154 | OnReminder定时器,在具体的一个时间点触发。需要先通过AddReminder函数添加定时器,到指定时间则触发OnReminder函数。例如日内交易策略,想在收盘前10分钟就不再允许开新的仓位,假设9点开盘15点收盘。 155 | 156 | ```text 157 | bool allowOpenFlag = true;//是否允许开仓标志,true允许,false不允许 158 | DateTime myCloseTime;//尾盘禁止开仓的时间 159 | protected override void OnStrategyStart() 160 | { 161 | System.Console.WriteLine("Hello OpenQuant"); 162 | myCloseTime = new DateTime(DateTime.Now.Year,DateTime.Now.Month,DateTime.Now.Day,14,50,0); 163 | AddReminder(myCloseTime, "my close time");//添加第一个尾盘定时器 164 | } 165 | protected override void OnReminder(DateTime dateTime, object data) 166 | { 167 | //通过时间和data参数判断是否是尾盘定时器触发 168 | if (dateTime == myCloseTime && data.ToString() == "my close time") 169 | { 170 | allowOpenFlag = false;//设置开仓标志为false,不允许开仓 171 | myCloseTime = myCloseTime.AddDays(1);//尾盘禁止开仓时间加1天,变为下个交易日的尾盘禁止交易时间 172 | AddReminder(myCloseTime, "my close time");//添加下个交易日尾盘定时器 173 | } 174 | } 175 | protected override void OnBarOpen(Instrument instrument, Bar bar) 176 | { 177 | if (bar.OpenDateTime.Hour == 9 && allowOpenFlag == false) 178 | { 179 | allowOpenFlag = true;//开盘设置允许开仓标志为 true 180 | } 181 | } 182 | ``` 183 | 184 | ## **OnStopExecuted** 185 | 186 | OnStopExecuted当达到设置的止损条件时调用,需要先通过AddStop函数设置止损条件。 187 | 188 | 使用AddStop函数,需要构造一个Stop止损对象做为参数传入,Stop止损条件对象又分两种触发模式,一是定时触发,二是根据行情触发。 189 | 190 | Stop\(Strategy strategy,Position position,DateTime time\) 在到达time时触发止损 191 | 192 | Stop\(Strategy strategy,Position position,double level,StopType type,StopMode mode\) 根据行情触发止损 193 | 194 | strategy:策略对象 195 | 196 | position:持仓对象 197 | 198 | time:具体时间,达到这个时间就调用OnStopExecuted 199 | 200 | level:具体数值结合type、mode使用 201 | 202 | Stoptype:止损方式,固定StopType.Fixed还是跟踪StopType.Trailing,Fixed就表示价格回撤固定的level点(百分比)就调用OnStopExecuted,Trailing就表示行情从AddStop之后的最高(低)点回落(回升)level点(百分比)就调用OnStopExecuted 203 | 204 | StopMode:level的取值方式(单位),StopMode.Absolute-level按照报价加减level计算止损点位,StopMode.Percent-level按照百分比计算止损点位。 205 | 206 | Stop\(strategy,position,10,StopType.Fixed,StopMode.Absolute\)- 从当前价位回撤10点则调用OnStopExecuted 207 | 208 | Stop\(strategy,position,10,StopType.Trailing,StopMode.Absolute\)- 从之后最优价位回撤10点则调用OnStopExecuted 209 | 210 | Stop\(strategy,position,0.02,StopType.Fixed,StopMode.Percent\)- 从当前价位回撤2%则调用OnStopExecuted 211 | 212 | Stop\(strategy,position,0.02,StopType.Trailing,StopMode.Percent\)- 从之后最优价位回撤2%则调用OnStopExecuted 213 | 214 | 下面是一个跟踪止损的示例 215 | 216 | ```text 217 | protected override void OnPositionOpened(Position position) 218 | { 219 | Stop s = new Stop(this, position, position.Instrument.TickSize * 10, StopType.Trailing, StopMode.Absolute); 220 | AddStop(s);//从AddStop之后,价格从最优回落10跳则调用OnStopExecuted 221 | } 222 | protected override void OnStopExecuted(Stop stop) 223 | { 224 | if (stop.Side == PositionSide.Long) 225 | { 226 | Order closeOrder = SellOrder(stop.Instrument, stop.Qty, "close long position"); 227 | Send(closeOrder); 228 | } 229 | else 230 | { 231 | Order closeOrder = BuyOrder(stop.Instrument, stop.Qty, "close short position"); 232 | Send(closeOrder); 233 | } 234 | } 235 | ``` 236 | 237 | 238 | 239 | --------------------------------------------------------------------------------