예제 #1
0
 def __init__(self):
     self.cu_wind = sql_oracle.cu
     self.cu_pra = sql_oracle.cu_pra_sel
     self.time_tool = Time_tool()
     self.init_funcs()
     self.market = pd.DataFrame()
     self.gen_market()
예제 #2
0
    def __init__(self):
        self.cu = sql_oracle.cu
        self.cu_pra = sql_oracle.cu_pra_sel
        self.t = Time_tool()
        self.init_table()
        self.init_funcs()

        self.year_x = 52
예제 #3
0
class SeasonLabel(object):
    def __init__(self):
        self.cu_wind = sql_oracle.cu
        self.cu_pra = sql_oracle.cu_pra_sel
        self.time_tool = Time_tool()
        self.init_funcs()
        self.market = pd.DataFrame()
        self.gen_market()

    def init_funcs(self):
        '''初始化各种外挂方法'''
        classes = [LeverageRatio, StandardDeviation, MaxDrawDown, IntervalProfit, AlphaCategroy, SharpRation, DownStd]
        for class_ in classes:
            class_(self).add_func()

    def gen_time_list(self, start_date, end_date, s_type='daily', pre_flag=True):
        '''生成交易日序列
        s_type: daily, 日频; weekly, 周频
        pre_flag: True, 需要计算收益率的标签在取样时需要往前多取一个交易日
        attention: 算法不需要用前一交易日信息,但需要用前一日净值信息来替代, 
        '''
        t_list = []
        if s_type == 'daily':
            t_df = self.time_tool.get_trade_days(start_date, end_date)
            t_list = list(t_df.iloc[:, 0])
            if pre_flag == True:
                pre_day = self.time_tool.get_pre_trade_day(start_date)
                t_list.insert(0, pre_day)
        if s_type == 'weekly':
            t_df = self.time_tool.get_week_trade_days(start_date, end_date)
            t_list = list(t_df.iloc[:, 0])
            if pre_flag == True:
                pre_day = self.time_tool.get_pre_week_trade_day(start_date)
                t_list.insert(0, pre_day)
        return t_list

    def get_fund_price(self, code, start_date='', end_date='', time_list=[]):
        '''计算波动和回测时用到的sql查询方法'''
        if time_list:
            start_date = time_list[0]
            end_date = time_list[-1]
        sql = '''
        select
        f13_1101 as 截止日期, f21_1101 as 复权单位净值 
        from
        wind.tb_object_1101
        left join wind.tb_object_1090
        on f2_1090 = f14_1101
        where 
        F16_1090= '%(code)s'
        and
        F13_1101 >= '%(start_date)s'
        and
        f13_1101 <= '%(end_date)s'
        order by f13_1101
        ''' % {'end_date': end_date, 'code': code, 'start_date': start_date}
        fund_price = pd.DataFrame(self.cu_wind.execute(sql).fetchall(), columns=['日期', '复权单位净值'])
        fund_price.set_index('日期', inplace=True)
        if fund_price.empty:
            raise Exception('lact of fund value')
        if time_list:
            # 基金净值数据是按照周频发布
            # 基金成立在时间段中间,导致获取净值数据不足
            # if len(time_list) - fund_price.shape[0] > len(time_list) * 0.1:
            time_list_dt = pd.DataFrame(time_list, columns=['日期'])
            fund_price = pd.merge(time_list_dt, fund_price, on=['日期'], how='outer')
            if fund_price.shape[0] / len(time_list) < 0.9:
                raise Exception('lack of data, timelist>>fund_price.shape[0]')
            fund_price.fillna(method='ffill', inplace=True)
            fund_price = pd.merge(time_list_dt, fund_price, on=['日期'], how='left')
            fund_price.set_index(['日期'], inplace=True)
            # fund_price = fund_price.reindex(time_list)
        return fund_price

    def get_fund_price_biwi(self, code, start_date='', end_date='', time_list=[]):
        '''获取基金基准
        '''
        if time_list:
            t1, t2 = time_list[0], time_list[-1]
        else:
            t1, t2 = start_date, end_date
        sql_code = code + 'BI.WI'
        sql_week_close_bibw = f"""
        select  trade_dt,s_dq_close from wind.chinamutualfundbenchmarkeod 
        where s_info_windcode = '{sql_code}' and (trade_dt >= '{t1}' and trade_dt <='{t2}')
        order by trade_dt 
        """
        sql_res = self.cu_wind.execute(sql_week_close_bibw).fetchall()
        assert sql_res, f'{code}基准查询结果为空,请改变基准'
        df = pd.DataFrame(sql_res, columns=['日期', '收盘价'])
        if df.empty:
            raise Exception('基金基准查询结果为空')
        if df.shape[0] < len(time_list) * 0.9:
            raise Exception('基准数据不足')
        time_list_dt = pd.DataFrame(time_list, columns=['日期'])
        df = pd.merge(time_list_dt, df, on=['日期'], how='outer')
        df.fillna(method='ffill', inplace=True)
        df = pd.merge(time_list_dt, df, on=['日期'], how='left')
        df.set_index(['日期'], inplace=True)
        return df

    def get_ejfl_type(self, code, start_date, end_date):
        '''获取区间内第一个匹配的二级分类类型'''
        end_date = end_date[0: 4] + '1231'
        sql_string = f'''
        select * from (
            select ejfl from t_fund_classify_his
            where rptdate <= {end_date}
            and cpdm = {code}
            order by rptdate
        )
        where rownum=1 
        '''
        ejfl_type = self.cu_pra.execute(sql_string).fetchall()
        if ejfl_type:
            rst = ejfl_type[0][0]
        else:
            rst = None
        return rst

    def get_market(self, fund_type, time_list):
        """获取同类基准
         """
        if self.market.empty:
            self.gen_market()
        time_list_dt = pd.DataFrame(time_list, columns=['日期'])
        market_tmp = pd.merge(time_list_dt, self.market, on=['日期'], how='outer')
        market_tmp.fillna(method='ffill', inplace=True)
        market_tmp = pd.merge(time_list_dt, market_tmp, on=['日期'], how='left')
        market_all = pd.DataFrame()
        for i in ['中证800','中证国债','恒生指数','中证综合债','中证短债','中证可转债','MSCI']:
            market_all[str(i)+'收益率'] = market_tmp[str(i)].pct_change()
        if fund_type =='股票型':
            market_type  = market_all['中证800收益率']
        elif fund_type == '激进配置型':
            market_type = market_all['中证800收益率']*0.8+market_all['中证国债收益率']*0.2
        elif fund_type =='标准配置型':
            market_type = market_all['中证800收益率']*0.6+market_all['中证国债收益率']*0.4
        elif fund_type == '保守配置型':
            market_type = market_all['中证800收益率'] * 0.2 + market_all['中证国债收益率'] * 0.8
        elif fund_type == '灵活配置型':
            market_type = market_all['中证800收益率'] * 0.5 + market_all['中证国债收益率'] * 0.5
        elif fund_type == '沪港深股票型':
            market_type = market_all['中证800收益率'] * 0.45 + market_all['中证国债收益率'] * 0.1+market_all['恒生指数收益率']*0.45
        elif fund_type == '沪港深配置型':
            market_type = market_all['中证800收益率'] * 0.35 + market_all['中证国债收益率'] * 0.3 + market_all['恒生指数收益率'] * 0.35
        elif fund_type =='纯债型':
            market_type = market_all['中证综合债收益率']
        elif fund_type == '普通债券型':
            market_type = market_all['中证综合债收益率']*0.9+market_all['中证800收益率'] * 0.1
        elif fund_type == '激进债券型':
            market_type = market_all['中证综合债收益率']*0.8+market_all['中证800收益率'] * 0.2
        elif fund_type =='短债型':
            market_type = market_all['中证短债收益率']
        elif fund_type =='可转债型':
            market_type = market_all['中证可转债收益率']
        elif fund_type =='环球股票':
            market_type = market_all['MSCI收益率']
        else:
            market_type = np.array([])
        rst = pd.DataFrame(market_type, columns=['市场组合收益率'])
        rst['日期'] = time_list
        rst.set_index(['日期'], inplace=True)
        return rst

    def gen_market(self):
        '''计算同类基准
        中证800收益率, 中证国债收益率, 恒生指数收益率, 中证综合债收益率, 中证短债收益率
        MSCI收益率
        没有用到 中证可转债
        '''
        # 中证800
        market2 = self.market_fetch('000906')
        market1 = self.market_fetch('000001')
        market1 = market1[market1.index < '20050105']
        a = market2[market2.index == '20050104'].iloc[0, 0] / market1[market1.index== '20050104'].iloc[-1, 0]
        market1['000906'] = market1['000001'] * a
        index = market1[market1.index == '20050104'].index.tolist()[0]
        market_800 = pd.concat([market1[['000906']] , market2], axis=0).drop([index])

        # 中证国债
        m_country = self.market_fetch('h11006')
        # 恒生指数
        HSI  = self.get_market_wind('HSI.HI')
        #中证综合债
        m_bond = self.market_fetch('h11009')
        # 中证短债
        market_short = self.market_fetch('h11015')
        # 中证可转债
        market_tran = self.market_fetch('000832')
        # MSCI
        MSCI = self.get_market_wind("892400.MI")
        self.market = market_800.join([m_country,HSI,m_bond,market_short,market_tran,MSCI])
        self.market.columns = ['中证800','中证国债','恒生指数','中证综合债','中证短债','中证可转债','MSCI']
        return 

    def market_fetch(self, stock_index):
        '''获取所有交易日指数数据'''
        sql1 = '''
        SELECT
          T0.F2_1425 日期,
          T0.F7_1425 AS 复权收盘价
          FROM
            wind.TB_OBJECT_1425 T0
          LEFT JOIN wind.TB_OBJECT_1090 T1 ON T1.F2_1090 = T0.F1_1425
          WHERE
            T1.F16_1090 = '%(index_code)s'
          AND T1.F4_1090 = 'S'
          ORDER BY
            T0.F2_1425
        ''' % {'index_code': stock_index}
        market = pd.DataFrame(self.cu_wind.execute(sql1).fetchall(), columns=['日期', '指数收盘价'])
        market.index = market['日期']
        del market['日期']
        market.columns = [stock_index]
        # market = market.pct_change()
        return market

    def get_market_wind(slef, code, index_start_date='19900101', end_date='20190331'):
        try:
            df = w.wsd(code, "close", index_start_date, end_date, "","Currency=CNY", usedf=True)[1]
            #df = w.wsd(code, "close", "2015-01-01", end_date, "","Currency=CNY", usedf=True)[1]
            df.index = pd.Series(df.index).apply(lambda x: str(x)[:4] + str(x)[5:7] + str(x)[8:10])
            df.columns = [code]
        except:
            df = pd.DataFrame(columns=[code])
        return df

    def get_fund_price_fof(self, code, start_date='', end_date='', time_list=[]):
        '''fof 基金计算波动和回测时用到的sql查询方法'''
        if time_list:
            start_date = time_list[0]
            end_date = time_list[-1]
        sql = '''
        select
        tradedate, closeprice
        from
        t_fof_value_info 
        where 
        fundid = '%(code)s'
        and
        tradedate >= '%(start_date)s'
        and
        tradedate <= '%(end_date)s'
        ''' % {'end_date': end_date, 'code': code, 'start_date': start_date}
        fund_price = pd.DataFrame(self.cu_pra.execute(sql).fetchall(), columns=['日期', '复权单位净值'])
        fund_price.set_index('日期', inplace=True)
        if fund_price.empty:
            raise Exception('lact of fund value')
        if time_list:
            if len(time_list) - fund_price.shape[0] > 30:
                raise Exception('lack of data')
            fund_price = fund_price.reindex(time_list)
        return fund_price

    def get_fund_price_index(self, code, start_date='', end_date='', time_list=[]):
        '''获取指数的净值数据'''
        if time_list:
            start_date = time_list[0]
            end_date = time_list[-1]
        sql =f'''
        select f2_1425,f7_1425 from wind.tb_object_1425  left join wind.tb_object_1090  on f1_1425 = f2_1090
        where f16_1090 = '{code}'
        and (f2_1425 >='{start_date}' and f2_1425 <= '{end_date}')
        and f4_1090 = 'S'
        order by f2_1425
        '''
        fund_price = pd.DataFrame(self.cu_wind.execute(sql).fetchall(), columns=['日期', '复权单位净值'])
        fund_price.set_index('日期', inplace=True)
        if fund_price.empty:
            raise Exception('lact of fund value')
        if time_list:
            if len(time_list) - fund_price.shape[0] > 30:
                raise Exception('lack of data')
            fund_price = fund_price.reindex(time_list)
        return fund_price
예제 #4
0
class Week_return:
    """周收益率相关类
    对外接口:
    zhoubodong:波动率
        :param code: 代码:str
        :param start_date:起始日期 :str
        :param end_date: 结束日期:str
        :return: float

    max_down_fund:最大回测
        :param code: 代码:str
        :param start_date:起始日期 :str
        :param end_date: 结束日期:str
        :return: float


    performance_stability_fof:业绩稳定
        :param code: fof 代码:str
        :param start_date:起始日期 :str
        :param end_date: 结束日期:str
        :return: float


    compute_alpha2:计算alpha
        :param code: 代码:str
        :param start_date:起始日期 :str
        :param end_date: 结束日期:str
        :return: float

    abs_return:获取绝对收益率
        :param code: 代码:str
        :param start_date:起始日期 :str
        :param end_date: 结束日期:str
        :return: float

    performance_stability:业绩稳定,code
        :param code: 代码:str
        :param start_date:起始日期 :str
        :param end_date: 结束日期:str
        :return: float


    """

    def __init__(self):
        self.cu = sql_oracle.cu
        self.cu_pra = sql_oracle.cu_pra_sel
        self.t = Time_tool()
        self.init_table()
        self.init_funcs()


        self.year_x = 52

    def init_table(self):
        """初始化各种数据库表名"""
        self.fof_member_info = 't_fof_member_info'

    def init_funcs(self):
        """初始化各种外挂方法"""
        classes = [Compute_alpha]
        for class_ in classes:
            class_(self).add_func()

    def set_year_x(self, x):
        """设置计算年化时的系数"""
        self.year_x = x

    def _get_winning(self, df):
        """
        计算胜率
        :param df:超额收益
        :return: 胜率
        """
        # 超额收益大于0的个数/总个数

        res = len(df.loc[df['超额收益'] > 0]) / len(df)
        return res

    def get_week_return_year(self, df):
        """根据传入的周收益表计算年化收益"""
        # 周收益平均*系数,默认是52
        return_mena = df['超额收益'].mean()
        res = return_mena * self.year_x
        return res

    def get_week_return(self, code: str, start_date: str, end_date: str, types: str = 'fund', jz: str = 'biwi'):
        """周超额收益查询"""

        # 首先计算出时间序列
        time_df = self.t.get_week_trade_days(start_date, end_date)
        pre_day = self.t.get_pre_week_trade_day(start_date)
        time_list = list(time_df['日期'])
        # 对于第一周的计算 需要用到上一周的数据,所有向列表头部插入了一个日期
        time_list.insert(0, pre_day)

        if types == 'fund':
            df = self.get_week_return_fund(code, time_list, jz)

        else:
            df = self.get_week_return_fund_fof(code, time_list, jz)
        return df

    def get_week_return_fund(self, code: str, time_list: list, jz: str = 'biwi'):
        """
        fund 周收益查询
        :param code: 基金代码
        :param time_list: 时间序列
        :param js: 基准
        :return:
        """

        df01 = self.get_week_value_fund(code, time_list)

        if jz == 'biwi':
            try:
                df02 = self.get_week_close_biwi(code, time_list)
            except:
                df02 = self.get_week_close_ejfl(code,time_list)

        else:
            df02 = self.get_week_close_biwi(code, time_list)

        # 超额收益计算 基金收益率-指数收益率
        df = pd.merge(df01, df02, on='日期', how='left')
        df['超额收益'] = df['周收益率_x'] - df['周收益率_y']

        # 去重
        df.dropna(inplace=True)
        # time_index = df01.index.values
        # return_value = df01['周收益率'].values - df02['周收益率'].values
        # df = pd.DataFrame(columns=['时间', '超额收益'])
        # df['时间'] = time_index
        # df['超额收益'] = return_value
        df.set_index('日期', inplace=True)
        df = df[['超额收益']]

        return df

    def get_week_return_fund_fof(self, code: str, time_list: list, jz: str = 'zz800'):
        """
        fund 周收益查询 fof 版
        :param code: 基金代码
        :param time_list: 时间序列
        :param js: 基准
        :return:
        """

        df01 = self.get_week_value_fund_fof(code, time_list)

        if jz == 'zz800':
            # 中证800
            index_code = '000906'
            df02 = self.get_week_close_zz800(index_code, time_list)
        else:
            df02 = self.get_week_close_biwi(code, time_list)

        # 超额收益计算 基金收益率-指数收益率
        df = pd.merge(df01, df02, on='日期', how='left')

        df['超额收益'] = df['周收益率_x'] - df['周收益率_y']

        # 去空
        df.dropna(inplace=True)
        # time_index = df01.index.values
        # return_value = df01['周收益率'].values - df02['周收益率'].values
        # df = pd.DataFrame(columns=['时间', '超额收益'])
        # df['时间'] = time_index
        # df['超额收益'] = return_value
        df.set_index('日期', inplace=True)
        df = df[['超额收益']]

        return df

    def get_week_value_fund(self, code: str, time_list: list):
        """
        获取周净值,算周收益,fund
        :param code: 基金代码
        :param time_list: 每个交易周中的最后一个交易日,含有起始日期的上一个交易周的最后一个交易日
        :return: df index 日期,columns收益率
        """
        t1 = time_list[0]
        t2 = time_list[-1]

        sql_week_value_fund = f"""
        select f13_1101,f21_1101 from wind.tb_object_1101 left join wind.tb_object_1090  on f14_1101 = f2_1090
        where f16_1090 = '{code}' and (f13_1101 >= '{t1}' and f13_1101 <='{t2}')
        order by f13_1101
        """
        sql_res = self.cu.execute(sql_week_value_fund).fetchall()

        df = pd.DataFrame(sql_res, columns=['日期', '复权单位净值'])
        df.set_index('日期', inplace=True)
        # 筛选出需要的日期
        df = df.reindex(time_list)

        # df02 = df['复权单位净值'].pct_change()
        df['上周复权单位净值'] = df['复权单位净值'].shift()
        df['周收益率'] = (df['复权单位净值'] - df['上周复权单位净值']) / df['上周复权单位净值']
        # df = df[['周收益率']]
        # 去重,其索引,后期merge会用到日期字段
        df.dropna(inplace=True)
        df.reset_index(inplace=True)

        return df

    def get_week_value_fund_fof(self, code: str, time_list: list):
        """
        获取周净值,算周收益,fof
        :param code: 基金代码
        :param time_list: 每个交易周中的最后一个交易日,含有起始日期的上一个交易周的最后一个交易日
        :return: df index 日期,columns收益率
        """
        t1 = time_list[0]
        t2 = time_list[-1]

        # sql_week_value_fund = f"""
        # select f13_1101,f21_1101 from wind.tb_object_1101 left join wind.tb_object_1090  on f14_1101 = f2_1090
        # where f16_1090 = '{code}' and (f13_1101 >= '{t1}' and f13_1101 <='{t2}')
        # order by f13_1101
        # """

        sql_week_value_fund = f"""
         select tradedate,closeprice from t_fof_value_info where fundid = '{code}' 
         and tradedate >= '{t1}' and tradedate <= '{t2}'
         order by tradedate
        """
        print(sql_week_value_fund)
        sql_res = self.cu_pra.execute(sql_week_value_fund).fetchall()

        df = pd.DataFrame(sql_res, columns=['日期', '复权单位净值'])
        # print(df)
        df.set_index('日期', inplace=True)
        # 筛选出需要的日期
        df = df.reindex(time_list)

        # df02 = df['复权单位净值'].pct_change()
        df['上周复权单位净值'] = df['复权单位净值'].shift()
        df['周收益率'] = (df['复权单位净值'] - df['上周复权单位净值']) / df['上周复权单位净值']
        # df = df[['周收益率']]
        # 去重,其索引,后期merge会用到日期字段
        df.dropna(inplace=True)
        df.reset_index(inplace=True)
        # print(df)
        return df


    def get_week_close_biwi(self, code: str, time_list: list):
        """
        取基准,算周收益,biwi

        这里要做异常处理,基准不能有空!基准含有空直接报错!
        :param code: 基金代码
        :param time_list: 每个交易周中的最后一个交易日,含有起始日期的上一个交易周的最后一个交易日
        :return:
        """
        t1 = time_list[0]
        t2 = time_list[-1]

        sql_code = code + 'BI.WI'
        sql_week_close_bibw = f"""
        select  trade_dt,s_dq_close from wind.chinamutualfundbenchmarkeod 
        where s_info_windcode = '{sql_code}' and (trade_dt >= '{t1}' and trade_dt <='{t2}')
        order by trade_dt 
        """

        sql_res = self.cu.execute(sql_week_close_bibw).fetchall()
        assert sql_res, f'{code}基准查询结果为空,请改变基准'
        df = pd.DataFrame(sql_res, columns=['日期', '收盘价'])

        assert df.iloc[0][0] == t1, f'{code}基准查询结果含有空值,请改变基准'

        df.set_index('日期', inplace=True)
        # 筛选出需要的日期
        df = df.reindex(time_list)
        # 计算收益率  close2-close1/close1
        df['周收益率'] = df['收盘价'].pct_change()
        # 去空值
        df.dropna(inplace=True)
        # df = df[['周收益率']]
        # 去索引,后面merge 会用到日期字段
        df.reset_index(inplace=True)
        return df


    def get_week_close_zz800(self,index_code:str,time_list:list):
        """
        取基准,算周收益,biwi

        这里要做异常处理,基准不能有空!基准含有空直接报错!
        :param code: 基金代码
        :param time_list: 每个交易周中的最后一个交易日,含有起始日期的上一个交易周的最后一个交易日
        :return:
        """
        t1 = time_list[0]
        t2 = time_list[-1]
        sql_week_close_zz800 = f"""
        select f2_1425,f7_1425 from wind.tb_object_1425  left join wind.tb_object_1090  on f1_1425 = f2_1090
        where f16_1090 = '{index_code}'
        and (f2_1425 >='{t1}' and f2_1425 <= '{t2}')
        and f4_1090 = 'S'
        order by f2_1425
        """
        # print(sql_week_close_zz800)
        sql_res = self.cu.execute(sql_week_close_zz800).fetchall()
        assert sql_res, f'{code}基准查询结果为空,请改变基准'
        df = pd.DataFrame(sql_res, columns=['日期', '收盘价'])

        assert df.iloc[0][0] == t1, f'{code}基准查询结果含有空值,请改变基准'

        df.set_index('日期', inplace=True)
        # 筛选出需要的日期
        df = df.reindex(time_list)
        # 计算收益率  close2-close1/close1
        df['周收益率'] = df['收盘价'].pct_change()
        # 去空值

        df.dropna(inplace=True)
        # df = df[['周收益率']]
        # 去索引,后面merge 会用到日期字段
        df.reset_index(inplace=True)
        return df

    def get_week_close_ejfl(self,code:str,time_list:list):
        """
        判断二级分类并且取出相应基准的周收盘
        :param codeLStr: 基金代码
        :param time_list: 时间列表
        :return:
        """
        ejfl = self.get_ejfl(code,time_list)
        index = self.change_ejfl_to_index(ejfl,time_list)
        index['日期'] = time_list
        index.rename(columns = {'市场组合收益率':'周收益率'},inplace = True)
        return index


    def get_ejfl(self,code:str,time_list:list):
        """根据代码和输入周期,计算二级分类"""
        end_date = time_list[-1]
        sql_string = f'''
                select * from (
                    select ejfl from t_fund_classify_his
                    where rptdate <= {end_date}
                    and cpdm = {code}
                    order by rptdate
                )
                where rownum=1 
                '''
        sql_res = self.cu_pra.execute(sql_string).fetchall()
        if sql_res:
            res = sql_res[0][0]
        else:
            res = None
        return res

    def change_ejfl_to_index(self,fund_type:str,time_list:list):
        """
        输入二级分类和时间轴
        :param fund_type: 二级分类
        :param time_list: 时间轴
        :return: 
        """

        res = sl.get_market(fund_type,time_list)
        return res


    def unpack_fof(self, fof,start_date,end_date):

        """解包fof"""
        sql_unpakc_fof = f"""
        select memberfundid,weight from {self.fof_member_info} 
        where fundid = '{fof}'

        """
        sql_res = self.cu_pra.execute(sql_unpakc_fof).fetchall()
        df = pd.DataFrame(sql_res, columns=['X', 'P'])


        return df

    def get_fund_price(self, code, start_date, end_date):
        """计算波动和回测时用到的sql查询方法"""
        sql = '''
        select
        f13_1101 as 截止日期, f21_1101 as 复权单位净值 
        from
        wind.tb_object_1101
        left join wind.tb_object_1090
        on f2_1090 = f14_1101
        where 
        F16_1090= '%(code)s'
        and
        F13_1101 >= '%(start_date)s'
        and
        f13_1101 <= '%(end_date)s'
        ''' % {'end_date': end_date, 'code': code, 'start_date': start_date}
        fund_price = pd.DataFrame(self.cu.execute(sql).fetchall(), columns=['截止日期', '复权单位净值'])
        return fund_price

    # ************ 下面是对外的接口 *************************

    def performance_stability(self, code: str, start_date: str, end_date: str, types: str = 'fund', jz: str = 'biwi'):
        """
        计算顺率
        :param code:代码
        :param start_date:开始日期
        :param end_date: 结束日期
        :param types: 代码类型,默认 fund
        :param jz: 指数类型,默认 biwi
        :return:
        """
        if types == 'fund':
            df_return = self.get_week_return(code, start_date, end_date, types, jz)
            res = self._get_winning(df_return)
        elif types == 'fof':
            # 这里的js是自己重新定义的,理想状态是在外面的js定义好
            jz = 'zz800'
            df_return = self.get_week_return(code, start_date, end_date, types, jz)

            res = self._get_winning(df_return)
        else:
            res = 0.0

        return res

    def zhoubodong(self, code='163807', start_date='20190101', end_date='20190225'):
        fund_price = self.get_fund_price(code, start_date, end_date)
        fund_price2 = fund_price.sort_values(by=['截止日期']).reset_index(drop=True)

        fund_price2['fund_return'] = fund_price2.复权单位净值.diff() / fund_price2.复权单位净值.shift(1)
        fund_price2.dropna(axis=0, inplace=True)
        fund_price2.reset_index(drop=True, inplace=True)

        zhou_bodong = fund_price2.fund_return.std() * (math.sqrt(250))
        return zhou_bodong

    # 计算最大回测
    def max_down_fund(self, code='163807', start_date='20150528', end_date='20190225'):
        # 输出单只基金的最大回撤,返回一个float数值
        # 提取复权净值
        fund_price = self.get_fund_price(code, start_date, end_date)
        fund_price2 = fund_price.sort_values(by=['截止日期']).reset_index(drop=True)
        price_list = fund_price2['复权单位净值'].tolist()
        i = np.argmax((np.maximum.accumulate(price_list) - price_list) / np.maximum.accumulate(price_list))  # 结束位置
        if i == 0:
            max_down_value = 0
        else:
            j = np.argmax(price_list[:i])  # 开始位置
            max_down_value = (price_list[j] - price_list[i]) / (price_list[j])
        return -max_down_value

    def performance_stability_fof(self, fof: str, start_date: str, end_date: str):
        """
        业绩稳定性
        :param code: 基金代码
        :param start_date: 起始时间
        :param end_date: 结束时间
        :param types: 代码类型,默认 fund基金
        :param jz: 基准指标,默认 biwi
        :return:
        """
        # 先计算时间列表
        time_df = self.t.get_week_trade_days(start_date, end_date)
        pre_day = self.t.get_pre_week_trade_day(start_date)
        time_list = list(time_df['日期'])
        time_list.insert(0, pre_day)
        # 再解包产品集D,得到x1,x2,x3和 p1,p2,p3
        df_D = self.unpack_fof(fof,start_date,end_date)
        x_list = df_D['X'].values
        p_list = df_D['P'].values
        # print('x_list:',x_list)
        # print('p_list:',p_list)
        # 计算每个x的胜率
        win_list = []
        for x in x_list:
            df_week_return = self.get_week_return(x, start_date, end_date)
            winning = self._get_winning(df_week_return)
            win_list.append(winning)
        # 对上面的结果做加权平均
        print('win_lilst:',win_list)
        res = np.average(win_list, weights=p_list)
        return res

    def abs_return(self, fof: str, start_date: str, end_date: str):
        """获取绝对收益率"""
        print('待开发')
        return 0.0
        pass