-
Notifications
You must be signed in to change notification settings - Fork 1.6k
/
interface.py
680 lines (549 loc) · 21.5 KB
/
interface.py
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
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
# -*- coding: utf-8 -*-
# 版权所有 2019 深圳米筐科技有限公司(下称“米筐科技”)
#
# 除非遵守当前许可,否则不得使用本软件。
#
# * 非商业用途(非商业用途指个人出于非商业目的使用本软件,或者高校、研究所等非营利机构出于教育、科研等目的使用本软件):
# 遵守 Apache License 2.0(下称“Apache 2.0 许可”),
# 您可以在以下位置获得 Apache 2.0 许可的副本:http://www.apache.org/licenses/LICENSE-2.0。
# 除非法律有要求或以书面形式达成协议,否则本软件分发时需保持当前许可“原样”不变,且不得附加任何条件。
#
# * 商业用途(商业用途指个人出于任何商业目的使用本软件,或者法人或其他组织出于任何目的使用本软件):
# 未经米筐科技授权,任何个人不得出于任何商业目的使用本软件(包括但不限于向第三方提供、销售、出租、出借、转让本软件、
# 本软件的衍生产品、引用或借鉴了本软件功能或源代码的产品或服务),任何法人或其他组织不得出于任何目的使用本软件,
# 否则米筐科技有权追究相应的知识产权侵权责任。
# 在此前提下,对本软件的使用同样需要遵守 Apache 2.0 许可,Apache 2.0 许可与本许可冲突之处,以本许可为准。
# 详细的授权流程,请联系 public@ricequant.com 获取。
import abc
from datetime import datetime, date
from typing import Any, Union, Optional, Iterable, Dict, List, Sequence
import numpy
from six import with_metaclass
import pandas
from rqalpha.utils.typing import DateLike
from rqalpha.model.tick import TickObject
from rqalpha.model.order import Order
from rqalpha.model.trade import Trade
from rqalpha.model.instrument import Instrument
from rqalpha.const import POSITION_DIRECTION, TRADING_CALENDAR_TYPE, INSTRUMENT_TYPE
class AbstractPosition(with_metaclass(abc.ABCMeta)):
"""
仓位接口,主要用于构建仓位信息
您可以在 Mod 的 start_up 阶段通过 Portfolio.register_instrument_type 来注册 Position 类型
"""
@abc.abstractmethod
def get_state(self):
# type: () -> Any
"""
主要用于进行持久化时候,提供对应需要持久化的数据
"""
raise NotImplementedError
@abc.abstractmethod
def set_state(self, state):
# type: (Any) -> None
"""
主要用于持久化恢复时,根据提供的持久化数据进行恢复 Position 的实现
"""
raise NotImplementedError
@property
@abc.abstractmethod
def order_book_id(self):
# type: () -> str
"""
返回当前持仓的 order_book_id
"""
raise NotImplementedError
@property
def direction(self):
# type: () -> POSITION_DIRECTION
"""
返回当前持仓的方向
"""
raise NotImplementedError
@property
@abc.abstractmethod
def market_value(self):
# type: () -> Union[int, float]
"""
返回当前持仓的市值
"""
raise NotImplementedError
@property
@abc.abstractmethod
def transaction_cost(self):
# type: () -> Union[int, float]
# 返回当前持仓的当日交易费用
raise NotImplementedError
@property
@abc.abstractmethod
def position_pnl(self):
# type: () -> Union[int, float]
"""
返回当前持仓当日的持仓盈亏
"""
raise NotImplementedError
@property
@abc.abstractmethod
def trading_pnl(self):
# type: () -> Union[int, float]
"""
返回当前持仓当日的交易盈亏
"""
raise NotImplementedError
@property
@abc.abstractmethod
def closable(self):
# type: () -> Union[int, float]
"""
返回可平仓位
"""
raise NotImplementedError
@property
@abc.abstractmethod
def today_closable(self):
# type: () -> Union[int, float]
"""
返回今仓中的可平仓位
"""
raise NotImplementedError
@property
@abc.abstractmethod
def quantity(self):
# type: () -> Union[int, float]
"""
返回当前持仓量
"""
raise NotImplementedError
@property
@abc.abstractmethod
def avg_price(self):
# type: () -> Union[int, float]
"""
开仓均价
"""
raise NotImplementedError
@property
@abc.abstractmethod
def pnl(self):
# type: () -> float
"""
该持仓的累计盈亏
"""
raise NotImplementedError
@property
@abc.abstractmethod
def equity(self):
# type: () -> float
"""
当前持仓市值
"""
raise NotImplementedError
@property
@abc.abstractmethod
def prev_close(self):
# type: () -> float
"""
昨日收盘价
"""
raise NotImplementedError
@property
@abc.abstractmethod
def last_price(self):
# type: () -> float
"""
当前最新价
"""
raise NotImplementedError
class AbstractStrategyLoader(with_metaclass(abc.ABCMeta)):
"""
策略加载器,其主要作用是加载策略,并将策略运行所需要的域环境传递给策略执行代码。
在扩展模块中,可以通过调用 ``env.set_strategy_loader`` 来替换默认的策略加载器。
"""
@abc.abstractmethod
def load(self, scope):
"""
[Required]
load 函数负责组装策略代码和策略代码所在的域,并输出最终组装好的可执行域。
:param dict scope: 策略代码运行环境,在传入时,包含了所有基础API。
通过在 scope 中添加函数可以实现自定义API;通过覆盖 scope 中相应的函数,可以覆盖原API。
:return: scope,其中应包含策略相应函数,如 ``init``, ``before_trading`` 等
"""
raise NotImplementedError
class AbstractEventSource(with_metaclass(abc.ABCMeta)):
"""
事件源接口。RQAlpha 从此对象中获取事件,驱动整个事件循环。
在扩展模块中,可以通过调用 ``env.set_event_source`` 来替换默认的事件源。
"""
@abc.abstractmethod
def events(self, start_date, end_date, frequency):
"""
[Required]
扩展 EventSource 必须实现 events 函数。
events 是一个 event generator, 在相应事件的时候需要以如下格式来传递事件
.. code-block:: python
yield trading_datetime, calendar_datetime, EventEnum
其中 trading_datetime 为基于交易日的 datetime, calendar_datetime 为基于自然日的 datetime (因为夜盘的存在,交易日和自然日未必相同)
EventEnum 为 :class:`~Events`
:param datetime.date start_date: 起始日期, 系统会将 `config.base.start_date` 传递 events 函数
:param datetime.date end_date: 结束日期,系统会将 `config.base.end_date` 传递给 events 函数
:param str frequency: 周期频率,`1d` 表示日周期, `1m` 表示分钟周期
:return: None
"""
raise NotImplementedError
class AbstractPriceBoard(with_metaclass(abc.ABCMeta)):
"""
RQAlpha多个地方需要使用最新「行情」,不同的数据源其最新价格获取的方式不尽相同
因此抽离出 `AbstractPriceBoard`, 您可以自行进行扩展并替换默认 PriceBoard
"""
@abc.abstractmethod
def get_last_price(self, order_book_id):
# type: (str) -> float
"""
获取合约的最新价
"""
raise NotImplementedError
@abc.abstractmethod
def get_limit_up(self, order_book_id):
# type: (str) -> float
"""
获取合约的涨停价
"""
raise NotImplementedError
@abc.abstractmethod
def get_limit_down(self, order_book_id):
# type: (str) -> float
"""
获取合约的跌停价
"""
raise NotImplementedError
def get_a1(self, order_book_id):
# type: (str) -> Union[float, numpy.nan]
"""
获取合约的卖一价
"""
raise NotImplementedError
def get_b1(self, order_book_id):
# type: (str) -> Union[float, numpy.nan]
"""
获取合约的买一价
"""
raise NotImplementedError
class AbstractDataSource(object):
"""
数据源接口。RQAlpha 中通过 :class:`DataProxy` 进一步进行了封装,向上层提供更易用的接口。
在扩展模块中,可以通过调用 ``env.set_data_source`` 来替换默认的数据源。可参考 :class:`BaseDataSource`。
"""
def get_instruments(self, id_or_syms=None, types=None):
# type: (Optional[Iterable[str]], Optional[Iterable[INSTRUMENT_TYPE]]) -> Iterable[Instrument]
"""
获取 instrument,
可指定 order_book_id 或 symbol 或 instrument type,id_or_syms 优先级高于 types,
id_or_syms 和 types 均为 None 时返回全部 instruments
"""
raise NotImplementedError
def get_trading_calendars(self):
# type: () -> Dict[TRADING_CALENDAR_TYPE, pandas.DatetimeIndex]
"""
获取交易日历,DataSource 应返回所有支持的交易日历种类
"""
raise NotImplementedError
def get_yield_curve(self, start_date, end_date, tenor=None):
"""
获取国债利率
:param pandas.Timestamp str start_date: 开始日期
:param pandas.Timestamp end_date: 结束日期
:param str tenor: 利率期限
:return: pandas.DataFrame, [start_date, end_date]
"""
raise NotImplementedError
def get_dividend(self, instrument):
# type: (Instrument) -> numpy.ndarray
"""
获取股票/基金分红信息
"""
raise NotImplementedError
def get_split(self, instrument):
# type: (Instrument) -> numpy.ndarray
"""
获取拆股信息
"""
raise NotImplementedError
def get_bar(self, instrument, dt, frequency):
"""
根据 dt 来获取对应的 Bar 数据
:param instrument: 合约对象
:type instrument: :class:`~Instrument`
:param datetime.datetime dt: calendar_datetime
:param str frequency: 周期频率,`1d` 表示日周期, `1m` 表示分钟周期
:return: `numpy.ndarray` | `dict`
"""
raise NotImplementedError
def get_open_auction_bar(self, instrument, dt):
# type: (Instrument, Union[datetime, date]) -> Dict
"""
获取指定资产当日的集合竞价 Bar 数据,该 Bar 数据应包含的字段有:
datetime, open, limit_up, limit_down, volume, total_turnover
"""
raise NotImplementedError
def get_settle_price(self, instrument, date):
"""
获取期货品种在 date 的结算价
:param instrument: 合约对象
:type instrument: :class:`~Instrument`
:param datetime.date date: 结算日期
:return: `str`
"""
raise NotImplementedError
def history_bars(self, instrument, bar_count, frequency, fields, dt, skip_suspended=True,
include_now=False, adjust_type='pre', adjust_orig=None):
"""
获取历史数据
:param instrument: 合约对象
:type instrument: :class:`~Instrument`
:param int bar_count: 获取的历史数据数量
:param str frequency: 周期频率,`1d` 表示日周期, `1m` 表示分钟周期
:param str fields: 返回数据字段
========================= ===================================================
fields 字段名
========================= ===================================================
datetime 时间戳
open 开盘价
high 最高价
low 最低价
close 收盘价
volume 成交量
total_turnover 成交额
datetime int类型时间戳
open_interest 持仓量(期货专用)
basis_spread 期现差(股指期货专用)
settlement 结算价(期货日线专用)
prev_settlement 结算价(期货日线专用)
========================= ===================================================
:param datetime.datetime dt: 时间
:param bool skip_suspended: 是否跳过停牌日
:param bool include_now: 是否包含当天最新数据
:param str adjust_type: 复权类型,'pre', 'none', 'post'
:param datetime.datetime adjust_orig: 复权起点;
:return: `Optional[numpy.ndarray]`, fields 不合法时返回 None
"""
raise NotImplementedError
def history_ticks(self, instrument, count, dt):
# type: (Instrument, int, datetime) -> List[TickObject]
"""
获取指定合约历史 tick 对象
:param instrument: 合约对象
:param int count: 获取的 tick 数量
:param dt: 时间
"""
raise NotImplementedError
def current_snapshot(self, instrument, frequency, dt):
"""
获得当前市场快照数据。只能在日内交易阶段调用,获取当日调用时点的市场快照数据。
市场快照数据记录了每日从开盘到当前的数据信息,可以理解为一个动态的day bar数据。
在目前分钟回测中,快照数据为当日所有分钟线累积而成,一般情况下,最后一个分钟线获取到的快照数据应当与当日的日线行情保持一致。
需要注意,在实盘模拟中,该函数返回的是调用当时的市场快照情况,所以在同一个handle_bar中不同时点调用可能返回的数据不同。
如果当日截止到调用时候对应股票没有任何成交,那么snapshot中的close, high, low, last几个价格水平都将以0表示。
:param instrument: 合约对象
:type instrument: :class:`~Instrument`
:param str frequency: 周期频率,`1d` 表示日周期, `1m` 表示分钟周期
:param datetime.datetime dt: 时间
:return: :class:`~Snapshot`
"""
raise NotImplementedError
def get_trading_minutes_for(self, instrument, trading_dt):
"""
获取证券某天的交易时段,用于期货回测
:param instrument: 合约对象
:type instrument: :class:`~Instrument`
:param datetime.datetime trading_dt: 交易日。注意期货夜盘所属交易日规则。
:return: list[`datetime.datetime`]
"""
raise NotImplementedError
def available_data_range(self, frequency):
"""
此数据源能提供数据的时间范围
:param str frequency: 周期频率,`1d` 表示日周期, `1m` 表示分钟周期
:return: (earliest, latest)
"""
raise NotImplementedError
def get_commission_info(self, instrument):
"""
获取合约的手续费信息
:param instrument:
:return:
"""
raise NotImplementedError
def get_merge_ticks(self, order_book_id_list, trading_date, last_dt=None):
"""
获取合并的 ticks
:param list order_book_id_list: 合约名列表
:param datetime.date trading_date: 交易日
:param datetime.datetime last_dt: 仅返回 last_dt 之后的时间
:return: Iterable object of Tick
"""
raise NotImplementedError
def get_share_transformation(self, order_book_id):
"""
获取股票转换信息
:param order_book_id: 合约代码
:return: (successor, conversion_ratio), (转换后的合约代码,换股倍率)
"""
raise NotImplementedError
def is_suspended(self, order_book_id, dates):
# type: (str, Sequence[DateLike]) -> Sequence[bool]
raise NotImplementedError
def is_st_stock(self, order_book_id, dates):
# type: (str, Sequence[DateLike]) -> Sequence[bool]
raise NotImplementedError
def get_algo_bar(self, id_or_ins, start_min, end_min, dt):
# type: (Union[str, Instrument], int, int, datetime) -> Optional[numpy.void]
# 格式: (date, VWAP, TWAP, volume) -> 案例 (20200102, 16.79877183, 16.83271429, 144356044)
raise NotImplementedError
class AbstractBroker(with_metaclass(abc.ABCMeta)):
"""
券商接口。
RQAlpha 将产生的订单提交给此对象,此对象负责对订单进行撮合(不论是自行撮合还是委托给外部的真实交易所),
并通过 ``EVENT.ORDER_*`` 及 ``EVENT.TRADE`` 事件将撮合结果反馈进入 RQAlpha。
在扩展模块中,可以通过调用 ``env.set_broker`` 来替换默认的 Broker。
"""
@abc.abstractmethod
def submit_order(self, order):
# type: (Order) -> None
# 提交订单。RQAlpha 会生成 :class:`~Order` 对象,再通过此接口提交到 Broker。
raise NotImplementedError
@abc.abstractmethod
def cancel_order(self, order):
"""
[Required]
撤单。
:param order: 订单
:type order: :class:`~Order`
"""
raise NotImplementedError
@abc.abstractmethod
def get_open_orders(self, order_book_id=None):
"""
[Required]
获得当前未完成的订单。
:return: list[:class:`~Order`]
"""
raise NotImplementedError
class AbstractMod(with_metaclass(abc.ABCMeta)):
"""
扩展模块接口。
"""
@abc.abstractmethod
def start_up(self, env, mod_config):
"""
RQAlpha 在系统启动时会调用此接口;在此接口中,可以通过调用 ``env`` 的相应方法来覆盖系统默认组件。
:param env: 系统环境
:type env: :class:`~Environment`
:param mod_config: 模块配置参数
"""
raise NotImplementedError
def tear_down(self, code, exception=None):
"""
RQAlpha 在系统退出前会调用此接口。
:param code: 退出代码
:type code: rqalpha.const.EXIT_CODE
:param exception: 如果在策略执行过程中出现错误,此对象为相应的异常对象
"""
raise NotImplementedError
class AbstractPersistProvider(with_metaclass(abc.ABCMeta)):
"""
持久化服务提供者接口。
扩展模块可以通过调用 ``env.set_persist_provider`` 接口来替换默认的持久化方案。
"""
@abc.abstractmethod
def store(self, key, value):
"""
store
:param str key:
:param bytes value:
:return:
"""
raise NotImplementedError
@abc.abstractmethod
def load(self, key):
"""
:param str key:
:return: bytes 如果没有对应的值,返回 None
"""
raise NotImplementedError
@abc.abstractmethod
def should_resume(self):
"""
是否应该以 resume 模式运行
:return: bool
"""
raise NotImplementedError
@abc.abstractmethod
def should_run_init(self):
"""
是否应该执行策略的 init 函数
:return: bool
"""
raise NotImplementedError
class Persistable(with_metaclass(abc.ABCMeta)):
@abc.abstractmethod
def get_state(self):
"""
:return: bytes
"""
raise NotImplementedError
@abc.abstractmethod
def set_state(self, state):
"""
:param state: bytes
:return:
"""
raise NotImplementedError
@classmethod
def __subclasshook__(cls, C):
if cls is Persistable:
if (any("get_state" in B.__dict__ for B in C.__mro__) and
any("set_state" in B.__dict__ for B in C.__mro__)):
return True
return NotImplemented
class AbstractFrontendValidator(with_metaclass(abc.ABCMeta)):
"""
前端风控接口,下撤单请求在到达券商代理模块前会经过前端风控。
扩展模块可以通过 env.add_frontend_validator 添加自定义的前端风控逻辑
"""
@abc.abstractmethod
def can_submit_order(self, order, account=None):
"""
判断是否可以下单
"""
raise NotImplementedError
@abc.abstractmethod
def can_cancel_order(self, order, account=None):
"""
判读是否可以撤单
"""
raise NotImplementedError
class AbstractTransactionCostDecider((with_metaclass(abc.ABCMeta))):
"""
订单税费计算接口,通过实现次接口可以定义不同市场、不同合约的个性化税费计算逻辑。
"""
@abc.abstractmethod
def get_trade_tax(self, trade):
# type: (Trade) -> float
"""
计算指定交易应付的印花税
"""
raise NotImplementedError
@abc.abstractmethod
def get_trade_commission(self, trade):
# type: (Trade) -> float
"""
计算指定交易应付的佣金
"""
raise NotImplementedError
@abc.abstractmethod
def get_order_transaction_cost(self, order):
# type: (Order) -> float
"""
计算指定订单应付的交易成本(税 + 费)
"""
raise NotImplementedError