• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

ricequant / rqalpha / 21348937310

26 Jan 2026 06:55AM UTC coverage: 67.675%. First build
21348937310

Pull #961

github

web-flow
Fix coverage (#964)

* add pytest-cov and open it

* revise install mode

---------

Co-authored-by: Don <lin.dongzhao@ricequant.com>
Pull Request #961: Develop

501 of 585 new or added lines in 26 files covered. (85.64%)

7428 of 10976 relevant lines covered (67.67%)

5.36 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

76.79
/rqalpha/data/base_data_source/data_source.py
1
# -*- coding: utf-8 -*-
2
# 版权所有 2020 深圳米筐科技有限公司(下称“米筐科技”)
3
#
4
# 除非遵守当前许可,否则不得使用本软件。
5
#
6
#     * 非商业用途(非商业用途指个人出于非商业目的使用本软件,或者高校、研究所等非营利机构出于教育、科研等目的使用本软件):
7
#         遵守 Apache License 2.0(下称“Apache 2.0 许可”),
8
#         您可以在以下位置获得 Apache 2.0 许可的副本:http://www.apache.org/licenses/LICENSE-2.0。
9
#         除非法律有要求或以书面形式达成协议,否则本软件分发时需保持当前许可“原样”不变,且不得附加任何条件。
10
#
11
#     * 商业用途(商业用途指个人出于任何商业目的使用本软件,或者法人或其他组织出于任何目的使用本软件):
12
#         未经米筐科技授权,任何个人不得出于任何商业目的使用本软件(包括但不限于向第三方提供、销售、出租、出借、转让本软件、
13
#         本软件的衍生产品、引用或借鉴了本软件功能或源代码的产品或服务),任何法人或其他组织不得出于任何目的使用本软件,
14
#         否则米筐科技有权追究相应的知识产权侵权责任。
15
#         在此前提下,对本软件的使用同样需要遵守 Apache 2.0 许可,Apache 2.0 许可与本许可冲突之处,以本许可为准。
16
#         详细的授权流程,请联系 public@ricequant.com 获取。
17
from collections import defaultdict, ChainMap
8✔
18
import os
8✔
19
from datetime import date, datetime, timedelta
8✔
20
from itertools import chain, repeat
8✔
21
from typing import DefaultDict, Dict, Iterable, List, Mapping, Optional, Sequence, Union, cast, Tuple
8✔
22

23
try:
8✔
24
    from typing import Protocol, runtime_checkable
8✔
25
except ImportError:
1✔
26
    from typing_extensions import Protocol, runtime_checkable
1✔
27

28
import numpy as np
8✔
29
import pandas as pd
8✔
30
import six
8✔
31
from rqalpha.utils.i18n import gettext as _
8✔
32
from rqalpha.const import INSTRUMENT_TYPE, MARKET, TRADING_CALENDAR_TYPE
8✔
33
from rqalpha.interface import AbstractDataSource, ExchangeRate
8✔
34
from rqalpha.model.instrument import Instrument
8✔
35
from rqalpha.utils.datetime_func import (convert_date_to_int, convert_int_to_date, convert_int_to_datetime, convert_dt_to_int)
8✔
36
from rqalpha.utils.exception import RQInvalidArgument
8✔
37
from rqalpha.utils.functools import lru_cache
8✔
38
from rqalpha.utils.typing import DateLike
8✔
39
from rqalpha.utils.logger import system_log
8✔
40
from rqalpha.environment import Environment
8✔
41
from rqalpha.data.base_data_source.adjust import FIELDS_REQUIRE_ADJUSTMENT, adjust_bars
8✔
42
from rqalpha.data.base_data_source.storage_interface import (AbstractCalendarStore, AbstractDateSet,
8✔
43
                                AbstractDayBarStore, AbstractDividendStore,
44
                                AbstractInstrumentStore, AbstractSimpleFactorStore)
45
from rqalpha.data.base_data_source.storages import (DateSet, DayBarStore, DividendStore,
8✔
46
                       ExchangeTradingCalendarStore, FutureDayBarStore,
47
                       FutureInfoStore, ShareTransformationStore, SimpleFactorStore,
48
                       YieldCurveStore, FuturesTradingParameters, load_instruments_from_pkl)
49

50

51
BAR_RESAMPLE_FIELD_METHODS = {
8✔
52
    "open": "first",
53
    "close": "last",
54
    "iopv": "last",
55
    "high": "max",
56
    "low": "min",
57
    "total_turnover": "sum",
58
    "volume": "sum",
59
    "num_trades": "sum",
60
    "acc_net_value": "last",
61
    "unit_net_value": "last",
62
    "discount_rate": "last",
63
    "settlement": "last",
64
    "prev_settlement": "last",
65
    "open_interest": "last",
66
    "basis_spread": "last",
67
    "contract_multiplier": "last",
68
    "strike_price": "last",
69
}
70

71

72
@runtime_checkable
8✔
73
class BaseDataSourceProtocol(Protocol):
8✔
74
    def register_day_bar_store(self, instrument_type: INSTRUMENT_TYPE, store: AbstractDayBarStore, market: MARKET = MARKET.CN) -> None:
2✔
75
        ...
76
    def register_instruments(self, instruments: Iterable[Instrument]) -> None:
2✔
77
        ...
78
    def register_dividend_store(self, instrument_type: INSTRUMENT_TYPE, dividend_store: AbstractDividendStore, market: MARKET = MARKET.CN) -> None:
2✔
79
        ...
80
    def register_split_store(self, instrument_type: INSTRUMENT_TYPE, split_store: AbstractSimpleFactorStore, market: MARKET = MARKET.CN) -> None:
2✔
81
        ...
82
    def register_calendar_store(self, calendar_type: TRADING_CALENDAR_TYPE, calendar_store: AbstractCalendarStore) -> None:
2✔
83
        ...
84
    def register_ex_factor_store(self, instrument_type: INSTRUMENT_TYPE, ex_factor_store: AbstractSimpleFactorStore, market: MARKET = MARKET.CN) -> None:
2✔
85
        ...
86

87

88
class BaseDataSource(AbstractDataSource):
8✔
89
    DEFAULT_INS_TYPES = (
8✔
90
        INSTRUMENT_TYPE.CS, INSTRUMENT_TYPE.FUTURE, INSTRUMENT_TYPE.ETF, INSTRUMENT_TYPE.LOF, INSTRUMENT_TYPE.INDX,
91
        INSTRUMENT_TYPE.PUBLIC_FUND, INSTRUMENT_TYPE.REITs
92
    )
93

94
    def __init__(self, base_config) -> None:
8✔
95
        path = base_config.data_bundle_path
8✔
96
        custom_future_info = getattr(base_config, "future_info", {})
8✔
97
        if not os.path.exists(path):
8✔
98
            raise RuntimeError('bundle path {} not exist'.format(os.path.abspath(path)))
×
99

100
        def _p(name):
8✔
101
            return os.path.join(path, name)
8✔
102
        
103
        # static registered storages
104
        self._future_info_store = FutureInfoStore(_p("future_info.json"), custom_future_info)
8✔
105
        self._yield_curve = YieldCurveStore(_p('yield_curve.h5'))
8✔
106
        self._share_transformation = ShareTransformationStore(_p('share_transformation.json'))
8✔
107
        self._suspend_days = [DateSet(_p('suspended_days.h5'))]  # type: List[AbstractDateSet]
8✔
108
        self._st_stock_days = DateSet(_p('st_stock_days.h5'))
8✔
109

110
        # dynamic registered storages
111
        self._ins_id_or_sym_type_map: Dict[str, INSTRUMENT_TYPE] = {}
8✔
112
        self._day_bar_stores: Dict[Tuple[INSTRUMENT_TYPE, MARKET], AbstractDayBarStore] = {}
8✔
113
        self._dividend_stores: Dict[Tuple[INSTRUMENT_TYPE, MARKET], AbstractDividendStore] = {}
8✔
114
        self._split_stores: Dict[Tuple[INSTRUMENT_TYPE, MARKET], AbstractSimpleFactorStore] = {}
8✔
115
        self._calendar_stores: Dict[TRADING_CALENDAR_TYPE, AbstractCalendarStore] = {}
8✔
116
        self._ex_factor_stores: Dict[Tuple[INSTRUMENT_TYPE, MARKET], AbstractSimpleFactorStore] = {}
8✔
117

118
        # instruments
119
        self._id_instrument_map: DefaultDict[str, dict[datetime, Instrument]] = defaultdict(dict)
8✔
120
        self._sym_instrument_map: DefaultDict[str, dict[datetime, Instrument]] = defaultdict(dict)
8✔
121
        self._id_or_sym_instrument_map: Mapping[str, dict[datetime, Instrument]] = ChainMap(self._id_instrument_map, self._sym_instrument_map)
8✔
122
        self._grouped_instruments: DefaultDict[INSTRUMENT_TYPE, dict[datetime, Instrument]] = defaultdict(dict)
8✔
123

124
        # register instruments
125
        self.register_instruments(load_instruments_from_pkl(_p('instruments.pk'), self._future_info_store))
8✔
126

127
        # register day bar stores
128
        funds_day_bar_store = DayBarStore(_p('funds.h5'))
8✔
129
        for ins_type, store in chain([
8✔
130
            (INSTRUMENT_TYPE.CS, DayBarStore(_p('stocks.h5'))),
131
            (INSTRUMENT_TYPE.INDX, DayBarStore(_p('indexes.h5'))),
132
            (INSTRUMENT_TYPE.FUTURE, FutureDayBarStore(_p('futures.h5'))),
133
        ], zip([INSTRUMENT_TYPE.ETF, INSTRUMENT_TYPE.LOF, INSTRUMENT_TYPE.REITs], repeat(funds_day_bar_store))):
134
            self.register_day_bar_store(ins_type, store)
8✔
135

136
        # register dividends and split factors stores
137
        dividend_store = DividendStore(_p('dividends.h5'))
8✔
138
        split_store = SimpleFactorStore(_p('split_factor.h5'))
8✔
139
        ex_factor_store = SimpleFactorStore(_p('ex_cum_factor.h5'))
8✔
140
        for ins_type in [INSTRUMENT_TYPE.CS, INSTRUMENT_TYPE.ETF, INSTRUMENT_TYPE.LOF, INSTRUMENT_TYPE.REITs]:
8✔
141
            self.register_dividend_store(ins_type, dividend_store)
8✔
142
            self.register_split_store(ins_type, split_store)
8✔
143
            self.register_ex_factor_store(ins_type, ex_factor_store)
8✔
144

145
        # register calendar stores
146
        self.register_calendar_store(TRADING_CALENDAR_TYPE.CN_STOCK, ExchangeTradingCalendarStore(_p("trading_dates.npy")))
8✔
147

148
    def register_day_bar_store(self, instrument_type: INSTRUMENT_TYPE, store: AbstractDayBarStore, market: MARKET = MARKET.CN):
8✔
149
        self._day_bar_stores[instrument_type, market] = store
8✔
150

151
    def register_instruments(self, instruments: Iterable[Instrument]):
8✔
152
        for ins in instruments:
8✔
153
            self._id_instrument_map[ins.order_book_id][ins.listed_date] = ins
8✔
154
            self._sym_instrument_map[ins.symbol][ins.listed_date] = ins
8✔
155
            self._grouped_instruments[ins.type][ins.listed_date] = ins
8✔
156
    
157
    def register_dividend_store(self, instrument_type: INSTRUMENT_TYPE, dividend_store: AbstractDividendStore, market: MARKET = MARKET.CN):
8✔
158
        self._dividend_stores[instrument_type, market] = dividend_store
8✔
159

160
    def register_split_store(self, instrument_type: INSTRUMENT_TYPE, split_store: AbstractSimpleFactorStore, market: MARKET = MARKET.CN):
8✔
161
        self._split_stores[instrument_type, market] = split_store
8✔
162

163
    def register_calendar_store(self, calendar_type: TRADING_CALENDAR_TYPE, calendar_store: AbstractCalendarStore):
8✔
164
        self._calendar_stores[calendar_type] = calendar_store
8✔
165

166
    def register_ex_factor_store(self, instrument_type: INSTRUMENT_TYPE, ex_factor_store: AbstractSimpleFactorStore, market: MARKET = MARKET.CN):
8✔
167
        self._ex_factor_stores[instrument_type, market] = ex_factor_store
8✔
168

169
    def append_suspend_date_set(self, date_set):
8✔
170
        # type: (AbstractDateSet) -> None
171
        self._suspend_days.append(date_set)
×
172

173
    @lru_cache(2048)
8✔
174
    def get_dividend(self, instrument):
7✔
175
        try:
8✔
176
            dividend_store = self._dividend_stores[instrument.type, instrument.market]
8✔
177
        except KeyError:
8✔
178
            return None
8✔
179

180
        return dividend_store.get_dividend(instrument.order_book_id)
8✔
181

182
    def get_trading_minutes_for(self, instrument, trading_dt):
8✔
183
        raise NotImplementedError
×
184

185
    def get_trading_calendars(self) -> Dict[TRADING_CALENDAR_TYPE, pd.DatetimeIndex]:
8✔
186
        return {t: store.get_trading_calendar() for t, store in self._calendar_stores.items()}
8✔
187

188
    def get_instruments(self, id_or_syms: Optional[Iterable[str]] = None, types: Optional[Iterable[INSTRUMENT_TYPE]] = None) -> Iterable[Instrument]:
8✔
189
        if id_or_syms is not None:
8✔
190
            seen = set()
8✔
191
            for i in id_or_syms:
8✔
192
                if i in self._id_or_sym_instrument_map:
8✔
193
                    for ins in self._id_or_sym_instrument_map[i].values():
8✔
194
                        if ins not in seen:
8✔
195
                            seen.add(ins)
8✔
196
                            yield ins
8✔
197
        else:
198
            for t in types or self._grouped_instruments.keys():
8✔
199
                yield from self._grouped_instruments[t].values()
8✔
200

201
    def get_share_transformation(self, order_book_id):
8✔
202
        return self._share_transformation.get_share_transformation(order_book_id)
8✔
203

204
    def is_suspended(self, order_book_id: str, dates: Sequence[DateLike]) -> List[bool]:
8✔
205
        for date_set in self._suspend_days:
8✔
206
            result = date_set.contains(order_book_id, dates)
8✔
207
            if result is not None:
8✔
208
                return result
8✔
209
        else:
210
            return [False] * len(dates)
8✔
211

212
    def is_st_stock(self, order_book_id: str, dates: Sequence[DateLike]) -> List[bool]:
8✔
213
        result = self._st_stock_days.contains(order_book_id, dates)
8✔
214
        return result if result is not None else [False] * len(dates)
8✔
215

216
    @lru_cache(None)
8✔
217
    def _all_day_bars_of(self, instrument):
7✔
218
        return self._day_bar_stores[instrument.type, instrument.market].get_bars(instrument.order_book_id)
8✔
219

220
    @lru_cache(None)
8✔
221
    def _filtered_day_bars(self, instrument):
7✔
222
        bars = self._all_day_bars_of(instrument)
8✔
223
        return bars[bars['volume'] > 0]
8✔
224

225
    def get_bar(self, instrument, dt, frequency):
8✔
226
        # type: (Instrument, Union[datetime, date], str) -> Optional[np.ndarray]
227
        if frequency != '1d':
8✔
228
            raise NotImplementedError
×
229

230
        bars = self._all_day_bars_of(instrument)
8✔
231
        if len(bars) <= 0:
8✔
232
            return
×
233
        dt_int = np.uint64(convert_date_to_int(dt))
8✔
234
        pos = bars['datetime'].searchsorted(dt_int)
8✔
235
        if pos >= len(bars) or bars['datetime'][pos] != dt_int:
8✔
236
            return None
×
237

238
        return bars[pos]
8✔
239

240
    OPEN_AUCTION_BAR_FIELDS = ["datetime", "open", "limit_up", "limit_down", "volume", "total_turnover"]
8✔
241

242
    def get_open_auction_bar(self, instrument, dt):
8✔
243
        # type: (Instrument, Union[datetime, date]) -> Dict
244
        day_bar = self.get_bar(instrument, dt, "1d")
8✔
245
        if day_bar is None:
8✔
246
            bar = dict.fromkeys(self.OPEN_AUCTION_BAR_FIELDS, np.nan)
×
247
        else:
248
            bar = {k: day_bar[k] if k in day_bar.dtype.names else np.nan for k in self.OPEN_AUCTION_BAR_FIELDS}
8✔
249
        bar["last"] = bar["open"]  # type: ignore
8✔
250
        return bar
8✔
251

252
    def get_settle_price(self, instrument, date):
8✔
253
        bar = self.get_bar(instrument, date, '1d')
8✔
254
        if bar is None:
8✔
255
            return np.nan
×
256
        return bar['settlement']
8✔
257

258
    @staticmethod
8✔
259
    def _are_fields_valid(fields, valid_fields):
7✔
260
        if fields is None:
8✔
261
            return True
×
262
        if isinstance(fields, six.string_types):
8✔
263
            return fields in valid_fields
8✔
264
        for field in fields:
8✔
265
            if field not in valid_fields:
8✔
266
                return False
×
267
        return True
8✔
268

269
    @lru_cache(1024)
8✔
270
    def get_ex_cum_factor(self, instrument: Instrument):
8✔
271
        try:
8✔
272
            ex_factor_store = self._ex_factor_stores[instrument.type, instrument.market]
8✔
273
        except KeyError:
×
274
            return None
×
275
        factors = ex_factor_store.get_factors(instrument.order_book_id)
8✔
276
        if factors is None:
8✔
NEW
277
            return None
×
278
        # 考虑代码复用的情况,需要过滤掉不在上市日期范围内到数据
279
        factors = factors[
8✔
280
            (factors["start_date"] >= convert_dt_to_int(instrument.listed_date)) & 
281
            (factors["start_date"] <= convert_dt_to_int(instrument.de_listed_date))
282
        ]
283
        if len(factors) == 0:
8✔
NEW
284
            return None
×
285
        if factors["start_date"][0] != 0:
8✔
286
            # kind of dirty,强行设置初始值为 1
287
            factors = np.concatenate([np.array([(0, 1.0)], dtype=factors.dtype), factors])
8✔
288
        return factors
8✔
289

290
    def _update_weekly_trading_date_index(self, idx):
8✔
291
        env = Environment.get_instance()
×
292
        if env.data_proxy.is_trading_date(idx):
×
293
            return idx
×
294
        return env.data_proxy.get_previous_trading_date(idx)
×
295

296
    def resample_week_bars(self, bars, bar_count: Optional[int], fields: Union[str, List[str]]):
8✔
297
        df_bars: pd.DataFrame = pd.DataFrame(bars)
×
298
        df_bars['datetime'] = df_bars.apply(lambda x: convert_int_to_datetime(x['datetime']), axis=1)
×
299
        df_bars = df_bars.set_index('datetime')
×
300
        nead_fields = fields
×
301
        if isinstance(nead_fields, str):
×
302
            nead_fields = [nead_fields]
×
303
        hows = {field: BAR_RESAMPLE_FIELD_METHODS[field] for field in nead_fields if field in BAR_RESAMPLE_FIELD_METHODS}
×
304
        df_bars = df_bars.resample('W-Fri').agg(hows)  # type: ignore
×
305
        df_bars.index = df_bars.index.map(self._update_weekly_trading_date_index)
×
306
        df_bars = cast(pd.DataFrame, df_bars[~df_bars.index.duplicated(keep='first')])
×
307
        df_bars.sort_index(inplace=True)
×
308
        if bar_count is not None:
×
309
            df_bars = cast(pd.DataFrame, df_bars[-bar_count:])
×
310
        df_bars = df_bars.reset_index()
×
311
        df_bars['datetime'] = df_bars.apply(lambda x: np.uint64(convert_date_to_int(x['datetime'].date())), axis=1)  # type: ignore
×
312
        df_bars = df_bars.set_index('datetime')
×
313
        bars = df_bars.to_records()
×
314
        return bars
×
315

316
    def history_bars(
8✔
317
        self, 
318
        instrument: Instrument, 
319
        bar_count: Optional[int], 
320
        frequency: str, 
321
        fields: Union[str, List[str], None], 
322
        dt: datetime, 
323
        skip_suspended: bool = True,
324
        include_now: bool = False, 
325
        adjust_type: str = 'pre', 
326
        adjust_orig: Optional[datetime] = None
327
    ) -> Optional[np.ndarray]:
328

329
        if frequency != '1d' and frequency != '1w':
8✔
330
            raise NotImplementedError
×
331

332
        if skip_suspended and instrument.type == 'CS':
8✔
333
            bars = self._filtered_day_bars(instrument)
8✔
334
        else:
335
            bars = self._all_day_bars_of(instrument)
8✔
336

337
        if not self._are_fields_valid(fields, bars.dtype.names):
8✔
338
            raise RQInvalidArgument("invalid fields: {}".format(fields))
×
339

340
        if len(bars) <= 0:
8✔
341
            return bars
8✔
342

343
        if frequency == '1w':
8✔
344
            if include_now:
×
345
                i = bars['datetime'].searchsorted(np.uint64(convert_date_to_int(dt)), side='right')
×
346
            else:
347
                monday = dt - timedelta(days=dt.weekday())
×
348
                monday = np.uint64(convert_date_to_int(monday))
×
349
                i = bars['datetime'].searchsorted(monday, side='left')
×
350
            
351
            if bar_count is None:
×
352
                left = 0
×
353
            else:
354
                left = i - bar_count * 5 if i >= bar_count * 5 else 0
×
355
            bars = bars[left:i]
×
356

NEW
357
            resample_fields: Union[str, List[str]] = list(bars.dtype.names) if fields is None else fields
×
358
            if adjust_type == 'none' or instrument.type in {'Future', 'INDX'}:
×
359
                # 期货及指数无需复权
NEW
360
                week_bars = self.resample_week_bars(bars, bar_count, resample_fields)
×
361
                return week_bars if fields is None else week_bars[fields]
×
362

363
            if isinstance(fields, str) and fields not in FIELDS_REQUIRE_ADJUSTMENT:
×
NEW
364
                week_bars = self.resample_week_bars(bars, bar_count, resample_fields)
×
365
                return week_bars if fields is None else week_bars[fields]
×
366

367
            adjust_bars_date = adjust_bars(bars, self.get_ex_cum_factor(instrument),
×
368
                                           fields, adjust_type, adjust_orig)
NEW
369
            adjust_week_bars = self.resample_week_bars(adjust_bars_date, bar_count, resample_fields)
×
370
            return adjust_week_bars if fields is None else adjust_week_bars[fields]
×
371
        i = bars['datetime'].searchsorted(np.uint64(convert_date_to_int(dt)), side='right')
8✔
372
        if bar_count is None:
8✔
373
            left = 0
8✔
374
        else:
375
            left = i - bar_count if i >= bar_count else 0
8✔
376
        bars = bars[left:i]
8✔
377
        if adjust_type == 'none' or instrument.type in {'Future', 'INDX'}:
8✔
378
            # 期货及指数无需复权
379
            return bars if fields is None else bars[fields]
8✔
380

381
        if isinstance(fields, str) and fields not in FIELDS_REQUIRE_ADJUSTMENT:
8✔
382
            return bars if fields is None else bars[fields]
×
383

384
        bars = adjust_bars(bars, self.get_ex_cum_factor(instrument),
8✔
385
                           fields, adjust_type, adjust_orig)
386

387
        return bars if fields is None else bars[fields]
8✔
388

389
    def current_snapshot(self, instrument, frequency, dt):
8✔
390
        raise NotImplementedError
×
391

392
    @lru_cache(2048)
8✔
393
    def get_split(self, instrument):
7✔
394
        try:
8✔
395
            splilt_store = self._split_stores[instrument.type, instrument.market]
8✔
396
        except KeyError:
8✔
397
            return None
8✔
398

399
        return splilt_store.get_factors(instrument.order_book_id)
8✔
400

401
    def available_data_range(self, frequency):
8✔
402
        # FIXME
403
        from rqalpha.const import DEFAULT_ACCOUNT_TYPE
8✔
404
        accounts = Environment.get_instance().config.base.accounts
8✔
405
        if not (DEFAULT_ACCOUNT_TYPE.STOCK in accounts or DEFAULT_ACCOUNT_TYPE.FUTURE in accounts):
8✔
406
            return date.min, date.max
8✔
407
        if frequency in ['tick', '1d']:
8✔
408
            s, e = self._day_bar_stores[INSTRUMENT_TYPE.INDX, MARKET.CN].get_date_range('000001.XSHG')
8✔
409
            return convert_int_to_date(s).date(), convert_int_to_date(e).date()
8✔
410

411
    def get_yield_curve(self, start_date, end_date, tenor=None):
8✔
412
        return self._yield_curve.get_yield_curve(start_date, end_date, tenor=tenor)
8✔
413

414
    @lru_cache(1024)
8✔
415
    def get_futures_trading_parameters(self, instrument: Instrument, dt: datetime) -> FuturesTradingParameters:
8✔
416
        return self._future_info_store.get_future_info(instrument.order_book_id, instrument.underlying_symbol)
8✔
417

418
    def get_merge_ticks(self, order_book_id_list, trading_date, last_dt=None):
8✔
419
        raise NotImplementedError
×
420

421
    def history_ticks(self, instrument, count, dt):
8✔
422
        raise NotImplementedError
×
423

424
    def get_algo_bar(self, id_or_ins: Union[str, Instrument], start_min: int, end_min: int, dt: datetime) -> Optional[np.ndarray]:
8✔
425
        raise NotImplementedError("open source rqalpha not support algo order")
×
426

427
    def get_open_auction_volume(self, instrument: Instrument, dt: datetime):
8✔
428
        volume = self.get_open_auction_bar(instrument, dt)['volume']
8✔
429
        return volume
8✔
430

431
    # deprecated
432
    def register_instruments_store(self, instruments_store, market: MARKET = MARKET.CN):
8✔
433
        system_log.warn("register_instruments_store is deprecated, please use register_instruments instead")
×
434
        self.register_instruments(instruments_store.get_instruments(None))
×
435

436
    exchange_rate_1 = ExchangeRate(
8✔
437
        bid_reference=1,
438
        ask_reference=1,
439
        bid_settlement_sh=1,
440
        ask_settlement_sh=1,
441
        bid_settlement_sz=1,
442
        ask_settlement_sz=1
443
    )
444

445
    def get_exchange_rate(self, trading_date: date, local: MARKET, settlement: MARKET = MARKET.CN) -> ExchangeRate:
8✔
446
        if local == settlement:
8✔
447
            return self.exchange_rate_1
8✔
448
        else:
449
            raise NotImplementedError
×
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc