Пример #1
0
def buy(code, to_be_bought_codes, 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': to_be_bought_codes}, 'date': _date, 'index': False, 'is_trading': False},
            projection={'code': True, '_id': False, 'open': True}
        ).hint([('code', 1), ('date', -1)])

        for buy_daily in buy_daily_cursor:
            if cash > single_position:
                buy_price = buy_daily['open']
                buy_volume = int(single_positon / buy_price)
                buy_amount = buy_price * buy_volume
                cash -= buy_amount
                holding_code_dict[code] = {
                    'volume': buy_volume,
                    'last_value': buy_price,
                    'cost': buy_amount
                }
                print('buy %s, %6d, %6.2f, %8.2f' % (code, buy_volume, buy_amount))
    print('cash after buy: %10.2f' % cash)
    return holding_code_dict, cash 
Пример #2
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
Пример #3
0
def pingan_ma5(begin_date=None, end_date=None, code=None):
    if code is None:
        code = '000001'
    CASH = 100000
    daily_cursor = daily_collection.find(
        {
            'code': code,
            'date': {
                '$gte': begin_date,
                '$lte': end_date
            },
            'index': False
        },
        projection={
            'date': True,
            'close': True,
            '_id': False
        },
        sort=[('date', ASCENDING)],
    ).hint([('code', 1), ('date', -1)])

    df_daily = DataFrame([daily for daily in daily_cursor])
    df_daily.set_index('date', inplace=True)
    # print(df_daily)
    df_daily['ma5'] = round(df_daily['close'].rolling(5).mean())

    df_daily['last_close'] = df_daily['close'].shift(1)

    df_daily['buy_signal'] = df_daily['close'] > 1.01 * df_daily['ma5']
    df_daily['sell_signal'] = df_daily['close'] < df_daily['ma5']

    df_daily = df_daily[df_daily['buy_signal'] | df_daily['sell_signal']]

    record_stock_dict = dict()
    df_capital = dict()
    rest_cash = CASH
    hold_stock_dict = dict()
    hold_date = set()
    capital = CASH

    for date in df_daily.index:
        price = df_daily.loc[date]['close']
        if df_daily.loc[date]['buy_signal']:
            # price = df_daily.loc[date]['close']
            amount = rest_cash / price // 100 * 100
            if amount > 0:
                rest_cash = rest_cash - price * amount
                hold_stock_dict[date] = {'price': price, 'amount': amount}
                capital = amount * price + rest_cash
                hold_date.add(date)
                print(
                    'buy,  date: %s, price: %5.2f, amount: %8.2f, rest_cash: %10.2f, capital: %10.2f'
                    % (date, price, amount, rest_cash, capital))

        if df_daily.loc[date]['sell_signal']:
            try:
                if len(hold_date) > 0:
                    amount = 0
                    for _date in hold_date:
                        amount += hold_stock_dict[_date]['amount']
                    # amount = CASH / price // 100 * 100
                    rest_cash = rest_cash + price * amount
                    capital = rest_cash
                    print(
                        'sell, date: %s, price: %5.2f, amount: %8.2f, rest_cash: %10.2f, capital: %10.2f'
                        % (date, price, amount, rest_cash, capital))
                    del hold_stock_dict[_date]
                    hold_date.remove(_date)
            except:
                traceback.print_exc()

        dt_date = datetime.strptime(date, '%Y-%m-%d')
        holding_amount = 0
        if len(hold_date) > 0:
            for _date in hold_date:
                holding_amount += hold_stock_dict[_date]['amount']
            # holding_amount = hold_stock_dict[date]['amount']
            df_capital[dt_date] = rest_cash + price * holding_amount
        else:
            df_capital[dt_date] = rest_cash

    df_capital = DataFrame.from_dict(df_capital,
                                     orient='index',
                                     columns=['capital'])
    df_capital['profit'] = round((df_capital['capital'] - CASH) / CASH, 2)
    print(df_capital)
    df_capital.plot(title='Backtest Result', y=['profit'], kind='line')
    plt.grid()
    plt.show()
Пример #4
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()
Пример #5
0
def stock_pool(begin_date, end_date):

    adjust_date_codes_dict = dict()
    # 调整周期
    adjust_interval = 7
    all_adjust_dates = []
    last_phase_codes = []

    # 从数据库中挑选出0<pe<30的股票
    all_dates = get_trading_dates(begin_date=begin_date, end_date=end_date)

    for _index in range(0, len(all_dates), adjust_interval):
        adjust_date = all_dates[_index]
        all_adjust_dates.append(adjust_date)
        print('adjust date: %s' % adjust_date)
        daily_cursor = daily_collection.find(
            {
                'date': adjust_date,
                'pe': {
                    '$gt': 0,
                    '$lt': 30
                },
                'is_trading': True,
                'index': False
            },
            projection={
                'code': True,
                '_id': False
            },
            sort=[('pe', ASCENDING)],
            limit=100)

        codes = [x['code'] for x in daily_cursor]
        if codes == []:
            continue
        this_phase_codes = []

        # 判断是否在调整日停牌
        supension_codes = []
        if len(last_phase_codes) > 0:
            supension_cursor = daily_collection.find(
                {
                    'code': {
                        '$in': last_phase_codes
                    },
                    'date': adjust_date,
                    'is_trading': False
                },
                projection={
                    'code': True
                }).hint([('code', 1), ('date', -1)])
            supension_codes = [x['code'] for x in supension_cursor]
            this_phase_codes = supension_codes

        # 判断是否在上一期股票池中
        print('last phase code supended in this adjust day:')
        print(supension_codes)

        # 得到这一期的股票池
        this_phase_codes += codes[0:100 - len(this_phase_codes)]
        last_phase_codes = this_phase_codes
        # 建立该调整日和股票列表的对应关系
        adjust_date_codes_dict[adjust_date] = this_phase_codes

        print('this phase codes:')
        print(this_phase_codes)

    return all_adjust_dates, adjust_date_codes_dict
Пример #6
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()
Пример #7
0
def pe_computing(codes=None):
    '''
    利用eps和close计算股票的pe,并保存到mongodb中
    '''
    # 从finance_report中取出eps
    if codes is None:
        codes = get_all_codes()

    if isinstance(codes, list) is False:
        codes = [codes]

    for code in codes:
        # 从daily中找出close价格
        daily_cursor = daily_collection.find({'code': code},
                                             projection={
                                                 'close': True,
                                                 'date': True,
                                                 '_id': False
                                             })
        update_requests = []
        for daily in daily_cursor:
            date = daily['date']
            finance_eps_cursor = finance_report_collection.find_one(
                {
                    'code': code,
                    'report_date': {
                        '$regex': '\d{4}-12-31'
                    },
                    'announced_date': {
                        '$lt': date
                    }
                },
                projection={
                    'code': True,
                    'eps': True,
                    "_id": False
                },
                sort=[('announced_date', DESCENDING)])

            if finance_eps_cursor is None:
                continue

            if date < '2008-01-01':
                print('have no date in finance_reprot, code: %s' % code)
                finance_xiaoxiang().crawl_finance_report(code)
                break
            # 计算市盈率
            eps = 0
            if finance_eps_cursor['eps'] != '-':
                eps = finance_eps_cursor['eps']

            if eps != 0:
                update_requests.append(
                    UpdateOne({
                        'code': code,
                        'date': date
                    }, {'$set': {
                        'pe': round(daily['close'] / eps, 4)
                    }}))
        # 将市盈率更新到mongodb中
        if len(update_requests) > 0:
            update_result = daily_collection.bulk_write(update_requests,
                                                        ordered=False)
            print('update pe, code: %s, insert: %s, update: %s' %
                  (code, update_result.upserted_count,
                   update_result.modified_count))