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

ricequant / rqalpha / 29477577340

16 Jul 2026 06:43AM UTC coverage: 70.68% (+1.1%) from 69.597%
29477577340

push

github

web-flow
feat: support partial fills for open orders with insufficient cash (#1019)

* in development

* feat: support partial fills for open orders with insufficient cash

* Refactor matchers to support partial fills on insufficient cash

* Fix partial-fill order handling in matchers

* Refactor matcher order handling to use typed exceptions for rejection, cancellation, and non-matchable states

* requires-python >= 3.8

* update

* update transaction

* update

---------

Co-authored-by: Don <lin.dongzhao@ricequant.com>
Co-authored-by: Cuizi7 <Cuizi7@users.noreply.github.com>
Co-authored-by: lingjun55 <lingjun5_5@qq.com>

385 of 535 new or added lines in 20 files covered. (71.96%)

123 existing lines in 7 files now uncovered.

8389 of 11869 relevant lines covered (70.68%)

4.93 hits per line

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

76.16
/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 ChainMap
7✔
18
import os
7✔
19
from datetime import date, datetime, timedelta
7✔
20
from itertools import chain, repeat
7✔
21
from typing import Dict, Iterable, List, Mapping, Optional, Sequence, Union, cast, Tuple
7✔
22

23
try:
7✔
24
    from typing import Protocol, runtime_checkable
7✔
UNCOV
25
except ImportError:
×
UNCOV
26
    from typing_extensions import Protocol, runtime_checkable
×
27

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

50

51
BAR_RESAMPLE_FIELD_METHODS = {
7✔
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
7✔
73
class BaseDataSourceProtocol(Protocol):
7✔
74
    def register_day_bar_store(self, instrument_type: INSTRUMENT_TYPE, store: AbstractDayBarStore, market: MARKET = MARKET.CN) -> None:
1✔
75
        ...
76
    def register_instruments(self, instruments: Iterable[Instrument]) -> None:
1✔
77
        ...
78
    def register_dividend_store(self, instrument_type: INSTRUMENT_TYPE, dividend_store: AbstractDividendStore, market: MARKET = MARKET.CN) -> None:
1✔
79
        ...
80
    def register_split_store(self, instrument_type: INSTRUMENT_TYPE, split_store: AbstractSimpleFactorStore, market: MARKET = MARKET.CN) -> None:
1✔
81
        ...
82
    def register_calendar_store(self, calendar_type: TRADING_CALENDAR_TYPE, calendar_store: AbstractCalendarStore) -> None:
1✔
83
        ...
84
    def register_ex_factor_store(self, instrument_type: INSTRUMENT_TYPE, ex_factor_store: AbstractSimpleFactorStore, market: MARKET = MARKET.CN) -> None:
1✔
85
        ...
86

87

88
class BaseDataSource(AbstractDataSource):
7✔
89
    DEFAULT_INS_TYPES = (
7✔
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:
7✔
95
        path = base_config.data_bundle_path
7✔
96
        custom_future_info = getattr(base_config, "future_info", {})
7✔
97
        if not os.path.exists(path):
7✔
98
            raise RuntimeError('bundle path {} not exist'.format(os.path.abspath(path)))
×
99

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

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

118
        # instruments
119
        self._id_instrument_map: Dict[str, Dict[datetime, Instrument]] = {}
7✔
120
        self._sym_instrument_map: Dict[str, Dict[datetime, Instrument]] = {}
7✔
121
        self._id_or_sym_instrument_map: Mapping[str, Dict[datetime, Instrument]] = ChainMap(self._id_instrument_map, self._sym_instrument_map)
7✔
122
        self._grouped_instruments: Dict[INSTRUMENT_TYPE, List[Instrument]] = {}
7✔
123

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

127
        # register day bar stores
128
        funds_day_bar_store = SecuritiesDayBarStore(_p('funds.h5'))
7✔
129
        for ins_type, store in chain([
7✔
130
            (INSTRUMENT_TYPE.CS, SecuritiesDayBarStore(_p('stocks.h5'))),
131
            (INSTRUMENT_TYPE.INDX, INDXDayBarStore(_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)
7✔
135

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

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

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

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

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

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

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

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

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

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

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

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

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

202
    def get_share_transformation(self, order_book_id):
7✔
203
        return self._share_transformation.get_share_transformation(order_book_id)
7✔
204

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

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

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

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

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

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

239
        return bars[pos]
7✔
240

241
    OPEN_AUCTION_BAR_FIELDS = ["datetime", "open", "limit_up", "limit_down", "volume", "total_turnover"]
7✔
242

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

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

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

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

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

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

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

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

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

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

341
        if len(bars) <= 0:
7✔
342
            return bars
7✔
343

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

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

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

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

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

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

388
        return bars if fields is None else bars[fields]
7✔
389

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

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

400
        return splilt_store.get_factors(instrument.order_book_id)
7✔
401

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

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

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

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

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

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

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

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

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

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

© 2026 Coveralls, Inc