Example #1
0
def dump_orders(orders, s, die=True):
    if len(orders) > 0:
        # print "\n", s
        logger.info(
            "order|%10s|%2s|%8s|%10s|%10s|%8s|%10s|%8s|%7s|%10s|%10s|%10s|%10s|%10s"
            % ("order_id", 'op', 'fund_id', 'place_date', 'place_time',
               'amount', 'share', 'fee', 'nav', 'nav_date', 'ack_date',
               'ack_amount', 'ack_share', 'share_id'))
    for o in orders:
        #     (order_id, fund_id, fund_code, op, place_date, place_time, amount, share, fee, nav, nav_date, ack_date, ack_amount, ack_share, div_mode)
        logger.info(
            "order|%s|%2d|%d|%s|%10s|%8.6f|%10.6f|%6.6f|%7.4f|%s|%s|%10.6f|%10.6f|%10s"
            % (o['order_id'], o['op'], o['fund_id'],
               o['place_date'].strftime("%Y-%m-%d"), o['place_time'],
               o['amount'], o['share'], o['fee'], o['nav'],
               o['nav_date'].strftime("%Y-%m-%d"),
               o['ack_date'].strftime("%Y-%m-%d"), o['ack_amount'],
               o['ack_share'], o['share_id']))

    if die:
        dd('----end orders----')
Example #2
0
def dump_event(x, e, die=False):
    dt, op, order_id, fund_id, argv = e
    if op == 0:
        s = "nav:%.4f, nav_date:%s" % (argv['nav'],
                                       argv['nav_date'].strftime("%Y-%m-%d"))
    elif op == 1:
        s = "at:%s %s, share:%.4f, nav:%.4f, fee:%.2f" % (
            argv['place_date'].strftime("%Y-%m-%d"), argv['place_time'],
            argv['share'], argv['nav'], argv['fee'])
    elif op == 11:
        s = "ack_date:%s, share:%.4f " % (
            argv['ack_date'].strftime("%Y-%m-%d"), argv['share'])
    elif op == 2:
        s = "at:%s %s, share:%.4f, nav:%.4f, fee:%.2f" % (
            argv['place_date'].strftime("%Y-%m-%d"), argv['place_time'],
            argv['share'], argv['nav'], argv['fee'])
    elif op == 12:
        s = "ack_date:%s, share:%.4f " % (
            argv['ack_date'].strftime("%Y-%m-%d"), argv['share'])
    elif op == 8:
        s = ''
    elif op == 15:
        s = ''
    elif op == 16:
        s = ''
    elif op == 17:
        s = ''
    elif op == 18:
        s = ''
    elif op == 100:
        s = ''
    elif op == 101:
        s = ''

    logger.info(
        "%c xev|%20s|%3d|%10s|%10s|%s" %
        (x, dt.strftime("%Y-%m-%d %H:%M:%S"), op, order_id, fund_id, s))

    if die:
        dd('----end events----')
Example #3
0
    def process(self, ev):
        result = []
        # 事件类型:0:净值更新;1:申购;2:赎回;3:分红;8:调仓;11:申购确认;12:赎回到账;15:分红登记;16:分红除息;17:分红派息;18:基金分拆;
        #         100:例行事件生成;101:记录当前持仓;
        dt, op, order_id, fund_id, argv = ev

        #
        # 更新模拟时钟
        #
        if dt >= self.ts:
            self.ts = dt
        else:
            #dd("SNH: ev out of date", self.ts, ev)
            pass

        if op == 0:
            #
            # 净值更新
            #
            if fund_id in self.df_share.index.levels[0]:
                # if dt.strftime("%Y-%m-%d") == '2014-11-11' and fund_id == 30000237:
                #     pdb.set_trace()
                # df = self.df_share.query('fund_id in [%d]' % fund_id)
                df = self.df_share.loc[self.df_share.index.get_level_values(0)
                                       == fund_id]
                self.df_share.loc[fund_id,
                                  'yield'] = (df['share'] + df['share_buying']
                                              ) * (argv['nav'] - df['nav'])
                self.df_share.loc[fund_id, 'nav'] = argv['nav']
                self.df_share.loc[fund_id, 'nav_date'] = argv['nav_date']
            else:
                dd("SNH: fund_id not in df_share.index", fund_id,
                   self.df_share)

        elif op == 1:
            #
            # 申购
            #
            self.cash -= argv['share'] * argv['nav'] + argv['fee']
            buy_date = argv['nav_date']
            df_tmp = self.make_share(fund_id, order_id, argv['share'],
                                     buy_date, argv['nav'], argv['nav_date'],
                                     argv['ack_date'], argv['div_mode'])
            self.df_share = self.df_share.append(df_tmp)
            # 记录购买费率
            self.dt_today_fee_buy[fund_id] = self.dt_today_fee_buy.setdefault(
                fund_id, 0) + (-argv['fee'])

            #
            # 生成申购确认事件
            #
            if argv['ack_date'].date() == dt.date():
                hours = 19
            else:
                hours = 2

            ev2 = (argv['ack_date'] + timedelta(hours=hours), 11, order_id,
                   fund_id, argv)
            result.append(ev2)

        elif op == 11:
            #
            # 申购确认
            #
            if argv['order_id'] in self.df_share.index.get_level_values(1):
                self.df_share.loc[(fund_id, order_id),
                                  'share'] = self.df_share.loc[(fund_id,
                                                                order_id),
                                                               'share_buying']
                self.df_share.loc[(fund_id, order_id), 'share_buying'] = 0

        elif op == 2:
            #
            # 赎回
            #
            left = self.df_share.loc[(fund_id, argv['share_id']),
                                     'share'] - argv['share']
            self.df_share.loc[(fund_id, argv['share_id']),
                              'share'] = left if left > 0.00000099 else 0
            # 生成赎回上下文
            row = (fund_id, argv['order_id'], argv['share_id'], argv['share'],
                   argv['nav'], argv['nav_date'], argv['ack_date'],
                   argv['fee'])
            tmp = pd.DataFrame([row],
                               columns=[
                                   'fund_id', 'redeem_id', 'share_id', 'share',
                                   'nav', 'nav_date', 'ack_date', 'fee'
                               ])
            self.df_redeem = self.df_redeem.append(
                tmp.set_index(['fund_id', 'redeem_id']))
            # 记录赎回费率
            self.dt_today_fee_redeem[
                fund_id] = self.dt_today_fee_redeem.setdefault(
                    fund_id, 0) + (-argv['fee'])

            #
            # 生成赎回确认事件
            #
            if argv['ack_date'].date() == dt.date():
                hours = 19
            else:
                hours = 2

            ev2 = (argv['ack_date'] + timedelta(hours=hours), 12, order_id,
                   fund_id, argv)
            result.append(ev2)

        elif op == 12:
            #
            # 赎回确认
            #
            # pdb.set_trace()
            self.cash += argv['share'] * argv['nav'] - argv['fee']
            self.df_redeem.drop((fund_id, argv['order_id']), inplace=True)

        elif op == 8:
            #
            # 调仓处理
            #
            # df_share: 是当前状态;argv['pos']: 是目标状态
            #
            # 调仓逻辑里面,首先取消掉所有未提交的订单,然后在根据当前状态
            # 重新生成订单
            #
            self.remove_flying_op()
            orders = self.adjust(dt, argv['pos'])
            #
            # 将订单插入事件队列
            #
            for order in orders:
                argv = order
                if order['op'] == 1:
                    ev2 = (order['nav_date'] + timedelta(hours=18), 1,
                           order['order_id'], order['fund_id'], argv)
                else:
                    ev2 = (order['nav_date'] + timedelta(hours=18, minutes=30),
                           2, order['order_id'], order['fund_id'], argv)
                result.append(ev2)

            self.orders.extend(orders)

        elif op == 15:
            #
            # 基金分红:权益登记
            #
            # [XXX] 这里啰嗦几句基金分红的处理:基金的分红方式有两种,
            # 现金分红和红利再投。
            #
            # 对于红利再投的方式,再投份额的折算发生在除息日,按照除息
            # 日的净值,但该部分份额不可赎回,直到派息日方可赎回。
            #
            # 对于现金分红方式,除息日扣除相应的净值,派息日打款
            #
            #
            df = self.df_share.loc[[fund_id]]
            df['share_bonusing'] = df['share'] + df['share_buying']
            # if dt.strftime("%Y-%m-%d") == '2013-05-16':
            #     pdb.set_trace()

            #
            # 生成分红订单,记录分红操作
            #
            share_dividend = df.loc[df['div_mode'] == 1,
                                    'share_bonusing'].sum()
            share_cash = df['share_bonusing'].sum() - share_dividend
            orders, dividend_id, cash_id = [], "0", "0"
            if share_dividend > 0.000000001:
                order = self.make_bonus_order(dt, fund_id, share_dividend,
                                              argv, 1)
                orders.append(order)
                dividend_id = order['order_id']

            if share_cash > 0.000000001:
                order = self.make_bonus_order(dt, fund_id, share_cash, argv, 0)
                orders.append(order)
                cash_id = order['order_id']
            if orders:
                dump_orders(orders, "bonus %s" % dt.strftime("%Y-%m-%d"),
                            False)
                self.orders.extend(orders)

            self.df_share.loc[[fund_id]] = df
            # dd(orders, argv, self.df_share.loc[[fund_id]], dt, share_dividend, share_cash, df)

            #
            # 调度除息事件
            #
            share = df['share_bonusing'].sum()
            if share > 0.000000001:
                argv2 = {
                    'share': share,
                    'bonus_ratio': argv['bonus_ratio'],
                    'bonus_nav': argv['bonus_nav'],
                    'bonus_nav_date': argv['bonus_nav_date'],
                    'payment_date': argv['payment_date'],
                    'order_dividend': dividend_id,
                    'order_cash': cash_id,
                }
                ev2 = (argv['dividend_date'] + timedelta(hours=16, minutes=30),
                       16, 0, fund_id, argv2)
                result.append(ev2)

        elif op == 16:
            #
            # 基金分红:除息
            #
            # pdb.set_trace()
            df = self.df_share.loc[[fund_id]]
            df['amount_bonusing'] = df['share_bonusing'] * argv['bonus_ratio']
            ev2 = (argv['payment_date'] + timedelta(hours=16, minutes=45), 17,
                   0, fund_id, argv)
            result.append(ev2)
            # 记录分红业绩
            self.dt_today_bonus[fund_id] = self.dt_today_bonus.setdefault(
                fund_id, 0) + df['amount_bonusing'].sum()

            #
            # 处理红利再投的份额转换
            #
            mask = (df['div_mode'] == 1)
            share = df.loc[mask, 'amount_bonusing'].sum() / argv['bonus_nav']
            #
            # 清除红利再投上下文
            #
            df.loc[mask, 'share_bonusing'] = 0
            df.loc[mask, 'amount_bonusing'] = 0

            self.df_share.loc[[fund_id]] = df

            #
            # 生成再投份额
            #
            df_tmp = self.make_share(fund_id, argv['order_dividend'], share,
                                     pd.to_datetime(dt.date()),
                                     argv['bonus_nav'], argv['bonus_nav_date'],
                                     argv['payment_date'], 1)
            self.df_share = self.df_share.append(df_tmp)

            # tmp = {
            #     'share': 0.0,
            #     'yield': 0.0,
            #     'share_buying': share,
            #     'nav': argv['bonus_nav'],
            #     'nav_date': argv['bonus_nav_date'],
            #     'buy_date': pd.to_datetime(dt.date()),
            #     'ack_date': argv['payment_date'],
            #     'share_bonusing': 0.0,
            #     'amount_bonusing': 0.0,
            #     'div_mode': 1,
            # }
            # self.df_share.loc[(fund_id, argv['order_dividend']), :] = tmp

        elif op == 17:
            # pdb.set_trace()
            #
            # 基金分红:派息
            #
            if fund_id in self.df_share.index.get_level_values(0):
                df = self.df_share.loc[[fund_id]]
                #
                # 现金分红
                #
                mask = (df['div_mode'] == 0)
                if mask.any():
                    self.cash_bounused = df.loc[mask, 'amount_bonusing'].sum()
                    #
                    # 清除现金分红上下文
                    #
                    df.loc[mask, 'share_bonusing'] = 0
                    df.loc[mask, 'amount_bonusing'] = 0

                #
                # 红利再投, 确认红利再投份额
                #
                if argv['order_dividend'] in df.index.get_level_values(1):
                    df.loc[(fund_id, argv['order_dividend']),
                           'share'] = df.loc[(fund_id, argv['order_dividend']),
                                             'share_buying']
                    df.loc[(fund_id, argv['order_dividend']),
                           'share_buying'] = 0

                self.df_share.loc[[fund_id]] = df

        elif op == 18:
            #
            # 基金分拆
            #

            df = self.df_share.loc[[fund_id]]
            df['share'] *= argv['ra_split_proportion']
            df['share_buying'] *= argv['ra_split_proportion']
            #
            # 理论上此时的净值为昨天的净值, 因为分拆是在调整今天净值之前处理的.
            #
            # 要保证后面日收益计算的正确, 这个地方需要对净值进行折算.
            #
            df['nav'] /= argv['ra_split_proportion']
            self.df_share.loc[[fund_id]] = df

        elif op == 100:
            #
            # 当日持仓相关的例行事件
            #
            result.extend(self.share_routine(dt, argv))

        elif op == 101:
            # if dt.strftime("%Y-%m-%d") in ['2014-02-10']:
            #     pdb.set_trace()
            day = pd.to_datetime(dt.date())

            #
            # 记录持仓
            #
            if self.debug and self.df_share.sum().sum() > 0.000099:
                self.dt_holding[dt] = self.df_share.copy()
            #
            # 记录净值
            #
            amount = (
                (self.df_share['share'] + self.df_share['share_buying']) *
                self.df_share['nav'] + self.df_share['amount_bonusing']).sum()
            amount += (self.df_redeem['share'] * self.df_redeem['nav'] -
                       self.df_redeem['fee']).sum() + self.cash
            self.nav[day] = amount
            #
            # 记录业绩归因
            #
            sr_yield = self.df_share['yield'].groupby(level=0).sum()
            sr_yield = sr_yield.loc[sr_yield.abs() > 0.00000099]
            sr_fee_buy = pd.Series(self.dt_today_fee_buy)
            sr_fee_redeem = pd.Series(self.dt_today_fee_redeem)
            sr_bonus = pd.Series(self.dt_today_bonus)

            sr_contrib = pd.concat({
                0: sr_yield,
                1: sr_fee_buy,
                2: sr_fee_redeem,
                3: sr_bonus
            })
            sr_contrib.index.names = ['ra_return_type', 'ra_fund_id']

            self.contrib[day] = sr_contrib

            #print "%s: %.6f / %.6f" % (day.strftime("%Y-%m-%d"), self.cash + 0.000000001, amount)

            #
            # 删除无用持仓
            #
            mask = (self.df_share['share'] + self.df_share['share_buying'] +
                    self.df_share['amount_bonusing']) < 0.000000001
            if mask.any():
                self.df_share.drop(self.df_share[mask].index, inplace=True)

            # self.idebug(dt)

        return result