def test__adjust_number_of_open_positions_2(self, generate_close_orders): """ Test description: - max number of positions is 1 - portfolio contains position with contract ExampleZ00 Comdty - there is a signal with suggested exposure LONG for ExampleN01 Comdty - Expected output: ExampleN01 Comdty suggested exposure will be unchanged """ self.future_ticker.get_current_specific_ticker.return_value = BloombergTicker( "ExampleN01 Comdty") alpha_model_strategy = AlphaModelStrategy( self.ts, {self.alpha_model: [self.future_ticker]}, use_stop_losses=False, max_open_positions=1) self.alpha_model.get_signal.return_value = Signal( self.future_ticker, Exposure.LONG, 1) self.positions_in_portfolio = [ Mock(spec=BacktestPosition, **{ 'contract.return_value': Contract("ExampleZ00 Comdty", "FUT", "SIM_EXCHANGE"), 'quantity.return_value': -10, 'start_time': str_to_date("2000-01-01") }) ] alpha_model_strategy.on_before_market_open() self.ts.position_sizer.size_signals.assert_called_with( [Signal(self.future_ticker, Exposure.LONG, 1)], False)
def get_signal(self, ticker: Ticker, current_exposure: Exposure) -> Signal: """ Returns the Signal calculated for a specific AlphaModel and a set of data for a specified Ticker Parameters ---------- ticker: Ticker A ticker of an asset for which the Signal should be generated current_exposure: Exposure The actual exposure, based on which the AlphaModel should return its Signal. Can be different from previous Signal suggestions, but it should correspond with the current trading position Returns ------- Signal Signal being the suggestion for the next trading period """ suggested_exposure = self.calculate_exposure(ticker, current_exposure) fraction_at_risk = self.calculate_fraction_at_risk(ticker) signal = Signal(ticker, suggested_exposure, fraction_at_risk, alpha_model=self) return signal
def test__adjust_number_of_open_positions_4(self): """ Test description: - max number of positions is 1 - portfolio contains position with contract ExampleZ00 Comdty - there is signal for ExampleZ00 Comdty with suggested exposure OUT and for Example Ticker - LONG - Expected output: Example Ticker will be changed to OUT """ self.future_ticker.get_current_specific_ticker.return_value = BloombergTicker( "AN01 Index") alpha_model_strategy = AlphaModelStrategy(self.ts, { self.alpha_model: [ BloombergTicker("ExampleZ00 Comdty"), BloombergTicker("Example Ticker") ] }, use_stop_losses=False, max_open_positions=1) exposures = { BloombergTicker("ExampleZ00 Comdty"): Exposure.OUT, BloombergTicker("Example Ticker"): Exposure.LONG, } self.alpha_model.get_signal.side_effect = lambda ticker, _: Signal( ticker, exposures[ticker], 1) self.positions_in_portfolio = [ Mock(spec=BacktestPosition, **{ 'contract.return_value': Contract("ExampleZ00 Comdty", "FUT", "SIM_EXCHANGE"), 'quantity.return_value': -10, 'start_time': str_to_date("2000-01-01") }) ] alpha_model_strategy.on_before_market_open() self.ts.position_sizer.size_signals.assert_called_once() args, kwargs = self.ts.position_sizer.size_signals.call_args_list[0] signals, _ = args expected_signals = [ Signal(BloombergTicker("ExampleZ00 Comdty"), Exposure.OUT, 1), Signal(BloombergTicker("Example Ticker"), Exposure.OUT, 1) ] self.assertCountEqual(signals, expected_signals)
def test__adjust_number_of_open_positions__multiple_models_3( self, generate_close_orders): """ Test description: - max number of positions is 1 - portfolio contains position with contract ExampleZ00 Comdty - ExampleZ00 Comdty ane Example Ticker are traded by two independent alpha models - there is signal with suggested exposure LONG for Example Ticker and OUT for ExampleN00 Comdty - Expected output: Example Ticker suggested exposure will be changed to OUT """ self.future_ticker.get_current_specific_ticker.return_value = BloombergTicker( "ExampleN00 Comdty") alpha_model_2 = MagicMock() alpha_model_strategy = AlphaModelStrategy(self.ts, { self.alpha_model: [self.future_ticker], alpha_model_2: [BloombergTicker("Example Ticker")] }, use_stop_losses=False, max_open_positions=1) self.alpha_model.get_signal.return_value = Signal( self.future_ticker, Exposure.OUT, 1) alpha_model_2.get_signal.return_value = Signal( BloombergTicker("Example Ticker"), Exposure.LONG, 1) self.positions_in_portfolio = [ Mock(spec=BacktestPosition, **{ 'contract.return_value': Contract("ExampleZ00 Comdty", "FUT", "SIM_EXCHANGE"), 'quantity.return_value': -10, 'start_time': str_to_date("2000-01-01") }) ] alpha_model_strategy.on_before_market_open() self.ts.position_sizer.size_signals.assert_called_once() args, kwargs = self.ts.position_sizer.size_signals.call_args_list[0] signals, _ = args expected_signals = [ Signal(self.future_ticker, Exposure.OUT, 1), Signal(BloombergTicker("Example Ticker"), Exposure.OUT, 1) ] self.assertCountEqual(signals, expected_signals)
def test_out_signal(self): fraction_at_risk = 0.02 signal = Signal(self.ticker, Exposure.OUT, fraction_at_risk) orders = self.simple_position_sizer.size_signals([signal]) self.assertEqual(len(orders), 1) # market order only self.assertEqual( orders[0], Order(self.contract, -200, MarketOrder(), TimeInForce.OPG))
def test_alpha_model__get_signal(self, calculate_fraction_at_risk, calculate_exposure_mock): calculate_exposure_mock.return_value = Exposure.LONG calculate_fraction_at_risk.return_value = 3 alpha_model = AlphaModel(risk_estimation_factor=4, data_handler=MagicMock()) signal = alpha_model.get_signal(self.ticker, Exposure.OUT) expected_signal = Signal(self.ticker, Exposure.LONG, 3, alpha_model=alpha_model) self.assertEqual(signal, expected_signal)
def test_get_signals__one_ticker_multiple_signals(self): """ Save signals belonging to one ticker. In this case, even if multiple different signals will be generated for one date, only one of them will be returned (always the first one). """ ticker = BloombergTicker("Example Index") number_of_days = 30 start_date = str_to_date("2000-01-01") end_date = start_date + RelativeDelta(days=number_of_days - 1) signals_register = SignalsRegister() for date in date_range(start_date, end_date, freq="D"): signals_register.save_signals([Signal(ticker, Exposure.LONG, 0.0)], date) signals_register.save_signals([Signal(ticker, Exposure.SHORT, 0.0)], date) signals_df = signals_register.get_signals() self.assertEqual(type(signals_df), QFDataFrame) self.assertEqual(signals_df.shape, (number_of_days, 1)) for column, tms in signals_df.iteritems(): self.assertTrue(all(s.suggested_exposure == Exposure.LONG for s in tms))
def test_get_signals__one_future_ticker(self, ticker_mock): fut_ticker_1 = BloombergFutureTicker("Ticker name", "family id", 1, 1) ticker_mock.return_value = "Specific ticker" number_of_days = 30 start_date = str_to_date("2000-01-01") rolling_date = start_date + RelativeDelta(days=number_of_days - 1) signals_register = SignalsRegister() for date in date_range(start_date, rolling_date, freq="D"): signals_register.save_signals([Signal(fut_ticker_1, Exposure.LONG, 0.0)], date) signals_df = signals_register.get_signals() self.assertEqual(type(signals_df), QFDataFrame) self.assertEqual(signals_df.shape, (number_of_days, 1))
def test_simple_position_sizer(self): fraction_at_risk = 0.02 signal = Signal(self.ticker, Exposure.LONG, fraction_at_risk) orders = self.simple_position_sizer.size_signals([signal]) quantity = np.floor(self.initial_position * (1 / self.initial_allocation - 1)) self.assertEqual(len(orders), 2) # market order and stop order self.assertEqual( orders[0], Order(self.contract, quantity, MarketOrder(), TimeInForce.OPG)) stop_price = self.last_price * (1 - fraction_at_risk) stop_quantity = -(self.initial_position + quantity) self.assertEqual( orders[1], Order(self.contract, stop_quantity, StopOrder(stop_price), TimeInForce.GTC))
def test_get_signals__multiple_tickers(self): """ Save signals, which belong to multiple tickers. """ tickers = [BloombergTicker("Example Index"), BloombergTicker("Example 2 Index")] number_of_days = 30 start_date = str_to_date("2000-01-01") end_date = start_date + RelativeDelta(days=number_of_days - 1) signals_register = SignalsRegister() for date in date_range(start_date, end_date, freq="D"): signals_register.save_signals([Signal(ticker, Exposure.LONG, 0.0) for ticker in tickers], date) signals_df = signals_register.get_signals() self.assertEqual(type(signals_df), QFDataFrame) self.assertEqual(signals_df.shape, (number_of_days, 2))
def test_get_signals__single_contract(self): """ Save signals, which belong to one ticker (contract). The returned signals data frame should contain only one column, named after the ticker and used model. """ ticker = BloombergTicker("Example Index") number_of_days = 30 start_date = str_to_date("2000-01-01") end_date = start_date + RelativeDelta(days=number_of_days-1) signals_register = SignalsRegister() for date in date_range(start_date, end_date, freq="D"): signals_register.save_signals([Signal(ticker, Exposure.LONG, 0.0)], date) signals_df = signals_register.get_signals() self.assertEqual(type(signals_df), QFDataFrame) self.assertEqual(signals_df.shape, (number_of_days, 1))
def test_initial_risk_position_sizer_with_cap(self): """ Max leverage will be limited by position sizer to 1.5 """ fraction_at_risk = 0.01 # will give leverage of 2, that will be capped to 1.5 signal = Signal(self.ticker, Exposure.LONG, fraction_at_risk) orders = self.initial_risk_position_sizer.size_signals([signal]) self.assertEqual(len(orders), 2) # market order and stop order portfolio_value = self.initial_position / self.initial_allocation max_leverage = self.initial_risk_position_sizer.max_target_percentage target_quantity = int(np.floor(portfolio_value * max_leverage)) additional_contracts = target_quantity - self.initial_position self.assertEqual( orders[0], Order(self.contract, additional_contracts, MarketOrder(), TimeInForce.OPG)) stop_price = self.last_price * (1 - fraction_at_risk) stop_quantity = -(self.initial_position + additional_contracts) self.assertEqual( orders[1], Order(self.contract, stop_quantity, StopOrder(stop_price), TimeInForce.GTC))