예제 #1
0
    def _handle_dividend_book_closure(self, trading_date):
        for order_book_id, position in six.iteritems(self._positions):
            if position.quantity == 0:
                continue

            dividend = Environment.get_instance(
            ).data_proxy.get_dividend_by_book_date(order_book_id, trading_date)
            if dividend is None:
                continue

            dividend_per_share = dividend[
                'dividend_cash_before_tax'] / dividend['round_lot']
            position.dividend_(dividend_per_share)

            config = Environment.get_instance().config
            if config.extra.dividend_reinvestment:
                last_price = Environment.get_instance().data_proxy.get_bar(
                    order_book_id, trading_date).close
                shares = position.quantity * dividend_per_share / last_price
                position._quantity += shares
            else:
                self._dividend_receivable[order_book_id] = {
                    'quantity': position.quantity,
                    'dividend_per_share': dividend_per_share,
                    'payable_date':
                    self._int_to_date(dividend['payable_date']),
                }
예제 #2
0
 def _before_trading(self, event):
     trading_date = Environment.get_instance().trading_dt.date()
     last_date = Environment.get_instance(
     ).data_proxy.get_previous_trading_date(trading_date)
     self._handle_dividend_book_closure(last_date)
     self._handle_dividend_payable(trading_date)
     self._handle_split(trading_date)
예제 #3
0
def plot(series_name, value):
    """
    Add a point to custom series.
    :param str series_name: the name of custom series
    :param float value: the value of the series in this time
    :return: None
    """
    Environment.get_instance().add_plot(series_name, value)
예제 #4
0
 def is_de_listed(self):
     """
     判断合约是否过期
     """
     instrument = Environment.get_instance().get_instrument(
         self._order_book_id)
     current_date = Environment.get_instance().trading_dt
     if instrument.de_listed_date is not None and current_date >= instrument.de_listed_date:
         return True
     return False
예제 #5
0
    def init(self):
        if not self._init:
            return

        with ExecutionContext(EXECUTION_PHASE.ON_INIT):
            with ModifyExceptionFromType(EXC_TYPE.USER_EXC):
                self._init(self._user_context)

        Environment.get_instance().event_bus.publish_event(
            Event(EVENT.POST_USER_INIT))
예제 #6
0
def update_universe(id_or_symbols):
    """
    该方法用于更新现在关注的证券的集合(e.g.:股票池)。PS:会在下一个bar事件触发时候产生(新的关注的股票池更新)效果。并且update_universe会是覆盖(overwrite)的操作而不是在已有的股票池的基础上进行增量添加。比如已有的股票池为['000001.XSHE', '000024.XSHE']然后调用了update_universe(['000030.XSHE'])之后,股票池就会变成000030.XSHE一个股票了,随后的数据更新也只会跟踪000030.XSHE这一个股票了。

    :param id_or_ins: 标的物
    :type id_or_ins: :class:`~Instrument` object | `str` | List[:class:`~Instrument`] | List[`str`]
    """
    if isinstance(id_or_symbols, (six.string_types, Instrument)):
        id_or_symbols = [id_or_symbols]
    order_book_ids = set(
        assure_order_book_id(order_book_id) for order_book_id in id_or_symbols)
    if order_book_ids != Environment.get_instance().get_universe():
        Environment.get_instance().update_universe(order_book_ids)
예제 #7
0
def is_suspended(order_book_id, count=1):
    """
    判断某只股票是否全天停牌。

    :param str order_book_id: 某只股票的代码或股票代码,可传入单只股票的order_book_id, symbol

    :param int count: 回溯获取的数据个数。默认为当前能够获取到的最近的数据

    :return: count为1时 `bool`; count>1时 `pandas.DataFrame`
    """
    dt = Environment.get_instance().calendar_dt.date()
    order_book_id = assure_stock_order_book_id(order_book_id)
    return Environment.get_instance().data_proxy.is_suspended(
        order_book_id, dt, count)
예제 #8
0
    def prev_close(self):
        """
        [float] 截止到当前的最低价
        """
        try:
            return self._data['prev_close']
        except (ValueError, KeyError):
            pass

        if self._prev_close is None:
            trading_dt = Environment.get_instance().trading_dt
            data_proxy = Environment.get_instance().data_proxy
            self._prev_close = data_proxy.get_prev_close(
                self._instrument.order_book_id, trading_dt)
        return self._prev_close
예제 #9
0
    def prev_settlement(self):
        """
        [float] 昨日结算价(期货专用)
        """
        try:
            return self._data['prev_settlement']
        except (ValueError, KeyError):
            pass

        if self._prev_settlement is None:
            trading_dt = Environment.get_instance().trading_dt
            data_proxy = Environment.get_instance().data_proxy
            self._prev_settlement = data_proxy.get_prev_settlement(
                self._instrument.order_book_id, trading_dt)
        return self._prev_settlement
예제 #10
0
 def register_event(self):
     """
     注册事件
     """
     event_bus = Environment.get_instance().event_bus
     event_bus.prepend_listener(EVENT.PRE_BEFORE_TRADING,
                                self._pre_before_trading)
예제 #11
0
    def suspended(self):
        if self.isnan:
            return True

        return Environment.get_instance().data_proxy.is_suspended(
            self._instrument.order_book_id,
            int(self._data['datetime'] // 1000000))
예제 #12
0
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)))
예제 #13
0
def order_lots(id_or_ins, amount, price=None, style=None):
    """
    指定手数发送买/卖单。如有需要落单类型当做一个参量传入,如果忽略掉落单类型,那么默认是市价单(market order)。

    :param id_or_ins: 下单标的物
    :type id_or_ins: :class:`~Instrument` object | `str`

    :param int amount: 下单量, 正数代表买入,负数代表卖出。将会根据一手xx股来向下调整到一手的倍数,比如中国A股就是调整成100股的倍数。

    :param float price: 下单价格,默认为None,表示 :class:`~MarketOrder`, 此参数主要用于简化 `style` 参数。

    :param style: 下单类型, 默认是市价单。目前支持的订单类型有 :class:`~LimitOrder` 和 :class:`~MarketOrder`
    :type style: `OrderStyle` object

    :return: :class:`~Order` object

    :example:

    .. code-block:: python

        #买入20手的平安银行股票,并且发送市价单:
        order_lots('000001.XSHE', 20)
        #买入10手平安银行股票,并且发送限价单,价格为¥10:
        order_lots('000001.XSHE', 10, style=LimitOrder(10))

    """
    order_book_id = assure_stock_order_book_id(id_or_ins)

    round_lot = int(
        Environment.get_instance().get_instrument(order_book_id).round_lot)

    style = cal_style(price, style)

    return order_shares(id_or_ins, amount * round_lot, style=style)
예제 #14
0
 def wrapper(*args, **kwargs):
     if not Environment.get_instance().config.extra.is_hold:
         return func(*args, **kwargs)
     else:
         system_log.debug(
             _(u"not run {}({}, {}) because strategy is hold").format(
                 func, args, kwargs))
예제 #15
0
def order_percent(id_or_ins, percent, price=None, style=None):
    """
    发送一个等于目前投资组合价值(市场价值和目前现金的总和)一定百分比的买/卖单,正数代表买,负数代表卖。股票的股数总是会被调整成对应的一手的股票数的倍数(1手是100股)。百分比是一个小数,并且小于或等于1(<=100%),0.5表示的是50%.需要注意,如果资金不足,该API将不会创建发送订单。

    :param id_or_ins: 下单标的物
    :type id_or_ins: :class:`~Instrument` object | `str`

    :param float percent: 占有现有的投资组合价值的百分比。正数表示买入,负数表示卖出。

    :param float price: 下单价格,默认为None,表示 :class:`~MarketOrder`, 此参数主要用于简化 `style` 参数。

    :param style: 下单类型, 默认是市价单。目前支持的订单类型有 :class:`~LimitOrder` 和 :class:`~MarketOrder`
    :type style: `OrderStyle` object

    :return: :class:`~Order` object

    :example:

    .. code-block:: python

        #买入等于现有投资组合50%价值的平安银行股票。如果现在平安银行的股价是¥10/股并且现在的投资组合总价值是¥2000,那么将会买入200股的平安银行股票。(不包含交易成本和滑点的损失):
        order_percent('000001.XSHG', 0.5)
    """
    if percent < -1 or percent > 1:
        raise RQInvalidArgument(_(u"percent should between -1 and 1"))

    style = cal_style(price, style)
    account = Environment.get_instance().portfolio.accounts[
        DEFAULT_ACCOUNT_TYPE.STOCK.name]
    return order_value(id_or_ins, account.total_value * percent, style=style)
예제 #16
0
 def get_commission(self, trade):
     order_book_id = trade.order_book_id
     env = Environment.get_instance()
     info = env.data_proxy.get_commission_info(order_book_id)
     commission = 0
     if info['commission_type'] == COMMISSION_TYPE.BY_MONEY:
         contract_multiplier = env.get_instrument(
             trade.order_book_id).contract_multiplier
         if trade.position_effect == POSITION_EFFECT.OPEN:
             commission += trade.last_price * trade.last_quantity * contract_multiplier * info[
                 'open_commission_ratio']
         else:
             commission += trade.last_price * (
                 trade.last_quantity - trade.close_today_amount
             ) * contract_multiplier * info['close_commission_ratio']
             commission += trade.last_price * trade.close_today_amount * contract_multiplier * info[
                 'close_commission_today_ratio']
     else:
         if trade.position_effect == POSITION_EFFECT.OPEN:
             commission += trade.last_quantity * info[
                 'open_commission_ratio']
         else:
             commission += (trade.last_quantity - trade.close_today_amount
                            ) * info['close_commission_ratio']
             commission += trade.close_today_amount * info[
                 'close_commission_today_ratio']
     return commission * self.multiplier
예제 #17
0
def order_target_value(id_or_ins, cash_amount, price=None, style=None):
    """
    买入/卖出并且自动调整该证券的仓位到一个目标价值。如果还没有任何该证券的仓位,那么会买入全部目标价值的证券。如果已经有了该证券的仓位,则会买入/卖出调整该证券的现在仓位和目标仓位的价值差值的数目的证券。需要注意,如果资金不足,该API将不会创建发送订单。

    :param id_or_ins: 下单标的物
    :type id_or_ins: :class:`~Instrument` object | `str` | List[:class:`~Instrument`] | List[`str`]

    :param float cash_amount: 最终的该证券的仓位目标价值。

    :param float price: 下单价格,默认为None,表示 :class:`~MarketOrder`, 此参数主要用于简化 `style` 参数。

    :param style: 下单类型, 默认是市价单。目前支持的订单类型有 :class:`~LimitOrder` 和 :class:`~MarketOrder`
    :type style: `OrderStyle` object

    :return: :class:`~Order` object

    :example:

    .. code-block:: python

        #如果现在的投资组合中持有价值¥3000的平安银行股票的仓位并且设置其目标价值为¥10000,以下代码范例会发送价值¥7000的平安银行的买单到市场。(向下调整到最接近每手股数即100的倍数的股数):
        order_target_value('000001.XSHE', 10000)
    """
    order_book_id = assure_stock_order_book_id(id_or_ins)
    account = Environment.get_instance().portfolio.accounts[
        DEFAULT_ACCOUNT_TYPE.STOCK.name]
    position = account.positions[order_book_id]

    style = cal_style(price, style)
    if cash_amount == 0:
        return _sell_all_stock(order_book_id, position.sellable, style)

    return order_value(order_book_id,
                       cash_amount - position.market_value,
                       style=style)
예제 #18
0
def is_st_stock(order_book_id, count=1):
    """
    判断股票在一段时间内是否为ST股(包括ST与*ST)。

    ST股是有退市风险因此风险比较大的股票,很多时候您也会希望判断自己使用的股票是否是'ST'股来避开这些风险大的股票。另外,我们目前的策略比赛也禁止了使用'ST'股。

    :param str order_book_id: 某只股票的代码,可传入单只股票的order_book_id, symbol

    :param int count: 回溯获取的数据个数。默认为当前能够获取到的最近的数据

    :return: count为1时 `bool`; count>1时 `pandas.DataFrame`
    """
    dt = Environment.get_instance().calendar_dt.date()
    order_book_id = assure_stock_order_book_id(order_book_id)
    return Environment.get_instance().data_proxy.is_st_stock(
        order_book_id, dt, count)
예제 #19
0
 def annualized_returns(self):
     """
     [float] 累计年化收益率
     """
     current_date = Environment.get_instance().trading_dt.date()
     return self.unit_net_value**(DAYS_CNT.DAYS_A_YEAR / float(
         (current_date - self.start_date).days + 1)) - 1
예제 #20
0
def industry(code):
    if not isinstance(code, six.string_types):
        code = code.code
    else:
        code = to_industry_code(code)

    return Environment.get_instance().data_proxy.industry(code)
예제 #21
0
def current_snapshot(id_or_symbol):
    """
    获得当前市场快照数据。只能在日内交易阶段调用,获取当日调用时点的市场快照数据。市场快照数据记录了每日从开盘到当前的数据信息,可以理解为一个动态的day bar数据。在目前分钟回测中,快照数据为当日所有分钟线累积而成,一般情况下,最后一个分钟线获取到的快照数据应当与当日的日线行情保持一致。需要注意,在实盘模拟中,该函数返回的是调用当时的市场快照情况,所以在同一个handle_bar中不同时点调用可能返回的数据不同。如果当日截止到调用时候对应股票没有任何成交,那么snapshot中的close, high, low, last几个价格水平都将以0表示。

    :param str order_book_id: 合约代码或简称

    :return: :class:`~Snapshot`

    :example:

    在handle_bar中调用该函数,假设策略当前时间是20160104 09:33:

    ..  code-block:: python3
        :linenos:

        [In]
        logger.info(current_snapshot('000001.XSHE'))
        [Out]
        2016-01-04 09:33:00.00  INFO
        Snapshot(order_book_id: '000001.XSHE', datetime: datetime.datetime(2016, 1, 4, 9, 33), open: 10.0, high: 10.025, low: 9.9667, last: 9.9917, volume: 2050320, total_turnover: 20485195, prev_close: 9.99)
    """
    env = Environment.get_instance()
    frequency = env.config.base.frequency
    order_book_id = assure_order_book_id(id_or_symbol)
    return env.data_proxy.current_snapshot(order_book_id, frequency,
                                           env.calendar_dt)
예제 #22
0
def sector(code):
    if not isinstance(code, six.string_types):
        code = code.name
    else:
        code = to_sector_name(code)

    return Environment.get_instance().data_proxy.sector(code)
예제 #23
0
def get_open_orders():
    """
    获取当日未成交订单数据

    :return: List[:class:`~Order` object]
    """
    return Environment.get_instance().broker.get_open_orders()
예제 #24
0
 def _handle_split(self, trading_date):
     data_proxy = Environment.get_instance().data_proxy
     for order_book_id, position in six.iteritems(self._positions):
         ratio = data_proxy.get_split_by_ex_date(order_book_id,
                                                 trading_date)
         if ratio is None:
             continue
         position.split_(ratio)
예제 #25
0
    def days_to_expire(self):
        if self.type != 'Future' or self.order_book_id[
                -2:] == '88' or self.order_book_id[-2:] == '99':
            return -1

        date = Environment.get_instance().trading_dt.date()
        days = (self.maturity_date.date() - date).days
        return -1 if days < 0 else days
예제 #26
0
 def value_percent(self):
     """
     [float] 获得该持仓的实时市场价值在总投资组合价值中所占比例,取值范围[0, 1]
     """
     accounts = Environment.get_instance().portfolio.accounts
     if DEFAULT_ACCOUNT_TYPE.STOCK.name not in accounts:
         return 0
     total_value = accounts[DEFAULT_ACCOUNT_TYPE.STOCK.name].total_value
     return 0 if total_value == 0 else self.market_value / total_value
예제 #27
0
    def universe(self):
        """
        list[`str`]

        在运行 :func:`update_universe`, :func:`subscribe` 或者 :func:`unsubscribe` 的时候,合约池会被更新。

        需要注意,合约池内合约的交易时间(包含股票的策略默认会在股票交易时段触发)是handle_bar被触发的依据。
        """
        return Environment.get_instance().get_universe()
예제 #28
0
    def basis_spread(self):
        try:
            return self._data['basis_spread']
        except (ValueError, KeyError):
            if self._instrument.type != 'Future' or Environment.get_instance(
            ).config.base.run_type != RUN_TYPE.PAPER_TRADING:
                raise

        if self._basis_spread is None:
            if self._instrument.underlying_symbol in ['IH', 'IC', 'IF']:
                order_book_id = self.INDEX_MAP[
                    self._instrument.underlying_symbol]
                bar = Environment.get_instance().data_proxy.get_bar(
                    order_book_id, None, '1m')
                self._basis_spread = self.close - bar.close
            else:
                self._basis_spread = np.nan
        return self._basis_spread
예제 #29
0
def get_account_type(order_book_id):
    from bwtougu.environment import Environment
    instrument = Environment.get_instance().get_instrument(order_book_id)
    enum_type = instrument.enum_type
    if enum_type in INST_TYPE_IN_STOCK_ACCOUNT:
        return DEFAULT_ACCOUNT_TYPE.STOCK.name
    elif enum_type == INSTRUMENT_TYPE.FUTURE:
        return DEFAULT_ACCOUNT_TYPE.FUTURE.name
    else:
        raise NotImplementedError
예제 #30
0
def assure_order_book_id(id_or_ins):
    if isinstance(id_or_ins, Instrument):
        order_book_id = id_or_ins.order_book_id
    elif isinstance(id_or_ins, six.string_types):
        order_book_id = Environment.get_instance().data_proxy.instruments(
            id_or_ins).order_book_id
    else:
        raise RQInvalidArgument(_(u"unsupported order_book_id type"))

    return order_book_id