def get_industry_factor(self): # 读取行业信息数据 industry = data.read_data(['Industry'], ['Industry']) self.industry = industry.ix['Industry'] # 对第一个拥有所有行业的日期取虚拟变量,以建立储存数据的panel industry_num = self.industry.apply(lambda x: x.unique().size, axis=1) # 注意所有行业28个,加上nan有29个 first_valid_index = industry_num[industry_num == 29].index[0] temp_dum = pd.get_dummies(self.industry.ix[first_valid_index], prefix='Industry') industry_dummies = pd.Panel(data=None, major_axis=temp_dum.index, minor_axis=temp_dum.columns) # 开始循环 for time, ind_data in self.industry.iterrows(): industry_dummies[time] = pd.get_dummies(ind_data, prefix='Industry') # 转置 industry_dummies = industry_dummies.transpose(2, 0, 1) # 将行业因子暴露与风格因子暴露的索引对其 industry_dummies = data.align_index(self.bb_data.factor_expo.ix[0], industry_dummies) # 将nan填成0,主要是有些行业在某一时间点,没有一只股票属于它,这会造成在这个行业上的暴露是nan # 因此需要把这个行业的暴露填成0,而uninv的nan同样会被填上,但会在之后的filter中再次变成nan industry_dummies = industry_dummies.fillna(0) # 将行业因子暴露与风格因子暴露衔接在一起 self.bb_data.factor_expo = pd.concat( [self.bb_data.factor_expo, industry_dummies])
def reset_bkt_benchmark(self, new_bkt_benchmark_data): self.bkt_data.benchmark_price = data.read_data(new_bkt_benchmark_data, ['ClosePrice_adj']) # 将benchmark price数据期调整为回测期 self.bkt_data.benchmark_price = data.align_index(self.tar_pct_position.holding_matrix, self.bkt_data.benchmark_price, axis='major') # 重置回测数据 self.reset_bkt_data()
def __init__(self, bkt_position, *, initial_money = 100000000, trade_ratio = 0.95, buy_cost = 1.5/1000, sell_cost = 1.5/1000, bkt_start = 'default', bkt_end = 'default', risk_free_rate = 0.0, bkt_stock_data = 'default', bkt_benchmark_data = 'default', infinitesimal=1e-4): """ Initialize backtest object. foo """ # 初始化传入的持仓类,是要回测的策略构造出的持仓矩阵对象,是回测的目标持仓,注意此日期为调仓日 self.bkt_position = bkt_position # 只支持正杠杆,即买空卖空的持仓比例之和必须大于0 greater_than_zero_condition = self.bkt_position.holding_matrix.sum(1) > infinitesimal # 确保这些持仓比例和为0的股票并非全是0,以免将全是0的持仓判断为非法持仓 # all_zeros_condition = self.bkt_position.holding_matrix.ix[~greater_than_zero_condition].prod(1) == 0.0 all_zeros_condition = (self.bkt_position.holding_matrix == 0.0).all(1) assert np.logical_or(greater_than_zero_condition, all_zeros_condition).all(), \ 'Sum of the holding matrix are no greater than 0 for at least 1 timestamp, this is not supported by this ' \ 'backtest system. Note that the timestamp whose holdings are all 0 has been excluded from this error.\n' # 初始化回测用到的股价数据类 self.bkt_data = backtest_data() # 初始化股价数据,包括收盘开盘价等 if bkt_stock_data == 'default': self.bkt_data.stock_price = data.read_data(['ClosePrice_adj','OpenPrice_adj'], ['ClosePrice_adj','OpenPrice_adj']) else: self.bkt_data.stock_price = data.read_data(bkt_stock_data) # 初始化基准价格数据,默认设为中证500,只需要收盘数据, 开盘数据只是为了初始化序列的第一个值 # 注意, 因为做空期货实际上做空的是指数的全收益序列, 因此我们要计算基准的全收益价格序列 # 基准指数的全收益价格序列没有开盘价, 因此只能全部用收盘价替代 if bkt_benchmark_data == 'default': self.bkt_data.benchmark_price = data.read_data(['ClosePrice_adj_zz500'], ['ClosePrice_adj']) else: self.bkt_data.benchmark_price = data.read_data([bkt_benchmark_data], [bkt_benchmark_data]) # 读取股票上市退市停牌数据,并生成标记股票是否可交易的矩阵 self.bkt_data.generate_if_tradable() # 根据传入的持仓类,校准回测股价和基准股价的数据,将股票代码对齐 self.bkt_data.stock_price = data.align_index(self.bkt_position.holding_matrix, self.bkt_data.stock_price, axis = 'minor') self.bkt_data.if_tradable = data.align_index(self.bkt_position.holding_matrix, self.bkt_data.if_tradable, axis = 'minor') # 检测股票代码是否都包含在回测数据中,当有一只股票的某一个回测数据全是nan,且对这只股票有持仓时, # 则认为有股票代码没有全部包含在回测数据中 stock_in_condition = np.logical_and(self.bkt_data.stock_price.isnull().all(1).any(1), self.bkt_position.holding_matrix.sum()>0) assert not stock_in_condition.any(), \ 'Some stocks in the input holding matrix are NOT included in the backtest database, '\ 'please check it carefully!\n' # 检测回测数据是否覆盖了回测时间段 # 检测起始时间 if bkt_start == 'default': assert self.bkt_data.stock_price.major_axis[0]<=self.bkt_position.holding_matrix.index[0], \ 'The default start time of backtest is earlier than the start time in backtest database, '\ 'please try to set a later start time which must be a trading day\n' else: assert self.bkt_data.stock_price.major_axis[0]<=bkt_start, \ 'The input start time of backtest is earlier than the start time in backteset database, '\ 'please try to set a later start time which must be a trading day, or try to set it as default\n' # 检测结束时间 if bkt_end == 'default': # 如果回测数据中的最后一天直接在最后一个调仓日前,则直接报错 assert self.bkt_data.stock_price.major_axis[-1]>self.bkt_position.holding_matrix.index[-1], \ 'The default end time of backtest is later than the end time in backtest database, '\ 'please try to set an earlier end time which must be a trading day\n' # 回测数据中的最后一天在最后一个调仓日后,现在判断是否之后有60个交易日可取 last_holding_loc = self.bkt_data.stock_price.major_axis.get_loc(self.bkt_position.holding_matrix.index[-1]) total_size = self.bkt_data.stock_price.major_axis.size assert total_size>=last_holding_loc+1+60, \ 'The default end time of backtest is later than the end time in backtest database, '\ 'please try to set an earlier end time which must be a trading day\n' else: assert self.bkt_data.stock_price.major_axis[-1]>bkt_end, \ 'The input end time of backtest is later than the end time in backtest database, '\ 'please try to set an earlier end time which must be a trading day, or try to set it as default\n' # 设置回测的起止时间,这里要注意默认的时间可能超过回测数据的范围 # 起始时间:默认为第一个调仓日,如有输入数据,则为输入数据和默认时间的较晚日期 default_start = self.bkt_data.stock_price.major_axis[self.bkt_data.stock_price.major_axis.get_loc(self.bkt_position.holding_matrix.index[0])] if bkt_start == 'default': self.bkt_start = default_start else: self.bkt_start = max(default_start, bkt_start) # 停止时间:默认为最后一个调仓日后的21个交易日,如有输入数据,则以输入数据为准 if bkt_end == 'default': default_end = self.bkt_data.stock_price.major_axis[self.bkt_data.stock_price.major_axis.get_loc(self.bkt_position.holding_matrix.index[-1])+21] self.bkt_end = default_end else: self.bkt_end = bkt_end # 对回测的其他数据进行初始化 self.initial_money = initial_money self.trade_ratio = trade_ratio self.buy_cost = buy_cost self.sell_cost = sell_cost self.risk_free_rate = risk_free_rate # 以回测期(而不是回测数据期或调仓期)为时间索引的持仓量矩阵,注意vol的持仓单位为手,pct的持仓单位为百分比 start_loc = self.bkt_data.stock_price.major_axis.get_loc(self.bkt_start) end_loc = self.bkt_data.stock_price.major_axis.get_loc(self.bkt_end) backtest_period_holding_matrix = self.bkt_data.stock_price.ix[0,start_loc:end_loc+1,:] self.tar_pct_position = position(backtest_period_holding_matrix) # 初始化持仓目标矩阵 self.tar_pct_position.holding_matrix = self.bkt_position.holding_matrix.reindex( index = self.tar_pct_position.holding_matrix.index, method = 'ffill') # 初始化实际持仓矩阵 self.real_vol_position = position(backtest_period_holding_matrix) # 初始化实际持仓的百分比 self.real_pct_position = position(backtest_period_holding_matrix) # 初始化目标持仓矩阵,单位为手,这个持仓量矩阵主要作为参考 self.tar_vol_position = position(backtest_period_holding_matrix) # 将回测数据期也调整为回测期 self.bkt_data.stock_price = data.align_index(self.tar_pct_position.holding_matrix, self.bkt_data.stock_price, axis = 'major') self.bkt_data.benchmark_price = data.align_index(self.tar_pct_position.holding_matrix, self.bkt_data.benchmark_price, axis = 'major') self.bkt_data.if_tradable = data.align_index(self.tar_pct_position.holding_matrix, self.bkt_data.if_tradable, axis = 'major') # 初始化回测要用到的现金数据: self.cash = pd.Series(np.zeros(self.real_vol_position.holding_matrix.shape[0]), index = self.real_vol_position.holding_matrix.index) self.cash.ix[0] = self.initial_money*self.trade_ratio # 初始化回测得到的账户价值数据: self.account_value = [] # 初始化计算业绩指标及作图用到的benchmark价值数据 self.benchmark_value = self.bkt_data.benchmark_price.ix['ClosePrice_adj', :, 0] # 初始化其他信息序列,包括换手率,持有的股票数等 self.info_series = pd.DataFrame(0, index=self.cash.index, columns=['holding_value', 'sell_value', 'buy_value', 'trading_value', 'turnover_ratio', 'cost_value', 'holding_num']) # 暂时用一个警告的string初始化performance对象,防止提前调用此对象出错 self.bkt_performance = 'The performance object of this backtest object has NOT been initialized, '\ 'please try to call this attribute after call backtest.get_performance()\n' # 初始化结束时,目标和实际持仓矩阵、回测数据都是一样的时间股票索引(即策略持仓股票为股票索引,回测期间为时间索引), # 传入的bkt_position股票索引是一样的,但是时间索引为调仓日的时间 # 控制回测对象是否需要输出提示用户的警告 self.enable_warning = True print('The backtest system has been successfully initialized!\n')
def read_original_data(self): # 先读取市值 if self.bb_data.stock_price.empty: self.bb_data.stock_price = data.read_data(['FreeMarketValue'], ['FreeMarketValue']) elif 'FreeMarketValue' not in self.bb_data.stock_price.items: mv = data.read_data(['FreeMarketValue'], ['FreeMarketValue']) self.bb_data.stock_price['FreeMarketValue'] = mv.ix[ 'FreeMarketValue'] # 初始化无风险利率序列 if os.path.isfile('const_data.csv'): self.bb_data.const_data = pd.read_csv('const_data.csv', index_col=0, parse_dates=True, encoding='GB18030') if 'risk_free' not in self.bb_data.const_data.columns: self.bb_data.const_data['risk_free'] = 0 else: print('risk free rate successfully loaded') else: self.bb_data.const_data = pd.DataFrame( 0, index=self.bb_data.stock_price.major_axis, columns=['risk_free']) # 读取价格数据 if 'ClosePrice_adj' not in self.bb_data.stock_price.items: temp_closeprice = data.read_data(['ClosePrice_adj'], ['ClosePrice_adj']) self.bb_data.stock_price['ClosePrice_adj'] = temp_closeprice.ix[ 'ClosePrice_adj'] # 计算每只股票的日对数收益率 if 'daily_return' not in self.bb_data.stock_price.items: self.bb_data.stock_price['daily_return'] = np.log( self.bb_data.stock_price.ix['ClosePrice_adj'].div( self.bb_data.stock_price.ix['ClosePrice_adj'].shift(1))) # 计算每只股票的日超额收益 if 'daily_excess_return' not in self.bb_data.stock_price.items: self.bb_data.stock_price[ 'daily_excess_return'] = self.bb_data.stock_price.ix[ 'daily_return'].sub( self.bb_data.const_data.ix[:, 'risk_free'], axis=0) # 读取交易量数据 if 'Volume' not in self.bb_data.stock_price.items: volume = data.read_data(['Volume'], ['Volume']) self.bb_data.stock_price['Volume'] = volume.ix['Volume'] # 读取流通股数数据 if 'FreeShares' not in self.bb_data.stock_price.items: shares = data.read_data(['FreeShares'], ['FreeShares']) self.bb_data.stock_price['FreeShares'] = shares.ix['FreeShares'] # 读取pb if self.bb_data.raw_data.empty: self.bb_data.raw_data = data.read_data(['PB'], ['PB']) # 一切的数据标签都以stock_price为准 self.bb_data.raw_data = data.align_index( self.bb_data.stock_price.ix[0], self.bb_data.raw_data, axis='both') elif 'PB' not in self.bb_data.raw_data.items: pb = data.read_data(['PB'], ['PB']) self.bb_data.raw_data['PB'] = pb.ix['PB'] # 读取ni_fy1, ni_fy2 if 'NetIncome_fy1' not in self.bb_data.raw_data.items: NetIncome_fy1 = data.read_data(['NetIncome_fy1'], ['NetIncome_fy1']) self.bb_data.raw_data['NetIncome_fy1'] = NetIncome_fy1.ix[ 'NetIncome_fy1'] if 'NetIncome_fy2' not in self.bb_data.raw_data.items: NetIncome_fy2 = data.read_data(['NetIncome_fy2'], ['NetIncome_fy2']) self.bb_data.raw_data['NetIncome_fy2'] = NetIncome_fy2.ix[ 'NetIncome_fy2'] # 读取cash_earnings_ttm,现金净流入的ttm if 'CashEarnings_ttm' not in self.bb_data.raw_data.items: CashEarnings_ttm = data.read_data(['CashEarnings_ttm'], ['CashEarnings_ttm']) self.bb_data.raw_data['CashEarnings_ttm'] = CashEarnings_ttm.ix[ 'CashEarnings_ttm'] # 读取pe_ttm if 'PE_ttm' not in self.bb_data.raw_data.items: pe_ttm = data.read_data(['PE_ttm'], ['PE_ttm']) self.bb_data.raw_data['PE_ttm'] = pe_ttm.ix['PE_ttm'] # 读取净利润net income ttm if 'NetIncome_ttm' not in self.bb_data.raw_data.items: ni_ttm = data.read_data(['NetIncome_ttm'], ['NetIncome_ttm']) self.bb_data.raw_data['NetIncome_ttm'] = ni_ttm.ix['NetIncome_ttm'] # 读取ni ttm的2年增长率,用ni增长率代替eps增长率,因为ni增长率的数据更全 if 'NetIncome_ttm_growth_8q' not in self.bb_data.raw_data.items: ni_ttm_growth_8q = data.read_data(['NetIncome_ttm_growth_8q'], ['NetIncome_ttm_growth_8q']) self.bb_data.raw_data[ 'NetIncome_ttm_growth_8q'] = ni_ttm_growth_8q.ix[ 'NetIncome_ttm_growth_8q'] # 读取revenue ttm的2年增长率 if 'Revenue_ttm_growth_8q' not in self.bb_data.raw_data.items: Revenue_ttm_growth_8q = data.read_data(['Revenue_ttm_growth_8q'], ['Revenue_ttm_growth_8q']) self.bb_data.raw_data[ 'Revenue_ttm_growth_8q'] = Revenue_ttm_growth_8q.ix[ 'Revenue_ttm_growth_8q'] # 读取总资产和总负债,用资产负债率代替复杂的leverage因子 if 'TotalAssets' not in self.bb_data.raw_data.items: TotalAssets = data.read_data(['TotalAssets'], ['TotalAssets']) self.bb_data.raw_data['TotalAssets'] = TotalAssets.ix[ 'TotalAssets'] if 'TotalLiability' not in self.bb_data.raw_data.items: TotalLiability = data.read_data(['TotalLiability'], ['TotalLiability']) self.bb_data.raw_data['TotalLiability'] = TotalLiability.ix[ 'TotalLiability'] # 生成可交易及可投资数据 self.bb_data.generate_if_tradable() self.bb_data.handle_stock_pool() # 读取完所有数据后,过滤数据 # 注意:在之后的因子计算中,中间计算出的因子之间相互依赖的,都要再次过滤,如一个需要从另一个中算出 # 或者回归,正交化,而且凡是由多个因子加权得到的因子,都属于这一类 # 以及因子的计算过程中用到非此时间点的原始数据时,如在a时刻的因子值要用到在a-t时刻的原始数据 # 需要算暴露的时候,一定要过滤uninv的数据,因为暴露是在股票池中计算的,即正交化的时候也需要过滤uninv # 在barra base中,事实上只有beta需要不依赖于股票池的全局计算,在beta因子计算过后,即可过滤uninv # 但同时注意,一旦过滤uninv,数据就不能再作为一般的因子值储存了 self.bb_data.discard_untradable_data()
def __init__(self, bkt_position, *, initial_money=100000000, buy_cost=1.5/1000, sell_cost=1.5/1000, bkt_start=None, bkt_end=None, risk_free_rate=None, bkt_stock_data=None, bkt_benchmark_data=None, infinitesimal=1e-4): """ Initialize backtest object. foo """ # 初始化传入的持仓类,是要回测的策略构造出的持仓矩阵对象,是回测的目标持仓,注意此日期为调仓日 self.bkt_position = bkt_position # 只支持正杠杆,即买空卖空的持仓比例之和必须大于0 greater_than_zero_condition = self.bkt_position.holding_matrix.sum(1) > infinitesimal # 确保这些持仓比例和为0的股票并非全是0,以免将全是0的持仓判断为非法持仓 # all_zeros_condition = self.bkt_position.holding_matrix.ix[~greater_than_zero_condition].prod(1) == 0.0 all_zeros_condition = (self.bkt_position.holding_matrix == 0.0).all(1) assert np.logical_or(greater_than_zero_condition, all_zeros_condition).all(), \ 'Sum of the holding matrix are no greater than 0 for at least 1 timestamp, this is not supported by this ' \ 'backtest system. Note that the timestamp whose holdings are all 0 has been excluded from this error.\n' # 将持仓进行归一化 self.bkt_position.to_percentage() # 初始化回测用到的股价数据类 self.bkt_data = backtest_data() # 初始化股价数据,包括收盘价, vwap(交易量加权平均价)等 if bkt_stock_data is None: self.bkt_data.stock_price = data.read_data(['ClosePrice_adj','vwap_adj'], item_name=['ClosePrice_adj', 'vwap_adj']) else: self.bkt_data.stock_price = data.read_data(bkt_stock_data, item_name=['ClosePrice_adj', 'vwap_adj']) # self.bkt_data.stock_price['vwap_adj'] = self.bkt_data.stock_price['vwap_adj'].shift(1) # 初始化基准价格数据,默认设为中证500,只需要收盘数据, 开盘数据只是为了初始化序列的第一个值 # 注意, 因为做空期货实际上做空的是指数的全收益序列, 因此我们要计算基准的全收益价格序列 # 基准指数的全收益价格序列没有开盘价, 因此只能全部用收盘价替代 if bkt_benchmark_data is None: self.bkt_data.benchmark_price = data.read_data(['ClosePrice_adj_zz500'], item_name=['ClosePrice_adj']) else: self.bkt_data.benchmark_price = data.read_data([bkt_benchmark_data], item_name=['ClosePrice_adj']) # 读取股票上市退市停牌数据,并生成标记股票是否可交易的矩阵 self.bkt_data.generate_if_tradable() # 生成标记股票是否涨跌停, 是否可买入卖出的矩阵 self.bkt_data.generate_if_buyable_sellable() # 根据传入的持仓类,校准回测股价和基准股价的数据,将股票代码对齐 self.bkt_data.stock_price = data.align_index(self.bkt_position.holding_matrix, self.bkt_data.stock_price, axis = 'minor') self.bkt_data.if_tradable = data.align_index(self.bkt_position.holding_matrix, self.bkt_data.if_tradable, axis = 'minor') # 检测股票代码是否都包含在回测数据中,当有一只股票的某一个回测数据全是nan,且对这只股票有持仓时, # 则认为有股票代码没有全部包含在回测数据中 stock_in_condition = np.logical_and(self.bkt_data.stock_price.isnull().all(1).any(1), self.bkt_position.holding_matrix.sum()>0) assert not stock_in_condition.any(), \ 'Some stocks in the input holding matrix are NOT included in the backtest database, '\ 'please check it carefully!\n' # 读取无风险利率数据 if isinstance(risk_free_rate, pd.Series): self.bkt_data.const_data = pd.DataFrame(risk_free_rate.values, index=risk_free_rate.index, columns=['risk_free_rate']) else: self.bkt_data.const_data = data.read_data('const_data') if 'risk_free' not in self.bkt_data.const_data.columns: self.bkt_data.const_data['risk_free_rate'] = 0.0 else: self.bkt_data.const_data = pd.DataFrame(0.0, index=self.bkt_data.stock_price.major_axis, columns=['risk_free_rate']) # 检测回测数据是否覆盖了回测时间段 # 检测起始时间 if bkt_start is None: assert self.bkt_data.stock_price.major_axis[0]<=self.bkt_position.holding_matrix.index[0], \ 'The default start time of backtest is earlier than the start time in backtest database, '\ 'please try to set a later start time which must be a trading day\n' else: assert self.bkt_data.stock_price.major_axis[0]<=bkt_start, \ 'The input start time of backtest is earlier than the start time in backteset database, '\ 'please try to set a later start time which must be a trading day, or try to set it as default\n' # 检测结束时间 if bkt_end is None: # 如果回测数据中的最后一天直接在最后一个调仓日前,则直接报错 assert self.bkt_data.stock_price.major_axis[-1]>self.bkt_position.holding_matrix.index[-1], \ 'The default end time of backtest is later than the end time in backtest database, '\ 'please try to set an earlier end time which must be a trading day\n' # 回测数据中的最后一天在最后一个调仓日后,现在判断是否之后有21个交易日可取 last_holding_loc = self.bkt_data.stock_price.major_axis.get_loc(self.bkt_position.holding_matrix.index[-1]) total_size = self.bkt_data.stock_price.major_axis.size assert total_size>=last_holding_loc+1+21, \ 'The default end time of backtest is later than the end time in backtest database, '\ 'please try to set an earlier end time which must be a trading day\n' else: assert self.bkt_data.stock_price.major_axis[-1]>bkt_end, \ 'The input end time of backtest is later than the end time in backtest database, '\ 'please try to set an earlier end time which must be a trading day, or try to set it as default\n' # 设置回测的起止时间,这里要注意默认的时间可能超过回测数据的范围 # 起始时间:默认为第一个调仓日,如有输入数据,则为输入数据和默认时间的较晚日期 default_start = self.bkt_data.stock_price.major_axis[self.bkt_data.stock_price.major_axis. get_loc(self.bkt_position.holding_matrix.index[0])] if bkt_start is None: self.bkt_start = default_start else: self.bkt_start = max(default_start, bkt_start) # 停止时间:默认为最后一个调仓日后的21个交易日,如有输入数据,则以输入数据为准 if bkt_end is None: default_end = self.bkt_data.stock_price.major_axis[self.bkt_data.stock_price.major_axis. get_loc(self.bkt_position.holding_matrix.index[-1])+21] self.bkt_end = default_end else: self.bkt_end = bkt_end # 对回测的其他数据进行初始化 self.initial_money = initial_money self.buy_cost = buy_cost self.sell_cost = sell_cost # 以回测期(而不是回测数据期或调仓期)为时间索引的持仓量矩阵,注意vol的持仓单位为手,pct的持仓单位为百分比 start_loc = self.bkt_data.stock_price.major_axis.get_loc(self.bkt_start) end_loc = self.bkt_data.stock_price.major_axis.get_loc(self.bkt_end) backtest_period_holding_matrix = self.bkt_data.stock_price.ix[0,start_loc:end_loc+1,:] self.tar_pct_position = position(backtest_period_holding_matrix) # 初始化持仓目标矩阵 self.tar_pct_position.holding_matrix = self.bkt_position.holding_matrix.reindex( index=self.tar_pct_position.holding_matrix.index, method='ffill') self.tar_pct_position.cash = self.bkt_position.cash.reindex( index=self.tar_pct_position.cash.index, method='ffill') # 初始化实际持仓矩阵 self.real_vol_position = position(backtest_period_holding_matrix) # 初始化实际持仓的百分比 self.real_pct_position = position(backtest_period_holding_matrix) # 初始化目标持仓矩阵,单位为手,这个持仓量矩阵主要作为参考 self.tar_vol_position = position(backtest_period_holding_matrix) # 将回测数据期也调整为回测期 self.bkt_data.stock_price = data.align_index(self.tar_pct_position.holding_matrix, self.bkt_data.stock_price, axis='major') self.bkt_data.benchmark_price = data.align_index(self.tar_pct_position.holding_matrix, self.bkt_data.benchmark_price, axis='major') self.bkt_data.if_tradable = data.align_index(self.tar_pct_position.holding_matrix, self.bkt_data.if_tradable, axis='major') self.bkt_data.const_data = self.bkt_data.const_data.reindex(index=self.tar_pct_position.holding_matrix.index) # 初始化回测要用到的现金数据: # 总的现金资产, 总现金资产中分为不能用来购买股票的, 和可以购买股票的 # 可以用来购买股票的现金资产. 在回测期间, 可能不为0 # 第一: 持仓期间非调仓日可能有股票的卖出, 如退市, 但是这个时候并不调仓, 因此不买入股票, 而是持有现金 # 第二: 买卖股票可能由于手数限制, 导致会有残余现金剩下(暂时没有设置手续限制) self.real_vol_position.cash.iloc[0] = self.initial_money * 1 # 初始化回测得到的账户价值数据: self.account_value = pd.Series(0.0, index=self.tar_pct_position.holding_matrix.index) # 初始化计算业绩指标及作图用到的benchmark价值数据 self.benchmark_value = self.bkt_data.benchmark_price.ix['ClosePrice_adj', :, 0] # 初始化其他信息序列,包括换手率,持有的股票数等 self.info_series = pd.DataFrame(0, index=self.real_vol_position.cash.index, columns=['holding_value', 'sell_value', 'buy_value', 'trading_value', 'turnover_ratio', 'cost_value', 'holding_num', 'holding_sus', 'target_sus', 'buy_cap', 'sell_bottom', 'holding_diff', 'cash_diff']) # 初始化performance对象 self.bkt_performance = None # 初始化结束时,目标和实际持仓矩阵、回测数据都是一样的时间股票索引(即策略持仓股票为股票索引,回测期间为时间索引), # 传入的bkt_position股票索引是一样的,但是时间索引为调仓日的时间 # 控制回测对象是否需要输出提示用户的警告 self.show_warning = True # 标记是否执行本次换仓 self.if_exec_this_trading = True print('The backtest system has been successfully initialized!\n')