def forcastStkReturn(self): ''' 给出下一期股票收益的预测 :return:dataframe,纵轴:股票,横轴:e_ret,各因子暴露收益 ''' nextDate = fapi.TradingTimePoints( asset_code=None, starttime=self.timespan[1] + timedelta(days=1), endtime=self.timespan[1] + timedelta(days=10), freq=self.freq).index[0].to_pydatetime() FactorMatDict = { x.descriptorRefName(): get_feature(descriptor=x, starttime=nextDate, endtime=nextDate, freq=self.freq, check=False) for x in self.factors } matchDs = xr.Dataset(FactorMatDict) CalibratedFeats = { fename: matchDs[fename].values.flatten() for fename in matchDs } stocks = matchDs.indexes['StockCode'] df_factorLoading = pd.DataFrame(index=stocks, data=CalibratedFeats) expFreturnLi = [ self.expFreturn[f.descriptorRefName()] for f in self.factors ] df_ForcastReturns = df_factorLoading.mul(expFreturnLi, axis=1) df_ForcastReturns['e_ret'] = df_ForcastReturns.sum(axis=1) return df_ForcastReturns
def __init__(self, asset_code: str, factors: List[Union[Descriptor]], starttime: datetime, endtime: datetime, freq: str = 'd', forcast_period: int = 1): ''' :param stockcode: 待预测标的 :param factors: 特征列表 :param starttime: 样本起始时间 :param endtime: 样本结束时间 :param freq: 学习频率 'm'(分)/'d'(日)/'w'(周)/'M'(月) :param forcast_period: 预测期 ''' #todo 如何预测同标的的期货合约(要考虑合约换月)? # (丢给feature算法/get_return特殊处理,此处仅考虑可以由stockcode顺利获取特征及收益) ReturnSeries = fapi.getReturn(asset_code=asset_code, starttime=starttime, endtime=endtime, forcast_period=forcast_period, freq=freq) for factor in factors: factor.freq = freq feSeries = get_feature(factor, starttime, endtime, asset_code, True)
def forcastStkReturn(self, check=True) -> pd.DataFrame: ''' 给出下一期股票收益的预测 :param check: bool 是否检查更新特征数据 :return:dataframe,纵轴:股票,横轴:e_ret,各因子暴露收益 ''' nextDate = fapi.TradingTimePoints( asset_code=None, starttime=self.timespan[1] + timedelta(days=1), endtime=self.timespan[1] + timedelta(days=10), freq=self.freq).index[0].to_pydatetime() FactorMatDict = { x.descriptorRefName(): get_feature(descriptor=x, starttime=nextDate, endtime=nextDate, freq=self.freq, checkLevel=2 if check else 0) for x in self.factors } matchDs = xr.Dataset(FactorMatDict) CalibratedFeats = { fename: matchDs[fename].values.flatten() for fename in matchDs } stocks = matchDs.indexes['StockCode'] df_factorLoading = pd.DataFrame(index=stocks, data=CalibratedFeats) expFreturnLi = [ self.expFreturn[f.descriptorRefName()] for f in self.factors ] df_ForcastReturns: pd.DataFrame = df_factorLoading.mul(expFreturnLi, axis=1) df_ForcastReturns['e_ret'] = df_ForcastReturns.sum(axis=1) cashdict = {i: 0 for i in list(df_ForcastReturns.columns)} cash = pd.DataFrame(cashdict, index=['cash']) aa = df_ForcastReturns.append(cash) return aa
def __getfundamental(self, timespan): ''' 计算并返回指定时间段内的交易日、描述子数据、收益数据以及横截面回归结果. :param timespan: 指定的时间段 :return: (out_dateIndex,out_endogs,out_exogs,out_dateIndex) out_dateIndex:时间段内的交易时点序列 out_endogs:时间段内的股票收益数据 out_exogs:时间段内的描述子数据 out_rst:时间段内的横截面回归结果 ''' ReturnMat = fapi.getReturn(asset_code=None, starttime=timespan[0], endtime=timespan[1], forcast_period=self.forcast_period, freq=self.freq, asset_type='stock') #取因子矩阵 FactorMatDict = { 'feat_' + x.descriptorRefName(): get_feature(descriptor=x, starttime=timespan[0], endtime=timespan[1], freq=self.freq, check=False) for x in self.factors } ControlMatDict = { 'ctrl_' + x.descriptorRefName(): get_feature(descriptor=x, starttime=timespan[0], endtime=timespan[1], freq=self.freq, check=False) for x in self.controls } #FMB回归 matchDict = {'return': ReturnMat} matchDict.update(FactorMatDict) matchDict.update(ControlMatDict) matchDs = xr.Dataset(matchDict) def ProdTrue(*args): for obj in args: if (args is True): continue else: return False return True CalibratedCtrls = [ matchDs[fe_name].values for fe_name in matchDs if fe_name[0:4] == 'ctrl' ] CalibratedFeats = [ matchDs[fe_name].values for fe_name in matchDs if fe_name[0:4] == 'feat' ] if (CalibratedCtrls.__len__() > 0): ArrayProdTrue = np.frompyfunc(ProdTrue, CalibratedCtrls.__len__(), 1) AssembledControlMat = ArrayProdTrue( *CalibratedCtrls).astype('bool') MaskedReturn = np.ma.MaskedArray(matchDs['return'].values, mask=~AssembledControlMat, fill_value=np.nan) else: MaskedReturn = matchDs['return'].values l = MaskedReturn.shape[0] out_rst = [] exogs = np.stack(CalibratedFeats) noneCount = 0 for i in tqdm(range(l), desc='正在截面回归...'): try: out_rst.append( sm.OLS(endog=MaskedReturn[i], exog=exogs[:, i, :].T, missing='drop').fit()) except: out_rst.append(None) noneCount += 1 if (noneCount == l): raise Exception("所选时间区间内无有效回归样本,请检查基础数据!") out_dateIndex = matchDs['return'].indexes['Time'] return (out_dateIndex, out_rst)
''' 择时模型: 根据选择的资产、特征,在样本时间区间内训练择时模型,并进行样本外回测. 输入:资产代码、特征对象列表、样本时间区间; 输出:一个可给出回测报告(输入时间区间即可)的对象。 对其它api的假定: get_feature(descriptor:Descriptor,starttime:datetime, endtime:datetime,stock_name:list=None,check:bool=True) descriptor的频率交由get_feature来指定,并在对象初始化中被剔除。 todo:现在回头补写一些基础数据和因子特征算法,用multifactor模型研究一下因子收益的持续性; 加入残差动量因子:将因子横街面回归残差 ''' from typing import List, Union from datetime import datetime from core.features.Descriptor import Descriptor from core.fundamentals.getfundamentals import fundamentalApi as fapi from core.features.getfeature import get_feature class TSmodel: def __init__(self, asset_code: str, factors: List[Union[Descriptor]], starttime: datetime, endtime: datetime, freq: str = 'd', forcast_period: int = 1): ''' :param stockcode: 待预测标的