示例#1
0
    def peg(self):
        # PEG = PE / 过去12个月的EPS增长率
        pe_daily = self.pe_daily
        basicepsyoy = self.basicepsyoy
        basicepsyoy = adjust_months(basicepsyoy)
        epsyoy = append_df(basicepsyoy, target_feq='D', fill_type='preceding')

        pe_daily = CALFUNC.del_dat_early_than(pe_daily, START_YEAR)
        epsyoy = CALFUNC.del_dat_early_than(epsyoy, START_YEAR)

        [pe_daily, epsyoy] = align(pe_daily, epsyoy)

        [h, l] = pe_daily.shape
        pe_ar = pe_daily.values
        eps_ar = epsyoy.values

        res = np.zeros([h, l])
        for i in range(0, h):
            for j in range(0, l):
                if pd.isna(eps_ar[i, j]) or eps_ar[i, j] == 0:
                    res[i, j] = np.nan
                else:
                    res[i, j] = pe_ar[i, j] / eps_ar[i, j]

        res_df = pd.DataFrame(data=res,
                              index=pe_daily.index,
                              columns=pe_daily.columns)

        return res_df
示例#2
0
def easy_bt(wei_stocks, basic_return_infor):
    data = Data()
    changepct_daily = data.CHANGEPECT_OPEN_DAILY
    changepct_daily = changepct_daily.shift(-1, axis=1)
    changepct_daily.dropna(how='all', axis=1, inplace=True)

    changepct_daily = changepct_daily / 100

    wei_stocks, changepct_daily = align(wei_stocks, changepct_daily)

    # fee_type='No_fee' 不计算佣金和印花税, 'fee_1'计算佣金和印花税,不计算冲击成本
    daily_return, net_value = back_test(changepct_daily, wei_stocks, fee_type='fee_1')
    # plt.plot(net_cpd)

    # 若有基准日度收益率,则计算累计超额收益率
    if isinstance(basic_return_infor, str):
        # 有基准收益,算超额收益
        basic_return = pd.read_csv(basic_return_infor, engine='python')
        basic_return = basic_return.set_index('date')
        if 'daily_return' in basic_return.columns:
            daily_excess_r = daily_return['daily_return'] - basic_return['daily_return']
        # 若没有日度收益数据,则根据日度净值数据计算出日度收益收益数据
        elif 'daily_return' not in basic_return.columns and 'net_value' in basic_return.columns:
            basic_return['daily_return'] = basic_return['net_value']/basic_return['net_value'].shift(1) - 1
            daily_excess_r = daily_return['daily_return'] - basic_return['daily_return']
            daily_excess_r.dropna(inplace=True)

        daily_excess_cum = (daily_excess_r + 1).cumprod()
        cum_excess_df = pd.DataFrame({'cum_excess_ret': daily_excess_cum})

    elif isinstance(basic_return_infor, pd.DataFrame):
        if 'daily_return' not in basic_return_infor.columns and 'net_value' in basic_return_infor.columns:
            basic_return_infor['daily_return'] = basic_return_infor['net_value'] / \
                                                 basic_return_infor['net_value'].shift(1) - 1
            daily_excess_r = daily_return['daily_return'] - basic_return_infor['daily_return']
            daily_excess_r.dropna(inplace=True)

        daily_excess_cum = (daily_excess_r + 1).cumprod()
        cum_excess_df = pd.DataFrame({'cum_excess_ret': daily_excess_cum})
    else:
        cum_excess_df = None

    return daily_return, net_value, cum_excess_df
示例#3
0
    def reverse_nm(self):
        '''
        1)在每个月底,对于股票s,回溯其过去N个交易日的数据(为方便处理, N取偶数);
        2)对于股票s,逐日计算平均单笔成交金额D(D = 当日成交金额 / 当日成交笔数),将N个交易日按D值从大到小排序,前N/2
          个交易日称为高D组,后N/2个交易日称为低D组;
        3)对于股票s,将高D组交易日的涨跌幅加总[1],得到因子M_high;将低D组交易日的涨跌幅加总,得到因子M_low;
        4) 对于所有股票,分别按照上述流程计算因子值。
        '''
        # n为20、60、180
        deals = self.turnoverdeals
        turnovervalue = self.turnovervalue_daily  # 成交额(万元)
        turnovervalue, deals = align(turnovervalue, deals)

        value_per_deal = turnovervalue / deals
        pct = self.changepct_daily / 100

        value_per_deal, pct = align(value_per_deal, pct)

        def _cal_M_reverse(series, pct_chg=None):
            code = series.name
            series = series.dropna()
            if len(series) == 0:
                return None

            series = series.sort_values()
            if len(series) % 2 == 1:
                low_vals = series.iloc[:len(series) // 2 + 1]
            else:
                low_vals = series.iloc[:len(series) // 2]
            high_vals = series.iloc[len(series) // 2:]
            m_high = (pct_chg.loc[code, high_vals.index] +
                      1).cumprod().iloc[-1] - 1
            m_low = (pct_chg.loc[code, low_vals.index] +
                     1).cumprod().iloc[-1] - 1
            res = m_high - m_low

            return res

        if self._status == 'update':
            new_mes = self._get_update_month('REVERSE_20')
            # 若返回None,表示没有更新必要,因子计算函数同样返回None
            if not new_mes:
                return None

            reverse_20 = self.REVERSE_20
            reverse_60 = self.REVERSE_60
            reverse_180 = self.REVERSE_180

        elif self._status == 'all':
            new_mes = [m for m in self._mes if m in value_per_deal.columns]
            reverse_20 = pd.DataFrame()
            reverse_60 = pd.DataFrame()
            reverse_180 = pd.DataFrame()

        for m in new_mes:
            print(m)
            loc = np.where(value_per_deal.columns == m)[0][0]
            if loc > 180:
                tmp_20 = value_per_deal.iloc[:, loc + 1 - 20:loc + 1].apply(
                    _cal_M_reverse, axis=1, args=(pct, ))
                tmp_60 = value_per_deal.iloc[:, loc + 1 - 60:loc + 1].apply(
                    _cal_M_reverse, axis=1, args=(pct, ))
                tmp_180 = value_per_deal.iloc[:, loc + 1 - 180:loc + 1].apply(
                    _cal_M_reverse, axis=1, args=(pct, ))

                reverse_20 = pd.concat(
                    [reverse_20, pd.DataFrame({m: tmp_20})], axis=1)
                reverse_60 = pd.concat(
                    [reverse_60, pd.DataFrame({m: tmp_60})], axis=1)
                reverse_180 = pd.concat(
                    [reverse_180, pd.DataFrame({m: tmp_180})], axis=1)

        reverse_20 = CALFUNC.del_dat_early_than(reverse_20, START_YEAR)
        reverse_60 = CALFUNC.del_dat_early_than(reverse_60, START_YEAR)
        reverse_180 = CALFUNC.del_dat_early_than(reverse_180, START_YEAR)

        res_dict = {
            "Reverse_20": reverse_20,
            "Reverse_60": reverse_60,
            "Reverse_180": reverse_180,
        }

        return res_dict
示例#4
0
    def month_bt(self):

        # 先对行和列取交集,然后再转换为array,再矩阵乘法得到每个月的收益,再判断是不是要去费,
        [self.weight, self.changePCT_np] = align(self.weight, self.changePCT_np)
        self.weight.fillna(0, inplace=True)
        self.changePCT_np.fillna(0, inplace=True)

        # 净值数据
        if self.fee_type == 'No_fee':
            ret_df = self.weight * self.changePCT_np
            # 月度收益pct
            self.net_pct = ret_df.sum(axis=0)
            self.net_value = (self.net_pct + 1).cumprod()
        else:
            # 计算出,每个月仓位变动中,没有变动的比例和变动的比率是多少
            unchanged_wei = pd.DataFrame(0, index=self.weight.index, columns=self.weight.columns)
            buy_wei = pd.DataFrame(0, index=self.weight.index, columns=self.weight.columns)
            sell_wei = pd.DataFrame(0, index=self.weight.index, columns=self.weight.columns)
            for col_i in range(0, len(self.weight.columns)):
                if col_i == 0:
                    buy_wei[self.weight.columns[col_i]] = self.weight[self.weight.columns[col_i]]
                else:
                    pre_i = col_i - 1
                    unchanged_wei[self.weight.columns[col_i]] = self.weight[self.weight.columns[pre_i:col_i + 1]].min(
                        axis=1)

                    cha = self.weight[self.weight.columns[col_i]] - self.weight[self.weight.columns[pre_i]]
                    buy_wei[self.weight.columns[col_i]] = cha.where(cha > 0, 0)
                    sell_wei[self.weight.columns[col_i]] = abs(cha.where(cha < 0, 0))

            wei_ar = self.weight.values
            change_pct_ar = self.changePCT_np.values
            unchanged_wei_ar = unchanged_wei.values
            buy_wei_ar = buy_wei.values
            sell_wei_ar = sell_wei.values

            # 双边佣金率0.02%,建仓冲击成本0.5%,减仓冲击成本0.3%,卖出单边印花税0.1%
            tax = 0.0001
            fee = 0.00002
            buy_impact_cost = 0.001
            sell_impact_cost = 0.001

            net_value_ar = np.zeros(wei_ar.shape)
            h_n, l_n = net_value_ar.shape
            net_value_se = np.zeros(l_n)
            for col in range(0, l_n):
                wei_tmp = wei_ar[:, col]
                change_pct_tmp = change_pct_ar[:, col]
                unchanged_wei_tmp = unchanged_wei_ar[:, col]
                buy_wei_tmp = buy_wei_ar[:, col]
                sell_wei_tmp = sell_wei_ar[:, col]

                if col != 0:

                    sell_wei_tmp.sum()
                    net_value_ar[:, col - 1].sum()
                    # 先减仓后才可加仓,建仓时产生的冲击成本对整体净值有影响
                    fee1 = (net_value_ar[:, col - 1] * sell_wei_tmp).sum() * (1 - sell_impact_cost) * tax   # 交的印花税
                    fee2 = (net_value_ar[:, col - 1] * sell_wei_tmp * sell_impact_cost).sum()            # 卖出冲击成本导致的减值
                    total_sell_impact_cost = fee1 + fee2

                # 新建仓的股票的本期收益,新建仓时的冲击成本对本期收益产生影响
                new_set = buy_wei_tmp * (1-fee) * (1 + change_pct_tmp/(1 + buy_impact_cost))
                # 仓位不变的股票的本期收益,仓位不变,不收冲击成本影响
                unc = unchanged_wei_tmp * (1 + change_pct_tmp)

                # 上期净值先减去卖出的成本得到本期基准净值,然后再得到本期的收益净值
                if col != 0:
                    net_value_ar[:, col] = net_value_se[col-1] * (1-total_sell_impact_cost) * (new_set + unc)
                    net_value_se[col] = net_value_ar[col].sum()
                else:
                    net_value_ar[:, col] = new_set
                    net_value_se[col] = new_set.sum()

            net_value = pd.Series(net_value_se, index=self.weight.index)

            return net_value