def update_return_data_300(ds, **kwargs): ref_date = kwargs['next_execution_date'] if not isBizDay('china.sse', ref_date): logger.info("{0} is not a business day".format(ref_date)) return 0 start_date = advanceDateByCalendar('china.sse', ref_date, '-30b') for date in bizDatesList('china.sse', start_date, ref_date): date = date.strftime('%Y-%m-%d') conn1 = create_ms_engine('PortfolioManagements300') df = fetch_date('StockReturns', date, conn1) conn2 = create_my_engine() delete_data('return_300', date, conn2) insert_data('return_300', df, conn2) conn3 = create_my_engine2() delete_data('return_300', date, conn3) insert_data('return_300', df, conn3) return 0
def setUp(self): self.engine = SqlEngine(DATA_ENGINE_URI) dates_list = bizDatesList('china.sse', '2010-10-01', '2018-04-27') self.ref_date = random.choice(dates_list).strftime('%Y-%m-%d') alpha_logger.info("Test date: {0}".format(self.ref_date))
def createPerformanceTearSheet(prices=None, returns=None, benchmark=None, benchmarkReturns=None, plot=True): if prices is not None and not isinstance(prices, pd.Series): raise TypeError("prices series should be a pandas time series.") elif returns is not None and prices is not None: raise ValueError("prices series and returns series can't be both set.") if benchmark is not None and not (isinstance(benchmark, pd.Series) or isinstance(benchmark, str)): raise TypeError("benchmark series should be a pandas time series or a string ticker.") if returns is None: returns = np.log(prices / prices.shift(1)) returns.fillna(0, inplace=True) returns = returns[~np.isinf(returns)] if benchmark is not None and isinstance(benchmark, str) and benchmarkReturns is None: startDate = advanceDateByCalendar("China.SSE", prices.index[0], '-1b', BizDayConventions.Preceding) benchmarkPrices = get_benchmark_data(benchmark, start_date=startDate.strftime('%Y-%m-%d'), end_data=returns.index[-1].strftime("%Y-%m-%d")) # do the linear interpolation on the target time line date_index = prices.index new_index = benchmarkPrices.index.union(date_index) benchmarkPrices = benchmarkPrices.reindex(new_index) benchmarkPrices = benchmarkPrices.interpolate().ix[date_index].dropna() benchmarkReturns = np.log(benchmarkPrices['closePrice'] / benchmarkPrices['closePrice'].shift(1)) benchmarkReturns.name = benchmark benchmarkReturns.fillna(0, inplace=True) benchmarkReturns.index = pd.to_datetime(benchmarkReturns.index.date) elif benchmark is not None and isinstance(benchmark, pd.Series): benchmarkReturns = np.log(benchmark / benchmark.shift(1)) try: benchmarkReturns.name = benchmark.name except AttributeError: benchmarkReturns.name = "benchmark" benchmarkReturns.dropna(inplace=True) benchmarkReturns.index = pd.to_datetime(benchmarkReturns.index.date) aggregateDaily = aggregateReturns(returns) drawDownDaily = drawDown(aggregateDaily) # perf metric annualRet = annualReturn(aggregateDaily) annualVol = annualVolatility(aggregateDaily) sortino = sortinoRatio(aggregateDaily) sharp = sharpRatio(aggregateDaily) maxDrawDown = np.min(drawDownDaily['draw_down']) winningDays = np.sum(aggregateDaily > 0.) lossingDays = np.sum(aggregateDaily < 0.) perf_metric = pd.DataFrame([annualRet, annualVol, sortino, sharp, maxDrawDown, winningDays, lossingDays], index=['annual_return', 'annual_volatiltiy', 'sortino_ratio', 'sharp_ratio', 'max_draw_down', 'winning_days', 'lossing_days'], columns=['metrics']) perf_df = pd.DataFrame(index=aggregateDaily.index) perf_df['daily_return'] = aggregateDaily perf_df['daily_cum_return'] = np.exp(aggregateDaily.cumsum()) - 1.0 perf_df['daily_draw_down'] = drawDownDaily['draw_down'] if benchmarkReturns is not None: perf_df['benchmark_return'] = benchmarkReturns perf_df['benchmark_cum_return'] = benchmarkReturns.cumsum() perf_df.dropna(inplace=True) perf_df['benchmark_cum_return'] = np.exp(perf_df['benchmark_cum_return'] - perf_df['benchmark_cum_return'][0]) - 1.0 perf_df['access_return'] = aggregateDaily - benchmarkReturns perf_df['access_cum_return'] = (1.0 + perf_df['daily_cum_return']) \ / (1.0 + perf_df['benchmark_cum_return']) - 1.0 perf_df.fillna(0.0, inplace=True) accessDrawDownDaily = drawDown(perf_df['access_return']) else: accessDrawDownDaily = None if 'benchmark_cum_return' in perf_df: benchmarkCumReturns = perf_df['benchmark_cum_return'] benchmarkCumReturns.name = benchmarkReturns.name accessCumReturns = perf_df['access_cum_return'] accessReturns = perf_df['access_return'] index = perf_df.index length1 = len(bizDatesList('China.SSE', index[0], index[-1])) length2 = len(perf_df) factor = length1 / float(length2) rb = RollingBeta(perf_df['daily_return'], perf_df['benchmark_return'], [1, 3, 6], factor=factor) rs = RollingSharp(perf_df['daily_return'], [1, 3, 6], factor=factor) else: benchmarkCumReturns = None accessReturns = None accessCumReturns = None if len(perf_df['daily_return']) > APPROX_BDAYS_PER_MONTH and benchmarkCumReturns is not None: rollingRisk = pd.concat([pd.concat(rs, axis=1), pd.concat(rb, axis=1)], axis=1) else: rollingRisk = None if plot: verticalSections = 2 plt.figure(figsize=(16, 7 * verticalSections)) gs = gridspec.GridSpec(verticalSections, 3, wspace=0.5, hspace=0.5) axRollingReturns = plt.subplot(gs[0, :]) axDrawDown = plt.subplot(gs[1, :], sharex=axRollingReturns) plottingRollingReturn(perf_df['daily_cum_return'], benchmarkCumReturns, axRollingReturns) plottingDrawdownPeriods(perf_df['daily_cum_return'], drawDownDaily, 5, axDrawDown) if rollingRisk is not None: plt.figure(figsize=(16, 7 * verticalSections)) gs = gridspec.GridSpec(verticalSections, 3, wspace=0.5, hspace=0.5) axRollingBeta = plt.subplot(gs[0, :]) axRollingSharp = plt.subplot(gs[1, :]) bmName = benchmarkReturns.name plottingRollingBeta(rb, bmName, ax=axRollingBeta) plottingRollingSharp(rs, ax=axRollingSharp) plt.figure(figsize=(16, 7 * verticalSections)) gs = gridspec.GridSpec(verticalSections, 3, wspace=0.5, hspace=0.5) axUnderwater = plt.subplot(gs[0, :]) axMonthlyHeatmap = plt.subplot(gs[1, 0]) axAnnualReturns = plt.subplot(gs[1, 1]) axMonthlyDist = plt.subplot(gs[1, 2]) plottingUnderwater(drawDownDaily['draw_down'], axUnderwater) plottingMonthlyReturnsHeapmap(returns, axMonthlyHeatmap) plottingAnnualReturns(returns, axAnnualReturns) plottingMonthlyRetDist(returns, axMonthlyDist) if accessReturns is not None and plot: plt.figure(figsize=(16, 7 * verticalSections)) gs = gridspec.GridSpec(verticalSections, 3, wspace=0.5, hspace=0.5) axRollingAccessReturns = plt.subplot(gs[0, :]) axAccessDrawDown = plt.subplot(gs[1, :], sharex=axRollingAccessReturns) plottingRollingReturn(accessCumReturns, None, axRollingAccessReturns, title='Access Cumulative Returns w.r.t. ' + benchmarkReturns.name) plottingDrawdownPeriods(accessCumReturns, accessDrawDownDaily, 5, axAccessDrawDown, title=('Top 5 Drawdown periods w.r.t. ' + benchmarkReturns.name)) plt.figure(figsize=(16, 7 * verticalSections)) gs = gridspec.GridSpec(verticalSections, 3, wspace=0.5, hspace=0.5) axAccessUnderwater = plt.subplot(gs[0, :]) axAccessMonthlyHeatmap = plt.subplot(gs[1, 0]) axAccessAnnualReturns = plt.subplot(gs[1, 1]) axAccessMonthlyDist = plt.subplot(gs[1, 2]) plottingUnderwater(accessDrawDownDaily['draw_down'], axAccessUnderwater, title='Underwater Plot w.r.t. ' + benchmarkReturns.name) plottingMonthlyReturnsHeapmap(accessReturns, ax=axAccessMonthlyHeatmap, title='Monthly Access Returns (%)') plottingAnnualReturns(accessReturns, ax=axAccessAnnualReturns, title='Annual Access Returns') plottingMonthlyRetDist(accessReturns, ax=axAccessMonthlyDist, title='Distribution of Monthly Access Returns') return perf_metric, perf_df, rollingRisk
class StocksPositionsBook(object): _bizDatesList = bizDatesList("China.SSE", dt.datetime(1993, 1, 1), dt.datetime(2025, 12, 31)) def __init__(self, assets): self.assets = assets self._lags = {s: self.assets[s].lag for s in self.assets.keys()} self._shortable = {s: self.assets[s].short for s in self.assets.keys()} self._cachedSaleAmount = {} self._allPositions = {} def positions(self, symbol): return self._allPositions[symbol] def avaliableForTrade(self, symbol, currDT): if symbol in self._cachedSaleAmount: record = self._cachedSaleAmount[symbol] if record['date'] < currDT: return self._avaliableForTrade(symbol, currDT) else: return record['amount'] else: return self._avaliableForTrade(symbol, currDT) def _avaliableForTrade(self, symbol, currDT): if symbol not in self._allPositions: avaliableForSell, avaliableForBuy = 0, 0 else: symbolPositionsHistory = self._allPositions[symbol] avaliableForSell, avaliableForBuy =\ symbolPositionsHistory.avaliableForTrade(currDT, StocksPositionsBook._bizDatesList) self._cachedSaleAmount[symbol] = {'date': currDT, 'amount': (avaliableForSell, avaliableForBuy)} return avaliableForSell, avaliableForBuy def updatePositionsByOrder(self, symbol, currDT, quantity, direction): direction = convertDirection(direction) if symbol not in self._allPositions: if not self._shortable[symbol] and direction == -1: raise ValueError("Short sell is not allowed for {0}".format(symbol)) else: symbolPositionsHistory = self._allPositions[symbol] symbolPositionsHistory.updatePositionsByOrder(currDT, quantity, direction) # update cache for future usage self._avaliableForTrade(symbol, currDT) def updatePositionsByCancelOrder(self, symbol, currDT, quantity, direction): direction = convertDirection(direction) if symbol in self._allPositions: symbolPositionsHistory = self._allPositions[symbol] symbolPositionsHistory.updatePositionsByCancelOrder(currDT, quantity, direction) # update cache for future usage self._avaliableForTrade(symbol, currDT) def updatePositionsByFill(self, fill_evevt): posClosed = 0 pnl = 0. symbol = fill_evevt.symbol currDT = fill_evevt.timeindex.date() quantity = fill_evevt.quantity direction = convertDirection(fill_evevt.direction) value = fill_evevt.nominal / quantity / direction if symbol not in self._allPositions: lag = self._lags[symbol] short = self._shortable[symbol] self._allPositions[symbol] = SymbolPositionsHistory(symbol, lag, short, currDT, quantity, 0, direction, value) posOpened = quantity else: symbolPositionsHistory = self._allPositions[symbol] posClosed, posOpened, pnl = \ symbolPositionsHistory.updatePositionsByFill(currDT, quantity, direction, value) if symbolPositionsHistory.empty(): del self._allPositions[symbol] self._avaliableForTrade(symbol, currDT) return -posClosed * direction, posOpened * direction, pnl def getBookValueAndBookPnL(self, symbol, currentPrice): if symbol not in self._allPositions: return 0., 0. else: symbolPositionsHistory = self._allPositions[symbol] return symbolPositionsHistory.bookValueAndBookPnL(currentPrice)
def createPerformanceTearSheet(prices=None, returns=None, benchmark=None, benchmarkReturns=None, other_curves=None, turn_over=None, tc_cost=0., plot=True): if prices is not None and not isinstance(prices, pd.Series): raise TypeError("prices series should be a pandas time series.") elif returns is not None and prices is not None: raise ValueError("prices series and returns series can't be both set.") if benchmark is not None and not (isinstance(benchmark, pd.Series) or isinstance(benchmark, str)): raise TypeError("benchmark series should be a pandas time series or a string ticker.") if returns is None: returns = np.log(prices / prices.shift(1)) returns.fillna(0, inplace=True) returns = returns[~np.isinf(returns)] if benchmark is not None and isinstance(benchmark, str) and benchmarkReturns is None: startDate = advanceDateByCalendar("China.SSE", prices.index[0], '-1b', BizDayConventions.Preceding) benchmarkPrices = get_benchmark_data(benchmark, start_date=startDate.strftime('%Y-%m-%d'), end_data=returns.index[-1].strftime("%Y-%m-%d")) # do the linear interpolation on the target time line date_index = prices.index new_index = benchmarkPrices.index.union(date_index) benchmarkPrices = benchmarkPrices.reindex(new_index) benchmarkPrices = benchmarkPrices.interpolate().ix[date_index].dropna() benchmarkReturns = np.log(benchmarkPrices['closePrice'] / benchmarkPrices['closePrice'].shift(1)) benchmarkReturns.name = benchmark benchmarkReturns.fillna(0, inplace=True) benchmarkReturns.index = pd.to_datetime(benchmarkReturns.index.date) elif benchmark is not None and isinstance(benchmark, pd.Series): benchmarkReturns = np.log(benchmark / benchmark.shift(1)) try: benchmarkReturns.name = benchmark.name except AttributeError: benchmarkReturns.name = "benchmark" benchmarkReturns.dropna(inplace=True) benchmarkReturns.index = pd.to_datetime(benchmarkReturns.index.date) aggregateDaily, aggregateDailyAfterTC = aggregateReturns(returns, turn_over, tc_cost) if aggregateDailyAfterTC is not None: aggregateDailyBeforeTC = aggregateDaily aggregateDaily = aggregateDailyAfterTC else: aggregateDailyBeforeTC = aggregateDaily drawDownDaily = drawDown(aggregateDaily) # perf metric annualRet = annualReturn(aggregateDaily) annualVol = annualVolatility(aggregateDaily) sortino = sortinoRatio(aggregateDaily) sharp = sharpRatio(aggregateDaily) maxDrawDown = np.min(drawDownDaily['draw_down']) winningDays = np.sum(aggregateDaily > 0.) lossingDays = np.sum(aggregateDaily < 0.) perf_metric = pd.DataFrame([annualRet, annualVol, sortino, sharp, maxDrawDown, winningDays, lossingDays], index=['annual_return', 'annual_volatiltiy', 'sortino_ratio', 'sharp_ratio', 'max_draw_down', 'winning_days', 'lossing_days'], columns=['metrics']) perf_df = pd.DataFrame(index=aggregateDaily.index) perf_df['daily_return'] = aggregateDaily perf_df['daily_return (w/o tc)'] = aggregateDailyBeforeTC perf_df['daily_cum_return'] = np.exp(aggregateDaily.cumsum()) - 1.0 perf_df['daily_cum_return (w/o tc)'] = np.exp(aggregateDailyBeforeTC.cumsum()) - 1.0 perf_df['daily_draw_down'] = drawDownDaily['draw_down'] if benchmarkReturns is not None: perf_df['benchmark_return'] = benchmarkReturns perf_df['benchmark_cum_return'] = benchmarkReturns.cumsum() perf_df.fillna(0.0, inplace=True) perf_df['benchmark_cum_return'] = np.exp(perf_df['benchmark_cum_return'] - perf_df['benchmark_cum_return'][0]) - 1.0 perf_df['access_return'] = aggregateDaily - perf_df['benchmark_return'] perf_df['access_cum_return'] = (1.0 + perf_df['daily_cum_return']) \ / (1.0 + perf_df['benchmark_cum_return']) - 1.0 accessDrawDownDaily = drawDown(perf_df['access_return']) else: accessDrawDownDaily = None if 'benchmark_cum_return' in perf_df: benchmarkCumReturns = perf_df['benchmark_cum_return'] benchmarkCumReturns.name = benchmarkReturns.name accessCumReturns = perf_df['access_cum_return'] accessReturns = perf_df['access_return'] index = perf_df.index length1 = len(bizDatesList('China.SSE', index[0], index[-1])) length2 = len(perf_df) factor = length1 / float(length2) rb = RollingBeta(perf_df['daily_return'], perf_df['benchmark_return'], [1, 3, 6], factor=factor) rs = RollingSharp(perf_df['daily_return'], [1, 3, 6], factor=factor) else: benchmarkCumReturns = None accessReturns = None accessCumReturns = None if len(perf_df['daily_return']) > APPROX_BDAYS_PER_MONTH and benchmarkCumReturns is not None: rollingRisk = pd.concat([pd.concat(rs, axis=1), pd.concat(rb, axis=1)], axis=1) else: rollingRisk = None if plot: verticalSections = 2 plt.figure(figsize=(16, 7 * verticalSections)) gs = gridspec.GridSpec(verticalSections, 3, wspace=0.5, hspace=0.5) axRollingReturns = plt.subplot(gs[0, :]) axDrawDown = plt.subplot(gs[1, :]) plottingRollingReturn(perf_df['daily_cum_return'], perf_df['daily_cum_return (w/o tc)'], benchmarkCumReturns, other_curves, axRollingReturns) plottingDrawdownPeriods(perf_df['daily_cum_return'], drawDownDaily, 5, axDrawDown) if rollingRisk is not None: plt.figure(figsize=(16, 7 * verticalSections)) gs = gridspec.GridSpec(verticalSections, 3, wspace=0.5, hspace=0.5) axRollingBeta = plt.subplot(gs[0, :]) axRollingSharp = plt.subplot(gs[1, :]) bmName = benchmarkReturns.name plottingRollingBeta(rb, bmName, ax=axRollingBeta) plottingRollingSharp(rs, ax=axRollingSharp) plt.figure(figsize=(16, 7 * verticalSections)) gs = gridspec.GridSpec(verticalSections, 3, wspace=0.5, hspace=0.5) axUnderwater = plt.subplot(gs[0, :]) axMonthlyHeatmap = plt.subplot(gs[1, 0]) axAnnualReturns = plt.subplot(gs[1, 1]) axMonthlyDist = plt.subplot(gs[1, 2]) plottingUnderwater(drawDownDaily['draw_down'], axUnderwater) plottingMonthlyReturnsHeapmap(aggregateDaily, axMonthlyHeatmap) plottingAnnualReturns(aggregateDaily, axAnnualReturns) plottingMonthlyRetDist(aggregateDaily, axMonthlyDist) if accessReturns is not None and plot: plt.figure(figsize=(16, 7 * verticalSections)) gs = gridspec.GridSpec(verticalSections, 3, wspace=0.5, hspace=0.5) axRollingAccessReturns = plt.subplot(gs[0, :]) axAccessDrawDown = plt.subplot(gs[1, :], sharex=axRollingAccessReturns) plottingRollingReturn(accessCumReturns, None, None, None, axRollingAccessReturns, title='Access Cumulative Returns w.r.t. ' + benchmarkReturns.name) plottingDrawdownPeriods(accessCumReturns, accessDrawDownDaily, 5, axAccessDrawDown, title=('Top 5 Drawdown periods w.r.t. ' + benchmarkReturns.name)) plt.figure(figsize=(16, 7 * verticalSections)) gs = gridspec.GridSpec(verticalSections, 3, wspace=0.5, hspace=0.5) axAccessUnderwater = plt.subplot(gs[0, :]) axAccessMonthlyHeatmap = plt.subplot(gs[1, 0]) axAccessAnnualReturns = plt.subplot(gs[1, 1]) axAccessMonthlyDist = plt.subplot(gs[1, 2]) plottingUnderwater(accessDrawDownDaily['draw_down'], axAccessUnderwater, title='Underwater Plot w.r.t. ' + benchmarkReturns.name) plottingMonthlyReturnsHeapmap(accessReturns, ax=axAccessMonthlyHeatmap, title='Monthly Access Returns (%)') plottingAnnualReturns(accessReturns, ax=axAccessAnnualReturns, title='Annual Access Returns') plottingMonthlyRetDist(accessReturns, ax=axAccessMonthlyDist, title='Distribution of Monthly Access Returns') return perf_metric, perf_df, rollingRisk
def test_calc101(): INDU_STYLES = ['Bank','RealEstate','Health','Transportation','Mining','NonFerMetal', 'HouseApp','LeiService','MachiEquip','BuildDeco','CommeTrade','CONMAT', 'Auto','Textile','FoodBever','Electronics','Computer','LightIndus', 'Utilities','Telecom','AgriForest','CHEM','Media','IronSteel', 'NonBankFinan','ELECEQP','AERODEF'] alpha_number = 101 engine = create_engine('') begin_date = '2018-12-01' end_date = '2018-12-28' query = select([Market]).where( and_(Market.trade_date >= begin_date, Market.trade_date <= end_date, )) mkt_df = pd.read_sql(query, engine) mkt_df.rename(columns={'preClosePrice':'pre_close','openPrice':'open_price', 'highestPrice':'highest_price','lowestPrice':'lowest_price', 'closePrice':'close_price','turnoverVol':'turnover_vol', 'turnoverValue':'turnover_value','accumAdjFactor':'accum_adj', 'vwap':'vwap','negMarketValue':'neg_mkt_value','marketValue':'mkt_value', 'chgPct':'chg_pct','PE':'pe_ttm','PE1':'pe','PB':'pb'}, inplace=True) mkt_df = mkt_df[[('000000' + str(code))[-6:][0] in '036' for code in mkt_df['code']]] trade_date_list = list(set(mkt_df.trade_date)) trade_date_list.sort(reverse=True) mkt_df = mkt_df[mkt_df['turnover_vol'] > 0] for p in mkt_df.columns: if p in ['open_price', 'highest_price', 'lowest_price', 'close_price', 'vwap']: mkt_df[p+'_raw'] = mkt_df[p] mkt_df[p] = mkt_df[p] * mkt_df['accum_adj'] # multiplier for pe, pb, mkt_value and neg_mkt_value mkt_multiplier = mkt_df[['trade_date', 'code', 'accum_adj', 'close_price', 'neg_mkt_value', 'mkt_value', 'pe_ttm', 'pe', 'pb']] for p in ['neg_mkt_value', 'mkt_value', 'pe_ttm', 'pe', 'pb']: mkt_multiplier[p] = mkt_multiplier[p] / mkt_multiplier['close_price'] mkt_multiplier.drop('close_price', axis=1, inplace=True) mkt_df.drop(['accum_adj', 'neg_mkt_value', 'mkt_value', 'pe_ttm', 'pe', 'pb'], axis=1, inplace=True) mkt_df = mkt_df.merge(mkt_multiplier, on=['trade_date', 'code'], how='left') mkt_df['turnover'] = mkt_df['turnover_value'] / mkt_df['mkt_value'] mkt_df = mkt_df.set_index(['trade_date', 'code']) query = select([Exposure]).where( and_(Exposure.trade_date >= begin_date, Exposure.trade_date <= end_date)) risk_df = pd.read_sql(query, engine) risk_df = risk_df[[('000000' + str(code))[-6:][0] in '036' for code in risk_df['code']]] risk_df = risk_df.sort_values(['trade_date', 'code']).reset_index(drop=True) date_list = bizDatesList('China.SSE', begin_date, end_date) indu_dict = {} indu_names = INDU_STYLES + ['COUNTRY'] for date in date_list: date_indu_df = risk_df[risk_df['trade_date'] == date_list[-1]].set_index('code')[indu_names] indu_check_se = date_indu_df.sum(axis=1).sort_values() date_indu_df.drop(indu_check_se[indu_check_se < 2].index, inplace=True) indu_dict[date] = date_indu_df.sort_index() # total dataframe to dataframe dict total_data = {} for col in ['open_price', 'highest_price', 'lowest_price', 'close_price', 'vwap', 'turnover_vol','turnover_value', 'neg_mkt_value','mkt_value', 'pe_ttm', 'pe', 'pb', 'open_price_raw', 'highest_price_raw', 'lowest_price_raw', 'close_price_raw', 'vwap_raw', 'accum_adj']: total_data[col] = mkt_df[col].unstack().sort_index() total_data['returns'] = total_data['close_price'].pct_change() total_data['indu'] = indu_dict #58, 59, 67,69, 76, 80, 82, 87, 90, 91, 97 alpha_num_list = [58, 59, 67, 69, 76, 80, 82, 87, 90, 91, 97] pdb.set_trace() for date in trade_date_list: for number in alpha_num_list: print('Alpha101().alpha_' + str(number), date) alpha_fun = eval('Alpha101().alpha_' + str(number)) fun_param = inspect.signature(alpha_fun).parameters dependencies = fun_param['dependencies'].default max_window = fun_param['max_window'].default #若在外部指定参数则可计算出max_windows begin = advanceDateByCalendar('china.sse', date, '-%sb' % (max_window - 1)) data = {} for dep in dependencies: data[dep] = total_data[dep].loc[begin:date] data['indu'] = total_data['indu'] alpha_fun(data)
how='left', on=['trade_date', 'code']) total_data['risk_cov'] = risk_cov industry_info = self.fetch_industry_range(universe, start_date=start_date, end_date=end_date, dates=dates, category=industry) factor_data = pd.merge(factor_data, industry_info, on=['trade_date', 'code']) total_data['factor'] = factor_data return total_data if __name__ == '__main__': from PyFin.api import bizDatesList engine = SqlEngine() ref_date = '2017-05-03' universe = Universe('zz800') dates = bizDatesList('china.sse', '2018-05-01', '2018-05-10') codes = engine.fetch_codes(ref_date, universe) res = engine.fetch_dx_return_range(universe, dates=dates, horizon=4, benchmark=300) print(res)
class StocksPositionsBook(object): _bizDatesList = bizDatesList("China.SSE", dt.datetime(1993, 1, 1), dt.datetime(2025, 12, 31)) def __init__(self, assets): self._allPositions = {} self.assets = assets self._lags = {s: self.assets[s].lag for s in self.assets.keys()} self._shortable = {s: self.assets[s].short for s in self.assets.keys()} self._cachedSaleAmount = {} self._allPositions = {} def avaliableForTrade(self, symbol, currDT): if symbol in self._cachedSaleAmount: record = self._cachedSaleAmount[symbol] if record['date'] < currDT: return self._avaliableForTrade(symbol, currDT) else: return record['amount'] else: return self._avaliableForTrade(symbol, currDT) def _avaliableForTrade(self, symbol, currDT): lag = self._lags[symbol] if symbol not in self._allPositions: avaliableForSell = 0 avaliableForBuy = 0 elif lag == 0: _, positions, locked, existDirections, _ = self._allPositions[ symbol] avaliableForSell = 0 avaliableForBuy = 0 for i, direction in enumerate(existDirections): if direction == 1: avaliableForSell += positions[i] - locked[i] else: avaliableForBuy += positions[i] - locked[i] else: dates, positions, locked, existDirections, _ = self._allPositions[ symbol] i = len(dates) - 1 date = dates[i] while date > currDT: i -= 1 if i < 0: break date = dates[i] while i >= 0: startPos = bisect.bisect_left( StocksPositionsBook._bizDatesList, date) endPos = bisect.bisect_left(StocksPositionsBook._bizDatesList, currDT) bizDates = endPos - startPos + 1 if StocksPositionsBook._bizDatesList[endPos] == currDT: bizDates -= 1 else: bizDates -= 2 if bizDates >= lag: break i -= 1 if i < 0: break date = dates[i] avaliableForSell = 0 avaliableForBuy = 0 if i >= 0: for k in range(i + 1): if existDirections[k] == 1: avaliableForSell += positions[k] - locked[k] else: avaliableForBuy += positions[k] - locked[k] self._cachedSaleAmount[symbol] = { 'date': currDT, 'amount': (avaliableForSell, avaliableForBuy) } return avaliableForSell, avaliableForBuy def updatePositionsByOrder(self, symbol, currDT, quantity, direction): if symbol not in self._allPositions: if not self._shortable[symbol] and direction == -1: raise ValueError( "Short sell is not allowed for {0}".format(symbol)) else: dates, positions, locked, existDirections, _ = self._allPositions[ symbol] toFinish = quantity i = 0 while toFinish != 0 and i != len(dates): if existDirections[i] != direction: amount = positions[i] - locked[i] if amount >= toFinish: locked[i] += toFinish toFinish = 0 break else: locked[i] = positions[i] i += 1 toFinish -= amount else: i += 1 if toFinish > 0 and direction == -1 and not self._shortable[symbol]: raise ValueError( "Existing amount is not enough to cover sell order. Short sell is not allowed for {0}" .format(symbol)) self._avaliableForTrade(symbol, currDT) def updatePositionsByFill(self, fill_evevt): posClosed = 0 posOpened = 0 pnl = 0. symbol = fill_evevt.symbol currDT = fill_evevt.timeindex.date() quantity = fill_evevt.quantity direction = fill_evevt.direction value = fill_evevt.nominal / quantity / direction if symbol not in self._allPositions: self._allPositions[symbol] = [currDT], [quantity], [0 ], [direction ], [value] posOpened = quantity else: dates, positions, locked, existDirections, existValues = self._allPositions[ symbol] toFinish = quantity for i, d in enumerate(existDirections): if d != direction: amount = positions[i] if amount >= toFinish: positions[i] -= toFinish locked[i] -= toFinish posClosed += toFinish pnl += (value - existValues[i]) * d * toFinish toFinish = 0 break else: toFinish -= amount positions[i] = 0 locked[i] = 0 posClosed += amount pnl += (value - existValues[i]) * d * amount if toFinish != 0: dates.append(currDT) positions.append(toFinish) locked.append(0) existDirections.append(direction) existValues.append(value) posOpened = toFinish deleted = 0 for k in range(i + 1): if positions[k - deleted] == 0: del dates[k - deleted] del positions[k - deleted] del locked[k - deleted] del existDirections[k - deleted] del existValues[k - deleted] deleted += 1 if not dates: del self._allPositions[symbol] self._avaliableForTrade(symbol, currDT) return -posClosed * direction, posOpened * direction, pnl def getBookValueAndBookPnL(self, symbol, currentPrice): if symbol not in self._allPositions: return 0., 0. else: bookValue = 0. bookPnL = 0. _, positions, _, existDirections, existCosts = self._allPositions[ symbol] for p, d, c in zip(positions, existDirections, existCosts): bookValue += p * d * currentPrice bookPnL += p * d * (currentPrice - c) return bookValue, bookPnL