Ejemplo n.º 1
0
 def backtest(self):
     ap.sound(f'entry: backtest')
     self.l_signal = self.l_signal.shift(1).fillna(0).astype(int)
     l_signal_pct = self.l_signal * self.l_each_close_pct
     self.l_yield = (1 + l_signal_pct).cumprod()
     self.l_close_norm = (1 + np.array(self.l_each_close_pct[1:])).cumprod()
     return self
Ejemplo n.º 2
0
    def get_holdidx(self):
        """
        获取持仓索引列表l_holdidx
            l_aux eg: [1, 3, 4, 6, 7, 8], 两两一组,表示开仓和平仓的索引,第一笔交易开仓1,平仓3,第二笔交易开仓4,平仓6...
            l_holdidx: [[4, 6], [8, 20], [45, 47]], 每一个元素表示一次交易,内层列表表示每一次交易开始和结束的索引
        process:
            l_signal是信号布尔列表->aux,1表示满足开仓条件,持有仓位,0表示不满足开仓条件,没有仓位
            l_signal平移一位相减,得到的列表只包括1/0/-1三种情况,1为开仓,-1为平仓,
            存在一种特殊情况,最后一次开仓后,在测试数据范围内没有满足平仓条件,需要判断后补上一个-1表示平仓
            信号布尔列表aux只保留1和-1值后,得到的就是开平仓的列表,取其索引得到l_aux
            通过l_aux获取到l_holdidx
        :return:
        """
        ap.sound(f'entry: get_holdidx')

        df_temp = pd.DataFrame()
        df_temp['sig'] = self.l_signal
        df_temp['sig_shift'] = self.l_signal
        df_temp['sig_shift'] = df_temp['sig_shift'].shift(1).fillna(0).astype(int)
        df_temp['aux'] = df_temp['sig'] - df_temp['sig_shift']
        df_temp = df_temp.reset_index()
        df_aux = df_temp[['aux']][df_temp['aux'] != 0].reset_index().copy()

        if df_aux.loc[len(df_aux) - 1, 'aux'] == 1:
            df_aux = ap.concat(df_aux,
                               pd.DataFrame({'index': [df_aux['index'].tolist()[-1] + 1], 'aux': [-1]}))
        l_aux = df_aux['index'].tolist()
        step = 2
        self.l_holdidx = [l_aux[i:i + step] for i in range(0, len(l_aux), step)]

        print(f'df_aux: {df_aux.head()}')
        return self
    def stat_otherindex(self):
        """
        计算其他指标:
            sharpe_pct: 夏普比率
            info_pct: 信息比率
            benchmark_volatility: 基准波动率
            strategy_volatility: 策略波动率
            bate: 贝塔值
            alpha: 阿尔法值
        :return:
        """
        ap.sound(f'entry: stat_shape')

        self.sharpe_pct = qp.sharpe_ratio(self.strategy_ytd_pct,
                                          self.l_cum_strategy_pct, self.rf)
        self.info_pct = qp.information_ratio(self.l_each_strategy_pct,
                                             self.l_each_close_pct,
                                             self.strategy_ytd_pct,
                                             self.benchmark_ytd_pct,
                                             self.year_tradeday)
        self.benchmark_volatility = qp.volatility(self.l_each_close_pct,
                                                  self.year_tradeday,
                                                  self.kline_num)
        self.strategy_volatility = qp.volatility(self.l_each_strategy_pct,
                                                 self.year_tradeday,
                                                 self.kline_num)
        self.bate = qp.bate(self.l_each_strategy_pct, self.l_each_close_pct)
        self.alpha = qp.alpha(self.strategy_ytd_pct, self.benchmark_ytd_pct,
                              self.rf, self.bate)

        return self
 def draw_back(self):
     ap.sound(f'entry: draw_back')
     plt.figure(figsize=(18, 8))
     plt.plot(self.l_cum_benchmark_pct, color='teal')
     plt.plot(self.l_cum_strategy_pct, color='grey')
     plt.legend(['benchmark', 'strategy yield curve'], loc="best")
     plt.show()
     return self
Ejemplo n.º 5
0
 def idx_signal(self):
     ap.sound(f'entry: idx_signal')
     dif, dea, hist = talib.MACD(self.df['close'])
     # ema12 = talib.EMA(self.df['close'], 12)
     l_ema26 = talib.EMA(self.df['close'], 26)
     m5 = talib.SMA(self.df['close'], 5)
     self.l_signal = (hist < 0) & (dea < 0)
     return self
 def draw_price(self):
     ap.sound(f'entry: draw_price')
     plt.figure(figsize=(18, 8))
     ax_close = plt.subplot(2, 1, 1)
     ax_close.plot(self.df['close'], color='teal')
     ax_pct = plt.subplot(2, 1, 2)
     ax_pct.plot(self.l_each_close_pct, color='grey')
     plt.show()
     return self
Ejemplo n.º 7
0
 def draw_signal(self):
     ap.sound(f'entry: draw_signal')
     plt.figure(figsize=(18, 12))
     ax_close = plt.subplot(2, 1, 1)
     ax_close.plot(self.df['close'], color='teal')
     ax_signal = plt.subplot(2, 1, 2)
     ax_signal.bar(x=self.l_signal.index, height=self.l_signal.values, color='grey')
     plt.show()
     return self
Ejemplo n.º 8
0
 def draw(self):
     ap.sound(f'entry: draw')
     df = pd.DataFrame()
     df['holdtime'] = self.l_each_holdtime
     df['strategy'] = self.l_each_strategy_pct
     with sns.axes_style("dark"):
         sns.jointplot('holdtime', 'strategy', data=df,
                       kind='kde', color='grey', space=0, pct=6)
     plt.show()
     return self
 def run(self):
     self.asd_data()
     self.idx_signal()
     self.backtest()
     self.feedback()
     self.draw_price()
     self.draw_signal()
     self.draw_back()
     ap.sound(f'finished')
     return self
 def stat_tradeday(self):
     """
     统计交易日相关指标:
         tradeday_num: 交易日总数
         tradeday_pct: 交易日占比
     :return:
     """
     ap.sound(f'entry: stat_tradeday')
     self.tradeday_num = len([i for i in self.l_signal if i == 1])
     self.tradeday_pct = self.tradeday_num / self.kline_num
     return self
    def stat_yield(self):
        """
        统计收益率相关指标:
            l_each_strategy_pct: 每一笔交易的收益率
            avg_strategy_pct: 总体平均收益率
            profit_num: 盈利交易次数
            profit_avg_pct: 盈利交易平均收益率
            loss_num: 亏损交易次数
            loss_avg_pct: 亏损交易平均收益率
            win_pct: 胜率
            winloss_pct: 盈亏比
            strategy_pct: 策略总收益率
            strategy_ytd_pct: 策略年化收益率
            benchmark_pct: 基准总收益率
            benchmark_ytd_pct: 基准年化收益率
            car_pct: 超额收益率
            max_each_strategy_pct: 策略单笔交易最大收益率
            min_each_strategy_pct: 策略单笔交易最小收益率
        :return:
        """
        ap.sound(f'entry: stat_strategy')
        self.l_each_strategy_pct = [
            sum(self.l_each_close_pct[x:y]) for (x, y) in self.l_holdidx
        ]
        self.avg_strategy_pct = float(np.mean(self.l_each_strategy_pct))

        self.profit_num = len([i for i in self.l_each_strategy_pct if i > 0])
        self.profit_avg_pct = float(
            np.mean([i for i in self.l_each_strategy_pct if i > 0]))
        self.loss_num = len([i for i in self.l_each_strategy_pct if i <= 0])
        self.loss_avg_pct = float(
            np.mean([i for i in self.l_each_strategy_pct if i <= 0]))
        self.win_pct = self.profit_num / (self.profit_num + self.loss_num)
        self.winloss_pct = sum([
            i for i in self.l_each_strategy_pct if i > 0
        ]) / sum([i for i in self.l_each_strategy_pct if i <= 0])

        self.strategy_pct = (self.l_cum_strategy_pct[-1] - 1)
        self.strategy_ytd_pct = qp.total_annualized_returns(
            self.strategy_pct, self.year_tradeday, self.kline_num)

        self.benchmark_pct = (self.df['close'][-1] -
                              self.df['close'][0]) / self.df['close'][0]
        self.benchmark_ytd_pct = self.benchmark_pct / self.kline_num * self.year_tradeday

        self.car_pct = self.strategy_ytd_pct - self.benchmark_ytd_pct

        self.max_each_strategy_pct = max(self.l_cum_strategy_pct[1:])
        self.min_each_strategy_pct = min(self.l_cum_strategy_pct[1:])

        return self
Ejemplo n.º 12
0
    def get_data(self):
        ap.sound(f'entry: get_data')
        self.df = pd.read_excel(self.path_r, encoding='gb18030')
        self.df = self.df.set_index('datetime')
        print(f'df: \n{self.df.head()}')

        token = '31e528be4a85855ac2408fb477b2e9bd0f083e53461f1119d6e9619f'
        pro = ts.pro_api(token)

        # df = pro.daily(ts_code='000001.SZ', start_date='20190101', end_date='20190630')
        # print(df.head())
        # self.df = df[['trade_date', 'pre_close']].copy()
        # self.df.rename(columns={'trade_date': 'datetime', 'pre_close': 'close'}, inplace=True)
        # self.df.sort_values(by='datetime', inplace=True)
        # self.df = self.df.set_index('datetime')
        return self
    def stat_maxtrade(self):
        """
        统计最大回撤交易和最大增长交易
            mdd_pct: 最大回撤比率
            mdd_range: 最大回撤所在序列范围
            mrg_pct: 最大增长比率
            mrg_range: 最大增长所在序列范围
        :return:
        """
        ap.sound(f'entry: stat_maxtrade')
        mdd = qp.maxdrawdown(np.array(self.l_cum_strategy_pct[1:]))
        self.mdd_pct = mdd['pct']
        self.mdd_range = mdd['range']

        mrg = qp.maxrevenuegrowth(np.array(self.l_cum_strategy_pct[1:]))
        self.mrg_pct = mrg['pct']
        self.mrg_range = mrg['range']
        return self
Ejemplo n.º 14
0
    def output(self):
        ap.sound(f'entry: output')
        print(f'基准总收益率: {round(self.benchmark_pct, 4)}, 策略总收益率: {round(self.strategy_pct, 4)}\n'
              f'基准年化收益率: {round(self.benchmark_ytd_pct, 4)}, 策略年化收益率: {round(self.strategy_ytd_pct, 4)}\n'
              f'超额收益率: {round(self.car_pct, 4)}, 胜率: {round(self.win_pct, 4)}, 盈亏比: {round(self.winloss_pct, 4)}\n'
              f'夏普比率: {round(self.sharpe_pct, 4)}, Alpha: ..., Bate: ...\n'
              f'信息比率: ..., 策略波动率: {round(self.strategy_volatility, 4)}, '
              f'基准波动率: {round(self.benchmark_volatility, 4)}'
              f'最高浮动收益率: {round(self.max_each_strategy_pct, 4)}, '
              f'最低浮动收益率: {round(self.min_each_strategy_pct, 4)}\n'
              f'最大回撤率: {round(self.mdd_pct, 4)}, 最大回撤位置: {self.mdd_range}\n'
              f'最大收益率: {round(self.mrg_pct, 4)}, 最大收益位置: {self.mrg_range}\n'
              f'总交易次数: {len(self.l_each_strategy_pct)}, 平均收益率: {round(self.avg_strategy_pct, 4)}, '
              f'平均持仓时间: {self.avg_holdtime}\n'
              f'盈利交易次数: {self.profit_num}, 盈利交易平均收益率: {round(self.profit_avg_pct, 4)}, '
              f'盈利交易平均持仓时间: {self.profit_avg_holdtime}\n'
              f'亏损交易次数: {self.loss_num}, 亏损交易平均收益率: {round(self.loss_avg_pct, 4)}, '
              f'亏损交易平均持仓时间: {self.loss_avg_holdtime}\n'
              f'总测试天数: {self.kline_num}, 持仓天数: {self.tradeday_num}, 持仓天数占比: {round(self.tradeday_pct, 2)}')

        return self
    def stat_holdtime(self):
        """
        统计持仓时间相关指标:
            l_each_holdtime: 每一笔交易持仓时间
            avg_holdtime: 总平均持仓时间
            profit_avg_holdtime: 盈利交易平均持仓时间
            loss_avg_holdtime: 亏损交易平均持仓时间
        :return:
        """
        ap.sound(f'entry: stat_holdtime')

        self.l_each_holdtime = [y - x for (x, y) in self.l_holdidx]
        self.avg_holdtime = np.mean(self.l_each_holdtime)

        arr_each_strategy = np.array(self.l_each_strategy_pct)
        arr_each_holdtime = np.array(self.l_each_holdtime)
        arr_profit = arr_each_holdtime[arr_each_strategy > 0]
        arr_loss = arr_each_holdtime[arr_each_strategy <= 0]
        self.profit_avg_holdtime = np.mean(arr_profit)
        self.loss_avg_holdtime = np.mean(arr_loss)
        return self
 def asd_data(self):
     ap.sound(f'entry: asd_data')
     self.l_each_close_pct = self.df['close'].pct_change().tolist()
     self.l_cum_benchmark_pct = (
         1 + np.array(self.l_each_close_pct[1:])).cumprod()
     return self
Ejemplo n.º 17
0
 def asd_data(self):
     ap.sound(f'entry: asd_data')
     self.l_each_close_pct = self.df['close'].pct_change().tolist()
     return self
Ejemplo n.º 18
0
    def feedback(self):
        ap.sound(f'entry: feedback')

        df_feedback = pd.DataFrame()
        df_feedback['arr'] = self.l_signal
        df_feedback['arr_shift'] = self.l_signal
        df_feedback['arr_shift'] = df_feedback['arr_shift'].shift(1).fillna(0).astype(int)
        df_feedback['aux'] = df_feedback['arr'] - df_feedback['arr_shift']
        df_feedback = df_feedback.reset_index()
        df_target = df_feedback[['aux']][df_feedback['aux'] != 0].reset_index().copy()

        print(f'df_target: {df_target.head()}')
        if df_target.loc[len(df_target) - 1, 'aux'] == 1:
            df_target = ap.concat(df_target,
                                  pd.DataFrame({'index': [df_target['index'].tolist()[-1] + 1], 'aux': [-1]}))
        l_aux = df_target['index'].tolist()

        step = 2
        l_holdidx = [l_aux[i:i + step] for i in range(0, len(l_aux), step)]

        l_each_yield = [sum(self.l_each_close_pct[x:y]) for (x, y) in l_holdidx]
        avg_yield = float(np.mean(l_each_yield))

        profit_num = len([i for i in l_each_yield if i > 0])
        profit_avg_ratio = float(np.mean([i for i in l_each_yield if i > 0]))
        loss_num = len([i for i in l_each_yield if i < 0])
        loss_avg_ratio = float(np.mean([i for i in l_each_yield if i < 0]))

        l_each_holdtime = [y - x for (x, y) in l_holdidx]
        avg_holdtime = np.mean(l_each_holdtime)

        arr_each_yield = np.array(l_each_yield)
        arr_each_holdtime = np.array(l_each_holdtime)
        arr_profit = arr_each_holdtime[arr_each_yield > 0]
        arr_loss = arr_each_holdtime[arr_each_yield < 0]
        profit_avg_holdtime = np.mean(arr_profit)
        loss_avg_holdtime = np.mean(arr_loss)

        mdd = qp.maxdrawdown(np.array(self.l_yield[1:]))
        mdd_ratio = mdd['ratio'] * 100
        mdd_range = mdd['range']

        mrg = qp.maxrevenuegrowth(np.array(self.l_yield[1:]))
        mrg_ratio = mrg['ratio'] * 100
        mrg_range = mrg['range']

        yields = (self.l_yield[-1] - 1) * 100
        benchmark = (self.df['close'][-1] - self.df['close'][0]) / self.df['close'][0] * 100
        max_yield = max(self.l_yield[1:]) * 100
        min_yield = min(self.l_yield[1:]) * 100

        # todo: 改成 (年化收益率 - 利率) / 标准差
        sharpe_ratio = yields / 100 / np.std(self.l_yield, ddof=1)

        tradeday_num = len([i for i in self.l_signal if i == 1])
        tradeday_ratio = tradeday_num / len(self.l_signal) * 100

        print(f'基准收益率: {round(benchmark, 2)}%, 策略收益率: {round(yields, 2)}%, 夏普比率: {sharpe_ratio}\n'
              f'最高浮动收益率: {round(max_yield, 2)}%, 最低浮动收益率: {round(min_yield, 2)}%\n'
              f'最大回撤率: {round(mdd_ratio, 2)}%, 最大回撤位置: {mdd_range}\n'
              f'最大收益率: {round(mrg_ratio, 2)}%, 最大收益位置: {mrg_range}\n'
              f'总交易次数: {len(l_each_yield)}, 平均收益率: {round(avg_yield, 5)}%, 平均持仓时间: {avg_holdtime}\n'
              f'盈利交易次数: {profit_num}, 盈利交易平均收益率: {round(profit_avg_ratio, 5)}%, 盈利交易平均持仓时间: {profit_avg_holdtime}\n'
              f'亏损交易次数: {loss_num}, 亏损交易平均收益率: {round(loss_avg_ratio, 5)}%, 亏损交易平均持仓时间: {loss_avg_holdtime}\n'
              f'总测试天数: {len(self.l_signal)}, 持仓天数: {tradeday_num}, 持仓天数占比: {round(tradeday_ratio, 2)}%')

        dfs = pd.DataFrame()
        dfs['holdtime'] = l_each_holdtime
        dfs['yield'] = l_each_yield
        with sns.axes_style("dark"):
            # sns.jointplot('holdtime', 'yield', data=dfs,
            #               kind='reg', color='grey', space=0, ratio=6,
            #               marginal_kws={'bins': 20}, scatter={'s': 3})
            sns.jointplot('holdtime', 'yield', data=dfs,
                          kind='kde', color='grey', space=0, ratio=6)
        plt.show()
        return self
 def backtest(self):
     ap.sound(f'entry: backtest')
     self.l_signal = self.l_signal.shift(1).fillna(0).astype(int)
     l_signal_pct = self.l_signal * self.l_each_close_pct
     self.l_cum_strategy_pct = (1 + l_signal_pct).cumprod()
     return self