def test_portfolio_overrides(mocker):
    swap_1 = IRSwap("Pay", "5y", "EUR", fixed_rate=-0.005, name="5y")
    swap_2 = IRSwap("Pay", "10y", "EUR", fixed_rate=-0.005, name="10y")
    swap_3 = IRSwap("Pay", "5y", "GBP", fixed_rate=-0.005, name="5y")
    swap_4 = IRSwap("Pay", "10y", "GBP", fixed_rate=-0.005, name="10y")
    eur_port = Portfolio([swap_1, swap_2], name="EUR")
    gbp_port = Portfolio([swap_3, swap_4], name="GBP")

    # override instruments after portfolio construction
    for idx in range(len(eur_port)):
        eur_port[idx].fixed_rate = eur_port[idx].fixed_rate - 0.0005

    assert eur_port[swap_1] is not None

    with MockCalc(mocker):
        # override instruments after portfolio construction and resolution
        gbp_port.resolve()
        for idx in range(len(gbp_port)):
            gbp_port[idx].notional_amount = gbp_port[idx].notional_amount - 1

        with PricingContext(dt.date(2020, 1, 14)):
            r1 = eur_port.calc(risk.Price)
            r2 = eur_port.calc((risk.Price, risk.DollarPrice))
            r3 = gbp_port.calc(risk.Price)
            r4 = gbp_port.calc((risk.DollarPrice, risk.Price))

    assert gbp_port[swap_3] is not None

    assert r1[eur_port[0]] is not None
    assert r1['5y'] is not None
    assert r1.to_frame() is not None
    assert r2[eur_port[0]] is not None
    assert r2[risk.Price][0] is not None
    assert r2[0][risk.Price] is not None
    assert r3[gbp_port[0]] is not None
    assert r3.to_frame() is not None
    assert r4[gbp_port[0]] is not None
    assert r4[risk.DollarPrice][0] is not None
    assert r4[0][risk.DollarPrice] is not None
Beispiel #2
0
    def _raise_order(self,
                     state: Union[date, Iterable[date]],
                     trigger_info: Optional[Union[AddTradeActionInfo, Iterable[AddTradeActionInfo]]] = None):
        with PricingContext(is_batch=True, show_progress=True):
            state_list = make_list(state)
            orders = {}
            if trigger_info is None or isinstance(trigger_info, AddTradeActionInfo):
                trigger_info = [trigger_info for _ in range(len(state_list))]
            for s, ti in zip_longest(state_list, trigger_info):
                active_portfolio = self.action.dated_priceables.get(s) or self.action.priceables
                with PricingContext(pricing_date=s):
                    orders[s] = (Portfolio(active_portfolio).resolve(in_place=False), ti)
        final_orders = {}
        for d, p in orders.items():
            new_port = []
            for t in p[0].result():
                t.name = f'{t.name}_{d}'
                new_port.append(t)
            new_port = Portfolio(new_port)
            final_orders[d] = new_port.scale(None if p[1] is None else p[1].scaling, in_place=False)

        return final_orders
def test_portfolio(mocker):

    with MockCalc(mocker):
        with PricingContext(pricing_date=dt.date(2020, 10, 15)):
            swap1 = IRSwap('Pay', '10y', 'USD', fixed_rate=0.001, name='swap_10y@10bp')
            swap2 = IRSwap('Pay', '10y', 'USD', fixed_rate=0.002, name='swap_10y@20bp')
            swap3 = IRSwap('Pay', '10y', 'USD', fixed_rate=0.003, name='swap_10y@30bp')

            portfolio = Portfolio((swap1, swap2, swap3))

            prices: PortfolioRiskResult = portfolio.dollar_price()
            result = portfolio.calc((risk.DollarPrice, risk.IRDelta))

        assert tuple(sorted(map(lambda x: round(x, 0), prices))) == (4439478.0, 5423405.0, 6407332.0)
        assert round(prices.aggregate(), 2) == 16270214.48
        assert round(prices[0], 0) == 6407332.0
        assert round(prices[swap2], 0) == 5423405.0
        assert round(prices['swap_10y@30bp'], 0) == 4439478.0

        assert tuple(map(lambda x: round(x, 0), result[risk.DollarPrice])) == (6407332.0, 5423405.0, 4439478.0)
        assert round(result[risk.DollarPrice].aggregate(), 0) == 16270214.0
        assert round(result[risk.DollarPrice]['swap_10y@30bp'], 0) == 4439478.0
        assert round(result[risk.DollarPrice]['swap_10y@30bp'], 0) == round(result['swap_10y@30bp'][risk.DollarPrice],
                                                                            0)

        assert round(result[risk.IRDelta].aggregate().value.sum(), 0) == 278977.0

        prices_only = result[risk.DollarPrice]
        assert tuple(map(lambda x: round(x, 0), prices)) == tuple(map(lambda x: round(x, 0), prices_only))

        swap4 = IRSwap('Pay', '10y', 'USD', fixed_rate=-0.001, name='swap_10y@-10bp')
        portfolio.append(swap4)
        assert len(portfolio.instruments) == 4

        extracted_swap = portfolio.pop('swap_10y@20bp')
        assert extracted_swap == swap2
        assert len(portfolio.instruments) == 3

        swap_dict = {'swap_5': swap1,
                     'swap_6': swap2,
                     'swap_7': swap3}

        portfolio = Portfolio(swap_dict)
        assert len(portfolio) == 3
Beispiel #4
0
    def __getitem__(self, item):
        futures = []

        if isinstance(item,
                      RiskMeasure) or (isinstance(item, list)
                                       and isinstance(item[0], RiskMeasure)):
            '''Slicing a list of risk measures'''
            if isinstance(item, list):
                if any([it not in self.risk_measures for it in item]):
                    raise ValueError('{} not computed'.format(item))
            else:
                if item not in self.risk_measures:
                    raise ValueError('{} not computed'.format(item))

            if len(self.risk_measures) == 1:
                return self
            elif isinstance(item, list):
                return PortfolioRiskResult(self.__portfolio,
                                           tuple([it for it in item]),
                                           self.futures)
            else:
                return PortfolioRiskResult(self.__portfolio, (item, ),
                                           self.futures)

        elif isinstance(item, list) and isinstance(item[0], InstrumentBase):
            '''Slicing a list of instruments'''
            from gs_quant.markets.portfolio import Portfolio
            portfolio = Portfolio(self.__portfolio[item])
            for idx, result in enumerate(self):
                instr = self.portfolio[idx]
                futures.extend(
                    [PricingFuture(result) for it in item if instr == it])
            return PortfolioRiskResult(portfolio, self.risk_measures, futures)

        elif isinstance(item, dt.date):
            for result in self:
                if isinstance(
                        result,
                    (MultipleRiskMeasureResult, PortfolioRiskResult)):
                    futures.append(PricingFuture(result[item]))
                elif isinstance(result, (DataFrameWithInfo, SeriesWithInfo)):
                    futures.append(PricingFuture(_value_for_date(result,
                                                                 item)))
                else:
                    raise RuntimeError(
                        'Can only index by date on historical results')
            return PortfolioRiskResult(self.__portfolio, self.risk_measures,
                                       futures)

        else:
            return self.__results(items=item)
    def apply_action(self, state: Union[date, Iterable[date]],
                     backtest: BackTest):
        with HistoricalPricingContext(dates=make_list(state)):
            backtest.calc_calls += 1
            backtest.calculations += len(make_list(state))
            f = Portfolio(make_list(
                self.action.priceable)).resolve(in_place=False)

        for create_date, portfolio in f.result().items():
            active_dates = [
                s for s in backtest.states
                if get_final_date(portfolio.instruments[0], create_date, self.
                                  action.trade_duration) >= s >= create_date
            ]
            if len(active_dates):
                for t in portfolio:
                    t.name = f'{t.name}_{create_date.strftime("%Y-%m-%d")}'
                backtest.scaling_portfolios[create_date].append(
                    ScalingPortfolio(trade=portfolio.instruments[0],
                                     dates=active_dates,
                                     risk=self.action.risk))

        return backtest
def test_backtothefuture_pricing(mocker):
    with MockCalc(mocker):
        swap1 = IRSwap('Pay', '10y', 'USD', fixed_rate=0.01, name='swap1')
        swap2 = IRSwap('Pay', '10y', 'USD', fixed_rate=0.02, name='swap2')
        swap3 = IRSwap('Pay', '10y', 'USD', fixed_rate=0.03, name='swap3')

        portfolio = Portfolio((swap1, swap2, swap3))
        pricing_date = dt.date(2021, 2, 10)
        with PricingContext(pricing_date=pricing_date):
            with BackToTheFuturePricingContext(dates=business_day_offset(pricing_date, [-1, 0, 1],
                                                                         roll='forward')) as hpc:
                risk_key = hpc._PricingContext__risk_key(risk.DollarPrice, swap1.provider)
                results = portfolio.calc(risk.DollarPrice)

    expected = risk.SeriesWithInfo(
        pd.Series(
            data=[-22711963.80864744, -22655907.930484552, -21582551.58922608],
            index=business_day_offset(pricing_date, [-1, 0, 1], roll='forward')
        ),
        risk_key=historical_risk_key(risk_key), )

    actual = results[risk.DollarPrice].aggregate()

    assert actual.equals(expected)
Beispiel #7
0
 def _raise_order(self,
                  state: Union[date, Iterable[date]],
                  trigger_info: Optional[Union[AddTradeActionInfo, Iterable[AddTradeActionInfo]]] = None):
     with PricingContext(is_batch=True):
         state_list = make_list(state)
         orders = {}
         if trigger_info is None or isinstance(trigger_info, AddTradeActionInfo):
             trigger_info = [trigger_info for _ in range(len(state_list))]
         for s, ti in zip_longest(state_list, trigger_info):
             active_portfolio = self.action.dated_priceables.get(s) or self.action.priceables
             with PricingContext(pricing_date=s):
                 orders[s] = (Portfolio(active_portfolio).resolve(in_place=False), ti)
     orders = {k: v[0].result().scale(None if v[1] is None else v[1].scaling, in_place=False) for k, v in
               orders.items()}
     return orders
Beispiel #8
0
    def __add__(self, other):
        if isinstance(other, (int, float)):
            return self.__op(op.add, other)
        elif isinstance(other, MultipleRiskMeasureResult):
            if not _risk_keys_compatible(self, other):
                raise ValueError(
                    'Results must have matching scenario and location')

            instruments_equal = self.__instrument == other.__instrument

            self_dt = [list(self.values())[0].risk_key.date] if len(
                self.dates) == 0 else self.dates
            other_dt = [list(other.values())[0].risk_key.date] if len(
                other.dates) == 0 else other.dates
            dates_overlap = not set(self_dt).isdisjoint(other_dt)

            if not set(self.keys()).isdisjoint(
                    other.keys()) and instruments_equal and dates_overlap:
                raise ValueError(
                    'Results overlap on risk measures, instruments or dates')

            all_keys = set(chain(self.keys(), other.keys()))

            if not instruments_equal:
                from gs_quant.markets.portfolio import Portfolio
                return PortfolioRiskResult(
                    Portfolio((self.__instrument, other.__instrument)),
                    all_keys,
                    tuple(
                        MultipleRiskMeasureFuture(
                            r.__instrument, {
                                k: PricingFuture(r[k]) if k in r else None
                                for k in all_keys
                            }) for r in (self, other)))
            else:
                results = {}
                for result in (self, other):
                    for key in all_keys:
                        if key in result:
                            results[key] = _compose(
                                results[key],
                                result[key]) if key in results else result[key]

                return MultipleRiskMeasureResult(self.__instrument, results)
        else:
            raise ValueError(
                'Can only add instances of MultipleRiskMeasureResult or int, float'
            )
Beispiel #9
0
    def apply_action(self, state: Union[datetime.date, Iterable[datetime.date]], backtest: BackTest):
        with PricingContext(is_batch=True):
            f = {}
            for s in state:
                active_portfolio = self._dated_priceables.get(s) or self._priceables
                with PricingContext(pricing_date=s):
                    f[s] = Portfolio(active_portfolio).resolve(in_place=False)

        for s in backtest.states:
            pos = []
            for create_date, portfolio in f.items():
                pos += [inst for inst in portfolio.result().instruments
                        if get_final_date(inst, create_date, self.trade_duration) >= s >= create_date]
            backtest.portfolio_dict[s].append(pos)

        return backtest
Beispiel #10
0
def test_nested_portfolios(mocker):
    swap1 = IRSwap('Pay', '10y', 'USD', name='USD-swap')
    swap2 = IRSwap('Pay', '10y', 'EUR', name='EUR-swap')
    swap3 = IRSwap('Pay', '10y', 'GBP', name='GBP-swap')

    swap4 = IRSwap('Pay', '10y', 'JPY', name='JPY-swap')
    swap5 = IRSwap('Pay', '10y', 'HUF', name='HUF-swap')
    swap6 = IRSwap('Pay', '10y', 'CHF', name='CHF-swap')

    portfolio2_1 = Portfolio((swap1, swap2, swap3), name='portfolio2_1')
    portfolio2_2 = Portfolio((swap1, swap2, swap3), name='portfolio2_2')
    portfolio1_1 = Portfolio((swap4, portfolio2_1), name='portfolio1_1')
    portfolio1_2 = Portfolio((swap5, portfolio2_2), name='USD-swap')
    portfolio = Portfolio((swap6, portfolio1_1, portfolio1_2), name='portfolio')

    assert portfolio.paths('USD-swap') == (PortfolioPath(2), PortfolioPath((1, 1, 0)), PortfolioPath((2, 1, 0)))
Beispiel #11
0
    def apply_action(self, state: datetime.date, backtest: BackTest):
        with PricingContext(pricing_date=state):
            f = self._priceable.resolve(in_place=False)
            hedge_delta = self._priceable.calc(self.risk)

        hedge = f.result()
        ratio = backtest.results[state][self.risk].aggregate() / hedge_delta.result()
        hedge = scale_trade(hedge, ratio)

        active_dates = [pricing_date for pricing_date in backtest.states if
                        get_final_date(hedge, state, self.trade_duration) >= pricing_date >= state]
        with HistoricalPricingContext(dates=active_dates):
            backtest.calc_calls += 1
            backtest.calculations += len(active_dates) * len(backtest.risks)
            hedge_res = Portfolio(hedge).calc(backtest.risks)

        for pricing_date in active_dates:
            results = hedge_res[pricing_date]
            backtest.add_results(pricing_date, results)
Beispiel #12
0
def test_nested_portfolio(mocker):
    with MockCalc(mocker):
        cols1, res1, frame1 = get_attributes(port1,
                                             (risk.DollarPrice, risk.Price))
        cols2, res2, frame2 = get_attributes(port,
                                             (risk.DollarPrice, risk.Price))
        _, swap1_6_res, frame3 = get_attributes(
            Portfolio((swap_1, swap_6), name='swap_1_6'), risk.DollarPrice)
        _, res4, frame4 = get_attributes(
            port1, (risk.DollarPrice, risk.Price, risk.Theta))

    price_values_test(res1, frame1)
    price_values_test(res2, frame2)
    dollar_eur_frame1 = frame1[(frame1['portfolio_name_0'] == 'EUR') & (
        frame1['risk_measure'] == risk.DollarPrice)]['value'].values
    dollar_eur_frame2 = frame2[(frame2['portfolio_name_0'] == 'EURGBP')
                               & (frame2['portfolio_name_1'] == 'EUR') &
                               (frame2['risk_measure']
                                == risk.DollarPrice)]['value'].values

    default_pivot_table_test(res1)
    default_pivot_table_test(res2)

    # test slicing
    # slice multiple instruments
    slice_res2 = res1[[swap_1, swap_6
                       ]][risk.DollarPrice].to_frame(None, None,
                                                     None)['value'].values
    assert all(
        slice_res2 == swap1_6_res.to_frame(None, None, None)['value'].values)

    sub_frame1 = res1[risk.DollarPrice][swap_1].to_frame()
    assert sub_frame1 == dollar_eur_frame1[0]
    assert sub_frame1 == dollar_eur_frame2[0]

    sub_frame2 = res2[eur_port][risk.DollarPrice].to_frame(
        None, None, None)['value'].values
    assert all(dollar_eur_frame1 == sub_frame2)
    assert all(dollar_eur_frame2 == sub_frame2)
    # slice multiple risk measures
    sub_res4 = res4[[risk.Price, risk.DollarPrice]]
    assert all(sub_res4.to_frame() == res1.to_frame())
Beispiel #13
0
    def __add__(self, other):
        if isinstance(other, (int, float)):
            return self.__op(op.add, other)
        elif isinstance(other, MultipleRiskMeasureResult):
            if sorted(self.keys()) == sorted(other.keys()):
                from gs_quant.markets.portfolio import Portfolio
                return PortfolioRiskResult(
                    Portfolio((self.__instrument, other.__instrument)),
                    self.keys(),
                    tuple(MultipleRiskMeasureFuture(r.__instrument, dict((k, PricingFuture(v)) for k, v in r))
                          for r in (self, other))
                )
            elif set(self.keys()).isdisjoint(other.keys()) and self.__instrument == other.__instrument:
                if set(self.keys()).intersection(other.keys()):
                    raise ValueError('Keys must be disjoint')

                return MultipleRiskMeasureResult(self.__instrument, chain(self.items(), other.items()))
            else:
                raise ValueError('Can only add where risk_measures match or instrument identical &' +
                                 'risk_measures disjoint')
        else:
            raise ValueError('Can only add instances of MultipleRiskMeasureResult or int, float')
Beispiel #14
0
def test_pull_from_marquee(mocker):
    portfolio_search_results = {
        'results': [
            MQPortfolio(id='portfolio_id',
                        name='Test Portfolio',
                        currency='USD',
                        entitlements=Entitlements(admin=('guid:12345', )))
        ]
    }

    mocker.patch.object(GsSession.current,
                        '_get',
                        return_value=portfolio_search_results)
    mocker.patch.object(User,
                        'get_many',
                        return_value=([
                            User(user_id='12345',
                                 name='Fake User',
                                 email='*****@*****.**',
                                 company='Goldman Sachs')
                        ]))
    portfolio = Portfolio.get(name='Test Portfolio')
    assert portfolio.id == 'portfolio_id'
    return portfolio
Beispiel #15
0
def test_historical_pricing(mocker):
    set_session()

    dollar_price_ir_delta_values = [[[{
        '$type': 'Risk',
        'val': 0.01
    }, {
        '$type': 'Risk',
        'val': 0.011
    }, {
        '$type': 'Risk',
        'val': 0.012
    }],
                                     [{
                                         '$type': 'Risk',
                                         'val': 0.02
                                     }, {
                                         '$type': 'Risk',
                                         'val': 0.021
                                     }, {
                                         '$type': 'Risk',
                                         'val': 0.022
                                     }],
                                     [{
                                         '$type': 'Risk',
                                         'val': 0.03
                                     }, {
                                         '$type': 'Risk',
                                         'val': 0.031
                                     }, {
                                         '$type': 'Risk',
                                         'val': 0.032
                                     }]],
                                    [[{
                                        '$type':
                                        'RiskVector',
                                        'asset': [0.01, 0.015],
                                        'points': [{
                                            'type': 'IR',
                                            'asset': 'USD',
                                            'class_': 'Swap',
                                            'point': '1y'
                                        }, {
                                            'type': 'IR',
                                            'asset': 'USD',
                                            'class_': 'Swap',
                                            'point': '2y'
                                        }]
                                    }, {
                                        '$type':
                                        'RiskVector',
                                        'asset': [0.011, 0.0151],
                                        'points': [{
                                            'type': 'IR',
                                            'asset': 'USD',
                                            'class_': 'Swap',
                                            'point': '1y'
                                        }, {
                                            'type': 'IR',
                                            'asset': 'USD',
                                            'class_': 'Swap',
                                            'point': '2y'
                                        }]
                                    }, {
                                        '$type':
                                        'RiskVector',
                                        'asset': [0.012, 0.0152],
                                        'points': [{
                                            'type': 'IR',
                                            'asset': 'USD',
                                            'class_': 'Swap',
                                            'point': '1y'
                                        }, {
                                            'type': 'IR',
                                            'asset': 'USD',
                                            'class_': 'Swap',
                                            'point': '2y'
                                        }]
                                    }],
                                     [{
                                         '$type':
                                         'RiskVector',
                                         'asset': [0.02, 0.025],
                                         'points': [{
                                             'type': 'IR',
                                             'asset': 'USD',
                                             'class_': 'Swap',
                                             'point': '1y'
                                         }, {
                                             'type': 'IR',
                                             'asset': 'USD',
                                             'class_': 'Swap',
                                             'point': '2y'
                                         }]
                                     }, {
                                         '$type':
                                         'RiskVector',
                                         'asset': [0.021, 0.0251],
                                         'points': [{
                                             'type': 'IR',
                                             'asset': 'USD',
                                             'class_': 'Swap',
                                             'point': '1y'
                                         }, {
                                             'type': 'IR',
                                             'asset': 'USD',
                                             'class_': 'Swap',
                                             'point': '2y'
                                         }]
                                     }, {
                                         '$type':
                                         'RiskVector',
                                         'asset': [0.022, 0.0252],
                                         'points': [{
                                             'type': 'IR',
                                             'asset': 'USD',
                                             'class_': 'Swap',
                                             'point': '1y'
                                         }, {
                                             'type': 'IR',
                                             'asset': 'USD',
                                             'class_': 'Swap',
                                             'point': '2y'
                                         }]
                                     }],
                                     [{
                                         '$type':
                                         'RiskVector',
                                         'asset': [0.03, 0.035],
                                         'points': [{
                                             'type': 'IR',
                                             'asset': 'USD',
                                             'class_': 'Swap',
                                             'point': '1y'
                                         }, {
                                             'type': 'IR',
                                             'asset': 'USD',
                                             'class_': 'Swap',
                                             'point': '2y'
                                         }]
                                     }, {
                                         '$type':
                                         'RiskVector',
                                         'asset': [0.031, 0.0351],
                                         'points': [{
                                             'type': 'IR',
                                             'asset': 'USD',
                                             'class_': 'Swap',
                                             'point': '1y'
                                         }, {
                                             'type': 'IR',
                                             'asset': 'USD',
                                             'class_': 'Swap',
                                             'point': '2y'
                                         }]
                                     }, {
                                         '$type':
                                         'RiskVector',
                                         'asset': [0.032, 0.0352],
                                         'points': [{
                                             'type': 'IR',
                                             'asset': 'USD',
                                             'class_': 'Swap',
                                             'point': '1y'
                                         }, {
                                             'type': 'IR',
                                             'asset': 'USD',
                                             'class_': 'Swap',
                                             'point': '2y'
                                         }]
                                     }]]]

    mocker.return_value = [dollar_price_ir_delta_values]

    swap1 = IRSwap('Pay', '10y', 'USD', fixed_rate=0.01, name='swap1')
    swap2 = IRSwap('Pay', '10y', 'USD', fixed_rate=0.02, name='swap2')
    swap3 = IRSwap('Pay', '10y', 'USD', fixed_rate=0.03, name='swap3')

    portfolio = Portfolio((swap1, swap2, swap3))

    with HistoricalPricingContext(dates=(dt.date(2019, 10, 7),
                                         dt.date(2019, 10, 8),
                                         dt.date(2019, 10, 9))) as hpc:
        risk_key = hpc._PricingContext__risk_key(risk.DollarPrice,
                                                 swap1.provider())
        results = portfolio.calc((risk.DollarPrice, risk.IRDelta))

    expected = risk.SeriesWithInfo(
        pd.Series(data=[0.06, 0.063, 0.066],
                  index=[
                      dt.date(2019, 10, 7),
                      dt.date(2019, 10, 8),
                      dt.date(2019, 10, 9)
                  ]),
        risk_key=risk_key.base,
    )

    actual = results[risk.DollarPrice].aggregate()

    assert actual.equals(expected)
Beispiel #16
0
from gs_quant.common import PayReceive, Currency  # import constants
from gs_quant.instrument import IRSwaption  # import instruments
from gs_quant.markets.portfolio import Portfolio
from gs_quant.session import Environment, GsSession  # import sessions

client_id = None  # Supply your application id
client_secret = None  # Supply your client secret
scopes = ('run_analytics', )
GsSession.use(Environment.PROD, client_id, client_secret, scopes)

swaption1 = IRSwaption(PayReceive.Pay,
                       '5y',
                       Currency.EUR,
                       expiration_date='3m',
                       name='EUR-3m5y')
swaption2 = IRSwaption(PayReceive.Pay,
                       '5y',
                       Currency.EUR,
                       expiration_date='6m',
                       name='EUR-6m5y')
portfolio = Portfolio((swaption1, swaption2))

# price of individual instrument
price_result = portfolio.price()
print(price_result['EUR-3m5y'])

# price for entire portfolio
price_agg = price_result.aggregate()
print(price_agg)
Beispiel #17
0
    def run_backtest(self,
                     strategy,
                     start=None,
                     end=None,
                     frequency='BM',
                     window=None,
                     states=None,
                     risks=Price,
                     show_progress=True):
        dates = pd.date_range(start=start, end=end,
                              freq=frequency).date.tolist()
        risks = make_list(risks) + strategy.risks

        backtest = BackTest(strategy, dates, risks)

        if len(strategy.initial_portfolio):
            init_port = Portfolio(strategy.initial_portfolio)
            with PricingContext(pricing_date=dates[0]):
                init_port.resolve()
            for d in dates:
                backtest.portfolio_dict[d].append(init_port.instruments)

        for trigger in strategy.triggers:
            if trigger.calc_type != CalcType.path_dependent:
                triggered_dates = [
                    d for d in dates if trigger.has_triggered(d, backtest)
                ]
                for action in trigger.actions:
                    if action.calc_type != CalcType.path_dependent:
                        self.get_action_handler(action).apply_action(
                            triggered_dates, backtest)

        with PricingContext(is_batch=True, show_progress=show_progress):
            for day, portfolio in backtest.portfolio_dict.items():
                with PricingContext(day):
                    backtest.calc_calls += 1
                    backtest.calculations += len(portfolio) * len(risks)
                    backtest.add_results(day, portfolio.calc(tuple(risks)))

            # semi path dependent initial calc
            for _, scaling_list in backtest.scaling_portfolios.items():
                for p in scaling_list:
                    with HistoricalPricingContext(dates=p.dates):
                        backtest.calc_calls += 1
                        backtest.calculations += len(p.dates) * len(risks)
                        p.results = Portfolio([p.trade]).calc(tuple(risks))

        for d in dates:
            # semi path dependent scaling
            if d in backtest.scaling_portfolios:
                initial_portfolio = backtest.scaling_portfolios[d][0]
                scale_date = initial_portfolio.dates[0]
                current_risk = backtest.results[scale_date][
                    initial_portfolio.risk].aggregate()
                hedge_risk = initial_portfolio.results[scale_date][
                    initial_portfolio.risk][0]
                scaling_factor = current_risk / hedge_risk
                for p in backtest.scaling_portfolios[d]:
                    new_notional = p.trade.notional_amount * -scaling_factor
                    scaled_trade = p.trade.as_dict()
                    scaled_trade['notional_amount'] = new_notional
                    scaled_trade = Instrument.from_dict(scaled_trade)
                    for day in p.dates:
                        backtest.add_results(day,
                                             p.results[day] * -scaling_factor)
                        backtest.portfolio_dict[day] += Portfolio(scaled_trade)

            # path dependent
            for trigger in strategy.triggers:
                if trigger.calc_type == CalcType.path_dependent:
                    if trigger.has_triggered(d, backtest):
                        for action in trigger.actions:
                            self.get_action_handler(action).apply_action(
                                d, backtest)
                else:
                    for action in trigger.actions:
                        if action.calc_type == CalcType.path_dependent:
                            if trigger.has_triggered(d, backtest):
                                self.get_action_handler(action).apply_action(
                                    d, backtest)
        return backtest
Beispiel #18
0
# Access instruments within a portfolio

from gs_quant.common import PayReceive, Currency  # import constants
from gs_quant.instrument import IRSwaption  # import instruments
from gs_quant.markets.portfolio import Portfolio
from gs_quant.session import Environment, GsSession  # import sessions

client_id = None  # Supply your application id
client_secret = None  # Supply your client secret
scopes = ('run_analytics',)
GsSession.use(Environment.PROD, client_id, client_secret, scopes)

swaption1 = IRSwaption(PayReceive.Pay, '5y', Currency.EUR, expiration_date='3m', name='EUR-3m5y')
swaption2 = IRSwaption(PayReceive.Pay, '5y', Currency.EUR, expiration_date='6m', name='EUR-6m5y')
portfolio = Portfolio((swaption1, swaption2))

print(portfolio[0])  # index
print(portfolio[swaption2])  # instrument object
print(portfolio['EUR-6m5y'])  # instrument name
Beispiel #19
0
        cols = [col for col in frame.columns]
        return cols, res, frame
    else:
        return res


swap_1 = IRSwap("Pay", "5y", "EUR", fixed_rate=-0.005, name="5y")
swap_2 = IRSwap("Pay", "10y", "EUR", fixed_rate=-0.005, name="10y")
swap_3 = IRSwap("Pay", "5y", "USD", fixed_rate=-0.005, name="5y")
swap_4 = IRSwap("Pay", "10y", "USD", fixed_rate=-0.005, name="10y")
swap_5 = IRSwap("Pay", "5y", "GBP", fixed_rate=-0.005, name="5y")
swap_6 = IRSwap("Pay", "10y", "GBP", fixed_rate=-0.005, name="10y")
swap_7 = IRSwap("Pay", "5y", "JPY", fixed_rate=-0.005, name="5y")
swap_8 = IRSwap("Pay", "10y", "JPY", fixed_rate=-0.005, name="10y")
eur_port = Portfolio([swap_1, swap_2], name="EUR")
usd_port = Portfolio([swap_3, swap_4], name="USD")
gbp_port = Portfolio([swap_5, swap_6], name="GBP")
jpy_port = Portfolio([swap_7, swap_8], name='JPY')
port1 = Portfolio([eur_port, gbp_port], name='EURGBP')
port2 = Portfolio([jpy_port, usd_port], name='USDJPY')
port = Portfolio([port1, port2])
swaption_port = Portfolio([
    IRSwaption("Receive",
               '5y',
               'USD',
               expiration_date='2m',
               strike='atm',
               name='Swaption1'),
    IRSwaption("Receive",
               '10y',
Beispiel #20
0
"""
`Portfolio` supports the same methods as `Instrument` including `resolve()`, `calc()`, and `price()`
Resolving the portfolio resolves each individual instrument within the portfolio.
"""
from gs_quant.common import PayReceive, Currency  # import constants
from gs_quant.instrument import IRSwaption  # import instruments
from gs_quant.markets.portfolio import Portfolio
from gs_quant.session import Environment, GsSession  # import sessions

client_id = None  # Supply your application id
client_secret = None  # Supply your client secret
scopes = ('run_analytics', )
GsSession.use(Environment.PROD, client_id, client_secret, scopes)

swaption1 = IRSwaption(PayReceive.Pay,
                       '5y',
                       Currency.EUR,
                       expiration_date='3m',
                       name='EUR-3m5y')
swaption2 = IRSwaption(PayReceive.Pay,
                       '5y',
                       Currency.EUR,
                       expiration_date='6m',
                       name='EUR-6m5y')

portfolio = Portfolio((swaption1, swaption2))
portfolio.resolve()
print(portfolio.as_dict())
Beispiel #21
0
    def apply_action(
        self,
        state: Union[date, Iterable[date]],
        backtest: BackTest,
        trigger_info: Optional[Union[ExitTradeActionInfo,
                                     Iterable[ExitTradeActionInfo]]] = None):

        for s in make_list(state):

            trades_to_remove = []

            fut_dates = list(
                filter(lambda d: d >= s and type(d) is dt.date,
                       backtest.states))
            for port_date in fut_dates:
                pos_fut = list(
                    backtest.portfolio_dict[port_date].all_instruments)

                # We expect tradable names to be defined as <ActionName>_<TradeName>_<TradeDate>
                if self.action.priceable_names:
                    # List of trade names provided -> TradeDate <= exit trigger date and TradeName is present in list
                    indexes_to_remove = [
                        i for i, x in enumerate(pos_fut)
                        if dt.datetime.strptime(
                            x.name.split('_')[-1], '%Y-%m-%d').date() <= s and
                        x.name.split('_')[-2] in self.action.priceable_names
                    ]
                else:
                    # List of trade names not provided -> TradeDate <= exit trigger date
                    indexes_to_remove = [
                        i for i, x in enumerate(pos_fut)
                        if dt.datetime.strptime(
                            x.name.split('_')[-1], '%Y-%m-%d').date() <= s
                    ]

                for index in sorted(indexes_to_remove, reverse=True):
                    # Get list of trades' names that have been removed to check for their future cash flow date
                    if pos_fut[index].name not in trades_to_remove:
                        trades_to_remove.append(pos_fut[index].name)
                    del pos_fut[index]
                backtest.portfolio_dict[port_date] = Portfolio(tuple(pos_fut))

            for cp_date, cp_list in list(backtest.cash_payments.items()):
                if cp_date > s:
                    indexes_to_remove = [
                        i for i, cp in enumerate(cp_list)
                        if cp.trade.name in trades_to_remove
                    ]
                    for index in sorted(indexes_to_remove, reverse=True):
                        cp = cp_list[index]
                        prev_pos = [
                            i for i, x in enumerate(backtest.cash_payments[s])
                            if cp.trade.name == x.trade.name
                        ]
                        # If trade already exists in exit trigger date cash payments, net out the position
                        if prev_pos:
                            backtest.cash_payments[s][
                                prev_pos[0]].direction += cp.direction
                        else:
                            cp.effective_date = s
                            backtest.cash_payments[s].append(cp)
                        del backtest.cash_payments[cp_date][index]

                    if not backtest.cash_payments[cp_date]:
                        del backtest.cash_payments[cp_date]

        return backtest
Beispiel #22
0
def test_portfolio(mocker):
    set_session()

    dollar_price_values = [[[{
        'date': '2019-10-07',
        'value': 0.01
    }], [{
        'date': '2019-10-07',
        'value': 0.02
    }], [{
        'date': '2019-10-07',
        'value': 0.03
    }]]]

    dollar_price_ir_delta_values = [[[{
        'date': '2019-10-07',
        'value': 0.01
    }], [{
        'date': '2019-10-07',
        'value': 0.02
    }], [{
        'date': '2019-10-07',
        'value': 0.03
    }]],
                                    [[{
                                        'date': '2019-10-07',
                                        'marketDataType': 'IR',
                                        'assetId': 'USD',
                                        'pointClass': 'Swap',
                                        'point': '1y',
                                        'value': 0.01
                                    }, {
                                        'date': '2019-10-07',
                                        'marketDataType': 'IR',
                                        'assetId': 'USD',
                                        'pointClass': 'Swap',
                                        'point': '2y',
                                        'value': 0.015
                                    }],
                                     [{
                                         'date': '2019-10-07',
                                         'marketDataType': 'IR',
                                         'assetId': 'USD',
                                         'pointClass': 'Swap',
                                         'point': '1y',
                                         'value': 0.02
                                     }, {
                                         'date': '2019-10-07',
                                         'marketDataType': 'IR',
                                         'assetId': 'USD',
                                         'pointClass': 'Swap',
                                         'point': '2y',
                                         'value': 0.025
                                     }],
                                     [{
                                         'date': '2019-10-07',
                                         'marketDataType': 'IR',
                                         'assetId': 'USD',
                                         'pointClass': 'Swap',
                                         'point': '1y',
                                         'value': 0.03
                                     }, {
                                         'date': '2019-10-07',
                                         'marketDataType': 'IR',
                                         'assetId': 'USD',
                                         'pointClass': 'Swap',
                                         'point': '2y',
                                         'value': 0.035
                                     }]]]

    swap1 = IRSwap('Pay', '10y', 'USD', fixed_rate=0.01, name='swap1')
    swap2 = IRSwap('Pay', '10y', 'USD', fixed_rate=0.02, name='swap2')
    swap3 = IRSwap('Pay', '10y', 'USD', fixed_rate=0.03, name='swap3')

    portfolio = Portfolio((swap1, swap2, swap3))

    mocker.return_value = dollar_price_values
    prices: PortfolioRiskResult = portfolio.dollar_price()
    assert tuple(sorted(prices)) == (0.01, 0.02, 0.03)
    assert round(prices.aggregate(), 2) == 0.06
    assert prices[0] == 0.01
    assert prices[swap2] == 0.02
    assert prices['swap3'] == 0.03

    mocker.return_value = dollar_price_ir_delta_values
    result = portfolio.calc((risk.DollarPrice, risk.IRDelta))

    assert tuple(result[risk.DollarPrice]) == (0.01, 0.02, 0.03)
    assert result[risk.DollarPrice].aggregate() == 0.06
    assert result[risk.DollarPrice]['swap3'] == 0.03
    assert result[risk.DollarPrice]['swap3'] == result['swap3'][
        risk.DollarPrice]

    expected = risk.aggregate_risk(
        [pd.DataFrame(v) for v in dollar_price_ir_delta_values[1]])
    assert result[risk.IRDelta].aggregate().equals(expected)

    prices_only = result[risk.DollarPrice]
    assert tuple(prices) == tuple(prices_only)
Beispiel #23
0
def test_historical_pricing(mocker):
    set_session()

    dollar_price_ir_delta_values = [[[{
        'date': '2019-10-07',
        'value': 0.01
    }, {
        'date': '2019-10-08',
        'value': 0.011
    }, {
        'date': '2019-10-09',
        'value': 0.012
    }],
                                     [{
                                         'date': '2019-10-07',
                                         'value': 0.02
                                     }, {
                                         'date': '2019-10-08',
                                         'value': 0.021
                                     }, {
                                         'date': '2019-10-09',
                                         'value': 0.022
                                     }],
                                     [{
                                         'date': '2019-10-07',
                                         'value': 0.03
                                     }, {
                                         'date': '2019-10-08',
                                         'value': 0.031
                                     }, {
                                         'date': '2019-10-09',
                                         'value': 0.032
                                     }]],
                                    [[{
                                        'date': '2019-10-07',
                                        'marketDataType': 'IR',
                                        'assetId': 'USD',
                                        'pointClass': 'Swap',
                                        'point': '1y',
                                        'value': 0.01
                                    }, {
                                        'date': '2019-10-07',
                                        'marketDataType': 'IR',
                                        'assetId': 'USD',
                                        'pointClass': 'Swap',
                                        'point': '2y',
                                        'value': 0.015
                                    }, {
                                        'date': '2019-10-08',
                                        'marketDataType': 'IR',
                                        'assetId': 'USD',
                                        'pointClass': 'Swap',
                                        'point': '1y',
                                        'value': 0.011
                                    }, {
                                        'date': '2019-10-08',
                                        'marketDataType': 'IR',
                                        'assetId': 'USD',
                                        'pointClass': 'Swap',
                                        'point': '2y',
                                        'value': 0.0151
                                    }, {
                                        'date': '2019-10-09',
                                        'marketDataType': 'IR',
                                        'assetId': 'USD',
                                        'pointClass': 'Swap',
                                        'point': '1y',
                                        'value': 0.012
                                    }, {
                                        'date': '2019-10-09',
                                        'marketDataType': 'IR',
                                        'assetId': 'USD',
                                        'pointClass': 'Swap',
                                        'point': '2y',
                                        'value': 0.0152
                                    }],
                                     [{
                                         'date': '2019-10-07',
                                         'marketDataType': 'IR',
                                         'assetId': 'USD',
                                         'pointClass': 'Swap',
                                         'point': '1y',
                                         'value': 0.02
                                     }, {
                                         'date': '2019-10-07',
                                         'marketDataType': 'IR',
                                         'assetId': 'USD',
                                         'pointClass': 'Swap',
                                         'point': '2y',
                                         'value': 0.025
                                     }, {
                                         'date': '2019-10-08',
                                         'marketDataType': 'IR',
                                         'assetId': 'USD',
                                         'pointClass': 'Swap',
                                         'point': '1y',
                                         'value': 0.021
                                     }, {
                                         'date': '2019-10-08',
                                         'marketDataType': 'IR',
                                         'assetId': 'USD',
                                         'pointClass': 'Swap',
                                         'point': '2y',
                                         'value': 0.0251
                                     }, {
                                         'date': '2019-10-09',
                                         'marketDataType': 'IR',
                                         'assetId': 'USD',
                                         'pointClass': 'Swap',
                                         'point': '1y',
                                         'value': 0.022
                                     }, {
                                         'date': '2019-10-09',
                                         'marketDataType': 'IR',
                                         'assetId': 'USD',
                                         'pointClass': 'Swap',
                                         'point': '2y',
                                         'value': 0.0252
                                     }],
                                     [{
                                         'date': '2019-10-07',
                                         'marketDataType': 'IR',
                                         'assetId': 'USD',
                                         'pointClass': 'Swap',
                                         'point': '1y',
                                         'value': 0.03
                                     }, {
                                         'date': '2019-10-07',
                                         'marketDataType': 'IR',
                                         'assetId': 'USD',
                                         'pointClass': 'Swap',
                                         'point': '2y',
                                         'value': 0.035
                                     }, {
                                         'date': '2019-10-08',
                                         'marketDataType': 'IR',
                                         'assetId': 'USD',
                                         'pointClass': 'Swap',
                                         'point': '1y',
                                         'value': 0.031
                                     }, {
                                         'date': '2019-10-08',
                                         'marketDataType': 'IR',
                                         'assetId': 'USD',
                                         'pointClass': 'Swap',
                                         'point': '2y',
                                         'value': 0.0351
                                     }, {
                                         'date': '2019-10-09',
                                         'marketDataType': 'IR',
                                         'assetId': 'USD',
                                         'pointClass': 'Swap',
                                         'point': '1y',
                                         'value': 0.032
                                     }, {
                                         'date': '2019-10-09',
                                         'marketDataType': 'IR',
                                         'assetId': 'USD',
                                         'pointClass': 'Swap',
                                         'point': '2y',
                                         'value': 0.0352
                                     }]]]

    mocker.return_value = dollar_price_ir_delta_values

    swap1 = IRSwap('Pay', '10y', 'USD', fixed_rate=0.01, name='swap1')
    swap2 = IRSwap('Pay', '10y', 'USD', fixed_rate=0.02, name='swap2')
    swap3 = IRSwap('Pay', '10y', 'USD', fixed_rate=0.03, name='swap3')

    portfolio = Portfolio((swap1, swap2, swap3))

    with HistoricalPricingContext(3):
        results = portfolio.calc((risk.DollarPrice, risk.IRDelta))

    expected = pd.Series(data=[0.06, 0.063, 0.066],
                         index=[
                             dt.date(2019, 10, 7),
                             dt.date(2019, 10, 8),
                             dt.date(2019, 10, 9)
                         ])

    assert results[risk.DollarPrice].aggregate().equals(expected)
Beispiel #24
0
def test_portfolio(mocker):
    set_session()

    dollar_price_values = [[[{
        '$type': 'Risk',
        'val': 0.01
    }], [{
        '$type': 'Risk',
        'val': 0.02
    }], [{
        '$type': 'Risk',
        'val': 0.03
    }]]]

    dollar_price_ir_delta_values = [[[{
        '$type': 'Risk',
        'val': 0.01
    }], [{
        '$type': 'Risk',
        'val': 0.02
    }], [{
        '$type': 'Risk',
        'val': 0.03
    }]],
                                    [[{
                                        '$type':
                                        'RiskVector',
                                        'asset': [0.01, 0.015],
                                        'points': [{
                                            'type': 'IR',
                                            'asset': 'USD',
                                            'class_': 'Swap',
                                            'point': '1y'
                                        }, {
                                            'type': 'IR',
                                            'asset': 'USD',
                                            'class_': 'Swap',
                                            'point': '2y'
                                        }]
                                    }],
                                     [{
                                         '$type':
                                         'RiskVector',
                                         'asset': [0.02, 0.025],
                                         'points': [{
                                             'type': 'IR',
                                             'asset': 'USD',
                                             'class_': 'Swap',
                                             'point': '1y'
                                         }, {
                                             'type': 'IR',
                                             'asset': 'USD',
                                             'class_': 'Swap',
                                             'point': '2y'
                                         }]
                                     }],
                                     [{
                                         '$type':
                                         'RiskVector',
                                         'asset': [0.03, 0.035],
                                         'points': [{
                                             'type': 'IR',
                                             'asset': 'USD',
                                             'class_': 'Swap',
                                             'point': '1y'
                                         }, {
                                             'type': 'IR',
                                             'asset': 'USD',
                                             'class_': 'Swap',
                                             'point': '2y'
                                         }]
                                     }]]]

    swap1 = IRSwap('Pay', '10y', 'USD', fixed_rate=0.01, name='swap1')
    swap2 = IRSwap('Pay', '10y', 'USD', fixed_rate=0.02, name='swap2')
    swap3 = IRSwap('Pay', '10y', 'USD', fixed_rate=0.03, name='swap3')

    portfolio = Portfolio((swap1, swap2, swap3))

    mocker.return_value = [dollar_price_values]
    prices: PortfolioRiskResult = portfolio.dollar_price()
    assert tuple(sorted(prices)) == (0.01, 0.02, 0.03)
    assert round(prices.aggregate(), 2) == 0.06
    assert prices[0] == 0.01
    assert prices[swap2] == 0.02
    assert prices['swap3'] == 0.03

    mocker.return_value = [dollar_price_ir_delta_values]
    result = portfolio.calc((risk.DollarPrice, risk.IRDelta))

    assert tuple(result[risk.DollarPrice]) == (0.01, 0.02, 0.03)
    assert result[risk.DollarPrice].aggregate() == 0.06
    assert result[risk.DollarPrice]['swap3'] == 0.03
    assert result[risk.DollarPrice]['swap3'] == result['swap3'][
        risk.DollarPrice]

    assert result[risk.IRDelta].aggregate().value.sum() == 0.135

    prices_only = result[risk.DollarPrice]
    assert tuple(prices) == tuple(prices_only)

    swap4 = IRSwap('Pay', '10y', 'USD', fixed_rate=0.01, name='swap4')
    portfolio.append(swap4)
    assert len(portfolio.instruments) == 4

    extracted_swap = portfolio.pop('swap2')
    assert extracted_swap == swap2
    assert len(portfolio.instruments) == 3

    swap_dict = {'swap_5': swap1, 'swap_6': swap2, 'swap_7': swap3}

    portfolio = Portfolio(swap_dict)
    assert len(portfolio) == 3
Beispiel #25
0
def test_results_with_resolution():
    set_session()

    dollar_price_ir_delta_values = [[[{
        '$type': 'Risk',
        'val': 0.01
    }], [{
        '$type': 'Risk',
        'val': 0.02
    }], [{
        '$type': 'Risk',
        'val': 0.03
    }]],
                                    [[{
                                        '$type':
                                        'RiskVector',
                                        'asset': [0.01, 0.015],
                                        'points': [{
                                            'type': 'IR',
                                            'asset': 'USD',
                                            'class_': 'Swap',
                                            'point': '1y'
                                        }, {
                                            'type': 'IR',
                                            'asset': 'USD',
                                            'class_': 'Swap',
                                            'point': '2y'
                                        }]
                                    }],
                                     [{
                                         '$type':
                                         'RiskVector',
                                         'asset': [0.02, 0.025],
                                         'points': [{
                                             'type': 'IR',
                                             'asset': 'USD',
                                             'class_': 'Swap',
                                             'point': '1y'
                                         }, {
                                             'type': 'IR',
                                             'asset': 'USD',
                                             'class_': 'Swap',
                                             'point': '2y'
                                         }]
                                     }],
                                     [{
                                         '$type':
                                         'RiskVector',
                                         'asset': [0.03, 0.035],
                                         'points': [{
                                             'type': 'IR',
                                             'asset': 'USD',
                                             'class_': 'Swap',
                                             'point': '1y'
                                         }, {
                                             'type': 'IR',
                                             'asset': 'USD',
                                             'class_': 'Swap',
                                             'point': '2y'
                                         }]
                                     }]]]

    swap1 = IRSwap('Pay', '10y', 'USD', name='swap1')
    swap2 = IRSwap('Pay', '10y', 'GBP', name='swap2')
    swap3 = IRSwap('Pay', '10y', 'EUR', name='swap3')

    portfolio = Portfolio((swap1, swap2, swap3))

    with mock.patch('gs_quant.api.gs.risk.GsRiskApi._exec') as mocker:
        mocker.return_value = [dollar_price_ir_delta_values]
        result = portfolio.calc((risk.DollarPrice, risk.IRDelta))

    # Check that we've got results
    assert result[swap1][risk.DollarPrice] is not None

    # Now resolve portfolio and assert that we can still get the result

    resolution_values = [[[{
        '$type': 'LegDefinition',
        'fixedRate': 0.01
    }], [{
        '$type': 'LegDefinition',
        'fixedRate': 0.007
    }], [{
        '$type': 'LegDefinition',
        'fixedRate': 0.05
    }]]]

    orig_swap1 = swap1.clone()

    with mock.patch('gs_quant.api.gs.risk.GsRiskApi._exec') as mocker:
        mocker.return_value = [resolution_values]
        portfolio.resolve()

    # Assert that the resolved swap is indeed different and that we can retrieve results by both

    assert swap1 != orig_swap1
    assert result[swap1][risk.DollarPrice] is not None
    assert result[orig_swap1][risk.DollarPrice] is not None

    # Now reset the instruments and portfolio

    swap1 = IRSwap('Pay', '10y', 'USD', name='swap1')
    swap2 = IRSwap('Pay', '10y', 'GBP', name='swap2')
    swap3 = IRSwap('Pay', '10y', 'EUR', name='swap3')

    portfolio = Portfolio((swap1, swap2, swap3, swap1))

    with mock.patch('gs_quant.api.gs.risk.GsRiskApi._exec') as mocker:
        with PricingContext(dt.date(1066, 11, 14)):
            # Resolve under a different pricing date
            mocker.return_value = [resolution_values]
            portfolio.resolve()

    # Assert that after resolution under a different context, we cannot retrieve the result

    try:
        _ = result[swap1][risk.DollarPrice]
        assert False
    except KeyError:
        assert True
Beispiel #26
0
def test_backtothefuture_pricing(mocker):
    set_session()

    day1 = [[
        [{
            '$type': 'Risk',
            'val': 0.01
        }],
        [{
            '$type': 'Risk',
            'val': 0.02
        }],
        [{
            '$type': 'Risk',
            'val': 0.03
        }],
    ]]

    day2 = [[
        [{
            '$type': 'Risk',
            'val': 0.011
        }],
        [{
            '$type': 'Risk',
            'val': 0.021
        }],
        [{
            '$type': 'Risk',
            'val': 0.031
        }],
    ]]

    day3 = [[
        [{
            '$type': 'Risk',
            'val': 0.012
        }],
        [{
            '$type': 'Risk',
            'val': 0.022
        }],
        [{
            '$type': 'Risk',
            'val': 0.032
        }],
    ]]

    mocker.return_value = [day1, day2, day3]

    swap1 = IRSwap('Pay', '10y', 'USD', fixed_rate=0.01, name='swap1')
    swap2 = IRSwap('Pay', '10y', 'USD', fixed_rate=0.02, name='swap2')
    swap3 = IRSwap('Pay', '10y', 'USD', fixed_rate=0.03, name='swap3')

    portfolio = Portfolio((swap1, swap2, swap3))

    with BackToTheFuturePricingContext(dates=business_day_offset(
            dt.datetime.today().date(), [-1, 0, 1], roll='forward')) as hpc:
        risk_key = hpc._PricingContext__risk_key(risk.DollarPrice,
                                                 swap1.provider)
        results = portfolio.calc(risk.DollarPrice)

    expected = risk.SeriesWithInfo(
        pd.Series(data=[0.06, 0.063, 0.066],
                  index=business_day_offset(dt.datetime.today().date(),
                                            [-1, 0, 1],
                                            roll='forward')),
        risk_key=risk_key.ex_date_and_market,
    )

    actual = results[risk.DollarPrice].aggregate()

    assert actual.equals(expected)
Beispiel #27
0
    def run_backtest(self,
                     strategy,
                     start=None,
                     end=None,
                     frequency='1m',
                     states=None,
                     risks=Price,
                     show_progress=True,
                     csa_term=None,
                     visible_to_gs=False,
                     initial_value=0,
                     result_ccy=None,
                     holiday_calendar=None):
        """
        run the backtest following the triggers and actions defined in the strategy.  If states are entered run on
        those dates otherwise build a schedule from the start, end, frequency
        using gs_quant.datetime.relative_date.RelativeDateSchedule
        :param strategy: the strategy object
        :param start: a datetime
        :param end: a datetime
        :param frequency: str, default '1m'
        :param states: a list of dates will override the start, end, freq if provided
        :param risks: risks to run
        :param show_progress: boolean default true
        :param csa_term: the csa term to use
        :param visible_to_gs: are the contents of risk requests visible to GS (defaults to False)
        :param initial_value: initial cash value of strategy defaults to 0
        :param result_ccy: ccy of all risks, pvs and cash
        :param holiday_calendar for date maths - list of dates
        :return: a backtest object containing the portfolios on each day and results which show all risks on all days

        """

        logging.info(
            f'Starting Backtest: Building Date Schedule - {dt.datetime.now()}')

        strategy_pricing_dates = RelativeDateSchedule(frequency,
                                                      start,
                                                      end).apply_rule(holiday_calendar=holiday_calendar) \
            if states is None else states

        strategy_start_date = strategy_pricing_dates[0]
        strategy_end_date = strategy_pricing_dates[-1]

        risks = list(set(make_list(risks) + strategy.risks))
        if result_ccy is not None:
            risks = [(r(
                currency=result_ccy) if isinstance(r, ParameterisedRiskMeasure)
                      else raiser(f'Unparameterised risk: {r}'))
                     for r in risks]
        price_risk = Price(
            currency=result_ccy) if result_ccy is not None else Price

        backtest = BackTest(strategy, strategy_pricing_dates, risks)

        logging.info('Resolving initial portfolio')
        if len(strategy.initial_portfolio):
            for index in range(len(strategy.initial_portfolio)):
                old_name = strategy.initial_portfolio[index].name
                strategy.initial_portfolio[
                    index].name = f'{old_name}_{strategy_start_date.strftime("%Y-%m-%d")}'
                entry_payment = CashPayment(strategy.initial_portfolio[index],
                                            effective_date=strategy_start_date,
                                            direction=-1)
                backtest.cash_payments[strategy_start_date].append(
                    entry_payment)
                final_date = get_final_date(strategy.initial_portfolio[index],
                                            strategy_start_date, None)
                exit_payment = CashPayment(strategy.initial_portfolio[index],
                                           effective_date=final_date)
                backtest.cash_payments[final_date].append(exit_payment)
            init_port = Portfolio(strategy.initial_portfolio)
            with PricingContext(pricing_date=strategy_start_date,
                                csa_term=csa_term,
                                show_progress=show_progress,
                                visible_to_gs=visible_to_gs):
                init_port.resolve()
            for d in strategy_pricing_dates:
                backtest.portfolio_dict[d].append(init_port.instruments)

        logging.info(
            'Building simple and semi-deterministic triggers and actions')
        for trigger in strategy.triggers:
            if trigger.calc_type != CalcType.path_dependent:
                triggered_dates = []
                trigger_infos = defaultdict(list)
                for d in strategy_pricing_dates:
                    t_info = trigger.has_triggered(d, backtest)
                    if t_info:
                        triggered_dates.append(d)
                        if t_info.info_dict:
                            for k, v in t_info.info_dict.items():
                                trigger_infos[k].append(v)

                for action in trigger.actions:
                    if action.calc_type != CalcType.path_dependent:
                        self.get_action_handler(action).apply_action(
                            triggered_dates, backtest,
                            trigger_infos[type(action)]
                            if type(action) in trigger_infos else None)

        logging.info(
            f'Filtering strategy calculations to run from {strategy_start_date} to {strategy_end_date}'
        )
        backtest.portfolio_dict = defaultdict(
            Portfolio, {
                k: backtest.portfolio_dict[k]
                for k in backtest.portfolio_dict
                if strategy_start_date <= k <= strategy_end_date
            })
        backtest.scaling_portfolios = defaultdict(
            list, {
                k: backtest.scaling_portfolios[k]
                for k in backtest.scaling_portfolios
                if strategy_start_date <= k <= strategy_end_date
            })

        logging.info(
            'Pricing simple and semi-deterministic triggers and actions')
        with PricingContext(is_batch=True,
                            show_progress=show_progress,
                            csa_term=csa_term,
                            visible_to_gs=visible_to_gs):
            backtest.calc_calls += 1
            for day, portfolio in backtest.portfolio_dict.items():
                if isinstance(day, dt.date):
                    with PricingContext(day):
                        backtest.calculations += len(portfolio) * len(risks)
                        backtest.add_results(day, portfolio.calc(tuple(risks)))

            # semi path dependent initial calc
            for _, scaling_list in backtest.scaling_portfolios.items():
                for p in scaling_list:
                    with HistoricalPricingContext(dates=p.dates):
                        backtest.calculations += len(risks) * len(p.dates)
                        port = p.trade if isinstance(
                            p.trade, Portfolio) else Portfolio([p.trade])
                        p.results = port.calc(tuple(risks))

        logging.info(
            'Scaling semi-deterministic triggers and actions and calculating path dependent triggers '
            'and actions')
        for d in strategy_pricing_dates:
            logging.info(f'{d}: Processing triggers and actions')
            # path dependent
            for trigger in strategy.triggers:
                if trigger.calc_type == CalcType.path_dependent:
                    if trigger.has_triggered(d, backtest):
                        for action in trigger.actions:
                            self.get_action_handler(action).apply_action(
                                d, backtest)
                else:
                    for action in trigger.actions:
                        if action.calc_type == CalcType.path_dependent:
                            if trigger.has_triggered(d, backtest):
                                self.get_action_handler(action).apply_action(
                                    d, backtest)
            # test to see if new trades have been added and calc
            port = []
            for t in backtest.portfolio_dict[d]:
                if t.name not in list(backtest.results[d].to_frame().index):
                    port.append(t)

            with PricingContext(is_batch=True,
                                csa_term=csa_term,
                                show_progress=show_progress,
                                visible_to_gs=visible_to_gs):
                if len(port):
                    with PricingContext(pricing_date=d):
                        results = Portfolio(port).calc(tuple(risks))

                for sp in backtest.scaling_portfolios[d]:
                    if sp.results is None:
                        with HistoricalPricingContext(dates=sp.dates):
                            backtest.calculations += len(risks) * len(sp.dates)
                            port_sp = sp.trade if isinstance(
                                sp.trade, Portfolio) else Portfolio([sp.trade])
                            sp.results = port_sp.calc(tuple(risks))

            # results should be added outside of pricing context and not in the same call as valuating them
            if len(port):
                backtest.add_results(d, results)

            # semi path dependent scaling
            if d in backtest.scaling_portfolios:
                for p in backtest.scaling_portfolios[d]:
                    current_risk = backtest.results[d][p.risk].aggregate(
                        allow_mismatch_risk_keys=True)
                    hedge_risk = p.results[d][p.risk].aggregate()
                    if current_risk.unit != hedge_risk.unit:
                        raise RuntimeError(
                            'cannot hedge in a different currency')
                    scaling_factor = current_risk / hedge_risk
                    if isinstance(p.trade, Portfolio):
                        # Scale the portfolio by risk target
                        scaled_portfolio_position = copy.deepcopy(p.trade)
                        scaled_portfolio_position.name = f'Scaled_{scaled_portfolio_position.name}'
                        for instrument in scaled_portfolio_position.all_instruments:
                            instrument.name = f'Scaled_{instrument.name}'

                        # trade hedge in opposite direction
                        scale_direction = -1
                        scaled_portfolio_position.scale(scaling_factor *
                                                        scale_direction)

                        for day in p.dates:
                            # add scaled hedge position to portfolio for day. NOTE this adds leaves, not the portfolio
                            backtest.portfolio_dict[day] += copy.deepcopy(
                                scaled_portfolio_position)

                        # now apply scaled portfolio to cash payments
                        for d, payments in backtest.cash_payments.items():
                            for payment in payments:
                                if payment.trade == p.trade:
                                    payment.trade = copy.deepcopy(
                                        scaled_portfolio_position)
                                    payment.scale_date = None

                    else:
                        new_notional = getattr(
                            p.trade, p.scaling_parameter) * -scaling_factor
                        scaled_trade = p.trade.as_dict()
                        scaled_trade[p.scaling_parameter] = new_notional
                        scaled_trade = Instrument.from_dict(scaled_trade)
                        scaled_trade.name = p.trade.name
                        for day in p.dates:
                            backtest.add_results(
                                day, p.results[day] * -scaling_factor)
                            backtest.portfolio_dict[day] += Portfolio(
                                scaled_trade)

        logging.info('Calculating and scaling newly added portfolio positions')
        # test to see if new trades have been added and calc
        with PricingContext(is_batch=True,
                            show_progress=show_progress,
                            csa_term=csa_term,
                            visible_to_gs=visible_to_gs):
            backtest.calc_calls += 1
            leaves_by_date = {}
            for day, portfolio in backtest.portfolio_dict.items():
                results_for_date = backtest.results[day]
                if len(results_for_date) == 0:
                    continue

                trades_for_date = list(results_for_date.to_frame().index)
                leaves = []
                for leaf in portfolio:
                    if leaf.name not in trades_for_date:
                        logging.info(
                            f'{day}: new portfolio position {leaf} scheduled for calculation'
                        )
                        leaves.append(leaf)

                if len(leaves):
                    with PricingContext(pricing_date=day):
                        leaves_by_date[day] = Portfolio(leaves).calc(
                            tuple(risks))
                        backtest.calculations += len(leaves) * len(risks)

        logging.info('Processing results for newly added portfolio positions')
        for day, leaves in leaves_by_date.items():
            backtest.add_results(day, leaves)

        logging.info('Calculating prices for cash payments')
        # run any additional calcs to handle cash scaling (e.g. unwinds)
        cash_results = {}
        with PricingContext(is_batch=True,
                            show_progress=show_progress,
                            csa_term=csa_term,
                            visible_to_gs=visible_to_gs):
            backtest.calc_calls += 1
            cash_trades_by_date = defaultdict(list)
            for _, cash_payments in backtest.cash_payments.items():
                for cp in cash_payments:
                    # only calc if additional point is required
                    trades = cp.trade.all_instruments if isinstance(
                        cp.trade, Portfolio) else [cp.trade]
                    for trade in trades:
                        if cp.effective_date and cp.effective_date <= end:
                            if cp.effective_date not in backtest.results or \
                                    trade not in backtest.results[cp.effective_date]:
                                cash_trades_by_date[cp.effective_date].append(
                                    trade)
                            else:
                                cp.scale_date = None

            for cash_date, trades in cash_trades_by_date.items():
                with PricingContext(cash_date):
                    backtest.calculations += len(risks)
                    cash_results[cash_date] = Portfolio(trades).calc(
                        price_risk)

        # handle cash
        current_value = None
        for d in sorted(
                set(strategy_pricing_dates +
                    list(backtest.cash_payments.keys()))):
            if d <= end:
                if current_value is not None:
                    backtest.cash_dict[d] = current_value
                if d in backtest.cash_payments:
                    for cp in backtest.cash_payments[d]:
                        trades = cp.trade.all_instruments if isinstance(
                            cp.trade, Portfolio) else [cp.trade]
                        for trade in trades:
                            value = cash_results.get(
                                cp.effective_date,
                                {}).get(price_risk, {}).get(trade.name, {})
                            try:
                                value = backtest.results[cp.effective_date][price_risk][trade.name] \
                                    if value == {} else value
                            except (KeyError, ValueError):
                                raise RuntimeError(
                                    f'failed to get cash value for {trade.name} on '
                                    f'{cp.effective_date} received value of {value}'
                                )
                            if not isinstance(value, float):
                                raise RuntimeError(
                                    f'failed to get cash value for {trade.name} on '
                                    f'{cp.effective_date} received value of {value}'
                                )
                            ccy = next(iter(value.unit))
                            if d not in backtest.cash_dict:
                                backtest.cash_dict[d] = {ccy: initial_value}
                            if ccy not in backtest.cash_dict[d]:
                                backtest.cash_dict[d][ccy] = 0
                            if cp.scale_date:
                                scale_notional = backtest.portfolio_dict[
                                    cp.scale_date][
                                        cp.trade.name].notional_amount
                                scale_date_adj = scale_notional / cp.trade.notional_amount
                                cp.cash_paid = value * scale_date_adj * cp.direction
                                backtest.cash_dict[d][ccy] += cp.cash_paid
                            else:
                                cp.cash_paid = (
                                    0 if cp.cash_paid is None else
                                    cp.cash_paid) + value * cp.direction
                                backtest.cash_dict[d][ccy] += cp.cash_paid

                current_value = copy.deepcopy(backtest.cash_dict[d])

        logging.info(f'Finished Backtest:- {dt.datetime.now()}')
        return backtest
Beispiel #28
0
    def run_backtest(cls,
                     strategy,
                     start=None,
                     end=None,
                     frequency='BM',
                     window=None,
                     states=None,
                     risks=Price,
                     show_progress=True):
        dates = pd.date_range(start=start, end=end,
                              freq=frequency).date.tolist()
        risks = make_list(risks) + strategy.risks

        backtest = BackTest(strategy, dates, risks)

        for trigger in strategy.triggers:
            if trigger.calc_type != CalcType.path_dependent:
                triggered_dates = [
                    date for date in dates
                    if trigger.has_triggered(date, backtest)
                ]
                for action in trigger.actions:
                    if action.calc_type != CalcType.path_dependent:
                        action.apply_action(triggered_dates, backtest)

        with PricingContext(is_batch=True, show_progress=show_progress):
            for day, portfolio in backtest.portfolio_dict.items():
                with PricingContext(day):
                    backtest.calc_calls += 1
                    backtest.calculations += len(portfolio) * len(risks)
                    backtest.add_results(day, portfolio.calc(tuple(risks)))

            # semi path dependent initial calc
            for _, scaling_list in backtest.scaling_portfolios.items():
                for p in scaling_list:
                    with HistoricalPricingContext(dates=p.dates):
                        backtest.calc_calls += 1
                        backtest.calculations += len(p.dates) * len(risks)
                        p.results = Portfolio([p.trade]).calc(tuple(risks))

        for date in dates:
            # semi path dependent scaling
            if date in backtest.scaling_portfolios:
                for p in backtest.scaling_portfolios[date]:
                    scale_date = p.dates[0]
                    scaling_factor = backtest.results[scale_date][
                        p.risk][0] / p.results[scale_date][p.risk][0]
                    scaled_trade = p.trade.as_dict()
                    scaled_trade['notional_amount'] *= scaling_factor
                    scaled_trade = Instrument.from_dict(scaled_trade)
                    for day in p.dates:
                        backtest.add_results(day,
                                             p.results[day] * scaling_factor)
                        backtest.portfolio_dict[day] += Portfolio(scaled_trade)

            # path dependent
            for trigger in strategy.triggers:
                if trigger.calc_type == CalcType.path_dependent:
                    if trigger.has_triggered(date, backtest):
                        for action in trigger.actions:
                            action.apply_action(date, backtest)
                else:
                    for action in trigger.actions:
                        if action.calc_type == CalcType.path_dependent:
                            if trigger.has_triggered(date, backtest):
                                action.apply_action(date, backtest)
            return backtest
Beispiel #29
0
def test_results_with_resolution(mocker):
    with MockCalc(mocker):

        swap1 = IRSwap('Pay', '10y', 'USD', name='swap1')
        swap2 = IRSwap('Pay', '10y', 'GBP', name='swap2')
        swap3 = IRSwap('Pay', '10y', 'EUR', name='swap3')

        portfolio = Portfolio((swap1, swap2, swap3))

        with PricingContext(pricing_date=dt.date(2020, 10, 15)):
            result = portfolio.calc((risk.DollarPrice, risk.IRDelta))

        # Check that we've got results
        assert result[swap1][risk.DollarPrice] is not None

        # Now resolve portfolio and assert that we can still get the result

        orig_swap1 = swap1.clone()

        with PricingContext(pricing_date=dt.date(2020, 10, 15)):
            portfolio.resolve()

        # Assert that the resolved swap is indeed different and that we can retrieve results by both

        assert swap1 != orig_swap1
        assert result[swap1][risk.DollarPrice] is not None
        assert result[orig_swap1][risk.DollarPrice] is not None

        # Now reset the instruments and portfolio

        swap1 = IRSwap('Pay', '10y', 'USD', name='swap1')
        swap2 = IRSwap('Pay', '10y', 'GBP', name='swap2')
        swap3 = IRSwap('Pay', '10y', 'EUR', name='swap3')

        portfolio = Portfolio((swap1, swap2, swap3, swap1))

        with PricingContext(dt.date(2020, 10, 14)):
            # Resolve under a different pricing date
            portfolio.resolve()

        assert portfolio.instruments[0].termination_date == dt.date(
            2030, 10, 16)
        assert portfolio.instruments[1].termination_date == dt.date(
            2030, 10, 14)
        assert round(swap1.fixed_rate, 4) == 0.0075
        assert round(swap2.fixed_rate, 4) == 0.004
        assert round(swap3.fixed_rate, 4) == -0.0027

        # Assert that after resolution under a different context, we cannot retrieve the result

        try:
            _ = result[swap1][risk.DollarPrice]
            assert False
        except KeyError:
            assert True

        # Resolve again and check we get the same values

        with PricingContext(dt.date(2020, 10, 14)):
            # Resolve under a different pricing date
            portfolio.resolve()

        assert portfolio.instruments[0].termination_date == dt.date(
            2030, 10, 16)
        assert portfolio.instruments[1].termination_date == dt.date(
            2030, 10, 14)
        assert round(swap1.fixed_rate, 4) == 0.0075
        assert round(swap2.fixed_rate, 4) == 0.004
        assert round(swap3.fixed_rate, 4) == -0.0027
Beispiel #30
0
    def run_backtest(self,
                     strategy,
                     start=None,
                     end=None,
                     frequency='BM',
                     states=None,
                     risks=Price,
                     show_progress=True,
                     csa_term=None):
        """
        run the backtest following the triggers and actions defined in the strategy.  If states are entered run on
        those dates otherwise build a schedule from the start, end, frequency using pd.date_range
        :param strategy: the strategy object
        :param start: a datetime
        :param end: a datetime
        :param frequency: str or DateOffset, default 'D'. Frequency strings can have multiples, e.g. '5H'.
        :param window: not used yet - intended for running a strategy over a series of potentially overlapping dates
        :param states: a list of dates will override the start, end, freq if provided
        :param risks: risks to run
        :param show_progress: boolean default true
        :param csa_term: the csa term to use
        :return: a backtest object containing the portfolios on each day and results which show all risks on all days

        """

        dates = pd.date_range(
            start=start, end=end,
            freq=frequency).date.tolist() if states is None else states
        risks = make_list(risks) + strategy.risks

        backtest = BackTest(strategy, dates, risks)

        if len(strategy.initial_portfolio):
            init_port = Portfolio(strategy.initial_portfolio)
            with PricingContext(pricing_date=dates[0], csa_term=csa_term):
                init_port.resolve()
            for d in dates:
                backtest.portfolio_dict[d].append(init_port.instruments)

        for trigger in strategy.triggers:
            if trigger.calc_type != CalcType.path_dependent:
                triggered_dates = []
                trigger_infos = defaultdict(list)
                for d in dates:
                    t_info = trigger.has_triggered(d, backtest)
                    if t_info:
                        triggered_dates.append(d)
                        if t_info.info_dict:
                            for k, v in t_info.info_dict.items():
                                trigger_infos[k].append(v)

                for action in trigger.actions:
                    if action.calc_type != CalcType.path_dependent:
                        self.get_action_handler(action).apply_action(
                            triggered_dates, backtest,
                            trigger_infos[type(action)]
                            if type(action) in trigger_infos else None)

        with PricingContext(is_batch=True,
                            show_progress=show_progress,
                            csa_term=csa_term):
            for day, portfolio in backtest.portfolio_dict.items():
                with PricingContext(day):
                    backtest.calc_calls += 1
                    backtest.calculations += len(portfolio) * len(risks)
                    backtest.add_results(day, portfolio.calc(tuple(risks)))

            # semi path dependent initial calc
            for _, scaling_list in backtest.scaling_portfolios.items():
                for p in scaling_list:
                    with HistoricalPricingContext(dates=p.dates):
                        backtest.calc_calls += 1
                        backtest.calculations += len(p.dates) * len(risks)
                        p.results = Portfolio([p.trade]).calc(tuple(risks))

        for d in dates:
            # semi path dependent scaling
            if d in backtest.scaling_portfolios:
                for p in backtest.scaling_portfolios[d]:
                    current_risk = backtest.results[d][p.risk].aggregate(
                        allow_mismatch_risk_keys=True)
                    hedge_risk = p.results[d][p.risk].aggregate()
                    scaling_factor = current_risk / hedge_risk
                    new_notional = p.trade.notional_amount * -scaling_factor
                    scaled_trade = p.trade.as_dict()
                    scaled_trade['notional_amount'] = new_notional
                    scaled_trade = Instrument.from_dict(scaled_trade)
                    scaled_trade.name = p.trade.name
                    for day in p.dates:
                        backtest.add_results(day,
                                             p.results[day] * -scaling_factor)
                        backtest.portfolio_dict[day] += Portfolio(scaled_trade)

            # path dependent
            for trigger in strategy.triggers:
                if trigger.calc_type == CalcType.path_dependent:
                    if trigger.has_triggered(d, backtest):
                        for action in trigger.actions:
                            self.get_action_handler(action).apply_action(
                                d, backtest)
                else:
                    for action in trigger.actions:
                        if action.calc_type == CalcType.path_dependent:
                            if trigger.has_triggered(d, backtest):
                                self.get_action_handler(action).apply_action(
                                    d, backtest)

        # run any additional calcs to handle cash scaling (e.g. unwinds)
        cash_results = defaultdict(list)
        with PricingContext(is_batch=True, csa_term=csa_term):
            for _, cash_payments in backtest.cash_payments.items():
                for cp in cash_payments:
                    # only calc if additional point is required
                    if cp.effective_date and cp.effective_date <= end and \
                            cp.trade not in backtest.results[cp.effective_date]:
                        with PricingContext(cp.effective_date):
                            backtest.calc_calls += 1
                            backtest.calculations += len(risks)
                            cash_results[cp.effective_date].append(
                                Portfolio([cp.trade]).calc(tuple(risks)))

        # add cash to risk results
        for day, risk_results in cash_results.items():
            for rr in risk_results:
                backtest.add_results(day, rr)

        # handle cash
        for day, cash_payments in backtest.cash_payments.items():
            if day <= end:
                for cp in cash_payments:
                    if cp.scale_date:
                        scale_notional = backtest.portfolio_dict[
                            cp.scale_date][cp.trade.name].notional_amount
                        scale_date_adj = scale_notional / cp.trade.notional_amount
                        backtest.cash_dict[cp.effective_date] += \
                            backtest.results[cp.effective_date][Price][cp.trade] * scale_date_adj * cp.direction
                    else:
                        backtest.cash_dict[day] += backtest.results[day][
                            Price][cp.trade] * cp.direction

        return backtest