Пример #1
0
    def update(self) -> Dict:
        """
        Update your custom basket

        :return: dictionary containing asset id and report id

        **Usage**

        Make updates to your basket's metadata, pricing options, publishing options, or composition

        **See also**

        :func:`get_details` :func:`poll_status` :func:`create`

        """
        self.__finish_populating_attributes_for_existing_basket()
        edit_inputs, rebal_inputs = self.__get_updates()
        if edit_inputs is None and rebal_inputs is None:
            raise MqValueError('Update failed: Nothing on the basket was changed')
        elif edit_inputs is not None and rebal_inputs is None:
            response = GsIndexApi.edit(self.id, edit_inputs)
        elif rebal_inputs is not None and edit_inputs is None:
            response = GsIndexApi.rebalance(self.id, rebal_inputs)
        else:
            response = self.__edit_and_rebalance(edit_inputs, rebal_inputs)
        gs_asset = GsAssetApi.get_asset(self.id)
        self.__latest_create_report = GsReportApi.get_report(response.report_id)
        self.__error_messages.remove(ErrorMessage.UNMODIFIABLE)
        self.__init__(gs_asset=gs_asset)
        return response.as_dict()
Пример #2
0
 def __validate_ticker(self, ticker: str):
     """ Blocks ticker setter if entry is invalid """
     if not len(ticker) == 8:
         raise MqValueError('Invalid ticker: must be 8 characters')
     GsIndexApi.validate_ticker(ticker)
     if not ticker[:2] == 'GS':
         _logger.info('Remember to prefix your ticker with \'GS\' if you\'d like to \
             publish your basket to Bloomberg')
Пример #3
0
 def __edit_and_rebalance(self, edit_inputs: CustomBasketsEditInputs,
                          rebal_inputs: CustomBasketsRebalanceInputs) -> CustomBasketsResponse:
     """ If updates require edit and rebalance, rebal will not be scheduled until/if edit report succeeds """
     _logger.info('Current update request requires multiple reports. Your rebalance request will be submitted \
                   once the edit report has completed. Submitting basket edits now...')
     response = GsIndexApi.edit(self.id, edit_inputs)
     report_id = response.report_id
     self.__latest_create_report = GsReportApi.get_report(response.report_id)
     report_status = self.poll_report(report_id, timeout=600, step=15)
     if report_status != ReportStatus.done:
         raise MqError(f'The basket edit report\'s status is {status}. The current rebalance request will \
                         not be submitted in the meantime.')
     _logger.info('Your basket edits have completed successfuly. Submitting rebalance request now...')
     response = GsIndexApi.rebalance(self.id, rebal_inputs)
     return response
Пример #4
0
    def get_latest_rebalance_date(self) -> dt.date:
        """
        Retrieve the most recent rebalance date for a basket

        :return: dictionary

        **Usage**

        Retrieve the most recent rebalance date for a basket

        **Examples**

        Retrieve the most recent rebalance date for a basket

        >>> from gs_quant.markets.baskets import Basket
        >>>
        >>> basket = Basket.get("GSMBXXXX")
        >>> basket.get_latest_rebalance_date()

        **See also**

        :func:`get_latest_rebalance_data`
        """
        last_rebalance = GsIndexApi.last_rebalance_data(self.id)
        return dt.datetime.strptime(last_rebalance['date'], '%Y-%m-%d').date()
Пример #5
0
    def get_rebalance_approval_status(self) -> str:
        """
        Retrieve the most recent rebalance submission's approval status

        :return: current approval status

        **Usage**

        Retrieve the most recent rebalance submission's approval status

        **Examples**

        Retrieve the most recent rebalance submission's approval status

        >>> from gs_quant.markets.baskets import Basket
        >>>
        >>> basket = Basket.get("GSMBXXXX")
        >>> basket.get_rebalance_approval_status()

        **See also**

        :func:`cancel_rebalance` :func:`poll_report`
        """
        last_approval = GsIndexApi.last_rebalance_approval(self.id)
        return get(last_approval, 'status')
Пример #6
0
    def add_factor_risk_report(self, risk_model_id: str, fx_hedged: bool):
        """
        Create and schedule a new factor risk report for your basket

        :param risk_model_id: risk model identifier
        :param fx_hedged: Assume basket is FX hedged

        **Usage**

        Create and schedule a new factor risk report for your basket

        **Examples**

        >>> from gs_quant.markets.baskets import Basket
        >>>
        >>> basket = Basket.get("GSMBXXXX")
        >>> basket.add_factor_risk_report('AXUS4M', True)

        **See also**

        :func:`delete_factor_risk_report`
        """
        payload = CustomBasketRiskParams(risk_model=risk_model_id,
                                         fx_hedged=fx_hedged)
        return GsIndexApi.update_risk_reports(payload)
Пример #7
0
    def create(self) -> Dict:
        """
        Create a new custom basket in Marquee

        :return: dictionary containing asset id and report id

        **Usage**

        Create a new custom basket in Marquee

        **See also**

        :func:`get_details` :func:`poll_status` :func:`update`

        """
        inputs, pricing, publish = {}, {}, {}
        for prop in CustomBasketsCreateInputs.properties():
            set_(inputs, prop, get(self, prop))
        for prop in CustomBasketsPricingParameters.properties():
            set_(pricing, prop, get(self, prop))
        for prop in PublishParameters.properties():
            set_(publish, prop, get(self, prop))
        set_(inputs, 'position_set', self.position_set.to_target(common=False))
        set_(inputs, 'pricing_parameters',
             CustomBasketsPricingParameters(**pricing))
        set_(inputs, 'publish_parameters', PublishParameters(**publish))
        create_inputs = CustomBasketsCreateInputs(**inputs)

        response = GsIndexApi.create(create_inputs)
        gs_asset = GsAssetApi.get_asset(response.asset_id)
        self.__latest_create_report = GsReportApi.get_report(
            response.report_id)
        self.__init__(gs_asset=gs_asset, _finish_init=True)
        return response.as_dict()
Пример #8
0
    def __populate_current_attributes_for_existing_basket(
            self, gs_asset: GsAsset):
        self.__description = get(gs_asset, 'description', None)
        self.__gs_asset_type = get(gs_asset, 'type', None)
        self.__live_date = get(gs_asset, 'live_date', None)
        self.__ticker = get(gs_asset, 'xref.ticker', None)

        self.__clone_parent_id = get(gs_asset, 'parameters.clone_parent_id',
                                     None)
        self.__default_backcast = get(gs_asset, 'parameters.default_backcast',
                                      None)
        self.__flagship = get(gs_asset, 'parameters.flagship', None)
        self.__hedge_id = get(gs_asset, 'parameters.hedge_id', None)
        self.__return_type = get(gs_asset, 'parameters.index_calculation_type',
                                 None)

        last_positions = GsAssetApi.get_latest_positions(self.__id)
        self.__divisor = get(last_positions, 'divisor', None)
        last_initial_price = GsIndexApi.initial_price(gs_asset.id,
                                                      DateLimit.TODAY.value)
        self.__initial_price = get(last_initial_price, 'price', None)

        report = self.__get_last_create_report()
        self.__include_price_history = get(report,
                                           'parameters.include_price_history',
                                           None)
        self.__publish_to_bloomberg = get(report,
                                          'parameters.publish_to_bloomberg',
                                          None)
        self.__publish_to_factset = get(report,
                                        'parameters.publish_to_factset', None)
        self.__publish_to_reuters = get(report,
                                        'parameters.publish_to_reuters', None)
Пример #9
0
def test_get_asset_positions_data(mocker):
    marquee_id = 'MQA1234567890'
    position_date = dt.date(2019, 2, 19)

    mock_response = {
        'results': [
            {
                'underlyingAssetId': 'MA4B66MW5E27UAFU2CD',
                'divisor': 8305900333.262549,
                'quantity': 0.016836826158,
                'positionType': 'close',
                'bbid': 'EXPE UW',
                'assetId': 'MA4B66MW5E27U8P32SB',
                'positionDate': '2019-11-07',
                'assetClassificationsGicsSector': 'Consumer Discretionary',
                'closePrice': 98.29,
                'ric': 'EXPE.OQ'
            },
        ]
    }

    expected_response = [
        {
            'underlyingAssetId': 'MA4B66MW5E27UAFU2CD',
            'divisor': 8305900333.262549,
            'quantity': 0.016836826158,
            'positionType': 'close',
            'bbid': 'EXPE UW',
            'assetId': 'MA4B66MW5E27U8P32SB',
            'positionDate': '2019-11-07',
            'assetClassificationsGicsSector': 'Consumer Discretionary',
            'closePrice': 98.29,
            'ric': 'EXPE.OQ'
        },
    ]

    # mock GsSession
    mocker.patch.object(GsSession.__class__,
                        'default_value',
                        return_value=GsSession.get(Environment.QA, 'client_id',
                                                   'secret'))
    mocker.patch.object(GsSession.current, '_get', return_value=mock_response)

    # run test
    response = GsIndexApi.get_positions_data(marquee_id, position_date,
                                             position_date)

    position_date_str = position_date.isoformat()
    GsSession.current._get.assert_called_with(
        '/indices/{id}/positions/data?startDate={start_date}&endDate={end_date}'
        .format(id=marquee_id,
                start_date=position_date_str,
                end_date=position_date_str))

    testfixtures.compare(response, expected_response)
Пример #10
0
def test_basket_initial_price(mocker):
    # construct mock response
    mock_response = {'price': 100}

    # setup mock session and api response
    mock_session()
    mocker.return_value = mock_response

    # run test
    response = GsIndexApi.initial_price(basket_id, date)
    assert response == mock_response
Пример #11
0
def test_basket_last_rebalance_data(mocker):
    # construct mock response
    mock_response = {'reportId': report_id, 'assetId': basket_id}

    # setup mock session and api response
    mock_session()
    mocker.return_value = mock_response

    # run test
    response = GsIndexApi.last_rebalance_data(basket_id)
    assert response == mock_response
Пример #12
0
def test_basket_rebalance(mocker):
    # construct inputs and mock response
    inputs = CustomBasketsRebalanceInputs(position_set, pricing_parameters)
    mock_response = CustomBasketsResponse(report_id, basket_id, 'done')

    # setup mock session and api response
    mock_session()
    mocker.return_value = mock_response

    # run test
    response = GsIndexApi.rebalance(basket_id, AssetType.Custom_Basket, inputs)
    assert response == mock_response
Пример #13
0
def test_basket_edit(mocker):
    # construct inputs and mock response
    inputs = CustomBasketsEditInputs(name=name, flagship=True)
    mock_response = CustomBasketsResponse(report_id, basket_id, 'done')

    # setup mock session and api response
    mock_session()
    mocker.return_value = mock_response

    # run test
    response = GsIndexApi.edit(basket_id, inputs)
    assert response == mock_response
Пример #14
0
def test_basket_cancel_rebalance(mocker):
    # construct inputs and mock response
    inputs = CustomBasketsRebalanceAction(comment='test cancel')
    mock_response = f'Rebalance submission for {basket_id} has been cancelled'

    # setup mock session and api response
    mock_session()
    mocker.return_value = mock_response

    # run test
    response = GsIndexApi.cancel_rebalance(basket_id, inputs)
    assert response == mock_response
Пример #15
0
 def get_positions_data(
         self,
         start: dt.date = DateLimit.LOW_LIMIT.value,
         end: dt.date = dt.date.today(),
         fields: [str] = None,
         position_type: PositionType = PositionType.CLOSE) -> List[Dict]:
     if self.positioned_entity_type == EntityType.ASSET:
         return GsIndexApi.get_positions_data(self.id, start, end, fields,
                                              position_type)
     if self.positioned_entity_type == EntityType.PORTFOLIO:
         return GsPortfolioApi.get_positions_data(self.id, start, end,
                                                  fields, position_type)
     raise NotImplementedError
Пример #16
0
    def update(self) -> Dict:
        """
        Update your custom basket

        :return: dictionary containing asset id and report id

        **Usage**

        Make updates to your basket's metadata, pricing options, publishing options, or composition

        **See also**

        :func:`get_details` :func:`poll_status` :func:`create`

        """
        edit_inputs, rebal_inputs = self.__get_updates()
        entitlements = self.__entitlements.to_target()
        response = None
        if not entitlements == self.__initial_entitlements:
            response = GsAssetApi.update_asset_entitlements(
                self.id, entitlements)
        if edit_inputs is None and rebal_inputs is None:
            if response:
                return response.as_dict()
            raise MqValueError(
                'Update failed: Nothing on the basket was changed')
        elif edit_inputs is not None and rebal_inputs is None:
            response = GsIndexApi.edit(self.id, edit_inputs)
        elif rebal_inputs is not None and edit_inputs is None:
            response = GsIndexApi.rebalance(self.id, rebal_inputs)
        else:
            response = self.__edit_and_rebalance(edit_inputs, rebal_inputs)
        gs_asset = GsAssetApi.get_asset(self.id)
        self.__latest_create_report = GsReportApi.get_report(
            response.report_id)
        self.__init__(gs_asset=gs_asset, _finish_init=True)
        return response.as_dict()
Пример #17
0
def test_basket_create(mocker):
    # construct inputs and mock response
    inputs = CustomBasketsCreateInputs(name,
                                       position_set,
                                       pricing_parameters,
                                       return_type,
                                       ticker,
                                       publish_parameters=publish_parameters)
    mock_response = CustomBasketsResponse(report_id, basket_id, 'done')

    # setup mock session and api response
    mock_session()
    mocker.return_value = mock_response

    # run test
    response = GsIndexApi.create(inputs)
    assert response == mock_response
Пример #18
0
    def upload_position_history(self,
                                position_sets: List[PositionSet]) -> Dict:
        """
        Upload basket composition history

        :param position_sets: list of dated position sets
        :return: dictionary containing asset id and report id

        **Usage**

        Upload your basket's historical composition after it's been created

        **Examples**

        Upload composition history from a list of identifiers:

        >>> from datetime import date
        >>> from gs_quant.markets.baskets import Basket
        >>> from gs_quant.markets.position_set import PositionSet
        >>>
        >>> first_position_set = PositionSet.from_list(['BBID1', 'BBID2'], date(2020, 1, 1))
        >>> second_position_set = PositionSet.from_list(['BBID1','BBID2', 'BBID3'], date(2021, 1, 1))
        >>>
        >>> basket = Basket.get("GSMBXXXX")
        >>> basket.upload_position_history([first_position_set, second_position_set])

        **See also**

        :class:`PositionSet`
        """
        if self.default_backcast:
            raise MqValueError(
                'Unable to upload position history: option must be set during basket creation'
            )
        historical_position_sets = []
        for position_set in position_sets:
            positions = [
                IndicesPositionInput(p.asset_id, p.weight)
                for p in position_set.positions
            ]
            historical_position_sets.append(
                IndicesPositionSet(tuple(positions), position_set.date))
        response = GsIndexApi.backcast(
            self.id,
            CustomBasketsBackcastInputs(tuple(historical_position_sets)))
        return response.as_dict()
Пример #19
0
 def __finish_populating_attributes_for_existing_basket(self):
     """ Populates all values not originally fetched during initialization due to required API calls """
     if self.__populate_api_attrs:
         position_set = GsAssetApi.get_latest_positions(self.id, PositionType.ANY)
         report = get(self, '__latest_create_report', self.__get_latest_create_report())
         self.__divisor = get(position_set, 'divisor')
         self.__initial_price = get(GsIndexApi.initial_price(self.id, dt.date.today()), 'price')
         self.__parent_basket = None if self.__clone_parent_id is None else \
             get(GsAssetApi.get_asset(self.__clone_parent_id), 'id')
         self.__position_set = PositionSet.from_target(position_set)
         self.__publish_to_bloomberg = get(report, 'parameters.publish_to_bloomberg')
         self.__publish_to_factset = get(report, 'parameters.publish_to_factset')
         self.__publish_to_reuters = get(report, 'parameters.publish_to_reuters')
         set_(self.__initial_state, 'divisor', self.__divisor)
         set_(self.__initial_state, 'initial_price', self.__initial_price)
         set_(self.__initial_state, 'position_set', self.__position_set)
         set_(self.__initial_state, 'publish_to_bloomberg', self.__publish_to_bloomberg)
         set_(self.__initial_state, 'publish_to_factset', self.__publish_to_factset)
         set_(self.__initial_state, 'publish_to_reuters', self.__publish_to_reuters)
         self.__initial_positions = set(deepcopy(self.__position_set.positions))
         self.__populate_api_attrs = False
Пример #20
0
    def cancel_rebalance(self) -> Dict:
        """
        Cancel the most recent rebalance submission

        **Usage**

        Cancel the basket's most recent rebalance submission if it has not yet been approved

        **Examples**

        Cancel the basket's most recent rebalance submission

        >>> from gs_quant.markets.baskets import Basket
        >>>
        >>> basket = Basket.get("GSMBXXXX")
        >>> basket.cancel_rebalance()

        **See also**

        :func:`get_rebalance_approval_status` :func:`update`
        """
        return GsIndexApi.cancel_rebalance(self.id)
Пример #21
0
    def get_latest_rebalance_data(self) -> Dict:
        """
        Retrieve the most recent rebalance data for a basket

        **Usage**

        Retrieve the most recent rebalance data for a basket

        **Examples**

        Retrieve the most recent rebalance data for a basket

        >>> from gs_quant.markets.baskets import Basket
        >>>
        >>> basket = Basket.get("GSMBXXXX")
        >>> basket.get_latest_rebalance_data()

        **See also**

        :func:`get_latest_rebalance_date`
        """
        return GsIndexApi.last_rebalance_data(self.id)
Пример #22
0
 def __finish_initialization(self):
     """ Fetches remaining data not retrieved during basket initialization """
     if has(self, 'id'):
         if not has(self, '__initial_positions'):
             position_set = GsAssetApi.get_latest_positions(
                 self.id, PositionType.ANY)
             position_set = PositionSet.from_target(position_set)
             self.__position_set = position_set
             self.__divisor = get(position_set, 'divisor')
             self.__initial_positions = set(
                 deepcopy(self.__position_set.positions))
             set_(self.__initial_state, 'divisor', self.__divisor)
             set_(self.__initial_state, 'position_set', self.__position_set)
         if not has(self.__initial_state, 'initial_price'):
             initial_price = GsIndexApi.initial_price(
                 self.id, dt.date.today())
             self.__initial_price = get(initial_price, 'price')
             set_(self.__initial_state, 'initial_price',
                  self.__initial_price)
         if not has(self.__initial_state, 'publish_to_bloomberg'):
             report = get(self, '__latest_create_report',
                          self.__get_latest_create_report())
             self.__publish_to_bloomberg = get(
                 report, 'parameters.publish_to_bloomberg')
             self.__publish_to_factset = get(
                 report, 'parameters.publish_to_factset')
             self.__publish_to_reuters = get(
                 report, 'parameters.publish_to_reuters')
             set_(self.__initial_state, 'publish_to_bloomberg',
                  self.__publish_to_bloomberg)
             set_(self.__initial_state, 'publish_to_factset',
                  self.__publish_to_factset)
             set_(self.__initial_state, 'publish_to_reuters',
                  self.__publish_to_reuters)
         if not has(self, '__entitlements'):
             self.__entitlements = BasketEntitlements.from_target(
                 self.__initial_entitlements)
     self.__set_error_messages()
Пример #23
0
    def delete_factor_risk_report(self, risk_model_id: str):
        """
        Delete an existing factor risk report for your basket

        :param risk_model_id: risk model identifier for the report you'd like to delete

        **Usage**

        Delete an existing factor risk report for your basket

        **Examples**

        >>> from gs_quant.markets.baskets import Basket
        >>>
        >>> basket = Basket.get("GSMBXXXX")
        >>> basket.delete_factor_risk_report('AXUS4M')

        **See also**

        :func:`add_factor_risk_report`
        """
        payload = CustomBasketRiskParams(risk_model=risk_model_id, delete=True)
        return GsIndexApi.update_risk_reports(payload)
Пример #24
0
    def get_last_rebalance_date(self) -> dt.date:
        if not self.id:
            self.__raise_initialization_error('retrieve latest rebalance date')

        last_rebalance = GsIndexApi.last_rebalance_data(self.id)
        return dt.datetime.strptime(last_rebalance['date'], '%Y-%m-%d').date()
Пример #25
0
    def get_last_rebalance_data(self) -> Dict:
        if not self.id:
            self.__raise_initialization_error('retrieve latest rebalance data')

        return GsIndexApi.last_rebalance_data(self.id)