Skip to content

Commit

Permalink
Chore: Make release 1.0.104
Browse files Browse the repository at this point in the history
  • Loading branch information
martinroberson committed Jul 31, 2024
1 parent 76b62c1 commit 8285cc6
Show file tree
Hide file tree
Showing 4 changed files with 34 additions and 32 deletions.
1 change: 1 addition & 0 deletions gs_quant/backtests/actions.py
Original file line number Diff line number Diff line change
Expand Up @@ -278,6 +278,7 @@ class HedgeAction(Action):
class_type: str = static_field('hedge_action')

def __post_init__(self):
super().__post_init__()
self._calc_type = CalcType.semi_path_dependent
if isinstance(self.priceables, Portfolio):
named_priceables = []
Expand Down
55 changes: 27 additions & 28 deletions gs_quant/backtests/generic_engine.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
from gs_quant.risk.results import PortfolioRiskResult
from gs_quant.target.backtests import BacktestTradingQuantityType
from gs_quant.common import AssetClass
from gs_quant.target.measures import ResolvedInstrumentValues
from gs_quant.tracing import Tracer

# priority set to contexts making requests to the pricing API (min. 1 - max. 10)
Expand Down Expand Up @@ -113,7 +114,7 @@ class AddScaledTradeActionImpl(ActionHandler):
def __init__(self, action: AddScaledTradeAction):
super().__init__(action)

def _nav_scale_orders(self, orders, first_quantity):
def _nav_scale_orders(self, orders):
sorted_order_days = sorted(make_list(orders.keys()))
final_days_orders = {}

Expand All @@ -126,7 +127,7 @@ def _nav_scale_orders(self, orders, first_quantity):
final_days_orders[d].append(inst)

# Start with first_quantity, then only use proceeds from selling instruments
available_cash = first_quantity
available_cash = self.action.scaling_level

# Go through each order day of the strategy in sorted order
for idx, cur_day in enumerate(sorted_order_days):
Expand Down Expand Up @@ -165,48 +166,45 @@ def _nav_scale_orders(self, orders, first_quantity):
for val in unwind_vals:
available_cash += val.result()

def _scale_order(self, orders, scaling_type, scaling_risk, scaling_level):
if scaling_type == ScalingActionType.size:
def _scale_order(self, orders, daily_risk):
if self.action.scaling_type == ScalingActionType.size:
for _, portfolio in orders.items():
portfolio.scale(scaling_level)
elif scaling_type == ScalingActionType.NAV:
self._nav_scale_orders(orders, scaling_level)
elif scaling_type == ScalingActionType.risk_measure:
# Scale risk daily risk to specified value otherwise
orders_risk = {}
with PricingContext():
for day, portfolio in orders.items():
with PricingContext(pricing_date=day):
orders_risk[day] = portfolio.calc(scaling_risk)

portfolio.scale(self.action.scaling_level)
elif self.action.scaling_type == ScalingActionType.NAV:
self._nav_scale_orders(orders)
elif self.action.scaling_type == ScalingActionType.risk_measure:
for day, portfolio in orders.items():
risk_to_scale = orders_risk[day].aggregate()
scaling_factor = scaling_level / risk_to_scale
scaling_factor = self.action.scaling_level / daily_risk[day]
portfolio.scale(scaling_factor)
else:
raise RuntimeError(f'Scaling Type {scaling_type} not supported by engine')
raise RuntimeError(f'Scaling Type {self.action.scaling_type} not supported by engine')

def _raise_order(self,
state: Union[date, Iterable[date]]):
state_list = make_list(state)
orders = {}

order_valuations = (ResolvedInstrumentValues,)
if self.action.scaling_type == ScalingActionType.risk_measure:
order_valuations += (self.action.scaling_risk,)
with PricingContext():
for s in state_list:
active_portfolio = self.action.priceables
with PricingContext(pricing_date=s):
orders[s] = Portfolio(active_portfolio).resolve(in_place=False)
orders[s] = Portfolio(self.action.priceables).calc(order_valuations)

final_orders = {}
for d, p in orders.items():
for d, res in orders.items():
new_port = []
for t in p.result():
t.name = f'{t.name}_{d}'
new_port.append(t)
for inst in self.action.priceables:
new_inst = res[inst]
if len(order_valuations) > 1:
new_inst = new_inst[ResolvedInstrumentValues]
new_inst.name = f'{new_inst.name}_{d}'
new_port.append(new_inst)
final_orders[d] = Portfolio(new_port)
daily_risk = {d: res[self.action.scaling_risk].aggregate() for d, res in orders.items()} if \
self.action.scaling_type == ScalingActionType.risk_measure else None

self._scale_order(final_orders, self.action.scaling_type,
self.action.scaling_risk, self.action.scaling_level)
self._scale_order(final_orders, daily_risk)

return final_orders

Expand Down Expand Up @@ -576,6 +574,7 @@ def is_eq_underlier(leg):
if hasattr(leg, 'asset_class'):
return isinstance(leg.asset_class, AssetClass) and leg.asset_class == AssetClass.Equity
return leg.__class__.__name__.lower().startswith('eq')

if isinstance(action, EnterPositionQuantityScaledAction) and \
not all([is_eq_underlier(p) for p in action.priceables]):
raise RuntimeError('EnterPositionQuantityScaledAction only supported for equity underliers')
Expand Down Expand Up @@ -620,7 +619,7 @@ def new_pricing_context(self):

context = PricingContext(set_parameters_only=True, show_progress=show_progress, csa_term=csa_term,
market_data_location=market_data_location, request_priority=request_priority,
is_batch=is_batch)
is_batch=is_batch, use_historical_diddles_only=True)

context._max_concurrent = 10000

Expand Down
6 changes: 3 additions & 3 deletions gs_quant/markets/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ def __init__(self,
use_server_cache: Optional[bool] = None,
market_behaviour: Optional[str] = 'ContraintsBased',
set_parameters_only: bool = False,
use_historical_diddles_only: bool = False,
use_historical_diddles_only: Optional[bool] = None,
provider: Optional[Type[GenericRiskApi]] = None):
"""
The methods on this class should not be called directly. Instead, use the methods on the instruments,
Expand Down Expand Up @@ -382,7 +382,7 @@ def __risk_key(self, risk_measure: RiskMeasure, provider: type) -> RiskKey:
def _parameters(self) -> RiskRequestParameters:
return RiskRequestParameters(csa_term=self.__csa_term, raw_results=True,
market_behaviour=self.__market_behaviour,
use_historical_diddles_only=self.__use_historical_diddles_only)
use_historical_diddles_only=self.use_historical_diddles_only)

@property
def _scenario(self) -> Optional[MarketDataScenario]:
Expand Down Expand Up @@ -497,7 +497,7 @@ def set_parameters_only(self) -> bool:
def use_historical_diddles_only(self) -> bool:
if self.__use_historical_diddles_only is not None:
return self.__use_historical_diddles_only
return self._inherited_val('self.__use_historical_diddles_only', default=False)
return self._inherited_val('use_historical_diddles_only', default=False)

def clone(self, **kwargs):
clone_kwargs = {k: getattr(self, k, None) for k in signature(self.__init__).parameters.keys()}
Expand Down
4 changes: 3 additions & 1 deletion gs_quant/test/markets/test_pricing_context.py
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ def test_creation():
def test_inheritance():
c1 = PricingContext(pricing_date=datetime.date(2022, 6, 16), market_data_location='NYC', provider=TestProvider)
c2 = PricingContext(pricing_date=datetime.date(2022, 7, 1))
c3 = PricingContext()
c3 = PricingContext(use_historical_diddles_only=True)

with c1:
with c2:
Expand All @@ -170,6 +170,7 @@ def test_inheritance():
assert c2.is_batch is False
assert c2.use_cache is False
assert c2._max_concurrent == 1000
assert not c2.use_historical_diddles_only
with c3:
# market data location is inherited from c1 (the active context)
assert c3.market_data_location == c1.market_data_location
Expand All @@ -179,6 +180,7 @@ def test_inheritance():
assert c3.is_batch is False
assert c3.use_cache is False
assert c3._max_concurrent == 1000
assert c3.use_historical_diddles_only


def test_max_concurrent():
Expand Down

0 comments on commit 8285cc6

Please sign in to comment.