-
Notifications
You must be signed in to change notification settings - Fork 95
/
Copy pathbasic-tutorial-5.html
546 lines (492 loc) · 35.1 KB
/
basic-tutorial-5.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
<!DOCTYPE html>
<html lang="zh"
>
<head>
<title>Python量化交易平台开发教程系列5-底层接口对接 - 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-5.html">
<meta name="author" content="用Python的交易员" />
<meta name="description" content="原创文章,转载请注明出处:用Python的交易员 前言 从本篇教程开始,所有的开发都会在Python环境中进行(谢天谢地可以和C++说再见了)。 通常情况下,一个交易程序的架构会由以下三个部分组成: 底层接口:负责对接行情和交易API,将数据推送到系统核心中,以及发送指令(下单、数据请求等) 中层引擎:用于整合程序中的各个组件(包括底层接口、数据库接口等等)到一个对象中,便于顶层UI调用 顶层GUI:用于显示数据和调用中层引擎暴露的主动函数,实现各项具体功能 上面这张图展示的是国外的一款开源交易平台AlgoTrader的架构: 两边的Adapters代表的是底层接口(左边数据,右边交易) 红色圆柱形中包括的是中层引擎架构,事件驱动方面使用了Esper复杂事件处理(CEP)引擎,同时内置了一些常用的功能引擎,如期权定价引擎、外汇对冲模块、投资组合管理模块等 上方的Strategy1、2等代表的是顶层应用(算法策略、GUI界面等),通过调用中层引擎的功能来实现用户所需的业务 vn.py和AlgoTrader的比较: 这里对两个项目做一个简单的比较。 vn.py优势: 语言易用:Java语言比Python啰嗦 架构简洁 ..." />
<meta property="og:site_name" content="vn.py" />
<meta property="og:type" content="article"/>
<meta property="og:title" content="Python量化交易平台开发教程系列5-底层接口对接"/>
<meta property="og:url" content="/basic-tutorial-5.html"/>
<meta property="og:description" content="原创文章,转载请注明出处:用Python的交易员 前言 从本篇教程开始,所有的开发都会在Python环境中进行(谢天谢地可以和C++说再见了)。 通常情况下,一个交易程序的架构会由以下三个部分组成: 底层接口:负责对接行情和交易API,将数据推送到系统核心中,以及发送指令(下单、数据请求等) 中层引擎:用于整合程序中的各个组件(包括底层接口、数据库接口等等)到一个对象中,便于顶层UI调用 顶层GUI:用于显示数据和调用中层引擎暴露的主动函数,实现各项具体功能 上面这张图展示的是国外的一款开源交易平台AlgoTrader的架构: 两边的Adapters代表的是底层接口(左边数据,右边交易) 红色圆柱形中包括的是中层引擎架构,事件驱动方面使用了Esper复杂事件处理(CEP)引擎,同时内置了一些常用的功能引擎,如期权定价引擎、外汇对冲模块、投资组合管理模块等 上方的Strategy1、2等代表的是顶层应用(算法策略、GUI界面等),通过调用中层引擎的功能来实现用户所需的业务 vn.py和AlgoTrader的比较: 这里对两个项目做一个简单的比较。 vn.py优势: 语言易用:Java语言比Python啰嗦 架构简洁 ..."/>
<meta property="article:published_time" content="2015-05-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-5.html"
rel="bookmark"
title="Permalink to Python量化交易平台开发教程系列5-底层接口对接">
Python量化交易平台开发教程系列5-底层接口对接
</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-05-05T14:46:00+08:00"> 2015-05-05(周二)</time>
</span>
</footer><!-- /.post-info --> </div>
</div>
<p>原创文章,转载请注明出处:用Python的交易员</p>
<h2>前言</h2>
<p>从本篇教程开始,所有的开发都会在Python环境中进行(谢天谢地可以和C++说再见了)。</p>
<p><strong>通常情况下,一个交易程序的架构会由以下三个部分组成:</strong></p>
<ul>
<li>
<p>底层接口:负责对接行情和交易API,将数据推送到系统核心中,以及发送指令(下单、数据请求等)</p>
</li>
<li>
<p>中层引擎:用于整合程序中的各个组件(包括底层接口、数据库接口等等)到一个对象中,便于顶层UI调用</p>
</li>
<li>
<p>顶层GUI:用于显示数据和调用中层引擎暴露的主动函数,实现各项具体功能</p>
</li>
</ul>
<p><img alt="AlgoTrader架构" src="http://7x2w1m.com1.z0.glb.clouddn.com/%E6%95%99%E7%A8%8B5algotrader_%E6%9E%84%E6%9E%B6.png" /></p>
<p><strong>上面这张图展示的是国外的一款开源交易平台AlgoTrader的架构:</strong></p>
<ul>
<li>
<p>两边的Adapters代表的是底层接口(左边数据,右边交易)</p>
</li>
<li>
<p>红色圆柱形中包括的是中层引擎架构,事件驱动方面使用了Esper复杂事件处理(CEP)引擎,同时内置了一些常用的功能引擎,如期权定价引擎、外汇对冲模块、投资组合管理模块等</p>
</li>
<li>
<p>上方的Strategy1、2等代表的是顶层应用(算法策略、GUI界面等),通过调用中层引擎的功能来实现用户所需的业务</p>
</li>
</ul>
<p><strong>vn.py和AlgoTrader的比较:</strong></p>
<p>这里对两个项目做一个简单的比较。</p>
<p>vn.py优势:</p>
<ul>
<li>
<p>语言易用:Java语言比Python啰嗦</p>
</li>
<li>
<p>架构简洁:Java的编程理念(纯面向对象,大量使用框架等)更是比Python的编程理念(人生苦短,我们的目标是搞定问题)繁琐</p>
</li>
<li>
<p>事件驱动引擎:AlgoTrader使用的Esper引擎尽管功能强大,使用起来也过于复杂,对于国内绝大部分的量化业务而言完全用不着</p>
</li>
<li>
<p>本地化:vn.py完全为中国市场设计,在功能设计上更符合国人的使用习惯,而AlgoTrader则是针对欧美市场设计</p>
</li>
</ul>
<p>AlgoTrader优势:</p>
<ul>
<li>
<p>静态语言:Java在开发时可以进行静态检查,同时相对较低的灵活性使得其更适合大型团队使用(即每个成员未必对项目整体非常了解)</p>
</li>
<li>
<p>国外接口:已有大量的国外经纪商和行情提供商接口,如果用户主要做欧美市场基本可以开箱即用</p>
</li>
<li>
<p>成熟度:AlgoTrader从2009发布至今已经有6年的历史,同时有着相当数量的机构客户</p>
</li>
</ul>
<p>两个项目的相似之处:</p>
<ul>
<li>
<p>作者在最初都是为了交易某种期权策略而开发了该项目</p>
</li>
<li>
<p>整体框架设计类似(底层接口、中层引擎、顶层GUI)</p>
</li>
<li>
<p>都可以非常方便的开发全自动交易策略</p>
</li>
<li>
<p>都是开源项目,目前托管在Github上(废话),用户可以根据自己的需求随意定制相关功能</p>
</li>
<li>
<p>都可以应用于高频交易(毫秒级延迟),不适用于超高频交易(微秒级延迟)</p>
</li>
</ul>
<p><strong>教程说明</strong></p>
<p>本篇教程将会介绍底层接口的开发,后面的若干篇则是关于中层引擎和各种顶层GUI组件。</p>
<p>相关的示例都是基于vn.demo中的LTS接口DEMO,发布在:
<a href="https://github.com/vnpy/vnpy/tree/master/vn.demo/ltsdemo">https://github.com/vnpy/vnpy/tree/master/vn.demo/ltsdemo</a></p>
<h2>底层接口对接</h2>
<p>通过前面的教程,我们已经获得了和原生C++ API功能完全相同的Python封装API。通常情况下,为了将某个API对接到我们的程序中,需要以下两步:</p>
<ol>
<li>
<p>将API的回调函数收到的数据推送到程序的中层引擎中,等待处理</p>
</li>
<li>
<p>将API的主动函数进行一定的简化封装,便于中层引擎调用</p>
</li>
</ol>
<p>vn.lts中的API接口在使用时需要由用户继承后实现回调函数对应的具体功能,下面的内容以行情接口为例。</p>
<h3>接口对象设计</h3>
<div class="highlight"><pre><span></span><span class="c1">########################################################################</span>
<span class="k">class</span> <span class="nc">DemoMdApi</span><span class="p">(</span><span class="n">MdApi</span><span class="p">):</span>
<span class="sd">"""</span>
<span class="sd"> Demo中的行情API封装</span>
<span class="sd"> 封装后所有数据自动推送到事件驱动引擎中,由其负责推送到各个监听该事件的回调函数上</span>
<span class="sd"> 对用户暴露的主动函数包括:</span>
<span class="sd"> 登陆 login</span>
<span class="sd"> 订阅合约 subscribe</span>
<span class="sd"> """</span>
<span class="c1">#----------------------------------------------------------------------</span>
<span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">eventEngine</span><span class="p">):</span>
<span class="sd">"""</span>
<span class="sd"> API对象的初始化函数</span>
<span class="sd"> """</span>
<span class="nb">super</span><span class="p">(</span><span class="n">DemoMdApi</span><span class="p">,</span> <span class="bp">self</span><span class="p">)</span><span class="o">.</span><span class="n">__init__</span><span class="p">()</span>
<span class="c1"># 事件引擎,所有数据都推送到其中,再由事件引擎进行分发</span>
<span class="bp">self</span><span class="o">.</span><span class="n">__eventEngine</span> <span class="o">=</span> <span class="n">eventEngine</span>
<span class="c1"># 请求编号,由api负责管理</span>
<span class="bp">self</span><span class="o">.</span><span class="n">__reqid</span> <span class="o">=</span> <span class="mi">0</span>
<span class="c1"># 以下变量用于实现连接和重连后的自动登陆</span>
<span class="bp">self</span><span class="o">.</span><span class="n">__userid</span> <span class="o">=</span> <span class="s1">''</span>
<span class="bp">self</span><span class="o">.</span><span class="n">__password</span> <span class="o">=</span> <span class="s1">''</span>
<span class="bp">self</span><span class="o">.</span><span class="n">__brokerid</span> <span class="o">=</span> <span class="s1">''</span>
<span class="c1"># 以下集合用于重连后自动订阅之前已订阅的合约,使用集合为了防止重复</span>
<span class="bp">self</span><span class="o">.</span><span class="n">__setSubscribed</span> <span class="o">=</span> <span class="nb">set</span><span class="p">()</span>
<span class="c1"># 初始化.con文件的保存目录为\mdconnection,注意这个目录必须已存在,否则会报错</span>
<span class="bp">self</span><span class="o">.</span><span class="n">createFtdcMdApi</span><span class="p">(</span><span class="n">os</span><span class="o">.</span><span class="n">getcwd</span><span class="p">()</span> <span class="o">+</span> <span class="s1">'</span><span class="se">\\</span><span class="s1">mdconnection</span><span class="se">\\</span><span class="s1">'</span><span class="p">)</span>
</pre></div>
<ol>
<li>
<p>DemoMdApi类继承自MdApi类,并实现了回调函数的具体功能。</p>
</li>
<li>
<p>创建DemoMdApi的对象时,用户需要传入的参数是事件驱动引擎对象eventEngine。</p>
</li>
<li>
<p>每次调用API的主动函数时,需要传入一个reqid的参数,作为本次请求的唯一标识,绝大部分情况下我们不需要在意每个请求的标识情况,因此选择将该参数交给DemoMdApi对象来维护,每次调用主动函数时自动加1。</p>
</li>
<li>
<p>我们在DemoMdApi的对象中保存用户名、密码和经纪商编号,用于前置机连接完成后的自动登录功能,以及断线重连相关的操作。</p>
</li>
<li>
<p>__setSubscribed对应的是一个Python集合,用于保存我们通过订阅函数订阅过的合约,在断线重连后自动进行订阅,之所以选择set而不是list是为了保证合约的唯一性,避免重复订阅(尽管重复订阅也没影响)。</p>
</li>
<li>
<p>在创建对象DemoMdApi对象的同时,自动调用createFtdcMdApi来初始化连接接口,选择使用当前目录下的mdconnection文件夹来保存.con通讯文件。</p>
</li>
</ol>
<h3>回调函数</h3>
<div class="highlight"><pre><span></span> <span class="c1">#----------------------------------------------------------------------</span>
<span class="k">def</span> <span class="nf">onFrontConnected</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="sd">"""服务器连接"""</span>
<span class="n">event</span> <span class="o">=</span> <span class="n">Event</span><span class="p">(</span><span class="n">type_</span><span class="o">=</span><span class="n">EVENT_LOG</span><span class="p">)</span>
<span class="n">event</span><span class="o">.</span><span class="n">dict_</span><span class="p">[</span><span class="s1">'log'</span><span class="p">]</span> <span class="o">=</span> <span class="s1">u'行情服务器连接成功'</span>
<span class="bp">self</span><span class="o">.</span><span class="n">__eventEngine</span><span class="o">.</span><span class="n">put</span><span class="p">(</span><span class="n">event</span><span class="p">)</span>
<span class="c1"># 如果用户已经填入了用户名等等,则自动尝试连接</span>
<span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">__userid</span><span class="p">:</span>
<span class="n">req</span> <span class="o">=</span> <span class="p">{}</span>
<span class="n">req</span><span class="p">[</span><span class="s1">'UserID'</span><span class="p">]</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">__userid</span>
<span class="n">req</span><span class="p">[</span><span class="s1">'Password'</span><span class="p">]</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">__password</span>
<span class="n">req</span><span class="p">[</span><span class="s1">'BrokerID'</span><span class="p">]</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">__brokerid</span>
<span class="bp">self</span><span class="o">.</span><span class="n">__reqid</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">__reqid</span> <span class="o">+</span> <span class="mi">1</span>
<span class="bp">self</span><span class="o">.</span><span class="n">reqUserLogin</span><span class="p">(</span><span class="n">req</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">__reqid</span><span class="p">)</span>
<span class="o">...</span>
<span class="c1">#----------------------------------------------------------------------</span>
<span class="k">def</span> <span class="nf">onRspUserLogin</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">data</span><span class="p">,</span> <span class="n">error</span><span class="p">,</span> <span class="n">n</span><span class="p">,</span> <span class="n">last</span><span class="p">):</span>
<span class="sd">"""登陆回报"""</span>
<span class="n">event</span> <span class="o">=</span> <span class="n">Event</span><span class="p">(</span><span class="n">type_</span><span class="o">=</span><span class="n">EVENT_LOG</span><span class="p">)</span>
<span class="k">if</span> <span class="n">error</span><span class="p">[</span><span class="s1">'ErrorID'</span><span class="p">]</span> <span class="o">==</span> <span class="mi">0</span><span class="p">:</span>
<span class="n">log</span> <span class="o">=</span> <span class="s1">u'行情服务器登陆成功'</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">log</span> <span class="o">=</span> <span class="s1">u'登陆回报,错误代码:'</span> <span class="o">+</span> <span class="nb">unicode</span><span class="p">(</span><span class="n">error</span><span class="p">[</span><span class="s1">'ErrorID'</span><span class="p">])</span> <span class="o">+</span> <span class="s1">u','</span> <span class="o">+</span> <span class="s1">u'错误信息:'</span> <span class="o">+</span> <span class="n">error</span><span class="p">[</span><span class="s1">'ErrorMsg'</span><span class="p">]</span><span class="o">.</span><span class="n">decode</span><span class="p">(</span><span class="s1">'gbk'</span><span class="p">)</span>
<span class="n">event</span><span class="o">.</span><span class="n">dict_</span><span class="p">[</span><span class="s1">'log'</span><span class="p">]</span> <span class="o">=</span> <span class="n">log</span>
<span class="bp">self</span><span class="o">.</span><span class="n">__eventEngine</span><span class="o">.</span><span class="n">put</span><span class="p">(</span><span class="n">event</span><span class="p">)</span>
<span class="c1"># 重连后自动订阅之前已经订阅过的合约</span>
<span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">__setSubscribed</span><span class="p">:</span>
<span class="k">for</span> <span class="n">instrument</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">__setSubscribed</span><span class="p">:</span>
<span class="bp">self</span><span class="o">.</span><span class="n">subscribe</span><span class="p">(</span><span class="n">instrument</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="n">instrument</span><span class="p">[</span><span class="mi">1</span><span class="p">])</span>
<span class="o">...</span>
<span class="c1">#---------------------------------------------------------------------- </span>
<span class="k">def</span> <span class="nf">onRtnDepthMarketData</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">data</span><span class="p">):</span>
<span class="sd">"""行情推送"""</span>
<span class="c1"># 行情推送收到后,同时触发常规行情事件,以及特定合约行情事件,用于满足不同类型的监听</span>
<span class="c1"># 常规行情事件</span>
<span class="n">event1</span> <span class="o">=</span> <span class="n">Event</span><span class="p">(</span><span class="n">type_</span><span class="o">=</span><span class="n">EVENT_MARKETDATA</span><span class="p">)</span>
<span class="n">event1</span><span class="o">.</span><span class="n">dict_</span><span class="p">[</span><span class="s1">'data'</span><span class="p">]</span> <span class="o">=</span> <span class="n">data</span>
<span class="bp">self</span><span class="o">.</span><span class="n">__eventEngine</span><span class="o">.</span><span class="n">put</span><span class="p">(</span><span class="n">event1</span><span class="p">)</span>
<span class="c1"># 特定合约行情事件</span>
<span class="n">event2</span> <span class="o">=</span> <span class="n">Event</span><span class="p">(</span><span class="n">type_</span><span class="o">=</span><span class="p">(</span><span class="n">EVENT_MARKETDATA_CONTRACT</span><span class="o">+</span><span class="n">data</span><span class="p">[</span><span class="s1">'InstrumentID'</span><span class="p">]))</span>
<span class="n">event2</span><span class="o">.</span><span class="n">dict_</span><span class="p">[</span><span class="s1">'data'</span><span class="p">]</span> <span class="o">=</span> <span class="n">data</span>
<span class="bp">self</span><span class="o">.</span><span class="n">__eventEngine</span><span class="o">.</span><span class="n">put</span><span class="p">(</span><span class="n">event2</span><span class="p">)</span>
<span class="o">...</span>
</pre></div>
<ol>
<li>
<p>通过回调函数收到API的数据推送后,创建不同类型的事件Event对象(来自于事件驱动引擎模块),在事件对象的数据字典dict_中保存需要具体推送的数据,然后推送到事件驱动引擎中,由其负责处理。</p>
</li>
<li>
<p>回调函数收到的数据中,data和error分别对应的是保存主要数据(如行情)和错误信息的字典,n是该回调函数对应的请求号(即调用主动函数时的reqid),last是一个布尔值,代表是否为该次调用的最后返回信息。</p>
</li>
<li>
<p>我们主要对data字典感兴趣,因此选择在事件中整体推送。</p>
</li>
<li>
<p>而error字典每次收到后应当立即检查是否包含错误信息(因为即使没有发生错误也会推送),若有则自动保存为一个日志事件(通过日志监控控件显示出来)。</p>
</li>
<li>
<p>服务器连接完成后(onFrontConnected),检查是否已经填入了用户名等登录信息,若有则自动登录(请参考后面主动函数中的示例)。</p>
</li>
<li>
<p>登陆完成后(onRspUserLogin),自动订阅__setSubscribed中之前已经订阅过的合约。</p>
</li>
<li>
<p>收到行情推送后(onRtnDepthMarketData),我们选择创建两种事件,一种是常规行情事件(通常适用于市场行情监控GUI等对所有行情推送都关注的组件),另一种是特定合约行情事件(通常适用于算法等仅关注特定合约行情的组件)。</p>
</li>
<li>
<p>当我们调用会有返回信息的主动函数时,需要传入本次请求的编号,此时我们先将__reqid自加1,再作为参数传入主动函数中。</p>
</li>
</ol>
<h3>主动函数</h3>
<div class="highlight"><pre><span></span> <span class="c1">#----------------------------------------------------------------------</span>
<span class="k">def</span> <span class="nf">login</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">address</span><span class="p">,</span> <span class="n">userid</span><span class="p">,</span> <span class="n">password</span><span class="p">,</span> <span class="n">brokerid</span><span class="p">):</span>
<span class="sd">"""连接服务器"""</span>
<span class="bp">self</span><span class="o">.</span><span class="n">__userid</span> <span class="o">=</span> <span class="n">userid</span>
<span class="bp">self</span><span class="o">.</span><span class="n">__password</span> <span class="o">=</span> <span class="n">password</span>
<span class="bp">self</span><span class="o">.</span><span class="n">__brokerid</span> <span class="o">=</span> <span class="n">brokerid</span>
<span class="c1"># 注册服务器地址</span>
<span class="bp">self</span><span class="o">.</span><span class="n">registerFront</span><span class="p">(</span><span class="n">address</span><span class="p">)</span>
<span class="c1"># 初始化连接,成功会调用onFrontConnected</span>
<span class="bp">self</span><span class="o">.</span><span class="n">init</span><span class="p">()</span>
<span class="c1">#----------------------------------------------------------------------</span>
<span class="k">def</span> <span class="nf">subscribe</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">instrumentid</span><span class="p">,</span> <span class="n">exchangeid</span><span class="p">):</span>
<span class="sd">"""订阅合约"""</span>
<span class="n">req</span> <span class="o">=</span> <span class="p">{}</span>
<span class="n">req</span><span class="p">[</span><span class="s1">'InstrumentID'</span><span class="p">]</span> <span class="o">=</span> <span class="n">instrumentid</span>
<span class="n">req</span><span class="p">[</span><span class="s1">'ExchangeID'</span><span class="p">]</span> <span class="o">=</span> <span class="n">exchangeid</span>
<span class="bp">self</span><span class="o">.</span><span class="n">subscribeMarketData</span><span class="p">(</span><span class="n">req</span><span class="p">)</span>
<span class="n">instrument</span> <span class="o">=</span> <span class="p">(</span><span class="n">instrumentid</span><span class="p">,</span> <span class="n">exchangeid</span><span class="p">)</span>
<span class="bp">self</span><span class="o">.</span><span class="n">__setSubscribed</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">instrument</span><span class="p">)</span>
</pre></div>
<ol>
<li>
<p>主动函数仅封装了两个功能,登录login和订阅合约subscribe。这里假设通常我们不会做登出(直接杀进程)和退订合约(不一定)之类的操作,有需求的话可以自行封装对应的函数。</p>
</li>
<li>
<p>对于登录函数login而言,传入参数包括服务器前置机地址address,用户名userid,密码password以及经纪商代码brokerid。函数调用后,我们先将userid,password和brokerid保存下来,然后注册服务器地址registerFront,并初始化连接init。连接完成后,onFrontConnected回调函数会被自动调用,然后发生的操作请参考前一段落的回调函数工作流程。</p>
</li>
<li>
<p>LTS的API在订阅行情时,需要传入合约的代码以及合约所在的交易所(因为存在两个证券交易所相同代码的情况),而CTP的API在期货方面则不存在该问题,只需传入合约代码。发送订阅请求后,将该订阅请求保存在__setSubscribed集合中,使得断线重连时可以自动重新订阅。</p>
</li>
</ol>
<h2>总结</h2>
<p>在交易程序的开发中,所有的API对接原理均大同小异,除了类CTP API以外,国内的恒生接口、FIX引擎接口等等也可以同样遵照以上的原理进行对接设计。</p>
<p>文章中的例子是行情接口,交易接口因为包含了更多的回调函数和主动函数,在设计上相对更为复杂,感兴趣读者建议直接阅读demo中的源代码,相关问题可以在vn.py框架交流群(群号:262656087)中提问。</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>