Esempio n. 1
0
def test_TurtleStrategy_4():
    symbol = '123456'
    holds = {
        symbol: [
            TurtleStrategy.Hold(
                symbol,
                datetime.date(1999, 1, 1),
                10,  # 买入价
                100,  # 持仓数量
                9,  # 止损价
                11,  # 止盈价
                10.5  # 下一个仓位价格
            )
        ]
    }
    ts = TurtleStrategy('', holds=holds)

    assert 1 == len(ts.holds[symbol])
    # 虽然有持仓,但是没有任何的卖出点标记,也没有到止盈/止损/加仓点位
    assert not ts.on_check_sell(datetime.date(2000, 1, 1), symbol, 10.2, 1000,
                                0, 10)
    # 没有到达止盈点位
    assert 0 == ts.on_calc_sell_amount(datetime.date(2000, 1, 1), symbol,
                                       10.99, 1000, 0, 10)
    # 到达止盈点位
    assert 100 == ts.on_calc_sell_amount(datetime.date(2000, 1, 1), symbol, 11,
                                         1000, 0, 10)
    assert 0 == len(ts.holds[symbol])
Esempio n. 2
0
def test_TurtleStrategy_1():
    symbol = '123456'
    holds = {
        symbol: [
            TurtleStrategy.Hold(
                symbol,
                datetime.date(1999, 1, 1),
                10,  #买入价
                100,  #持仓数量
                9,  #止损价
                11,  #止盈价
                10.5  #下一个仓位价格
            )
        ]
    }
    ts = TurtleStrategy('', holds=holds)
    # 当前时间不包含在卖出点字典中-开始
    assert 1 == len(ts.holds[symbol])
    assert 0 == ts.on_calc_sell_amount(datetime.date(2000, 1, 1), symbol, 10.2,
                                       1000, 0, 10)
    assert not ts.on_check_sell(datetime.date(2000, 1, 1), symbol, 10.2, 1000,
                                0, 10)
    assert 1 == len(ts.holds[symbol])
Esempio n. 3
0
def test_TurtleStrategy_7():
    """买卖在同一天时,不更新止盈/下一个买点价格"""
    symbol = '123456'
    holds = {
        symbol: [
            TurtleStrategy.Hold(
                symbol,
                datetime.date(1999, 1, 1),
                10,  # 买入价
                100,  # 持仓数量
                9,  # 止损价
                11,  # 止盈价
                10.5  # 下一个仓位价格
            ),
            TurtleStrategy.Hold(
                symbol,
                datetime.date(1999, 2, 1),
                20,  # 买入价
                200,  # 持仓数量
                18,  # 止损价
                25,  # 止盈价
                30  # 下一个仓位价格
            )
        ]
    }
    ts = TurtleStrategy(colname='atr5',
                        update_price_onsameday=False,
                        holds=holds,
                        buy_dict={symbol: [datetime.date(2000, 1, 1)]})

    assert ts.holds[symbol][-1].stopprofit_price == 25
    assert ts.holds[symbol][-1].next_price == 30

    row = pd.Series({'atr5': 0.05})
    ts.on_buy_sell_on_same_day(datetime.date(2000, 1, 1),
                               symbol,
                               50,
                               row=row,
                               verbose=2)

    new_stoploss, new_stopprofit, new_next = ts.calc_price(50, row=row)

    assert ts.holds[symbol][-1].stopprofit_price == 25
    assert ts.holds[symbol][-1].next_price == 30

    assert not ts.holds[symbol][-1].stopprofit_price == new_stopprofit
    assert not ts.holds[symbol][-1].next_price == new_next
Esempio n. 4
0
def test_TurtleStrategy_5():
    symbol = '123456'
    holds = {
        symbol: [
            TurtleStrategy.Hold(
                symbol,
                datetime.date(1999, 1, 1),
                10,  # 买入价
                100,  # 持仓数量
                9,  # 止损价
                11,  # 止盈价
                10.5  # 下一个仓位价格
            )
        ]
    }

    ts = TurtleStrategy('',
                        holds=holds,
                        buy_dict={symbol: [datetime.date(2000, 1, 1)]},
                        sell_dict={symbol: [datetime.date(2000, 1, 2)]})

    assert 100 == ts.on_calc_buy_amount(datetime.date(2000, 1, 1), symbol, 20,
                                        10000)
    assert 2 == len(ts.holds[symbol])
    assert 100 == ts.holds[symbol][0].amount
    assert 10 == ts.holds[symbol][0].price
    assert 100 == ts.holds[symbol][-1].amount
    assert 20 == ts.holds[symbol][-1].price

    assert ts.on_check_sell(datetime.date(2000, 1, 2), symbol, 15, 9999, 300,
                            -1)
    assert ts.on_check_sell(datetime.date(2000, 1, 2), symbol, 15, 9999, -1,
                            -1)

    assert 200 == ts.on_calc_sell_amount(datetime.date(2000, 1, 2), symbol, 15,
                                         9999, -1, -1)
    assert 0 == len(ts.holds[symbol])
Esempio n. 5
0
def test_TurtleStrategy():
    ts = TurtleStrategy(colname='atr5')
    assert ts.stoploss_point == 2
    assert ts.stopprofit_point == 10
    assert ts.next_point == 1
    row = pd.Series({'atr5': 0.05})
    ls, lf, n = ts.calc_price(1, row=row)
    assert ls == (1 - ts.stoploss_point * 0.05)
    assert lf == (1 + ts.stopprofit_point * 0.05)
    assert n == (1 + ts.next_point * 0.05)

    print(">>> from finance_tools_py.backtest import TurtleStrategy")
    print(">>> ts = TurtleStrategy(colname='atr5')")
    print(">>> row = pd.Series({'atr5': 0.05})")
    print(">>> ts.calc_price(1, row=row")
    print("(0.9, 1.5, 1.05)")

    ts = TurtleStrategy(colname='',
                        stoploss_point=0.5,
                        stopprofit_point=20,
                        next_point=2)
    assert ts.stoploss_point == 0.5
    assert ts.stopprofit_point == 20
    assert ts.next_point == 2

    ls, lf, n = ts.calc_price(1, row=row)
    assert ls == -1
    assert lf == -1
    assert n == -1

    # 只有一笔持仓时的判断-开始
    ts = TurtleStrategy(
        colname='atr5',
        max_amount={'0': 100},
        verbose=2,
        buy_dict={'0': [datetime.date(2000, 1, 1),
                        datetime.date(2000, 1, 2)]})
    ts.on_calc_buy_amount(datetime.date(2000, 1, 1),
                          '0',
                          1,
                          1000,
                          row=row,
                          verbose=2)
    print(ts.holds['0'][0])
    # 超过最大持仓线时不再购买
    assert not ts.on_check_buy(
        datetime.date(2000, 1, 2), '0', 1.01, 500, row=row, verbose=2)
    print(ts.holds['0'][0])
    assert not ts.on_check_buy(
        datetime.date(2000, 1, 2), '0', 1.1, 500, row=row, verbose=2)

    # 没有达到止损线,不卖
    assert not ts.on_check_sell(
        datetime.date(2000, 1, 3), '0', 0.95, 0, 0, 0, row=row, verbose=2)
    # 低于止损线,卖出
    assert ts.on_check_sell(datetime.date(2000, 1, 3),
                            '0',
                            0.89,
                            0,
                            0,
                            0,
                            row=row,
                            verbose=2)
    # 低于止盈,不卖
    assert not ts.on_check_sell(
        datetime.date(2000, 1, 3), '0', 1.49, 0, 0, 0, row=row, verbose=2)
    # 超过止盈,卖出
    assert ts.on_check_sell(datetime.date(2000, 1, 3),
                            '0',
                            1.51,
                            0,
                            0,
                            0,
                            row=row,
                            verbose=2)

    # 止损数量
    assert 100 == ts.on_calc_sell_amount(datetime.date(2000, 1, 3),
                                         '0',
                                         0,
                                         0,
                                         0,
                                         0,
                                         row=row,
                                         verbose=2)
    # 只有一笔持仓时的判断-结束

    # 多笔持仓时的判断-开始
    ts = TurtleStrategy(colname='atr5',
                        max_amount={'0': 100},
                        verbose=2,
                        buy_dict={
                            '0': [
                                datetime.date(2000, 1, 1),
                                datetime.date(2000, 1, 2),
                                datetime.date(2000, 1, 3)
                            ]
                        })

    ts.on_calc_buy_amount(datetime.date(2000, 1, 1),
                          '0',
                          1,
                          1000,
                          row=row,
                          verbose=2)
    ts.on_calc_buy_amount(datetime.date(2000, 1, 2),
                          '0',
                          2,
                          1000,
                          row=row,
                          verbose=2)
    print(ts.holds['0'][0])
    print(ts.holds['0'][1])
    # 超过最大持仓线时不再购买
    assert not ts.on_check_buy(
        datetime.date(2000, 1, 2), '0', 1.01, 500, row=row, verbose=2)
    print(ts.holds['0'][0])
    assert not ts.on_check_buy(
        datetime.date(2000, 1, 2), '0', 1.1, 500, row=row, verbose=2)

    # 止损数量
    assert 100 == ts.on_calc_sell_amount(datetime.date(2000, 1, 3),
                                         '0',
                                         1.8,
                                         0,
                                         0,
                                         0,
                                         row=row,
                                         verbose=2)
    print(ts.holds['0'][0])
    assert 100 == ts.holds['0'][0].amount
Esempio n. 6
0
def test_TurtleStrategy_MaxDays():
    symbol = '123456'
    holds = {
        symbol: [
            TurtleStrategy.Hold(
                symbol,
                datetime.date(1999, 1, 1),
                10,  # 买入价
                100,  # 持仓数量
                9,  # 止损价
                11,  # 止盈价
                10.5  # 下一个仓位价格
            ),
            TurtleStrategy.Hold(
                symbol,
                datetime.date(1999, 1, 2),
                20,  # 买入价
                100,  # 持仓数量
                9,  # 止损价
                11,  # 止盈价
                10.5  # 下一个仓位价格
            ),
        ]
    }
    ts = TurtleStrategy(
        colname='',
        holds=holds,
    )
    assert ts._get_overdue(symbol, datetime.date(2222, 1, 1)) is None

    ts = TurtleStrategy(
        colname='',
        holds=holds,
        max_days=10,
    )
    assert not ts._get_overdue(symbol, datetime.date(1999, 1, 9))
    assert not ts._get_overdue(symbol, datetime.date(1999, 1, 10))
    assert len(ts._get_overdue(symbol, datetime.date(1999, 1, 11))) > 0

    assert ts.on_calc_sell_amount(datetime.date(1999, 1, 9),
                                  symbol,
                                  10,
                                  0,
                                  0,
                                  0,
                                  verbose=2) == 0
    assert sum([h.amount for h in ts.holds[symbol]]) == 200
    assert ts.on_calc_sell_amount(datetime.date(1999, 1, 10),
                                  symbol,
                                  10,
                                  0,
                                  0,
                                  0,
                                  verbose=2) == 0
    assert sum([h.amount for h in ts.holds[symbol]]) == 200
    assert ts.on_calc_sell_amount(datetime.date(1999, 1, 11),
                                  symbol,
                                  10,
                                  0,
                                  0,
                                  0,
                                  verbose=2) == 100
    assert sum([h.amount for h in ts.holds[symbol]]) == 100
    assert ts.holds[symbol][0].price == 20
Esempio n. 7
0
def test_TurtleStrategy_4():
    symbol = '123456'
    holds = {
        symbol: [
            TurtleStrategy.Hold(
                symbol,
                datetime.date(1999, 1, 1),
                10,  # 买入价
                100,  # 持仓数量
                9,  # 止损价
                11,  # 止盈价
                10.5  # 下一个仓位价格
            )
        ]
    }
    ts = TurtleStrategy('',
                        holds=holds,
                        buy_dict={symbol: [datetime.date(2000, 1, 1)]})

    assert 1 == len(ts.holds[symbol])
    # 没有到达加仓点位
    assert not ts.on_check_buy(
        datetime.date(2000, 1, 1), symbol, 10.49, 1000, verbose=2)
    # 到达加仓点位
    assert ts.on_check_buy(datetime.date(2000, 1, 1),
                           symbol,
                           10.50,
                           1000,
                           verbose=2)
    # 没有加仓点位
    assert 0 == ts.on_calc_buy_amount(datetime.date(2000, 1, 1),
                                      symbol,
                                      10.49,
                                      1000,
                                      verbose=2)
    # 到达购买点,但是资金不足
    assert 0 == ts.on_calc_buy_amount(datetime.date(2000, 1, 1),
                                      symbol,
                                      10.50,
                                      1000,
                                      verbose=2)
    # 到达购买点,资金充足
    assert 100 == ts.on_calc_buy_amount(datetime.date(2000, 1, 1),
                                        symbol,
                                        10.50,
                                        1200,
                                        verbose=2)
    assert 2 == len(ts.holds[symbol])
    assert ts.holds[symbol][-1].amount == 100
    assert ts.holds[symbol][-1].stoploss_price == -1
    assert ts.holds[symbol][-1].stopprofit_price == -1
    assert ts.holds[symbol][-1].next_price == -1
    # 到达加仓点位
    assert ts.on_check_buy(datetime.date(2000, 1, 1), symbol, 10.50, 1000)
    assert 100 == ts.on_calc_buy_amount(datetime.date(2000, 1, 1),
                                        symbol,
                                        10.50,
                                        1200,
                                        verbose=2)
    # 到达加仓点位
    assert ts.on_check_buy(datetime.date(2000, 1, 1), symbol, 10.50, 1000)
    assert 100 == ts.on_calc_buy_amount(datetime.date(2000, 1, 1),
                                        symbol,
                                        10.50,
                                        1200,
                                        verbose=2)
    # 到达加仓点位。但是到达持仓限制
    assert not ts.on_check_buy(
        datetime.date(2000, 1, 1), symbol, 10.50, 1000, verbose=2)
    def test_all_years_single_symbol(symbol,
                                     init_cash=10000,
                                     start_year=2005,
                                     end_year=2007,
                                     verbose=2,
                                     show_report=True,
                                     show_plot=True,
                                     cbs=cbs,
                                     show_history=False,
                                     min_amount=100,
                                     single_max=400,
                                     **kwargs):
        """

        Args:
            init_cash:
            start_year (int): 开始计算年份。
            end_year (int): 结束计算年份。


        Returns:
            report (dict): BackTest字典。key值为年份。
            datas (dict): 回测用的数据源字典。key值为年份。
            buys (dict): 买点字典。key值为年份。
            sells (dict): 卖点字典。key值为年份。
        """
        hold = pd.DataFrame()
        report = {}
        datas = {}
        buys = {}
        sells = {}
        h = {}

        from tqdm import tqdm

        for year in tqdm(range(start_year, end_year)):
            df_symbol_year = ret_datas[
                (ret_datas.index.get_level_values(0) == symbol)
                & (ret_datas.index.get_level_values(1) <= '{}-12-31'.format(
                    year))]
            s = Simulation(df_symbol_year.reset_index(), symbol, callbacks=cbs)
            s.simulate()
            df_symbol_years = s.data
            df_symbol_years.sort_values('date', inplace=True)
            # 遍历股票,对每支股票进行数据处理-结束

            buy_dict = df_symbol_years[
                df_symbol_years['opt'] == 1].reset_index().groupby('code')[
                    'date'].apply(lambda x: x.dt.to_pydatetime()).to_dict()

            sell_dict = df_symbol_years[
                df_symbol_years['opt'] == 0].reset_index().groupby('code')[
                    'date'].apply(lambda x: x.dt.to_pydatetime()).to_dict()

            buys[year] = buy_dict
            sells[year] = sell_dict

            df_symbol_years = df_symbol_years[
                df_symbol_years['date'] >= '{}-01-01'.format(year)]

            datas[year] = df_symbol_years

            if verbose == 2:
                print('起止日期:{:%Y-%m-%d}~{:%Y-%m-%d}'.format(
                    min(df_symbol_years['date']),
                    max(df_symbol_years['date'])))
            #     print('数据量:{}'.format(len(df_symbol_years)))

            ts = TurtleStrategy(
                colname='atr_20',
                buy_dict=buy_dict,
                sell_dict=sell_dict,
                holds=h,
                max_amount=single_max,
                min_amount=min_amount,
            )
            bt = BackTest(df_symbol_years,
                          init_cash=init_cash,
                          init_hold=hold,
                          live_start_date=datetime.datetime(year, 1, 1),
                          callbacks=[ts])
            bt.calc_trade_history(verbose=2)
            report[year] = bt

            h = ts.holds
            if h:
                hs = []
                for k, v in h.items():
                    for v1 in v:
                        hs.append(
                            pd.DataFrame({
                                'code': [k],
                                'amount': [v1.amount],
                                'price': [v1.price],
                                'buy_date': [v1.date],
                                'stoploss_price': [v1.stoploss_price],
                                'stopprofit_price': [v1.stopprofit_price],
                                'next_price': [v1.next_price],
                            }))
                hold = pd.concat(hs) if hs else pd.DataFrame()

            init_cash = bt.available_cash
            if show_report:
                print(bt.report(show_history=show_history))
            if show_report or show_plot:
                rp = bt.profit_loss_df()
            if show_report:
                print(rp)
        return report, datas, buys, sells
Esempio n. 9
0
def all_years(fulldata,
              cbs,
              init_cash=10000,
              start_year=2005,
              end_year=2020,
              lookback=1,
              verbose=2,
              show_report=True,
              show_plot=True,
              tb_kwgs={},
              top=10,
              show_history=False,
              **kwargs):
    """逐年度对流动性最大的n支股票进行回测。

    采用 :py:class:`finance_tools_py.backtest.TurtleStrategy` 进行回测

    Args:
        fulldata (:py:class:`pandas.DataFrame`): 完整的原始数据。
            index[0]为股票代码,index[1]为日期。
        init_cash:
        top (int): 选取流动性最大的n值股票。默认为10。
            流动性计算参考 :py:func:`finance_tools_py.calc.fluidity`
        start_year (int): 开始计算年份。
        end_year (int): 结束计算年份。
        lookback (int): 回看几年的数据,用来计算流动性。当lookback==1时,实际会回看
        cbs ([:py:class:`finance_tools_py.simulation.callbacks.CallBack`]): 对数据进行模拟填充时的回调。参考 :py:class:`finance_tools_py.simulation.Simulation` 中的`callbacks`参数。
        tb_kwgs (dict): :py:class:`finance_tools_py.backtest.TurtleStrategy` 的参数集合。
        unit_percent (float): 计算头寸单元时使用的基准,默认为1%。
        fixed_unit (bool): 是否使用固定金额(init_cash)作为计算头寸单元的标的。默认为True。
            如果为False的话,会在每年开始时,使用上一年度的总资产(:py:attr:`finance_tools_py.backtest.BackTest.total_assets_cur`)结合`unit_percent`进行运算。
            如果是第一年则使用`init_cash`结合`unit_percent`进行运算。

    Returns:
        - dict: BackTest字典。key值为年份。

        - dict: 回测用的数据源字典。key值为年份。

        - dict: 买点字典。key值为年份。

        - dict: 卖点字典。key值为年份。
    """
    hold = pd.DataFrame()
    report = {}
    datas = {}
    buys = {}
    sells = {}
    h = {}
    tb_kwgs_copy = copy.deepcopy(tb_kwgs)
    baseValue = init_cash * kwargs.get('unit_percent', 0.01)  #计算头寸单元时使用的基准
    lookbacks = []
    years = []
    lookback = lookback - 1
    for i in range(start_year, end_year):
        if i + lookback + 1 <= end_year:
            lookbacks.append([i, i + lookback])
            years.append(i + lookback + 1)

    if verbose == 2:
        for lookback, year in zip(lookbacks, years):
            print(lookback, year)

    _top_dict = {}
    _every_year_dict = {}

    if 'symbol' not in fulldata.columns:
        fulldata['symbol'] = fulldata.index.get_level_values(0)
    if 'datetime' not in fulldata.columns:
        fulldata['datetime'] = fulldata.index.get_level_values(1)

    for look, year in tqdm(zip(lookbacks, years)):
        # 取 year 年的n支流动性最大的股票-开始
        year_df = fulldata[
            (fulldata['datetime'] <= datetime.date(look[-1], 12, 31))
            & (fulldata['datetime'] >= datetime.date(look[0], 1, 1))]
        #
        # year_df = fluidity(year_df)
        #
        # #计算所有的头寸单元
        # year_df.dropna(inplace=True)
        # year_df['unit'] = year_df.apply(lambda row: int(position_unit(row['close'], row['atr_20'], baseValue)/100), axis=1)
        # year_df=year_df[year_df['unit']>0]
        # #计算所有的头寸单元
        #
        # top_year = year_df[:top] if top > 0 else year_df

        tb_kwgs_copy['min_amount'] = {}
        tb_kwgs_copy['max_amount'] = {}
        top_year = []
        for v in fluidity(year_df).index.values:
            c = _cache(v)
            _s_data = None
            if c not in _top_dict or _top_dict[c] is None:
                df_symbol = year_df[year_df['symbol'] == v]
                s = Simulation(df_symbol.reset_index(), v,
                               callbacks=[ATR(20)])  #TODO
                s.simulate()
                s.data.dropna(inplace=True)
                _s_data = s.data.copy()
                _top_dict[c] = _s_data.copy()
            else:
                _s_data = _top_dict[c]
            if _s_data.empty:
                continue
            _s_data['unit'] = _s_data.apply(lambda row: position_unit(
                row['close'], row[tb_kwgs_copy['colname']], baseValue),
                                            axis=1)
            m = int(_s_data.iloc[-1]['unit'] / 100) * 100
            if m > 0:
                tb_kwgs_copy['min_amount'][v] = m
                tb_kwgs_copy['max_amount'][v] = m * 4
                top_year.append(v)
            else:
                if verbose > 0:
                    print('{}-根据时间 {:%Y-%m-%d}~{:%Y-%m-%d} 计算头寸单位大小为0'.format(
                        v, year_df['datetime'][0], year_df['datetime'][-1]))
            if len(top_year) >= top:
                break

        ls = list(
            set(
                list(top_year) +
                list(hold['code'].unique() if not hold.empty else [])))
        if not ls:
            if verbose > 0:
                print('{}无任何可跟踪的股票'.format(year))
            continue

        # 取 year 年的10支流动性最大的股票-结束
        #     print('{}年的10支流动性最大的股票'.format(year))
        # 遍历股票,对每支股票进行数据处理-开始
        df_symbol_years = []
        for symbol in ls:
            c = _cache(symbol, look[0], year)
            _s_data = None
            if c not in _every_year_dict or _every_year_dict[c] is None:
                df_symbol_year = fulldata[
                    (fulldata['symbol'] == symbol)
                    & (fulldata['datetime'] <= datetime.date(year, 12, 31))
                    & (fulldata['datetime'] >= datetime.date(look[0], 1, 1))]
                s = Simulation(df_symbol_year.reset_index(),
                               symbol,
                               callbacks=cbs)
                s.simulate()
                _s_data = s.data.copy()
            else:
                _s_data = _every_year_dict[c]
            df_symbol_years.append(_s_data)
        df_symbol_years = pd.concat(df_symbol_years)
        df_symbol_years.sort_values('date', inplace=True)
        # 遍历股票,对每支股票进行数据处理-结束

        buy_dict = df_symbol_years[df_symbol_years['opt'] == 1].reset_index(
        ).groupby('code')['date'].apply(
            lambda x: x.dt.to_pydatetime()).to_dict()

        sell_dict = df_symbol_years[df_symbol_years['opt'] == 0].reset_index(
        ).groupby('code')['date'].apply(
            lambda x: x.dt.to_pydatetime()).to_dict()

        if not hold.empty:
            for onlysell in set(hold['code'].to_list()).difference(
                    set(top_year)):
                if onlysell in buy_dict:
                    del buy_dict[onlysell]

        buys[year] = buy_dict
        sells[year] = sell_dict

        df_symbol_years = df_symbol_years[
            df_symbol_years['date'] >= '{}-01-01'.format(year)]

        datas[year] = df_symbol_years

        if verbose == 2:
            print('起止日期:{:%Y-%m-%d}~{:%Y-%m-%d}'.format(
                min(df_symbol_years['date']), max(df_symbol_years['date'])))
        #     print('数据量:{}'.format(len(df_symbol_years)))

        ts = TurtleStrategy(buy_dict=buy_dict,
                            sell_dict=sell_dict,
                            holds=h,
                            **tb_kwgs_copy)
        bt = BackTest(df_symbol_years,
                      init_cash=init_cash,
                      init_hold=hold,
                      live_start_date=datetime.datetime(year, 1, 1),
                      callbacks=[ts])
        bt.calc_trade_history(verbose=verbose)
        report[year] = bt

        if not kwargs.get('fixed_unit', True):
            baseValue = bt.total_assets_cur * kwargs.get('unit_percent',
                                                         0.01)  # 计算头寸单元时使用的基准

        h = ts.holds
        if h:
            hs = []
            for k, v in h.items():
                for v1 in v:
                    hs.append(
                        pd.DataFrame({
                            'code': [k],
                            'amount': [v1.amount],
                            'price': [v1.price],
                            'buy_date': [v1.date],
                            'stoploss_price': [v1.stoploss_price],
                            'stopprofit_price': [v1.stopprofit_price],
                            'next_price': [v1.next_price],
                        }))
            hold = pd.concat(hs) if hs else pd.DataFrame()

        init_cash = bt.available_cash
        if show_report:
            print(bt.report(show_history=show_history))
        if show_report or show_plot:
            rp = bt.profit_loss_df()
        if show_report:
            print(rp)
        if show_plot:
            fig, axes = plt.subplots(1, 2, figsize=(10, 3))
            Utils.plt_win_rate(rp, ax=axes[0])
            Utils.plt_pnl_ratio(rp, ax=axes[1])
            plt.gcf().autofmt_xdate()
            plt.show()
    df_profit = pd.concat([x.profit_loss_df() for x in report.values()])
    return df_profit, report, datas, buys, sells
Esempio n. 10
0
def all_years_single_symbol(symbol,
                            fulldata,
                            cbs,
                            init_cash=10000,
                            start_year=2005,
                            end_year=2007,
                            verbose=2,
                            show_report=True,
                            show_plot=True,
                            show_history=False,
                            tb_kwgs={},
                            **kwargs):
    """逐年度对单一股票进行回测。

    采用 :py:class:`finance_tools_py.backtest.TurtleStrategy` 进行回测

    Args:
        fulldata (:py:class:`pandas.DataFrame`): 完整的原始数据。
            index[0]为股票代码,index[1]为日期。
        init_cash:
        start_year (int): 开始计算年份。
        end_year (int): 结束计算年份。
        cbs ([:py:class:`finance_tools_py.simulation.callbacks.CallBack`]): 对数据进行模拟填充时的回调。参考 :py:class:`finance_tools_py.simulation.Simulation` 中的`callbacks`参数。
        tb_kwgs (dict): :py:class:`finance_tools_py.backtest.TurtleStrategy` 的参数集合。

    Returns:
        - dict: BackTest字典。key值为年份。

        - dict: 回测用的数据源字典。key值为年份。

        - dict: 买点字典。key值为年份。

        - dict: 卖点字典。key值为年份。
    """
    hold = pd.DataFrame()
    report = {}
    datas = {}
    buys = {}
    sells = {}
    h = {}
    tb_kwgs_copy = copy.deepcopy(tb_kwgs)

    for year in tqdm(range(start_year, end_year)):
        df_symbol_year = fulldata[
            (fulldata.index.get_level_values(0) == symbol)
            & (fulldata.index.get_level_values(1) <= '{}-12-31'.format(year))]
        s = Simulation(df_symbol_year.reset_index(), symbol, callbacks=cbs)
        s.simulate()
        df_symbol_years = s.data
        df_symbol_years.sort_values('date', inplace=True)
        # 遍历股票,对每支股票进行数据处理-结束

        buy_dict = df_symbol_years[df_symbol_years['opt'] == 1].reset_index(
        ).groupby('code')['date'].apply(
            lambda x: x.dt.to_pydatetime()).to_dict()

        sell_dict = df_symbol_years[df_symbol_years['opt'] == 0].reset_index(
        ).groupby('code')['date'].apply(
            lambda x: x.dt.to_pydatetime()).to_dict()

        buys[year] = buy_dict
        sells[year] = sell_dict

        df_symbol_years = df_symbol_years[
            df_symbol_years['date'] >= '{}-01-01'.format(year)]

        datas[year] = df_symbol_years

        if verbose == 2:
            print('起止日期:{:%Y-%m-%d}~{:%Y-%m-%d}'.format(
                min(df_symbol_years['date']), max(df_symbol_years['date'])))
            #     print('数据量:{}'.format(len(df_symbol_years)))

        ts = TurtleStrategy(buy_dict=buy_dict,
                            sell_dict=sell_dict,
                            holds=h,
                            **tb_kwgs_copy)
        bt = BackTest(df_symbol_years,
                      init_cash=init_cash,
                      init_hold=hold,
                      live_start_date=datetime.datetime(year, 1, 1),
                      callbacks=[ts])
        bt.calc_trade_history(verbose=2)
        report[year] = bt

        h = ts.holds
        if h:
            hs = []
            for k, v in h.items():
                for v1 in v:
                    hs.append(
                        pd.DataFrame({
                            'code': [k],
                            'amount': [v1.amount],
                            'price': [v1.price],
                            'buy_date': [v1.date],
                            'stoploss_price': [v1.stoploss_price],
                            'stopprofit_price': [v1.stopprofit_price],
                            'next_price': [v1.next_price],
                        }))
            hold = pd.concat(hs) if hs else pd.DataFrame()

        init_cash = bt.available_cash
        if show_report:
            print(bt.report(show_history=show_history))
        if show_report or show_plot:
            rp = bt.profit_loss_df()
        if show_report:
            print(rp)
        if show_plot:
            fig, axes = plt.subplots(1, 2, figsize=(10, 3))
            Utils.plt_win_rate(rp, ax=axes[0])
            Utils.plt_pnl_ratio(rp, ax=axes[1])
            plt.gcf().autofmt_xdate()
            plt.show()
    return report, datas, buys, sells