Skip to content

Commit

Permalink
Chore: Make release 1.0.78
Browse files Browse the repository at this point in the history
  • Loading branch information
martinroberson authored and Vanden Bon, David V [GBM Public] committed May 21, 2024
1 parent 97bdd72 commit e9e365e
Show file tree
Hide file tree
Showing 15 changed files with 363 additions and 137 deletions.
4 changes: 2 additions & 2 deletions gs_quant/api/gs/risk_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -182,8 +182,8 @@ def upload_risk_model_data(cls,
if final_upload is not None:
final_upload_flag = 'true' if final_upload else 'false'
url += f'&finalUpload={final_upload_flag}'
if aws_upload:
url += '&awsUpload=true'
if aws_upload:
url += '&awsUpload=true'
return GsSession.current._post(url, model_data, timeout=200)

@classmethod
Expand Down
2 changes: 1 addition & 1 deletion gs_quant/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -287,7 +287,7 @@ def __coerce_value(cls, typ: type, value):
return value.item()
elif hasattr(value, 'tolist'):
# tolist converts scalar or array to native python type if not already native.
return value()
return value.tolist()
elif typ in (DictBase, Optional[DictBase]) and isinstance(value, Base):
return value.to_dict()
is_supported_generic = _get_is_supported_generic(typ)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@
"metadata": {},
"outputs": [],
"source": [
"position_sets = basket.get_position_sets().to_frame()\n",
"position_sets = basket.get_position_sets()\n",
"position_sets = pd.concat([position_set.to_frame() for position_set in position_sets])"
]
}
Expand Down
2 changes: 2 additions & 0 deletions gs_quant/entities/entity.py
Original file line number Diff line number Diff line change
Expand Up @@ -520,6 +520,7 @@ def get_factor_risk_report(self,
if risk_model_id:
reports = [report for report in reports if report.parameters.risk_model == risk_model_id]
reports = [report for report in reports if report.parameters.benchmark == benchmark_id]
reports = [report for report in reports if report.parameters.tags == tags]
if len(reports) == 0:
raise MqError(f'This {position_source_type} has no factor risk reports that match '
'your parameters. Please edit the risk model ID, fxHedged, and/or benchmark value in the '
Expand All @@ -538,6 +539,7 @@ def get_thematic_report(self, tags: Dict = None) -> ThematicReport:
position_source_id=self.id,
report_type=f'{position_source_type} Thematic Analytics',
tags=tags)
reports = [report for report in reports if report.parameters.tags == tags]
if len(reports) == 0:
raise MqError(f'This {position_source_type} has no thematic analytics report.')
return ThematicReport.from_target(reports[0])
Expand Down
1 change: 1 addition & 0 deletions gs_quant/markets/portfolio_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@ def get_performance_report(self, tags: Dict = None) -> PerformanceReport:
position_source_id=self.id,
report_type='Portfolio Performance Analytics',
tags=tags)
reports = [report for report in reports if report.parameters.tags == tags]
if len(reports) == 0:
raise MqError('No performance report found.')
return PerformanceReport.from_target(reports[0])
Expand Down
98 changes: 90 additions & 8 deletions gs_quant/models/risk_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,17 +21,15 @@
import numpy as np
import logging
import deprecation
from gs_quant.target.common import Currency

from gs_quant.api.gs.risk_models import GsFactorRiskModelApi, GsRiskModelApi
from gs_quant.base import EnumBase
from gs_quant.data import DataMeasure
from gs_quant.errors import MqValueError, MqRequestError
from gs_quant.markets.factor import Factor
from gs_quant.markets.securities import SecurityMaster, AssetIdentifier
from gs_quant.models.risk_model_utils import build_asset_data_map, build_factor_data_map, \
build_pfp_data_dataframe, get_isc_dataframe, get_covariance_matrix_dataframe, get_closest_date_index, \
batch_and_upload_partial_data, get_universe_size, batch_and_upload_coverage_data, only_factor_data_is_present, \
upload_model_data, build_factor_id_to_name_map, build_factor_volatility_dataframe
from gs_quant.models.risk_model_utils import *
from gs_quant.target.risk_models import RiskModel as RiskModelBuilder, RiskModelEventType, RiskModelData, \
RiskModelCalendar, RiskModelDataAssetsRequest as DataAssetsRequest, RiskModelDataMeasure as Measure, \
RiskModelCoverage as CoverageType, RiskModelUniverseIdentifier as UniverseIdentifier, Entitlements, \
Expand Down Expand Up @@ -910,9 +908,9 @@ def upload_data(self,
:param data: complete or partial risk model data for uploading on given date
includes: date, and one or more of: factorData, assetData, covarianceMatrix,
issuerSpecificCovariance and factorPortfolios. Look at risk model upload documentation for
further information on what data can be grouped together if asset data size is above the
max asset batch size
issuerSpecificCovariance, factorPortfolios and currencyRatesData. Look at risk model upload
documentation for further information on what data can be grouped together if asset data size is above
the max asset batch size
:param max_asset_batch_size: size of payload to batch with. Defaults to 20000 assets which works well for
models that have factor ids ranging from 1- 3 characters in length. For models with longer factor ids,
consider batching with a smaller max asset batch size
Expand Down Expand Up @@ -1909,6 +1907,89 @@ def get_pre_vra_covariance_matrix(self,
return self._build_covariance_matrix_measure(Measure.Pre_VRA_Covariance_Matrix, start_date, end_date, assets,
format)

def _build_currency_rates_data(self, rows: List[Dict], currencies: List[Currency], rates_key: str,
format: ReturnFormat) -> Union[Dict, pd.DataFrame]:
currency_rates_key = "currencyRatesData"
currency_rates_df = get_optional_data_as_dataframe(rows, currency_rates_key)
if currencies:
currency_rates_df = currency_rates_df.loc[currency_rates_df['currency'].isin([cur.value
for cur in currencies])]
if format == ReturnFormat.DATA_FRAME:
return currency_rates_df
return currency_rates_df.to_dict()

def get_risk_free_rate(self,
start_date: dt.date,
end_date: dt.date = None,
currencies: List[Currency] = [],
format: ReturnFormat = ReturnFormat.DATA_FRAME) -> Union[Dict, pd.DataFrame]:
""" Get risk-free rates for existing risk model
:param start_date: start date for data request
:param end_date: end date for data request
:param currencies: return risk-free rates for these currencies. If empty returns data for all currencies
:param format: which format to return the results in
:return: risk-free rates data
**Usage**
Get risk-free rates data between `start_date` and `end_date`
**Examples**
>>> from gs_quant.models.risk_model import FactorRiskModel
>>> import datetime as dt
>>>
>>> start_date = dt.date(2022, 1, 1)
>>> end_date = dt.date(2022, 5, 2)
>>> model = FactorRiskModel.get("MODEL_ID")
>>> risk_free_rates = model.get_risk_free_rate(start_date, end_date))
**See also**
:func:`get_currency_exchange_rate`
"""
results = self.get_data(measures=[RiskModelDataMeasure.Risk_Free_Rate], start_date=start_date,
end_date=end_date, limit_factors=False).get('results')
return self._build_currency_rates_data(results, rates_key="riskFreeRate", currencies=currencies, format=format)

def get_currency_exchange_rate(self,
start_date: dt.date,
end_date: dt.date = None,
currencies: List[Currency] = [],
format: ReturnFormat = ReturnFormat.DATA_FRAME) -> Union[Dict, pd.DataFrame]:
""" Get currency exchange rates for existing risk model
:param start_date: start date for data request
:param end_date: end date for data request
:param currencies: return currency exchange rates for these currencies. If empty returns data for all currencies
:param format: which format to return the results in
:return: currency exchange rates data
**Usage**
Get currency exchange rates data between `start_date` and `end_date`
**Examples**
>>> from gs_quant.models.risk_model import FactorRiskModel
>>> import datetime as dt
>>>
>>> start_date = dt.date(2022, 1, 1)
>>> end_date = dt.date(2022, 5, 2)
>>> model = FactorRiskModel.get("MODEL_ID")
>>> currency_exchange_rates = model.get_currency_exchange_rate(start_date, end_date))
**See also**
:func:`get_risk_free_rate`
"""
results = self.get_data(measures=[RiskModelDataMeasure.Currency_Exchange_Rate], start_date=start_date,
end_date=end_date, limit_factors=False).get('results')
return self._build_currency_rates_data(results, rates_key="exchangeRate", currencies=currencies, format=format)

def get_factor_volatility(self,
start_date: dt.date,
end_date: dt.date = None,
Expand Down Expand Up @@ -2044,7 +2125,8 @@ def get_issuer_specific_covariance(self,
measures=[Measure.Issuer_Specific_Covariance],
limit_factors=False
).get('results')
isc_data = isc if format == ReturnFormat.JSON else get_isc_dataframe(isc)
isc_data = isc if format == ReturnFormat.JSON else get_optional_data_as_dataframe(isc,
'issuerSpecificCovariance')
return isc_data

def get_factor_portfolios(self,
Expand Down
9 changes: 7 additions & 2 deletions gs_quant/models/risk_model_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -153,11 +153,11 @@ def build_pfp_data_dataframe(results: List) -> pd.DataFrame:
return results


def get_isc_dataframe(results: dict) -> pd.DataFrame:
def get_optional_data_as_dataframe(results: List, optional_data_key: str) -> pd.DataFrame:
cov_list = []
date_list = []
for row in results:
matrix_df = pd.DataFrame(row.get('issuerSpecificCovariance'))
matrix_df = pd.DataFrame(row.get(optional_data_key))
cov_list.append(matrix_df)
date_list.append(row.get('date'))
results = pd.concat(cov_list, keys=date_list) if cov_list else pd.DataFrame({})
Expand Down Expand Up @@ -278,6 +278,11 @@ def batch_and_upload_partial_data(model_id: str, data: dict, max_asset_size: int
date = data.get('date')
_upload_factor_data_if_present(model_id, data, date, **kwargs)
sleep(2)
if data.get('currencyRatesData'):
_repeat_try_catch_request(GsFactorRiskModelApi.upload_risk_model_data, model_id=model_id,
model_data={"currencyRatesData": data.get('currencyRatesData'), 'date': date},
partial_upload=True, **kwargs)
sleep(2)
for risk_model_data_type in ["assetData", "issuerSpecificCovariance", "factorPortfolios"]:
_repeat_try_catch_request(_batch_data_v2, model_id=model_id, data=data.get(risk_model_data_type),
data_type=risk_model_data_type, max_asset_size=max_asset_size, date=date, **kwargs)
Expand Down
8 changes: 4 additions & 4 deletions gs_quant/risk/transform.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,15 +55,15 @@ def apply(self, results: Iterable[Union[float, FloatWithInfo, SeriesWithInfo, Da
elif isinstance(result, SeriesWithInfo):
val = getattr(result, self.risk_col).sum()
elif isinstance(result, DataFrameWithInfo):
if self.filter_coord is not None:
if result.empty:
val = 0
elif self.filter_coord is not None:
df = result.filter_by_coord(self.filter_coord)
val = getattr(df, self.risk_col).sum()
elif result.empty:
val = 0
else:
val = getattr(result, self.risk_col).sum()
else:
raise ValueError(f'Aggregation of {type(result).__name__} not currently supported')
raise ValueError(f'Aggregation of {type(result).__name__} not currently supported.')
risk_key = result.risk_key
unit = result.unit
error = result.error
Expand Down
14 changes: 13 additions & 1 deletion gs_quant/target/risk_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,9 @@ class RiskModelDataMeasure(EnumBase, Enum):
Unadjusted_Specific_Risk = 'Unadjusted Specific Risk'
Dividend_Yield = 'Dividend Yield'
Pre_VRA_Covariance_Matrix = 'Pre VRA Covariance Matrix'
Unadjusted_Covariance_Matrix = 'Unadjusted Covariance Matrix'
Unadjusted_Covariance_Matrix = 'Unadjusted Covariance Matrix'
Risk_Free_Rate = 'Risk Free Rate'
Currency_Exchange_Rate = "Currency Exchange Rate"


class RiskModelEventType(EnumBase, Enum):
Expand Down Expand Up @@ -206,6 +208,15 @@ class RiskModelIssuerSpecificCovarianceData(Base):
name: Optional[str] = field(default=None, metadata=name_metadata)


@handle_camel_case_args
@dataclass_json(letter_case=LetterCase.CAMEL)
@dataclass(unsafe_hash=True, repr=False)
class RiskModelCurrencyRatesData(Base):
currency: Tuple[str, ...] = field(default=None, metadata=field_metadata)
exchangeRate: Tuple[float, ...] = field(default=None, metadata=field_metadata)
risk_free_rate: Tuple[float, ...] = field(default=None, metadata=field_metadata)


@handle_camel_case_args
@dataclass_json(letter_case=LetterCase.CAMEL)
@dataclass(unsafe_hash=True, repr=False)
Expand Down Expand Up @@ -311,6 +322,7 @@ class RiskModelData(Base):
pre_vra_covariance_matrix: Optional[Tuple[Tuple[float, ...], ...]] = field(default=None, metadata=config(field_name='preVRACovarianceMatrix', exclude=exclude_none))
unadjusted_covariance_matrix: Optional[Tuple[Tuple[float, ...], ...]] = field(default=None, metadata=field_metadata)
issuer_specific_covariance: Optional[RiskModelIssuerSpecificCovarianceData] = field(default=None, metadata=field_metadata)
currency_rates_data: Optional[RiskModelCurrencyRatesData] = field(default=None, metadata=field_metadata)
factor_portfolios: Optional[RiskModelFactorPortfoliosData] = field(default=None, metadata=field_metadata)
name: Optional[str] = field(default=None, metadata=name_metadata)

Expand Down
Loading

0 comments on commit e9e365e

Please sign in to comment.