Example #1
0
def update_minute_lib():
    minute_lib = arctic['minute']
    last_index = minute_lib.read(
        '000001.XSHG', columns=['close'], chunk_range=('2018-09-20',
                                                       None)).index[-1]
    if last_index.time() == time(15):
        start_date = rq.get_next_trading_date(last_index)
    else:
        start_date = last_index.date()

    for sid in tqdm(all_sid()):
        try:
            df = rq.get_price(
                sid,
                start_date=start_date,
                end_date=date.today(),
                frequency='1m',
                adjust_type='post')
            df.index.name = 'date'
            if len(df) > 0:
                minute_lib.update(
                    sid, df, chunk_range=(start_date, None), upsert=True)
        except Exception as e:
            # TODO: add logger later
            print(f'{sid}: {str(e)}')
Example #2
0
def update_minute1_lib():
    minute1_lib = arctic['minute1']
    last_index = minute1_lib.read('000001.XSHG').data.index[-1]

    if last_index.time() == time(15):
        start_date = rq.get_next_trading_date(last_index)

        if not rq.get_trading_dates(start_date, date.today()):
            print('DB is already up to date.')
            return

        for sid in tqdm(all_sid()):
            try:
                df = rq.get_price(sid,
                                  start_date=start_date,
                                  end_date=date.today(),
                                  frequency='1m',
                                  adjust_type='post')
                df.index.name = 'date'
                if len(df) > 0:
                    minute1_lib.append(sid, df, upsert=True)
            except Exception as e:
                # TODO: add logger later
                print(f'{sid}: {str(e)}')
    else:
        # read previous version, and get last index to compute start date
        previous_version = minute1_lib.list_versions('000001.XSHG')[1]
        last_index = minute1_lib.read(
            '000001.XSHG', as_of=previous_version['version']).data.index[-1]
        start_date = rq.get_next_trading_date(last_index)

        for sid in tqdm(all_sid()):
            try:
                df = rq.get_price(sid,
                                  start_date=start_date,
                                  end_date=date.today(),
                                  frequency='1m',
                                  adjust_type='post')
                df.index.name = 'date'
                pre_version_number = minute1_lib.list_versions(
                    sid)[1]['version']
                minute1_lib.restore_version(sid, pre_version_number)
                if len(df) > 0:
                    minute1_lib.append(sid, df, upsert=True)
            except Exception as e:
                # TODO: add logger later
                print(f'{sid}: {str(e)}')
Example #3
0
def get_recent_five_annual_shares(stock_list, date):

    # 上市公司每年4月30日前必须公布当年报告。因此,取此前每年5月1日后第一个交易日的股票A股流通股本,作为当年的股本

    previous_year = datetime.strptime(date, '%Y-%m-%d').year - 1

    month = datetime.strptime(date, '%Y-%m-%d').month

    if month > 5:

        list_of_dates = [
            str(previous_year) + '-05-01',
            str(previous_year - 1) + '-05-01',
            str(previous_year - 2) + '-05-01',
            str(previous_year - 3) + '-05-01',
            str(previous_year - 4) + '-05-01'
        ]

    else:

        list_of_dates = [
            str(previous_year - 1) + '-05-01',
            str(previous_year - 2) + '-05-01',
            str(previous_year - 3) + '-05-01',
            str(previous_year - 4) + '-05-01',
            str(previous_year - 5) + '-05-01'
        ]

    recent_five_annual_shares = pd.DataFrame()

    for report_date in list_of_dates:

        next_trading_date = rqdatac.get_next_trading_date(report_date)

        recent_five_annual_shares[report_date] = rqdatac.get_shares(
            stock_list,
            start_date=next_trading_date.strftime('%Y-%m-%d'),
            end_date=next_trading_date.strftime('%Y-%m-%d'),
            fields='total_a').iloc[0]

    # 调整股本 dataframe 的列名,方便相除计算每股收入

    recent_five_annual_shares.columns = [
        'first', 'second', 'third', 'fourth', 'fifth'
    ]

    return recent_five_annual_shares
Example #4
0
    def __call__(self, path, fields, **kwargs):
        with h5py.File(path, 'a') as h5:
            for order_book_id in self._order_book_ids:
                if order_book_id in h5:
                    try:
                        start_date = rqdatac.get_next_trading_date(
                            int(h5[order_book_id]['datetime'][-1] // 1000000))
                    except ValueError:
                        h5.pop(order_book_id)
                        start_date = START_DATE
                else:
                    start_date = START_DATE
                df = rqdatac.get_price(order_book_id,
                                       start_date,
                                       END_DATE,
                                       '1d',
                                       adjust_type='none',
                                       fields=fields,
                                       expect_df=True)
                if not (df is None or df.empty):
                    df = df.loc[order_book_id]
                    df.reset_index(inplace=True)
                    df['datetime'] = [
                        convert_date_to_int(d) for d in df['date']
                    ]
                    del df['date']
                    df.set_index('datetime', inplace=True)

                    if order_book_id in h5:
                        data = np.array([
                            tuple(i) for i in chain(h5[order_book_id][:],
                                                    df.to_records())
                        ],
                                        dtype=h5[order_book_id].dtype)
                        del h5[order_book_id]
                        h5.create_dataset(order_book_id, data=data, **kwargs)
                    else:
                        h5.create_dataset(order_book_id,
                                          data=df.to_records(),
                                          **kwargs)
                yield 1
Example #5
0
def update_day_lib():
    day_lib = arctic['day']
    last_index = day_lib.read('000001.XSHG').data.index[-1]
    start_date = rq.get_next_trading_date(last_index)
    if not rq.get_trading_dates(start_date, date.today()):
        print('DB is already up to date.')
        return

    for sid in tqdm(all_sid()):
        try:
            df = rq.get_price(sid,
                              start_date=start_date,
                              end_date=date.today(),
                              frequency='1d',
                              adjust_type='post')
            df.index.name = 'date'
            if len(df) > 0:
                day_lib.append(sid, df, upsert=True)
        except Exception as e:
            # TODO: add logger later
            print(f'{sid}: {str(e)}')
Example #6
0
def black_litterman_prep(order_book_ids,
                         start_date,
                         investors_views,
                         investors_views_indicate_M,
                         investors_views_uncertainty=None,
                         asset_type=None,
                         market_weight=None,
                         risk_free_rate_tenor=None,
                         risk_aversion_coefficient=None,
                         excess_return_cov_uncertainty=None,
                         confidence_of_views=None,
                         windows=None,
                         data_freq=None):
    """
    Generate expected return and expected return covariance matrix with Black-Litterman model. Suppose we have N assets
    and K views. The method can only support daily data so far.
    It's highly recommended to use your own ways to create investors_views_uncertainty, risk_aversion_coefficient and
    excess_return_cov_uncertainty beforehand to get the desired distribution parameters.
    :param order_book_ids: str list. A group of assets;
    :param asset_type: str. "fund" or "stock";
    :param start_date: str. The first day of backtest period;
    :param windows: int. Interval length of sample; Default: 132;
    :param investors_views: K*1 numpy matrix. Each row represents one view;
    :param investors_views_indicate_M: K*N numpy matrix. Each row corresponds to one view. Indicate which view is
    involved during calculation;
    :param investors_views_uncertainty: K*K diagonal matrix, optional. If it is skipped, He and Litterman's method will
    be called to generate diagonal matrix if confidence_of_view is also skipped; Idzorek's method will be called if
    confidence_of_view is passed in; Has to be non-singular;
    :param market_weight: floats list, optional. Weights for market portfolio; Default: Equal weights portfolio;
    :param risk_free_rate_tenor: str, optional. Risk free rate term. Default: "0S"; Support input: "0S", "1M", "3M",
    "6M", "1Y";
    :param risk_aversion_coefficient: float, optional. If no risk_aversion_coefficient is passed in, then
    risk_aversion_coefficient = market portfolio risk premium / market portfolio volatility;
    :param excess_return_cov_uncertainty: float, optional. Default: 1/T where T is the time length of sample;
    :param confidence_of_views: floats list, optional. Represent investors' confidence levels on each view.
    :param data_freq: str. Support input: "D": daily data; "W": weekly data; "M": monthly data.
    Weekly data means the close price at the end of each week is taken; monthly means the close price at the end of each
    month. When weekly and monthly data are used, suspended days issues will not be considered. In addition, weekly and
    monthly data don't consider public holidays which have no trading. Users should use a windows a little bit larger
    to get desired data length.
    Users should be very careful when using weekly or monthly data to avoid the observations have too short length.
    :return:
    numpy matrix. Expected return vector;
    numpy matrix. Covariance matrix of expected return;
    float. risk_aversion_coefficient;
    numpy ndarray. investors_views_uncertainty.
    """

    risk_free_rate_dict = {'0S': 1, '1M': 30, '3M': 92, '6M': 183, '1Y': 365}

    if market_weight is None:
        market_weight = pd.DataFrame([1 / len(order_book_ids)] *
                                     len(order_book_ids),
                                     index=order_book_ids)
    if windows is None:
        windows = 132
    if data_freq is None:
        data_freq = "D"
    if asset_type is None:
        asset_type = "fund"
    if risk_free_rate_tenor is None:
        risk_free_rate_tenor = "0S"

    # Clean data
    end_date = rqdatac.get_previous_trading_date(start_date)
    end_date = pd.to_datetime(end_date)
    clean_period_prices, reset_start_date = (data_process(
        order_book_ids, asset_type, start_date, windows, data_freq)[i]
                                             for i in [0, 2])

    if excess_return_cov_uncertainty is None:
        excess_return_cov_uncertainty = 1 / clean_period_prices.shape[0]

    # Fetch risk free rate data
    reset_start_date = rqdatac.get_next_trading_date(reset_start_date)
    risk_free_rate = rqdatac.get_yield_curve(reset_start_date,
                                             end_date,
                                             tenor=risk_free_rate_tenor,
                                             country='cn')
    if data_freq is not "D":
        risk_free_rate = risk_free_rate.asfreq(data_freq, method="pad")
    risk_free_rate[data_freq] = pd.Series(
        np.power(1 + risk_free_rate.iloc[:, 0],
                 risk_free_rate_dict[risk_free_rate_tenor] / 365) - 1,
        index=risk_free_rate.index)

    # Calculate risk premium for each equity
    clean_period_prices_pct_change = clean_period_prices.pct_change()
    clean_period_excess_return = clean_period_prices_pct_change.subtract(
        risk_free_rate[data_freq], axis=0)

    # Wash out the ones in kick_out_list
    clean_market_weight = market_weight.loc[clean_period_prices.columns.values]
    temp_sum_weight = clean_market_weight.sum()
    clean_market_weight = clean_market_weight.div(temp_sum_weight)

    # If no risk_aversion_coefficient is passed in, then
    # risk_aversion_coefficient = market portfolio risk premium / market portfolio volatility
    if risk_aversion_coefficient is None:
        market_portfolio_return = np.dot(clean_period_prices_pct_change,
                                         clean_market_weight)
        risk_aversion_coefficient = ((market_portfolio_return[1:].mean() -
                                      risk_free_rate[data_freq].mean()) /
                                     market_portfolio_return[1:].var())

    clean_period_excess_return_cov = clean_period_excess_return[1:].cov()
    equilibrium_return = np.multiply(
        np.dot(clean_period_excess_return_cov, clean_market_weight),
        risk_aversion_coefficient)

    # Generate the investors_views_uncertainty matrix if none is passed in
    if investors_views_uncertainty is None:
        if confidence_of_views is None:
            # He and Litteman's(1999) method to generate the uncertainty diagonal matrix, confidence level on each view
            # doesn't need.
            Omeg_diag = list()
            for i in range(investors_views_indicate_M.shape[0]):
                temp = np.dot(
                    np.dot(investors_views_indicate_M[i, :],
                           clean_period_excess_return_cov),
                    investors_views_indicate_M[
                        i, :].transpose()) * excess_return_cov_uncertainty
                Omeg_diag.append(temp.item(0))
            investors_views_uncertainty = np.diag(Omeg_diag)
        else:
            # Idzorek's(2002) method, users can specify their confidence level on each view.
            Omeg_diag = list()
            for i in range(len(investors_views)):
                part1 = excess_return_cov_uncertainty * np.dot(
                    clean_period_excess_return_cov,
                    investors_views_indicate_M[i, :].transpose())
                part2 = 1 / (excess_return_cov_uncertainty * np.dot(
                    investors_views_indicate_M[i, :],
                    np.dot(clean_period_excess_return_cov,
                           investors_views_indicate_M[i, :].T)))
                part3 = investors_views[i] - np.dot(
                    investors_views_indicate_M[i, :], equilibrium_return)
                return_with_full_confidence = equilibrium_return + np.multiply(
                    part2 * part3, part1)
                weights_with_full_confidence = np.dot(
                    np.linalg.inv(
                        np.multiply(risk_aversion_coefficient,
                                    clean_period_excess_return_cov)),
                    return_with_full_confidence)
                temp1 = weights_with_full_confidence - clean_market_weight
                temp2 = np.multiply(
                    confidence_of_views[i],
                    np.absolute(investors_views_indicate_M[i, :].transpose()))
                tilt = np.multiply(temp1, temp2)
                weights_with_partial_confidence = clean_market_weight.as_matrix(
                ) + tilt

                def objective_fun(x):
                    temp1 = np.linalg.inv(
                        np.multiply(risk_aversion_coefficient,
                                    clean_period_excess_return_cov))
                    temp2 = np.linalg.inv(
                        np.linalg.inv(
                            np.multiply(excess_return_cov_uncertainty,
                                        clean_period_excess_return_cov)) +
                        np.multiply(
                            np.reciprocal(x),
                            np.dot(
                                investors_views_indicate_M[i, :].transpose(),
                                investors_views_indicate_M[i, :])))
                    temp3 = (np.dot(
                        np.linalg.inv(
                            np.multiply(excess_return_cov_uncertainty,
                                        clean_period_excess_return_cov)),
                        equilibrium_return) + np.multiply(
                            investors_views[i] * np.reciprocal(x),
                            investors_views_indicate_M[i, :].transpose()))
                    wk = np.dot(temp1, np.dot(temp2, temp3))
                    return np.linalg.norm(
                        np.subtract(weights_with_partial_confidence, wk))

                # Upper bound should be consistent with the magnitude of return
                upper_bound = abs(equilibrium_return.mean()) * 100
                omega_k = sc_opt.minimize_scalar(objective_fun,
                                                 bounds=(10**-8, upper_bound),
                                                 method="bounded",
                                                 options={"xatol": 10**-8})
                Omeg_diag.append(omega_k.x.item(0))
            investors_views_uncertainty = np.diag(Omeg_diag)

    # Combine all the information above to get the distribution of expected return with given views
    combined_return_covar = np.linalg.inv(
        np.linalg.inv(
            np.multiply(excess_return_cov_uncertainty,
                        clean_period_excess_return_cov)) + np.dot(
                            np.dot(investors_views_indicate_M.transpose(),
                                   np.linalg.inv(investors_views_uncertainty)),
                            investors_views_indicate_M))
    temp1 = np.dot(
        np.linalg.inv(
            np.multiply(excess_return_cov_uncertainty,
                        clean_period_excess_return_cov)), equilibrium_return)
    temp2 = np.dot(
        np.dot(investors_views_indicate_M.transpose(),
               np.linalg.inv(investors_views_uncertainty)), investors_views)
    temp = temp1 + temp2

    combined_return_mean = np.dot(combined_return_covar, temp)

    return combined_return_mean, combined_return_covar, risk_aversion_coefficient, investors_views_uncertainty
Example #7
0
def test_get_next_trading_date():
    assert rq.get_next_trading_date('2018-09-21') == date(2018, 9, 25)
    assert rq.get_next_trading_date('2018-09-20') == date(2018, 9, 21)
    # 计算
    pctChange = pd.DataFrame(index=range(2011, 2021), columns=contractList)

    for year_id in range(2011, 2021):
        # year_id = 2011
        print(year_id)
        endDate = str(year_id) + endBenchDate
        startDate = str(year_id) + startBenchDate
        dateSeries = pd.Series(rq.get_trading_dates(startDate, endDate))
        dateDelta = [0] + [
            delta.days for delta in dateSeries.diff()[1:].tolist()
        ]
        dateDf = pd.DataFrame({'date': dateSeries, 'delta': dateDelta})
        dateDf = dateDf[dateDf['delta'] > 3]
        startDate = dateDf.iloc[0, 0]
        endDate = rq.get_next_trading_date(startDate, n=dateLen)
        print(startDate)

        Data = calendarArbitrage.dataLoad.data_load(contractList,
                                                    start_date=startDate,
                                                    end_date=endDate)

        dataDf = pd.DataFrame()
        for contract_id in contractList:
            dataClose = Data[contract_id]['close']
            dataDf = pd.concat([dataDf, dataClose], axis=1)
        dataDf.columns = contractList

        pctChangeDf = dataDf / dataDf.iloc[0, :]
        pctChange.loc[year_id] = pctChangeDf.iloc[-1, :] - 1
Example #9
0
def black_litterman_prep(order_book_ids, start_date, investors_views, investors_views_indicate_M,
                         investors_views_uncertainty=None, asset_type=None, market_weight=None,
                         risk_free_rate_tenor=None, risk_aversion_coefficient=None, excess_return_cov_uncertainty=None,
                         confidence_of_views=None):

    risk_free_rate_dict = ['0S', '1M', '2M', '3M', '6M', '9M', '1Y', '2Y', '3Y', '4Y', '5Y', '6Y', '7Y', '8Y',
                           '9Y', '10Y', '15Y', '20Y', '30Y', '40Y', '50Y']
    windows = 132
    if market_weight is None:
        market_weight = pd.DataFrame([1/len(order_book_ids)] * len(order_book_ids), index=order_book_ids)

    # Clean data
    if asset_type is None:
        asset_type = "fund"
    end_date = rqdatac.get_previous_trading_date(start_date)
    end_date = pd.to_datetime(end_date)
    clean_period_prices, reset_start_date = (pf.data_process(order_book_ids, asset_type, start_date, windows)[i]
                                             for i in [0, 2])
    
    if excess_return_cov_uncertainty is None:
        excess_return_cov_uncertainty = 1 / clean_period_prices.shape[0]

    reset_start_date = rqdatac.get_next_trading_date(reset_start_date)
    # Take daily risk free rate
    if risk_free_rate_tenor is None:
        risk_free_rate = rqdatac.get_yield_curve(reset_start_date, end_date, tenor='0S', country='cn')
    elif risk_free_rate_tenor in risk_free_rate_dict:
        risk_free_rate = rqdatac.get_yield_curve(reset_start_date, end_date, tenor=risk_free_rate_tenor,
                                                 country='cn')
    risk_free_rate['Daily'] = pd.Series(np.power(1 + risk_free_rate['0S'], 1 / 365) - 1, index=risk_free_rate.index)

    # Calculate daily risk premium for each equity
    clean_period_prices_pct_change = clean_period_prices.pct_change()
    clean_period_excess_return = clean_period_prices_pct_change.subtract(risk_free_rate['Daily'], axis=0)

    # Wash out the ones in kick_out_list
    clean_market_weight = market_weight.loc[clean_period_prices.columns.values]
    temp_sum_weight = clean_market_weight.sum()
    clean_market_weight = clean_market_weight.div(temp_sum_weight)

    # If no risk_aversion_coefficient is passed in, then
    # risk_aversion_coefficient = market portfolio risk premium / market portfolio volatility
    if risk_aversion_coefficient is None:
        market_portfolio_return = np.dot(clean_period_prices_pct_change, clean_market_weight)
        risk_aversion_coefficient = ((market_portfolio_return[1:].mean()-risk_free_rate["Daily"].mean()) /
                                     market_portfolio_return[1:].var())

    equilibrium_return = np.multiply(np.dot(clean_period_excess_return[1:].cov(), clean_market_weight),
                                     risk_aversion_coefficient)

    clean_period_excess_return_cov = clean_period_excess_return[1:].cov()
    # Generate the investors_views_uncertainty matrix if none is passed in
    if investors_views_uncertainty is None:
        if confidence_of_views is None:
            # He and Litteman's(1999) method to generate the uncertainty diagonal matrix, confidence level on each view
            # doesn't need.
            Omeg_diag = list()
            for i in range(investors_views_indicate_M.shape[0]):
                temp = np.dot(np.dot(investors_views_indicate_M[i, :], clean_period_excess_return_cov),
                              investors_views_indicate_M[i, :].transpose()) * excess_return_cov_uncertainty
                Omeg_diag.append(temp.item(0))
            investors_views_uncertainty = np.diag(Omeg_diag)
        else:
            # Idzorek's(2002) method, users can specify their confidence level on each view.
            Omeg_diag = list()
            for i in range(len(investors_views)):
                part1 = excess_return_cov_uncertainty * np.dot(clean_period_excess_return_cov,
                                                               investors_views_indicate_M[i, :].transpose())
                part2 = 1 / (excess_return_cov_uncertainty*np.dot(investors_views_indicate_M[i, :],
                                                                  np.dot(clean_period_excess_return_cov,
                                                                         investors_views_indicate_M[i, :].transpose())))
                part3 = investors_views[i]-np.dot(investors_views_indicate_M[i, :], equilibrium_return)
                return_with_full_confidence = equilibrium_return + np.multiply(part2 * part3, part1)
                weights_with_full_confidence = np.dot(np.linalg.inv(np.multiply(risk_aversion_coefficient,
                                                                    clean_period_excess_return_cov)),
                                                      return_with_full_confidence)
                temp1 = weights_with_full_confidence-clean_market_weight
                temp2 = np.multiply(confidence_of_views[i], np.absolute(investors_views_indicate_M[i, :].transpose()))
                tilt = np.multiply(temp1, temp2)
                weights_with_partial_confidence =clean_market_weight.as_matrix() + tilt

                def objective_fun(x):
                    temp1 = np.linalg.inv(np.multiply(risk_aversion_coefficient, clean_period_excess_return_cov))
                    temp2 = np.linalg.inv(np.linalg.inv(np.multiply(excess_return_cov_uncertainty,
                                                                    clean_period_excess_return_cov)) +
                                          np.multiply(np.reciprocal(x), np.dot(investors_views_indicate_M[i, :].transpose(),
                                                     investors_views_indicate_M[i, :])))
                    temp3 = (np.dot(np.linalg.inv(np.multiply(excess_return_cov_uncertainty,
                                                             clean_period_excess_return_cov)), equilibrium_return) +
                             np.multiply(investors_views[i]*np.reciprocal(x),
                                         investors_views_indicate_M[i, :].transpose()))
                    wk = np.dot(temp1, np.dot(temp2, temp3))
                    return np.linalg.norm(np.subtract(weights_with_partial_confidence, wk))

                # Upper bound should be consistent with the magnitude of return
                upper_bound = equilibrium_return.mean()*100
                omega_k = sc_opt.minimize_scalar(objective_fun, bounds=(10**-8, upper_bound), method="bounded",
                                                 options={"xatol": 10**-8})
                Omeg_diag.append(omega_k.x.item(0))
            investors_views_uncertainty = np.diag(Omeg_diag)

    # Combine all the information above to get the distribution of expected return with given views
    combined_return_covar = np.linalg.inv(np.linalg.inv(np.multiply(excess_return_cov_uncertainty, 
                                                                      clean_period_excess_return_cov))
                                            + np.dot(np.dot(investors_views_indicate_M.transpose(),
                                                            np.linalg.inv(investors_views_uncertainty)),
                                                     investors_views_indicate_M))
    temp1 = np.dot(np.linalg.inv(np.multiply(excess_return_cov_uncertainty, clean_period_excess_return_cov)), 
                   equilibrium_return)
    temp2 = np.dot(np.dot(investors_views_indicate_M.transpose(), np.linalg.inv(investors_views_uncertainty)),
                   investors_views)
    temp = temp1 + temp2

    combined_return_mean = np.dot(combined_return_covar, temp)
    return combined_return_mean, combined_return_covar, risk_aversion_coefficient, investors_views_uncertainty
Example #10
0
def black_litterman_prep(order_book_ids,
                         start_date,
                         investors_views,
                         investors_views_indicate_M,
                         investors_views_uncertainty=None,
                         asset_type=None,
                         market_weight=None,
                         risk_free_rate_tenor=None,
                         risk_aversion_coefficient=None,
                         excess_return_cov_uncertainty=None,
                         confidence_of_views=None,
                         windows=None):
    """
    Generate expected return and expected return covariance matrix with Black-Litterman model. Suppose we have N assets
    and K views.
    It's highly recommended to use your own ways to create investors_views_uncertainty, risk_aversion_coefficient and
    excess_return_cov_uncertainty beforehand to get the desired distribution parameters.
    :param order_book_ids: str list. A group of assets;
    :param asset_type: str. "fund" or "stock";
    :param start_date: str. The first day of backtest period;
    :param windows: int. Interval length of sample; Default: 132;
    :param investors_views: K*1 numpy matrix. Each row represents one view;
    :param investors_views_indicate_M: K*N numpy matrix. Each row corresponds to one view. Indicate which view is
    involved during calculation;
    :param investors_views_uncertainty: K*K diagonal matrix, optional. If it is skipped, He and Litterman's method will
    be called to generate diagonal matrix if confidence_of_view is also skipped; Idzorek's method will be called if
    confidence_of_view is passed in; Has to be non-singular;
    :param market_weight: floats list, optional. Weights for market portfolio; Default: Equal weights portfolio;
    :param risk_free_rate_tenor: str, optional. The period of risk free rate will be used. Default: "0s";
    :param risk_aversion_coefficient: float, optional. If no risk_aversion_coefficient is passed in, then
    risk_aversion_coefficient = market portfolio risk premium / market portfolio volatility;
    :param excess_return_cov_uncertainty: float, optional. Default: 1/T where T is the time length of sample;
    :param confidence_of_views: floats list, optional. Represent investors' confidence levels on each view.
    :return: expected return vector, covariance matrix of expected return, risk_aversion_coefficient,
    investors_views_uncertainty.
    """

    risk_free_rate_dict = [
        '0S', '1M', '2M', '3M', '6M', '9M', '1Y', '2Y', '3Y', '4Y', '5Y', '6Y',
        '7Y', '8Y', '9Y', '10Y', '15Y', '20Y', '30Y', '40Y', '50Y'
    ]

    if market_weight is None:
        market_weight = pd.DataFrame([1 / len(order_book_ids)] *
                                     len(order_book_ids),
                                     index=order_book_ids)
    if windows is None:
        windows = 132

    # Clean data
    if asset_type is None:
        asset_type = "fund"
    end_date = rqdatac.get_previous_trading_date(start_date)
    end_date = pd.to_datetime(end_date)
    clean_period_prices, reset_start_date = (data_process(
        order_book_ids, asset_type, start_date, windows)[i] for i in [0, 2])

    if excess_return_cov_uncertainty is None:
        excess_return_cov_uncertainty = 1 / clean_period_prices.shape[0]

    reset_start_date = rqdatac.get_next_trading_date(reset_start_date)
    # Take daily risk free rate
    if risk_free_rate_tenor is None:
        risk_free_rate = rqdatac.get_yield_curve(reset_start_date,
                                                 end_date,
                                                 tenor='0S',
                                                 country='cn')
    elif risk_free_rate_tenor in risk_free_rate_dict:
        risk_free_rate = rqdatac.get_yield_curve(reset_start_date,
                                                 end_date,
                                                 tenor=risk_free_rate_tenor,
                                                 country='cn')
    risk_free_rate['Daily'] = pd.Series(
        np.power(1 + risk_free_rate['0S'], 1 / 365) - 1,
        index=risk_free_rate.index)

    # Calculate daily risk premium for each equity
    clean_period_prices_pct_change = clean_period_prices.pct_change()
    clean_period_excess_return = clean_period_prices_pct_change.subtract(
        risk_free_rate['Daily'], axis=0)

    # Wash out the ones in kick_out_list
    clean_market_weight = market_weight.loc[clean_period_prices.columns.values]
    temp_sum_weight = clean_market_weight.sum()
    clean_market_weight = clean_market_weight.div(temp_sum_weight)

    # If no risk_aversion_coefficient is passed in, then
    # risk_aversion_coefficient = market portfolio risk premium / market portfolio volatility
    if risk_aversion_coefficient is None:
        market_portfolio_return = np.dot(clean_period_prices_pct_change,
                                         clean_market_weight)
        risk_aversion_coefficient = ((market_portfolio_return[1:].mean() -
                                      risk_free_rate["Daily"].mean()) /
                                     market_portfolio_return[1:].var())

    equilibrium_return = np.multiply(
        np.dot(clean_period_excess_return[1:].cov(), clean_market_weight),
        risk_aversion_coefficient)

    clean_period_excess_return_cov = clean_period_excess_return[1:].cov()
    # Generate the investors_views_uncertainty matrix if none is passed in
    if investors_views_uncertainty is None:
        if confidence_of_views is None:
            # He and Litteman's(1999) method to generate the uncertainty diagonal matrix, confidence level on each view
            # doesn't need.
            Omeg_diag = list()
            for i in range(investors_views_indicate_M.shape[0]):
                temp = np.dot(
                    np.dot(investors_views_indicate_M[i, :],
                           clean_period_excess_return_cov),
                    investors_views_indicate_M[
                        i, :].transpose()) * excess_return_cov_uncertainty
                Omeg_diag.append(temp.item(0))
            investors_views_uncertainty = np.diag(Omeg_diag)
        else:
            # Idzorek's(2002) method, users can specify their confidence level on each view.
            Omeg_diag = list()
            for i in range(len(investors_views)):
                part1 = excess_return_cov_uncertainty * np.dot(
                    clean_period_excess_return_cov,
                    investors_views_indicate_M[i, :].transpose())
                part2 = 1 / (excess_return_cov_uncertainty * np.dot(
                    investors_views_indicate_M[i, :],
                    np.dot(clean_period_excess_return_cov,
                           investors_views_indicate_M[i, :].transpose())))
                part3 = investors_views[i] - np.dot(
                    investors_views_indicate_M[i, :], equilibrium_return)
                return_with_full_confidence = equilibrium_return + np.multiply(
                    part2 * part3, part1)
                weights_with_full_confidence = np.dot(
                    np.linalg.inv(
                        np.multiply(risk_aversion_coefficient,
                                    clean_period_excess_return_cov)),
                    return_with_full_confidence)
                temp1 = weights_with_full_confidence - clean_market_weight
                temp2 = np.multiply(
                    confidence_of_views[i],
                    np.absolute(investors_views_indicate_M[i, :].transpose()))
                tilt = np.multiply(temp1, temp2)
                weights_with_partial_confidence = clean_market_weight.as_matrix(
                ) + tilt

                def objective_fun(x):
                    temp1 = np.linalg.inv(
                        np.multiply(risk_aversion_coefficient,
                                    clean_period_excess_return_cov))
                    temp2 = np.linalg.inv(
                        np.linalg.inv(
                            np.multiply(excess_return_cov_uncertainty,
                                        clean_period_excess_return_cov)) +
                        np.multiply(
                            np.reciprocal(x),
                            np.dot(
                                investors_views_indicate_M[i, :].transpose(),
                                investors_views_indicate_M[i, :])))
                    temp3 = (np.dot(
                        np.linalg.inv(
                            np.multiply(excess_return_cov_uncertainty,
                                        clean_period_excess_return_cov)),
                        equilibrium_return) + np.multiply(
                            investors_views[i] * np.reciprocal(x),
                            investors_views_indicate_M[i, :].transpose()))
                    wk = np.dot(temp1, np.dot(temp2, temp3))
                    return np.linalg.norm(
                        np.subtract(weights_with_partial_confidence, wk))

                # Upper bound should be consistent with the magnitude of return
                upper_bound = abs(equilibrium_return.mean()) * 100
                omega_k = sc_opt.minimize_scalar(objective_fun,
                                                 bounds=(10**-8, upper_bound),
                                                 method="bounded",
                                                 options={"xatol": 10**-8})
                Omeg_diag.append(omega_k.x.item(0))
            investors_views_uncertainty = np.diag(Omeg_diag)

    # Combine all the information above to get the distribution of expected return with given views
    combined_return_covar = np.linalg.inv(
        np.linalg.inv(
            np.multiply(excess_return_cov_uncertainty,
                        clean_period_excess_return_cov)) + np.dot(
                            np.dot(investors_views_indicate_M.transpose(),
                                   np.linalg.inv(investors_views_uncertainty)),
                            investors_views_indicate_M))
    temp1 = np.dot(
        np.linalg.inv(
            np.multiply(excess_return_cov_uncertainty,
                        clean_period_excess_return_cov)), equilibrium_return)
    temp2 = np.dot(
        np.dot(investors_views_indicate_M.transpose(),
               np.linalg.inv(investors_views_uncertainty)), investors_views)
    temp = temp1 + temp2

    combined_return_mean = np.dot(combined_return_covar, temp)

    return combined_return_mean, combined_return_covar, risk_aversion_coefficient, investors_views_uncertainty
Example #11
0
    # 参数
    dateLen = 10
    startBenchDate = '0420'
    endBenchDate = '0430'
    contractList = ('000016.XSHG', '000300.XSHG', '000905.XSHG', '000852.XSHG',
                    '399006.XSHE')

    # 计算
    pctChange = pd.DataFrame(index=range(2011, 2021), columns=contractList)

    for year_id in range(2011, 2021):
        # year_id = 2011
        print(year_id)
        endDate = str(year_id) + endBenchDate
        endDate = rq.get_previous_trading_date(
            rq.get_next_trading_date(endDate))
        # startDate = rq.get_previous_trading_date(endDate, n=dateLen)
        startDate = str(year_id) + startBenchDate
        startDate = rq.get_previous_trading_date(
            rq.get_next_trading_date(startDate))

        Data = calendarArbitrage.dataLoad.data_load(contractList,
                                                    start_date=startDate,
                                                    end_date=endDate)

        dataDf = pd.DataFrame()
        for contract_id in contractList:
            dataClose = Data[contract_id]['close']
            dataDf = pd.concat([dataDf, dataClose], axis=1)
        dataDf.columns = contractList