Пример #1
0
    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)
Пример #2
0
    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.ticker = 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, Mock(), Mock())

        self.positions_in_portfolio = [
            Mock(spec=BacktestPosition,
                 **{
                     'ticker.return_value':
                     BloombergTicker("ExampleZ00 Comdty", SecurityType.FUTURE,
                                     1),
                     'quantity.return_value':
                     -10,
                     'start_time':
                     str_to_date("2000-01-01")
                 })
        ]
        alpha_model_strategy.calculate_and_place_orders()
        self.ts.position_sizer.size_signals.assert_called_with(
            [Signal(self.future_ticker, Exposure.LONG, 1, Mock(), Mock())],
            False, TimeInForce.OPG, Frequency.DAILY)
Пример #3
0
    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)
Пример #4
0
    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 = BacktestSignalsRegister()

        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))
Пример #5
0
    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,
                        self.last_price, self.timer.now())
        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.ticker, 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.ticker, stop_quantity, StopOrder(stop_price),
                  TimeInForce.GTC))
Пример #6
0
    def test_initial_risk_position_sizer_without_cap(self):
        """
        Max leverage will not be limited by position sizer
        """
        fraction_at_risk = 0.23
        signal = Signal(self.ticker, Exposure.LONG, fraction_at_risk,
                        self.last_price)
        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
        target_quantity = int(
            np.floor(portfolio_value * self.initial_risk / fraction_at_risk))
        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))
Пример #7
0
    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)
        last_available_price = self.data_handler.get_last_available_price(
            ticker)

        signal = Signal(ticker,
                        suggested_exposure,
                        fraction_at_risk,
                        last_available_price,
                        alpha_model=self)
        return signal
Пример #8
0
    def test__adjust_number_of_open_positions__multiple_models(self):
        """
        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 LONG for ExampleZ00 Comdty
        - Expected output: Example Ticker suggested exposure will be changed to OUT
        """
        alpha_model_2 = MagicMock()
        alpha_model_strategy = AlphaModelStrategy(self.ts, {
            self.alpha_model: [BloombergTicker("ExampleZ00 Comdty")],
            alpha_model_2: [BloombergTicker("Example Ticker")]
        },
                                                  use_stop_losses=False,
                                                  max_open_positions=1)

        self.alpha_model.get_signal.return_value = Signal(
            BloombergTicker("ExampleZ00 Comdty"), Exposure.LONG, 1, Mock(),
            Mock())
        alpha_model_2.get_signal.return_value = Signal(
            BloombergTicker("Example Ticker"), Exposure.LONG, 1, Mock(),
            Mock())

        self.positions_in_portfolio = [
            Mock(spec=BacktestPosition,
                 **{
                     'ticker.return_value':
                     BloombergTicker("ExampleZ00 Comdty", SecurityType.FUTURE,
                                     1),
                     'quantity.return_value':
                     -10,
                     'start_time':
                     str_to_date("2000-01-01")
                 })
        ]
        alpha_model_strategy.calculate_and_place_orders()
        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.LONG, 1,
                   Mock(), Mock()),
            Signal(BloombergTicker("Example Ticker"), Exposure.OUT, 1, Mock(),
                   Mock())
        ]
        self.assertCountEqual(signals, expected_signals)
Пример #9
0
    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_provider=MagicMock())
        signal = alpha_model.get_signal(self.ticker, Exposure.OUT)

        expected_signal = Signal(self.ticker, Exposure.LONG, 3, Mock(), Mock(), alpha_model=alpha_model)
        self.assertEqual(signal, expected_signal)
Пример #10
0
    def test_out_signal(self):
        fraction_at_risk = 0.02
        signal = Signal(self.ticker, Exposure.OUT, fraction_at_risk,
                        self.last_price)
        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))
Пример #11
0
    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)
Пример #12
0
    def test_decreasing_stop_price__with_open_positions(self):
        """
        Tests if the stop price of consecutive StopOrders, created for a single position, can decrease over time.
        The PositionSizer + Broker setup should not allow this situation to happen.
        """
        position_sizer = self.simple_position_sizer
        self.broker.get_open_orders.return_value = []

        # Set the last available price to 100, fraction_at_risk to 0.1, stop price would be in this case
        # equal to 100 * (1 - 0.1) = 90
        self.timer.now.return_value = str_to_date(
            "2017-01-01") + RelativeDelta(hours=7)
        self.last_price = 100
        fraction_at_risk = 0.1
        signal = Signal(self.ticker, Exposure.LONG, fraction_at_risk,
                        self.last_price)
        orders = position_sizer.size_signals([signal], use_stop_losses=True)
        stop_order_1 = [
            o for o in orders if isinstance(o.execution_style, StopOrder)
        ][0]

        # Simulate placing the orders - broker should return them as open orders
        self.broker.get_open_orders.return_value = orders

        # Simulate next day price change to a price above the previous stop_price - StopOrder is not triggered
        self.last_price = 91

        # Size signals once again (the next day). The new StopOrder stop price should not be lower than the
        # previous one (90)
        self.timer.now.return_value = str_to_date(
            "2017-01-02") + RelativeDelta(hours=7)
        signal = Signal(self.ticker, Exposure.LONG, fraction_at_risk,
                        self.last_price)
        orders = position_sizer.size_signals([signal], use_stop_losses=True)

        stop_order_2 = [
            o for o in orders if isinstance(o.execution_style, StopOrder)
        ][0]
        self.assertTrue(stop_order_1.execution_style.stop_price ==
                        stop_order_2.execution_style.stop_price)
Пример #13
0
    def test__adjust_number_of_open_positions_3(self, generate_close_orders):
        """
        Test description:
        - max number of positions is 1
        - portfolio contains position with contract ExampleZ00 Comdty
        - there are 2 LONG signals for ExampleN01 Comdty and Example Ticker
        - Expected output: Example Ticker will be changed to OUT, signal for ExampleN01 Comdty will be unchanged
        """
        self.future_ticker.ticker = BloombergTicker("ExampleN01 Comdty")
        alpha_model_strategy = AlphaModelStrategy(
            self.ts, {self.alpha_model: [self.future_ticker, self.ticker]},
            use_stop_losses=False,
            max_open_positions=1)
        self.alpha_model.get_signal.side_effect = lambda ticker, exposure, time, freq: Signal(
            ticker, Exposure.LONG, 1, Mock(), Mock())

        self.positions_in_portfolio = [
            Mock(spec=BacktestPosition,
                 **{
                     'ticker.return_value':
                     BloombergTicker("ExampleZ00 Comdty", SecurityType.FUTURE,
                                     1),
                     'quantity.return_value':
                     -10,
                     'start_time':
                     str_to_date("2000-01-01")
                 })
        ]
        alpha_model_strategy.calculate_and_place_orders()
        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.LONG, 1, Mock(), Mock()),
            Signal(self.ticker, Exposure.OUT, 1, Mock(), Mock())
        ]
        self.assertCountEqual(signals, expected_signals)
Пример #14
0
    def get_signal(self, ticker: Ticker, current_exposure: Exposure) -> Signal:
        self.ticker_name_to_ticker[ticker.name] = ticker
        suggested_exposure = self.calculate_exposure(ticker, current_exposure)
        fraction_at_risk = self.calculate_fraction_at_risk(ticker)

        specific_ticker = ticker.get_current_specific_ticker() if isinstance(
            ticker, FutureTicker) else ticker
        last_available_price = self.data_handler.get_last_available_price(
            specific_ticker)

        signal = Signal(ticker,
                        suggested_exposure,
                        fraction_at_risk,
                        last_available_price,
                        alpha_model=self)
        return signal
Пример #15
0
    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 = BacktestSignalsRegister()

        for date in date_range(start_date, rolling_date, freq="D"):
            signals_register.save_signals([Signal(fut_ticker_1, Exposure.LONG, 0.0, 17, date)])

        signals_df = signals_register.get_signals()

        self.assertEqual(type(signals_df), QFDataFrame)
        self.assertEqual(signals_df.shape, (number_of_days, 1))
Пример #16
0
    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 = BacktestSignalsRegister()

        for date in date_range(start_date, end_date, freq="D"):
            signals_register.save_signals([Signal(ticker, Exposure.LONG, 0.0, 17, date)])

        signals_df = signals_register.get_signals()

        self.assertEqual(type(signals_df), QFDataFrame)
        self.assertEqual(signals_df.shape, (number_of_days, 1))
Пример #17
0
    def test_simple_position_sizer(self):
        fraction_at_risk = 0.02
        signal = Signal(self.ticker, Exposure.LONG, fraction_at_risk,
                        self.last_price)
        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))
Пример #18
0
    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 = BacktestSignalsRegister()

        for date in date_range(start_date, end_date, freq="D"):
            signals_register.save_signals([Signal(ticker, Exposure.LONG, 0.0, 17, date) for ticker in tickers])

        signals_df = signals_register.get_signals()

        self.assertEqual(type(signals_df), QFDataFrame)
        self.assertEqual(signals_df.shape, (number_of_days, 2))
Пример #19
0
    def get_signal(self,
                   ticker: Ticker,
                   current_exposure: Exposure,
                   current_time: Optional[datetime] = None,
                   frequency: Frequency = Frequency.DAILY) -> 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
        current_time: Optional[datetime]
            current time, which is afterwards recorded inside each of the Signals. The parameter is optional and if not
            provided, defaults to the current user time.
        frequency: Optional[Frequency]
            frequency of trading. Optional parameter, with the default value being equal to daily frequency. Used to
            obtain the last available price.

        Returns
        -------
        Signal
            Signal being the suggestion for the next trading period
        """
        current_time = current_time or datetime.now()
        suggested_exposure = self.calculate_exposure(ticker, current_exposure)
        fraction_at_risk = self.calculate_fraction_at_risk(ticker)
        last_available_price = self.data_provider.get_last_available_price(
            ticker, frequency, current_time)

        signal = Signal(ticker,
                        suggested_exposure,
                        fraction_at_risk,
                        last_available_price,
                        current_time,
                        alpha_model=self)
        return signal
Пример #20
0
    def get_signal(self,
                   ticker: Ticker,
                   current_exposure: Exposure,
                   current_time: Optional[datetime] = None,
                   frequency: Frequency = Frequency.DAILY) -> Signal:

        current_time = current_time or datetime.now()
        self.ticker_name_to_ticker[ticker.name] = ticker
        suggested_exposure = self.calculate_exposure(ticker, current_exposure)
        fraction_at_risk = self.calculate_fraction_at_risk(ticker)

        specific_ticker = ticker.get_current_specific_ticker() if isinstance(
            ticker, FutureTicker) else ticker
        last_available_price = self.data_provider.get_last_available_price(
            specific_ticker, frequency, current_time)

        signal = Signal(ticker,
                        suggested_exposure,
                        fraction_at_risk,
                        last_available_price,
                        current_time,
                        alpha_model=self)
        return signal