def __getattribute__(self, name): ret = super().__getattribute__(name) if ret is not None or name not in self.properties(): return ret resolved = False try: resolved = super().__getattribute__('resolution_key') is not None except AttributeError: pass if GsSession.current_is_set and not resolved: attr = getattr(super().__getattribute__('__class__'), name, None) if attr and isinstance(attr, property): resolved_inst = self.resolve(in_place=False) if isinstance(resolved_inst, PricingFuture): ret = PricingFuture() resolved_inst.add_done_callback( lambda inst_f: ret.set_result( object.__getattribute__(inst_f.result(), name))) else: ret = object.__getattribute__(resolved_inst, name) return ret
def market(self) -> Union[OverlayMarket, PricingFuture, dict]: """ Market Data map of coordinates and values. Note that this is not yet supported on all instruments ***Examples** >>> from gs_quant.markets.portfolio import Portfolio >>> >>> portfolio = Portfolio(...) >>> market = portfolio.market() """ pricing_context = self.__pricing_context with pricing_context: futures = [i.market() for i in self.all_instruments] result_future = PricingFuture() return_future = not isinstance( pricing_context, PricingContext ) or pricing_context.is_async or pricing_context.is_entered def cb(future: CompositeResultFuture): def update_market_data(all_market_data, this_market_data): for item in this_market_data: existing_value = all_market_data.setdefault( item.coordinate, item.value) if abs(existing_value - item.value) > 1e-6: raise ValueError( f'Conflicting values for {item.coordinate}: {existing_value} vs {item.value}' ) results = [f.result() for f in future.futures] is_historical = isinstance(results[0], dict) market_data = None if is_historical else {} overlay_markets = {} if is_historical else None for result in results: if market_data is not None: update_market_data(market_data, result.market_data) else: for market in result.values(): update_market_data( overlay_markets.setdefault(market.base_market, {}), market.market_data) if market_data: ret = OverlayMarket(base_market=results[0].base_market, market_data=market_data) else: ret = { base_market.date: OverlayMarket(base_market=base_market, market_data=market_data) for base_market, market_data in overlay_markets.items() } if result_future: result_future.set_result(ret) CompositeResultFuture(futures).add_done_callback(cb) return result_future if return_future else result_future.result()
def calc(self, risk_measure: Union[RiskMeasure, Iterable[RiskMeasure]], fn=None)\ -> Union[DataFrameWithInfo, ErrorValue, FloatWithInfo, PriceableImpl, PricingFuture, SeriesWithInfo, Tuple[MarketDataCoordinate, ...]]: """ Calculate the value of the risk_measure :param risk_measure: the risk measure to compute, e.g. IRDelta (from gs_quant.risk) :param fn: post-processing function (optional) :return: a float or dataframe, depending on whether the value is scalar or structured, or a future thereof (depending on how PricingContext is being used) **Examples** >>> from gs_quant.instrument import IRCap >>> from gs_quant.risk import IRDelta >>> >>> cap = IRCap('1y', 'USD') >>> delta = cap.calc(IRDelta) delta is a dataframe >>> from gs_quant.instrument import EqOption >>> from gs_quant.risk import EqDelta >>> >>> option = EqOption('.SPX', '3m', 'ATMF', 'Call', 'European') >>> delta = option.calc(EqDelta) delta is a float >>> from gs_quant.markets import PricingContext >>> >>> cap_usd = IRCap('1y', 'USD') >>> cap_eur = IRCap('1y', 'EUR') >>> with PricingContext(): >>> usd_delta_f = cap_usd.calc(IRDelta) >>> eur_delta_f = cap_eur.calc(IRDelta) >>> >>> usd_delta = usd_delta_f.result() >>> eur_delta = eur_delta_f.result() usd_delta_f and eur_delta_f are futures, usd_delta and eur_delta are dataframes """ futures = {r: r.pricing_context.calc(self, r) for r in ((risk_measure,) if isinstance(risk_measure, RiskMeasure) else risk_measure)} future = MultipleRiskMeasureFuture(futures) if len(futures) > 1 else futures[risk_measure] if fn is not None: ret = PricingFuture() def cb(f): try: ret.set_result(fn(f.result())) except Exception as e: ret.set_exception(e) future.add_done_callback(cb) future = ret return future.result() if not (PricingContext.current.is_entered or PricingContext.current.is_async) else future
def resolve(self, in_place: bool = True) -> Optional[Union[PricingFuture, PriceableImpl, dict]]: priceables = self._get_instruments(self.__position_context.position_date, in_place, True) pricing_context = self._pricing_context with pricing_context: futures = [p.resolve(in_place) for p in priceables] if not in_place: ret = {} if isinstance(PricingContext.current, HistoricalPricingContext) else Portfolio(name=self.name) result_future = PricingFuture() if self._return_future else None def cb(future: CompositeResultFuture): if isinstance(ret, Portfolio): ret.priceables = [f.result() for f in future.futures] else: priceables_by_date = {} for future in futures: for date, priceable in future.result().items(): priceables_by_date.setdefault(date, []).append(priceable) for date, priceables in priceables_by_date.items(): if any(p for p in priceables if not isinstance(p, PriceableImpl)): _logger.error(f'Error resolving on {date}, skipping that date') else: ret[date] = Portfolio(priceables, name=self.name) if result_future: result_future.set_result(ret) CompositeResultFuture(futures).add_done_callback(cb) return result_future or ret
def resolve( self, in_place: bool = True ) -> Optional[Union[PricingFuture, PriceableImpl, dict]]: pricing_context = self.__pricing_context with pricing_context: futures = [i.resolve(in_place) for i in self.__priceables] if not in_place: ret = {} if isinstance(PricingContext.current, HistoricalPricingContext) else Portfolio( name=self.name) result_future = PricingFuture() if not isinstance(pricing_context, PricingContext) or\ pricing_context.is_async or pricing_context.is_entered else None def cb(future): if isinstance(ret, Portfolio): ret.priceables = [f.result() for f in future.futures] else: priceables_by_date = {} for future in futures: for date, priceable in future.result().items(): priceables_by_date.setdefault(date, []).append(priceable) for date, priceables in priceables_by_date.items(): ret[date] = Portfolio(priceables, name=self.name) if result_future: result_future.set_result(ret) CompositeResultFuture(futures).add_done_callback(cb) return result_future or ret
def calc(self, risk_measure: Union[RiskMeasure, Iterable[RiskMeasure]], fn=None) ->\ Union[DataFrameWithInfo, ErrorValue, FloatWithInfo, PriceableImpl, PricingFuture, SeriesWithInfo, Tuple[MarketDataCoordinate, ...]]: # Tactical fix until the equities pricing service notion of IRDelta is changed to match FICC from gs_quant.markets import PricingContext from gs_quant.risk import IRDelta, IRDeltaParallel error_result = None if risk_measure == IRDeltaParallel: risk_measure = IRDelta elif risk_measure == IRDelta: error_result = ErrorValue(None, 'IRDelta not supported for EqOption') elif not isinstance(risk_measure, RiskMeasure): if IRDelta in risk_measure: risk_measure = tuple(r for r in risk_measure if r != IRDelta) else: risk_measure = tuple(IRDelta if r == IRDeltaParallel else r for r in risk_measure) if error_result: return PricingFuture(error_result) if PricingContext.current.is_entered or PricingContext.current.is_async\ else error_result else: return super().calc(risk_measure, fn=fn)
def _calc(self, priceable: Priceable, risk_key: RiskKey) -> PricingFuture: future = self.active_context.__pending.get((risk_key, priceable)) if future is None: future = PricingFuture() cached_result = PricingCache.get( risk_key, priceable) if self.use_cache else None if cached_result is not None: future.set_result(cached_result) else: self.active_context.__pending[(risk_key, priceable)] = future if not (self.is_entered or self.is_async): self.__calc() return future
def _calc(self, instrument: InstrumentBase, risk_key: RiskKey) -> PricingFuture: pending = self.active_context.__pending from gs_quant.instrument import DummyInstrument if isinstance(instrument, DummyInstrument): return PricingFuture(StringWithInfo(value=instrument.dummy_result, risk_key=risk_key)) future = pending.get((risk_key, instrument)) if future is None: future = PricingFuture() cached_result = PricingCache.get(risk_key, instrument) if self.use_cache else None if cached_result is not None: future.set_result(cached_result) else: pending[(risk_key, instrument)] = future return future
def _calc(self, instrument: InstrumentBase, risk_key: RiskKey) -> PricingFuture: pending = self.active_context.__pending future = pending.get((risk_key, instrument)) if future is None: future = PricingFuture() cached_result = PricingCache.get( risk_key, instrument) if self.use_cache else None if cached_result is not None: future.set_result(cached_result) else: pending[(risk_key, instrument)] = future if not (self.is_entered or self.is_async): self.__calc() return future
def calc(self, priceable: Priceable, risk_measure: RiskMeasure) -> PricingFuture: """ Calculate the risk measure for the priceable instrument. Do not use directly, use via instruments :param priceable: The priceable (e.g. instrument) :param risk_measure: The measure we wish to calculate :return: A PricingFuture whose result will be the calculation result **Examples** >>> from gs_quant.instrument import IRSwap >>> from gs_quant.risk import IRDelta >>> >>> swap = IRSwap('Pay', '10y', 'USD', fixed_rate=0.01) >>> delta = swap.calc(IRDelta) """ with self.active_context.__lock: risk_key = self.__risk_key(risk_measure, priceable.provider()) future = self.active_context.__pending.get((risk_key, priceable)) if future is None: future = PricingFuture() cached_result = PricingCache.get( risk_key, priceable) if self.use_cache else None if cached_result is not None: future.set_result(cached_result) else: self.active_context.__pending[(risk_key, priceable)] = future if not (self.is_entered or self.is_async): self.__calc() return future
def __getattribute__(self, name): ret = super().__getattribute__(name) flds = super().__getattribute__('_fields_by_name')() if ret is not None or name not in flds or super().__getattribute__( '_Instrument__suppress_resolution'): return ret if GsSession.current_is_set and super().__getattribute__( 'resolution_key') is None: try: self.__suppress_resolution = True resolved_inst = self.resolve(in_place=False) if isinstance(resolved_inst, PricingFuture): ret = PricingFuture() resolved_inst.add_done_callback( lambda inst_f: ret.set_result( object.__getattribute__(inst_f.result(), name))) else: ret = object.__getattribute__(resolved_inst, name) finally: self.__suppress_resolution = False return ret
def calc(self, risk_measure: Union[RiskMeasure, Iterable[RiskMeasure]], fn=None) \ -> Union[DataFrameWithInfo, ErrorValue, FloatWithInfo, PriceableImpl, PricingFuture, SeriesWithInfo, Tuple[MarketDataCoordinate, ...]]: """ Calculate the value of the risk_measure :param risk_measure: the risk measure to compute, e.g. IRDelta (from gs_quant.risk) :param fn: post-processing function (optional) :return: a float or dataframe, depending on whether the value is scalar or structured, or a future thereof (depending on how PricingContext is being used) **Examples** >>> from gs_quant.instrument import IRCap >>> from gs_quant.risk import IRDelta >>> >>> cap = IRCap('1y', 'USD') >>> delta = cap.calc(IRDelta) delta is a dataframe >>> from gs_quant.instrument import EqOption >>> from gs_quant.risk import EqDelta >>> >>> option = EqOption('.SPX', '3m', 'ATMF', 'Call', 'European') >>> delta = option.calc(EqDelta) delta is a float >>> from gs_quant.markets import PricingContext >>> >>> cap_usd = IRCap('1y', 'USD') >>> cap_eur = IRCap('1y', 'EUR') >>> with PricingContext(): >>> usd_delta_f = cap_usd.calc(IRDelta) >>> eur_delta_f = cap_eur.calc(IRDelta) >>> >>> usd_delta = usd_delta_f.result() >>> eur_delta = eur_delta_f.result() usd_delta_f and eur_delta_f are futures, usd_delta and eur_delta are dataframes """ single_measure = isinstance(risk_measure, RiskMeasure) with self._pricing_context: future = risk_measure.pricing_context.calc(self, risk_measure) if single_measure else \ MultipleRiskMeasureFuture(self, {r: r.pricing_context.calc(self, r) for r in risk_measure}) # Warn on use of deprecated measures def warning_on_one_line(msg, category, _filename, _lineno, _file=None, _line=None): return f'{category.__name__}:{msg}' for measure in (risk_measure,) if single_measure else risk_measure: if measure.name in DEPRECATED_MEASURES.keys(): message = '{0} risk measure is deprecated. Please use {1} instead and pass in arguments to describe ' \ 'risk measure specifics.\n'.format(measure.name, DEPRECATED_MEASURES[measure.name]) warnings.simplefilter('once') warnings.formatwarning = warning_on_one_line warnings.warn(message, DeprecationWarning) warnings.simplefilter('ignore') if fn is not None: ret = PricingFuture() def cb(f): try: ret.set_result(fn(f.result())) except Exception as e: ret.set_exception(e) future.add_done_callback(cb) future = ret return future if self._return_future else future.result()