def test_eq_vol_engine_result(mocker): # 1. setup strategy start_date = dt.date(2019, 2, 18) end_date = dt.date(2019, 2, 20) option = EqOption('.STOXX50E', expirationDate='3m', strikePrice='ATM', optionType=OptionType.Call, optionStyle=OptionStyle.European) action = EnterPositionQuantityScaledAction(priceables=option, trade_duration='1m') trigger = PeriodicTrigger( trigger_requirements=PeriodicTriggerRequirements(start_date=start_date, end_date=end_date, frequency='1m'), actions=action) hedgetrigger = PeriodicTrigger( trigger_requirements=PeriodicTriggerRequirements(start_date=start_date, end_date=end_date, frequency='B'), actions=HedgeAction(EqDelta, priceables=option, trade_duration='B')) strategy = Strategy(initial_portfolio=None, triggers=[trigger, hedgetrigger]) # 2. setup mock api response mock_api_response(mocker, api_mock_data()) # 3. when run backtest set_session() backtest_result = EquityVolEngine.run_backtest(strategy, start_date, end_date) # 4. assert response df = pd.DataFrame(api_mock_data().risks[FlowVolBacktestMeasure.PNL.value]) df.date = pd.to_datetime(df.date) expected_pnl = df.set_index('date').value assert expected_pnl.equals(backtest_result.get_measure_series(FlowVolBacktestMeasure.PNL))
def test_engine_mapping_trade_quantity_nav(mocker): # 1. setup strategy start_date = dt.date(2019, 2, 18) end_date = dt.date(2019, 2, 20) option = EqOption('.STOXX50E', expirationDate='3m', strikePrice='ATM', optionType=OptionType.Call, optionStyle=OptionStyle.European) action = EnterPositionQuantityScaledAction(priceables=option, trade_duration='1m', trade_quantity=12345, trade_quantity_type=BacktestTradingQuantityType.NAV) trigger = PeriodicTrigger( trigger_requirements=PeriodicTriggerRequirements(start_date=start_date, end_date=end_date, frequency='1m'), actions=action) hedgetrigger = PeriodicTrigger( trigger_requirements=PeriodicTriggerRequirements(start_date=start_date, end_date=end_date, frequency='B'), actions=HedgeAction(EqDelta, priceables=option, trade_duration='B')) strategy = Strategy(initial_portfolio=None, triggers=[trigger, hedgetrigger]) # 2. setup mock api response mock_api_response(mocker, api_mock_data()) # 3. when run backtest set_session() EquityVolEngine.run_backtest(strategy, start_date, end_date) # 4. assert API call backtest_parameter_args = { 'trading_parameters': BacktestTradingParameters( quantity=12345, quantity_type=BacktestTradingQuantityType.NAV.value, trade_in_method=TradeInMethod.FixedRoll.value, roll_frequency='1m'), 'underliers': [BacktestStrategyUnderlier( instrument=option, notional_percentage=100, hedge=BacktestStrategyUnderlierHedge(risk_details=DeltaHedgeParameters(frequency='Daily')), market_model='SFK') ], 'index_initial_value': 12345, "measures": [FlowVolBacktestMeasure.ALL_MEASURES] } backtest_parameters = VolatilityFlowBacktestParameters.from_dict(backtest_parameter_args) backtest = Backtest(name="Flow Vol Backtest", mq_symbol="Flow Vol Backtest", parameters=backtest_parameters, start_date=start_date, end_date=end_date, type='Volatility Flow', asset_class=AssetClass.Equity, currency=Currency.USD, cost_netting=False) mocker.assert_called_with(backtest, None)
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_supports_strategy(): # 1. Valid strategy start_date = dt.date(2019, 2, 18) end_date = dt.date(2019, 2, 20) option = EqOption('.STOXX50E', expirationDate='3m', strikePrice='ATM', optionType=OptionType.Call, optionStyle=OptionStyle.European) action = AddTradesQuantityScaledAction(priceables=option, trade_duration='1m') trigger = PeriodicTrigger(trigger_requirements=PeriodicTriggerRequirements( start_date=start_date, end_date=end_date, frequency='1m'), actions=action) hedge_trigger = PeriodicTrigger( trigger_requirements=PeriodicTriggerRequirements(start_date=start_date, end_date=end_date, frequency='B'), actions=HedgeAction(EqDelta, priceables=option, trade_duration='B')) strategy = Strategy(initial_portfolio=None, triggers=[trigger, hedge_trigger]) assert EquityVolEngine.supports_strategy(strategy) # 2. Invalid - no trade action trigger = PeriodicTrigger(trigger_requirements=PeriodicTriggerRequirements( start_date=start_date, end_date=end_date, frequency='1m'), actions=None) strategy = Strategy(initial_portfolio=None, triggers=[trigger]) assert not EquityVolEngine.supports_strategy(strategy) # 3. Invalid - no trade quantity action = AddTradesQuantityScaledAction(priceables=option, trade_duration='1m', trade_quantity=None) trigger = PeriodicTrigger(trigger_requirements=PeriodicTriggerRequirements( start_date=start_date, end_date=end_date, frequency='1m'), actions=action) strategy = Strategy(initial_portfolio=None, triggers=[trigger]) assert not EquityVolEngine.supports_strategy(strategy) # 4. Invalid - no trade quantity type action = AddTradesQuantityScaledAction(priceables=option, trade_duration='1m', trade_quantity_type=None) trigger = PeriodicTrigger(trigger_requirements=PeriodicTriggerRequirements( start_date=start_date, end_date=end_date, frequency='1m'), actions=action) strategy = Strategy(initial_portfolio=None, triggers=[trigger]) assert not EquityVolEngine.supports_strategy(strategy) # 5. Invalid - mismatch trade duration and trigger period action = AddTradesQuantityScaledAction(priceables=option, trade_duration='2m', trade_quantity_type=None) trigger = PeriodicTrigger(trigger_requirements=PeriodicTriggerRequirements( start_date=start_date, end_date=end_date, frequency='1m'), actions=action) strategy = Strategy(initial_portfolio=None, triggers=[trigger]) assert not EquityVolEngine.supports_strategy(strategy) # 6. Invalid - mismatch hedge trade duration and trigger period action = AddTradesQuantityScaledAction(priceables=option, trade_duration='1m', trade_quantity_type=None) trigger = PeriodicTrigger(trigger_requirements=PeriodicTriggerRequirements( start_date=start_date, end_date=end_date, frequency='1m'), actions=action) hedge_trigger = PeriodicTrigger( trigger_requirements=PeriodicTriggerRequirements(start_date=start_date, end_date=end_date, frequency='B'), actions=HedgeAction(EqDelta, priceables=option, trade_duration='M')) strategy = Strategy(initial_portfolio=None, triggers=[trigger, hedge_trigger]) assert not EquityVolEngine.supports_strategy(strategy) # 6. Invalid - non-daily hedge trade action = AddTradesQuantityScaledAction(priceables=option, trade_duration='1m', trade_quantity_type=None) trigger = PeriodicTrigger(trigger_requirements=PeriodicTriggerRequirements( start_date=start_date, end_date=end_date, frequency='1m'), actions=action) hedge_trigger = PeriodicTrigger( trigger_requirements=PeriodicTriggerRequirements(start_date=start_date, end_date=end_date, frequency='M'), actions=HedgeAction(EqDelta, priceables=option, trade_duration='M')) strategy = Strategy(initial_portfolio=None, triggers=[trigger, hedge_trigger]) assert not EquityVolEngine.supports_strategy(strategy)