def get_instrument_quote_close_dict_by_period(db_session, instrument_id, start_date, end_date, is_primary=False): quote_close_dto_list = QuoteCloseService.get_instrument_quote_close_list_by_period(db_session, instrument_id, start_date, end_date, is_primary) # 转化为字典类型 quote_close_dto_dict = {} for quote_close in quote_close_dto_list: quote_close_dto_dict[quote_close.tradeDate] = quote_close # 校验缺失的收盘价数据 missing_dates = [] holidays = TradingDayService.get_holiday_list(db_session, start_date, end_date) trade_date = start_date while trade_date <= end_date: if DateTimeUtils.is_trading_day(trade_date, holidays): if trade_date not in quote_close_dto_dict: # 将缺失的日期添加到诊断中 missing_dates.append(trade_date) # 是否需要将缺失的数据按None补齐 quote_close_dto_dict[trade_date] = None trade_date += timedelta(days=1) # 添加诊断信息 diagnostics = [] if len(missing_dates) != 0: message = '标的物%s在[%s, %s]时段内中缺失%d条收盘数据' % ( instrument_id, DateTimeUtils.date2str(start_date), DateTimeUtils.date2str(end_date), len(missing_dates)) diagnostics.append(DiagnosticDTO(DiagnosticType.WARNING, message, missing_dates)) logging.debug(message) return quote_close_dto_dict, diagnostics
def calc_instrument_vol_cone(db_session, instrument_id, start_date, end_date, windows, percentiles, is_primary=False): origin_start_date = start_date holidays = TradingDayService.get_holiday_list(db_session) # 判断是否时节假日 if DateTimeUtils.is_trading_day(end_date, holidays): start_date = TradingDayService.go_trading_day(db_session, start_date, max(windows) - 1, direction=-1) else: start_date = TradingDayService.go_trading_day(db_session, start_date, max(windows), direction=-1) quote_close_dto_dict, diagnostics = QuoteCloseService.\ get_instrument_quote_close_dict_by_period(db_session, instrument_id, start_date, end_date, is_primary) vol_cone_dto_list = HistoricalVolService.\ calc_multiple_window_percentiles_by_quotes(origin_start_date, end_date, quote_close_dto_dict, windows, percentiles) return vol_cone_dto_list, diagnostics
def get_future_contract_order(db_session, contract_type, exist_dates, start_date, end_date): holidays = TradingCalendarRepo.get_holiday_list(db_session) special_dates = [] if start_date > end_date: logging.error( "日期指定非法:%s 大于 %s" % DateTimeUtils.date2str(start_date), DateTimeUtils.date2str(end_date)) return None else: all_dates = [ DateTimeUtils.str2date(date.strftime("%Y-%m-%d")) for date in rrule(DAILY, dtstart=start_date, until=end_date) ] if exist_dates: missing_dates = list(set(all_dates) - set(exist_dates)) else: missing_dates = all_dates listed_date, delisted_date = DateTimeUtils.offset_trade_date( start_date, end_date, holidays, special_dates) close_dict = CommodityFutureContractService.get_corresponding_close( db_session, contract_type, listed_date, delisted_date) instruments_list = db_session.query(Instrument).filter( Instrument.contractType == contract_type) fc_list = [] if close_dict: for trade_date in missing_dates: if DateTimeUtils.is_trading_day(trade_date, holidays, special_dates): logging.info("处理交易日%s" % DateTimeUtils.date2str(trade_date)) previous_trade_date, _ = DateTimeUtils.offset_trade_date( trade_date, trade_date, holidays, special_dates) pri, sec = FutureContractInfoAlgo.calc_one_future_contract_info( instruments_list, close_dict, contract_type, previous_trade_date) if pri: fc_info = FutureContractInfo( contractType=contract_type, tradeDate=trade_date, primaryContractId=pri, secondaryContractId=sec) logging.info( '合约的主力和次主力为:%s %s %s %s' % (fc_info.contractType, DateTimeUtils.date2str(fc_info.tradeDate), fc_info.primaryContractId, fc_info.secondaryContractId)) fc_list.append(fc_info) else: logging.info("跳过非交易日%s" % DateTimeUtils.date2str(trade_date)) else: fc_list = None return fc_list
def calc_instrument_realized_vol(db_session, instrument_id, trade_date, windows, is_primary=False): if trade_date > date.today(): raise CustomException('所选日期不能超过今天') # TODO: 如果不是交易日,当前默认使用上一个交易日 holidays = TradingCalendarRepo.get_holiday_list(db_session) start_date = DateTimeUtils.get_trading_day(trade_date, holidays, special_dates=[], step=max(windows), direction=-1) quote_close_dto_dict, diagnostics = QuoteCloseService.get_instrument_quote_close_dict_by_period( db_session, instrument_id, start_date, trade_date, is_primary) realized_vol_dto_list = [] for window in windows: return_rates = [] # 判断是否为节假日, 非节假日start_date为: trade_date往前走window-1天, 节假日start_date为: trade_date往前走window天 if DateTimeUtils.is_trading_day(trade_date, holidays): start_date = DateTimeUtils.get_trading_day(trade_date, holidays, special_dates=[], step=window - 1, direction=-1) else: start_date = DateTimeUtils.get_trading_day(trade_date, holidays, special_dates=[], step=window, direction=-1) # 只处理在窗口范围日期内的数据 for key in quote_close_dto_dict: if start_date <= key <= trade_date: quote_close = quote_close_dto_dict.get(key) if quote_close is not None and quote_close.returnRate is not None: return_rates.append(quote_close.returnRate) if len(return_rates) < window: logging.debug('窗口大小大于回报率个数,窗口大小:%d,回报率个数:%d' % (window, len(return_rates))) realized_vol = HistoricalVolAlgo.calc_one_realized_vol( return_rates) if realized_vol is None: # 如果计算得到的结果为None,直接跳过处理 logging.debug('计算得到的值为空,窗口:%d' % window) continue dto = RealizedVolDTO() dto.window = window dto.vol = realized_vol realized_vol_dto_list.append(dto) return realized_vol_dto_list, diagnostics
def calc_instrument_atm_vol_list(db_session, underlyer, start_date, end_date, is_primary): atm_quote_list = OtcAtmQuoteService.get_instrument_atm_quote_list_by_period( db_session, underlyer, start_date, end_date, is_primary) # TODO:去掉重复数据,相同valuation date, underlyer, source, expire date的数据需要去重 # 根据valuation date进行分类 atm_quote_dict = {} for atm_quote in atm_quote_list: if atm_quote.valuationDate not in atm_quote_dict: atm_quote_dict[atm_quote.valuationDate] = [] atm_quote_dict[atm_quote.valuationDate].append(atm_quote) # 取一个自然月后到期日的前后3天的ask_vol和bid_vol的平均值作为当天的atm_vol atm_vol_dict = {} for valuation_date in atm_quote_dict: quote_list = atm_quote_dict[valuation_date] atm_vol = OtcAtmQuoteService.calc_one_atm_vol( valuation_date, quote_list) if atm_vol is not None: atm_vol_dict[valuation_date] = atm_vol # 检测哪些日期缺失 missing_dates = [] holidays = TradingDayService.get_holiday_list(db_session, start_date, end_date) trade_date = start_date while trade_date <= end_date: if DateTimeUtils.is_trading_day(trade_date, holidays): if trade_date not in atm_vol_dict: # 将缺失的日期添加到诊断中 missing_dates.append(trade_date) # TODO: 是否需要将缺失的数据按0补足 trade_date += timedelta(days=1) # 添加诊断信息 diagnostics = [] if len(missing_dates) != 0: message = '标的物%s在[%s, %s]时段内中缺失%d条ATM Vol数据' % ( underlyer, DateTimeUtils.date2str(start_date), DateTimeUtils.date2str(end_date), len(missing_dates)) diagnostics.append( DiagnosticDTO(DiagnosticType.WARNING, message, missing_dates)) logging.error(message) return atm_vol_dict.values(), diagnostics
def calc_instrument_rolling_vol(db_session, instrument_id, start_date, end_date, window, is_primary=False): holidays = TradingDayService.get_holiday_list(db_session) # 判断是否时节假日 if DateTimeUtils.is_trading_day(end_date, holidays): start_date = TradingDayService.go_trading_day(db_session, start_date, window - 1, direction=-1) else: start_date = TradingDayService.go_trading_day(db_session, start_date, window, direction=-1) quote_close_dto_dict, diagnostics = QuoteCloseService.get_instrument_quote_close_dict_by_period( db_session, instrument_id, start_date, end_date, is_primary) realized_vol_dto_list = HistoricalVolService.calc_one_rolling_vol_by_quotes( quote_close_dto_dict, window) return realized_vol_dto_list, diagnostics
def update_all_instrument_vol_surface_to_terminal(observed_date): db_session = create_db_session() holidays = TradingCalendarRepo.get_holiday_list(db_session) special_dates = [] if not DateTimeUtils.is_trading_day(observed_date, holidays, special_dates): observed_date = DateTimeUtils.get_trading_day(observed_date, holidays, special_dates, 1, -1) # 登陆 logging.info('update all instrument vol surface to bct观察日为: %s' % DateTimeUtils.date2str(observed_date)) header = server_utils.login_terminal() # 从终端加载需要的标的物 terminal_instrument_ids = [ instrument['instrumentId'] for instrument in server_utils.get_instrument_list(header) ] logging.info( '从终端加载到的标的物为:%s, 长度为: %d' % (','.join(terminal_instrument_ids), len(terminal_instrument_ids))) # 获取数据库中标的物 vol_surface_list = VolSurfaceRepo.get_vol_surface_by_observed_date( db_session, observed_date) if not vol_surface_list: logging.info('observed_date为: %s没有可以导入到终端的vol surface' % observed_date) # 将instruments去重 unique_vol_surface_list = unique_instruments(vol_surface_list) logging.info('在trading_date为: %s时,vol surface 表获取到的标的数量为: %d' % (observed_date, len(unique_vol_surface_list))) # 写入vol surface 到 bct failed_instrument_ids = [] # hacky here, 由于bct接收的tenor是自然日,需要将vol surface中工作日转为自然日 for index, unique_vol_surface in enumerate(unique_vol_surface_list): # try: instrument_id = unique_vol_surface.instrumentId a = unique_vol_surface.modelInfo model_info = unique_vol_surface.modelInfo if model_info is None: continue # 获取到当前的vol surface的实时行情spot价格 market_data = get_real_time_market_data_by_instrument_id(instrument_id) if market_data is not None and market_data.get( 'lastPrice') is not None: now_price = market_data.get('lastPrice') else: logging.error('标的物%s当前行情为空' % instrument_id) continue if unique_vol_surface.instrumentId not in terminal_instrument_ids: logging.info('当前标的: %s的vol surface不在终端需要的列表里' % unique_vol_surface.instrumentId) continue logging.info('当前准备写入到bct的标的为: %s, 进度为: %d of %d' % (unique_vol_surface.instrumentId, index + 1, len(unique_vol_surface_list))) result = update_one_instrument_to_terminal(unique_vol_surface, header, now_price, observed_date) if not result: failed_instrument_ids.append(instrument_id) time.sleep(0.3) # except Exception as e: # logging.error('更新标的物%s波动率曲面失败, 异常:%s' % (instrument_id, str(e))) logging.error( '处理失败的标的物为:%d %s' % (len(failed_instrument_ids), ','.join(failed_instrument_ids))) db_session.close()
def is_trading_day(db_session, current_date): special_dates = [] holidays = TradingCalendarRepo.get_holiday_list(db_session) return DateTimeUtils.is_trading_day(current_date, holidays, special_dates)