验证下《指数基金投资指南》中的策略是否有效

背景

前一阵子,老哥向我推荐了《指数基金投资指南》。我读完之后,第一感觉是这本书写得非常小白,门槛较低。该书向读者推荐了两种投资策略(我后面介绍),然后我在这里用量化的方法进行回测,看看这中投资策略是否有效。

投资策略

该书介绍了上证50指数,红利指数等指数基金。
我对上证50指数进行回测。

该书中也介绍了一些优秀的行业指数,最主要的是消费指数,医药指数。这里也是对消费指数,医药指数做验证。
消费指数有:上证消费指数,上证消费80指数,中证消费指数,全指消费指数。
目前比较大型的消费指数基金有:华夏消费ETF(510630),汇添富中证主要消费ETF(159928)。
我对159928进行回测,它跟踪的指数是中证消费指数(000932(上海)/399932(深圳))。
医药指数有:中证医药指数,中证医药100指数,上证医药指数,全指医药指数,细分医药指数,300医药指数,500医药指数。
目前流通性较好的基金有:159929,广发医药ETF(159938)
我对159938进行回测,它跟踪的是全指医药指数(000991)。使用策略2进行回测。


策略1 - 盈利收益率法

根据市盈率倒数(该书称为盈利收益率)进行定投。
市盈率有两种算法,在这里采用的是 公司市值处以公司盈利的算法。
核心策略:
- 盈利收益率大于10%的时候,分批投资。
- 盈利收益率小于低于10%,大于6.4%时,坚持持有。
- 盈利小于6.4%时,分批卖出基金。

策略2 - 博格公式法(市盈率)

核心策略:
-在股息高的时候买入。
-在市盈率处于历史低位的时候买入。(以上两点往往同时发生。)
-买入之后,耐心等待“均值回归”,即等待市盈率从低到高。

策略3 - 博格公式法(市净率)

策略总结

策略 适用指数 我回测的数据
盈利收益率法 上证50指数、上证红利指数、中证红利指数、基本面50指数、央视50指数 上证50指数(000016),基金501050
博格公式法 沪深300指数、中证500指数、创业板指数、红利机会指数、必须消费品指数、
医药行业指数、可选消费行业指数、养老产业指数
我测试的是中证消费指数
(000932/399932),
基金159928。
博格公式法 证券行业指数、金融行业指数、非银金融行业指数、地产行业指数 不测

实现

测试数据是用聚框的数据(因为本人懒),聚框的数据的准确性不能说100%,但是我到目前为止我也没在上面找到错误的数据。

  1. 设置成本
# 设置佣金/印花税
# 基金,买入印花税为0,卖出印花税为万分之三,买入卖出佣金为万分之三,平仓佣金为0,最低佣金为5
set_order_cost(OrderCost(open_tax=0, close_tax=0.0001,
                         open_commission=0.0003, close_commission=0.0003,
                         close_today_commission=0.00004, min_commission=5)
               , 'fund')

# 设置滑点 注:如果您没有调用 set_slippage 函数, 系统默认的滑点是 PriceRelatedSlippage(0.00246)
set_slippage(FixedSlippage(0.02))
  1. 设置
    开始时间:2016-09-19 结束时间:2017-07-01;资金:100000。
    盈利收益率的算法:
def datetime_offset_by_month(dt, n=1):
    # create a shortcut object for one day
    one_day = datetime.timedelta(days=1)

    # first use div and mod to determine year cycle
    q, r = divmod(dt.month + n, 12)

    # create a datetime2
    # to be the last day of the target month
    result = datetime.datetime(
        dt.year + q, r + 1, 1) - one_day

    '''
       if input date is the last day of this month
       then the output date should also be the last
       day of the target month, although the day
       www.iplaypy.com
       may be different.
       for example:
       datetime1 = 8.31
       datetime2 = 9.30
    '''

    if dt.month != (dt + one_day).month:
        return result

    '''
        if datetime1 day is bigger than last day of
        target month, then, use datetime2
        for example:
        datetime1 = 10.31
        datetime2 = 11.30
    '''

    if dt.day >= result.day:
        return result

    '''
     then, here, we just replace datetime2's day
     with the same of datetime1, that's ok.
    '''

    return result.replace(day=dt.day)

def datetime_offset_by_season(dt, n=1):
    datetime_offset_by_month(dt, n*3)

def get_statDate_range(date, i):
    last_season = datetime_offset_by_month(date, -3 * i)
    season_month = last_season.month / 3
    year = last_season.year
    if int(season_month) == 0:
        year = year - 1
        season_month = 4

    return str(year) + 'q' + str(int(season_month))

def get_last_4_seasons_self_net_profit(stock_code, date):
    q = query(
        income.statDate,
        income.net_profit
    ).filter(
        income.code == stock_code
    )

    flag = 0
    sum = 0
    for i in range(1, 5):
        # log.info('statDate is '+get_statDate_range(date, i+flag))
        df = get_fundamentals(q, statDate=get_statDate_range(date, i+flag))
        if df.empty:
            df = get_fundamentals(q, statDate=get_statDate_range(datetime_offset_by_month(date,-3), i+flag))
            flag = flag + 1
            if df.empty:
                df = get_fundamentals(q, statDate=get_statDate_range(datetime_offset_by_month(date,-3), i+flag))
                flag = flag + 1
                if df.empty:
                    df = get_fundamentals(q, statDate=get_statDate_range(datetime_offset_by_month(date,-3), i+flag))
                    flag = flag + 1
                    if df.empty:
                        df = get_fundamentals(q, statDate=get_statDate_range(datetime_offset_by_month(date,-3), i+flag))
                        flag = flag + 1

        # log.info('stock:'+stock_code+' i is '+str(i))

        if df.empty:
            pass
        else:
            sum = sum + df['net_profit'][0]

    # log.info('sum is %s' % sum)
    return sum

# 盈利收益率
def index_ep(context, index_code):
    stock_list = get_index_stocks(index_code)
    sum_cap=0
    sum_net_profit=0
    for stock_code in stock_list:
        df_valuation = get_fundamentals(
            query(
                    valuation.market_cap
                ).filter(
                    valuation.code == stock_code
                )
            )
        cap = df_valuation['market_cap'][0]
        net_profit = get_last_4_seasons_self_net_profit(stock_code, context.current_dt)
        sum_cap = sum_cap + cap
        sum_net_profit = sum_net_profit + net_profit

    ep_mean = 100000000 * sum_cap / sum_net_profit
    return  ep_mean

策略核心:

## 开盘时运行函数
def market_open(context):
    # 确定时间是周几
    weekday = context.current_dt.isoweekday()

    # 操作代码
    index_code = '000016.XSHG'
    fund_code = '501050.XSHG'

    ## 操作判定
    if weekday == 1:
        # 操作
        ped = index_ep(context, index_code)
        log.info('沪深300盈利收益率为%s' % ped)
        record(key=ped)
        if ped > 10.00:
            log.info('买入1000元'+fund_code)
            order_value(fund_code, 1000, 0)
        elif ped < 6.4 and ped > 0:
            log.info('卖出10000元'+fund_code)
            order_value(fund_code, -10000, 0)

回测结果:
这里写图片描述
由于这次测试是做等权计算盈利收益率,这样得出的结论是《指数基金投资指南》的盈利收益率并不是有效的策略。当然这只是我个人的测试结果。

猜你喜欢

转载自blog.csdn.net/ydonghao2/article/details/79907729
今日推荐