-
Notifications
You must be signed in to change notification settings - Fork 95
/
Copy pathbasic-tutorial-1.html
577 lines (509 loc) · 34.3 KB
/
basic-tutorial-1.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
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
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
<!DOCTYPE html>
<html lang="zh"
>
<head>
<title>Python量化交易平台开发教程系列1-类CTP交易API的工作原理 - vn.py</title>
<!-- Using the latest rendering mode for IE -->
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link href="/images/favicon.png" rel="icon">
<link rel="canonical" href="/basic-tutorial-1.html">
<meta name="author" content="用Python的交易员" />
<meta name="description" content="原创文章,转载请注明出处:用Python的交易员 类CTP交易API简介 国内程序化交易技术的爆发式发展几乎就是起源于上期技术公司基于CTP柜台推出了交易API,使得用户可以随意开发自己的交易软件直接连接到交易柜台上进行交易,同时CTP API的设计模式也成为了许多其他柜台上交易API的设计标准,本人已知的类CTP交易API包括: 上期CTP 飞马 华宝证券LTS 飞创Xspeed 金仕达 恒生UFT 所以这个教程系列选择从类CTP交易API中的LTS API开始来介绍API的Python封装方法,真正掌握了以后想要做其他类型API(比如恒生的T2)的封装也只是大同小异而已。 LTS API文件说明 通常当用户从网上下载API的压缩包,解压后会看到以下的文件: .h文件:C++的头文件,包含了API的内部结构信息,开发C++程序时需要包含在项目内 .dll文件:windows下的动态链接库文件,API的实体,开发C++程序编译和链接时用,使用开发好的程序时也必须放在程序的文件夹内 .lib文件:windows下的库文件,编译和链接时用,程序开发好后无需放在程序的文件夹内 .so文件:linux下的动态链接库文件,其他同.dll文件 找不到压缩包的读者可以在这里直接看https://github.com/vnpy/vnpy ..." />
<meta property="og:site_name" content="vn.py" />
<meta property="og:type" content="article"/>
<meta property="og:title" content="Python量化交易平台开发教程系列1-类CTP交易API的工作原理"/>
<meta property="og:url" content="/basic-tutorial-1.html"/>
<meta property="og:description" content="原创文章,转载请注明出处:用Python的交易员 类CTP交易API简介 国内程序化交易技术的爆发式发展几乎就是起源于上期技术公司基于CTP柜台推出了交易API,使得用户可以随意开发自己的交易软件直接连接到交易柜台上进行交易,同时CTP API的设计模式也成为了许多其他柜台上交易API的设计标准,本人已知的类CTP交易API包括: 上期CTP 飞马 华宝证券LTS 飞创Xspeed 金仕达 恒生UFT 所以这个教程系列选择从类CTP交易API中的LTS API开始来介绍API的Python封装方法,真正掌握了以后想要做其他类型API(比如恒生的T2)的封装也只是大同小异而已。 LTS API文件说明 通常当用户从网上下载API的压缩包,解压后会看到以下的文件: .h文件:C++的头文件,包含了API的内部结构信息,开发C++程序时需要包含在项目内 .dll文件:windows下的动态链接库文件,API的实体,开发C++程序编译和链接时用,使用开发好的程序时也必须放在程序的文件夹内 .lib文件:windows下的库文件,编译和链接时用,程序开发好后无需放在程序的文件夹内 .so文件:linux下的动态链接库文件,其他同.dll文件 找不到压缩包的读者可以在这里直接看https://github.com/vnpy/vnpy ..."/>
<meta property="article:published_time" content="2015-03-05" />
<meta property="article:section" content="文章" />
<meta property="article:author" content="用Python的交易员" />
<!-- Bootstrap -->
<link rel="stylesheet" href="/theme/css/bootstrap.readable.min.css" type="text/css"/>
<link href="/theme/css/font-awesome.min.css" rel="stylesheet">
<link href="/theme/css/pygments/monokai.css" rel="stylesheet">
<link rel="stylesheet" href="/theme/css/style.css" type="text/css"/>
<script>
var _hmt = _hmt || [];
(function() {
var hm = document.createElement("script");
hm.src = "//hm.baidu.com/hm.js?e8c7573f82d43fa50c895a8e28c49ceb";
var s = document.getElementsByTagName("script")[0];
s.parentNode.insertBefore(hm, s);
})();
</script>
</head>
<body>
<div class="navbar navbar-default navbar-fixed-top" role="navigation">
<div class="container">
<div class="navbar-header">
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-ex1-collapse">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a href="/" class="navbar-brand">
<img src="/images/favicon.png" width=""/> vn.py </a>
</div>
<div class="collapse navbar-collapse navbar-ex1-collapse">
<ul class="nav navbar-nav">
<li><a href="/pages/quickstart.html">
Quick Start
</a></li>
<li><a href="/pages/tutorial.html">
教程
</a></li>
<li><a href="/pages/blog.html">
日志
</a></li>
<li><a href="/pages/screenshot.html">
截图
</a></li>
<li><a href="/pages/community.html">
社区
</a></li>
<li><a href="/pages/api.html">
API接口
</a></li>
<li><a href="/pages/download.html">
下载
</a></li>
</ul>
<ul class="nav navbar-nav navbar-right">
<li><a href="/archives.html"><i class="fa fa-th-list"></i><span class="icon-label">Archives</span></a></li>
</ul>
</div>
<!-- /.navbar-collapse -->
</div>
</div> <!-- /.navbar -->
<!-- Banner -->
<style>
#banner{
background-image:url("/images/banner.png");
}
</style>
<div id="banner">
<div class="container">
<div class="copy">
<h1>vn.py</h1>
<p class="intro">Developed by traders, for traders.</p>
</div>
</div>
</div><!-- End Banner -->
<div class="container">
<div class="row">
<div class="col-sm-9">
<section id="content">
<article>
<header class="page-header">
<h1>
<a href="/basic-tutorial-1.html"
rel="bookmark"
title="Permalink to Python量化交易平台开发教程系列1-类CTP交易API的工作原理">
Python量化交易平台开发教程系列1-类CTP交易API的工作原理
</a>
</h1>
</header>
<div class="entry-content">
<div class="panel">
<div class="panel-body">
<footer class="post-info">
<span class="label label-default">Date</span>
<span class="published">
<i class="fa fa-calendar"></i><time datetime="2015-03-05T14:28:49+08:00"> 2015-03-05(周四)</time>
</span>
</footer><!-- /.post-info --> </div>
</div>
<p>原创文章,转载请注明出处:用Python的交易员</p>
<h2>类CTP交易API简介</h2>
<p>国内程序化交易技术的爆发式发展几乎就是起源于上期技术公司基于CTP柜台推出了交易API,使得用户可以随意开发自己的交易软件直接连接到交易柜台上进行交易,同时CTP API的设计模式也成为了许多其他柜台上交易API的设计标准,本人已知的类CTP交易API包括:</p>
<ol>
<li>
<p>上期CTP </p>
</li>
<li>
<p>飞马 </p>
</li>
<li>
<p>华宝证券LTS</p>
</li>
<li>
<p>飞创Xspeed</p>
</li>
<li>
<p>金仕达</p>
</li>
<li>
<p>恒生UFT</p>
</li>
</ol>
<p>所以这个教程系列选择从类CTP交易API中的LTS API开始来介绍API的Python封装方法,真正掌握了以后想要做其他类型API(比如恒生的T2)的封装也只是大同小异而已。</p>
<h2>LTS API文件说明</h2>
<p>通常当用户从网上下载API的压缩包,解压后会看到以下的文件:
<img alt="" src="http://7x2w1m.com1.z0.glb.clouddn.com/API文件列表.jpg" /></p>
<ul>
<li>.h文件:C++的头文件,包含了API的内部结构信息,开发C++程序时需要包含在项目内</li>
<li>.dll文件:windows下的动态链接库文件,API的实体,开发C++程序编译和链接时用,使用开发好的程序时也必须放在程序的文件夹内 </li>
<li>.lib文件:windows下的库文件,编译和链接时用,程序开发好后无需放在程序的文件夹内</li>
<li>.so文件:linux下的动态链接库文件,其他同.dll文件</li>
</ul>
<p>找不到压缩包的读者可以在这里直接看<a href="https://github.com/vnpy/vnpy/tree/master/vn.lts/ltsapi" title="https://github.com/vnpy/vnpy/tree/master/vn.lts/ltsapi">https://github.com/vnpy/vnpy/tree/master/vn.lts/ltsapi</a>。</p>
<h2>.h头文件介绍</h2>
<p>.dll、.lib、.so文件都是编译好的二进制文件,无法打开,所以从用户角度我们只需关注.h文件中的内容。对于不同的API而言,.h文件的前缀可能有所区别,如LTS是SecurityFtdc,CTP是ThostFtdc,下面分别介绍这4个.h文件。</p>
<h3>ApiDataType.h</h3>
<p>该文件中包含了对API中用到的常量的定义,如以下代码定义了一个产品类型常量对应的字符:</p>
<div class="highlight"><pre><span></span><span class="cp">#define SECURITY_FTDC_PC_Futures '1'</span>
</pre></div>
<p>以及类型的定义,如以下代码定义了产品名称类型是一个长度为21个字符的字符串: </p>
<div class="highlight"><pre><span></span><span class="k">typedef</span> <span class="kt">char</span> <span class="n">TSecurityFtdcProductNameType</span><span class="p">[</span><span class="mi">21</span><span class="p">];</span>
</pre></div>
<h3>ApiStruct.h</h3>
<p>该文件中包含了API中用到的结构体的定义,如以下代码定义了交易所这个结构体的构成:</p>
<div class="highlight"><pre><span></span><span class="c1">///交易所</span>
<span class="k">struct</span> <span class="n">CSecurityFtdcExchangeField</span>
<span class="p">{</span>
<span class="c1">///交易所代码</span>
<span class="n">TSecurityFtdcExchangeIDType</span> <span class="n">ExchangeID</span><span class="p">;</span>
<span class="c1">///交易所名称</span>
<span class="n">TSecurityFtdcExchangeNameType</span> <span class="n">ExchangeName</span><span class="p">;</span>
<span class="c1">///交易所属性</span>
<span class="n">TSecurityFtdcExchangePropertyType</span> <span class="n">ExchangeProperty</span><span class="p">;</span>
<span class="p">};</span>
</pre></div>
<p>例如TSecurityFtdcExchangeIDType这个类型的定义,可以在ApiDataType.h中找到。</p>
<h3>MdApi.h</h3>
<p>该文件中包含了API中的行情相关组件的定义,文件通常开头会有一段这样的内容:</p>
<div class="highlight"><pre><span></span><span class="cp">#if !defined(SECURITY_FTDCMDAPI_H)</span>
<span class="cp">#define SECURITY_FTDCMDAPI_H</span>
<span class="cp">#if _MSC_VER > 1000</span>
<span class="cp">#pragma once</span>
<span class="cp">#endif </span><span class="c1">// _MSC_VER > 1000</span>
<span class="cp">#include</span> <span class="cpf">"SecurityFtdcUserApiStruct.h"</span><span class="cp"></span>
<span class="cp">#if defined(ISLIB) && defined(WIN32)</span>
<span class="cp">#ifdef LIB_MD_API_EXPORT</span>
<span class="cp">#define MD_API_EXPORT __declspec(dllexport)</span>
<span class="cp">#else</span>
<span class="cp">#define MD_API_EXPORT __declspec(dllimport)</span>
<span class="cp">#endif</span>
<span class="cp">#else</span>
<span class="cp">#define MD_API_EXPORT </span>
<span class="cp">#endif</span>
</pre></div>
<p>这些内容主要是一些和操作系统、编译环境相关的定义,一般用户忽略就好(作者其实也不太懂...)。</p>
<p>然后是两个类CSecurityFtdcMdSpi和CSecurityFtdcMdApi的定义。</p>
<h4>CSecurityFtdcMdSpi</h4>
<p>MdSpi类中包含了行情功能相关的回调函数接口,什么是回调函数呢?简单来说就是由于柜台端向用户端发送信息后才会被系统自动调用的函数(非用户主动调用),对应的主动函数会在下面介绍。CSecurityFtdcMdSpi大概看起来是这么个样子:</p>
<div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">CSecurityFtdcMdSpi</span>
<span class="p">{</span>
<span class="k">public</span><span class="o">:</span>
<span class="p">......</span>
<span class="c1">///登录请求响应</span>
<span class="k">virtual</span> <span class="kt">void</span> <span class="n">OnRspUserLogin</span><span class="p">(</span><span class="n">CSecurityFtdcRspUserLoginField</span> <span class="o">*</span><span class="n">pRspUserLogin</span><span class="p">,</span> <span class="n">CSecurityFtdcRspInfoField</span> <span class="o">*</span><span class="n">pRspInfo</span><span class="p">,</span> <span class="kt">int</span> <span class="n">nRequestID</span><span class="p">,</span> <span class="kt">bool</span> <span class="n">bIsLast</span><span class="p">)</span> <span class="p">{};</span>
<span class="p">......</span>
<span class="c1">///深度行情通知</span>
<span class="k">virtual</span> <span class="kt">void</span> <span class="n">OnRtnDepthMarketData</span><span class="p">(</span><span class="n">CSecurityFtdcDepthMarketDataField</span> <span class="o">*</span><span class="n">pDepthMarketData</span><span class="p">)</span> <span class="p">{};</span>
<span class="p">};</span>
</pre></div>
<p>......省略了部分代码。从上面的代码中可以注意到:</p>
<ol>
<li>
<p>回调函数都是以On开头。</p>
</li>
<li>
<p>柜台端向用户端发送的信息经过API处理后,传给我们的是一个结构体的指针,如CSecurityFtdcRspUserLoginField *pRspUserLogin,这里的pRspUserLogin就是一个C++的指针类型,其指向的结构体对象是CSecurityFtdcRspUserLoginField结构的,而该结构的定义可以在ApiStruct.h中找到。</p>
</li>
<li>
<p>不同的回调函数,传过来的参数数量是不同的,OnRspUserLogin中传入的参数包括两个结构体指针,以及一个整数(代表该响应对应的用户请求号)和一个布尔值(该响应是否是这个请求号的最后一次响应)。</p>
</li>
</ol>
<h4>CSecurityFtdcMdApi</h4>
<p>MdApi类中包含了行情功能相关的主动函数结构,顾名思义,主动函数指的是由用户负责进行调用的函数,用于向柜台端发送各种请求和指令,大概样子如下:</p>
<div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">MD_API_EXPORT</span> <span class="n">CSecurityFtdcMdApi</span>
<span class="p">{</span>
<span class="k">public</span><span class="o">:</span>
<span class="c1">///创建MdApi</span>
<span class="c1">///@param pszFlowPath 存贮订阅信息文件的目录,默认为当前目录</span>
<span class="c1">///@return 创建出的UserApi</span>
<span class="c1">///modify for udp marketdata</span>
<span class="k">static</span> <span class="n">CSecurityFtdcMdApi</span> <span class="o">*</span><span class="n">CreateFtdcMdApi</span><span class="p">(</span><span class="k">const</span> <span class="kt">char</span> <span class="o">*</span><span class="n">pszFlowPath</span> <span class="o">=</span> <span class="s">""</span><span class="p">);</span>
<span class="p">......</span>
<span class="c1">///注册回调接口</span>
<span class="c1">///@param pSpi 派生自回调接口类的实例</span>
<span class="k">virtual</span> <span class="kt">void</span> <span class="n">RegisterSpi</span><span class="p">(</span><span class="n">CSecurityFtdcMdSpi</span> <span class="o">*</span><span class="n">pSpi</span><span class="p">)</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
<span class="c1">///订阅行情。</span>
<span class="c1">///@param ppInstrumentID 合约ID </span>
<span class="c1">///@param nCount 要订阅/退订行情的合约个数</span>
<span class="c1">///@remark </span>
<span class="k">virtual</span> <span class="kt">int</span> <span class="nf">SubscribeMarketData</span><span class="p">(</span><span class="kt">char</span> <span class="o">*</span><span class="n">ppInstrumentID</span><span class="p">[],</span> <span class="kt">int</span> <span class="n">nCount</span><span class="p">,</span> <span class="kt">char</span><span class="o">*</span> <span class="n">pExchageID</span><span class="p">)</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">......</span>
<span class="c1">///用户登录请求</span>
<span class="k">virtual</span> <span class="kt">int</span> <span class="n">ReqUserLogin</span><span class="p">(</span><span class="n">CSecurityFtdcReqUserLoginField</span> <span class="o">*</span><span class="n">pReqUserLoginField</span><span class="p">,</span> <span class="kt">int</span> <span class="n">nRequestID</span><span class="p">)</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">......</span>
<span class="p">};</span>
</pre></div>
<p>以上代码中,需要注意的重点包括:</p>
<ol>
<li>
<p>MdApi对象不应该直接创建,而应该通过调用类的静态方法CreateFtdcMdApi创建,传入参数为你希望保存API的通讯用的.con文件的目录(可以选择留空,则.con文件会被放在程序所在的文件夹下)。</p>
</li>
<li>
<p>创建MdSpi对象后,需要使用MdApi对象的RegisterSpi方法将该MdSpi对象的指针注册到MdApi上,也就是告诉MdApi从柜台端收到数据后应该通过哪个对象的回调函数推送给用户。从API的这个设计上作者猜测MdApi中后包含了和柜台端通讯、接收和发送数据包的功能,而MdSpi仅仅是用来实现一个通过回调函数向用户程序推送数据的接口。</p>
</li>
<li>
<p>绝大部分主动函数(以Req开头)在调用时都会用到一个整数类型的参数nRequestID,该参数在整个API的调用中应当保持递增唯一性,从而在收到回调函数推送的数据时,可以知道是由哪次操作引起的。</p>
</li>
</ol>
<h3>TraderApi.h</h3>
<p>该文件中包含了API中的交易相关组件的定义,文件同样以一段看不懂的定义开头,然后包含了两个类CSecurityFtdcTraderSpi和CSecurityFtdcTraderApi,这两个类和MdApi中的两个类在结构上非常接近,区别仅仅在于类包含的方法函数上。</p>
<h4>CSecurityFtdcTraderSpi</h4>
<div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">CSecurityFtdcTraderSpi</span>
<span class="p">{</span>
<span class="k">public</span><span class="o">:</span>
<span class="c1">///当客户端与交易后台建立起通信连接时(还未登录前),该方法被调用。</span>
<span class="k">virtual</span> <span class="kt">void</span> <span class="n">OnFrontConnected</span><span class="p">(){};</span>
<span class="p">...</span>
<span class="c1">///错误应答</span>
<span class="k">virtual</span> <span class="kt">void</span> <span class="n">OnRspError</span><span class="p">(</span><span class="n">CSecurityFtdcRspInfoField</span> <span class="o">*</span><span class="n">pRspInfo</span><span class="p">,</span> <span class="kt">int</span> <span class="n">nRequestID</span><span class="p">,</span> <span class="kt">bool</span> <span class="n">bIsLast</span><span class="p">)</span> <span class="p">{};</span>
<span class="c1">///登录请求响应</span>
<span class="k">virtual</span> <span class="kt">void</span> <span class="nf">OnRspUserLogin</span><span class="p">(</span><span class="n">CSecurityFtdcRspUserLoginField</span> <span class="o">*</span><span class="n">pRspUserLogin</span><span class="p">,</span> <span class="n">CSecurityFtdcRspInfoField</span> <span class="o">*</span><span class="n">pRspInfo</span><span class="p">,</span> <span class="kt">int</span> <span class="n">nRequestID</span><span class="p">,</span> <span class="kt">bool</span> <span class="n">bIsLast</span><span class="p">)</span> <span class="p">{};</span>
<span class="p">...</span>
<span class="c1">///报单通知</span>
<span class="k">virtual</span> <span class="kt">void</span> <span class="n">OnRtnOrder</span><span class="p">(</span><span class="n">CSecurityFtdcOrderField</span> <span class="o">*</span><span class="n">pOrder</span><span class="p">)</span> <span class="p">{};</span>
<span class="p">...</span>
<span class="c1">///报单录入错误回报</span>
<span class="k">virtual</span> <span class="kt">void</span> <span class="n">OnErrRtnOrderInsert</span><span class="p">(</span><span class="n">CSecurityFtdcInputOrderField</span> <span class="o">*</span><span class="n">pInputOrder</span><span class="p">,</span> <span class="n">CSecurityFtdcRspInfoField</span> <span class="o">*</span><span class="n">pRspInfo</span><span class="p">)</span> <span class="p">{};</span>
<span class="p">...</span>
<span class="p">};</span>
</pre></div>
<p>Spi(包括MdSpi和TraderSpi)类的回调函数基本上可以分为以下四种:</p>
<ol>
<li>
<p>以On...开头,这种回调函数通常是返回API连接相关的信息内容,与业务逻辑无关,返回值(即回调函数的参数)通常为空或是简单的整数类型。</p>
</li>
<li>
<p>以OnRsp...开头,这种回调函数通常是针对用户的某次特定业务逻辑操作返回信息内容,返回值通常会包括4个参数:业务逻辑相关结构体的指针,错误信息结构体的指针,本次操作的请求号整数,是否是本次操作最后返回信息的布尔值。其中OnRspError主要用于一些通用错误信息的返回,因此返回的值中不包含业务逻辑相关结构体指针,只有3个返回值。</p>
</li>
<li>
<p>以OnRtn...开头,这种回调函数返回的通常是由柜台向用户主动推送的信息内容,如客户报单状态的变化、成交情况的变化、市场行情等等,因此返回值通常只有1个参数,为推送信息内容结构体的指针。</p>
</li>
<li>
<p>以OnErrRtn...开头,这种回调函数通常由于用户进行的某种业务逻辑操作请求(挂单、撤单等等)在交易所端触发了错误,如用户发出撤单指令、但是该订单在交易所端已经成交,返回值通常是2个参数,即业务逻辑相关结构体的指针和错误信息的指针。</p>
</li>
</ol>
<h4>CSecurityFtdcTraderApi</h4>
<div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">TRADER_API_EXPORT</span> <span class="n">CSecurityFtdcTraderApi</span>
<span class="p">{</span>
<span class="k">public</span><span class="o">:</span>
<span class="c1">///创建TraderApi</span>
<span class="c1">///@param pszFlowPath 存贮订阅信息文件的目录,默认为当前目录</span>
<span class="c1">///@return 创建出的UserApi</span>
<span class="k">static</span> <span class="n">CSecurityFtdcTraderApi</span> <span class="o">*</span><span class="n">CreateFtdcTraderApi</span><span class="p">(</span><span class="k">const</span> <span class="kt">char</span> <span class="o">*</span><span class="n">pszFlowPath</span> <span class="o">=</span> <span class="s">""</span><span class="p">);</span>
<span class="p">...</span>
<span class="c1">///初始化</span>
<span class="c1">///@remark 初始化运行环境,只有调用后,接口才开始工作</span>
<span class="k">virtual</span> <span class="kt">void</span> <span class="n">Init</span><span class="p">()</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">...</span>
<span class="c1">///用户登录请求</span>
<span class="k">virtual</span> <span class="kt">int</span> <span class="n">ReqUserLogin</span><span class="p">(</span><span class="n">CSecurityFtdcReqUserLoginField</span> <span class="o">*</span><span class="n">pReqUserLoginField</span><span class="p">,</span> <span class="kt">int</span> <span class="n">nRequestID</span><span class="p">)</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">...</span>
<span class="p">};</span>
</pre></div>
<p>Api类包括的主动函数通常分为以下三种:
1. Create...,类的静态方法,用于创建API对象,传入参数是用来保存API通讯.con文件的文件夹路径。</p>
<ol>
<li>
<p>Req...开头的函数,可以由用户主动调用的业务逻辑请求,传入参数通常包括2个:业务请求结构体指针和一个请求号的整数。</p>
</li>
<li>
<p>其他非Req...开头的函数,包括初始化、订阅数据流等等参数较为简单的功能,传入参数的数量和类型视乎函数功能不一定。</p>
</li>
</ol>
<h2>API工作流程</h2>
<p>简单介绍一下MdApi和TraderApi的一般工作流程,这里不会包含太多细节,仅仅是让读者有一个概念。</p>
<h3>MdApi</h3>
<ol>
<li>
<p>创建MdSpi对象</p>
</li>
<li>
<p>调用MdApi类以Create开头的静态方法,创建MdApi对象</p>
</li>
<li>
<p>调用MdApi对象的RegisterSpi方法注册MdSpi对象的指针</p>
</li>
<li>
<p>调用MdApi对象的RegisterFront方法注册行情柜台的前置机地址</p>
</li>
<li>
<p>调用MdApi对象的Init方法初始化到前置机的连接,连接成功后会通过MdSpi对象的OnFrontConnected回调函数通知用户</p>
</li>
<li>
<p>等待连接成功的通知后,可以调用MdApi的ReqUserLogin方法登陆,登陆成功后会通过MdSpi对象的OnRspUserLogin通知用户</p>
</li>
<li>
<p>登陆成功后就可以开始订阅合约了,使用MdApi对象的SubscribeMarketData方法,传入参数为想要订阅的合约的代码</p>
</li>
<li>
<p>订阅成功后,当合约有新的行情时,会通过MdApi的OnRtnDepthMarketData回调函数通知用户</p>
</li>
<li>
<p>用户的某次请求发生错误时,会通过OnRspError通知用户。</p>
</li>
<li>
<p>MdApi同样提供了退订合约、登出的功能,一般退出程序时就直接杀进程(不太安全)</p>
</li>
</ol>
<h3>TraderApi</h3>
<ol>
<li>
<p>TraderApi和MdApi类似,以下仅仅介绍不同点</p>
</li>
<li>
<p>注册TraderSpi对象的指针后,需要调用TraderApi对象的SubscribePrivateTopic和SubscribePublicTopic方法去选择公开和私有数据流的重传方法(这一步MdApi没有)</p>
</li>
<li>
<p>对于期货柜台而言(CTP、恒生UFT期货等),在每日第一次登陆成功后需要先查询前一日的结算单,等待结算单查询结果返回后,确认结算单,才可以进行后面的操作;而证券柜台LTS无此要求</p>
</li>
<li>
<p>上一步完成后,用户可以调用ReqQryInstrument的方法查询柜台上所有可以交易的合约信息(包括代码、中文名、涨跌停、最小价位变动、合约乘数等大量细节),一般是在这里获得合约信息列表后,再去MdApi中订阅合约;经常有人问为什么在MdApi中找不到查询可供订阅的合约代码的函数,这里尤其要注意,必须通过TraderApi来获取</p>
</li>
<li>
<p>当用户的报单、成交状态发生变化时,TraderApi会自动通过OnRtnOrder、OnRtnTrade通知用户,无需额外订阅</p>
</li>
</ol>
<h2>总结</h2>
<p>第一篇教程到这里已经接近结束了,如果你是一个没有任何交易API开发经验的读者,并且坚持看了下来,此时你心中很可能有这么个想法:我X,API开发这么复杂???!!!</p>
<p>相信我,这是人之常情(某些读者如果觉得很好理解那作者真是佩服你了),作者刚开始的时候大概在CTP API的头文件和网上的教程资料、示例中纠结了3个多月而不得入门,当时也没有任何C++的开发经验(我是金融工程出生,大学里编程只学了VBA和Matlab,还几乎都是些算法方面的内容),边学语言边研究怎么开发,真心痛苦。</p>
<p>在这里,我想告诉读者的一个好消息是:还剩两篇教程,我们基本就可以和C++ say goodbye,进入Python灵活快速开发的世界了。同时对于绝大部分不打算自己去封装API的读者,这三篇文章可以走马观花的过一遍,不会影响任何你未来对于vn.py框架的使用。</p>
<p>当然,对于有恒心和毅力的读者,100%自己掌握API的封装技术是一项绝对值得投入时间和精力的事情。在很多人的观念中Python并不适合用来开发低延迟的交易平台,这里作者可以用亲身经验告诉你:那只是在纯用Python的情况下。作为一门胶水语言,Python最大的特点之一就是易于通过混合编程来进行拓展,用户可以在真正需要优化的地方进行最深度的定制优化,把自己有限的时间、精力花在刀刃上。在交易API层面,可以定制的地方包括C++层面的数据结构改变、数据预处理、回调函数传递顺序调整等等诸多的优化,这些只有在你完全掌握API的封装后才能办得到。</p>
</div>
<!-- /.entry-content -->
</article>
</section>
</div>
<div class="col-sm-3" id="sidebar">
<aside>
<section class="well well-sm">
<ul class="list-group list-group-flush">
<li class="list-group-item"><h4><i class="fa fa-home fa-lg"></i><span class="icon-label">Social</span></h4>
<ul class="list-group" id="social">
<li class="list-group-item"><a href="http://github.com/vnpy/vnpy"><i class="fa fa-github-square fa-lg"></i> Github</a></li>
</ul>
</li>
<li class="list-group-item"><h4><i class="fa fa-external-link-square fa-lg"></i><span class="icon-label">Links</span></h4>
<ul class="list-group" id="links">
<li class="list-group-item">
<a href="http://www.vnpie.com" target="_blank">
官方论坛 - 维恩的派
</a>
</li>
<li class="list-group-item">
<a href="http://github.com/vnpy/vnpy/tree/master/vn.trader" target="_blank">
交易平台
</a>
</li>
<li class="list-group-item">
<a href="http://github.com/vnpy/vnpy/tree/master/vn.event" target="_blank">
事件引擎
</a>
</li>
<li class="list-group-item">
<a href="http://github.com/vnpy/vnpy/tree/master/vn.ctp" target="_blank">
CTP接口
</a>
</li>
<li class="list-group-item">
<a href="http://github.com/vnpy/vnpy/tree/master/vn.xspeed" target="_blank">
飞创接口
</a>
</li>
<li class="list-group-item">
<a href="http://github.com/vnpy/vnpy/tree/master/vn.femas" target="_blank">
飞马接口
</a>
</li>
<li class="list-group-item">
<a href="https://github.com/vnpy/vnpy/tree/master/vn.lts" target="_blank">
LTS接口
</a>
</li>
<li class="list-group-item">
<a href="http://github.com/vnpy/vnpy/tree/master/vn.ksotp" target="_blank">
金仕达期权接口
</a>
</li>
<li class="list-group-item">
<a href="http://github.com/vnpy/vnpy/tree/master/vn.ksgold" target="_blank">
金仕达黄金接口
</a>
</li>
<li class="list-group-item">
<a href="http://github.com/vnpy/vnpy/tree/master/vn.sgit" target="_blank">
飞鼠接口
</a>
</li>
<li class="list-group-item">
<a href="http://github.com/vnpy/vnpy/tree/dev/vn.qdp" target="_blank">
QDP接口
</a>
</li>
<li class="list-group-item">
<a href="http://github.com/vnpy/vnpy/tree/master/vn.oanda" target="_blank">
OANDA接口
</a>
</li>
<li class="list-group-item">
<a href="http://github.com/vnpy/vnpy/tree/master/vn.ib" target="_blank">
IB接口
</a>
</li>
<li class="list-group-item">
<a href="http://github.com/vnpy/vnpy/tree/master/vn.shzd" target="_blank">
直达期货接口
</a>
</li>
<li class="list-group-item">
<a href="http://github.com/vnpy/vnpy/tree/master/vn.okcoin" target="_blank">
OKCoin接口
</a>
</li>
<li class="list-group-item">
<a href="http://github.com/vnpy/vnpy/tree/master/vn.datayes" target="_blank">
通联数据接口
</a>
</li>
<li class="list-group-item">
<a href="http://github.com/vnpy/vnpy/tree/master/vn.demo" target="_blank">
开发DEMO
</a>
</li>
</ul>
</li>
</ul>
</section>
</aside>
</div>
</div>
</div>
<footer>
<div class="container">
<hr>
<div class="row">
<div class="col-xs-10">© 2017 用Python的交易员
· Powered by <a href="https://github.com/DandyDev/pelican-bootstrap3" target="_blank">pelican-bootstrap3</a>,
<a href="http://docs.getpelican.com/" target="_blank">Pelican</a>,
<a href="http://getbootstrap.com" target="_blank">Bootstrap</a> </div>
<div class="col-xs-2"><p class="pull-right"><i class="fa fa-arrow-up"></i> <a href="#">Back to top</a></p></div>
</div>
</div>
</footer>
<script src="/theme/js/jquery.min.js"></script>
<!-- Include all compiled plugins (below), or include individual files as needed -->
<script src="/theme/js/bootstrap.min.js"></script>
<!-- Enable responsive features in IE8 with Respond.js (https://github.com/scottjehl/Respond) -->
<script src="/theme/js/respond.min.js"></script>
<script src="/theme/js/bodypadding.js"></script>
</body>
</html>