Ejemplo n.º 1
0
def is_k_down_break_m10(code, date):
    '''
    查看当日收盘价是否上穿10日均线
    parameter:
    code: 股票代码
    date: 日期
    return: True/False
    '''
    current_daily = daily_collection.find_one({
        'code': code,
        'date': date
    },
                                              projection={
                                                  'code': True,
                                                  '_id': False,
                                                  'close': True
                                              })
    if current_daily is None:
        print('code: %s have no data in date: %s' % (code, date))
        return False

    daily_cursor = daily_collection.find(
        {
            'code': code,
            'date': {
                '$lte': date
            },
            'index': False
        },
        sort=[('date', DESCENDING)],
        limit=11,
        projection={
            'code': True,
            'close': True,
            'date': True,
            '_id': False
        }).hint([('code', 1), ('date', -1)])

    closes = [daily['close'] for daily in daily_cursor]
    closes.reverse()

    if closes is None:
        print('data before 10 days of %s is None, code: %s' % (date, code))
        return False
    if len(closes) < 11:
        print('K line is not enough: code %s, date: %s' % (code, date))
        return False

    last_close_2_last_ma10 = compare_close_2_ma10(closes[0:10], current_daily)
    current_close_2_current_ma10 = compare_close_2_ma10(
        closes[1:], current_daily)
    if last_close_2_last_ma10 == 1 and current_close_2_current_ma10 == -1:
        return True
    else:
        return False
Ejemplo n.º 2
0
def evaluate_stock_pool(begin_date, end_date):
    '''
    评价股票池的的alpha值,基准选为沪深300
    '''
    # 得到每一期的股票池信息
    adjust_dates, codes_dict = stock_pool(begin_date, end_date)
    # 得到第一组和最后一组的日期
    first_phase_date = adjust_dates[0]
    last_phase_date = adjust_dates[-1]
    # 计算沪深300的收益率
    hs300_begin_value = daily_collection.find_one({
        'code': '000300',
        'index': True,
        'date': first_phase_date
    })['close']

    df_profit = pd.DataFrame(columns=['profit', 'hs300'])
    df_profit.loc[datetime.strptime(adjust_dates[0], '%Y-%m-%d')] = {
        'profit': 1,
        'hs300': 1
    }

    # 计算每一期相对于上一期的收益率
    net_value = 1
    for _index in range(1, len(adjust_dates) - 1):
        last_adjust_date = adjust_dates[_index - 1]
        current_adjust_date = adjust_dates[_index]
        # 上一期的股票代码
        last_phase_codes = codes_dict[last_adjust_date]
        buy_cursor = daily_collection.find(
            {
                'code': {
                    '$in': last_phase_codes
                },
                'date': last_adjust_date,
                'index': False
            },
            projection={
                'code': True,
                'close': True,
                '_id': False
            }).hint([('code', 1), ('date', -1)])

        code_buy_close_dict = dict()
        for buy_daily in buy_cursor:
            code = buy_daily['code']
            code_buy_close_dict[code] = buy_daily['close']

        sell_cursor = daily_collection.find(
            {
                'code': {
                    '$in': last_phase_codes
                },
                'date': current_adjust_date,
                'index': False
            },
            projection={
                'code': True,
                'close': True,
                '_id': False
            }).hint([('code', 1), ('date', -1)])

        profit_sum = 0
        count = 0
        for sell_daily in sell_cursor:
            _code = sell_daily['code']
            if _code in code_buy_close_dict:
                buy_close = code_buy_close_dict[_code]
                sell_close = sell_daily['close']

                profit_sum += (sell_close - buy_close) / buy_close
                count += 1

        if count > 0:
            profit = round(profit_sum / count, 4)
            hs300_current_value = daily_collection.find_one({
                'code':
                '000300',
                'index':
                True,
                'date':
                current_adjust_date
            })['close']

            # 计算净值和累计收益
            net_value = net_value * (1 + profit)
            dt_current_adjust_date = datetime.strptime(current_adjust_date,
                                                       '%Y-%m-%d')
            df_profit.loc[dt_current_adjust_date] = {
                'profit':
                round((net_value), 4),
                'hs300':
                round((hs300_current_value - hs300_begin_value) /
                      hs300_begin_value + 1, 4)
            }

    # 绘制图片
    df_profit.plot(title='Stock Pool Evaluation Result',
                   grid=True,
                   kind='line')
    plt.show()
Ejemplo n.º 3
0
def backtest(begin_date, end_date, fun_sell, fun_buy):
    '''
    回测系统
    parameter:
    fun_sell: 卖出信号
    fun_buy: 买入信号函数
    '''
    # 设置初始值
    cash = 1E7
    single_positon = 2E5
    df_profit = pd.DataFrame(columns=['net_value', 'profit', 'hs300'])
    # 得到回测日期
    all_dates = get_trading_dates(begin_date, end_date)
    adjust_dates, date_codes_dict = stock_pool(begin_date, end_date)
    hs300_begin_value = daily_collection.find_one(
        {
            'code': '000300',
            'index': True,
            'date': adjust_dates[0]
        },
        projection={
            'close': True,
            '_id': False
        })['close']

    holding_code_dict = dict()
    last_date = None
    this_phase_codes = None
    last_phase_codes = None
    to_be_bought_codes = set()
    to_be_sold_codes = set()

    for _date in all_dates:
        print('Back test begin at: %s' % _date)
        before_sell_holding_codes = list(holding_code_dict.keys())

        # 对于每一个回测日期处理复权
        if last_date is not None and len(before_sell_holding_codes) > 0:
            # produce_au(before_sell_holding_codes)
            last_daily_cursor = daily_collection.find(
                {
                    'code': {
                        '$in': before_sell_holding_codes
                    },
                    'date': last_date
                },
                projection={
                    'code': True,
                    '_id': False,
                    'au_factor': True
                }).hint([('code', 1), ('date', 1)])

            code_last_aufactor_dict = dict()
            for last_daily in last_daily_cursor:
                code_last_aufactor_dict[
                    last_daily['code']] = last_daily['au_factor']

            current_daily_cursor = daily_collection.find(
                {
                    'code': {
                        '$in': before_sell_holding_codes
                    },
                    'date': _date
                },
                projection={
                    'code': True,
                    '_id': False,
                    'au_factor': True
                }).hint([('code', 1), ('date', 1)])

            for current_daily in current_daily_cursor:
                current_aufactor = current_daily['au_factor']
                code = current_daily['code']
                before_volume = holding_code_dict[code]['volume']
                if code in code_last_aufactor_dict:
                    last_aufactor = code_last_aufactor_dict[code]
                    after_volume = int(before_volume *
                                       (current_aufactor / last_aufactor))
                    holding_code_dict[code]['volume'] = after_volume
                    print(
                        'hold volume adjust: code: %s, %6d, %10.6f, %6d, %10.6f'
                        % (code, before_volume, last_aufactor, after_volume,
                           current_aufactor))

        # 卖出上一期持仓股
        # print('to sell stocks: %s' % to_be_sold_codes, flush=True)
        if len(to_be_sold_codes) > 0:
            sell_daily_cursor = daily_collection.find(
                {
                    'code': {
                        '$in': list(to_be_sold_codes)
                    },
                    'date': _date,
                    'index': True,
                    'is_trading': True
                },
                projection={
                    'open': True,
                    'code': True,
                    '_id': False
                }).hint([('code', 1), ('date', -1)])

            for sell_daily in sell_daily_cursor:
                sell_code = sell_daily['code']
                if sell_code in before_sell_holding_codes:
                    holding_stock = before_sell_holding_codes[code]
                    sell_price = sell_daily['open']
                    holding_volume = holding_stock['volume']
                    sell_amount = holding_volume * sell_price
                    cash += sell_amount

                    cost = holding_stock['cost']
                    single_profit = (sell_amount - cost) * 100 / cost
                    print('sell: %s, %6d, %6.2f, %8.2f, %4.2f' %
                          (code, holding_volume, sell_price, sell_amount,
                           single_profit))
                    del holding_code_dict[code]
                    to_be_sold_codes.remove(code)
        print('cash after sell: %10.2f' % cash)

        # 买入这一期股票
        # print('to buy stocks: ', to_be_bought_codes, flush=True)
        if len(to_be_bought_codes) > 0:
            buy_daily_cursor = daily_collection.find(
                {
                    'code': {
                        '$in': list(to_be_bought_codes)
                    },
                    'date': _date,
                    'index': False,
                    'is_trading': True
                },
                projection={
                    'code': True,
                    '_id': False,
                    'open': True
                }).hint([('code', 1), ('date', -1)])

            for buy_daily in buy_daily_cursor:
                if cash > single_positon:
                    code = buy_daily['code']
                    buy_price = buy_daily['open']
                    buy_volume = int(
                        int(single_positon / buy_price) / 100) * 100
                    buy_amount = buy_price * buy_volume
                    cash -= buy_amount
                    holding_code_dict[code] = {
                        'volume': buy_volume,
                        'last_value': buy_amount,
                        'cost': buy_amount
                    }
                    print('buy %s, %6d, %6.2f, %8.2f' %
                          (code, buy_volume, buy_price, buy_amount))

        print('cash after buy: %10.2f' % cash)

        # 计算收益率
        holding_codes = list(holding_code_dict.keys())

        if _date in adjust_dates:
            print('stock pool adjust date: %s' % _date)

            if this_phase_codes is not None:
                last_phase_codes = this_phase_codes
            this_phase_codes = date_codes_dict[_date]
            # print(this_phase_codes, flush=True)

            if last_phase_codes is not None:
                out_codes = find_out_stocks(last_phase_codes, this_phase_codes)
                for out_code in out_codes:
                    if out_code in holding_code_dict:
                        to_be_sold_codes.add(out_code)

        for holding_code in holding_codes:
            if fun_sell(holding_code, _date):
                to_be_sold_codes.add(holding_code)

        to_be_bought_codes.clear()
        if this_phase_codes is not None:
            for _code in this_phase_codes:
                if _code not in holding_codes and fun_buy(_code, _date):
                    to_be_bought_codes.add(_code)

        # 计算持仓股票市值
        total_value = 0
        holding_daily_cursor = daily_collection.find(
            {
                'code': {
                    '$in': holding_codes
                },
                'date': _date,
                'index': False
            },
            projection={
                'code': True,
                '_id': False,
                'close': True
            }).hint([('code', 1), ('date', -1)])

        for holding_daily in holding_daily_cursor:
            code = holding_daily['code']
            holding_stock = holding_code_dict[code]
            value = holding_daily['close'] * holding_stock['volume']
            total_value += value

            profit = (value -
                      holding_stock['cost']) * 100 / holding_stock['cost']
            one_day_profit = (value - holding_stock['last_value']
                              ) * 100 / holding_stock['last_value']

            holding_stock['last_value'] = value
            # print('holding stocks: %s, %10.2f, %4.2f, %4.2f' %
            #         (code, value, profit, one_day_profit))
        # 计算总资产
        total_capital = total_value + cash

        # 计算基准收益
        hs300_current_value = daily_collection.find_one(
            {
                'code': '000300',
                'date': _date,
                'index': True
            },
            projection={
                'code': True,
                'close': True,
                '_id': False
            })['close']
        print('after close, cash: %10.2f, total_capital: %10.2f' %
              (cash, total_capital))
        dt_date = datetime.strptime(_date, '%Y-%m-%d')
        df_profit.loc[dt_date] = {
            'net_value':
            round(total_capital / 1e7, 2),
            'profit':
            round(100 * (total_capital - 1e7) / 1e7, 2),
            'hs300':
            round(
                100 * (hs300_current_value - hs300_begin_value) /
                hs300_begin_value, 2)
        }
    drawdown = compute_drawdown(df_profit['net_value'])
    annual_profit, sharpe_ratio = compute_sharpe_ratio(df_profit['net_value'])
    print(
        'Backtest result: %s - %s,  annual_profit: %7.3f, maxdrawdown:%7.3f, sharpe ratio: %4.2f'
        % (begin_date, end_date, annual_profit, drawdown, sharpe_ratio))

    df_profit.plot(title='Backtest Result', y=['profit', 'hs300'], kind='line')
    plt.show()