def test_leg_valuations(mocker): with MockCalc(mocker): # children legs return values _, r1, f1 = get_attributes(mcb, risk.FXSpot) assert isinstance(r1.futures[0].result(), DataFrameWithInfo) assert 'path' in f1.columns
def test_exit_action_bytradename(mocker): with MockCalc(mocker): start_date = date(2021, 12, 6) end_date = date(2021, 12, 10) # Define trade irswap1 = IRSwap(PayReceive.Receive, '10y', Currency.USD, notional_amount=1e5, name='swap1') irswap2 = IRSwap(PayReceive.Pay, '5y', Currency.USD, notional_amount=1e5, name='swap2') trig_req_add = PeriodicTriggerRequirements(start_date=start_date, end_date=end_date, frequency='1b') trig_req_exit = PeriodicTriggerRequirements(start_date=start_date, end_date=end_date, frequency='2b') actions_add = AddTradeAction([irswap1, irswap2]) actions_exit = ExitTradeAction('swap1') triggers = [ PeriodicTrigger(trig_req_add, actions_add), PeriodicTrigger(trig_req_exit, actions_exit) ] strategy = Strategy(None, triggers) # run backtest daily engine = GenericEngine() # backtest = engine.run_backtest(strategy, start=start_date, end=end_date, frequency='1b', show_progress=True) backtest = engine.run_backtest(strategy, states=[ date(2021, 12, 6), date(2021, 12, 7), date(2021, 12, 8), date(2021, 12, 9), date(2021, 12, 10) ], end=end_date, show_progress=True) trade_ledger = backtest.trade_ledger().to_dict('index') assert trade_ledger['Action1_swap1_2021-12-06']['Open'] == date( 2021, 12, 6) assert trade_ledger['Action1_swap1_2021-12-06']['Close'] == date( 2021, 12, 6) assert trade_ledger['Action1_swap1_2021-12-07']['Open'] == date( 2021, 12, 7) assert trade_ledger['Action1_swap1_2021-12-07']['Close'] == date( 2021, 12, 8) assert trade_ledger['Action1_swap2_2021-12-06']['Status'] == 'open' assert trade_ledger['Action1_swap2_2021-12-07']['Status'] == 'open' assert trade_ledger['Action1_swap2_2021-12-10']['Status'] == 'open'
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)
def test_one_portfolio(mocker): with MockCalc(mocker): _, r1, f1 = get_attributes(eur_port, risk.Price) _, r2, f2 = get_attributes(eur_port, (risk.Price, risk.DollarPrice)) _, _, f3 = get_attributes(Portfolio(swap_1, name='swap_1'), (risk.Price, risk.DollarPrice)) price_values_test(r1, f1) price_values_test(r2, f2) default_pivot_table_test(r1) default_pivot_table_test(r2) # test slicing # slice one risk measure sub_r1 = r1[risk.Price] assert sub_r1 == r1 # slice one instrument sub_r2 = r2[swap_1].to_frame().values[0] assert all(sub_r2 == f3['value'].values) # test aggregate agg_r1 = r1.aggregate().to_frame() agg_r2 = r2.aggregate().to_frame().values[0] assert agg_r1 == sum(f1['value'].values) assert all(agg_r2 == [ sum(f2.loc[f2['risk_measure'] == rm]['value'].values) for rm in [risk.Price, risk.DollarPrice] ])
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(2020, 10, 7) 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=[-35280379.86540368, -35348910.76427929, -30830994.939595155], index=business_day_offset(pricing_date, [-1, 0, 1], roll='forward')), risk_key=risk_key.ex_date_and_market, ) actual = results[risk.DollarPrice].aggregate() assert actual.equals(expected)
def test_historical_pricing(mocker): with MockCalc(mocker): swap1 = IRSwap('Pay', '10y', 'USD', fixed_rate='ATM+1', name='10y@a+1') swap2 = IRSwap('Pay', '10y', 'USD', fixed_rate='ATM+2', name='10y@a+2') swap3 = IRSwap('Pay', '10y', 'USD', fixed_rate='ATM+3', name='10y@a+3') portfolio = Portfolio((swap1, swap2, swap3)) dates = (dt.date(2021, 2, 9), dt.date(2021, 2, 10), dt.date(2021, 2, 11)) with HistoricalPricingContext(dates=dates) 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=[-580316.7895084377, -580373.4091600645, -580811.1441974249], index=[dt.date(2021, 2, 9), dt.date(2021, 2, 10), dt.date(2021, 2, 11)] ), risk_key=historical_risk_key(risk_key), ) assert results.dates == dates actual = results[risk.DollarPrice].aggregate() assert actual.equals(expected) assert (results[dt.date(2021, 2, 9)][risk.DollarPrice]['10y@a+1'] == results[risk.DollarPrice][dt.date(2021, 2, 9)]['10y@a+1']) assert (results[dt.date(2021, 2, 9)][risk.DollarPrice]['10y@a+1'] == results[risk.DollarPrice]['10y@a+1'][dt.date(2021, 2, 9)]) assert (results[dt.date(2021, 2, 9)][risk.DollarPrice]['10y@a+1'] == results['10y@a+1'][risk.DollarPrice][dt.date(2021, 2, 9)]) assert (results[dt.date(2021, 2, 9)][risk.DollarPrice]['10y@a+1'] == results['10y@a+1'][dt.date(2021, 2, 9)][risk.DollarPrice]) assert (results[dt.date(2021, 2, 9)][risk.DollarPrice]['10y@a+1'] == results[dt.date(2021, 2, 9)]['10y@a+1'][risk.DollarPrice])
def test_aggregation_with_diff_risk_keys(mocker): with MockCalc(mocker): portfolio1 = Portfolio([ IRSwaption('Pay', '10y', 'EUR', expiration_date='3m', name='EUR3m10ypayer') ]) portfolio2 = Portfolio([ IRSwaption('Pay', '10y', 'EUR', expiration_date='6m', name='EUR6m10ypayer') ]) with PricingContext(csa_term='EUR-OIS', visible_to_gs=True): r1 = portfolio1.price() with PricingContext(csa_term='EUR-EuroSTR'): r2 = portfolio2.price() combined_result = r1 + r2 with pytest.raises(ValueError): combined_result.aggregate() assert isinstance(combined_result.aggregate(allow_mismatch_risk_keys=True), float)
def test_aggregation_with_empty_measures(mocker): with MockCalc(mocker): swaptions = (IRSwaption(notional_currency='EUR', termination_date='7y', expiration_date='1y', pay_or_receive='Receive', strike='ATM+35', name='EUR 1y7y'), IRSwaption(notional_currency='EUR', termination_date='10y', expiration_date='2w', pay_or_receive='Receive', strike='ATM+50', name='EUR 2w10y')) portfolio = Portfolio(swaptions) from_date = dt.date(2021, 11, 18) to_date = dt.date(2021, 11, 19) explain_2d = PnlExplain(CloseMarket(date=to_date)) with PricingContext(pricing_date=from_date, visible_to_gs=True): portfolio.resolve() result_explain = portfolio.calc(explain_2d) total_risk = aggregate_risk(result_explain[explain_2d])['value'].sum() risk_swaption_1 = result_explain[0]['value'].sum() risk_swaption_2 = result_explain[1]['value'].sum() assert total_risk == risk_swaption_1 + risk_swaption_2
def test_unnamed_portfolio(mocker): unnamed_1 = Portfolio((swap_1, swap_2)) unnamed_2 = Portfolio((swap_3, swap_4)) unnamed = Portfolio((unnamed_1, unnamed_2)) with MockCalc(mocker): res = unnamed.calc(risk.IRFwdRate) df = res.to_frame() assert len(df) == 2 assert list(df.index) == ['Portfolio_0', 'Portfolio_1'] assert list(df.columns) == ['5y', '10y']
def test_single_instrument_new_mock(mocker): with MockCalc(mocker): with PricingContext(pricing_date=dt.date(2020, 10, 15)): swap1 = IRSwap('Pay', '10y', 'USD', name='swap1') portfolio = Portfolio(swap1) fwd: PortfolioRiskResult = portfolio.calc(risk.IRFwdRate) assert portfolio.paths('swap1') == (PortfolioPath(0), ) assert tuple(map(lambda x: round(x, 6), fwd)) == (0.007512, ) assert round(fwd.aggregate(), 2) == 0.01 assert round(fwd[swap1], 6) == 0.007512
def test_currency_params(mocker): price = risk.Price myr_price = risk.Price(currency="MYR") with MockCalc(mocker): res1 = swap_1.calc(myr_price) res2 = swap_1.calc(price) res3 = swap_1.calc((price, myr_price)) assert (res1 != res2) assert (res3[price] == res2) assert (res3[myr_price] == res1)
def test_single_instrument(mocker): with MockCalc(mocker): swap1 = IRSwap('Pay', '10y', 'USD', fixed_rate=0.0, name='10y@0') portfolio = Portfolio(swap1) assert portfolio.paths('10y@0') == (PortfolioPath(0), ) with PricingContext(pricing_date=dt.date(2020, 10, 15)): prices: PortfolioRiskResult = portfolio.dollar_price() assert tuple(map(lambda x: round(x, 0), prices)) == (7391258.0, ) assert round(prices.aggregate(), 0) == 7391258.0 assert round(prices[swap1], 0) == 7391258.0
def test_dated_risk_values(mocker): with MockCalc(mocker): _, res1, frame1 = get_attributes(port, risk.Price, 'Multiple') _, res2, frame2 = get_attributes(port1, (risk.DollarPrice, risk.Price), 'Multiple') _, res3, frame3 = get_attributes(port1, risk.Price) _, res4, frame4 = get_attributes(port1, (risk.DollarPrice, risk.Price)) _, res5, frame5 = get_attributes(gbp_port, (risk.DollarPrice, risk.Price), 'Multiple') _, res6, frame6 = get_attributes(jpy_port, risk.Price, 'Multiple') price_values_test(res1, frame1, 'dated') price_values_test(res2, frame2, 'dated') price_values_test(res5, frame5, 'dated') price_values_test(res6, frame6, 'dated') default_pivot_table_test(res1, 'dated') default_pivot_table_test(res2, 'dated') default_pivot_table_test(res5, 'dated') default_pivot_table_test(res6, 'dated') # test slicing sub_res1 = res1[risk.Price] assert sub_res1 == res1 # slice one date slice_date_res2 = res2[date(2020, 1, 14)] assert all(slice_date_res2.to_frame(None, None, None) == frame4) slice_date_res3 = slice_date_res2[risk.Price] assert all(slice_date_res3.to_frame(None, None, None) == frame3) # slice dates slice_date_res2 = res2[[date(2020, 1, 14), date(2020, 1, 15)]] assert all(slice_date_res2.to_frame(None, None, None) == frame2) # test aggregate agg_res5 = res5.aggregate().to_frame(None, None, None) def filter_lambda(x): return (x['risk_measure'] == risk.DollarPrice) & (x['dates'] == date( 2020, 1, 14)) manual_agg_r5 = frame5.loc[frame5.apply(filter_lambda, axis=1)]['value'].values.sum() filter_agg_res5 = agg_res5.loc[agg_res5.apply(filter_lambda, axis=1)]['value'].values[0] assert filter_agg_res5 == manual_agg_r5 sub_res6 = res6.aggregate().to_frame().loc[date(2020, 1, 14)].values[0] manual_agg_r6 = frame6.loc[frame6['dates'] == date( 2020, 1, 14)]['value'].values.sum() assert sub_res6 == manual_agg_r6
def test_unsupported_error_datums(mocker): with MockCalc(mocker): f1 = eur_port.calc(risk.IRAnnualImpliedVol).to_frame() _, _, f2 = get_attributes(swap_port1, risk.IRAnnualImpliedVol) _, _, f3 = get_attributes(swaption_port1, risk.IRAnnualImpliedVol) _, _, f4 = get_attributes(swaption_port3, risk.IRAnnualImpliedVol) # assert that unsupported datums do not appear to_frame() assert f1 is None assert all(f2['value'] == f3['value']) # assert that errorvalue appears in to_frame() assert isinstance(f4['value'].values[0], ErrorValue)
def test_resolve_to_frame(mocker): # makes sure resolving portfolio doesn't break to_frame with MockCalc(mocker): _, r1, f1 = get_attributes(eur_port, risk.Price, resolve=True) _, r2, f2 = get_attributes(port1, risk.Price, resolve=True) _, r3, f3 = get_attributes(jpy_port, risk.Price, 'RollFwd', resolve=True) _, r4, f4 = get_attributes(port1, risk.Price, 'CurveScen1', resolve=True)
def test_cashflows_risk(mocker): with MockCalc(mocker): _, _, frame1 = get_attributes(eur_port, risk.Cashflows) _, _, frame2 = get_attributes(port1, risk.Cashflows) assert 'payment_date' in frame1.columns.values assert 'payment_date' in frame2.columns.values assert np.unique(frame1.risk_measure.values)[0] == risk.Cashflows assert np.unique(frame2.risk_measure.values)[0] == risk.Cashflows assert 'instrument_name' in frame1.columns.values assert 'instrument_name' in frame2.columns.values assert 'portfolio_name_0' in frame2.columns.values
def test_hedge_action_risk_trigger(mocker): with MockCalc(mocker): start_date = date(2021, 12, 1) # end_date = date(2021, 12, 3) # Define trade call = FXOption(buy_sell='Buy', option_type='Call', pair='USDJPY', strike_price='ATMF', notional_amount=1e5, expiration_date='2y', name='2y_call') hedge_risk = FXDelta(aggregation_level='Type') fwd_hedge = FXForward(pair='USDJPY', settlement_date='2y', notional_amount=1e5, name='2y_forward') trig_req = RiskTriggerRequirements(risk=hedge_risk, trigger_level=0, direction=TriggerDirection.ABOVE) action_hedge = HedgeAction(hedge_risk, fwd_hedge, '2b') triggers = StrategyRiskTrigger(trig_req, action_hedge) with PricingContext(pricing_date=start_date): fut = call.resolve(in_place=False) call = fut.result() strategy = Strategy(call, triggers) # run backtest daily engine = GenericEngine() # backtest = engine.run_backtest(strategy, start=start_date, end=end_date, frequency='1b', show_progress=True) backtest = engine.run_backtest( strategy, states=[date(2021, 12, 1), date(2021, 12, 2), date(2021, 12, 3)], show_progress=True) summary = backtest.result_summary assert len(summary) == 3 assert round(summary[hedge_risk].sum()) == 0 assert round(summary['Cumulative Cash'].sum()) == -7090 assert Price in summary.columns
def test_duplicate_instrument(mocker): with MockCalc(mocker): swap1 = IRSwap('Pay', '1y', 'EUR', name='EUR1y') swap2 = IRSwap('Pay', '2y', 'EUR', name='EUR2y') swap3 = IRSwap('Pay', '3y', 'EUR', name='EUR3y') portfolio = Portfolio((swap1, swap2, swap3, swap1)) assert portfolio.paths('EUR1y') == (PortfolioPath(0), PortfolioPath(3)) assert portfolio.paths('EUR2y') == (PortfolioPath(1), ) with PricingContext(pricing_date=dt.date(2020, 10, 15)): fwds: PortfolioRiskResult = portfolio.calc(risk.IRFwdRate) assert tuple(map(lambda x: round(x, 6), fwds)) == (-0.005378, -0.005224, -0.00519, -0.005378) assert round(fwds.aggregate(), 6) == -0.02117 assert round(fwds[swap1], 6) == -0.005378
def test_finite_difference_params(mocker): nok_delta = risk.IRDelta(currency="NOK") local_ccy_delta = risk.IRDelta(currency='local') with MockCalc(mocker): res3 = swap_1.calc(risk.IRDelta) res5 = swap_1.calc((risk.Price, nok_delta)) res6 = swap_1.calc((local_ccy_delta, nok_delta)) res7 = swap_1.calc( risk.IRDelta(aggregation_level=AggregationLevel.Asset)) assert isinstance(res5[risk.Price], FloatWithInfo) assert isinstance(res5[nok_delta], DataFrameWithInfo) assert res6[local_ccy_delta]['value'].size != res6[nok_delta]['value'].size assert res6[local_ccy_delta]['value'].size != res3['value'].size assert res6[nok_delta]['value'].size != res3['value'].size assert res7['mkt_asset'].size == 2
def test_mkt_trigger_data_sources(mocker): with MockCalc(mocker): s = pd.Series({ date(2021, 10, 1): 0.984274, date(2021, 10, 4): 1.000706, date(2021, 10, 5): 1.044055, date(2021, 10, 6): 1.095361, date(2021, 10, 7): 1.129336, date(2021, 10, 8): 1.182954, date(2021, 10, 12): 1.200108, date(2021, 10, 13): 1.220607, date(2021, 10, 14): 1.172837, date(2021, 10, 15): 1.163660, date(2021, 10, 18): 1.061084, date(2021, 10, 19): 1.025012, date(2021, 10, 20): 1.018035, date(2021, 10, 21): 1.080751, date(2021, 10, 22): 1.069340, date(2021, 10, 25): 1.033413 }) action = AddTradeAction( IRSwaption(notional_currency='USD', expiration_date='1y', termination_date='1y'), 'expiration_date') data_source = GenericDataSource(s, MissingDataStrategy.fill_forward) mkt_trigger = MktTrigger( MktTriggerRequirements(data_source, 1.1, TriggerDirection.ABOVE), action) strategy = Strategy(None, mkt_trigger) engine = GenericEngine() # backtest = engine.run_backtest(strategy, start=date(2021, 10, 1), end=date(2021, 10, 25), frequency='1b', # show_progress=True) backtest = engine.run_backtest(strategy, states=s.index, show_progress=True) summary = backtest.result_summary ledger = backtest.trade_ledger() assert len(summary) == 12 assert len(ledger) == 6 assert round(summary[Price].sum()) == 25163614 assert round(summary['Cumulative Cash'].sum()) == -2153015
def test_historical_pricing(mocker): with MockCalc(mocker): swap1 = IRSwap('Pay', '10y', 'USD', fixed_rate='ATM+1', name='10y@a+1') swap2 = IRSwap('Pay', '10y', 'USD', fixed_rate='ATM+2', name='10y@a+2') swap3 = IRSwap('Pay', '10y', 'USD', fixed_rate='ATM+3', name='10y@a+3') portfolio = Portfolio((swap1, swap2, swap3)) dates = (dt.date(2019, 10, 7), dt.date(2019, 10, 8), dt.date(2019, 10, 9)) with HistoricalPricingContext(dates=dates) 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=[ -564854.3640043903, -565604.2636791412, -564751.5121349357 ], index=[ dt.date(2019, 10, 7), dt.date(2019, 10, 8), dt.date(2019, 10, 9) ]), risk_key=risk_key.ex_date_and_market, ) assert results.dates == dates actual = results[risk.DollarPrice].aggregate() assert actual.equals(expected) assert (results[dt.date(2019, 10, 9)][risk.DollarPrice]['10y@a+1'] == results[risk.DollarPrice][dt.date(2019, 10, 9)]['10y@a+1']) assert (results[dt.date(2019, 10, 9)][risk.DollarPrice]['10y@a+1'] == results[risk.DollarPrice]['10y@a+1'][dt.date(2019, 10, 9)]) assert (results[dt.date(2019, 10, 9)][risk.DollarPrice]['10y@a+1'] == results['10y@a+1'][risk.DollarPrice][dt.date(2019, 10, 9)]) assert (results[dt.date( 2019, 10, 9)][risk.DollarPrice]['10y@a+1'] == results['10y@a+1'][dt.date( 2019, 10, 9)][risk.DollarPrice]) assert (results[dt.date( 2019, 10, 9)][risk.DollarPrice]['10y@a+1'] == results[dt.date( 2019, 10, 9)]['10y@a+1'][risk.DollarPrice])
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
def test_pricing_context(mocker): swap1 = IRSwap('Pay', '1y', 'EUR', name='EUR1y') future_date = business_day_offset(dt.date.today(), 10, roll='forward') with MockCalc(mocker): with RollFwd(date='10b', realise_fwd=True): market = swap1.market() with pytest.raises(ValueError): # cannot pass in future date into pricing context, use RollFwd instead with PricingContext(pricing_date=future_date): _ = swap1.calc(risk.Price) # cannot pass in market dated in the future into pricing context, use RollFwd instead with PricingContext(market=CloseMarket(date=future_date)): _ = swap1.calc(risk.Price) with PricingContext(market=OverlayMarket(base_market=CloseMarket(date=future_date, location='NYC'), market_data=market.result())): _ = swap1.calc(risk.Price)
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())
def test_empty_calc_request(mocker): # when calc req is sent for rm that inst is insensitive to with MockCalc(mocker): _, r1, f1 = get_attributes(swap_port1, (risk.IRVega, risk.Price)) _, r2, f2 = get_attributes( swap_port2, (risk.IRVega(aggregation_level=AggregationLevel.Asset), risk.Price)) _, r3, f3 = get_attributes( swap_port1, (risk.IRVega(aggregation_level=AggregationLevel.Asset, currency='local'), risk.Price)) _, r4, f4 = get_attributes(swap_port2, (risk.Price, risk.IRVega(currency='local'))) _, r5, f5 = get_attributes(swap_port2, (risk.Price, risk.IRVega), 'Multiple') _, r6, f6 = get_attributes( swap_port1, (risk.IRVega(aggregation_level=AggregationLevel.Asset), risk.Price), 'Multiple') _, r7, f7 = get_attributes( swap_port2, (risk.IRVega(aggregation_level=AggregationLevel.Asset, currency='local'), risk.Price), 'Multiple') _, r8, f8 = get_attributes(swap_port1, (risk.IRVega(currency='local'), risk.Price), 'Multiple') price_values_test(r1, f1) price_values_test(r2, f2) price_values_test(r3, f3) price_values_test(r4, f4) price_values_test(r5, f5, 'dated') price_values_test(r6, f6, 'dated') price_values_test(r7, f7, 'dated') price_values_test(r8, f8, 'dated') default_pivot_table_test(r1, 'has_bucketed') default_pivot_table_test(r2, 'has_bucketed') default_pivot_table_test(r3, 'has_bucketed') default_pivot_table_test(r4, 'has_bucketed') default_pivot_table_test(r5, 'has_bucketed') default_pivot_table_test(r6, 'has_bucketed') default_pivot_table_test(r7, 'has_bucketed') default_pivot_table_test(r8, 'has_bucketed')
def test_generic_engine_simple(mocker): with MockCalc(mocker): start_date = date(2021, 12, 1) # end_date = date(2021, 12, 3) # Define trade call = FXOption(buy_sell='Buy', option_type='Call', pair='USDJPY', strike_price='ATMF', notional_amount=1e5, expiration_date='2y', name='2y_call') # Periodic trigger: based on frequency freq = '1m' # trig_req = PeriodicTriggerRequirements(start_date=start_date, end_date=end_date, frequency=freq) trig_req = DateTriggerRequirements(dates=[start_date]) actions = AddTradeAction(call, freq) # starting with empty portfolio (first arg to Strategy), apply actions on trig_req triggers = DateTrigger(trig_req, actions) strategy = Strategy(None, triggers) # run backtest daily engine = GenericEngine() # backtest = engine.run_backtest(strategy, start=start_date, end=end_date, frequency='1b', show_progress=True) backtest = engine.run_backtest( strategy, states=[date(2021, 12, 1), date(2021, 12, 2), date(2021, 12, 3)], show_progress=True) summary = backtest.result_summary assert len(summary) == 3 assert round(summary[Price].sum()) == 2424 assert round(summary['Cumulative Cash'].sum()) == 0
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
def test_diff_types_risk_measures(mocker): # when risk results from scalar and bucketed risk measures are be to tabulated together with MockCalc(mocker): _, res1, frame1 = get_attributes(eur_port, (risk.Price, risk.IRDelta)) _, res2, frame2 = get_attributes(mixed_port, (risk.IRBasis, risk.Price)) _, res3, frame3 = get_attributes(mixed_port, (risk.IRBasis( aggregation_level=AggregationLevel.Asset), risk.Price)) _, res4, frame4 = get_attributes(eur_port, (risk.IRDelta, risk.Price), 'Multiple') _, res5, frame5 = get_attributes(mixed_port, (risk.Price, risk.IRBasis), 'Multiple') _, res6, frame6 = get_attributes(mixed_port, (risk.IRBasis( aggregation_level=AggregationLevel.Asset), risk.Price), 'Multiple') price_values_test(res1, frame1) price_values_test(res2, frame2) price_values_test(res3, frame3) price_values_test(res4, frame4, 'dated') price_values_test(res5, frame5, 'dated') price_values_test(res6, frame6, 'dated') default_pivot_table_test(res1, 'has_bucketed') default_pivot_table_test(res2, 'has_bucketed') default_pivot_table_test(res3, 'has_bucketed') default_pivot_table_test(res4, 'has_bucketed') default_pivot_table_test(res5, 'has_bucketed') default_pivot_table_test(res6, 'has_bucketed') # test aggregate sub_res1 = res1.aggregate().to_frame() assert all(sub_res1.loc[risk.IRDelta]['value'].values == res1[ risk.IRDelta].aggregate().to_frame()['value'].values) assert sub_res1.loc[risk.Price]['value'] == res1[ risk.Price].aggregate().to_frame()
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
def test_adding_risk_results(mocker): with MockCalc(mocker): result1 = get_attributes(eur_port, risk.Price, no_frame=True) result2 = get_attributes( eur_port, (risk.IRDelta(aggregation_level=AggregationLevel.Asset, currency='local'), risk.Price), no_frame=True) result3 = get_attributes( swaption_port, (risk.IRDelta(aggregation_level=AggregationLevel.Asset, currency='local'), risk.Price), no_frame=True) result4 = get_attributes(port1, risk.Price, no_frame=True) result5 = get_attributes( swaption_port, risk.IRVega(aggregation_level=AggregationLevel.Asset, ), no_frame=True) result6 = get_attributes(jpy_port, (risk.Price, ), 'RollFwd', no_frame=True) result7 = get_attributes(jpy_port, risk.Price, 'CurveScen1', no_frame=True) result8 = get_attributes(jpy_port, (risk.DollarPrice, risk.Price), 'CurveScen2', no_frame=True) # (2020, 1, 14) to (2020, 1, 15) result9 = get_attributes(port1, risk.Price, 'Multiple', no_frame=True) # (2020, 1, 16) to (2020, 1, 17) result10 = get_attributes(port1, risk.Price, 'Multiple2', no_frame=True) # (2020, 1, 14) result11 = get_attributes(port1, risk.Price, no_frame=True) # (2020, 1, 16), market_data_location='NYC' result12 = get_attributes(port1, risk.Price, 'PricingCtx2', no_frame=True) # (2020, 1, 16), market_data_location='LDN' result13 = get_attributes(port1, risk.Price, 'PricingCtx3', no_frame=True) # adding results with same portfolio but different risk measures add_1 = result3 + result5 # adding results with different portfolio but same risk measures add_2 = result2 + result3 # adding results with different portfolios and overlapping risk measures add_3 = result1 + result3 # adding results with different portfolios and different risk measures add_4 = result1 + result5 add_5 = result3 + result4 # adding dates add_6 = result9 + result13 add_7 = result11 + result13 add_8 = result10 + result11 add_9 = result9 + result10 default_pivot_table_test(add_1, 'has_bucketed') default_pivot_table_test(add_2, 'has_bucketed') default_pivot_table_test(add_3, 'has_bucketed') default_pivot_table_test(add_4, 'has_bucketed') default_pivot_table_test(add_5, 'has_bucketed') default_pivot_table_test(add_6, 'dated') default_pivot_table_test(add_7, 'dated') default_pivot_table_test(add_8, 'dated') default_pivot_table_test(add_9, 'dated') # throw value error when adding results where at least one particular value is being calculated twice # adding results with same portfolio but overlapping risk measures with pytest.raises(ValueError): _ = result1 + result2 # adding results with overlapping portfolios and different risk measures with pytest.raises(ValueError): _ = result2 + result4 # adding results with overlapping portfolios and same risk measures with pytest.raises(ValueError): _ = result1 + result4 # adding results with different scenarios with pytest.raises(ValueError): _ = result6 + result7 with pytest.raises(ValueError): _ = result7 + result8 # overlapping dates with pytest.raises(ValueError): _ = result9 + result11 with pytest.raises(ValueError): _ = result10 + result13 # adding results with different market locations with pytest.raises(ValueError): _ = result10 + result12 with pytest.raises(ValueError): _ = result9 + result12 with pytest.raises(ValueError): _ = result12 + result13 with pytest.raises(ValueError): _ = result11 + result12