def _validate_benchmark(bechmark_order_book_id, env): instrument = env.data_proxy.instruments(bechmark_order_book_id) if instrument is None: raise patch_user_exc( ValueError( _(u"invalid benchmark {}").format(bechmark_order_book_id))) if instrument.order_book_id == "000300.XSHG": # 000300.XSHG 数据进行了补齐,因此认为只要benchmark设置了000300.XSHG,就存在数据,不受限于上市日期。 return config = env.config start_date = config.base.start_date end_date = config.base.end_date if instrument.listed_date.date() > start_date: raise patch_user_exc( ValueError( _(u"benchmark {benchmark} has not been listed on {start_date}" ).format(benchmark=bechmark_order_book_id, start_date=start_date))) if instrument.de_listed_date.date() < end_date: if config.base.run_type == RUN_TYPE.BACKTEST: msg = _( u"benchmark {benchmark} has been de_listed on {end_date}" ).format(benchmark=bechmark_order_book_id, end_date=end_date) else: msg = _( u"the target {benchmark} will be delisted in the short term. " u"please choose a sustainable target.").format( benchmark=bechmark_order_book_id) raise patch_user_exc(ValueError(msg))
def __getitem__(self, key): if not isinstance(key, six.string_types): raise patch_user_exc( ValueError( 'invalid key {} (use order_book_id please)'.format(key))) instrument = self._data_proxy.instruments(key) if instrument is None: raise patch_user_exc( ValueError('invalid order book id or symbol: {}'.format(key))) order_book_id = instrument.order_book_id try: return self._cache[order_book_id] except KeyError: try: #system_log.debug("order_book_id1=" + order_book_id + ", dt=" + str(self._dt)) bar = self._data_proxy.get_bar(order_book_id, self._dt, self._frequency) #system_log.debug("order_book_id2=" + order_book_id + ", dt=" + str(self._dt)) except Exception as e: system_log.exception(e) raise patch_user_exc( KeyError( _(u"id_or_symbols {} does not exist").format(key))) if bar is None: return BarObject(instrument, NANDict, self._dt) else: self._cache[order_book_id] = bar return bar
def start_up(self, env, mod_config): mod_config.matching_type = self.parse_matching_type(mod_config.matching_type) if mod_config.commission_multiplier < 0: raise patch_user_exc(ValueError(_(u"invalid commission multiplier value: value range is [0, +∞)"))) if env.config.base.margin_multiplier <= 0: raise patch_user_exc(ValueError(_(u"invalid margin multiplier value: value range is (0, +∞]"))) if env.config.base.frequency == "tick": mod_config.volume_limit = False if mod_config.matching_type not in [ MATCHING_TYPE.NEXT_TICK_LAST, MATCHING_TYPE.NEXT_TICK_BEST_OWN, MATCHING_TYPE.NEXT_TICK_BEST_COUNTERPARTY, ]: raise RuntimeError(_("Not supported matching type {}").format(mod_config.matching_type)) else: if mod_config.matching_type not in [ MATCHING_TYPE.NEXT_BAR_OPEN, MATCHING_TYPE.CURRENT_BAR_CLOSE, ]: raise RuntimeError(_("Not supported matching type {}").format(mod_config.matching_type)) if mod_config.signal: env.set_broker(SignalBroker(env, mod_config)) else: env.set_broker(SimulationBroker(env, mod_config)) event_source = SimulationEventSource(env, env.config.base.account_list) env.set_event_source(event_source)
def _validate_benchmark(config, data_proxy): benchmark = config.base.benchmark if benchmark is None: return instrument = data_proxy.instruments(benchmark) if instrument is None: raise patch_user_exc( ValueError(_(u"invalid benchmark {}").format(benchmark))) if instrument.order_book_id == "000300.XSHG": # 000300.XSHG 数据进行了补齐,因此认为只要benchmark设置了000300.XSHG,就存在数据,不受限于上市日期。 return config = Environment.get_instance().config start_date = config.base.start_date end_date = config.base.end_date if instrument.listed_date.date() > start_date: raise patch_user_exc( ValueError( _(u"benchmark {benchmark} has not been listed on {start_date}" ).format(benchmark=benchmark, start_date=start_date))) if instrument.de_listed_date.date() < end_date: raise patch_user_exc( ValueError( _(u"benchmark {benchmark} has been de_listed on {end_date}"). format(benchmark=benchmark, end_date=end_date)))
def _verify_function(name, func): if not callable(func): raise patch_user_exc(ValueError('scheduler.{}: func should be callable'.format(name))) sig = signature(func) if len(sig.parameters) != 2: raise patch_user_exc(TypeError( 'scheduler.{}: func should take exactly 2 arguments (context, bar_dict)'.format(name)))
def start_up(self, env, mod_config): if env.config.base.run_type == RUN_TYPE.LIVE_TRADING: return mod_config.matching_type = self.parse_matching_type(mod_config.matching_type) if mod_config.commission_multiplier < 0: raise patch_user_exc(ValueError(_(u"invalid commission multiplier value: value range is [0, +∞)"))) if env.config.base.margin_multiplier <= 0: raise patch_user_exc(ValueError(_(u"invalid margin multiplier value: value range is (0, +∞]"))) if env.config.base.frequency == "tick": mod_config.volume_limit = False if mod_config.matching_type not in [ MATCHING_TYPE.NEXT_TICK_LAST, MATCHING_TYPE.NEXT_TICK_BEST_OWN, MATCHING_TYPE.NEXT_TICK_BEST_COUNTERPARTY, ]: raise RuntimeError(_("Not supported matching type {}").format(mod_config.matching_type)) else: if mod_config.matching_type not in [ MATCHING_TYPE.NEXT_BAR_OPEN, MATCHING_TYPE.CURRENT_BAR_CLOSE, ]: raise RuntimeError(_("Not supported matching type {}").format(mod_config.matching_type)) if mod_config.signal: env.set_broker(SignalBroker(env, mod_config)) else: env.set_broker(SimulationBroker(env, mod_config)) event_source = SimulationEventSource(env) env.set_event_source(event_source)
def run_weekly(self, func, weekday=None, tradingday=None, time_rule=None): _verify_function('run_weekly', func) if (weekday is not None and tradingday is not None) or (weekday is None and tradingday is None): raise patch_user_exc( ValueError('select one of weekday/tradingday')) if weekday is not None: if weekday < 1 or weekday > 7: raise patch_user_exc( ValueError('invalid weekday, should be in [1, 7]')) day_checker = lambda: self._is_weekday(weekday - 1) else: if tradingday > 5 or tradingday < -5 or tradingday == 0: raise patch_user_exc( ValueError( 'invalid trading day, should be in [-5, 0), (0, 5]')) if tradingday > 0: tradingday -= 1 day_checker = lambda: self._is_nth_trading_day_in_week(tradingday) time_checker = self._time_rule_for(time_rule) self._registry.append((day_checker, time_checker, func))
def __getitem__(self, key): if not isinstance(key, six.string_types): raise patch_user_exc(ValueError('invalid key {} (use order_book_id please)'.format(key))) instrument = self._data_proxy.instruments(key) if instrument is None: raise patch_user_exc(ValueError('invalid order book id or symbol: {}'.format(key))) order_book_id = instrument.order_book_id try: return self._cache[order_book_id] except KeyError: try: if not self._dt: return BarObject(instrument, NANDict, self._dt) if ExecutionContext.phase() == EXECUTION_PHASE.OPEN_AUCTION: bar = self._data_proxy.get_open_auction_bar(order_book_id, self._dt) else: bar = self._data_proxy.get_bar(order_book_id, self._dt, self._frequency) except PermissionError: raise except Exception as e: system_log.exception(e) raise patch_user_exc(KeyError(_(u"id_or_symbols {} does not exist").format(key))) if bar is None: return BarObject(instrument, NANDict, self._dt) else: self._cache[order_book_id] = bar return bar
def run_monthly(self, func, tradingday=None, time_rule=None, **kwargs): _verify_function('run_monthly', func) if tradingday is None and 'monthday' in kwargs: tradingday = kwargs.pop('monthday') if kwargs: raise patch_user_exc( ValueError('unknown argument: {}'.format(kwargs))) if tradingday is None: raise patch_user_exc(ValueError('tradingday is required')) if not isinstance(tradingday, int): raise patch_user_exc( ValueError('tradingday: <int> excpected, {} got'.format( repr(tradingday)))) if tradingday > 23 or tradingday < -23 or tradingday == 0: raise patch_user_exc( ValueError( 'invalid tradingday, should be in [-23, 0), (0, 23]')) if tradingday > 0: tradingday -= 1 time_checker = self._time_rule_for(time_rule) self._registry.append( (lambda: self._is_nth_trading_day_in_month(tradingday), time_checker, func))
def cancel_order(order): """ 撤单 :param order: 需要撤销的order对象 :type order: :class:`~Order` object """ if order is None: patch_user_exc(KeyError(_(u"Cancel order fail: invalid order id"))) env = Environment.get_instance() if env.can_cancel_order(order): env.broker.cancel_order(order) return order
def start_up(self, env, mod_config): mod_config.matching_type = self.parse_matching_type(mod_config.matching_type) if mod_config.commission_multiplier < 0: raise patch_user_exc(ValueError(_(u"invalid commission multiplier value: value range is [0, +∞)"))) if env.config.base.margin_multiplier <= 0: raise patch_user_exc(ValueError(_(u"invalid margin multiplier value: value range is (0, +∞]"))) if mod_config.signal: env.set_broker(SignalBroker(env, mod_config)) else: env.set_broker(SimulationBroker(env, mod_config)) event_source = SimulationEventSource(env, env.config.base.account_list) env.set_event_source(event_source)
def _get_universe(self): universe = self._env.get_universe() if len(universe) == 0 and DEFAULT_ACCOUNT_TYPE.STOCK.name not in self._config.base.accounts: raise patch_user_exc(RuntimeError(_( "Current universe is empty. Please use subscribe function before trade" )), force=True) return universe
def _get_universe(self): universe = Environment.get_instance().universe if len(universe) == 0 and ACCOUNT_TYPE.STOCK not in self._account_list: error = CustomError() error.set_msg("Current universe is empty. Please use subscribe function before trade") raise patch_user_exc(CustomException(error)) return universe
def start_up(self, env, mod_config): if mod_config.commission_multiplier < 0: raise patch_user_exc( ValueError( _(u"invalid commission multiplier value: value range is [0, +∞)" ))) if env.config.base.market == MARKET.CN: for instrument_type in INST_TYPE_IN_STOCK_ACCOUNT: if instrument_type == INSTRUMENT_TYPE.PUBLIC_FUND: continue env.set_transaction_cost_decider( instrument_type, CNStockTransactionCostDecider( mod_config.commission_multiplier, mod_config.cn_stock_min_commission)) env.set_transaction_cost_decider( INSTRUMENT_TYPE.FUTURE, CNFutureTransactionCostDecider( mod_config.commission_multiplier)) elif env.config.base.market == MARKET.HK: for instrument_type in INST_TYPE_IN_STOCK_ACCOUNT: env.set_transaction_cost_decider( instrument_type, HKStockTransactionCostDecider( mod_config.commission_multiplier, mod_config.hk_stock_min_commission))
def start_up(self, env, mod_config): if mod_config.commission_multiplier < 0: raise patch_user_exc( ValueError( _(u"invalid commission multiplier value: value range is [0, +∞)" ))) if env.config.base.market == MARKET.CN: env.set_transaction_cost_decider( DEFAULT_ACCOUNT_TYPE.STOCK, CNStockTransactionCostDecider( mod_config.commission_multiplier, mod_config.cn_stock_min_commission)) env.set_transaction_cost_decider( DEFAULT_ACCOUNT_TYPE.FUTURE, CNFutureTransactionCostDecider( mod_config.commission_multiplier)) elif env.config.base.market == MARKET.HK: env.set_transaction_cost_decider( DEFAULT_ACCOUNT_TYPE.STOCK, HKStockTransactionCostDecider( mod_config.commission_multiplier, mod_config.hk_stock_min_commission))
def _get_universe(self): universe = self._env.get_universe() if len(universe) == 0 and ACCOUNT_TYPE.STOCK not in self._account_list: error = CustomError() error.set_msg("Current universe is empty. Please use subscribe function before trade") raise patch_user_exc(CustomException(error)) return universe
def _get_universe(self): universe = self._env.get_universe() if len(universe) == 0 and DEFAULT_ACCOUNT_TYPE.STOCK.name not in self._config.base.accounts: error = CustomError() error.set_msg("Current universe is empty. Please use subscribe function before trade") raise patch_user_exc(CustomException(error), force=True) return universe
def compile_strategy(source_code, strategy, scope): try: code = compile(source_code, strategy, 'exec') six.exec_(code, scope) return scope except Exception as e: exc_type, exc_val, exc_tb = sys.exc_info() exc_val = patch_user_exc(exc_val, force=True) try: msg = str(exc_val) except Exception as e1: msg = "" six.print_(e1) error = CustomError() error.set_msg(msg) error.set_exc(exc_type, exc_val, exc_tb) stackinfos = list(traceback.extract_tb(exc_tb)) if isinstance(e, (SyntaxError, IndentationError)): error.add_stack_info(exc_val.filename, exc_val.lineno, "", exc_val.text) else: for item in stackinfos: filename, lineno, func_name, code = item if strategy == filename: error.add_stack_info(*item) # avoid empty stack if error.stacks_length == 0: error.add_stack_info(*item) raise CustomException(error)
def __init__(self, rate=0.): # Rate必须在0~1之间 if 0 <= rate < 1: self.rate = rate print('单向滑点为百分比滑点:', self.rate) else: raise patch_user_exc(ValueError(_(u"invalid slippage rate value: value range is [0, 1)")))
def __init__(self, rate=0.): if 0 <= rate: self.rate = rate else: raise patch_user_exc( ValueError( _(u"invalid slippage rate value: value range is greater than 0" )))
def _get_universe(self): universe = self._env.get_universe() if len(universe) == 0 and DEFAULT_ACCOUNT_TYPE.STOCK.name not in self._config.base.accounts: error = CustomError() error.set_msg( "Current universe is empty. Please use subscribe function before trade") raise patch_user_exc(CustomException(error), force=True) return universe
def wrapper(*args, **kwargs): phase = cls.stack.top.phase if phase not in phases: raise patch_user_exc( RuntimeError( _(u"You cannot call %s when executing %s") % (func.__name__, phase.value))) return func(*args, **kwargs)
def _time_rule_for(self, time_rule): if time_rule == 'before_trading': return lambda: self._is_before_trading() if time_rule is not None and not isinstance(time_rule, int): raise patch_user_exc(ValueError('invalid time_rule, "before_trading" or int expected, got {}'.format(repr(time_rule)))) time_rule = time_rule if time_rule else self._minutes_since_midnight(9, 31) return lambda: self._should_trigger(time_rule)
def run_weekly(self, func, weekday=None, tradingday=None, time_rule=None): _verify_function('run_weekly', func) if (weekday is not None and tradingday is not None) or (weekday is None and tradingday is None): raise patch_user_exc(ValueError('select one of weekday/tradingday')) if weekday is not None: if weekday < 1 or weekday > 7: raise patch_user_exc(ValueError('invalid weekday, should be in [1, 7]')) day_checker = lambda: self._is_weekday(weekday - 1) else: if tradingday > 5 or tradingday < -5 or tradingday == 0: raise patch_user_exc(ValueError('invalid trading day, should be in [-5, 0), (0, 5]')) if tradingday > 0: tradingday -= 1 day_checker = lambda: self._is_nth_trading_day_in_week(tradingday) time_checker = self._time_rule_for(time_rule) self._registry.append((day_checker, time_checker, func))
def get_trade_price(self, order, price): side = order.side tick_size = Environment.get_instance().data_proxy.instruments(order.order_book_id).tick_size() price = price + tick_size * self.rate * (1 if side == SIDE.BUY else -1) if price <= 0: raise patch_user_exc(ValueError(_(u"invalid slippage rate value {} which cause price <= 0").format(self.rate))) return price
def start_up(self, env, mod_config): mod_config.matching_type = self.parse_matching_type( mod_config.matching_type) if mod_config.commission_multiplier < 0: raise patch_user_exc( ValueError( _(u"invalid commission multiplier value: value range is [0, +∞)" ))) if env.config.base.margin_multiplier <= 0: raise patch_user_exc( ValueError( _(u"invalid margin multiplier value: value range is (0, +∞]" ))) if mod_config.signal: env.set_broker(SignalBroker(env, mod_config)) else: env.set_broker(SimulationBroker(env, mod_config)) event_source = SimulationEventSource(env, env.config.base.account_list) env.set_event_source(event_source)
def _validate_benchmark(bechmark_order_book_id, env): instrument = env.data_proxy.instruments(bechmark_order_book_id) if instrument is None: raise patch_user_exc(ValueError(_(u"invalid benchmark {}").format(bechmark_order_book_id))) if instrument.order_book_id == "000300.XSHG": # 000300.XSHG 数据进行了补齐,因此认为只要benchmark设置了000300.XSHG,就存在数据,不受限于上市日期。 return config = env.config start_date = config.base.start_date end_date = config.base.end_date if instrument.listed_date.date() > start_date: raise patch_user_exc(ValueError( _(u"benchmark {benchmark} has not been listed on {start_date}").format(benchmark=bechmark_order_book_id, start_date=start_date))) if instrument.de_listed_date.date() < end_date: raise patch_user_exc(ValueError( _(u"benchmark {benchmark} has been de_listed on {end_date}").format(benchmark=bechmark_order_book_id, end_date=end_date)))
def start_up(self, env, mod_config): self._env = env if env.config.base.run_type == RUN_TYPE.LIVE_TRADING: return mod_config.matching_type = self.parse_matching_type( mod_config.matching_type) if env.config.base.margin_multiplier <= 0: raise patch_user_exc( ValueError( _(u"invalid margin multiplier value: value range is (0, +∞]" ))) if env.config.base.frequency == "tick": mod_config.volume_limit = False if mod_config.matching_type not in [ MATCHING_TYPE.NEXT_TICK_LAST, MATCHING_TYPE.NEXT_TICK_BEST_OWN, MATCHING_TYPE.NEXT_TICK_BEST_COUNTERPARTY, MATCHING_TYPE.COUNTERPARTY_OFFER, ]: raise RuntimeError( _("Not supported matching type {}").format( mod_config.matching_type)) else: if mod_config.matching_type not in [ MATCHING_TYPE.NEXT_BAR_OPEN, MATCHING_TYPE.VWAP, MATCHING_TYPE.CURRENT_BAR_CLOSE, ]: raise RuntimeError( _("Not supported matching type {}").format( mod_config.matching_type)) if env.config.base.frequency == "1d" and mod_config.matching_type == MATCHING_TYPE.NEXT_BAR_OPEN: mod_config.matching_type = MATCHING_TYPE.CURRENT_BAR_CLOSE user_system_log.warn( _(u"matching_type = 'next_bar' is abandoned when frequency == '1d'," u"Current matching_type is 'current_bar'.")) if mod_config.signal: env.set_broker(SignalBroker(env, mod_config)) else: env.set_broker(SimulationBroker(env, mod_config)) if mod_config.management_fee: env.event_bus.add_listener(EVENT.POST_SYSTEM_INIT, self.register_management_fee_calculator) event_source = SimulationEventSource(env) env.set_event_source(event_source)
def run_monthly(self, func, tradingday=None, time_rule=None, **kwargs): _verify_function('run_monthly', func) if tradingday is None and 'monthday' in kwargs: tradingday = kwargs.pop('monthday') if kwargs: raise patch_user_exc(ValueError('unknown argument: {}'.format(kwargs))) if tradingday is None: raise patch_user_exc(ValueError('tradingday is required')) if not isinstance(tradingday, int): raise patch_user_exc(ValueError('tradingday: <int> excpected, {} got'.format(repr(tradingday)))) if tradingday > 23 or tradingday < -23 or tradingday == 0: raise patch_user_exc(ValueError('invalid tradingday, should be in [-23, 0), (0, 23]')) if tradingday > 0: tradingday -= 1 time_checker = self._time_rule_for(time_rule) self._registry.append((lambda: self._is_nth_trading_day_in_month(tradingday), time_checker, func))
def _adjust_start_date(config, data_proxy): origin_start_date, origin_end_date = config.base.start_date, config.base.end_date start, end = data_proxy.available_data_range(config.base.frequency) config.base.start_date = max(start, config.base.start_date) config.base.end_date = min(end, config.base.end_date) config.base.trading_calendar = data_proxy.get_trading_dates(config.base.start_date, config.base.end_date) if len(config.base.trading_calendar) == 0: raise patch_user_exc(ValueError(_(u"There is no data between {start_date} and {end_date}. Please check your" u" data bundle or select other backtest period.").format( start_date=origin_start_date, end_date=origin_end_date))) config.base.start_date = config.base.trading_calendar[0].date() config.base.end_date = config.base.trading_calendar[-1].date() config.base.timezone = pytz.utc
def __getitem__(self, key): if not isinstance(key, six.string_types): raise patch_user_exc(ValueError('invalid key {} (use order_book_id please)'.format(key))) instrument = self._data_proxy.instruments(key) if instrument is None: raise patch_user_exc(ValueError('invalid order book id or symbol: {}'.format(key))) order_book_id = instrument.order_book_id try: return self._cache[order_book_id] except KeyError: try: if not self._dt: return BarObject(instrument, NANDict, self._dt) bar = self._data_proxy.get_bar(order_book_id, self._dt, self._frequency) except Exception as e: system_log.exception(e) raise patch_user_exc(KeyError(_(u"id_or_symbols {} does not exist").format(key))) if bar is None: return BarObject(instrument, NANDict, self._dt) else: self._cache[order_book_id] = bar return bar
def start_up(self, env, mod_config): if mod_config.commission_multiplier < 0: raise patch_user_exc(ValueError(_(u"invalid commission multiplier value: value range is [0, +∞)"))) if env.config.base.market == MARKET.CN: env.set_transaction_cost_decider(DEFAULT_ACCOUNT_TYPE.STOCK, CNStockTransactionCostDecider( mod_config.commission_multiplier, mod_config.cn_stock_min_commission )) env.set_transaction_cost_decider(DEFAULT_ACCOUNT_TYPE.FUTURE, CNFutureTransactionCostDecider( mod_config.commission_multiplier )) elif env.config.base.market == MARKET.HK: env.set_transaction_cost_decider(DEFAULT_ACCOUNT_TYPE.STOCK, HKStockTransactionCostDecider( mod_config.commission_multiplier, mod_config.hk_stock_min_commission ))
def deco(*args, **kwargs): try: return func(*args, **kwargs) except RQInvalidArgument: raise except Exception as e: if isinstance(e, TypeError): exc_info = sys.exc_info() try: ret = inspect.getcallargs(unwrapper(func), *args, **kwargs) except TypeError: t, v, tb = exc_info raise patch_user_exc(v.with_traceback(tb)) if getattr(e, EXC_EXT_NAME, EXC_TYPE.NOTSET) == EXC_TYPE.NOTSET: patch_system_exc(e) raise
def get_trade_price(self, order, price): # type: (Order, float) -> float if order.position_effect == POSITION_EFFECT.EXERCISE: raise NotImplementedError( "TickSizeSlippage cannot handle exercise order") tick_size = Environment.get_instance().data_proxy.instruments( order.order_book_id).tick_size() price = price + tick_size * self.rate * (1 if order.side == SIDE.BUY else -1) if price <= 0: raise patch_user_exc( ValueError( _(u"invalid slippage rate value {} which cause price <= 0" ).format(self.rate))) return price
def start_up(self, env, mod_config): if mod_config.commission_multiplier < 0 or mod_config.tax_multiplier < 0: raise patch_user_exc( ValueError( _(u"invalid commission multiplier or tax multiplier" u" value: value range is [0, +∞)"))) for instrument_type in INST_TYPE_IN_STOCK_ACCOUNT: if instrument_type == INSTRUMENT_TYPE.PUBLIC_FUND: continue env.set_transaction_cost_decider( instrument_type, CNStockTransactionCostDecider( mod_config.commission_multiplier, mod_config.cn_stock_min_commission, mod_config.tax_multiplier)) env.set_transaction_cost_decider( INSTRUMENT_TYPE.FUTURE, CNFutureTransactionCostDecider(mod_config.commission_multiplier))
def __init__(self, rate=0.): # Rate必须在0~1之间 if 0 <= rate < 1: self.rate = rate else: raise patch_user_exc(ValueError(_(u"invalid slippage rate value: value range is [0, 1)")))
def __init__(self, rate=0.): if 0 <= rate: self.rate = rate else: raise patch_user_exc(ValueError(_(u"invalid slippage rate value: value range is greater than 0")))
def wrapper(*args, **kwargs): phase = cls.stack.top.phase if phase not in phases: raise patch_user_exc( RuntimeError(_(u"You cannot call %s when executing %s") % (func.__name__, phase.value))) return func(*args, **kwargs)
def _get_universe(self): universe = self._env.get_universe() if len(universe) == 0 and DEFAULT_ACCOUNT_TYPE.STOCK.name not in self._config.base.accounts: raise patch_user_exc(RuntimeError(_("Current universe is empty. Please use subscribe function before trade")), force=True) return universe