├── .gitattributes ├── .gitignore ├── CTP.Brokers.xml ├── CTPZQ.Brokers.xml ├── LICENSE.txt ├── QuantBox.nlog ├── README.md └── src ├── QuantBox.Helper.CTP ├── CTPAPI.cs ├── CTPQuote.cs ├── CTPTrade.cs ├── DataConvert.cs ├── Properties │ └── AssemblyInfo.cs ├── QuantBox.Helper.CTP.Net35.csproj ├── QuantBox.Helper.CTP.Net40.csproj ├── QuantBox.Helper.CTPZQ.Net35.csproj └── QuantBox.Helper.CTPZQ.Net40.csproj ├── QuantBox.OQ.CTP.sln └── QuantBox.OQ.CTP ├── APIProvider.CTP.Connection.cs ├── APIProvider.CTP.MarketData.cs ├── APIProvider.CTP.Order.cs ├── APIProvider.CTP.Quote.cs ├── APIProvider.CTP.cs ├── APIProvider.ExecutionProvider.cs ├── APIProvider.InstrumentProvider.cs ├── APIProvider.MarketDataProvider.cs ├── APIProvider.Provider.cs ├── APIProvider.Settings.cs ├── APIProvider.SimulationMarketDataProvider.cs ├── AccountItem.cs ├── ApiContainer.cs ├── ApiWrapper.cs ├── BrokerItem.cs ├── DataRecord.cs ├── OrderMap.cs ├── OrderRecord.cs ├── Properties ├── AssemblyInfo.cs └── DataSources │ ├── BrokerItem.datasource │ └── ServerItem.datasource ├── QuantBox.OQ.CTP.OQ3.csproj ├── QuantBox.OQ.CTP.QD.csproj ├── QuantBox.OQ.CTPZQ.OQ3.csproj ├── QuantBox.OQ.CTPZQ.QD.csproj ├── QuoteApiWrapper.cs ├── ServerItem.cs ├── ServersManagerForm.Designer.cs ├── ServersManagerForm.cs ├── ServersManagerForm.resx ├── ServersManagerTypeEditor.cs ├── TraderApiWrapper.cs └── WinAPI.cs /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text eol=auto 3 | 4 | # Custom for Visual Studio 5 | *.cs diff=csharp 6 | *.sln merge=union 7 | *.csproj merge=union 8 | *.vbproj merge=union 9 | *.fsproj merge=union 10 | *.dbproj merge=union 11 | 12 | # Standard to msysgit 13 | *.doc diff=astextplain 14 | *.DOC diff=astextplain 15 | *.docx diff=astextplain 16 | *.DOCX diff=astextplain 17 | *.dot diff=astextplain 18 | *.DOT diff=astextplain 19 | *.pdf diff=astextplain 20 | *.PDF diff=astextplain 21 | *.rtf diff=astextplain 22 | *.RTF diff=astextplain 23 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ################# 2 | ## Visual Studio 3 | ################# 4 | 5 | ## Ignore Visual Studio temporary files, build results, and 6 | ## files generated by popular Visual Studio add-ons. 7 | 8 | # User-specific files 9 | *.suo 10 | *.user 11 | *.sln.docstates 12 | 13 | # Build results 14 | [Dd]ebug/ 15 | [Rr]elease/ 16 | *_i.c 17 | *_p.c 18 | *.ilk 19 | *.meta 20 | *.obj 21 | *.pch 22 | *.pdb 23 | *.pgc 24 | *.pgd 25 | *.rsp 26 | *.sbr 27 | *.tlb 28 | *.tli 29 | *.tlh 30 | *.tmp 31 | *.vspscc 32 | .builds 33 | *.dotCover 34 | 35 | ## TODO: If you have NuGet Package Restore enabled, uncomment this 36 | #packages/ 37 | 38 | # Visual C++ cache files 39 | ipch/ 40 | *.aps 41 | *.ncb 42 | *.opensdf 43 | *.sdf 44 | 45 | # Visual Studio profiler 46 | *.psess 47 | *.vsp 48 | 49 | # ReSharper is a .NET coding add-in 50 | _ReSharper* 51 | 52 | # Installshield output folder 53 | [Ee]xpress 54 | 55 | # DocProject is a documentation generator add-in 56 | DocProject/buildhelp/ 57 | DocProject/Help/*.HxT 58 | DocProject/Help/*.HxC 59 | DocProject/Help/*.hhc 60 | DocProject/Help/*.hhk 61 | DocProject/Help/*.hhp 62 | DocProject/Help/Html2 63 | DocProject/Help/html 64 | 65 | # Click-Once directory 66 | publish 67 | 68 | # Others 69 | [Oo]bj 70 | sql 71 | TestResults 72 | *.Cache 73 | ClientBin 74 | stylecop.* 75 | ~$* 76 | *.dbmdl 77 | Generated_Code #added for RIA/Silverlight projects 78 | 79 | # Backup & report files from converting an old project file to a newer 80 | # Visual Studio version. Backup files are not needed, because we have git ;-) 81 | _UpgradeReport_Files/ 82 | Backup*/ 83 | UpgradeLog*.XML 84 | 85 | 86 | 87 | ############ 88 | ## Windows 89 | ############ 90 | 91 | # Windows image file caches 92 | Thumbs.db 93 | 94 | # Folder config file 95 | Desktop.ini 96 | 97 | # Mac crap 98 | .DS_Store 99 | -------------------------------------------------------------------------------- /CTP.Brokers.xml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 4040 9 | 10 | tcp://yhzx-front1.yhqh.com:51205 11 | tcp://yhzx-front3.yhqh.com:52205 12 | tcp://101.95.8.178:53205 13 | 14 | 15 | tcp://yhzx-front1.yhqh.com:41213 16 | tcp://yhzx-front3.yhqh.com:41213 17 | tcp://101.95.8.178:53213 18 | 19 | 20 | 21 | 22 | 23 | 4040 24 | 25 | tcp://yhzx-front2.yhqh.com:51205 26 | tcp://yhzx-front4.yhqh.com:52205 27 | tcp://58.247.171.146:53205 28 | 29 | 30 | tcp://yhzx-front2.yhqh.com:41213 31 | tcp://yhzx-front4.yhqh.com:41213 32 | tcp://58.247.171.146:53213 33 | 34 | 35 | 36 | 37 | 38 | 4040 39 | 40 | tcp://yhctp-front1.yhqh.com:41205 41 | tcp://yhctp-front3.yhqh.com:41205 42 | 43 | 44 | tcp://yhctp-front1.yhqh.com:41213 45 | tcp://yhctp-front3.yhqh.com:41213 46 | 47 | 48 | 49 | 50 | 51 | 4040 52 | 53 | tcp://yhctp-front2.yhqh.com:41205 54 | tcp://yhctp-front4.yhqh.com:41205 55 | 56 | 57 | tcp://yhctp-front2.yhqh.com:41213 58 | tcp://yhctp-front4.yhqh.com:41213 59 | 60 | 61 | 62 | 63 | 64 | 4040 65 | 66 | tcp://192.168.106.51:41219 67 | tcp://192.168.106.52:41205 68 | 69 | 70 | tcp://192.168.106.51:41207 71 | tcp://192.168.106.52:41213 72 | 73 | 74 | 75 | 76 | 3030 77 | 78 | tcp://124.207.185.168:4120 79 | 80 | 81 | tcp://124.207.185.168:4121 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 1013 93 | 94 | tcp://218.1.96.8:41205 95 | 96 | 97 | tcp://218.1.96.8:41213 98 | 99 | 100 | 101 | 102 | 103 | 4000 104 | 105 | tcp://203.110.179.220:41205 106 | 107 | 108 | tcp://203.110.179.220:41213 109 | 110 | 111 | 112 | 113 | 114 | 4000 115 | 116 | tcp://211.144.195.157:41205 117 | 118 | 119 | tcp://211.144.195.157:41213 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 1002 131 | 132 | tcp://sim-front1.ctp.shcifco.com:31205 133 | tcp://sim-front2.ctp.shcifco.com:31205 134 | 135 | 136 | tcp://sim-md1.ctp.shcifco.com:31213 137 | tcp://sim-md2.ctp.shcifco.com:31213 138 | 139 | 140 | 141 | 142 | 143 | 8070 144 | 145 | tcp://zjzx-front1.ctp.shcifco.com:41205 146 | tcp://zjzx-front2.ctp.shcifco.com:41205 147 | tcp://zjzx-front3.ctp.shcifco.com:41205 148 | tcp://zjzx-front4.ctp.shcifco.com:41205 149 | tcp://zjzx-front5.ctp.shcifco.com:41205 150 | 151 | 152 | tcp://zjzx-md1.ctp.shcifco.com:41213 153 | tcp://zjzx-md2.ctp.shcifco.com:41213 154 | tcp://zjzx-md3.ctp.shcifco.com:41213 155 | tcp://zjzx-md4.ctp.shcifco.com:41213 156 | tcp://zjzx-md5.ctp.shcifco.com:41213 157 | 158 | 159 | 160 | 161 | 162 | 8070 163 | 164 | tcp://zjzx-front11.ctp.shcifco.com:41205 165 | tcp://zjzx-front12.ctp.shcifco.com:41205 166 | tcp://zjzx-front13.ctp.shcifco.com:41205 167 | tcp://zjzx-front14.ctp.shcifco.com:41205 168 | tcp://zjzx-front15.ctp.shcifco.com:41205 169 | 170 | 171 | tcp://zjzx-md11.ctp.shcifco.com:41213 172 | tcp://zjzx-md12.ctp.shcifco.com:41213 173 | tcp://zjzx-md13.ctp.shcifco.com:41213 174 | tcp://zjzx-md14.ctp.shcifco.com:41213 175 | tcp://zjzx-md15.ctp.shcifco.com:41213 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 1001 187 | 188 | tcp://180.168.102.230:26205 189 | 190 | 191 | tcp://180.168.102.230:26213 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 1017 203 | 204 | tcp://ctpmn1-front1.citicsf.com:51205 205 | tcp://ctpmn1-front2.citicsf.com:51205 206 | 207 | 208 | tcp://ctpmn1-front1.citicsf.com:51213 209 | tcp://ctpmn1-front2.citicsf.com:51213 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 8090 221 | 222 | tcp://58.246.40.180:26205 223 | 224 | 225 | tcp://58.246.40.180:26213 226 | 227 | 228 | 229 | 230 | 231 | 8090 232 | 233 | tcp://cifco-front1.financial-trading-platform.com:41205 234 | tcp://cifco-front3.financial-trading-platform.com:41205 235 | tcp://cifco-front4.financial-trading-platform.com:41205 236 | tcp://cifco-front5.financial-trading-platform.com:41205 237 | tcp://cifco-front7.financial-trading-platform.com:41205 238 | tcp://cifco-front8.financial-trading-platform.com:41205 239 | tcp://cifco-front9.financial-trading-platform.com:41205 240 | 241 | 242 | tcp://cifco-md1.financial-trading-platform.com:41213 243 | tcp://cifco-md3.financial-trading-platform.com:41213 244 | tcp://cifco-md4.financial-trading-platform.com:41213 245 | tcp://cifco-md5.financial-trading-platform.com:41213 246 | tcp://cifco-md7.financial-trading-platform.com:41213 247 | tcp://cifco-md8.financial-trading-platform.com:41213 248 | tcp://cifco-md9.financial-trading-platform.com:41213 249 | 250 | 251 | 252 | 253 | 254 | 8090 255 | 256 | tcp://cifco-front2.financial-trading-platform.com:41205 257 | tcp://cifco-front6.financial-trading-platform.com:41205 258 | tcp://cifco-front9.financial-trading-platform.com:41205 259 | 260 | 261 | tcp://cifco-md2.financial-trading-platform.com:41213 262 | tcp://cifco-md6.financial-trading-platform.com:41213 263 | tcp://cifco-md9.financial-trading-platform.com:41213 264 | 265 | 266 | 267 | 268 | 269 | 8090 270 | 271 | tcp://218.241.197.56:41205 272 | tcp://218.241.197.55:41205 273 | 274 | 275 | tcp://218.241.197.56:41213 276 | tcp://218.241.197.55:41213 277 | 278 | 279 | 280 | 281 | 282 | 8090 283 | 284 | tcp://123.127.45.138:41205 285 | tcp://123.127.45.137:41205 286 | tcp://123.127.45.139:41205 287 | 288 | 289 | tcp://123.127.45.138:41213 290 | tcp://123.127.45.137:41213 291 | tcp://123.127.45.139:41213 292 | 293 | 294 | 295 | 296 | 297 | 8090 298 | 299 | tcp://61.144.241.113:41205 300 | tcp://61.144.241.114:41205 301 | tcp://61.144.241.115:41205 302 | 303 | 304 | tcp://61.144.241.113:41213 305 | tcp://61.144.241.114:41213 306 | tcp://61.144.241.115:41213 307 | 308 | 309 | 310 | 311 | 312 | 8090 313 | 314 | tcp://210.22.25.180:41205 315 | tcp://210.22.25.184:41205 316 | 317 | 318 | tcp://210.22.25.180:41213 319 | tcp://210.22.25.184:41213 320 | 321 | 322 | 323 | 324 | 325 | 8090 326 | 327 | tcp://218.241.197.52:41205 328 | tcp://218.241.197.53:41205 329 | tcp://218.241.197.54:41205 330 | tcp://123.127.45.145:41205 331 | tcp://218.241.197.59:41205 332 | 333 | 334 | tcp://218.241.197.52:41213 335 | tcp://218.241.197.53:41213 336 | tcp://218.241.197.54:41213 337 | tcp://123.127.45.145:41213 338 | tcp://218.241.197.59:41213 339 | 340 | 341 | 342 | 343 | 344 | 8090 345 | 346 | tcp://123.127.45.141:41205 347 | tcp://123.127.45.144:41205 348 | tcp://123.127.45.142:41205 349 | tcp://123.127.45.143:41205 350 | tcp://123.127.45.145:41205 351 | 352 | 353 | tcp://123.127.45.141:41213 354 | tcp://123.127.45.144:41213 355 | tcp://123.127.45.142:41213 356 | tcp://123.127.45.143:41213 357 | tcp://123.127.45.145:41213 358 | 359 | 360 | 361 | 362 | 363 | 364 | -------------------------------------------------------------------------------- /CTPZQ.Brokers.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 2011 9 | 10 | tcp://116.228.234.67:41205 11 | 12 | 13 | tcp://116.228.234.67:41213 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QuantBox/OpenQuant-CTP/31e0187e912fdb1baa56e52d9d87e50f57ffb049/LICENSE.txt -------------------------------------------------------------------------------- /QuantBox.nlog: -------------------------------------------------------------------------------- 1 |  2 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # OpenQuant内盘期货插件 2 | 3 | ## 目的 4 | 将OpenQuant与国内的CTP进行对接,让OpenQuant直接能交易国内期货 5 | 6 | ## 设计思路 7 | 1. 利用了本开源项目的C-CTP接口,与CSharp-CTP接口 8 | 2. C-CTP、CSharp-CTP都以dll方式调用 9 | 3. 本插件同时支持QuantDeveloper、OpenQuant2和OpenQuant3(以下分别简称QD、OQ2和OQ3),只要进行再编译即可 10 | 4. 为了支持查询合约列表功能,不使用OpenQuant接口,而是使用更底层的SmartQuant接口 11 | 12 | ## 如何安装使用 13 | 1. 找到SmartQuant接口插件目录C:\Program Files\SmartQuant Ltd\OpenQuant\Framework\bin\ 14 | 2. 复制QuantBox.OQ.CTP.dll这个SQ插件,确保此插件的版本正确 15 | 3. 找到OpenQuant接口插件目录C:\Program Files\SmartQuant Ltd\OpenQuant\Bin\ 16 | 4. 复制thostmduserapi.dll、thosttraderapi.dll两个CTP的dll到此目录 17 | 5. 复制QuantBox.C2CTP.dll、QuantBox.CSharp2CTP.dll、QuantBox.Helper.CTP.dll、NLog.dll到此目录 18 | 6. 复制CTP.nlog到此目录,或自己修改此文件 19 | 7. 找到软件的插件配置文件C:\Documents and Settings\Administrator\Application Data\SmartQuant Ltd\OpenQuant\Framework\ini\framework.xml 20 | 8. 添加``到对应位置 21 | 9. 如何使用请查看插件的使用说明 22 | 23 | ## 如何开发 24 | 1. 确保你的C-CTP接口的dll、CSharp-CTP接口等都是最新的 25 | 3. 修改引用中有关SmartQuant类库的地址,使用你目标OQ中下的dll 26 | 4. 修改.NET框架要使用的版本,QD使用2.0,OQ2使用3.5,OQ3使用4.0 27 | 5. 修改dll生成的目录,具体请参考如何安装。 28 | 6. 调试只能使用附加到进程,建议学习并使用远程调试 29 | 7. 如果插件完全无法加载,请找到对应的log文件,查看日志。 30 | -------------------------------------------------------------------------------- /src/QuantBox.Helper.CTP/CTPAPI.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using QuantBox.OQ.Extensions; 4 | using SmartQuant.FIX; 5 | 6 | #if CTP 7 | using QuantBox.CSharp2CTP; 8 | 9 | namespace QuantBox.Helper.CTP 10 | #elif CTPZQ 11 | using QuantBox.CSharp2CTPZQ; 12 | 13 | namespace QuantBox.Helper.CTPZQ 14 | #endif 15 | { 16 | public sealed class CTPAPI 17 | { 18 | private static readonly CTPAPI instance = new CTPAPI(); 19 | private CTPAPI() 20 | { 21 | } 22 | public static CTPAPI GetInstance() 23 | { 24 | return instance; 25 | } 26 | 27 | 28 | private IntPtr m_pMdApi = IntPtr.Zero; //行情对象指针 29 | private IntPtr m_pTdApi = IntPtr.Zero; //交易对象指针 30 | 31 | public void __RegTdApi(IntPtr pTdApi) 32 | { 33 | m_pTdApi = pTdApi; 34 | } 35 | 36 | public void __RegMdApi(IntPtr pMdApi) 37 | { 38 | m_pMdApi = pMdApi; 39 | } 40 | 41 | #region 合列列表 42 | public Dictionary Instruments { get; private set; } 43 | public void __RegInstrumentDictionary(Dictionary dict) 44 | { 45 | Instruments = dict; 46 | } 47 | 48 | public delegate void RspQryInstrument(CThostFtdcInstrumentField pInstrument); 49 | public event RspQryInstrument OnRspQryInstrument; 50 | public void FireOnRspQryInstrument(CThostFtdcInstrumentField pInstrument) 51 | { 52 | if (null != OnRspQryInstrument) 53 | { 54 | OnRspQryInstrument(pInstrument); 55 | } 56 | } 57 | 58 | public void ReqQryInstrument(string instrument) 59 | { 60 | if (null != Instruments) 61 | { 62 | CThostFtdcInstrumentField value; 63 | if (Instruments.TryGetValue(instrument, out value)) 64 | { 65 | FireOnRspQryInstrument(value); 66 | return; 67 | } 68 | } 69 | 70 | if (!string.IsNullOrEmpty(instrument) 71 | && null != m_pTdApi 72 | && IntPtr.Zero != m_pTdApi) 73 | { 74 | TraderApi.TD_ReqQryInstrument(m_pTdApi, instrument); 75 | } 76 | } 77 | #endregion 78 | 79 | #region 保证金率 80 | #if CTP 81 | public Dictionary MarginRates { get; private set; } 82 | public void __RegInstrumentMarginRateDictionary(Dictionary dict) 83 | { 84 | MarginRates = dict; 85 | } 86 | public void ReqQryInstrumentMarginRate(string instrument, TThostFtdcHedgeFlagType HedgeFlag) 87 | { 88 | if (null != MarginRates) 89 | { 90 | CThostFtdcInstrumentMarginRateField value; 91 | if (MarginRates.TryGetValue(instrument, out value)) 92 | { 93 | FireOnRspQryInstrumentMarginRate(value); 94 | return; 95 | } 96 | } 97 | 98 | if (!string.IsNullOrEmpty(instrument) 99 | && null != m_pTdApi 100 | && IntPtr.Zero != m_pTdApi) 101 | { 102 | TraderApi.TD_ReqQryInstrumentMarginRate(m_pTdApi, instrument, HedgeFlag); 103 | } 104 | } 105 | 106 | public delegate void RspQryInstrumentMarginRate(CThostFtdcInstrumentMarginRateField pInstrumentMarginRate); 107 | public event RspQryInstrumentMarginRate OnRspQryInstrumentMarginRate; 108 | public void FireOnRspQryInstrumentMarginRate(CThostFtdcInstrumentMarginRateField pInstrumentMarginRate) 109 | { 110 | if (null != OnRspQryInstrumentMarginRate) 111 | { 112 | OnRspQryInstrumentMarginRate(pInstrumentMarginRate); 113 | } 114 | } 115 | #endif 116 | #endregion 117 | 118 | #region 手续费率 119 | public Dictionary CommissionRates { get; private set; } 120 | public void __RegInstrumentCommissionRateDictionary(Dictionary dict) 121 | { 122 | CommissionRates = dict; 123 | } 124 | 125 | public void ReqQryInstrumentCommissionRate(string instrument) 126 | { 127 | if (null != CommissionRates) 128 | { 129 | CThostFtdcInstrumentCommissionRateField value; 130 | if (CommissionRates.TryGetValue(instrument, out value)) 131 | { 132 | FireOnRspQryInstrumentCommissionRate(value); 133 | return; 134 | } 135 | } 136 | 137 | if (!string.IsNullOrEmpty(instrument) 138 | && null != m_pTdApi 139 | && IntPtr.Zero != m_pTdApi) 140 | { 141 | TraderApi.TD_ReqQryInstrumentCommissionRate(m_pTdApi, instrument); 142 | } 143 | } 144 | 145 | public delegate void RspQryInstrumentCommissionRate(CThostFtdcInstrumentCommissionRateField pInstrumentCommissionRate); 146 | public event RspQryInstrumentCommissionRate OnRspQryInstrumentCommissionRate; 147 | public void FireOnRspQryInstrumentCommissionRate(CThostFtdcInstrumentCommissionRateField pInstrumentCommissionRate) 148 | { 149 | if (null != OnRspQryInstrumentCommissionRate) 150 | { 151 | OnRspQryInstrumentCommissionRate(pInstrumentCommissionRate); 152 | } 153 | } 154 | #endregion 155 | 156 | #region 深度行情1 157 | public Dictionary DepthMarketDatas { get; private set; } 158 | public void __RegDepthMarketDataDictionary(Dictionary dict) 159 | { 160 | DepthMarketDatas = dict; 161 | } 162 | 163 | public void ReqQryDepthMarketData(string instrument) 164 | { 165 | if (null != DepthMarketDatas) 166 | { 167 | CThostFtdcDepthMarketDataField value; 168 | if (DepthMarketDatas.TryGetValue(instrument, out value)) 169 | { 170 | FireOnRspQryDepthMarketData(value); 171 | return; 172 | } 173 | } 174 | 175 | if (!string.IsNullOrEmpty(instrument) 176 | && null != m_pTdApi 177 | && IntPtr.Zero != m_pTdApi) 178 | { 179 | TraderApi.TD_ReqQryDepthMarketData(m_pTdApi, instrument); 180 | } 181 | } 182 | 183 | public delegate void RspQryDepthMarketData(CThostFtdcDepthMarketDataField pDepthMarketData); 184 | public event RspQryDepthMarketData OnRspQryDepthMarketData; 185 | public void FireOnRspQryDepthMarketData(CThostFtdcDepthMarketDataField pDepthMarketData) 186 | { 187 | if (null != OnRspQryDepthMarketData) 188 | { 189 | OnRspQryDepthMarketData(pDepthMarketData); 190 | } 191 | } 192 | #endregion 193 | 194 | #region 交易所状态 195 | public delegate void RtnInstrumentStatus(CThostFtdcInstrumentStatusField pInstrumentStatus); 196 | public event RtnInstrumentStatus OnRtnInstrumentStatus; 197 | public void FireOnRtnInstrumentStatus(CThostFtdcInstrumentStatusField pInstrumentStatus) 198 | { 199 | if (null != OnRtnInstrumentStatus) 200 | { 201 | OnRtnInstrumentStatus(pInstrumentStatus); 202 | } 203 | } 204 | #endregion 205 | 206 | #region 主动请求资金 207 | public CThostFtdcTradingAccountField TradingAccount { get; private set; } 208 | public void __RegTradingAccount(CThostFtdcTradingAccountField pTradingAccount) 209 | { 210 | TradingAccount = pTradingAccount; 211 | } 212 | 213 | public void ReqQryTradingAccount() 214 | { 215 | if (m_pTdApi == null || m_pTdApi == IntPtr.Zero) 216 | return; 217 | 218 | TraderApi.TD_ReqQryTradingAccount(m_pTdApi); 219 | } 220 | 221 | public delegate void RspQryTradingAccount(CThostFtdcTradingAccountField pTradingAccount); 222 | public event RspQryTradingAccount OnRspQryTradingAccount; 223 | public void FireOnRspQryTradingAccount(CThostFtdcTradingAccountField pTradingAccount) 224 | { 225 | if (null != OnRspQryTradingAccount) 226 | { 227 | OnRspQryTradingAccount(pTradingAccount); 228 | } 229 | } 230 | #endregion 231 | 232 | #region 主动查持仓 233 | public Dictionary InvestorPositions { get; private set; } 234 | public void __RegInvestorPositionDictionary(Dictionary dict) 235 | { 236 | InvestorPositions = dict; 237 | } 238 | public void ReqQryInvestorPosition(string instrument) 239 | { 240 | if (null != m_pTdApi 241 | && IntPtr.Zero != m_pTdApi) 242 | { 243 | TraderApi.TD_ReqQryInvestorPosition(m_pTdApi, instrument); 244 | } 245 | } 246 | 247 | public delegate void RspReqQryInvestorPosition(CThostFtdcInvestorPositionField pInvestorPosition); 248 | public event RspReqQryInvestorPosition OnRspReqQryInvestorPosition; 249 | public void FireOnRspReqQryInvestorPosition(CThostFtdcInvestorPositionField pInvestorPosition) 250 | { 251 | if (null != OnRspReqQryInvestorPosition) 252 | { 253 | OnRspReqQryInvestorPosition(pInvestorPosition); 254 | } 255 | } 256 | #endregion 257 | 258 | #region 询价 259 | public delegate void RtnForQuoteRsp(CThostFtdcForQuoteRspField pForQuoteRsp); 260 | public event RtnForQuoteRsp OnRtnForQuoteRsp; 261 | public void FireOnRtnForQuoteRsp(CThostFtdcForQuoteRspField pForQuoteRsp) 262 | { 263 | if (null != OnRtnForQuoteRsp) 264 | { 265 | OnRtnForQuoteRsp(pForQuoteRsp); 266 | } 267 | } 268 | #endregion 269 | 270 | #region OnStrategyStart 271 | public EventHandler OnLive; 272 | public void EmitOnLive() 273 | { 274 | if (OnLive != null) 275 | OnLive(null, EventArgs.Empty); 276 | } 277 | #endregion 278 | 279 | #region 错误类型转换 280 | public static EnumError FromCTP(int ErrorID) 281 | { 282 | ErrorType e = (ErrorType)ErrorID; 283 | 284 | switch (e) 285 | { 286 | case ErrorType.NONE: 287 | return EnumError.SUCCESS; 288 | case ErrorType.INSUFFICIENT_MONEY: 289 | return EnumError.INSUFFICIENT_MONEY; 290 | case ErrorType.OVER_CLOSE_POSITION: 291 | return EnumError.OVER_CLOSE_POSITION; 292 | case ErrorType.OVER_CLOSETODAY_POSITION: 293 | return EnumError.OVER_CLOSETODAY_POSITION; 294 | case ErrorType.OVER_CLOSEYESTERDAY_POSITION: 295 | return EnumError.OVER_CLOSEYESTERDAY_POSITION; 296 | default: 297 | return EnumError.OTHER; 298 | } 299 | } 300 | #endregion 301 | 302 | #region 开平转换 303 | public static TThostFtdcOffsetFlagType ToCTP(EnumOpenClose offset) 304 | { 305 | switch (offset) 306 | { 307 | case EnumOpenClose.OPEN: 308 | return TThostFtdcOffsetFlagType.Open; 309 | case EnumOpenClose.CLOSE: 310 | return TThostFtdcOffsetFlagType.Close; 311 | case EnumOpenClose.CLOSE_TODAY: 312 | return TThostFtdcOffsetFlagType.CloseToday; 313 | default: 314 | return TThostFtdcOffsetFlagType.Open; 315 | } 316 | } 317 | #endregion 318 | 319 | #region 买卖转换 320 | public static Side FromCTP(TThostFtdcDirectionType Direction) 321 | { 322 | switch (Direction) 323 | { 324 | case TThostFtdcDirectionType.Buy: 325 | return Side.Buy; 326 | case TThostFtdcDirectionType.Sell: 327 | return Side.Sell; 328 | default: 329 | return Side.Undefined; 330 | } 331 | } 332 | #endregion 333 | } 334 | } 335 | -------------------------------------------------------------------------------- /src/QuantBox.Helper.CTP/CTPQuote.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | using SmartQuant.Data; 4 | 5 | #if CTP 6 | using QuantBox.CSharp2CTP; 7 | 8 | namespace QuantBox.Helper.CTP 9 | #elif CTPZQ 10 | using QuantBox.CSharp2CTPZQ; 11 | 12 | namespace QuantBox.Helper.CTPZQ 13 | #endif 14 | { 15 | public class CTPQuote:Quote 16 | { 17 | public CTPQuote():base() 18 | { 19 | } 20 | 21 | public CTPQuote(Quote quote): base(quote) 22 | { 23 | } 24 | 25 | public CTPQuote(DateTime datetime, double bid, int bidSize, double ask, int askSize) 26 | : base(datetime, bid, bidSize, ask, askSize) 27 | { 28 | } 29 | 30 | public CThostFtdcDepthMarketDataField DepthMarketData; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/QuantBox.Helper.CTP/CTPTrade.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | using SmartQuant.Data; 4 | 5 | 6 | #if CTP 7 | using QuantBox.CSharp2CTP; 8 | 9 | namespace QuantBox.Helper.CTP 10 | #elif CTPZQ 11 | using QuantBox.CSharp2CTPZQ; 12 | 13 | namespace QuantBox.Helper.CTPZQ 14 | #endif 15 | { 16 | public class CTPTrade:Trade 17 | { 18 | public CTPTrade():base() 19 | { 20 | } 21 | 22 | public CTPTrade(Trade trade):base(trade) 23 | { 24 | } 25 | 26 | public CTPTrade(DateTime datetime, double price, int size) 27 | : base(datetime, price, size) 28 | { 29 | } 30 | 31 | public CThostFtdcDepthMarketDataField DepthMarketData; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/QuantBox.Helper.CTP/DataConvert.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | 3 | #if OQ 4 | using OpenQuant.API; 5 | #elif QD 6 | using SmartQuant.Data; 7 | #endif 8 | 9 | #if CTP 10 | using QuantBox.CSharp2CTP; 11 | 12 | namespace QuantBox.Helper.CTP 13 | #elif CTPZQ 14 | using QuantBox.CSharp2CTPZQ; 15 | 16 | namespace QuantBox.Helper.CTPZQ 17 | #endif 18 | { 19 | public class DataConvert 20 | { 21 | static FieldInfo tradeField; 22 | static FieldInfo quoteField; 23 | 24 | public static bool TryConvert(Trade trade, ref CThostFtdcDepthMarketDataField DepthMarketData) 25 | { 26 | #if OQ 27 | if (tradeField == null) 28 | { 29 | tradeField = typeof(Trade).GetField("trade", BindingFlags.NonPublic | BindingFlags.Instance); 30 | } 31 | 32 | CTPTrade t = tradeField.GetValue(trade) as CTPTrade; 33 | #elif QD 34 | CTPTrade t = trade as CTPTrade; 35 | #endif 36 | if (null != t) 37 | { 38 | DepthMarketData = t.DepthMarketData; 39 | return true; 40 | } 41 | 42 | return false; 43 | } 44 | 45 | public static bool TryConvert(Quote quote, ref CThostFtdcDepthMarketDataField DepthMarketData) 46 | { 47 | #if OQ 48 | if (quoteField == null) 49 | { 50 | quoteField = typeof(Quote).GetField("quote", BindingFlags.NonPublic | BindingFlags.Instance); 51 | } 52 | 53 | CTPQuote q = quoteField.GetValue(quote) as CTPQuote; 54 | #elif QD 55 | CTPQuote q = quote as CTPQuote; 56 | #endif 57 | if (null != q) 58 | { 59 | DepthMarketData = q.DepthMarketData; 60 | return true; 61 | } 62 | return false; 63 | } 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/QuantBox.Helper.CTP/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // 有关程序集的常规信息通过以下 6 | // 特性集控制。更改这些特性值可修改 7 | // 与程序集关联的信息。 8 | [assembly: AssemblyTitle("QuantBox.Helper.CTP")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("QuantBox.cn")] 12 | [assembly: AssemblyProduct("QuantBox.Helper.CTP")] 13 | [assembly: AssemblyCopyright("Copyright © QuantBox.cn 2012")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // 将 ComVisible 设置为 false 使此程序集中的类型 18 | // 对 COM 组件不可见。如果需要从 COM 访问此程序集中的类型, 19 | // 则将该类型上的 ComVisible 特性设置为 true。 20 | [assembly: ComVisible(false)] 21 | 22 | // 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID 23 | [assembly: Guid("39f42680-fb9b-4dce-9497-b68ca230b2fb")] 24 | 25 | // 程序集的版本信息由下面四个值组成: 26 | // 27 | // 主版本 28 | // 次版本 29 | // 内部版本号 30 | // 修订号 31 | // 32 | // 可以指定所有这些值,也可以使用“内部版本号”和“修订号”的默认值, 33 | // 方法是按如下所示使用“*”: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.1.6.3")] 36 | [assembly: AssemblyFileVersion("1.1.6.3")] 37 | -------------------------------------------------------------------------------- /src/QuantBox.Helper.CTP/QuantBox.Helper.CTP.Net35.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Debug 5 | AnyCPU 6 | 8.0.30703 7 | 2.0 8 | {2C5C5377-E34C-4515-9404-3461AAE70A8A} 9 | Library 10 | Properties 11 | QuantBox.Helper.CTP 12 | QuantBox.Helper.CTP 13 | v3.5 14 | 512 15 | 16 | 17 | 18 | true 19 | full 20 | false 21 | ..\..\..\..\..\..\Program Files %28x86%29\SmartQuant Ltd\QuantDeveloper .NET\bin\ 22 | TRACE;DEBUG;CTP,QD 23 | prompt 24 | 4 25 | 26 | 27 | pdbonly 28 | true 29 | ..\..\bin\ 30 | TRACE;CTP,QD 31 | prompt 32 | 4 33 | 34 | 35 | 36 | False 37 | ..\..\..\..\..\..\Program Files (x86)\SmartQuant Ltd\QuantDeveloper .NET\bin\QuantBox.CSharp2CTP.dll 38 | 39 | 40 | ..\..\..\..\..\..\Program Files (x86)\SmartQuant Ltd\OpenQuant\Bin\QuantBox.OQ.Extensions.dll 41 | 42 | 43 | False 44 | ..\..\..\..\Program Files (x86)\SmartQuant Ltd\QuantDeveloper .NET\bin\SmartQuant.Data.dll 45 | 46 | 47 | False 48 | ..\..\..\..\..\..\Program Files (x86)\SmartQuant Ltd\OpenQuant\Framework\bin\SmartQuant.FIX.dll 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 71 | -------------------------------------------------------------------------------- /src/QuantBox.Helper.CTP/QuantBox.Helper.CTP.Net40.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Debug 5 | AnyCPU 6 | 8.0.30703 7 | 2.0 8 | {97AE93EC-5897-43C8-8D84-D92B73FE1434} 9 | Library 10 | Properties 11 | QuantBox.Helper.CTP 12 | QuantBox.Helper.CTP 13 | v4.0 14 | 512 15 | 16 | 17 | true 18 | full 19 | false 20 | ..\..\..\..\..\..\Program Files %28x86%29\SmartQuant Ltd\OpenQuant\Bin\ 21 | TRACE;DEBUG;CTP,OQ 22 | prompt 23 | 4 24 | 25 | 26 | pdbonly 27 | true 28 | ..\..\bin\ 29 | TRACE;CTP,OQ 30 | prompt 31 | 4 32 | 33 | 34 | 35 | False 36 | ..\..\..\..\..\..\Program Files (x86)\SmartQuant Ltd\OpenQuant\Bin\Newtonsoft.Json.dll 37 | 38 | 39 | False 40 | ..\..\..\..\..\..\Program Files (x86)\SmartQuant Ltd\OpenQuant\Bin\OpenQuant.API.dll 41 | 42 | 43 | False 44 | ..\..\..\..\..\..\Program Files (x86)\SmartQuant Ltd\OpenQuant\Bin\QuantBox.CSharp2CTP.dll 45 | 46 | 47 | False 48 | ..\..\..\..\..\..\Program Files (x86)\SmartQuant Ltd\OpenQuant\Bin\QuantBox.OQ.Extensions.dll 49 | 50 | 51 | False 52 | ..\..\..\..\..\..\Program Files (x86)\SmartQuant Ltd\OpenQuant\Framework\bin\SmartQuant.Data.dll 53 | 54 | 55 | False 56 | ..\..\..\..\..\..\Program Files (x86)\SmartQuant Ltd\OpenQuant\Framework\bin\SmartQuant.FIX.dll 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 79 | -------------------------------------------------------------------------------- /src/QuantBox.Helper.CTP/QuantBox.Helper.CTPZQ.Net35.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Debug 5 | AnyCPU 6 | 8.0.30703 7 | 2.0 8 | {4A6B6C0F-D169-4358-B42F-FAE8743DE897} 9 | Library 10 | Properties 11 | QuantBox.Helper.CTPZQ 12 | QuantBox.Helper.CTPZQ 13 | v3.5 14 | 512 15 | 16 | 17 | 18 | true 19 | full 20 | false 21 | ..\..\..\..\..\..\Program Files %28x86%29\SmartQuant Ltd\OpenQuant\Bin\ 22 | TRACE;DEBUG;CTPZQ,QD 23 | prompt 24 | 4 25 | 26 | 27 | pdbonly 28 | true 29 | ..\..\bin\ 30 | TRACE;CTPZQ,QD 31 | prompt 32 | 4 33 | 34 | 35 | 36 | ..\..\..\..\..\..\Program Files (x86)\SmartQuant Ltd\OpenQuant\Bin\QuantBox.CSharp2CTPZQ.dll 37 | 38 | 39 | False 40 | ..\..\..\..\..\..\Program Files (x86)\SmartQuant Ltd\OpenQuant\Bin\QuantBox.OQ.Extensions.dll 41 | 42 | 43 | False 44 | ..\..\..\..\..\..\Program Files (x86)\SmartQuant Ltd\OpenQuant\Framework\bin\SmartQuant.Data.dll 45 | 46 | 47 | False 48 | ..\..\..\..\..\..\Program Files (x86)\SmartQuant Ltd\OpenQuant\Framework\bin\SmartQuant.FIX.dll 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 71 | -------------------------------------------------------------------------------- /src/QuantBox.Helper.CTP/QuantBox.Helper.CTPZQ.Net40.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Debug 5 | AnyCPU 6 | 8.0.30703 7 | 2.0 8 | {5CAEB588-BA0F-4313-8B78-5101E97D695A} 9 | Library 10 | Properties 11 | QuantBox.Helper.CTPZQ 12 | QuantBox.Helper.CTPZQ 13 | v4.0 14 | 512 15 | 16 | 17 | true 18 | full 19 | false 20 | ..\..\..\..\..\..\Program Files %28x86%29\SmartQuant Ltd\OpenQuant\Bin\ 21 | TRACE;DEBUG;CTPZQ,OQ 22 | prompt 23 | 4 24 | 25 | 26 | pdbonly 27 | true 28 | ..\..\bin\ 29 | TRACE;CTPZQ,OQ 30 | prompt 31 | 4 32 | 33 | 34 | 35 | False 36 | ..\..\..\..\..\..\Program Files (x86)\SmartQuant Ltd\OpenQuant\Bin\OpenQuant.API.dll 37 | 38 | 39 | ..\..\..\..\..\..\Program Files (x86)\SmartQuant Ltd\OpenQuant\Bin\QuantBox.CSharp2CTPZQ.dll 40 | 41 | 42 | False 43 | ..\..\..\..\..\..\Program Files (x86)\SmartQuant Ltd\OpenQuant\Bin\QuantBox.OQ.Extensions.dll 44 | 45 | 46 | False 47 | ..\..\..\..\..\..\Program Files (x86)\SmartQuant Ltd\OpenQuant\Framework\bin\SmartQuant.Data.dll 48 | 49 | 50 | False 51 | ..\..\..\..\..\..\Program Files (x86)\SmartQuant Ltd\OpenQuant\Framework\bin\SmartQuant.FIX.dll 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 74 | -------------------------------------------------------------------------------- /src/QuantBox.OQ.CTP.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 2013 4 | VisualStudioVersion = 12.0.21005.1 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "QuantBox.Helper.CTP.Net40", "QuantBox.Helper.CTP\QuantBox.Helper.CTP.Net40.csproj", "{97AE93EC-5897-43C8-8D84-D92B73FE1434}" 7 | EndProject 8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "QuantBox.OQ.CTP.OQ3", "QuantBox.OQ.CTP\QuantBox.OQ.CTP.OQ3.csproj", "{72BE4BFC-E0F6-436F-8206-C6009932D620}" 9 | EndProject 10 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "QuantBox.Helper.CTPZQ.Net40", "QuantBox.Helper.CTP\QuantBox.Helper.CTPZQ.Net40.csproj", "{5CAEB588-BA0F-4313-8B78-5101E97D695A}" 11 | EndProject 12 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "QuantBox.OQ.CTPZQ.OQ3", "QuantBox.OQ.CTP\QuantBox.OQ.CTPZQ.OQ3.csproj", "{49F99E4A-F8D0-4CB8-84B2-39B4F6AC3576}" 13 | EndProject 14 | Global 15 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 16 | Debug|Any CPU = Debug|Any CPU 17 | Release|Any CPU = Release|Any CPU 18 | EndGlobalSection 19 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 20 | {97AE93EC-5897-43C8-8D84-D92B73FE1434}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 21 | {97AE93EC-5897-43C8-8D84-D92B73FE1434}.Debug|Any CPU.Build.0 = Debug|Any CPU 22 | {97AE93EC-5897-43C8-8D84-D92B73FE1434}.Release|Any CPU.ActiveCfg = Release|Any CPU 23 | {97AE93EC-5897-43C8-8D84-D92B73FE1434}.Release|Any CPU.Build.0 = Release|Any CPU 24 | {72BE4BFC-E0F6-436F-8206-C6009932D620}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 25 | {72BE4BFC-E0F6-436F-8206-C6009932D620}.Debug|Any CPU.Build.0 = Debug|Any CPU 26 | {72BE4BFC-E0F6-436F-8206-C6009932D620}.Release|Any CPU.ActiveCfg = Release|Any CPU 27 | {72BE4BFC-E0F6-436F-8206-C6009932D620}.Release|Any CPU.Build.0 = Release|Any CPU 28 | {5CAEB588-BA0F-4313-8B78-5101E97D695A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 29 | {5CAEB588-BA0F-4313-8B78-5101E97D695A}.Debug|Any CPU.Build.0 = Debug|Any CPU 30 | {5CAEB588-BA0F-4313-8B78-5101E97D695A}.Release|Any CPU.ActiveCfg = Release|Any CPU 31 | {5CAEB588-BA0F-4313-8B78-5101E97D695A}.Release|Any CPU.Build.0 = Release|Any CPU 32 | {49F99E4A-F8D0-4CB8-84B2-39B4F6AC3576}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 33 | {49F99E4A-F8D0-4CB8-84B2-39B4F6AC3576}.Debug|Any CPU.Build.0 = Debug|Any CPU 34 | {49F99E4A-F8D0-4CB8-84B2-39B4F6AC3576}.Release|Any CPU.ActiveCfg = Release|Any CPU 35 | {49F99E4A-F8D0-4CB8-84B2-39B4F6AC3576}.Release|Any CPU.Build.0 = Release|Any CPU 36 | EndGlobalSection 37 | GlobalSection(SolutionProperties) = preSolution 38 | HideSolutionNode = FALSE 39 | EndGlobalSection 40 | EndGlobal 41 | -------------------------------------------------------------------------------- /src/QuantBox.OQ.CTP/APIProvider.CTP.MarketData.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using SmartQuant; 3 | using SmartQuant.Data; 4 | using SmartQuant.Instruments; 5 | using QuantBox.OQ.CTP; 6 | 7 | #if CTP 8 | using QuantBox.CSharp2CTP; 9 | using QuantBox.Helper.CTP; 10 | 11 | namespace QuantBox.OQ.CTP 12 | #elif CTPZQ 13 | using QuantBox.CSharp2CTPZQ; 14 | using QuantBox.Helper.CTPZQ; 15 | 16 | namespace QuantBox.OQ.CTPZQ 17 | #endif 18 | { 19 | partial class APIProvider 20 | { 21 | #region 深度行情回调 22 | private DateTime _dateTime = DateTime.Now; 23 | private void OnRtnDepthMarketData(IntPtr pApi, ref CThostFtdcDepthMarketDataField pDepthMarketData) 24 | { 25 | #if CTP 26 | string symbol = pDepthMarketData.InstrumentID; 27 | #elif CTPZQ 28 | string symbol = GetYahooSymbol(pDepthMarketData.InstrumentID, pDepthMarketData.ExchangeID); 29 | #endif 30 | DataRecord record; 31 | if (!_dictAltSymbol2Instrument.TryGetValue(symbol, out record)) 32 | { 33 | mdlog.Warn("合约{0}不在订阅列表中却收到了数据", symbol); 34 | return; 35 | } 36 | 37 | Instrument instrument = record.Instrument; 38 | 39 | CThostFtdcDepthMarketDataField DepthMarket; 40 | _dictDepthMarketData.TryGetValue(symbol, out DepthMarket); 41 | 42 | //将更新字典的功能提前,因为如果一开始就OnTrade中下单,涨跌停没有更新 43 | _dictDepthMarketData[symbol] = pDepthMarketData; 44 | 45 | if (TimeMode.LocalTime == _TimeMode) 46 | { 47 | //为了生成正确的Bar,使用本地时间 48 | _dateTime = Clock.Now; 49 | } 50 | else 51 | { 52 | //直接按HH:mm:ss来解析,测试过这种方法目前是效率比较高的方法 53 | try 54 | { 55 | // 只有使用交易所行情时才需要处理跨天的问题 56 | #if CTP 57 | ChangeActionDay(pDepthMarketData.ActionDay); 58 | #else 59 | ChangeActionDay(pDepthMarketData.TradingDay); 60 | #endif 61 | 62 | int HH = int.Parse(pDepthMarketData.UpdateTime.Substring(0, 2)); 63 | int mm = int.Parse(pDepthMarketData.UpdateTime.Substring(3, 2)); 64 | int ss = int.Parse(pDepthMarketData.UpdateTime.Substring(6, 2)); 65 | 66 | _dateTime = new DateTime(_yyyy, _MM, _dd, HH, mm, ss, pDepthMarketData.UpdateMillisec); 67 | } 68 | catch (Exception) 69 | { 70 | _dateTime = Clock.Now; 71 | } 72 | } 73 | 74 | if (record.TradeRequested) 75 | { 76 | //通过测试,发现IB的Trade与Quote在行情过来时数量是不同的,在这也做到不同 77 | if (DepthMarket.LastPrice == pDepthMarketData.LastPrice 78 | && DepthMarket.Volume == pDepthMarketData.Volume) 79 | { } 80 | else 81 | { 82 | //行情过来时是今天累计成交量,得转换成每个tick中成交量之差 83 | int volume = pDepthMarketData.Volume - DepthMarket.Volume; 84 | if (0 == DepthMarket.Volume) 85 | { 86 | //没有接收到最开始的一条,所以这计算每个Bar的数据时肯定超大,强行设置为0 87 | volume = 0; 88 | } 89 | else if (volume < 0) 90 | { 91 | //如果隔夜运行,会出现今早成交量0-昨收盘成交量,出现负数,所以当发现为负时要修改 92 | volume = pDepthMarketData.Volume; 93 | } 94 | 95 | // 使用新的类,保存更多信息 96 | CTPTrade trade = new CTPTrade(_dateTime, 97 | pDepthMarketData.LastPrice == double.MaxValue ? 0 : pDepthMarketData.LastPrice, 98 | volume); 99 | 100 | // 记录深度数据 101 | trade.DepthMarketData = pDepthMarketData; 102 | 103 | EmitNewTradeEvent(instrument, trade); 104 | } 105 | } 106 | 107 | if (record.QuoteRequested) 108 | { 109 | //if ( 110 | //DepthMarket.BidVolume1 == pDepthMarketData.BidVolume1 111 | //&& DepthMarket.AskVolume1 == pDepthMarketData.AskVolume1 112 | //&& DepthMarket.BidPrice1 == pDepthMarketData.BidPrice1 113 | //&& DepthMarket.AskPrice1 == pDepthMarketData.AskPrice1 114 | //) 115 | //{ } 116 | //else 117 | { 118 | CTPQuote quote = new CTPQuote(_dateTime, 119 | pDepthMarketData.BidPrice1 == double.MaxValue ? 0 : pDepthMarketData.BidPrice1, 120 | pDepthMarketData.BidVolume1, 121 | pDepthMarketData.AskPrice1 == double.MaxValue ? 0 : pDepthMarketData.AskPrice1, 122 | pDepthMarketData.AskVolume1 123 | ); 124 | 125 | quote.DepthMarketData = pDepthMarketData; 126 | 127 | EmitNewQuoteEvent(instrument, quote); 128 | } 129 | } 130 | 131 | if (record.MarketDepthRequested) 132 | { 133 | bool bAsk = true; 134 | bool bBid = true; 135 | 136 | if (bAsk) 137 | bAsk = EmitNewMarketDepth(instrument, _dateTime, 0, MDSide.Ask, pDepthMarketData.AskPrice1, pDepthMarketData.AskVolume1); 138 | if (bBid) 139 | bBid = EmitNewMarketDepth(instrument, _dateTime, 0, MDSide.Bid, pDepthMarketData.BidPrice1, pDepthMarketData.BidVolume1); 140 | #if CTPZQ 141 | if(bAsk) 142 | bAsk = EmitNewMarketDepth(instrument, _dateTime, 1, MDSide.Ask, pDepthMarketData.AskPrice2, pDepthMarketData.AskVolume2); 143 | if(bBid) 144 | bBid = EmitNewMarketDepth(instrument, _dateTime, 1, MDSide.Bid, pDepthMarketData.BidPrice2, pDepthMarketData.BidVolume2); 145 | 146 | if(bAsk) 147 | bAsk = EmitNewMarketDepth(instrument, _dateTime, 2, MDSide.Ask, pDepthMarketData.AskPrice3, pDepthMarketData.AskVolume3); 148 | if(bBid) 149 | bBid = EmitNewMarketDepth(instrument, _dateTime, 2, MDSide.Bid, pDepthMarketData.BidPrice3, pDepthMarketData.BidVolume3); 150 | 151 | if(bAsk) 152 | bAsk = EmitNewMarketDepth(instrument, _dateTime, 3, MDSide.Ask, pDepthMarketData.AskPrice4, pDepthMarketData.AskVolume4); 153 | if(bBid) 154 | bBid = EmitNewMarketDepth(instrument, _dateTime, 3, MDSide.Bid, pDepthMarketData.BidPrice4, pDepthMarketData.BidVolume4); 155 | 156 | if(bAsk) 157 | bAsk = EmitNewMarketDepth(instrument, _dateTime, 4, MDSide.Ask, pDepthMarketData.AskPrice5, pDepthMarketData.AskVolume5); 158 | if(bBid) 159 | bBid = EmitNewMarketDepth(instrument, _dateTime, 4, MDSide.Bid, pDepthMarketData.BidPrice5, pDepthMarketData.BidVolume5); 160 | #endif 161 | } 162 | } 163 | 164 | public void OnRspQryDepthMarketData(IntPtr pTraderApi, ref CThostFtdcDepthMarketDataField pDepthMarketData, ref CThostFtdcRspInfoField pRspInfo, int nRequestID, bool bIsLast) 165 | { 166 | if (0 == pRspInfo.ErrorID) 167 | { 168 | CThostFtdcDepthMarketDataField DepthMarket; 169 | if (!_dictDepthMarketData.TryGetValue(pDepthMarketData.InstrumentID, out DepthMarket)) 170 | { 171 | //没找到此元素,保存一下 172 | _dictDepthMarketData[pDepthMarketData.InstrumentID] = pDepthMarketData; 173 | } 174 | 175 | tdlog.Info("已经接收查询深度行情 {0}", pDepthMarketData.InstrumentID); 176 | //通知单例 177 | CTPAPI.GetInstance().FireOnRspQryDepthMarketData(pDepthMarketData); 178 | } 179 | else 180 | { 181 | tdlog.Error("nRequestID:{0},ErrorID:{1},OnRspQryDepthMarketData:{2}", nRequestID, pRspInfo.ErrorID, pRspInfo.ErrorMsg); 182 | EmitError(nRequestID, pRspInfo.ErrorID, "OnRspQryDepthMarketData:" + pRspInfo.ErrorMsg); 183 | } 184 | } 185 | #endregion 186 | 187 | 188 | 189 | } 190 | } 191 | -------------------------------------------------------------------------------- /src/QuantBox.OQ.CTP/APIProvider.CTP.Quote.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | using SmartQuant.Execution; 5 | using SmartQuant.FIX; 6 | using SmartQuant.Instruments; 7 | using Newtonsoft.Json; 8 | using QuantBox.OQ.Extensions; 9 | using QuantBox.OQ.Extensions.OrderText; 10 | using QuantBox.OQ.Extensions.Combiner; 11 | using QuantBox.OQ.Extensions.OrderItem; 12 | 13 | #if CTP 14 | using QuantBox.CSharp2CTP; 15 | using QuantBox.Helper.CTP; 16 | 17 | namespace QuantBox.OQ.CTP 18 | #elif CTPZQ 19 | using QuantBox.CSharp2CTPZQ; 20 | using QuantBox.Helper.CTPZQ; 21 | 22 | namespace QuantBox.OQ.CTPZQ 23 | #endif 24 | { 25 | partial class APIProvider 26 | { 27 | #region 询价 28 | private void OnRtnForQuoteRsp(IntPtr pMdUserApi, ref CThostFtdcForQuoteRspField pForQuoteRsp) 29 | { 30 | Console.WriteLine("OnRtnForQuoteRsp"); 31 | // 询价请求 32 | CTPAPI.GetInstance().FireOnRtnForQuoteRsp(pForQuoteRsp); 33 | } 34 | #endregion 35 | 36 | private void OnErrRtnQuoteAction(IntPtr pTraderApi, ref CThostFtdcQuoteActionField pQuoteAction, ref CThostFtdcRspInfoField pRspInfo) 37 | { 38 | Console.WriteLine("OnErrRtnQuoteAction"); 39 | } 40 | 41 | private void OnErrRtnQuoteInsert(IntPtr pTraderApi, ref CThostFtdcInputQuoteField pInputQuote, ref CThostFtdcRspInfoField pRspInfo) 42 | { 43 | Console.WriteLine("OnErrRtnQuoteAction"); 44 | } 45 | 46 | private void OnRspQuoteAction(IntPtr pTraderApi, ref CThostFtdcInputQuoteActionField pInputQuoteAction, ref CThostFtdcRspInfoField pRspInfo, int nRequestID, bool bIsLast) 47 | { 48 | Console.WriteLine("OnRspQuoteAction"); 49 | } 50 | 51 | private void OnRspQuoteInsert(IntPtr pTraderApi, ref CThostFtdcInputQuoteField pInputQuote, ref CThostFtdcRspInfoField pRspInfo, int nRequestID, bool bIsLast) 52 | { 53 | Console.WriteLine("OnRspQuoteInsert"); 54 | } 55 | 56 | private void OnRtnQuote(IntPtr pTraderApi, ref CThostFtdcQuoteField pQuote) 57 | { 58 | Console.WriteLine("OnRtnQuote"); 59 | } 60 | 61 | 62 | #region 发双向报价单 63 | private void Send(QuoteOrderItem item) 64 | { 65 | if (item == null) 66 | return; 67 | 68 | SingleOrder AskOrder = item.Sell.Order; 69 | SingleOrder BidOrder = item.Buy.Order; 70 | 71 | string symbol = item.Buy.Order.Symbol; 72 | 73 | double AskPrice = AskOrder.Price; 74 | double BidPrice = BidOrder.Price; 75 | int AskVolume = (int)AskOrder.OrderQty; 76 | int BidVolume = (int)BidOrder.OrderQty; 77 | 78 | TThostFtdcOffsetFlagType AskOffsetFlag = CTPAPI.ToCTP(item.Sell.OpenClose); 79 | TThostFtdcOffsetFlagType BidOffsetFlag = CTPAPI.ToCTP(item.Buy.OpenClose); 80 | 81 | TThostFtdcHedgeFlagType AskHedgeFlag = HedgeFlagType; 82 | TThostFtdcHedgeFlagType BidHedgeFlag = HedgeFlagType; 83 | 84 | int nRet = 0; 85 | #if CTP 86 | nRet = TraderApi.TD_SendQuote(m_pTdApi, 87 | -1, 88 | symbol, 89 | AskPrice, 90 | BidPrice, 91 | AskVolume, 92 | BidVolume, 93 | AskOffsetFlag, 94 | BidOffsetFlag, 95 | AskHedgeFlag, 96 | BidHedgeFlag); 97 | #endif 98 | if (nRet > 0) 99 | { 100 | orderMap.CreateNewOrder(string.Format("{0}:{1}:{2}", _RspUserLogin.FrontID, _RspUserLogin.SessionID, nRet), item); 101 | } 102 | } 103 | #endregion 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /src/QuantBox.OQ.CTP/APIProvider.CTP.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Linq; 5 | using System.Threading; 6 | using System.Windows.Forms; 7 | using SmartQuant; 8 | using SmartQuant.Data; 9 | using SmartQuant.Execution; 10 | using SmartQuant.FIX; 11 | using SmartQuant.Instruments; 12 | using SmartQuant.Providers; 13 | using QuantBox.OQ.CTP; 14 | 15 | using QuantBox.OQ.Extensions.Combiner; 16 | using QuantBox.OQ.Extensions.OrderItem; 17 | 18 | #if CTP 19 | using QuantBox.CSharp2CTP; 20 | using QuantBox.Helper.CTP; 21 | 22 | namespace QuantBox.OQ.CTP 23 | #elif CTPZQ 24 | using QuantBox.CSharp2CTPZQ; 25 | using QuantBox.Helper.CTPZQ; 26 | 27 | namespace QuantBox.OQ.CTPZQ 28 | #endif 29 | { 30 | partial class APIProvider 31 | { 32 | private fnOnConnect _fnOnConnect_Holder; 33 | private fnOnDisconnect _fnOnDisconnect_Holder; 34 | private fnOnErrRtnOrderAction _fnOnErrRtnOrderAction_Holder; 35 | private fnOnErrRtnOrderInsert _fnOnErrRtnOrderInsert_Holder; 36 | private fnOnRspError _fnOnRspError_Holder; 37 | private fnOnRspOrderAction _fnOnRspOrderAction_Holder; 38 | private fnOnRspOrderInsert _fnOnRspOrderInsert_Holder; 39 | private fnOnRspQryDepthMarketData _fnOnRspQryDepthMarketData_Holder; 40 | private fnOnRspQryInstrument _fnOnRspQryInstrument_Holder; 41 | private fnOnRspQryInstrumentCommissionRate _fnOnRspQryInstrumentCommissionRate_Holder; 42 | private fnOnRspQryInvestorPosition _fnOnRspQryInvestorPosition_Holder; 43 | private fnOnRspQryTradingAccount _fnOnRspQryTradingAccount_Holder; 44 | private fnOnRtnDepthMarketData _fnOnRtnDepthMarketData_Holder; 45 | private fnOnRtnForQuoteRsp _fnOnRtnForQuoteRsp_Holder; 46 | private fnOnRtnInstrumentStatus _fnOnRtnInstrumentStatus_Holder; 47 | private fnOnRtnOrder _fnOnRtnOrder_Holder; 48 | private fnOnRtnTrade _fnOnRtnTrade_Holder; 49 | 50 | #if CTP 51 | private fnOnRspQryInstrumentMarginRate _fnOnRspQryInstrumentMarginRate_Holder; 52 | #endif 53 | private fnOnErrRtnQuoteAction _fnOnErrRtnQuoteAction_Holder; 54 | private fnOnErrRtnQuoteInsert _fnOnErrRtnQuoteInsert_Holder; 55 | private fnOnRspQuoteAction _fnOnRspQuoteAction_Holder; 56 | private fnOnRspQuoteInsert _fnOnRspQuoteInsert_Holder; 57 | private fnOnRtnQuote _fnOnRtnQuote_Holder; 58 | 59 | #region 回调 60 | private void InitCallbacks() 61 | { 62 | //由于回调函数可能被GC回收,所以用成员变量将回调函数保存下来 63 | _fnOnConnect_Holder = OnConnect; 64 | _fnOnDisconnect_Holder = OnDisconnect; 65 | _fnOnErrRtnOrderAction_Holder = OnErrRtnOrderAction; 66 | _fnOnErrRtnOrderInsert_Holder = OnErrRtnOrderInsert; 67 | _fnOnRspError_Holder = OnRspError; 68 | _fnOnRspOrderAction_Holder = OnRspOrderAction; 69 | _fnOnRspOrderInsert_Holder = OnRspOrderInsert; 70 | _fnOnRspQryDepthMarketData_Holder = OnRspQryDepthMarketData; 71 | _fnOnRspQryInstrument_Holder = OnRspQryInstrument; 72 | _fnOnRspQryInstrumentCommissionRate_Holder = OnRspQryInstrumentCommissionRate; 73 | _fnOnRspQryInvestorPosition_Holder = OnRspQryInvestorPosition; 74 | _fnOnRspQryTradingAccount_Holder = OnRspQryTradingAccount; 75 | _fnOnRtnInstrumentStatus_Holder = OnRtnInstrumentStatus; 76 | _fnOnRtnDepthMarketData_Holder = OnRtnDepthMarketData; 77 | _fnOnRtnOrder_Holder = OnRtnOrder; 78 | _fnOnRtnTrade_Holder = OnRtnTrade; 79 | 80 | #if CTP 81 | _fnOnRspQryInstrumentMarginRate_Holder = OnRspQryInstrumentMarginRate; 82 | #endif 83 | 84 | _fnOnRtnForQuoteRsp_Holder = OnRtnForQuoteRsp; 85 | _fnOnErrRtnQuoteAction_Holder = OnErrRtnQuoteAction; 86 | _fnOnErrRtnQuoteInsert_Holder = OnErrRtnQuoteInsert; 87 | _fnOnRspQuoteAction_Holder = OnRspQuoteAction; 88 | _fnOnRspQuoteInsert_Holder = OnRspQuoteInsert; 89 | _fnOnRtnQuote_Holder = OnRtnQuote; 90 | } 91 | #endregion 92 | 93 | private IntPtr m_pMsgQueue = IntPtr.Zero; //消息队列指针 94 | private IntPtr m_pMdApi = IntPtr.Zero; //行情对象指针 95 | private IntPtr m_pTdApi = IntPtr.Zero; //交易对象指针 96 | 97 | //行情有效状态,约定连接上并通过认证为有效 98 | private volatile bool _bMdConnected; 99 | //交易有效状态,约定连接上,通过认证并进行结算单确认为有效 100 | private volatile bool _bTdConnected; 101 | 102 | //表示用户操作,也许有需求是用户有多个行情,只连接第一个等 103 | private bool _bWantMdConnect; 104 | private bool _bWantTdConnect; 105 | 106 | private readonly object _lockMd = new object(); 107 | private readonly object _lockTd = new object(); 108 | private readonly object _lockMsgQueue = new object(); 109 | 110 | //记录交易登录成功后的SessionID、FrontID等信息 111 | private CThostFtdcRspUserLoginField _RspUserLogin; 112 | 113 | // 报单信息维护 114 | private readonly OrderMap orderMap = new OrderMap(); 115 | 116 | //记录账号的实际持仓,保证以最低成本选择开平 117 | private readonly Dictionary _dictPositions = new Dictionary(); 118 | //记录合约实际行情,用于向界面通知行情用,这里应当记录AltSymbol 119 | private readonly Dictionary _dictDepthMarketData = new Dictionary(); 120 | //记录合约列表,从实盘合约名到对象的映射 121 | private readonly Dictionary _dictInstruments = new Dictionary(); 122 | private Dictionary _dictInstruments2 = new Dictionary(); 123 | //记录手续费率,从实盘合约名到对象的映射 124 | private readonly Dictionary _dictCommissionRate = new Dictionary(); 125 | //记录保证金率,从实盘合约名到对象的映射 126 | private readonly Dictionary _dictMarginRate = new Dictionary(); 127 | //记录 128 | private readonly Dictionary _dictAltSymbol2Instrument = new Dictionary(); 129 | 130 | //用于行情的时间,只在登录时改动,所以要求开盘时能得到更新 131 | private int _yyyy; 132 | private int _MM; 133 | private int _dd; 134 | 135 | private ServerItem server; 136 | private AccountItem account; 137 | 138 | #region 合约列表 139 | private void OnRspQryInstrument(IntPtr pTraderApi, ref CThostFtdcInstrumentField pInstrument, ref CThostFtdcRspInfoField pRspInfo, int nRequestID, bool bIsLast) 140 | { 141 | if (0 == pRspInfo.ErrorID) 142 | { 143 | #if CTP 144 | _dictInstruments[pInstrument.InstrumentID] = pInstrument; 145 | #else 146 | //比较无语,测试平台上会显示很多无效数据,有关期货的还会把正确的数据给覆盖,所以临时这样处理 147 | if (pInstrument.ProductClass != TThostFtdcProductClassType.Futures) 148 | { 149 | string symbol = GetYahooSymbol(pInstrument.InstrumentID, pInstrument.ExchangeID); 150 | _dictInstruments[symbol] = pInstrument; 151 | 152 | // 行情中可能没有交易所信息,这个容器用于容错处理 153 | _dictInstruments2[pInstrument.InstrumentID] = symbol; 154 | } 155 | #endif 156 | 157 | if (bIsLast) 158 | { 159 | tdlog.Info("合约列表已经接收完成,共{0}条", _dictInstruments.Count); 160 | } 161 | } 162 | else 163 | { 164 | tdlog.Error("nRequestID:{0},ErrorID:{1},OnRspQryInstrument:{2}", nRequestID, pRspInfo.ErrorID, pRspInfo.ErrorMsg); 165 | EmitError(nRequestID, pRspInfo.ErrorID, "OnRspQryInstrument:" + pRspInfo.ErrorMsg); 166 | } 167 | } 168 | #endregion 169 | 170 | #region 手续费列表 171 | private void OnRspQryInstrumentCommissionRate(IntPtr pTraderApi, ref CThostFtdcInstrumentCommissionRateField pInstrumentCommissionRate, ref CThostFtdcRspInfoField pRspInfo, int nRequestID, bool bIsLast) 172 | { 173 | if (0 == pRspInfo.ErrorID) 174 | { 175 | _dictCommissionRate[pInstrumentCommissionRate.InstrumentID] = pInstrumentCommissionRate; 176 | tdlog.Info("已经接收手续费率 {0}", pInstrumentCommissionRate.InstrumentID); 177 | 178 | //通知单例 179 | CTPAPI.GetInstance().FireOnRspQryInstrumentCommissionRate(pInstrumentCommissionRate); 180 | } 181 | else 182 | { 183 | tdlog.Error("nRequestID:{0},ErrorID:{1},OnRspQryInstrumentCommissionRate:{2}", nRequestID, pRspInfo.ErrorID, pRspInfo.ErrorMsg); 184 | EmitError(nRequestID, pRspInfo.ErrorID, "OnRspQryInstrumentCommissionRate:" + pRspInfo.ErrorMsg); 185 | } 186 | } 187 | #endregion 188 | 189 | #region 保证金率列表 190 | #if CTP 191 | private void OnRspQryInstrumentMarginRate(IntPtr pTraderApi, ref CThostFtdcInstrumentMarginRateField pInstrumentMarginRate, ref CThostFtdcRspInfoField pRspInfo, int nRequestID, bool bIsLast) 192 | { 193 | if (0 == pRspInfo.ErrorID) 194 | { 195 | _dictMarginRate[pInstrumentMarginRate.InstrumentID] = pInstrumentMarginRate; 196 | tdlog.Info("已经接收保证金率 {0}", pInstrumentMarginRate.InstrumentID); 197 | 198 | //通知单例 199 | CTPAPI.GetInstance().FireOnRspQryInstrumentMarginRate(pInstrumentMarginRate); 200 | } 201 | else 202 | { 203 | tdlog.Error("nRequestID:{0},ErrorID:{1},OnRspQryInstrumentMarginRate:{2}", nRequestID, pRspInfo.ErrorID, pRspInfo.ErrorMsg); 204 | EmitError(nRequestID, pRspInfo.ErrorID, "OnRspQryInstrumentMarginRate:" + pRspInfo.ErrorMsg); 205 | } 206 | } 207 | #endif 208 | #endregion 209 | 210 | #region 持仓回报 211 | private string GetPositionKey(string InstrumentID, 212 | TThostFtdcPosiDirectionType PosiDirection, 213 | TThostFtdcHedgeFlagType HedgeFlag, 214 | TThostFtdcPositionDateType PositionDate) 215 | { 216 | return string.Format("{0}:{1}:{2}:{3}", InstrumentID, PosiDirection, HedgeFlag, PositionDate); 217 | } 218 | 219 | private string GetPositionKey(CThostFtdcInvestorPositionField p) 220 | { 221 | return GetPositionKey(p.InstrumentID, p.PosiDirection, p.HedgeFlag, p.PositionDate); 222 | } 223 | 224 | private void OnRspQryInvestorPosition(IntPtr pTraderApi, ref CThostFtdcInvestorPositionField pInvestorPosition, ref CThostFtdcRspInfoField pRspInfo, int nRequestID, bool bIsLast) 225 | { 226 | if (0 == pRspInfo.ErrorID) 227 | { 228 | string key = GetPositionKey(pInvestorPosition); 229 | _dictPositions[key] = pInvestorPosition; 230 | CTPAPI.GetInstance().FireOnRspReqQryInvestorPosition(pInvestorPosition); 231 | 232 | timerPonstion.Enabled = false; 233 | timerPonstion.Enabled = true; 234 | } 235 | else 236 | { 237 | tdlog.Error("nRequestID:{0},ErrorID:{1},OnRspQryInvestorPosition:{2}", nRequestID, pRspInfo.ErrorID, pRspInfo.ErrorMsg); 238 | EmitError(nRequestID, pRspInfo.ErrorID, "OnRspQryInvestorPosition:" + pRspInfo.ErrorMsg); 239 | } 240 | } 241 | #endregion 242 | 243 | #region 资金回报 244 | CThostFtdcTradingAccountField m_TradingAccount; 245 | private void OnRspQryTradingAccount(IntPtr pTraderApi, ref CThostFtdcTradingAccountField pTradingAccount, ref CThostFtdcRspInfoField pRspInfo, int nRequestID, bool bIsLastt) 246 | { 247 | if (0 == pRspInfo.ErrorID) 248 | { 249 | m_TradingAccount = pTradingAccount; 250 | 251 | //有资金信息过来了,重新计时 252 | timerAccount.Enabled = false; 253 | timerAccount.Enabled = true; 254 | 255 | //通知单例,还是使用GetBrokerInfo来取呢? 256 | CTPAPI.GetInstance().__RegTradingAccount(m_TradingAccount); 257 | CTPAPI.GetInstance().FireOnRspQryTradingAccount(pTradingAccount); 258 | } 259 | else 260 | { 261 | tdlog.Error("nRequestID:{0},ErrorID:{1},OnRspQryTradingAccount:{2}", nRequestID, pRspInfo.ErrorID, pRspInfo.ErrorMsg); 262 | EmitError(nRequestID, pRspInfo.ErrorID, "OnRspQryTradingAccount:" + pRspInfo.ErrorMsg); 263 | } 264 | } 265 | #endregion 266 | 267 | #region 错误回调 268 | private void OnRspError(IntPtr pApi, ref CThostFtdcRspInfoField pRspInfo, int nRequestID, bool bIsLast) 269 | { 270 | tdlog.Error("nRequestID:{0},ErrorID:{1},OnRspError:{2}", nRequestID, pRspInfo.ErrorID, pRspInfo.ErrorMsg); 271 | EmitError(nRequestID, pRspInfo.ErrorID, pRspInfo.ErrorMsg); 272 | } 273 | #endregion 274 | 275 | #region 交易所状态 276 | private void OnRtnInstrumentStatus(IntPtr pTraderApi, ref CThostFtdcInstrumentStatusField pInstrumentStatus) 277 | { 278 | tdlog.Info("{0},{1},{2},{3},{4},{5},{6},{7}", 279 | pInstrumentStatus.ExchangeID, pInstrumentStatus.InstrumentID, 280 | pInstrumentStatus.InstrumentStatus, pInstrumentStatus.EnterReason, 281 | pInstrumentStatus.EnterTime,pInstrumentStatus.TradingSegmentSN, 282 | pInstrumentStatus.ExchangeInstID,pInstrumentStatus.SettlementGroupID); 283 | 284 | //通知单例 285 | CTPAPI.GetInstance().FireOnRtnInstrumentStatus(pInstrumentStatus); 286 | 287 | // 到IF的交割日,是否会收到两个有关IF的记录?如果在此进行清理是否会有问题? 288 | // 只会收到一条 289 | // 遍历是否过期 290 | if (pInstrumentStatus.InstrumentStatus == TThostFtdcInstrumentStatusType.Closed) 291 | { 292 | Dictionary tmp = new Dictionary(); 293 | foreach (var pair in orderMap.OrderItem_OrderField) 294 | { 295 | if(pair.Value.ExchangeID == pInstrumentStatus.ExchangeID) 296 | { 297 | int cnt = pair.Key.GetLegNum(); 298 | foreach(var pair2 in orderMap.Order_OrderItem) 299 | { 300 | // 得找到OpenQuant层的单子 301 | if(pair.Key == pair2.Value) 302 | { 303 | --cnt; 304 | EmitExpired(pair2.Key); 305 | if (cnt <= 0) 306 | break; 307 | } 308 | } 309 | tmp[pair.Key] = pair.Value; 310 | } 311 | } 312 | 313 | foreach (var pair in tmp) 314 | { 315 | OnLastStatus(pair.Key, pair.Value.OrderSysID, pair.Value.OrderRef); 316 | } 317 | tmp.Clear(); 318 | } 319 | } 320 | #endregion 321 | } 322 | } 323 | -------------------------------------------------------------------------------- /src/QuantBox.OQ.CTP/APIProvider.ExecutionProvider.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Data; 4 | using SmartQuant; 5 | using SmartQuant.Execution; 6 | using SmartQuant.FIX; 7 | using SmartQuant.Providers; 8 | using System.Reflection; 9 | using QuantBox.OQ.CTP; 10 | 11 | #if CTP 12 | using QuantBox.CSharp2CTP; 13 | using QuantBox.Helper.CTP; 14 | 15 | namespace QuantBox.OQ.CTP 16 | #elif CTPZQ 17 | using QuantBox.CSharp2CTPZQ; 18 | using QuantBox.Helper.CTPZQ; 19 | 20 | namespace QuantBox.OQ.CTPZQ 21 | #endif 22 | { 23 | public partial class APIProvider : IExecutionProvider 24 | { 25 | private readonly Dictionary orderRecords = new Dictionary(); 26 | 27 | public event ExecutionReportEventHandler ExecutionReport; 28 | public event OrderCancelRejectEventHandler OrderCancelReject; 29 | 30 | public BrokerInfo GetBrokerInfo() 31 | { 32 | BrokerInfo brokerInfo = new BrokerInfo(); 33 | 34 | if (IsConnected) 35 | { 36 | if (!_bTdConnected || string.IsNullOrEmpty(m_TradingAccount.AccountID)) 37 | { 38 | return brokerInfo; 39 | } 40 | 41 | BrokerAccount brokerAccount = new BrokerAccount(m_TradingAccount.AccountID) { BuyingPower = m_TradingAccount.Available }; 42 | 43 | Type t = typeof(CThostFtdcTradingAccountField); 44 | FieldInfo[] fields = t.GetFields(BindingFlags.Public | BindingFlags.Instance); 45 | foreach (FieldInfo field in fields) 46 | { 47 | brokerAccount.AddField(field.Name, field.GetValue(m_TradingAccount).ToString()); 48 | } 49 | 50 | foreach (CThostFtdcInvestorPositionField pos in _dictPositions.Values) 51 | { 52 | BrokerPosition brokerPosition = new BrokerPosition 53 | { 54 | Symbol = pos.InstrumentID 55 | }; 56 | 57 | if (TThostFtdcPosiDirectionType.Long == pos.PosiDirection) 58 | { 59 | brokerPosition.LongQty = pos.Position; 60 | } 61 | else if (TThostFtdcPosiDirectionType.Short == pos.PosiDirection) 62 | { 63 | brokerPosition.ShortQty = pos.Position; 64 | } 65 | 66 | brokerPosition.Qty = brokerPosition.LongQty - brokerPosition.ShortQty; 67 | 68 | Type t2 = typeof(CThostFtdcInvestorPositionField); 69 | FieldInfo[] fields2 = t2.GetFields(BindingFlags.Public | BindingFlags.Instance); 70 | foreach (FieldInfo field in fields2) 71 | { 72 | brokerPosition.AddCustomField(field.Name, field.GetValue(pos).ToString()); 73 | } 74 | brokerAccount.AddPosition(brokerPosition); 75 | } 76 | brokerInfo.Accounts.Add(brokerAccount); 77 | } 78 | 79 | return brokerInfo; 80 | } 81 | 82 | public void SendNewOrderSingle(NewOrderSingle order) 83 | { 84 | SingleOrder key = order as SingleOrder; 85 | orderRecords.Add(key, new OrderRecord(key)); 86 | Send(key); 87 | } 88 | 89 | #region QuantDeveloper下的接口 90 | public void SendOrderCancelReplaceRequest(FIXOrderCancelReplaceRequest request) 91 | { 92 | //IOrder order = OrderManager.Orders.All[request.OrigClOrdID]; 93 | //SingleOrder order2 = order as SingleOrder; 94 | //this.provider.CallReplace(order2); 95 | EmitError(-1,-1,"不支持改单指令"); 96 | tdlog.Error("不支持改单指令"); 97 | } 98 | 99 | public void SendOrderCancelRequest(FIXOrderCancelRequest request) 100 | { 101 | IOrder order = OrderManager.Orders.All[request.OrigClOrdID]; 102 | SingleOrder order2 = order as SingleOrder; 103 | Cancel(order2); 104 | } 105 | 106 | public void SendOrderStatusRequest(FIXOrderStatusRequest request) 107 | { 108 | throw new NotImplementedException(); 109 | } 110 | #endregion 111 | 112 | private void EmitExecutionReport(ExecutionReport report) 113 | { 114 | if (ExecutionReport != null) 115 | { 116 | ExecutionReport(this, new ExecutionReportEventArgs(report)); 117 | } 118 | } 119 | 120 | private void EmitOrderCancelReject(OrderCancelReject reject) 121 | { 122 | if (OrderCancelReject != null) 123 | { 124 | OrderCancelReject(this, new OrderCancelRejectEventArgs(reject)); 125 | } 126 | } 127 | 128 | public void EmitExecutionReport(SingleOrder order, OrdStatus status) 129 | { 130 | EmitExecutionReport(order, status, ""); 131 | } 132 | 133 | public void EmitExecutionReport(SingleOrder order, OrdStatus status, string text) 134 | { 135 | OrderRecord record = orderRecords[order]; 136 | EmitExecutionReport(record, status, 0.0, 0, text, CommType.Absolute, 0); 137 | } 138 | 139 | public void EmitExecutionReport(SingleOrder order, double price, int quantity) 140 | { 141 | OrderRecord record = orderRecords[order]; 142 | EmitExecutionReport(record, OrdStatus.Undefined, price, quantity, "", CommType.Absolute, 0); 143 | } 144 | 145 | public void EmitExecutionReport(SingleOrder order, double price, int quantity, CommType commType, double commission) 146 | { 147 | OrderRecord record = orderRecords[order]; 148 | EmitExecutionReport(record, OrdStatus.Undefined, price, quantity, "", commType, commission); 149 | } 150 | 151 | private void EmitExecutionReport(OrderRecord record, OrdStatus ordStatus, double lastPx, int lastQty, string text, CommType commType, double commission) 152 | { 153 | ExecutionReport report = new ExecutionReport 154 | { 155 | TransactTime = Clock.Now, 156 | ClOrdID = record.Order.ClOrdID, 157 | OrigClOrdID = record.Order.ClOrdID, 158 | OrderID = record.Order.OrderID, 159 | Symbol = record.Order.Symbol, 160 | SecurityType = record.Order.SecurityType, 161 | SecurityExchange = record.Order.SecurityExchange, 162 | Currency = record.Order.Currency, 163 | CommType = commType, 164 | Commission = commission, 165 | Side = record.Order.Side, 166 | 167 | OrdType = record.Order.OrdType, 168 | TimeInForce = record.Order.TimeInForce, 169 | OrderQty = record.Order.OrderQty, 170 | Price = record.Order.Price, 171 | StopPx = record.Order.StopPx, 172 | LastPx = lastPx, 173 | LastQty = lastQty 174 | }; 175 | 176 | if (ordStatus == OrdStatus.Replaced) 177 | { 178 | report.OrdType = record.Order.ReplaceOrder.ContainsField(EFIXField.OrdType) ? record.Order.ReplaceOrder.OrdType : record.Order.OrdType; 179 | report.TimeInForce = record.Order.ReplaceOrder.ContainsField(EFIXField.TimeInForce) ? record.Order.ReplaceOrder.TimeInForce : record.Order.TimeInForce; 180 | report.OrderQty = record.Order.ReplaceOrder.ContainsField(EFIXField.OrderQty) ? record.Order.ReplaceOrder.OrderQty : record.Order.OrderQty; 181 | report.Price = record.Order.ReplaceOrder.ContainsField(EFIXField.Price) ? record.Order.ReplaceOrder.Price : record.Order.Price; 182 | report.StopPx = record.Order.ReplaceOrder.ContainsField(EFIXField.StopPx) ? record.Order.ReplaceOrder.StopPx : record.Order.StopPx; 183 | record.LeavesQty = ((int)report.OrderQty) - record.CumQty; 184 | } 185 | else 186 | { 187 | report.OrdType = record.Order.OrdType; 188 | report.TimeInForce = record.Order.TimeInForce; 189 | report.OrderQty = record.Order.OrderQty; 190 | report.Price = record.Order.Price; 191 | report.StopPx = record.Order.StopPx; 192 | } 193 | 194 | 195 | if (ordStatus == OrdStatus.Undefined) 196 | { 197 | record.AddFill(lastPx, lastQty); 198 | if (record.LeavesQty > 0) 199 | { 200 | ordStatus = OrdStatus.PartiallyFilled; 201 | } 202 | else 203 | { 204 | ordStatus = OrdStatus.Filled; 205 | } 206 | } 207 | report.AvgPx = record.AvgPx; 208 | report.CumQty = record.CumQty; 209 | report.LeavesQty = record.LeavesQty; 210 | report.ExecType = GetExecType(ordStatus); 211 | report.OrdStatus = ordStatus; 212 | report.Text = text; 213 | 214 | EmitExecutionReport(report); 215 | } 216 | 217 | protected void EmitAccepted(SingleOrder order) 218 | { 219 | EmitExecutionReport(order, OrdStatus.New); 220 | } 221 | 222 | protected void EmitCancelled(SingleOrder order) 223 | { 224 | EmitExecutionReport(order, OrdStatus.Cancelled); 225 | } 226 | 227 | protected void EmitExpired(SingleOrder order) 228 | { 229 | EmitExecutionReport(order, OrdStatus.Expired); 230 | } 231 | 232 | protected void EmitPendingCancel(SingleOrder order) 233 | { 234 | EmitExecutionReport(order, OrdStatus.PendingCancel); 235 | } 236 | 237 | protected void EmitCancelReject(SingleOrder order, OrdStatus status, string message) 238 | { 239 | OrderCancelReject reject = new OrderCancelReject 240 | { 241 | TransactTime = Clock.Now, 242 | ClOrdID = order.ClOrdID, 243 | OrigClOrdID = order.ClOrdID, 244 | OrderID = order.OrderID, 245 | 246 | CxlRejReason = CxlRejReason.BrokerOption, 247 | CxlRejResponseTo = CxlRejResponseTo.CancelRequest, 248 | OrdStatus = status 249 | }; 250 | 251 | EmitOrderCancelReject(reject); 252 | } 253 | 254 | protected void EmitFilled(SingleOrder order, double price, int quantity, CommType commType, double commission) 255 | { 256 | EmitExecutionReport(order, price, quantity,commType,commission); 257 | } 258 | 259 | protected void EmitRejected(SingleOrder order, string message) 260 | { 261 | EmitExecutionReport(order, OrdStatus.Rejected, message); 262 | } 263 | 264 | private static ExecType GetExecType(OrdStatus status) 265 | { 266 | switch (status) 267 | { 268 | case OrdStatus.New: 269 | return ExecType.New; 270 | case OrdStatus.PartiallyFilled: 271 | return ExecType.PartialFill; 272 | case OrdStatus.Filled: 273 | return ExecType.Fill; 274 | case OrdStatus.Cancelled: 275 | return ExecType.Cancelled; 276 | case OrdStatus.Replaced: 277 | return ExecType.Replace; 278 | case OrdStatus.PendingCancel: 279 | return ExecType.PendingCancel; 280 | case OrdStatus.Rejected: 281 | return ExecType.Rejected; 282 | case OrdStatus.PendingReplace: 283 | return ExecType.PendingReplace; 284 | case OrdStatus.Expired: 285 | return ExecType.Expired; 286 | } 287 | throw new ArgumentException(string.Format("Cannot find exec type for ord status - {0}", status)); 288 | } 289 | 290 | #region OpenQuant3接口中的新方法 291 | public void RegisterOrder(NewOrderSingle order) 292 | { 293 | tdlog.Info("RegisterOrder"); 294 | } 295 | #endregion 296 | 297 | #if OQ 298 | public void SendOrderCancelReplaceRequest(OrderCancelReplaceRequest request) 299 | { 300 | SendOrderCancelReplaceRequest(request as FIXOrderCancelReplaceRequest); 301 | } 302 | 303 | public void SendOrderCancelRequest(OrderCancelRequest request) 304 | { 305 | SendOrderCancelRequest(request as FIXOrderCancelRequest); 306 | } 307 | 308 | public void SendOrderStatusRequest(OrderStatusRequest request) 309 | { 310 | SendOrderStatusRequest(request as FIXOrderStatusRequest); 311 | } 312 | #endif 313 | } 314 | } 315 | -------------------------------------------------------------------------------- /src/QuantBox.OQ.CTP/APIProvider.InstrumentProvider.cs: -------------------------------------------------------------------------------- 1 | using SmartQuant.FIX; 2 | using SmartQuant.Providers; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Globalization; 6 | using System.Text.RegularExpressions; 7 | 8 | #if CTP 9 | using QuantBox.CSharp2CTP; 10 | using QuantBox.Helper.CTP; 11 | 12 | namespace QuantBox.OQ.CTP 13 | #elif CTPZQ 14 | using QuantBox.CSharp2CTPZQ; 15 | using QuantBox.Helper.CTPZQ; 16 | 17 | namespace QuantBox.OQ.CTPZQ 18 | #endif 19 | { 20 | public partial class APIProvider : IInstrumentProvider 21 | { 22 | public event SecurityDefinitionEventHandler SecurityDefinition; 23 | 24 | public void SendSecurityDefinitionRequest(FIXSecurityDefinitionRequest request) 25 | { 26 | lock (this) 27 | { 28 | if (!_bTdConnected) 29 | { 30 | EmitError(-1, -1, "交易没有连接,无法获取合约列表"); 31 | tdlog.Error("交易没有连接,无法获取合约列表"); 32 | return; 33 | } 34 | 35 | string symbol = request.ContainsField(EFIXField.Symbol) ? request.Symbol : null; 36 | string securityType = request.ContainsField(EFIXField.SecurityType) ? request.SecurityType : null; 37 | string securityExchange = request.ContainsField(EFIXField.SecurityExchange) ? request.SecurityExchange : null; 38 | 39 | #region 过滤 40 | List list = new List(); 41 | foreach (CThostFtdcInstrumentField inst in _dictInstruments.Values) 42 | { 43 | int flag = 0; 44 | if (null == symbol) 45 | { 46 | ++flag; 47 | } 48 | else if (inst.InstrumentID.ToUpper().StartsWith(symbol.ToUpper())) 49 | { 50 | ++flag; 51 | } 52 | 53 | if (null == securityExchange) 54 | { 55 | ++flag; 56 | } 57 | else if (inst.ExchangeID.ToUpper().StartsWith(securityExchange.ToUpper())) 58 | { 59 | ++flag; 60 | } 61 | 62 | if (null == securityType) 63 | { 64 | ++flag; 65 | } 66 | else 67 | { 68 | if (securityType == GetSecurityType(inst)) 69 | { 70 | ++flag; 71 | } 72 | } 73 | 74 | if (3==flag) 75 | { 76 | list.Add(inst); 77 | } 78 | } 79 | #endregion 80 | 81 | list.Sort(SortCThostFtdcInstrumentField); 82 | 83 | //如果查出的数据为0,应当想法立即返回 84 | if (0==list.Count) 85 | { 86 | FIXSecurityDefinition definition = new FIXSecurityDefinition 87 | { 88 | SecurityReqID = request.SecurityReqID, 89 | SecurityResponseID = request.SecurityReqID, 90 | SecurityResponseType = request.SecurityRequestType, 91 | TotNoRelatedSym = 1//有个除0错误的问题 92 | }; 93 | if (SecurityDefinition != null) 94 | { 95 | SecurityDefinition(this, new SecurityDefinitionEventArgs(definition)); 96 | } 97 | } 98 | 99 | foreach (CThostFtdcInstrumentField inst in list) 100 | { 101 | FIXSecurityDefinition definition = new FIXSecurityDefinition 102 | { 103 | SecurityReqID = request.SecurityReqID, 104 | //SecurityResponseID = request.SecurityReqID, 105 | SecurityResponseType = request.SecurityRequestType, 106 | TotNoRelatedSym = list.Count 107 | }; 108 | 109 | { 110 | string securityType2 = GetSecurityType(inst); 111 | definition.AddField(EFIXField.SecurityType, securityType2); 112 | } 113 | { 114 | double x = inst.PriceTick; 115 | if (x > 0.00001) 116 | { 117 | int i = 0; 118 | for (; x - (int)x != 0; ++i) 119 | { 120 | x = x * 10; 121 | } 122 | definition.AddField(EFIXField.PriceDisplay, string.Format("F{0}", i)); 123 | definition.AddField(EFIXField.TickSize, inst.PriceTick); 124 | } 125 | } 126 | #if CTP 127 | definition.AddField(EFIXField.Symbol, inst.InstrumentID); 128 | #elif CTPZQ 129 | definition.AddField(EFIXField.Symbol, GetYahooSymbol(inst.InstrumentID, inst.ExchangeID)); 130 | #endif 131 | definition.AddField(EFIXField.SecurityExchange, inst.ExchangeID); 132 | definition.AddField(EFIXField.Currency, "CNY");//Currency.CNY 133 | definition.AddField(EFIXField.SecurityDesc, inst.InstrumentName); 134 | definition.AddField(EFIXField.Factor, (double)inst.VolumeMultiple); 135 | 136 | if(inst.ProductClass == TThostFtdcProductClassType.Futures||inst.ProductClass == TThostFtdcProductClassType.Options) 137 | { 138 | try 139 | { 140 | definition.AddField(EFIXField.MaturityDate, DateTime.ParseExact(inst.ExpireDate, "yyyyMMdd", CultureInfo.InvariantCulture)); 141 | } 142 | catch (Exception ex) 143 | { 144 | tdlog.Warn("合约:{0},字段内容:{1},{2}", inst.InstrumentID, inst.ExpireDate, ex.Message); 145 | } 146 | 147 | //if (inst.ProductClass == TThostFtdcProductClassType.Options) 148 | //{ 149 | // // 支持中金所,大商所,郑商所 150 | // var match = Regex.Match(inst.InstrumentID, @"(\d+)(-?)([CP])(-?)(\d+)"); 151 | // if (match.Success) 152 | // { 153 | // definition.AddField(EFIXField.PutOrCall, match.Groups[3].Value == "C" ? FIXPutOrCall.Call : FIXPutOrCall.Put); 154 | // definition.AddField(EFIXField.StrikePrice, double.Parse(match.Groups[5].Value)); 155 | // } 156 | //} 157 | } 158 | 159 | // 中金所仿真平台下,居然全设的是股票 160 | var match = Regex.Match(inst.InstrumentID, @"(\d+)(-?)([CP])(-?)(\d+)"); 161 | if (match.Success) 162 | { 163 | definition.AddField(EFIXField.PutOrCall, match.Groups[3].Value == "C" ? FIXPutOrCall.Call : FIXPutOrCall.Put); 164 | definition.AddField(EFIXField.StrikePrice, double.Parse(match.Groups[5].Value)); 165 | } 166 | 167 | FIXSecurityAltIDGroup group = new FIXSecurityAltIDGroup(); 168 | group.SecurityAltID = inst.InstrumentID; 169 | group.SecurityAltExchange = inst.ExchangeID; 170 | group.SecurityAltIDSource = this.Name; 171 | 172 | definition.AddGroup(group); 173 | 174 | //还得补全内容 175 | 176 | if (SecurityDefinition != null) 177 | { 178 | SecurityDefinition(this, new SecurityDefinitionEventArgs(definition)); 179 | } 180 | } 181 | } 182 | } 183 | 184 | private static int SortCThostFtdcInstrumentField(CThostFtdcInstrumentField a1, CThostFtdcInstrumentField a2) 185 | { 186 | return a1.InstrumentID.CompareTo(a2.InstrumentID); 187 | } 188 | #region 证券接口 189 | 190 | /* 191 | * 上海证券交易所证券代码分配规则 192 | * http://www.docin.com/p-417422186.html 193 | * 194 | * http://wenku.baidu.com/view/f2e9ddf77c1cfad6195fa706.html 195 | */ 196 | private string GetSecurityType(CThostFtdcInstrumentField inst) 197 | { 198 | string securityType = FIXSecurityType.CommonStock; 199 | 200 | try 201 | { 202 | switch (inst.ProductClass) 203 | { 204 | case TThostFtdcProductClassType.Futures: 205 | securityType = FIXSecurityType.Future; 206 | break; 207 | case TThostFtdcProductClassType.Combination: 208 | securityType = FIXSecurityType.MultiLegInstrument;//此处是否理解上有不同 209 | break; 210 | case TThostFtdcProductClassType.Options: 211 | securityType = FIXSecurityType.FutureOption; 212 | break; 213 | #if CTPZQ 214 | case TThostFtdcProductClassType.StockA: 215 | case TThostFtdcProductClassType.StockB: 216 | securityType = GetSecurityTypeStock(inst.ProductID, inst.InstrumentID); 217 | break; 218 | case TThostFtdcProductClassType.ETF: 219 | case TThostFtdcProductClassType.ETFPurRed: 220 | securityType = GetSecurityTypeETF(inst.ProductID, inst.InstrumentID); 221 | break; 222 | #endif 223 | default: 224 | securityType = FIXSecurityType.CommonStock; 225 | break; 226 | } 227 | return securityType; 228 | } 229 | catch(Exception ex) 230 | { 231 | tdlog.Warn("合约:{0},字段内容:{1}", inst.InstrumentID, ex.Message); 232 | } 233 | 234 | return securityType; 235 | } 236 | 237 | /* 238 | 从CTPZQ中遍历出来的所有ID 239 | GC 6 090002 240 | SHETF 8 500001 241 | SHA 6 600000 242 | SZA 6 000001 243 | SZBONDS 6 100213 244 | RC 6 131800 245 | SZETF 8 150001*/ 246 | private string GetSecurityTypeStock(string ProductID, string InstrumentID) 247 | { 248 | string securityType = FIXSecurityType.CommonStock; 249 | switch (ProductID) 250 | { 251 | case "SHA": 252 | case "SZA": 253 | securityType = FIXSecurityType.CommonStock; 254 | break; 255 | case "SHBONDS": 256 | { 257 | int i = Convert.ToInt32(InstrumentID.Substring(0, 3)); 258 | if (i == 0) 259 | { 260 | securityType = FIXSecurityType.Index; 261 | } 262 | else if (i < 700) 263 | { 264 | securityType = FIXSecurityType.USTreasuryBond; 265 | } 266 | else if (i < 800) 267 | { 268 | securityType = FIXSecurityType.CommonStock; 269 | } 270 | else 271 | { 272 | securityType = FIXSecurityType.USTreasuryBond; 273 | } 274 | } 275 | break; 276 | case "SZBONDS": 277 | { 278 | int i = Convert.ToInt32(InstrumentID.Substring(0, 2)); 279 | if (i == 39) 280 | { 281 | securityType = FIXSecurityType.Index; 282 | } 283 | else 284 | { 285 | securityType = FIXSecurityType.USTreasuryBond; 286 | } 287 | } 288 | break; 289 | case "GC": 290 | case "RC": 291 | securityType = FIXSecurityType.USTreasuryBond; 292 | break; 293 | case "SHETF": 294 | case "SZETF": 295 | securityType = FIXSecurityType.ExchangeTradedFund; 296 | break; 297 | case "SHRATIONED": 298 | case "SZRATIONED": 299 | case "SZCYB": 300 | securityType = FIXSecurityType.CommonStock; 301 | break; 302 | default: 303 | securityType = FIXSecurityType.CommonStock; 304 | break; 305 | } 306 | return securityType; 307 | } 308 | 309 | private string GetSecurityTypeETF(string ProductID, string InstrumentID) 310 | { 311 | string securityType = FIXSecurityType.ExchangeTradedFund; 312 | switch (ProductID) 313 | { 314 | case "SHA": 315 | securityType = FIXSecurityType.CommonStock; 316 | break; 317 | case "SHETF": 318 | securityType = FIXSecurityType.ExchangeTradedFund; 319 | break; 320 | case "SZETF": 321 | securityType = FIXSecurityType.ExchangeTradedFund; 322 | break; 323 | case "SZA": 324 | { 325 | int i = Convert.ToInt32(InstrumentID.Substring(0, 2)); 326 | if (i < 10) 327 | { 328 | securityType = FIXSecurityType.CommonStock; 329 | } 330 | else if (i < 15) 331 | { 332 | securityType = FIXSecurityType.USTreasuryBond; 333 | } 334 | else if (i < 20) 335 | { 336 | securityType = FIXSecurityType.ExchangeTradedFund; 337 | } 338 | else if (i < 30) 339 | { 340 | securityType = FIXSecurityType.CommonStock; 341 | } 342 | else if (i < 39) 343 | { 344 | securityType = FIXSecurityType.CommonStock; 345 | } 346 | else if (i == 39) 347 | { 348 | securityType = FIXSecurityType.Index; 349 | } 350 | else 351 | { 352 | securityType = FIXSecurityType.CommonStock; 353 | } 354 | } 355 | break; 356 | } 357 | return securityType; 358 | } 359 | 360 | private string GetYahooSymbol(string InstrumentID, string ExchangeID) 361 | { 362 | if (InstrumentID.Length >= 6 && ExchangeID.Length >= 2) 363 | { 364 | return string.Format("{0}.{1}", InstrumentID.Substring(0,6), ExchangeID.Substring(0, 2)); 365 | } 366 | else 367 | { 368 | // 没有交易所信息时的容错处理 369 | string altSymbol; 370 | if (_dictInstruments2.TryGetValue(InstrumentID, out altSymbol)) 371 | { 372 | return altSymbol; 373 | } 374 | 375 | return string.Format("{0}.{1}", InstrumentID, ExchangeID); 376 | } 377 | } 378 | 379 | private string GetApiSymbol(string Symbol) 380 | { 381 | var match = Regex.Match(Symbol, @"(\d+)\.(\w+)"); 382 | if (match.Success) 383 | { 384 | var code = match.Groups[1].Value; 385 | return code; 386 | } 387 | return Symbol; 388 | } 389 | 390 | private string GetApiExchange(string Symbol) 391 | { 392 | var match = Regex.Match(Symbol, @"(\d+)\.(\w+)"); 393 | if (match.Success) 394 | { 395 | var code = match.Groups[2].Value; 396 | return code; 397 | } 398 | return Symbol; 399 | } 400 | #endregion 401 | } 402 | } 403 | -------------------------------------------------------------------------------- /src/QuantBox.OQ.CTP/APIProvider.MarketDataProvider.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.ComponentModel; 3 | using SmartQuant.Data; 4 | using SmartQuant.FIX; 5 | using SmartQuant.Instruments; 6 | using SmartQuant.Providers; 7 | using QuantBox.OQ.CTP; 8 | 9 | #if CTP 10 | using QuantBox.CSharp2CTP; 11 | using QuantBox.Helper.CTP; 12 | 13 | namespace QuantBox.OQ.CTP 14 | #elif CTPZQ 15 | using QuantBox.CSharp2CTPZQ; 16 | using QuantBox.Helper.CTPZQ; 17 | 18 | namespace QuantBox.OQ.CTPZQ 19 | #endif 20 | { 21 | public partial class APIProvider:IMarketDataProvider 22 | { 23 | #if OQ 24 | public IMarketDataFilter MarketDataFilter { get; set; } 25 | #endif 26 | private IBarFactory factory; 27 | 28 | public event MarketDataRequestRejectEventHandler MarketDataRequestReject; 29 | public event MarketDataSnapshotEventHandler MarketDataSnapshot; 30 | public event BarEventHandler NewBar; 31 | public event BarEventHandler NewBarOpen; 32 | public event BarSliceEventHandler NewBarSlice; 33 | public event CorporateActionEventHandler NewCorporateAction; 34 | public event FundamentalEventHandler NewFundamental; 35 | public event BarEventHandler NewMarketBar; 36 | public event MarketDataEventHandler NewMarketData; 37 | public event MarketDepthEventHandler NewMarketDepth; 38 | public event QuoteEventHandler NewQuote; 39 | public event TradeEventHandler NewTrade; 40 | 41 | #region IMarketDataProvider 42 | [Category(CATEGORY_BARFACTORY)] 43 | public IBarFactory BarFactory 44 | { 45 | get 46 | { 47 | return factory; 48 | } 49 | set 50 | { 51 | if (factory != null) 52 | { 53 | factory.NewBar -= OnNewBar; 54 | factory.NewBarOpen -= OnNewBarOpen; 55 | factory.NewBarSlice -= OnNewBarSlice; 56 | } 57 | factory = value; 58 | if (factory != null) 59 | { 60 | factory.NewBar += OnNewBar; 61 | factory.NewBarOpen += OnNewBarOpen; 62 | factory.NewBarSlice += OnNewBarSlice; 63 | } 64 | } 65 | } 66 | 67 | private void OnNewBarSlice(object sender, BarSliceEventArgs args) 68 | { 69 | if (NewBarSlice != null) 70 | { 71 | NewBarSlice(this, new BarSliceEventArgs(args.BarSize, this)); 72 | } 73 | } 74 | 75 | public void SendMarketDataRequest(FIXMarketDataRequest request) 76 | { 77 | if (!_bMdConnected) 78 | { 79 | EmitError(-1, -1, "行情服务器没有连接"); 80 | mdlog.Error("行情服务器没有连接"); 81 | return; 82 | } 83 | 84 | bool bSubscribe = false; 85 | bool bTrade = false; 86 | bool bQuote = false; 87 | bool bMarketDepth = false; 88 | if (request.NoMDEntryTypes > 0) 89 | { 90 | switch (request.GetMDEntryTypesGroup(0).MDEntryType) 91 | { 92 | case FIXMDEntryType.Bid: 93 | case FIXMDEntryType.Offer: 94 | if (request.MarketDepth != 1) 95 | { 96 | bMarketDepth = true; 97 | break; 98 | } 99 | bQuote = true; 100 | break; 101 | case FIXMDEntryType.Trade: 102 | bTrade = true; 103 | break; 104 | } 105 | } 106 | bSubscribe = (request.SubscriptionRequestType == DataManager.MARKET_DATA_SUBSCRIBE); 107 | 108 | if (bSubscribe) 109 | { 110 | for (int i = 0; i < request.NoRelatedSym; ++i) 111 | { 112 | FIXRelatedSymGroup group = request.GetRelatedSymGroup(i); 113 | Instrument inst = InstrumentManager.Instruments[group.Symbol]; 114 | 115 | //将用户合约转成交易所合约 116 | string altSymbol = inst.GetSymbol(this.Name); 117 | string altExchange = inst.GetSecurityExchange(this.Name); 118 | string apiSymbol = GetApiSymbol(altSymbol); 119 | string apiExchange = altExchange; 120 | #if CTPZQ 121 | altSymbol = GetYahooSymbol(apiSymbol, apiExchange); 122 | #endif 123 | CThostFtdcInstrumentField _Instrument; 124 | if (_dictInstruments.TryGetValue(altSymbol, out _Instrument)) 125 | { 126 | apiSymbol = _Instrument.InstrumentID; 127 | apiExchange = _Instrument.ExchangeID; 128 | } 129 | 130 | #if CTPZQ 131 | altSymbol = GetYahooSymbol(apiSymbol, apiExchange); 132 | #endif 133 | DataRecord record; 134 | if (!_dictAltSymbol2Instrument.TryGetValue(altSymbol, out record)) 135 | { 136 | record = new DataRecord(); 137 | record.Instrument = inst; 138 | record.Symbol = apiSymbol; 139 | record.Exchange = apiExchange; 140 | _dictAltSymbol2Instrument[altSymbol] = record; 141 | 142 | mdlog.Info("订阅合约/订阅询价 {0} {1} {2}", altSymbol, record.Symbol, record.Exchange); 143 | 144 | if (_bTdConnected) 145 | { 146 | TraderApi.TD_ReqQryInvestorPosition(m_pTdApi, null); 147 | timerPonstion.Enabled = false; 148 | timerPonstion.Enabled = true; 149 | } 150 | } 151 | 152 | //记录行情,同时对用户合约与交易所合约进行映射 153 | CThostFtdcDepthMarketDataField DepthMarket; 154 | if (!_dictDepthMarketData.TryGetValue(altSymbol, out DepthMarket)) 155 | { 156 | _dictDepthMarketData[altSymbol] = DepthMarket; 157 | } 158 | 159 | // 多次订阅也无所谓 160 | MdApi.MD_Subscribe(m_pMdApi, record.Symbol, record.Exchange); 161 | MdApi.MD_SubscribeQuote(m_pMdApi, record.Symbol, record.Exchange); 162 | 163 | if (bTrade) 164 | record.TradeRequested = true; 165 | if (bQuote) 166 | record.QuoteRequested = true; 167 | if (bMarketDepth) 168 | record.MarketDepthRequested = true; 169 | 170 | if (bMarketDepth) 171 | { 172 | inst.OrderBook.Clear(); 173 | } 174 | } 175 | } 176 | else 177 | { 178 | for (int i = 0; i < request.NoRelatedSym; ++i) 179 | { 180 | FIXRelatedSymGroup group = request.GetRelatedSymGroup(i); 181 | Instrument inst = InstrumentManager.Instruments[group.Symbol]; 182 | 183 | //将用户合约转成交易所合约 184 | string altSymbol = inst.GetSymbol(this.Name); 185 | string altExchange = inst.GetSecurityExchange(this.Name); 186 | 187 | DataRecord record; 188 | if (!_dictAltSymbol2Instrument.TryGetValue(altSymbol, out record)) 189 | { 190 | break; 191 | } 192 | 193 | if (bTrade) 194 | record.TradeRequested = false; 195 | if (bQuote) 196 | record.QuoteRequested = false; 197 | if (bMarketDepth) 198 | record.MarketDepthRequested = false; 199 | 200 | if (!record.TradeRequested && !record.QuoteRequested && !record.MarketDepthRequested) 201 | { 202 | _dictDepthMarketData.Remove(altSymbol); 203 | _dictAltSymbol2Instrument.Remove(altSymbol); 204 | mdlog.Info("取消合约/取消询价 {0} {1} {2}", altSymbol, record.Symbol, record.Exchange); 205 | MdApi.MD_Unsubscribe(m_pMdApi, record.Symbol, record.Exchange); 206 | MdApi.MD_UnsubscribeQuote(m_pMdApi, record.Symbol, record.Exchange); 207 | } 208 | else 209 | { 210 | // 只要有一种类型说要订阅,就给订上 211 | MdApi.MD_Subscribe(m_pMdApi, record.Symbol, record.Exchange); 212 | MdApi.MD_SubscribeQuote(m_pMdApi, record.Symbol, record.Exchange); 213 | } 214 | } 215 | } 216 | } 217 | 218 | private bool EmitNewMarketDepth(Instrument instrument, DateTime datatime, int position, MDSide ask, double price, int size) 219 | { 220 | bool bRet = false; 221 | MDOperation insert = MDOperation.Update; 222 | if (MDSide.Ask == ask) 223 | { 224 | if (position >= instrument.OrderBook.Ask.Count) 225 | { 226 | insert = MDOperation.Insert; 227 | } 228 | } 229 | else 230 | { 231 | if (position >= instrument.OrderBook.Bid.Count) 232 | { 233 | insert = MDOperation.Insert; 234 | } 235 | } 236 | 237 | if (price != 0 && size != 0) 238 | { 239 | EmitNewMarketDepth(instrument, new MarketDepth(datatime, "", position, insert, ask, price, size)); 240 | bRet = true; 241 | } 242 | return bRet; 243 | } 244 | 245 | private void EmitNewMarketDepth(IFIXInstrument instrument, MarketDepth marketDepth) 246 | { 247 | if (NewMarketDepth != null) 248 | { 249 | NewMarketDepth(this, new MarketDepthEventArgs(marketDepth, instrument, this)); 250 | } 251 | } 252 | #endregion 253 | 254 | private void OnNewBar(object sender, BarEventArgs args) 255 | { 256 | if (NewBar != null) 257 | { 258 | CThostFtdcDepthMarketDataField DepthMarket; 259 | Instrument inst = InstrumentManager.Instruments[args.Instrument.Symbol]; 260 | string altSymbol = inst.GetSymbol(Name); 261 | 262 | Bar bar = args.Bar; 263 | if (_dictDepthMarketData.TryGetValue(altSymbol, out DepthMarket)) 264 | { 265 | bar = new Bar(args.Bar); 266 | bar.OpenInt = (long)DepthMarket.OpenInterest; 267 | } 268 | #if OQ 269 | if (null != MarketDataFilter) 270 | { 271 | Bar b = MarketDataFilter.FilterBar(bar, args.Instrument.Symbol); 272 | if (null != b) 273 | { 274 | NewBar(this, new BarEventArgs(b, args.Instrument, this)); 275 | } 276 | } 277 | else 278 | #endif 279 | { 280 | NewBar(this, new BarEventArgs(bar, args.Instrument, this)); 281 | } 282 | } 283 | } 284 | 285 | private void OnNewBarOpen(object sender, BarEventArgs args) 286 | { 287 | if (NewBarOpen != null) 288 | { 289 | CThostFtdcDepthMarketDataField DepthMarket; 290 | Instrument inst = InstrumentManager.Instruments[args.Instrument.Symbol]; 291 | string altSymbol = inst.GetSymbol(Name); 292 | 293 | Bar bar = args.Bar; 294 | if (_dictDepthMarketData.TryGetValue(altSymbol, out DepthMarket)) 295 | { 296 | bar = new Bar(args.Bar); 297 | bar.OpenInt = (long)DepthMarket.OpenInterest; 298 | } 299 | 300 | #if OQ 301 | if (null != MarketDataFilter) 302 | { 303 | Bar b = MarketDataFilter.FilterBarOpen(bar, args.Instrument.Symbol); 304 | if (null != b) 305 | { 306 | NewBarOpen(this, new BarEventArgs(b, args.Instrument, this)); 307 | } 308 | } 309 | else 310 | #endif 311 | { 312 | NewBarOpen(this, new BarEventArgs(bar, args.Instrument, this)); 313 | } 314 | } 315 | } 316 | 317 | private void EmitNewQuoteEvent(IFIXInstrument instrument, Quote quote) 318 | { 319 | #if OQ 320 | if (this.MarketDataFilter != null) 321 | { 322 | quote = this.MarketDataFilter.FilterQuote(quote, instrument.Symbol); 323 | } 324 | #endif 325 | if (quote != null) 326 | { 327 | if (NewQuote != null) 328 | { 329 | NewQuote(this, new QuoteEventArgs(quote, instrument, this)); 330 | } 331 | if (factory != null) 332 | { 333 | factory.OnNewQuote(instrument, quote); 334 | } 335 | } 336 | } 337 | 338 | private void EmitNewTradeEvent(IFIXInstrument instrument, Trade trade) 339 | { 340 | #if OQ 341 | if (this.MarketDataFilter != null) 342 | { 343 | trade = this.MarketDataFilter.FilterTrade(trade, instrument.Symbol); 344 | } 345 | #endif 346 | if (trade != null) 347 | { 348 | if (NewTrade != null) 349 | { 350 | NewTrade(this, new TradeEventArgs(trade, instrument, this)); 351 | } 352 | if (factory != null) 353 | { 354 | factory.OnNewTrade(instrument, trade); 355 | } 356 | } 357 | } 358 | } 359 | } 360 | -------------------------------------------------------------------------------- /src/QuantBox.OQ.CTP/APIProvider.Provider.cs: -------------------------------------------------------------------------------- 1 | using NLog; 2 | using NLog.Config; 3 | using SmartQuant; 4 | using SmartQuant.Providers; 5 | using System; 6 | using System.Collections.Specialized; 7 | using System.ComponentModel; 8 | using System.IO; 9 | using System.Reflection; 10 | using System.Windows.Forms; 11 | 12 | #if CTP 13 | using QuantBox.CSharp2CTP; 14 | using QuantBox.Helper.CTP; 15 | using System.Collections.Generic; 16 | 17 | namespace QuantBox.OQ.CTP 18 | #elif CTPZQ 19 | using QuantBox.CSharp2CTPZQ; 20 | using QuantBox.Helper.CTPZQ; 21 | 22 | namespace QuantBox.OQ.CTPZQ 23 | #endif 24 | { 25 | public partial class APIProvider : IProvider, IDisposable 26 | { 27 | private byte _Id; 28 | private string _Name; 29 | 30 | private ProviderStatus status; 31 | private bool isConnected; 32 | 33 | public event EventHandler Connected; 34 | public event EventHandler Disconnected; 35 | public event ProviderErrorEventHandler Error; 36 | 37 | private bool disposed; 38 | 39 | private Logger mdlog; 40 | private Logger tdlog; 41 | 42 | // Use C# destructor syntax for finalization code. 43 | ~APIProvider() 44 | { 45 | // Simply call Dispose(false). 46 | Dispose(false); 47 | } 48 | 49 | static bool bDoOnce = true; 50 | public APIProvider() 51 | { 52 | #if CTP 53 | if (bDoOnce) 54 | { 55 | Init(55, "CTP"); 56 | bDoOnce = false; 57 | 58 | // 在QR中用多Provider变相实现多账号功能 59 | //new APIProvider().Init(100, "CTP100"); 60 | //new APIProvider().Init(101, "CTP101"); 61 | //new APIProvider().Init(102, "CTP102"); 62 | //new APIProvider().Init(103, "CTP103"); 63 | //new APIProvider().Init(104, "CTP104"); 64 | //new APIProvider().Init(105, "CTP105"); 65 | } 66 | #elif CTPZQ 67 | Init(56,"CTPZQ"); 68 | #endif 69 | } 70 | 71 | public void Init(byte Id,string Name) 72 | { 73 | _Id = Id; 74 | _Name = Name; 75 | 76 | mdlog = LogManager.GetLogger(Name + ".M"); 77 | tdlog = LogManager.GetLogger(Name + ".T"); 78 | 79 | try 80 | { 81 | LogManager.Configuration = new XmlLoggingConfiguration(@"Bin/QuantBox.nlog"); 82 | } 83 | catch (Exception ex) 84 | { 85 | tdlog.Warn(ex.Message); 86 | } 87 | 88 | timerConnect.Elapsed += timerConnect_Elapsed; 89 | timerDisconnect.Elapsed += timerDisconnect_Elapsed; 90 | timerAccount.Elapsed += timerAccount_Elapsed; 91 | timerPonstion.Elapsed += timerPonstion_Elapsed; 92 | 93 | InitCallbacks(); 94 | InitSettings(); 95 | 96 | BarFactory = new SmartQuant.Providers.BarFactory(); 97 | status = ProviderStatus.Unknown; 98 | SmartQuant.Providers.ProviderManager.Add(this); 99 | } 100 | 101 | //Implement IDisposable. 102 | public void Dispose() 103 | { 104 | Dispose(true); 105 | GC.SuppressFinalize(this); 106 | } 107 | 108 | protected virtual void Dispose(bool disposing) 109 | { 110 | if (!disposed) 111 | { 112 | if (disposing) 113 | { 114 | // Free other state (managed objects). 115 | } 116 | // Free your own state (unmanaged objects). 117 | // Set large fields to null. 118 | Shutdown(); 119 | disposed = true; 120 | } 121 | //base.Dispose(disposing); 122 | } 123 | 124 | 125 | 126 | #region IProvider 127 | [Category(CATEGORY_INFO)] 128 | public byte Id//不能与已经安装的插件ID重复 129 | { 130 | get { return _Id; } 131 | set { _Id = value; } 132 | } 133 | 134 | [Category(CATEGORY_INFO)] 135 | public string Name 136 | { 137 | get { return _Name; } 138 | set { _Name = value; } 139 | } 140 | 141 | [Category(CATEGORY_INFO)] 142 | public string Title 143 | { 144 | get { return string.Format("QuantBox {0} Provider",this.Name); } 145 | } 146 | 147 | [Category(CATEGORY_INFO)] 148 | public string URL 149 | { 150 | get { return "www.quantbox.cn"; } 151 | } 152 | 153 | [Category(CATEGORY_INFO)] 154 | [Description("插件版本信息")] 155 | public string Version 156 | { 157 | get { return Assembly.GetExecutingAssembly().GetName().Version.ToString(); } 158 | } 159 | 160 | [Category(CATEGORY_STATUS)] 161 | public bool IsConnected 162 | { 163 | get { return isConnected; } 164 | } 165 | 166 | [Category(CATEGORY_STATUS)] 167 | public ProviderStatus Status 168 | { 169 | get { return status; } 170 | } 171 | 172 | public void Connect(int timeout) 173 | { 174 | Connect(); 175 | ProviderManager.WaitConnected(this, timeout); 176 | } 177 | 178 | public void Connect() 179 | { 180 | _Connect(); 181 | } 182 | 183 | public void Disconnect() 184 | { 185 | _Disconnect(); 186 | } 187 | 188 | public void Shutdown() 189 | { 190 | Disconnect(); 191 | 192 | SettingsChanged(); 193 | 194 | timerConnect.Elapsed -= timerConnect_Elapsed; 195 | timerDisconnect.Elapsed -= timerDisconnect_Elapsed; 196 | timerAccount.Elapsed -= timerAccount_Elapsed; 197 | timerPonstion.Elapsed -= timerPonstion_Elapsed; 198 | } 199 | 200 | public event EventHandler StatusChanged; 201 | 202 | private void ChangeStatus(ProviderStatus status) 203 | { 204 | this.status = status; 205 | EmitStatusChangedEvent(); 206 | } 207 | 208 | private void EmitStatusChangedEvent() 209 | { 210 | if (StatusChanged != null) 211 | { 212 | StatusChanged(this, EventArgs.Empty); 213 | } 214 | } 215 | 216 | private void EmitConnectedEvent() 217 | { 218 | if (Connected != null) 219 | { 220 | Connected(this, EventArgs.Empty); 221 | } 222 | } 223 | 224 | private void EmitDisconnectedEvent() 225 | { 226 | if (Disconnected != null) 227 | { 228 | Disconnected(this, EventArgs.Empty); 229 | } 230 | } 231 | 232 | private void EmitError(int id, int code, string message) 233 | { 234 | if (Error != null) 235 | Error(new ProviderErrorEventArgs(new ProviderError(Clock.Now, this, id, code, message))); 236 | } 237 | #endregion 238 | } 239 | } 240 | -------------------------------------------------------------------------------- /src/QuantBox.OQ.CTP/APIProvider.Settings.cs: -------------------------------------------------------------------------------- 1 | using SmartQuant; 2 | using System; 3 | using System.ComponentModel; 4 | using System.Drawing.Design; 5 | using System.IO; 6 | using System.Xml.Serialization; 7 | using QuantBox.OQ.CTP; 8 | using QuantBox.OQ.Extensions; 9 | 10 | #if CTP 11 | using QuantBox.CSharp2CTP; 12 | using QuantBox.Helper.CTP; 13 | 14 | namespace QuantBox.OQ.CTP 15 | #elif CTPZQ 16 | using QuantBox.CSharp2CTPZQ; 17 | using QuantBox.Helper.CTPZQ; 18 | 19 | namespace QuantBox.OQ.CTPZQ 20 | #endif 21 | { 22 | partial class APIProvider 23 | { 24 | private const string CATEGORY_ACCOUNT = "Account"; 25 | private const string CATEGORY_BARFACTORY = "Bar Factory"; 26 | private const string CATEGORY_DEBUG = "Debug"; 27 | private const string CATEGORY_EXECUTION = "Settings - Execution"; 28 | private const string CATEGORY_HISTORICAL = "Settings - Historical Data"; 29 | private const string CATEGORY_INFO = "Information"; 30 | private const string CATEGORY_NETWORK = "Settings - Network"; 31 | private const string CATEGORY_STATUS = "Status"; 32 | private const string CATEGORY_TIME = "Settings - Time"; 33 | private const string CATEGORY_OTHER = "Settings - Other"; 34 | 35 | 36 | public string accountsFile; 37 | public string serversFile; 38 | public string brokersFile; 39 | 40 | #if CTP 41 | //交易所常量定义 42 | private enum ExchangID 43 | { 44 | SHFE, 45 | DCE, 46 | CZCE, 47 | CFFEX 48 | } 49 | 50 | private string _SupportMarketOrder; 51 | private string _SupportCloseToday; 52 | 53 | 54 | [Category(CATEGORY_OTHER)] 55 | [Description("支持市价单的交易所")] 56 | public string SupportMarketOrder 57 | { 58 | get { return _SupportMarketOrder; } 59 | } 60 | 61 | 62 | [Category(CATEGORY_OTHER)] 63 | [Description("区分平今与平昨的交易所")] 64 | public string SupportCloseToday 65 | { 66 | get { return _SupportCloseToday; } 67 | } 68 | 69 | 70 | 71 | #elif CTPZQ 72 | private enum ExchangID 73 | { 74 | SSE, 75 | SZE 76 | } 77 | #endif 78 | private EnumOpenClose _DefaultOpenClose; 79 | 80 | [DefaultValue(EnumOpenClose.OPEN)] 81 | [Category(CATEGORY_OTHER)] 82 | [Description("默认开平:当没有指定开平时,按此进行开平")] 83 | public EnumOpenClose DefaultOpenClose 84 | { 85 | get { return _DefaultOpenClose; } 86 | set { _DefaultOpenClose = value; } 87 | } 88 | 89 | public enum TimeMode 90 | { 91 | LocalTime, 92 | ExchangeTime 93 | } 94 | 95 | public enum SetTimeMode 96 | { 97 | None, 98 | LoginTime, 99 | SHFETime, 100 | DCETime, 101 | CZCETime, 102 | FFEXTime 103 | } 104 | 105 | #region 参数设置 106 | private TimeMode _TimeMode; 107 | 108 | [Category(CATEGORY_OTHER)] 109 | [Description("设置API生成临时文件的目录")] 110 | [Editor(typeof(System.Windows.Forms.Design.FolderNameEditor), typeof(System.Drawing.Design.UITypeEditor))] 111 | [Browsable(false)] 112 | public string ApiTempPath { get; set; } 113 | 114 | [Category(CATEGORY_TIME)] 115 | [Description("警告!仅保存行情数据时才用交易所时间。交易时使用交易所时间将导致Bar生成错误")] 116 | [DefaultValue(TimeMode.LocalTime)] 117 | public TimeMode DateTimeMode 118 | { 119 | get { return _TimeMode; } 120 | set { _TimeMode = value; } 121 | } 122 | 123 | [Category(CATEGORY_TIME)] 124 | [Description("修改本地时间。分别是:不修改、登录交易前置机时间、各大交易所时间。以管理员方式运行才有权限")] 125 | [DefaultValue(SetTimeMode.None)] 126 | public SetTimeMode SetLocalTimeMode 127 | { 128 | get; 129 | set; 130 | } 131 | 132 | [Category(CATEGORY_TIME)] 133 | [DefaultValue(0)] 134 | [Description("修改本地时间时,在取到的时间上添加指定毫秒")] 135 | public int AddMilliseconds 136 | { 137 | get; 138 | set; 139 | } 140 | 141 | [Category(CATEGORY_OTHER)] 142 | [Description("设置登录后是否接收完整的报单和成交记录")] 143 | [DefaultValue(THOST_TE_RESUME_TYPE.THOST_TERT_QUICK)] 144 | public THOST_TE_RESUME_TYPE ResumeType { get; set; } 145 | 146 | [Category(CATEGORY_OTHER)] 147 | [Description("设置投机套保标志。\nSpeculation - 投机\nArbitrage - 套利\nHedge - 套保")] 148 | [DefaultValue(TThostFtdcHedgeFlagType.Speculation)] 149 | public TThostFtdcHedgeFlagType HedgeFlagType 150 | { 151 | get; 152 | set; 153 | } 154 | 155 | 156 | 157 | [Category(CATEGORY_OTHER)] 158 | [Description("在最新价上调整N跳来模拟市价,超过涨跌停价按涨跌停价报单")] 159 | [DefaultValue(10)] 160 | public int LastPricePlusNTicks 161 | { 162 | get; 163 | set; 164 | } 165 | 166 | [Category(CATEGORY_OTHER)] 167 | [Description("True - 所有市价单都用限价单来模拟\nFalse - 仅对上期所进行模拟")] 168 | [DefaultValue(false)] 169 | public bool SwitchMakertOrderToLimitOrder 170 | { 171 | get; 172 | set; 173 | } 174 | 175 | private BindingList serversList = new BindingList(); 176 | [Category("Settings")] 177 | [Description("服务器信息,只选择第一条登录")] 178 | public BindingList Server 179 | { 180 | get { return serversList; } 181 | set { serversList = value; } 182 | } 183 | 184 | private BindingList accountsList = new BindingList(); 185 | [Category("Settings")] 186 | [Description("账号信息,只选择第一条登录")] 187 | public BindingList Account 188 | { 189 | get { return accountsList; } 190 | set { accountsList = value; } 191 | } 192 | 193 | private BindingList brokersList = new BindingList(); 194 | [Category("Settings"), Editor(typeof(ServersManagerTypeEditor), typeof(UITypeEditor)), 195 | Description("点击(...)查看经纪商列表")] 196 | public BindingList Brokers 197 | { 198 | get { return brokersList; } 199 | set { brokersList = value; } 200 | } 201 | 202 | [Category("Settings")] 203 | [Description("连接到行情。此插件不连接行情时底层对不支持市价的报单不会做涨跌停修正,需策略层处理")] 204 | [DefaultValue(true)] 205 | public bool ConnectToMarketData 206 | { 207 | get { return _bWantMdConnect; } 208 | set { _bWantMdConnect = value; } 209 | } 210 | 211 | [Category("Settings")] 212 | [Description("连接到交易")] 213 | [DefaultValue(true)] 214 | public bool ConnectToTrading 215 | { 216 | get { return _bWantTdConnect; } 217 | set { _bWantTdConnect = value; } 218 | } 219 | 220 | #endregion 221 | private void InitSettings() 222 | { 223 | accountsFile = string.Format(@"{0}\{1}.Accounts.xml", Framework.Installation.IniDir,this.Name); 224 | serversFile = string.Format(@"{0}\{1}.Servers.xml", Framework.Installation.IniDir, this.Name); 225 | brokersFile = string.Format(@"{0}\{1}.Brokers.xml", Framework.Installation.IniDir, this.Name); 226 | 227 | ApiTempPath = Framework.Installation.TempDir.FullName; 228 | ResumeType = THOST_TE_RESUME_TYPE.THOST_TERT_QUICK; 229 | HedgeFlagType = TThostFtdcHedgeFlagType.Speculation; 230 | _DefaultOpenClose = EnumOpenClose.OPEN; 231 | 232 | SwitchMakertOrderToLimitOrder = false; 233 | 234 | _bWantMdConnect = true; 235 | _bWantTdConnect = true; 236 | 237 | #if CTP 238 | _SupportMarketOrder = String.Format("{0};{1};{2};", ExchangID.DCE, ExchangID.CZCE, ExchangID.CFFEX); 239 | _SupportCloseToday = ExchangID.SHFE + ";"; 240 | 241 | #elif CTPZQ 242 | 243 | #endif 244 | LastPricePlusNTicks = 10; 245 | 246 | LoadAccounts(); 247 | LoadServers(); 248 | 249 | serversList.ListChanged += ServersList_ListChanged; 250 | accountsList.ListChanged += AccountsList_ListChanged; 251 | } 252 | 253 | void ServersList_ListChanged(object sender, ListChangedEventArgs e) 254 | { 255 | if (e.ListChangedType == ListChangedType.ItemAdded) 256 | { 257 | serversList[e.NewIndex].Changed += ServerItem_ListChanged; 258 | } 259 | SettingsChanged(); 260 | } 261 | 262 | void AccountsList_ListChanged(object sender, EventArgs e) 263 | { 264 | SettingsChanged(); 265 | } 266 | 267 | void ServerItem_ListChanged(object sender, EventArgs e) 268 | { 269 | SettingsChanged(); 270 | } 271 | 272 | public void SettingsChanged() 273 | { 274 | SaveAccounts(); 275 | SaveServers(); 276 | } 277 | 278 | 279 | void LoadAccounts() 280 | { 281 | accountsList.Clear(); 282 | 283 | try 284 | { 285 | XmlSerializer serializer = new XmlSerializer(accountsList.GetType()); 286 | using (FileStream stream = new FileStream(accountsFile, FileMode.Open)) 287 | { 288 | accountsList = (BindingList)serializer.Deserialize(stream); 289 | stream.Close(); 290 | } 291 | } 292 | catch (Exception) 293 | { 294 | } 295 | } 296 | 297 | void SaveAccounts() 298 | { 299 | XmlSerializer serializer = new XmlSerializer(accountsList.GetType()); 300 | using (TextWriter writer = new StreamWriter(accountsFile)) 301 | { 302 | serializer.Serialize(writer, accountsList); 303 | writer.Close(); 304 | } 305 | } 306 | 307 | void LoadServers() 308 | { 309 | serversList.Clear(); 310 | 311 | try 312 | { 313 | XmlSerializer serializer = new XmlSerializer(serversList.GetType()); 314 | using (FileStream stream = new FileStream(serversFile, FileMode.Open)) 315 | { 316 | serversList = (BindingList)serializer.Deserialize(stream); 317 | stream.Close(); 318 | } 319 | } 320 | catch (Exception) 321 | { 322 | } 323 | } 324 | 325 | void SaveServers() 326 | { 327 | XmlSerializer serializer = new XmlSerializer(serversList.GetType()); 328 | using (TextWriter writer = new StreamWriter(serversFile)) 329 | { 330 | serializer.Serialize(writer, serversList); 331 | writer.Close(); 332 | } 333 | } 334 | 335 | public void LoadBrokers() 336 | { 337 | brokersList.Clear(); 338 | 339 | try 340 | { 341 | XmlSerializer serializer = new XmlSerializer(brokersList.GetType()); 342 | using (FileStream stream = new FileStream(brokersFile, FileMode.Open)) 343 | { 344 | brokersList = (BindingList)serializer.Deserialize(stream); 345 | stream.Close(); 346 | } 347 | } 348 | catch (Exception) 349 | { 350 | } 351 | } 352 | 353 | void SaveBrokers() 354 | { 355 | XmlSerializer serializer = new XmlSerializer(brokersList.GetType()); 356 | using (TextWriter writer = new StreamWriter(brokersFile)) 357 | { 358 | serializer.Serialize(writer, brokersList); 359 | writer.Close(); 360 | } 361 | } 362 | } 363 | } 364 | -------------------------------------------------------------------------------- /src/QuantBox.OQ.CTP/APIProvider.SimulationMarketDataProvider.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.ComponentModel; 3 | 4 | using SmartQuant.Data; 5 | using SmartQuant.FIX; 6 | using SmartQuant.Instruments; 7 | using SmartQuant.Providers; 8 | 9 | #if CTP 10 | using QuantBox.CSharp2CTP; 11 | using QuantBox.Helper.CTP; 12 | 13 | namespace QuantBox.OQ.CTP 14 | #elif CTPZQ 15 | using QuantBox.CSharp2CTPZQ; 16 | using QuantBox.Helper.CTPZQ; 17 | 18 | namespace QuantBox.OQ.CTPZQ 19 | #endif 20 | { 21 | public partial class APIProvider :ISimulationMarketDataProvider 22 | { 23 | #region OpenQuant3接口的新方法 24 | public void EmitQuote(IFIXInstrument instrument, Quote quote) 25 | { 26 | EmitNewQuoteEvent(instrument, quote); 27 | } 28 | 29 | public void EmitTrade(IFIXInstrument instrument, Trade trade) 30 | { 31 | EmitNewTradeEvent(instrument, trade); 32 | } 33 | #endregion 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/QuantBox.OQ.CTP/AccountItem.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.ComponentModel; 6 | 7 | namespace QuantBox.OQ.CTP 8 | { 9 | [DefaultPropertyAttribute("Label")] 10 | public class AccountItem 11 | { 12 | [DescriptionAttribute("账号")] 13 | public string InvestorId 14 | { 15 | get; 16 | set; 17 | } 18 | [PasswordPropertyText(true)] 19 | [DescriptionAttribute("密码")] 20 | public string Password 21 | { 22 | get; 23 | set; 24 | } 25 | 26 | [CategoryAttribute("标签"), 27 | DescriptionAttribute("标签不能重复")] 28 | public string Label 29 | { 30 | get; 31 | set; 32 | } 33 | 34 | public override string ToString() 35 | { 36 | return "标签不能重复"; 37 | } 38 | 39 | [BrowsableAttribute(false)] 40 | public string Name 41 | { 42 | get { return Label; } 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/QuantBox.OQ.CTP/ApiContainer.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | 6 | namespace QuantBox.OQ.CTP 7 | { 8 | public class ApiContainer 9 | { 10 | private Dictionary string_T = new Dictionary(); 11 | private Dictionary IntPtr_T = new Dictionary(); 12 | 13 | public T this[string account] 14 | { 15 | get 16 | { 17 | return string_T[account]; 18 | } 19 | //set 20 | //{ 21 | // string_T[account] = value; 22 | //} 23 | } 24 | 25 | public T this[IntPtr ptr] 26 | { 27 | get 28 | { 29 | return IntPtr_T[ptr]; 30 | } 31 | //set 32 | //{ 33 | // IntPtr_T[ptr] = value; 34 | //} 35 | } 36 | 37 | public void Add(string account, T t) 38 | { 39 | string_T[account] = t; 40 | } 41 | 42 | public void Add(IntPtr ptr, T t) 43 | { 44 | IntPtr_T[ptr] = t; 45 | } 46 | 47 | public void Remove(IntPtr ptr) 48 | { 49 | } 50 | public void Remove(string account) 51 | { 52 | } 53 | public void Remove(ApiWrapper api) 54 | { 55 | } 56 | public void Remove(int index) 57 | { 58 | } 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/QuantBox.OQ.CTP/ApiWrapper.cs: -------------------------------------------------------------------------------- 1 | using NLog; 2 | using QuantBox.CSharp2CTP; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | using System.Text; 7 | 8 | namespace QuantBox.OQ.CTP 9 | { 10 | public class ApiWrapper 11 | { 12 | public Logger Log; 13 | 14 | public fnOnConnect _fnOnConnect_Holder; 15 | public fnOnDisconnect _fnOnDisconnect_Holder; 16 | public fnOnRspError _fnOnRspError_Holder; 17 | 18 | public ServerItem server; 19 | public AccountItem account; 20 | 21 | protected string tempPath; 22 | 23 | protected readonly object _lock = new object(); 24 | private readonly object _lockMsgQueue = new object(); 25 | 26 | protected IntPtr m_pMsgQueue = IntPtr.Zero; 27 | protected IntPtr Api = IntPtr.Zero; 28 | 29 | public volatile bool IsConnected; 30 | 31 | protected void Connect_MsgQueue() 32 | { 33 | lock (_lockMsgQueue) 34 | { 35 | if (null == m_pMsgQueue || IntPtr.Zero == m_pMsgQueue) 36 | { 37 | m_pMsgQueue = CommApi.CTP_CreateMsgQueue(); 38 | 39 | CommApi.CTP_RegOnConnect(m_pMsgQueue, _fnOnConnect_Holder); 40 | CommApi.CTP_RegOnDisconnect(m_pMsgQueue, _fnOnDisconnect_Holder); 41 | CommApi.CTP_RegOnRspError(m_pMsgQueue, _fnOnRspError_Holder); 42 | 43 | CommApi.CTP_StartMsgQueue(m_pMsgQueue); 44 | } 45 | } 46 | } 47 | 48 | protected void Disconnect_MsgQueue() 49 | { 50 | lock (_lockMsgQueue) 51 | { 52 | if (null != m_pMsgQueue && IntPtr.Zero != m_pMsgQueue) 53 | { 54 | CommApi.CTP_StopMsgQueue(m_pMsgQueue); 55 | 56 | CommApi.CTP_ReleaseMsgQueue(m_pMsgQueue); 57 | m_pMsgQueue = IntPtr.Zero; 58 | } 59 | } 60 | } 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/QuantBox.OQ.CTP/BrokerItem.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel; 4 | using System.Linq; 5 | using System.Text; 6 | 7 | namespace QuantBox.OQ.CTP 8 | { 9 | public class BrokerItem 10 | { 11 | public string Label 12 | { 13 | get; 14 | set; 15 | } 16 | 17 | public BindingList Server 18 | { 19 | get; 20 | set; 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/QuantBox.OQ.CTP/DataRecord.cs: -------------------------------------------------------------------------------- 1 | using SmartQuant.Instruments; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | 7 | namespace QuantBox.OQ.CTP 8 | { 9 | class DataRecord 10 | { 11 | public string Symbol; 12 | public string Exchange; 13 | public Instrument Instrument; 14 | public bool TradeRequested; 15 | public bool QuoteRequested; 16 | public bool MarketDepthRequested; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/QuantBox.OQ.CTP/OrderMap.cs: -------------------------------------------------------------------------------- 1 | using QuantBox.OQ.Extensions.OrderItem; 2 | using SmartQuant.Execution; 3 | using SmartQuant.FIX; 4 | using System.Collections.Generic; 5 | 6 | #if CTP 7 | using QuantBox.CSharp2CTP; 8 | 9 | namespace QuantBox.OQ.CTP 10 | #elif CTPZQ 11 | using QuantBox.CSharp2CTPZQ; 12 | 13 | namespace QuantBox.OQ.CTPZQ 14 | #endif 15 | { 16 | public class OrderMap 17 | { 18 | // API中的报单引用,一个Ref只对应一个报单组合 19 | public readonly Dictionary OrderRef_OrderItem = new Dictionary(); 20 | // 记录界面报单到报单组合的关系 21 | public readonly Dictionary Order_OrderItem = new Dictionary(); 22 | // 记录报单组合到报单回报的关系,用于撤单 23 | public readonly Dictionary OrderItem_OrderField = new Dictionary(); 24 | // 交易所信息映射到本地信息 25 | public readonly Dictionary OrderSysID_OrderRef = new Dictionary(); 26 | // 标记正在撤单 27 | public readonly Dictionary Order_OrdStatus = new Dictionary(); 28 | 29 | public void Clear() 30 | { 31 | OrderRef_OrderItem.Clear(); 32 | Order_OrderItem.Clear(); 33 | OrderItem_OrderField.Clear(); 34 | OrderSysID_OrderRef.Clear(); 35 | Order_OrdStatus.Clear(); 36 | } 37 | 38 | // 用于收到委托回报信息后进行处理 39 | public bool TryGetValue(string key,out GenericOrderItem value) 40 | { 41 | return OrderRef_OrderItem.TryGetValue(key, out value); 42 | } 43 | 44 | // 用于收到成交回报信息后找到原始的报单引用 45 | public bool TryGetValue(string key, out string value) 46 | { 47 | return OrderSysID_OrderRef.TryGetValue(key, out value); 48 | } 49 | 50 | // 界面撤单时用于找到对应的报单组合 51 | public bool TryGetValue(SingleOrder key, out GenericOrderItem value) 52 | { 53 | return Order_OrderItem.TryGetValue(key, out value); 54 | } 55 | 56 | // 通过报单组合,实际的向交易所撤单 57 | public bool TryGetValue(GenericOrderItem key, out CThostFtdcOrderField value) 58 | { 59 | return OrderItem_OrderField.TryGetValue(key, out value); 60 | } 61 | 62 | // 返回状态 63 | public bool TryGetValue(SingleOrder key, out OrdStatus value) 64 | { 65 | return Order_OrdStatus.TryGetValue(key, out value); 66 | } 67 | 68 | public void CreateNewOrder(string key,GenericOrderItem value) 69 | { 70 | OrderRef_OrderItem[key] = value; 71 | } 72 | 73 | // 通过一个报单引用,把相关的单子全删了 74 | public void Remove(string key) 75 | { 76 | 77 | } 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /src/QuantBox.OQ.CTP/OrderRecord.cs: -------------------------------------------------------------------------------- 1 | using SmartQuant.Execution; 2 | 3 | namespace QuantBox.OQ.CTP 4 | { 5 | class OrderRecord 6 | { 7 | // Fields 8 | private double avgPx; 9 | private int cumQty; 10 | private int leavesQty; 11 | private SingleOrder order; 12 | 13 | // Methods 14 | public OrderRecord(SingleOrder order) 15 | { 16 | this.order = order; 17 | this.avgPx = 0.0; 18 | this.leavesQty = (int)order.OrderQty; 19 | this.cumQty = 0; 20 | } 21 | 22 | public void AddFill(double lastPx, int lastQty) 23 | { 24 | this.avgPx = ((this.avgPx * this.cumQty) + (lastPx * lastQty)) / ((double)(this.cumQty + lastQty)); 25 | this.leavesQty -= lastQty; 26 | this.cumQty += lastQty; 27 | } 28 | 29 | // Properties 30 | public double AvgPx 31 | { 32 | get 33 | { 34 | return this.avgPx; 35 | } 36 | } 37 | 38 | public int CumQty 39 | { 40 | get 41 | { 42 | return this.cumQty; 43 | } 44 | } 45 | 46 | public int LeavesQty 47 | { 48 | get 49 | { 50 | return this.leavesQty; 51 | } 52 | internal set 53 | { 54 | this.leavesQty = value; 55 | } 56 | } 57 | 58 | public SingleOrder Order 59 | { 60 | get 61 | { 62 | return this.order; 63 | } 64 | } 65 | } 66 | 67 | } 68 | -------------------------------------------------------------------------------- /src/QuantBox.OQ.CTP/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // 有关程序集的常规信息通过以下 6 | // 特性集控制。更改这些特性值可修改 7 | // 与程序集关联的信息。 8 | [assembly: AssemblyTitle("QuantBox.OQ.CTP")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("QuantBox.cn")] 12 | [assembly: AssemblyProduct("QuantBox.OQ.CTP")] 13 | [assembly: AssemblyCopyright("Copyright © QuantBox.cn 2014")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // 将 ComVisible 设置为 false 使此程序集中的类型 18 | // 对 COM 组件不可见。如果需要从 COM 访问此程序集中的类型, 19 | // 则将该类型上的 ComVisible 特性设置为 true。 20 | [assembly: ComVisible(false)] 21 | 22 | // 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID 23 | [assembly: Guid("dea1de5e-e4af-46bc-aa5e-f0bd13d70c44")] 24 | 25 | // 程序集的版本信息由下面四个值组成: 26 | // 27 | // 主版本 28 | // 次版本 29 | // 内部版本号 30 | // 修订号 31 | // 32 | // 可以指定所有这些值,也可以使用“内部版本号”和“修订号”的默认值, 33 | // 方法是按如下所示使用“*”: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("4.0.0.14")] 36 | [assembly: AssemblyFileVersion("4.0.0.14")] 37 | -------------------------------------------------------------------------------- /src/QuantBox.OQ.CTP/Properties/DataSources/BrokerItem.datasource: -------------------------------------------------------------------------------- 1 |  2 | 8 | 9 | QuantBox.OQ.CTP.BrokerItem, QuantBox.OQ.CTP, Version=3.2.0.0, Culture=neutral, PublicKeyToken=null 10 | -------------------------------------------------------------------------------- /src/QuantBox.OQ.CTP/Properties/DataSources/ServerItem.datasource: -------------------------------------------------------------------------------- 1 |  2 | 8 | 9 | QuantBox.OQ.CTP.ServerItem, QuantBox.OQ.CTP, Version=3.2.0.0, Culture=neutral, PublicKeyToken=null 10 | -------------------------------------------------------------------------------- /src/QuantBox.OQ.CTP/QuantBox.OQ.CTP.OQ3.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Debug 5 | AnyCPU 6 | 8.0.30703 7 | 2.0 8 | {72BE4BFC-E0F6-436F-8206-C6009932D620} 9 | Library 10 | Properties 11 | QuantBox.OQ.CTP 12 | QuantBox.OQ.CTP 13 | v4.0 14 | 512 15 | 16 | 17 | 18 | true 19 | full 20 | false 21 | ..\..\..\..\..\..\Program Files %28x86%29\SmartQuant Ltd\OpenQuant\Framework\bin\ 22 | TRACE;DEBUG;CTP,OQ 23 | prompt 24 | 4 25 | 26 | 27 | pdbonly 28 | true 29 | ..\..\bin\ 30 | TRACE;CTP,OQ 31 | prompt 32 | 4 33 | 34 | 35 | 36 | False 37 | ..\..\..\..\..\..\Program Files (x86)\SmartQuant Ltd\OpenQuant\Bin\Newtonsoft.Json.dll 38 | 39 | 40 | 41 | False 42 | ..\..\..\..\..\..\Program Files (x86)\SmartQuant Ltd\OpenQuant\Bin\QuantBox.CSharp2CTP.dll 43 | 44 | 45 | ..\..\..\..\..\..\Program Files (x86)\SmartQuant Ltd\OpenQuant\Bin\QuantBox.Libray.dll 46 | 47 | 48 | ..\..\..\..\..\..\Program Files (x86)\SmartQuant Ltd\OpenQuant\Bin\QuantBox.OQ.Extensions.dll 49 | 50 | 51 | False 52 | ..\reference\using\SmartQuant.dll 53 | 54 | 55 | ..\reference\using\SmartQuant.Data.dll 56 | 57 | 58 | False 59 | ..\reference\using\SmartQuant.Execution.dll 60 | 61 | 62 | False 63 | ..\reference\using\SmartQuant.FIX.dll 64 | 65 | 66 | False 67 | ..\reference\using\SmartQuant.Instruments.dll 68 | 69 | 70 | False 71 | ..\reference\using\SmartQuant.Providers.dll 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | Form 105 | 106 | 107 | ServersManagerForm.cs 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | ServersManagerForm.cs 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | {97ae93ec-5897-43c8-8d84-d92b73fe1434} 125 | QuantBox.Helper.CTP.Net40 126 | 127 | 128 | 129 | 136 | -------------------------------------------------------------------------------- /src/QuantBox.OQ.CTP/QuantBox.OQ.CTP.QD.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Debug 5 | AnyCPU 6 | 8.0.30703 7 | 2.0 8 | {C29F1F5E-C773-4EF1-AD60-2312760276CA} 9 | Library 10 | Properties 11 | QuantBox.OQ.CTP 12 | QuantBox.OQ.CTP 13 | v3.5 14 | 512 15 | 16 | 17 | 18 | true 19 | full 20 | false 21 | ..\..\..\..\..\..\Program Files %28x86%29\SmartQuant Ltd\QuantDeveloper .NET\bin\ 22 | TRACE;DEBUG;CTP,QD 23 | prompt 24 | 4 25 | 26 | 27 | pdbonly 28 | true 29 | ..\..\bin\ 30 | TRACE;CTP 31 | prompt 32 | 4 33 | 34 | 35 | 36 | 37 | False 38 | ..\..\..\..\..\..\Program Files (x86)\SmartQuant Ltd\OpenQuant\Bin\QuantBox.CSharp2CTP.dll 39 | 40 | 41 | ..\..\..\..\..\..\Program Files (x86)\SmartQuant Ltd\OpenQuant\Bin\QuantBox.OQ.Extensions.dll 42 | 43 | 44 | False 45 | ..\reference\using\SmartQuant.dll 46 | 47 | 48 | ..\reference\using\SmartQuant.Data.dll 49 | 50 | 51 | False 52 | ..\reference\using\SmartQuant.Execution.dll 53 | 54 | 55 | False 56 | ..\reference\using\SmartQuant.FIX.dll 57 | 58 | 59 | False 60 | ..\reference\using\SmartQuant.Instruments.dll 61 | 62 | 63 | False 64 | ..\reference\using\SmartQuant.Providers.dll 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | Form 92 | 93 | 94 | ServersManagerForm.cs 95 | 96 | 97 | 98 | 99 | 100 | 101 | ServersManagerForm.cs 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | {2c5c5377-e34c-4515-9404-3461aae70a8a} 111 | QuantBox.Helper.CTP.Net35 112 | 113 | 114 | 115 | 122 | -------------------------------------------------------------------------------- /src/QuantBox.OQ.CTP/QuantBox.OQ.CTPZQ.OQ3.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Debug 5 | AnyCPU 6 | 8.0.30703 7 | 2.0 8 | {49F99E4A-F8D0-4CB8-84B2-39B4F6AC3576} 9 | Library 10 | Properties 11 | QuantBox.OQ.CTPZQ 12 | QuantBox.OQ.CTPZQ 13 | v4.0 14 | 512 15 | 16 | 17 | 18 | true 19 | full 20 | false 21 | ..\..\..\..\..\..\Program Files %28x86%29\SmartQuant Ltd\OpenQuant\Framework\bin\ 22 | TRACE;DEBUG;CTPZQ,OQ 23 | prompt 24 | 4 25 | 26 | 27 | pdbonly 28 | true 29 | ..\..\bin\ 30 | TRACE;CTPZQ,OQ 31 | prompt 32 | 4 33 | 34 | 35 | 36 | False 37 | ..\..\..\..\..\..\Program Files (x86)\SmartQuant Ltd\OpenQuant\Bin\Newtonsoft.Json.dll 38 | 39 | 40 | 41 | ..\..\..\..\..\..\Program Files (x86)\SmartQuant Ltd\OpenQuant\Bin\QuantBox.CSharp2CTPZQ.dll 42 | 43 | 44 | False 45 | ..\..\..\..\..\..\Program Files (x86)\SmartQuant Ltd\OpenQuant\Bin\QuantBox.OQ.Extensions.dll 46 | 47 | 48 | False 49 | ..\reference\using\SmartQuant.dll 50 | 51 | 52 | ..\reference\using\SmartQuant.Data.dll 53 | 54 | 55 | False 56 | ..\reference\using\SmartQuant.Execution.dll 57 | 58 | 59 | False 60 | ..\reference\using\SmartQuant.FIX.dll 61 | 62 | 63 | False 64 | ..\reference\using\SmartQuant.Instruments.dll 65 | 66 | 67 | False 68 | ..\reference\using\SmartQuant.Providers.dll 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | Form 98 | 99 | 100 | ServersManagerForm.cs 101 | 102 | 103 | 104 | 105 | 106 | 107 | ServersManagerForm.cs 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | {5caeb588-ba0f-4313-8b78-5101e97d695a} 117 | QuantBox.Helper.CTPZQ.Net40 118 | 119 | 120 | 121 | 128 | -------------------------------------------------------------------------------- /src/QuantBox.OQ.CTP/QuantBox.OQ.CTPZQ.QD.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Debug 5 | AnyCPU 6 | 8.0.30703 7 | 2.0 8 | {38331CDE-8393-490E-B56B-CA5A2E6DE01B} 9 | Library 10 | Properties 11 | QuantBox.OQ.CTPZQ 12 | QuantBox.OQ.CTPZQ 13 | v3.5 14 | 512 15 | 16 | 17 | 18 | true 19 | full 20 | false 21 | ..\..\..\..\..\..\Program Files %28x86%29\SmartQuant Ltd\OpenQuant\Framework\bin\ 22 | TRACE;DEBUG;CTPZQ,QD 23 | prompt 24 | 4 25 | 26 | 27 | pdbonly 28 | true 29 | ..\..\bin\ 30 | TRACE;CTPZQ 31 | prompt 32 | 4 33 | 34 | 35 | 36 | 37 | ..\..\..\..\..\..\Program Files (x86)\SmartQuant Ltd\OpenQuant\Bin\QuantBox.CSharp2CTPZQ.dll 38 | 39 | 40 | False 41 | ..\reference\using\SmartQuant.dll 42 | 43 | 44 | ..\reference\using\SmartQuant.Data.dll 45 | 46 | 47 | False 48 | ..\reference\using\SmartQuant.Execution.dll 49 | 50 | 51 | False 52 | ..\reference\using\SmartQuant.FIX.dll 53 | 54 | 55 | False 56 | ..\reference\using\SmartQuant.Instruments.dll 57 | 58 | 59 | False 60 | ..\reference\using\SmartQuant.Providers.dll 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | Form 88 | 89 | 90 | ServersManagerForm.cs 91 | 92 | 93 | 94 | 95 | 96 | 97 | ServersManagerForm.cs 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | {4a6b6c0f-d169-4358-b42f-fae8743de897} 107 | QuantBox.Helper.CTPZQ.Net35 108 | 109 | 110 | 111 | 118 | -------------------------------------------------------------------------------- /src/QuantBox.OQ.CTP/QuoteApiWrapper.cs: -------------------------------------------------------------------------------- 1 | using NLog; 2 | using QuantBox.CSharp2CTP; 3 | using SmartQuant; 4 | using System; 5 | using System.Collections.Generic; 6 | using System.IO; 7 | using System.Linq; 8 | using System.Text; 9 | 10 | namespace QuantBox.OQ.CTP 11 | { 12 | public class QuoteApiWrapper : ApiWrapper 13 | { 14 | public fnOnRtnDepthMarketData _fnOnRtnDepthMarketData_Holder; 15 | 16 | public void Connect(ServerItem server, AccountItem account) 17 | { 18 | tempPath = Framework.Installation.TempDir.FullName + Path.DirectorySeparatorChar + server.BrokerID + Path.DirectorySeparatorChar + account.InvestorId; 19 | Directory.CreateDirectory(tempPath); 20 | 21 | Disconnect_MD(); 22 | 23 | Connect_MsgQueue(); 24 | Connect_MD(); 25 | } 26 | 27 | public void Disconnect() 28 | { 29 | Disconnect_MD(); 30 | Disconnect_MsgQueue(); 31 | } 32 | 33 | private void Connect_MD() 34 | { 35 | lock (_lock) 36 | { 37 | if (null == Api || IntPtr.Zero == Api) 38 | { 39 | Api = MdApi.MD_CreateMdApi(); 40 | MdApi.CTP_RegOnRtnDepthMarketData(m_pMsgQueue, _fnOnRtnDepthMarketData_Holder); 41 | MdApi.MD_RegMsgQueue2MdApi(Api, m_pMsgQueue); 42 | MdApi.MD_Connect(Api, tempPath, string.Join(";", server.MarketData.ToArray()), server.BrokerID, account.InvestorId, account.Password); 43 | } 44 | } 45 | } 46 | 47 | private void Disconnect_MD() 48 | { 49 | lock (_lock) 50 | { 51 | if (null != Api && IntPtr.Zero != Api) 52 | { 53 | MdApi.MD_RegMsgQueue2MdApi(Api, IntPtr.Zero); 54 | MdApi.MD_ReleaseMdApi(Api); 55 | Api = IntPtr.Zero; 56 | } 57 | IsConnected = false; 58 | } 59 | } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/QuantBox.OQ.CTP/ServerItem.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.ComponentModel; 6 | 7 | 8 | namespace QuantBox.OQ.CTP 9 | { 10 | [DefaultPropertyAttribute("Label")] 11 | public class ServerItem 12 | { 13 | private const string OPEN_QUANT = "OpenQuant"; 14 | private string userProductInfo = OPEN_QUANT; 15 | 16 | [CategoryAttribute("客户端认证"), 17 | DescriptionAttribute("区别于其它客户端的标识"), 18 | DefaultValue(OPEN_QUANT)] 19 | public string UserProductInfo 20 | { 21 | get { return userProductInfo; } 22 | set { userProductInfo = value; } 23 | } 24 | 25 | [CategoryAttribute("客户端认证"), 26 | DescriptionAttribute("如果不需要认证此处一定要置为空")] 27 | public string AuthCode 28 | { 29 | get; 30 | set; 31 | } 32 | 33 | [CategoryAttribute("服务端信息")] 34 | public string BrokerID 35 | { 36 | get; 37 | set; 38 | } 39 | 40 | private BindingList trading = new BindingList(); 41 | [CategoryAttribute("服务端信息"), 42 | DescriptionAttribute("交易服务器地址")] 43 | public BindingList Trading 44 | { 45 | get{ return trading; } 46 | set{ trading = value;} 47 | } 48 | 49 | private BindingList marketData = new BindingList(); 50 | [CategoryAttribute("服务端信息"), 51 | DescriptionAttribute("行情服务器地址")] 52 | public BindingList MarketData 53 | { 54 | get { return marketData; } 55 | set { marketData = value; } 56 | } 57 | 58 | [CategoryAttribute("标签"), 59 | DescriptionAttribute("标签不能重复")] 60 | public string Label 61 | { 62 | get; 63 | set; 64 | } 65 | 66 | public override string ToString() 67 | { 68 | return "标签不能重复"; 69 | } 70 | 71 | [BrowsableAttribute(false)] 72 | public string Name 73 | { 74 | get { return Label; } 75 | } 76 | 77 | public ServerItem() 78 | { 79 | marketData.ListChanged += Settings_ListChanged; 80 | trading.ListChanged += Settings_ListChanged; 81 | } 82 | 83 | public event EventHandler Changed; 84 | 85 | void Settings_ListChanged(object sender, ListChangedEventArgs e) 86 | { 87 | EventHandler handler = Changed; 88 | if (handler != null) 89 | { 90 | handler(this, EventArgs.Empty); 91 | } 92 | } 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /src/QuantBox.OQ.CTP/ServersManagerForm.Designer.cs: -------------------------------------------------------------------------------- 1 | #if CTP 2 | namespace QuantBox.OQ.CTP 3 | #elif CTPZQ 4 | namespace QuantBox.OQ.CTPZQ 5 | #endif 6 | { 7 | partial class ServersManagerForm 8 | { 9 | /// 10 | /// Required designer variable. 11 | /// 12 | private System.ComponentModel.IContainer components = null; 13 | 14 | /// 15 | /// Clean up any resources being used. 16 | /// 17 | /// true if managed resources should be disposed; otherwise, false. 18 | protected override void Dispose(bool disposing) 19 | { 20 | if (disposing && (components != null)) 21 | { 22 | components.Dispose(); 23 | } 24 | base.Dispose(disposing); 25 | } 26 | 27 | #region Windows Form Designer generated code 28 | 29 | /// 30 | /// Required method for Designer support - do not modify 31 | /// the contents of this method with the code editor. 32 | /// 33 | private void InitializeComponent() 34 | { 35 | this.components = new System.ComponentModel.Container(); 36 | this.listBoxBroker = new System.Windows.Forms.ListBox(); 37 | this.brokerItemBindingSource = new System.Windows.Forms.BindingSource(this.components); 38 | this.listBoxServer = new System.Windows.Forms.ListBox(); 39 | this.serverItemBindingSource = new System.Windows.Forms.BindingSource(this.components); 40 | this.buttonAdd = new System.Windows.Forms.Button(); 41 | this.buttonRemove = new System.Windows.Forms.Button(); 42 | this.textBoxUrl = new System.Windows.Forms.TextBox(); 43 | this.buttonUpdate = new System.Windows.Forms.Button(); 44 | ((System.ComponentModel.ISupportInitialize)(this.brokerItemBindingSource)).BeginInit(); 45 | ((System.ComponentModel.ISupportInitialize)(this.serverItemBindingSource)).BeginInit(); 46 | this.SuspendLayout(); 47 | // 48 | // listBoxBroker 49 | // 50 | this.listBoxBroker.DataSource = this.brokerItemBindingSource; 51 | this.listBoxBroker.DisplayMember = "Label"; 52 | this.listBoxBroker.FormattingEnabled = true; 53 | this.listBoxBroker.Location = new System.Drawing.Point(12, 50); 54 | this.listBoxBroker.Name = "listBoxBroker"; 55 | this.listBoxBroker.Size = new System.Drawing.Size(216, 264); 56 | this.listBoxBroker.TabIndex = 0; 57 | // 58 | // brokerItemBindingSource 59 | // 60 | this.brokerItemBindingSource.DataSource = typeof(QuantBox.OQ.CTP.BrokerItem); 61 | // 62 | // listBoxServer 63 | // 64 | this.listBoxServer.DataSource = this.serverItemBindingSource; 65 | this.listBoxServer.DisplayMember = "Label"; 66 | this.listBoxServer.FormattingEnabled = true; 67 | this.listBoxServer.Location = new System.Drawing.Point(289, 50); 68 | this.listBoxServer.Name = "listBoxServer"; 69 | this.listBoxServer.Size = new System.Drawing.Size(216, 264); 70 | this.listBoxServer.TabIndex = 0; 71 | // 72 | // serverItemBindingSource 73 | // 74 | this.serverItemBindingSource.DataSource = typeof(QuantBox.OQ.CTP.ServerItem); 75 | // 76 | // buttonAdd 77 | // 78 | this.buttonAdd.Location = new System.Drawing.Point(234, 50); 79 | this.buttonAdd.Name = "buttonAdd"; 80 | this.buttonAdd.Size = new System.Drawing.Size(49, 23); 81 | this.buttonAdd.TabIndex = 1; 82 | this.buttonAdd.Text = "=>"; 83 | this.buttonAdd.UseVisualStyleBackColor = true; 84 | this.buttonAdd.Click += new System.EventHandler(this.buttonAdd_Click); 85 | // 86 | // buttonRemove 87 | // 88 | this.buttonRemove.Location = new System.Drawing.Point(234, 79); 89 | this.buttonRemove.Name = "buttonRemove"; 90 | this.buttonRemove.Size = new System.Drawing.Size(49, 23); 91 | this.buttonRemove.TabIndex = 1; 92 | this.buttonRemove.Text = "<-"; 93 | this.buttonRemove.UseVisualStyleBackColor = true; 94 | this.buttonRemove.Click += new System.EventHandler(this.buttonRemove_Click); 95 | // 96 | // textBoxUrl 97 | // 98 | this.textBoxUrl.Location = new System.Drawing.Point(12, 12); 99 | this.textBoxUrl.Name = "textBoxUrl"; 100 | this.textBoxUrl.Size = new System.Drawing.Size(412, 20); 101 | this.textBoxUrl.TabIndex = 2; 102 | this.textBoxUrl.Text = "https://raw.github.com/QuantBox/OpenQuant-CTP/master/CTP.Brokers.xml"; 103 | // 104 | // buttonUpdate 105 | // 106 | this.buttonUpdate.Location = new System.Drawing.Point(430, 9); 107 | this.buttonUpdate.Name = "buttonUpdate"; 108 | this.buttonUpdate.Size = new System.Drawing.Size(75, 23); 109 | this.buttonUpdate.TabIndex = 3; 110 | this.buttonUpdate.Text = "在线更新"; 111 | this.buttonUpdate.UseVisualStyleBackColor = true; 112 | this.buttonUpdate.Click += new System.EventHandler(this.buttonUpdate_Click); 113 | // 114 | // ServersManagerForm 115 | // 116 | this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); 117 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; 118 | this.ClientSize = new System.Drawing.Size(519, 334); 119 | this.Controls.Add(this.buttonUpdate); 120 | this.Controls.Add(this.textBoxUrl); 121 | this.Controls.Add(this.buttonRemove); 122 | this.Controls.Add(this.buttonAdd); 123 | this.Controls.Add(this.listBoxServer); 124 | this.Controls.Add(this.listBoxBroker); 125 | this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedToolWindow; 126 | this.Name = "ServersManagerForm"; 127 | this.Text = "经纪商 - 服务器地址 列表"; 128 | this.Load += new System.EventHandler(this.ServersManagerForm_Load); 129 | ((System.ComponentModel.ISupportInitialize)(this.brokerItemBindingSource)).EndInit(); 130 | ((System.ComponentModel.ISupportInitialize)(this.serverItemBindingSource)).EndInit(); 131 | this.ResumeLayout(false); 132 | this.PerformLayout(); 133 | 134 | } 135 | 136 | #endregion 137 | 138 | private System.Windows.Forms.ListBox listBoxBroker; 139 | private System.Windows.Forms.ListBox listBoxServer; 140 | private System.Windows.Forms.Button buttonAdd; 141 | private System.Windows.Forms.Button buttonRemove; 142 | private System.Windows.Forms.BindingSource serverItemBindingSource; 143 | private System.Windows.Forms.BindingSource brokerItemBindingSource; 144 | private System.Windows.Forms.TextBox textBoxUrl; 145 | private System.Windows.Forms.Button buttonUpdate; 146 | } 147 | } -------------------------------------------------------------------------------- /src/QuantBox.OQ.CTP/ServersManagerForm.cs: -------------------------------------------------------------------------------- 1 | using SmartQuant; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.ComponentModel; 5 | using System.Data; 6 | using System.Drawing; 7 | using System.Linq; 8 | using System.Net; 9 | using System.Text; 10 | using System.Windows.Forms; 11 | using QuantBox.OQ.CTP; 12 | 13 | #if CTP 14 | namespace QuantBox.OQ.CTP 15 | #elif CTPZQ 16 | namespace QuantBox.OQ.CTPZQ 17 | #endif 18 | { 19 | public partial class ServersManagerForm : Form 20 | { 21 | private APIProvider provider; 22 | public void Init(APIProvider provider) 23 | { 24 | this.provider = provider; 25 | 26 | textBoxUrl.Text = string.Format(@"https://raw.github.com/QuantBox/OpenQuant-CTP/master/{0}.Brokers.xml", provider.Name); 27 | } 28 | 29 | public ServersManagerForm() 30 | { 31 | InitializeComponent(); 32 | } 33 | 34 | private void ServersManagerForm_Load(object sender, EventArgs e) 35 | { 36 | provider.LoadBrokers(); 37 | 38 | serverItemBindingSource.DataSource = provider.Server; 39 | brokerItemBindingSource.DataSource = provider.Brokers; 40 | } 41 | 42 | private void buttonRemove_Click(object sender, EventArgs e) 43 | { 44 | int nSel = listBoxServer.SelectedIndex; 45 | if (nSel >= 0) 46 | { 47 | provider.Server.RemoveAt(nSel); 48 | provider.SettingsChanged(); 49 | } 50 | } 51 | 52 | private void buttonAdd_Click(object sender, EventArgs e) 53 | { 54 | int nSel = listBoxBroker.SelectedIndex; 55 | if (nSel >= 0) 56 | { 57 | BrokerItem bi = provider.Brokers[nSel]; 58 | foreach(ServerItem si in bi.Server) 59 | { 60 | provider.Server.Add(si); 61 | } 62 | provider.SettingsChanged(); 63 | } 64 | } 65 | 66 | private void buttonUpdate_Click(object sender, EventArgs e) 67 | { 68 | ServicePointManager.ServerCertificateValidationCallback = delegate { return true; }; 69 | 70 | WebClient wc = new WebClient(); 71 | try 72 | { 73 | buttonUpdate.Enabled = false; 74 | 75 | wc.DownloadFile(textBoxUrl.Text, provider.brokersFile); 76 | 77 | provider.LoadBrokers(); 78 | brokerItemBindingSource.DataSource = provider.Brokers; 79 | 80 | MessageBox.Show("远程配置下载成功!"); 81 | } 82 | catch (Exception ex) 83 | { 84 | MessageBox.Show(ex.Message); 85 | } 86 | finally 87 | { 88 | wc.Dispose(); 89 | buttonUpdate.Enabled = true; 90 | } 91 | } 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /src/QuantBox.OQ.CTP/ServersManagerForm.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | text/microsoft-resx 110 | 111 | 112 | 2.0 113 | 114 | 115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | 118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 119 | 120 | 121 | 205, 17 122 | 123 | 124 | 17, 17 125 | 126 | -------------------------------------------------------------------------------- /src/QuantBox.OQ.CTP/ServersManagerTypeEditor.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel; 4 | using System.Drawing.Design; 5 | using System.Linq; 6 | using System.Text; 7 | using System.Windows.Forms.Design; 8 | 9 | #if CTP 10 | namespace QuantBox.OQ.CTP 11 | #elif CTPZQ 12 | namespace QuantBox.OQ.CTPZQ 13 | #endif 14 | { 15 | class ServersManagerTypeEditor : UITypeEditor 16 | { 17 | // Methods 18 | public override object EditValue(ITypeDescriptorContext context, IServiceProvider provider, object value) 19 | { 20 | if (((context == null) || (context.Instance == null)) || (provider == null)) 21 | { 22 | return base.EditValue(context, provider, value); 23 | } 24 | IWindowsFormsEditorService service = provider.GetService(typeof(IWindowsFormsEditorService)) as IWindowsFormsEditorService; 25 | if (service != null) 26 | { 27 | ServersManagerForm dialog = new ServersManagerForm(); 28 | dialog.Init(context.Instance as APIProvider); 29 | service.ShowDialog(dialog); 30 | } 31 | return value; 32 | } 33 | 34 | public override UITypeEditorEditStyle GetEditStyle(ITypeDescriptorContext context) 35 | { 36 | if ((context != null) && (context.Instance != null)) 37 | { 38 | return UITypeEditorEditStyle.Modal; 39 | } 40 | return base.GetEditStyle(context); 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/QuantBox.OQ.CTP/TraderApiWrapper.cs: -------------------------------------------------------------------------------- 1 | using NLog; 2 | using QuantBox.CSharp2CTP; 3 | using SmartQuant; 4 | using System; 5 | using System.Collections.Generic; 6 | using System.IO; 7 | using System.Linq; 8 | using System.Text; 9 | 10 | namespace QuantBox.OQ.CTP 11 | { 12 | public class TraderApiWrapper:ApiWrapper 13 | { 14 | public fnOnErrRtnOrderAction _fnOnErrRtnOrderAction_Holder; 15 | public fnOnErrRtnOrderInsert _fnOnErrRtnOrderInsert_Holder; 16 | public fnOnRspOrderAction _fnOnRspOrderAction_Holder; 17 | public fnOnRspOrderInsert _fnOnRspOrderInsert_Holder; 18 | public fnOnRspQryDepthMarketData _fnOnRspQryDepthMarketData_Holder; 19 | public fnOnRspQryInstrument _fnOnRspQryInstrument_Holder; 20 | public fnOnRspQryInstrumentCommissionRate _fnOnRspQryInstrumentCommissionRate_Holder; 21 | public fnOnRspQryInvestorPosition _fnOnRspQryInvestorPosition_Holder; 22 | public fnOnRspQryTradingAccount _fnOnRspQryTradingAccount_Holder; 23 | public fnOnRtnInstrumentStatus _fnOnRtnInstrumentStatus_Holder; 24 | public fnOnRtnOrder _fnOnRtnOrder_Holder; 25 | public fnOnRtnTrade _fnOnRtnTrade_Holder; 26 | 27 | #if CTP 28 | public fnOnRspQryInstrumentMarginRate _fnOnRspQryInstrumentMarginRate_Holder; 29 | #endif 30 | 31 | private THOST_TE_RESUME_TYPE ResumeType; 32 | 33 | public void Connect(ServerItem server, AccountItem account,THOST_TE_RESUME_TYPE resumeType) 34 | { 35 | tempPath = Framework.Installation.TempDir.FullName + Path.DirectorySeparatorChar + server.BrokerID + Path.DirectorySeparatorChar + account.InvestorId; 36 | Directory.CreateDirectory(tempPath); 37 | ResumeType = resumeType; 38 | 39 | Disconnect_TD(); 40 | 41 | Connect_MsgQueue(); 42 | Connect_TD(); 43 | } 44 | 45 | public void Disconnect() 46 | { 47 | Disconnect_TD(); 48 | Disconnect_MsgQueue(); 49 | } 50 | 51 | //建立交易 52 | private void Connect_TD() 53 | { 54 | lock (_lock) 55 | { 56 | if (null == Api || IntPtr.Zero == Api) 57 | { 58 | Api = TraderApi.TD_CreateTdApi(); 59 | TraderApi.CTP_RegOnErrRtnOrderAction(m_pMsgQueue, _fnOnErrRtnOrderAction_Holder); 60 | TraderApi.CTP_RegOnErrRtnOrderInsert(m_pMsgQueue, _fnOnErrRtnOrderInsert_Holder); 61 | TraderApi.CTP_RegOnRspOrderAction(m_pMsgQueue, _fnOnRspOrderAction_Holder); 62 | TraderApi.CTP_RegOnRspOrderInsert(m_pMsgQueue, _fnOnRspOrderInsert_Holder); 63 | TraderApi.CTP_RegOnRspQryDepthMarketData(m_pMsgQueue, _fnOnRspQryDepthMarketData_Holder); 64 | TraderApi.CTP_RegOnRspQryInstrument(m_pMsgQueue, _fnOnRspQryInstrument_Holder); 65 | TraderApi.CTP_RegOnRspQryInstrumentCommissionRate(m_pMsgQueue, _fnOnRspQryInstrumentCommissionRate_Holder); 66 | TraderApi.CTP_RegOnRspQryInvestorPosition(m_pMsgQueue, _fnOnRspQryInvestorPosition_Holder); 67 | TraderApi.CTP_RegOnRspQryTradingAccount(m_pMsgQueue, _fnOnRspQryTradingAccount_Holder); 68 | TraderApi.CTP_RegOnRtnInstrumentStatus(m_pMsgQueue, _fnOnRtnInstrumentStatus_Holder); 69 | TraderApi.CTP_RegOnRtnOrder(m_pMsgQueue, _fnOnRtnOrder_Holder); 70 | TraderApi.CTP_RegOnRtnTrade(m_pMsgQueue, _fnOnRtnTrade_Holder); 71 | #if CTP 72 | TraderApi.CTP_RegOnRspQryInstrumentMarginRate(m_pMsgQueue, _fnOnRspQryInstrumentMarginRate_Holder); 73 | #endif 74 | TraderApi.TD_RegMsgQueue2TdApi(Api, m_pMsgQueue); 75 | TraderApi.TD_Connect(Api, tempPath, string.Join(";", server.Trading.ToArray()), 76 | server.BrokerID, account.InvestorId, account.Password, 77 | ResumeType, 78 | server.UserProductInfo, server.AuthCode); 79 | 80 | //向单例对象中注入操作用句柄 81 | //CTPAPI.GetInstance().__RegTdApi(m_pTdApi); 82 | } 83 | } 84 | } 85 | 86 | private void Disconnect_TD() 87 | { 88 | lock (_lock) 89 | { 90 | if (null != Api && IntPtr.Zero != Api) 91 | { 92 | TraderApi.TD_RegMsgQueue2TdApi(Api, IntPtr.Zero); 93 | TraderApi.TD_ReleaseTdApi(Api); 94 | Api = IntPtr.Zero; 95 | 96 | //CTPAPI.GetInstance().__RegTdApi(m_pTdApi); 97 | } 98 | IsConnected = false; 99 | } 100 | } 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /src/QuantBox.OQ.CTP/WinAPI.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Runtime.InteropServices; 3 | 4 | #if CTP 5 | namespace QuantBox.OQ.CTP 6 | #elif CTPZQ 7 | namespace QuantBox.OQ.CTPZQ 8 | #endif 9 | { 10 | class WinAPI 11 | { 12 | //imports SetLocalTime function from kernel32.dll 13 | [DllImport("kernel32.dll", SetLastError = true)] 14 | public static extern int SetLocalTime(ref SystemTime lpSystemTime); 15 | 16 | //struct for date/time apis 17 | [StructLayout(LayoutKind.Sequential)] 18 | public struct SystemTime 19 | { 20 | public short wYear; 21 | public short wMonth; 22 | public short wDayOfWeek; 23 | public short wDay; 24 | public short wHour; 25 | public short wMinute; 26 | public short wSecond; 27 | public short wMilliseconds; 28 | } 29 | 30 | public static int SetLocalTime(DateTime datetime) 31 | { 32 | SystemTime systNew = new SystemTime(); 33 | 34 | // 设置属性 35 | systNew.wDay = (short)datetime.Day; 36 | systNew.wMonth = (short)datetime.Month; 37 | systNew.wYear = (short)datetime.Year; 38 | systNew.wHour = (short)datetime.Hour; 39 | systNew.wMinute = (short)datetime.Minute; 40 | systNew.wSecond = (short)datetime.Second; 41 | systNew.wMilliseconds = (short)datetime.Millisecond; 42 | 43 | // 调用API,更新系统时间 44 | return SetLocalTime(ref systNew); 45 | } 46 | } 47 | } 48 | --------------------------------------------------------------------------------