Skip to content

Commit

Permalink
Chore: Make release 1.2.10
Browse files Browse the repository at this point in the history
  • Loading branch information
martinroberson authored and Vanden Bon, David V [GBM Public] committed Dec 16, 2024
1 parent cb3d056 commit cc003d9
Show file tree
Hide file tree
Showing 7 changed files with 202 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,20 @@ class TransactionDirection(Enum):
Exit = 'Exit'


class RollDateMode(Enum):
OTC = 'OTC'
Listed = 'Listed'

@classmethod
def _missing_(cls, value):
if value is None:
return None
for member in cls:
if member.value.lower() == value.lower():
return member
return None


@dataclass_json(letter_case=LetterCase.CAMEL)
@dataclass
class Transaction:
Expand Down Expand Up @@ -103,3 +117,4 @@ class Configuration:
market_data_location: Optional[PricingLocation] = None
market_model: Optional[EquityMarketModel] = None
cash_accrual: bool = False
roll_date_mode: Optional[RollDateMode] = None
1 change: 1 addition & 0 deletions gs_quant/api/gs/data.py
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,7 @@ class QueryType(Enum):
COVARIANCE = "Covariance"
FACTOR_EXPOSURE = "Factor Exposure"
FACTOR_RETURN = "Factor Return"
HISTORICAL_BETA = "Historical Beta"
FACTOR_PNL = "Factor Pnl"
FACTOR_PROPORTION_OF_RISK = "Factor Proportion Of Risk"
DAILY_RISK = "Daily Risk"
Expand Down
7 changes: 5 additions & 2 deletions gs_quant/backtests/strategy_systematic.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
from gs_quant.api.gs.backtests_xasset.apis import GsBacktestXassetApi
from gs_quant.api.gs.backtests_xasset.request import BasicBacktestRequest
from gs_quant.api.gs.backtests_xasset.response_datatypes.backtest_datatypes import DateConfig, Trade, \
CostPerTransaction, TransactionCostModel
CostPerTransaction, TransactionCostModel, Configuration, RollDateMode
from gs_quant.backtests.core import Backtest, TradeInMethod
from gs_quant.errors import MqValueError
from gs_quant.target.backtests import *
Expand Down Expand Up @@ -121,6 +121,8 @@ def __init__(self,
self.__trades = (Trade(tuple(trade_instruments), roll_frequency, trade_buy_dates, roll_frequency,
trade_exit_dates, quantity, quantity_type),)
self.__delta_hedge_frequency = '1b' if delta_hedge else None
self.__xasset_bt_service_config = Configuration(roll_date_mode=RollDateMode(roll_date_mode) if
roll_date_mode is not None else None)

backtest_parameters_class: Base = getattr(backtests, self.__backtest_type + 'BacktestParameters')
backtest_parameter_args = {
Expand Down Expand Up @@ -154,7 +156,8 @@ def __run_service_based_backtest(self, start: datetime.date, end: datetime.date,
if not calc_measures:
calc_measures = (FlowVolBacktestMeasure.PNL,)
basic_bt_request = BasicBacktestRequest(date_cfg, self.__trades, calc_measures, self.__delta_hedge_frequency,
CostPerTransaction(TransactionCostModel.Fixed, 0), None)
CostPerTransaction(TransactionCostModel.Fixed, 0),
self.__xasset_bt_service_config)
basic_bt_response = GsBacktestXassetApi.calculate_basic_backtest(basic_bt_request, decode_instruments=False)
risks = tuple(
BacktestRisk(name=k.value,
Expand Down
2 changes: 2 additions & 0 deletions gs_quant/session.py
Original file line number Diff line number Diff line change
Expand Up @@ -496,6 +496,8 @@ def _headers(self):
def _get_mds_domain(self):
env_config = GsSession._config_for_environment(self.environment.name)
current_domain = self.domain.replace('marquee.web', 'marquee') # remove .web from prod domain
if self.environment.name == Environment.QA.name:
current_domain = self.domain.replace('marquee-qa.web', 'marquee-qa') # remove .web from qa domain

is_mds_web = current_domain == Domain.MDS_WEB
is_env_mds_web = current_domain == env_config['MdsWebDomain']
Expand Down
14 changes: 14 additions & 0 deletions gs_quant/target/workflow_quote.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,18 @@ class PriceFormat(EnumBase, Enum):
Cents = 'Cents'


class RelativeExpiryType(EnumBase, Enum):
Relative = 'Relative'
Fixed = 'Fixed'


class RelativeStrikeType(EnumBase, Enum):
Relative_Delta = 'Relative Delta'
Relative_Spot = 'Relative Spot'
Relative_Fwd = 'Relative Fwd'
Fixed = 'Fixed'


@dataclass
class HedgeTypes(Base):
pass
Expand Down Expand Up @@ -284,6 +296,8 @@ class WorkflowPosition(Base):
creator: Optional[str] = field(default=None, metadata=field_metadata)
originating_system: Optional[str] = field(default=None, metadata=field_metadata)
is_read_only: Optional[bool] = field(default=None, metadata=field_metadata)
strike_and_barrier_type: Optional[RelativeStrikeType] = field(default=None, metadata=field_metadata)
expiry_type: Optional[RelativeExpiryType] = field(default=None, metadata=field_metadata)
name: Optional[str] = field(default=None, metadata=name_metadata)


Expand Down
45 changes: 45 additions & 0 deletions gs_quant/test/timeseries/test_measures_risk_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,51 @@ def mock_risk_model():
return actual


def test_risk_model_measure():
replace = Replacer()

# mock getting risk model entity()
mock = replace('gs_quant.api.gs.risk_models.GsRiskModelApi.get_risk_model', Mock())
mock.return_value = mock_risk_model_obj

# mock getting risk model factor entity
mock = replace('gs_quant.api.gs.risk_models.GsFactorRiskModelApi.get_risk_model_data', Mock())
mock.return_value = mock_risk_model_data

# mock getting risk model factor entity
mock = replace('gs_quant.api.gs.risk_models.GsFactorRiskModelApi.get_risk_model_factor_data', Mock())
mock.return_value = mock_risk_model_factor_data

# mock getting asset gsid
mock = replace('gs_quant.markets.securities.Asset.get_identifier', Mock())
mock.return_value = '14593'

# mock getting risk model dates
mock = replace('gs_quant.api.gs.risk_models.GsRiskModelApi.get_risk_model_dates', Mock())
mock.return_value = ['2020-01-01', '2020-01-02', '2020-01-03']

# mock getting risk model data
mock = replace('gs_quant.models.risk_model.MarqueeRiskModel.get_data', Mock())
mock.return_value = {
'totalResults': 3,
'missingDates': [],
'results': [
{'date': '2024-08-19', 'assetData': {'universe': ['14593'], 'bidAskSpread30d': [0.1]}},
{'date': '2024-08-20', 'assetData': {'universe': ['14593'], 'bidAskSpread30d': [0.2]}},
{'date': '2024-08-21', 'assetData': {'universe': ['14593'], 'bidAskSpread30d': [0.3]}}
]
}

with DataContext(datetime.date(2020, 1, 1), datetime.date(2020, 1, 3)):
actual = mrm.risk_model_measure(Stock(id_='id', name='Fake Asset'), 'model_id',
mrm.ModelMeasureString.BID_AKS_SPREAD_30D)
assert all(actual.values == [0.1, 0.2, 0.3])

with pytest.raises(AttributeError):
mrm.risk_model_measure(Stock(id_='id', name='Fake Asset'), 'model_id', 'Wrong Factor Name')
replace.restore()


def test_factor_zscore():
replace = Replacer()

Expand Down
120 changes: 120 additions & 0 deletions gs_quant/timeseries/measures_risk_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,11 @@
specific language governing permissions and limitations
under the License.
"""
from enum import Enum
from typing import Dict, Optional

import pandas as pd
import datetime as dt
from pydash import decapitalize

from gs_quant.api.gs.data import QueryType
Expand All @@ -30,6 +32,124 @@
from gs_quant.timeseries import plot_measure_entity, plot_measure, prices
from gs_quant.timeseries.measures import _extract_series_from_df

ModelMeasureStr = {
'Asset Universe': RiskModelDataMeasure.Asset_Universe,
'Historical Beta': RiskModelDataMeasure.Historical_Beta,
'Total Risk': RiskModelDataMeasure.Total_Risk,
'Specific Risk': RiskModelDataMeasure.Specific_Risk,
'Specific Return': RiskModelDataMeasure.Specific_Return,
'Daily Returns': RiskModelDataMeasure.Daily_Return,
'Estimation Universe Weight': RiskModelDataMeasure.Estimation_Universe_Weight,
'Residual Variance': RiskModelDataMeasure.Residual_Variance,
'Predicted Beta': RiskModelDataMeasure.Predicted_Beta,
'Global Predicted Beta': RiskModelDataMeasure.Global_Predicted_Beta,
'Universe Factor Exposure': RiskModelDataMeasure.Universe_Factor_Exposure,
'R Squared': RiskModelDataMeasure.R_Squared,
'Fair Value Gap Percent': RiskModelDataMeasure.Fair_Value_Gap_Percent,
'Fair Value Gap Standard Deviation': RiskModelDataMeasure.Fair_Value_Gap_Standard_Deviation,
'Bid Ask Spread': RiskModelDataMeasure.Bid_Ask_Spread,
'Bid Ask Spread 30d': RiskModelDataMeasure.Bid_Ask_Spread_30d,
'Bid Ask Spread 60d': RiskModelDataMeasure.Bid_Ask_Spread_60d,
'Bid Ask Spread 90d': RiskModelDataMeasure.Bid_Ask_Spread_90d,
'Trading Volume': RiskModelDataMeasure.Trading_Volume,
'Trading Volume 30d': RiskModelDataMeasure.Trading_Volume_30d,
'Trading Volume 60d': RiskModelDataMeasure.Trading_Volume_60d,
'Trading Volume 90d': RiskModelDataMeasure.Trading_Volume_90d,
'Trading Value 30d': RiskModelDataMeasure.Traded_Value_30d,
'Composite Volume': RiskModelDataMeasure.Composite_Volume,
'Composite Volume 30d': RiskModelDataMeasure.Composite_Volume_30d,
'Composite Volume 60d': RiskModelDataMeasure.Composite_Volume_60d,
'Composite Volume 90d': RiskModelDataMeasure.Composite_Volume_90d,
'Composite Value 30d': RiskModelDataMeasure.Composite_Value_30d,
'Composite Issuer Market Cap': RiskModelDataMeasure.Issuer_Market_Cap,
'Composite Price': RiskModelDataMeasure.Price,
'Composite Model Price': RiskModelDataMeasure.Model_Price,
'Composite Capitalization': RiskModelDataMeasure.Capitalization,
'Composite Currency': RiskModelDataMeasure.Currency,
'Composite Unadjusted Specific Risk': RiskModelDataMeasure.Unadjusted_Specific_Risk,
'Dividend Yield': RiskModelDataMeasure.Dividend_Yield}


class ModelMeasureString(Enum):
ASSET_UNIVERSE = 'Asset Universe'
HISTORICAL_BETA = 'Historical Beta'
TOTAL_RISK = 'Total Risk'
SPECIFIC_RISK = 'Specific Risk'
SPECIFIC_RETURNS = 'Specific Return'
DAILY_RETURNS = 'Daily Returns'
ESTIMATION_UNVERSE_WEIGHT = 'Estimation Universe Weight'
RESIDUAL_VARIANCE = 'Residual Variance'
PREDICTED_BETA = 'Predicted Beta'
GLOBAL_PREDICTED_BETA = 'Global Predicted Beta'
UNIVERSE_FACTOR_EXPOSURE = 'Universe Factor Exposure'
R_SQUARED = 'R Squared'
FAIR_VALUE_GAP_PERCENT = 'Fair Value Gap Percent'
FAIR_VALUE_GAP_STANDARD_DEVIATION = 'Fair Value Gap Standard Deviation'
BID_ASK_SPREAD = 'Bid Ask Spread'
BID_AKS_SPREAD_30D = 'Bid Ask Spread 30d'
BID_AKS_SPREAD_60D = 'Bid Ask Spread 60d'
BID_AKS_SPREAD_90D = 'Bid Ask Spread 90d'
TRADING_VOLUME = 'Trading Volume'
TRADING_VOLUME_30D = 'Trading Volume 30d'
TRADING_VOLUME_60D = 'Trading Volume 60d'
TRADING_VOLUME_90D = 'Trading Volume 90d'
TRADING_VALUE_30D = 'Trading Value 30d'
COMPOSITE_VOLUME = 'Composite Volume'
COMPOSITE_VOLUME_30D = 'Composite Volume 30d'
COMPOSITE_VOLUME_60D = 'Composite Volume 60d'
COMPOSITE_VOLUME_90D = 'Composite Volume 90d'
COMPOSITE_VALUE_30d = 'Composite Value 30d'
COMPOSITE_ISSUER_MARKET_CAP = 'Composite Issuer Market Cap'
COMPOSITE_PRICE = 'Composite Price'
COMPOSITE_MODEL_PRICE = 'Composite Model Price'
COMPOSITE_CAPITALIZATION = 'Composite Capitalization'
COMPOSITE_CURRENCY = 'Composite Currency'
COMPOSITE_UNADJUSTED_SPECIFIC_RISK = 'Composite Unadjusted Specific Risk'
DIVIDEND_YIELD = 'Dividend Yield'


@plot_measure((AssetClass.Equity,), (AssetType.Single_Stock,), [QueryType.HISTORICAL_BETA])
def risk_model_measure(asset: Asset, risk_model_id: str,
risk_model_measure_selected: ModelMeasureString = ModelMeasureString.HISTORICAL_BETA,
start_date: dt.date = dt.date.today(),
end_date: dt.date = dt.date.today() - dt.timedelta(7), *,
source: str = None, real_time: bool = False, request_id: Optional[str] = None) -> pd.Series:
"""
Retrieve risk model measures for a given asset.
:param asset: Asset object loaded from security master
:param risk_model_id: ID of the risk model
:param risk_model_measure_selected: Selected risk model measure
:param start_date: Start date for the data retrieval
:param end_date: End date for the data retrieval
:param source: Name of function caller
:param real_time: Whether to retrieve intraday data instead of EOD
:param request_id: Service request ID, if any
:return: Risk model measure data for the asset
"""
model = MarqueeRiskModel.get(risk_model_id)
gsid = asset.get_identifier(AssetIdentifier.GSID)
risk_model_measure_selected = ModelMeasureStr[risk_model_measure_selected.value]

query_results = model.get_data(
measures=[risk_model_measure_selected,
RiskModelDataMeasure.Asset_Universe],
start_date=start_date,
end_date=end_date,
assets=RiskModelDataAssetsRequest(identifier=RiskModelUniverseIdentifierRequest.gsid, universe=[gsid]),
limit_factors=False
).get('results', [])

measures = {}
for result in query_results:
if result:
measure_name = set(result.get('assetData', {}).keys()).difference({'universe'})
exposures = result.get('assetData', {}).get(measure_name.pop(), [])
if exposures:
measures[result['date']] = exposures[0]

return __format_plot_measure_results(measures, QueryType.FACTOR_EXPOSURE)


@plot_measure((AssetClass.Equity,), (AssetType.Single_Stock,))
def factor_zscore(asset: Asset, risk_model_id: str, factor_name: str, *,
Expand Down

0 comments on commit cc003d9

Please sign in to comment.