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 expire_date_fun(term_list, db_session): """ 根据当前日期和特定步长天数列表,除去节假日和双休,计算到期交易日 [1,3,5,10,22,44,66,123]: 特定步长天数列表 使用business_calendar库的Calendar方法 :param date: term_list(特定步长天数列表) :return: expire_date_dict """ # 获取当前时间 current_day = datetime.date.today() # 获取节假日 holidays = TradingCalendarRepo.get_holiday_list(db_session) # # todo 获取特殊日 # special_dates = load_special_dates(db_session, underlier) special_dates = [] # 根据step获取交易日是哪天,并与步长天数组成字典 # 将到期日与天数组成一个字典 expire_date_dict = {} for step_date in term_list: expire_date = DateTimeUtils.get_trading_day( current_day, holidays, special_dates, step_date) expire_date = expire_date.strftime('%Y-%m-%d') expire_date_dict[expire_date] = step_date return expire_date_dict
def go_trading_day(db_session, current_date, step, direction=1): special_dates = [] holidays = TradingCalendarRepo.get_holiday_list(db_session) return DateTimeUtils.get_trading_day(current_date, holidays, special_dates, step, direction=direction)
async def get_heat_map(self, trade_date=None): with self.make_session() as db_session: if trade_date is None: trade_date = datetime.now().date() # 求上一个交易日 holidays = TradingDayService.get_holiday_list(db_session) trade_date = DateTimeUtils.get_trading_day(trade_date, holidays, special_dates=[], step=2, direction=-1) heat_map_dto_list, diagnostics = OtcAtmQuoteService.get_heat_map(db_session, trade_date) heat_map_schema = HeatMapSchema(many=True, exclude=[]) return DiagnosticResponse(heat_map_schema.dump(heat_map_dto_list).data, diagnostics)
def calc_all_instrument_quote_vol_surface(observed_date): """ 从otc_option_quote表里取华泰的数据,格式化写入到vol_surface表中 :return: """ db_session = create_db_session() try: # 取所有instrument_id instrument_ids = OTCOptionQuoteRepo.get_instrument_ids_by_observe_date( db_session, observed_date) vol_surface_dbo_dict = {} for index, instrument_id in enumerate(instrument_ids): # 计算一个标的的vol_surface logger.info('准备加载的标的为: %s, 进度为: %d of %d' % (instrument_id, index + 1, len(instrument_ids))) vol_surface_dbo = VolSurfaceSpiderService.calc_one_instrument_quote_vol_surface( db_session, instrument_id, observed_date) if vol_surface_dbo is None: continue vol_surface_dbo_dict[instrument_id] = vol_surface_dbo logger.info('成功计算了标的: %s的vol_surface, 进度为: %d of %d' % (instrument_id, index + 1, len(instrument_ids))) # 获取所有的合约种类及其对应的主力合约 holidays = TradingCalendarRepo.get_holiday_list(db_session) special_dates = [] # 取上一个交易日 last_trade_date = DateTimeUtils.get_trading_day( observed_date, holidays, special_dates, 1, -1) # 获取所有的主力合约 contract_list = db_session.query(FutureContractInfo).filter( FutureContractInfo.tradeDate == last_trade_date).all() # 获取当天所有活跃的大宗期货合约 active_instrument_list = db_session.query(Instrument).filter( and_( Instrument.status == enum_dto.InstrumentStatusType.ACTIVE.name, Instrument.assetClass == enum_dto.AssetClassType.COMMODITY.name, Instrument.instrumentType == enum_dto.InstrumentType.FUTURE.name, or_(Instrument.delistedDate is None, Instrument.delistedDate > observed_date))).all() active_instrument_dict = {} for instrument in active_instrument_list: if instrument.contractType not in active_instrument_dict: active_instrument_dict[instrument.contractType] = [] active_instrument_dict[instrument.contractType].append( instrument.instrumentId) # 所有标的都使用主力合约对应的波动率曲面 vol_surface_dbos = [] for contract in contract_list: primary_contract_id = contract.primaryContractId if primary_contract_id not in vol_surface_dbo_dict: logger.warning('标的没有主力合约对应的波动率曲面:%s' % primary_contract_id) continue variety_type = contract.contractType if variety_type not in active_instrument_dict: logger.warning('主力合约没有活跃的合约:%s' % variety_type) continue active_future_list = active_instrument_dict[variety_type] for instrument_id in active_future_list: vol_surface_dbo = copy.deepcopy( vol_surface_dbo_dict[primary_contract_id]) vol_surface_dbo.uuid = uuid.uuid1() vol_surface_dbo.instrumentId = instrument_id vol_surface_dbos.append(vol_surface_dbo) # 将波动率曲面写入数据库 VolSurfaceRepo.insert_vol_surfaces(db_session, vol_surface_dbos) logger.info('爬虫vol surface计算完成') except Exception as e: logger.error(e)
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()