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)}')
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)}')
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
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
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)}')
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
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
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
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
# 参数 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