Exemplo n.º 1
0
    def ondata(self):
        ap.sound(f'entry: ondata')

        for idx, r in self.df.iterrows():
            if idx % 500 == 0:
                print(f'{idx} / {len(self.df)}')
            idx -= 1

            self.ths_yield_l = [0]
            self.ths_yield_s = [0]

            self.ths_avlb = self.ac.avlb[-1]
            self.ths_pst_l = self.ac.pst_l[-1]
            self.ths_pst_s = self.ac.pst_s[-1]

            if idx > 0:
                td.flatlong(self, idx, r)
                td.flatshort(self, idx, r)
                td.holdlong(self, r)
                td.holdshort(self, r)
                td.openlong(self, idx, r)
                td.openshort(self, idx, r)

            ths_yield_ls_res = sum(self.ths_yield_l) + sum(self.ths_yield_s)
            ths_ttas_res = self.ths_avlb + (self.ths_pst_l +
                                            self.ths_pst_s) * r.close

            self.pc.close.append(r.close)
            self.yd.ttas.append(ths_ttas_res)
            self.yd.eac_ls_pf.append(ths_yield_ls_res)
            self.yd.eac_l_pf.append(sum(self.ths_yield_l))
            self.yd.eac_s_pf.append(sum(self.ths_yield_s))
            self.ac.avlb.append(self.ths_avlb)
            self.ac.pst_l.append(self.ths_pst_l)
            self.ac.pst_s.append(self.ths_pst_s)
Exemplo n.º 2
0
 def idx_signal(self):
     ap.sound(f'entry: idx_signal')
     # l_sma13 = talib.SMA(self.l_close, 13)
     # l_sma89 = talib.SMA(self.l_close, 89)
     # self.l_signal_longopen = (self.l_close > l_sma13) & (l_sma13 > l_sma89)
     # self.l_signal_longflat = (self.l_close < l_sma13)
     return self
    def evaluation(self):
        ap.sound(f'entry: create_df')

        mdd = empyrical.max_drawdown(self.df.eac_stgy_rt)
        stgy_ret_an = empyrical.annual_return(self.df.eac_stgy_rt, annualization=self.cls.annualization)
        bcmk_ret_an = empyrical.annual_return(self.df.eac_bcmk_rt, annualization=self.cls.annualization)
        stgy_vlt_an = empyrical.annual_volatility(self.df.eac_stgy_rt, annualization=self.cls.annualization)
        bcmk_vlt_an = empyrical.annual_volatility(self.df.eac_bcmk_rt, annualization=self.cls.annualization)
        calmar = empyrical.calmar_ratio(self.df.eac_stgy_rt, annualization=self.cls.annualization)
        omega = empyrical.omega_ratio(self.df.eac_stgy_rt, risk_free=self.cls.rf, annualization=self.cls.annualization)
        sharpe = qp.sharpe_ratio(stgy_ret_an, self.df.cum_stgy_rt, self.cls.rf)
        sortino = empyrical.sortino_ratio(self.df.eac_stgy_rt, annualization=self.cls.annualization)
        dsrk = empyrical.downside_risk(self.df.eac_stgy_rt, annualization=self.cls.annualization)
        information = empyrical.information_ratio(self.df.eac_stgy_rt, factor_returns=self.df.eac_bcmk_rt)
        beta = empyrical.beta(self.df.eac_stgy_rt, factor_returns=self.df.eac_bcmk_rt, risk_free=self.cls.rf)
        tail_rt = empyrical.tail_ratio(self.df.eac_stgy_rt)
        alpha = qp.alpha_ratio(stgy_ret_an, bcmk_ret_an, self.cls.rf, beta)

        stgy_ttrt_rt = (self.cls.yd.ttas[-1] - self.cls.yd.ttas[0]) / self.cls.yd.ttas[0]
        bcmk_ttrt_rt = (self.cls.pc.close[-1] - self.cls.pc.close[0]) / self.cls.pc.close[0]
        car_rt = stgy_ttrt_rt - bcmk_ttrt_rt
        car_rt_an = stgy_ret_an - bcmk_ret_an

        self.cls.df_output = pd.DataFrame(
            {'sgty_ttrt_rt': [stgy_ttrt_rt], 'bcmk_ttrt_rt': [bcmk_ttrt_rt], 'car_rt': [car_rt],
             'stgy_ret_an': [stgy_ret_an], 'bcmk_ret_an': [bcmk_ret_an], 'car_rt_an': [car_rt_an],
             'stgy_vlt_an': [stgy_vlt_an], 'bcmk_vlt_an': [bcmk_vlt_an], 'mdd': [mdd],
             'sharpe': [sharpe], 'alpha': [alpha], 'beta': [beta], 'information': [information],
             'tail_rt': [tail_rt], 'calmar': [calmar], 'omega': [omega], 'sortino': [sortino], 'dsrk': [dsrk]})
        print(f'feedback: \n{self.cls.df_output.T}')
Exemplo n.º 4
0
 def backtest(self):
     ap.sound(f'entry: backtest')
     self.l_signal = self.l_signal.shift(1).fillna(0).astype(int)
     self.l_each_strategy_pct = self.l_signal * self.l_each_benchmark_pct
     self.l_cum_strategy_pct = (
         1 + np.array(self.l_each_strategy_pct)).cumprod()
     return self
def process(tushare, dict_replace_columns, year_tradeday=25, path_r=None):
    ap.sound(f'entry: process')

    pro = ts.pro_api()
    df = pd.DataFrame()

    df_code = pro.query('stock_basic', exchange='', list_status='L', fields='ts_code')
    l_code = df_code['ts_code'].tolist()

    # for i in range(len(l_code)):
    for i in range(200):
        print(f'i: {i} / {len(l_code)}')

        tushare['code'] = l_code[i]
        hss = HSStrategy(year_tradeday=year_tradeday, path_r=path_r,
                         tushare=tushare, dict_replace_columns=dict_replace_columns)
        hss.run()
        hss.df_output['code'] = l_code[i]
        print(hss.df_output)
        if i == 0:
            df = hss.df_output.copy()
        else:
            df = ap.concat(df, hss.df_output)

    df.to_csv(r'../../../../data/res.csv')
Exemplo n.º 6
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
Exemplo n.º 7
0
 def asd_benchmark(self):
     ap.sound(f'entry: asd_data')
     self.l_close = self.df['close'].copy()
     self.l_each_close_pct = self.l_close.pct_change().tolist()
     self.l_each_benchmark_pct = self.l_each_close_pct
     self.l_each_benchmark_pct[0] = 0
     self.l_cum_benchmark_pct = (1 + np.array(self.l_each_benchmark_pct)).cumprod()
     return self
Exemplo n.º 8
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
Exemplo n.º 9
0
 def draw_back(self):
     ap.sound(f'entry: draw_back')
     plt.figure(figsize=(18, 8))
     plt.plot(self.l_close_norm, color='teal')
     plt.plot(self.l_yield, color='grey')
     plt.legend(['benchmark', 'strategy yield curve'], loc="best")
     plt.show()
     return self
Exemplo n.º 10
0
    def output(self):
        ap.sound(f'entry: output')
        self.df_output['基准总收益率'] = [np.round(self.benchmark_total_pct, 4)]
        self.df_output['基准年化收益率'] = [np.round(self.benchmark_ytd_pct, 4)]
        self.df_output['策略总收益率'] = [np.round(self.strategy_total_pct, 4)]
        self.df_output['策略年化收益率'] = [np.round(self.strategy_ytd_pct, 4)]
        self.df_output['年化超额收益率'] = [np.round(self.car_pct, 4)]
        self.df_output['胜率'] = [np.round(self.win_pct, 4)]
        self.df_output['盈亏比'] = [np.round(self.win_pct, 4)]
        self.df_output['夏普比率'] = [np.round(self.sharpe_pct, 4)]
        self.df_output['Alpha'] = [np.round(self.alpha, 4)]
        self.df_output['Bate'] = [np.round(self.bate, 4)]
        self.df_output['信息比率'] = [np.round(self.info_pct, 4)]
        self.df_output['策略波动率'] = [np.round(self.strategy_volatility, 4)]
        self.df_output['基准波动率'] = [np.round(self.benchmark_volatility, 4)]

        self.df_output['最高浮动收益率'] = [np.round(self.max_each_strategy_pct, 4)]
        self.df_output['最低浮动收益率'] = [np.round(self.min_each_strategy_pct, 4)]
        self.df_output['最大回撤率'] = [np.round(self.mdd_pct, 4)]
        self.df_output['最大回撤位置'] = [self.mdd_range]
        self.df_output['最大收益率'] = [self.mrg_pct]
        self.df_output['最大收益位置'] = [self.mrg_range]
        self.df_output['总交易次数'] = [len(self.l_stroke_pct)]
        self.df_output['平均收益率'] = [self.avg_stroke_pct]

        self.df_output['平均持仓时间'] = [self.avg_holdtime]
        self.df_output['盈利交易次数'] = [self.profit_num]
        self.df_output['盈利交易平均收益率'] = [self.profit_avg_pct]
        self.df_output['盈利交易平均持仓时间'] = [self.profit_avg_holdtime]
        self.df_output['亏损交易次数'] = [self.loss_num]
        self.df_output['亏损交易平均收益率'] = [self.loss_avg_pct]
        self.df_output['亏损交易平均持仓时间'] = [self.loss_avg_holdtime]
        self.df_output['总测试天数'] = [self.kline_num]
        self.df_output['持仓天数'] = [self.tradeday_num]
        self.df_output['持仓天数占比'] = [self.tradeday_pct]

        print(
            f'基准总收益率: {np.round(self.benchmark_total_pct, 4)}, 策略总收益率: {np.round(self.strategy_total_pct, 4)}\n'
            f'基准年化收益率: {np.round(self.benchmark_ytd_pct, 4)}, 策略年化收益率: {np.round(self.strategy_ytd_pct, 4)}\n'
            f'年化超额收益率: {np.round(self.car_pct, 4)}, 胜率: {np.round(self.win_pct, 4)}, '
            f'盈亏比: {np.round(self.win_pct, 4)}\n'
            f'夏普比率: {np.round(self.sharpe_pct, 4)}, Alpha: {np.round(self.alpha, 4)}, '
            f'Bate: {np.round(self.bate, 4)}, 信息比率: {np.round(self.info_pct, 4)}\n'
            f'策略波动率: {np.round(self.strategy_volatility, 4)}, 基准波动率: {np.round(self.benchmark_volatility, 4)}\n'
            f'最高浮动收益率: {np.round(self.max_each_strategy_pct, 4)}, '
            f'最低浮动收益率: {np.round(self.min_each_strategy_pct, 4)}\n'
            f'最大回撤率: {np.round(self.mdd_pct, 4)}, 最大回撤位置: {self.mdd_range}\n'
            f'最大收益率: {np.round(self.mrg_pct, 4)}, 最大收益位置: {self.mrg_range}\n'
            f'总交易次数: {len(self.l_stroke_pct)}, 平均收益率: {np.round(self.avg_stroke_pct, 4)}, '
            f'平均持仓时间: {np.round(self.avg_holdtime, 4)}\n'
            f'盈利交易次数: {self.profit_num}, 盈利交易平均收益率: {np.round(self.profit_avg_pct, 4)}, '
            f'盈利交易平均持仓时间: {np.round(self.profit_avg_holdtime, 4)}\n'
            f'亏损交易次数: {self.loss_num}, 亏损交易平均收益率: {np.round(self.loss_avg_pct, 4)}, '
            f'亏损交易平均持仓时间: {np.round(self.loss_avg_holdtime, 4)}\n'
            f'总测试天数: {self.kline_num}, 持仓天数: {self.tradeday_num}, 持仓天数占比: {np.round(self.tradeday_pct, 2)}'
        )

        return self
Exemplo n.º 11
0
 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
Exemplo n.º 12
0
    def create_df(self):
        ap.sound(f'entry: create_df')

        self.df['datetime'] = self.cls.df.datetime
        self.df['eac_stgy_rt'] = self.cls.yd.eac_stgy_rt
        self.df['cum_stgy_rt'] = self.cls.yd.cum_stgy_rt
        self.df['eac_bcmk_rt'] = self.cls.yd.eac_bcmk_rt
        self.df['cum_bcmk_rt'] = self.cls.yd.cum_bcmk_rt
        self.df.set_index('datetime', inplace=True)
Exemplo n.º 13
0
 def run(self):
     self.asd_data()
     self.idx_signal()
     self.backtest()
     self.feedback()
     # dr.draw_price(self.l_close, self.l_each_benchmark_pct)
     # dr.draw_signal(self.l_close, self.l_signal)
     # dr.draw_srtoke_distribution(self.fb.l_stroke_holdtime, self.fb.l_stroke_pct)
     dr.draw_back(np.array(self.l_close), self.l_cum_strategy_pct)
     ap.sound(f'finished')
     return self
Exemplo n.º 14
0
def stgy_rt(cls):
    ap.sound(f'entry: stgy_rt')

    df = pd.DataFrame()
    df['ttas'] = cls.yd.ttas
    df['shift'] = cls.yd.ttas
    df['shift'] = df['shift'].shift(1).fillna(0)
    df['eac_stgy_rt'] = df.apply(lambda x: (x['ttas'] - x['shift']) / x['shift'] if x['shift'] != 0 else 0, axis=1)

    cls.yd.eac_stgy_rt = df.eac_stgy_rt.values
    cls.yd.cum_stgy_rt = (1 + cls.yd.eac_stgy_rt).cumprod()
Exemplo n.º 15
0
 def run(self):
     self.get_data()
     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
Exemplo n.º 16
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
Exemplo n.º 17
0
def bcmk_rt(cls):
    ap.sound(f'entry: bcmk_rt')

    df = pd.DataFrame()
    df['bcmk'] = cls.df.close
    df['shift'] = cls.df.close
    df['shift'] = df['shift'].shift(1).fillna(0)
    df['eac_bcmk_rt'] = df.apply(lambda x: (x['bcmk'] - x['shift']) / x['shift'] if x['shift'] != 0 else 0, axis=1)

    cls.yd.eac_bcmk_rt = df.eac_bcmk_rt.values
    cls.yd.cum_bcmk_rt = (1 + cls.yd.eac_bcmk_rt).cumprod()
Exemplo n.º 18
0
    def stat_yield(self):
        """
        统计收益率相关指标:
            l_stroke_pct: 每一笔交易的收益率
            avg_stroke_pct: 总体平均收益率
            profit_num: 盈利交易次数
            profit_avg_pct: 盈利交易平均收益率
            loss_num: 亏损交易次数
            loss_avg_pct: 亏损交易平均收益率
            win_pct: 胜率
            winloss_pct: 盈亏比
            strategy_total_pct: 策略总收益率
            strategy_ytd_pct: 策略年化收益率
            benchmark_total_pct: 基准总收益率
            benchmark_ytd_pct: 基准年化收益率
            car_pct: 超额收益率
            max_each_strategy_pct: 策略单笔交易最大收益率
            min_each_strategy_pct: 策略单笔交易最小收益率
        :return:
        """
        ap.sound(f'entry: stat_strategy')
        self.l_stroke_pct = [
            sum(self.l_each_benchmark_pct[x:y]) for (x, y) in self.l_holdidx
        ]
        self.avg_stroke_pct = float(np.mean(self.l_stroke_pct))

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

        self.strategy_total_pct = (self.l_cum_strategy_pct[-1] -
                                   self.l_cum_strategy_pct[0]) / np.mean(
                                       self.l_cum_strategy_pct[0:5])
        self.strategy_ytd_pct = qp.annualized(self.strategy_total_pct,
                                              self.year_tradeday,
                                              self.kline_num)
        self.benchmark_total_pct = (
            self.l_close[-1] - self.l_close[0]) / np.mean(self.l_close[0:5])
        self.benchmark_ytd_pct = qp.annualized(self.benchmark_total_pct,
                                               self.year_tradeday,
                                               self.kline_num)

        self.car_pct = self.strategy_ytd_pct - self.benchmark_ytd_pct
        self.max_each_strategy_pct = max(self.l_cum_strategy_pct)
        self.min_each_strategy_pct = min(self.l_cum_strategy_pct)
        return self
 def get_data(self):
     ap.sound(f'entry: get_data')
     if self.path_r:
         self.df = pd.read_csv(self.path_r, encoding='gb18030')
     elif self.tushare:
         pro = ts.pro_api(TushareToken)
         self.df = pro.daily(ts_code=self.tushare['code'],
                             start_date=self.tushare['start_datetime'],
                             end_date=self.tushare['end_datetime'])
     else:
         print(f'ERROR: Input read path is empty')
     print(f'columns_name: {self.df.columns.tolist()}')
     return self
Exemplo n.º 20
0
    def data_process(self):
        ap.sound(f'entry: get_data')

        if self.dict_replace_columns:
            self.df.rename(columns=self.dict_replace_columns, inplace=True)

        self.df = self.df[['datetime', 'open', 'high', 'low', 'close']].copy()
        self.df['datetime'] = pd.to_datetime(self.df['datetime'])
        self.df.sort_values(by='datetime', inplace=True)
        # self.df = self.df.set_index('datetime')
        # self.df.to_csv(r'../../../../data/20200708.csv')
        print(f'df: \n{self.df.head()}')
        return self
Exemplo n.º 21
0
def draw_back(l_cum_benchmark_pct, l_cum_strategy_pct):
    """
    画出策略收益曲线和基准收益曲线
    :param l_cum_benchmark_pct: array, 累计基准收益率
    :param l_cum_strategy_pct: array, 累计策略收益率
    :return:
    """
    ap.sound(f'entry: draw_back')
    plt.figure(figsize=(18, 8))
    plt.plot(l_cum_benchmark_pct, color='teal')
    plt.plot(l_cum_strategy_pct, color='grey')
    plt.legend(['benchmark', 'strategy yield curve'], loc="best")
    plt.show()
Exemplo n.º 22
0
def draw_signal(l_close, l_signal):
    """
    画出基准价格和信号
    :param l_close: DataFrame.Series, 收盘价列表
    :param l_signal: DataFrame.Series, 信号列表
    :return:
    """
    ap.sound(f'entry: draw_signal')
    plt.figure(figsize=(18, 8))
    ax_close = plt.subplot(2, 1, 1)
    ax_close.plot(l_close, color='teal')
    ax_signal = plt.subplot(2, 1, 2)
    ax_signal.bar(x=l_signal.index, height=l_signal.values, color='grey')
    plt.show()
Exemplo n.º 23
0
def draw_price(l_close, l_each_benchmark_pct):
    """
    画出基准曲线图
    :param l_close: DataFrame.Series, 收盘价列表
    :param l_each_benchmark_pct: list, 基准每个Kline的change_pct
    :return:
    """
    ap.sound(f'entry: draw_price')
    plt.figure(figsize=(18, 8))
    ax_close = plt.subplot(2, 1, 1)
    ax_close.plot(l_close, color='teal')
    ax_pct = plt.subplot(2, 1, 2)
    ax_pct.plot(l_each_benchmark_pct, color='grey')
    plt.show()
Exemplo n.º 24
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
Exemplo n.º 25
0
    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))
        self.mdd_pct = mdd['ratio']
        self.mdd_range = mdd['range']

        mrg = qp.maxrevenuegrowth(np.array(self.l_cum_strategy_pct))
        self.mrg_pct = mrg['ratio']
        self.mrg_range = mrg['range']
        return self
Exemplo n.º 26
0
def draw_srtoke_distribution(l_stroke_holdtime, l_stroke_pct):
    """
    画出每一笔交易的收益和持仓时间分布图
    :param l_stroke_holdtime: array, 每笔交易的持有时间列表
    :param l_stroke_pct: array, 每笔交易的收益
    :return:
    """
    ap.sound(f'entry: draw_srtoke_distribution')
    df = pd.DataFrame()
    df['holdtime'] = l_stroke_holdtime
    df['strategy'] = l_stroke_pct
    with sns.axes_style("dark"):
        sns.jointplot('holdtime',
                      'strategy',
                      data=df,
                      kind='kde',
                      color='grey',
                      space=0,
                      pct=6)
    plt.show()
Exemplo n.º 27
0
    def stat_holdtime(self):
        """
        统计持仓时间相关指标:
            l_stroke_holdtime: 每一笔交易持仓时间
            avg_holdtime: 总平均持仓时间
            profit_avg_holdtime: 盈利交易平均持仓时间
            loss_avg_holdtime: 亏损交易平均持仓时间
        :return:
        """
        ap.sound(f'entry: stat_holdtime')

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

        arr_stroke_pct = np.array(self.l_stroke_pct)
        arr_stroke_holdtime = np.array(self.l_stroke_holdtime)
        arr_profit = arr_stroke_holdtime[arr_stroke_pct > 0]
        arr_loss = arr_stroke_holdtime[arr_stroke_pct <= 0]
        self.profit_avg_holdtime = np.mean(arr_profit)
        self.loss_avg_holdtime = np.mean(arr_loss)
        return self
Exemplo n.º 28
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: \n{df_aux.head()}')
        print(f'tradenum: {len(df_aux) / 2}')
        return self