예제 #1
0
    def test_volume_orders_filter__adjust_buy_stop_orders(self):
        """
        Test if StopOrders are adjusted in a correct way. Suppose, the StopOrder quantity will be much bigger than
        the current MarketOrder, because the position for the contract already existed for some time, e.g.
        - there exists an open LONG position of size 100
        - the position needs to be adjusted to 200
        - a new MarketOrder of size 100 is created
        - a new StopOrder of size -200 is created
        - the volume percentage limit limits the MarketOrder to 15% of avg daily volume (set to volume_value = 100)
        - then the StopOrder needs to be adjusted to -115
        """

        volume_percentage_limit = 0.15
        volume_value = 100.0
        data_handler = self._setup_data_handler(volume_value)
        volume_orders_verifier = VolumeOrdersFilter(
            data_handler, self.contract_ticker_mapper, volume_percentage_limit)

        # Initialize a list of orders, which do not exceed the maximum volume limit
        contract = self.contract_ticker_mapper.ticker_to_contract(self.ticker)
        buy_order = [
            Order(contract, 100, MarketOrder(), TimeInForce.GTC),
            Order(contract, -200, StopOrder(1.0), TimeInForce.GTC)
        ]

        new_orders = volume_orders_verifier.adjust_orders(buy_order)

        expected_buy_order = [
            Order(contract, 15, MarketOrder(), TimeInForce.GTC),
            Order(contract, -115, StopOrder(1.0), TimeInForce.GTC)
        ]
        self.assertCountEqual(new_orders, expected_buy_order)
예제 #2
0
    def test_volume_orders_filter__adjust_sell_stop_orders(self):
        """
        Test if StopOrders are adjusted in a correct way. The MarketOrder corresponding to StopOrder is a sell order.
        """

        volume_percentage_limit = 0.15
        volume_value = 100.0
        data_handler = self._setup_data_handler(volume_value)
        volume_orders_verifier = VolumeOrdersFilter(
            data_handler, self.contract_ticker_mapper, volume_percentage_limit)

        # Initialize a list of orders, which do not exceed the maximum volume limit
        contract = self.contract_ticker_mapper.ticker_to_contract(self.ticker)
        sell_order = [
            Order(contract, -100, MarketOrder(), TimeInForce.GTC),
            Order(contract, 200, StopOrder(1.0), TimeInForce.GTC)
        ]

        new_orders = volume_orders_verifier.adjust_orders(sell_order)

        expected_sell_order = [
            Order(contract, -15, MarketOrder(), TimeInForce.GTC),
            Order(contract, 115, StopOrder(1.0), TimeInForce.GTC)
        ]
        self.assertCountEqual(new_orders, expected_sell_order)
예제 #3
0
    def test_order_target_percent(self):
        quantity = 40
        execution_style = StopOrder(4.20)
        time_in_force = TimeInForce.GTC

        orders = self.order_factory.target_percent_orders({self.contract: 0.5}, execution_style, time_in_force)
        self.assertEqual(orders[0], Order(self.contract, quantity, execution_style, time_in_force))
예제 #4
0
    def test_market_opens_at_much_higher_price_than_it_closed_at_yesterday(
            self):
        self.buy_stop_loss_order = Order(self.msft_contract,
                                         quantity=1,
                                         execution_style=StopOrder(120.0),
                                         time_in_force=TimeInForce.GTC)

        self.exec_hanlder.accept_orders([self.buy_stop_loss_order])
        self._set_bar_for_today(open=120.0,
                                high=130.0,
                                low=68.0,
                                close=90.0,
                                volume=100000000.0)
        self.exec_hanlder.on_market_close(...)

        assert_lists_equal([], self.exec_hanlder.get_open_orders())
        verify(self.spied_monitor, times=3).record_transaction(...)
        verify(self.portfolio, times=3).transact_transaction(...)

        self.assertEqual(3, len(self.monitor.transactions))

        actual_transaction_3 = self.monitor.transactions[2]
        self.assertEqual(self.msft_contract, actual_transaction_3.contract)
        self.assertEqual(1, actual_transaction_3.quantity)
        self.assertEqual(120.0, actual_transaction_3.price)
        self.assertEqual(0.0, actual_transaction_3.commission)
예제 #5
0
    def test_market_opens_at_much_higher_price_than_it_closed_at_yesterday(
            self):
        self.buy_stop_loss_order = Order(self.msft_contract,
                                         quantity=1,
                                         execution_style=StopOrder(120.0),
                                         time_in_force=TimeInForce.GTC)

        self.exec_handler.assign_order_ids([self.buy_stop_loss_order])
        self._set_bar_for_today(open_price=120.0,
                                high_price=130.0,
                                low_price=68.0,
                                close_price=90.0,
                                volume=100000000.0)

        self._trigger_single_time_event()
        self.exec_handler.on_market_close(...)

        assert_lists_equal([], self.exec_handler.get_open_orders())

        expected_transactions = [
            Transaction(self.timer.now(), self.msft_contract, -1,
                        self.stop_loss_order_1.execution_style.stop_price, 0),
            Transaction(self.timer.now(), self.msft_contract, -1,
                        self.stop_loss_order_2.execution_style.stop_price, 0),
            Transaction(self.timer.now(), self.msft_contract, 1, 120, 0),
        ]
        self.monitor.record_transaction.assert_has_calls(
            call(t) for t in expected_transactions)
        self.portfolio.transact_transaction.assert_has_calls(
            call(t) for t in expected_transactions)

        self.assertEqual(self.monitor.record_transaction.call_count, 3)
        self.assertEqual(self.portfolio.transact_transaction.call_count, 3)
예제 #6
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))
예제 #7
0
    def test_order_target_value(self):
        execution_style = StopOrder(4.20)
        time_in_force = TimeInForce.GTC
        quantity = 4

        orders = self.order_factory.target_value_orders({self.contract: 140.0}, execution_style, time_in_force)
        self.assertEqual(orders[0], Order(self.contract, quantity, execution_style, time_in_force))
예제 #8
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))
예제 #9
0
    def test_order_value(self):
        value = 100.0
        quantity = floor(100.0 / self.share_price)  # type: int
        execution_style = StopOrder(4.20)
        time_in_force = TimeInForce.DAY

        orders = self.order_factory.value_orders({self.contract: value}, execution_style, time_in_force)
        self.assertEqual(orders[0], Order(self.contract, quantity, execution_style, time_in_force))
예제 #10
0
    def test_order_percent(self):
        percentage = 0.5
        execution_style = StopOrder(4.20)
        time_in_force = TimeInForce.GTC
        quantity = floor(percentage * self.current_portfolio_value / self.share_price)  # type: int

        orders = self.order_factory.percent_orders({self.contract: percentage}, execution_style, time_in_force)
        self.assertEqual(orders[0], Order(self.contract, quantity, execution_style, time_in_force))
예제 #11
0
    def setUp(self):
        self.start_date = str_to_date("2018-02-04")
        self.msft_contract = Contract(self.MSFT_TICKER_STR,
                                      security_type='SEK',
                                      exchange='TEST')
        self.msft_ticker = BloombergTicker(self.MSFT_TICKER_STR)

        self.contracts_to_tickers_mapper = DummyBloombergContractTickerMapper()
        timer = SettableTimer(initial_time=self.start_date)

        self.data_handler = mock(strict=True)

        self.scheduler = mock()

        self.commission_model = FixedCommissionModel(commission=0.0)
        self.monitor = _MonitorMock()
        self.spied_monitor = spy(self.monitor)
        self.portfolio = mock()

        slippage_model = PriceBasedSlippage(0.0)
        self.exec_hanlder = SimulatedExecutionHandler(
            self.data_handler, timer, self.scheduler, self.spied_monitor,
            self.commission_model, self.contracts_to_tickers_mapper,
            self.portfolio, slippage_model)

        self._set_current_msft_price(100.0)
        self.stop_loss_order_1 = Order(self.msft_contract,
                                       quantity=-1,
                                       execution_style=StopOrder(95.0),
                                       time_in_force=TimeInForce.GTC)
        self.stop_loss_order_2 = Order(self.msft_contract,
                                       quantity=-1,
                                       execution_style=StopOrder(90.0),
                                       time_in_force=TimeInForce.GTC)

        self.stop_loss_order_3 = Order(self.msft_contract,
                                       quantity=-1,
                                       execution_style=StopOrder(50.0),
                                       time_in_force=TimeInForce.DAY)

        self.exec_hanlder.accept_orders([
            self.stop_loss_order_1, self.stop_loss_order_2,
            self.stop_loss_order_3
        ])
예제 #12
0
    def test_order_target(self):
        quantity = -5
        execution_style = StopOrder(4.20)
        time_in_force = TimeInForce.DAY

        orders = self.order_factory.target_orders({self.ticker: 5},
                                                  execution_style,
                                                  time_in_force)
        self.assertEqual(
            orders[0],
            Order(self.ticker, quantity, execution_style, time_in_force))
예제 #13
0
    def openOrder(self, orderId: OrderId, ib_contract: Contract,
                  ib_order: IBOrder, orderState: OrderState):
        super().openOrder(orderId, ib_contract, ib_order, orderState)

        if ib_order.orderType.upper() == 'STP':
            execution_style = StopOrder(ib_order.auxPrice)
        elif ib_order.orderType.upper() == 'MKT':
            execution_style = MarketOrder()
        else:
            error_message = "Order Type is not supported: {}".format(
                ib_order.orderType)
            self.logger.error(error_message)
            raise ValueError(error_message)

        if ib_order.action.upper() == 'SELL':
            quantity = -ib_order.totalQuantity
        elif ib_order.action.upper() == 'BUY':
            quantity = ib_order.totalQuantity
        else:
            error_message = "Order Action is not supported: {}".format(
                ib_order.action)
            self.logger.error(error_message)
            raise ValueError(error_message)

        if ib_order.tif.upper() == 'DAY':
            time_in_force = TimeInForce.DAY
        elif ib_order.tif.upper() == 'GTC':
            time_in_force = TimeInForce.GTC
        elif ib_order.tif.upper() == 'OPG':
            time_in_force = TimeInForce.OPG
        else:
            error_message = "Time in Force is not supported: {}".format(
                ib_order.tif)
            self.logger.error(error_message)
            raise ValueError(error_message)

        try:
            ticker = self.contract_ticker_mapper.contract_to_ticker(
                IBContract.from_ib_contract(ib_contract))
            order = Order(ticker=ticker,
                          quantity=quantity,
                          execution_style=execution_style,
                          time_in_force=time_in_force,
                          order_state=orderState.status)

            order.id = int(orderId)
            self.order_list.append(order)
        except ValueError as e:
            self.logger.error(
                f"Open Order for contract {ib_contract} will be skipped due to the following error "
                f"during parsing: \n{e}")
예제 #14
0
    def calculate_signals(self):
        last_price = self.data_handler.get_last_available_price(self.ticker)

        orders = self.order_factory.target_percent_orders({self.ticker: 1.0}, MarketOrder(),
                                                          time_in_force=TimeInForce.OPG, tolerance_percentage=0.02)

        stop_price = last_price * (1 - self.percentage)
        execution_style = StopOrder(stop_price=stop_price)
        stop_order = self.order_factory.percent_orders({self.ticker: -1}, execution_style=execution_style,
                                                       time_in_force=TimeInForce.DAY)

        self.broker.cancel_all_open_orders()
        self.broker.place_orders(orders)
        self.broker.place_orders(stop_order)
예제 #15
0
    def openOrder(self, orderId: OrderId, ib_contract: IBContract,
                  ib_order: IBOrder, orderState: OrderState):
        contract = Contract(ib_contract.symbol, ib_contract.secType,
                            ib_contract.exchange)

        if ib_order.orderType.upper() == 'STP':
            execution_style = StopOrder(ib_order.auxPrice)
        elif ib_order.orderType.upper() == 'MKT':
            execution_style = MarketOrder()
        else:
            error_message = "Order Type is not supported: {}".format(
                ib_order.orderType)
            self.logger.error(error_message)
            raise ValueError(error_message)

        if ib_order.action.upper() == 'SELL':
            quantity = -ib_order.totalQuantity
        elif ib_order.action.upper() == 'BUY':
            quantity = ib_order.totalQuantity
        else:
            error_message = "Order Action is not supported: {}".format(
                ib_order.action)
            self.logger.error(error_message)
            raise ValueError(error_message)

        if ib_order.tif.upper() == 'DAY':
            time_in_force = TimeInForce.DAY
        elif ib_order.tif.upper() == 'GTC':
            time_in_force = TimeInForce.GTC
        elif ib_order.tif.upper() == 'OPG':
            time_in_force = TimeInForce.OPG
        else:
            error_message = "Time in Force is not supported: {}".format(
                ib_order.tif)
            self.logger.error(error_message)
            raise ValueError(error_message)

        order = Order(contract=contract,
                      quantity=quantity,
                      execution_style=execution_style,
                      time_in_force=time_in_force,
                      order_state=orderState.status)

        order.id = int(orderId)
        self.order_list.append(order)
예제 #16
0
    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))
예제 #17
0
    def _generate_stop_order(self, contract, signal, market_order: Order):
        # stop_quantity = existing position size + recent market orders quantity
        stop_quantity = self._get_existing_position_quantity(contract)

        if market_order is not None:
            stop_quantity += market_order.quantity

        if stop_quantity != 0:
            stop_price = self._calculate_stop_price(signal)
            assert is_finite_number(
                stop_price), "Stop price should be a finite number"

            # put minus before the quantity as stop order has to go in the opposite direction
            stop_orders = self._order_factory.orders(
                {contract: -stop_quantity}, StopOrder(stop_price),
                TimeInForce.GTC)

            assert len(stop_orders) == 1, "Only one order should be generated"
            return stop_orders[0]
        else:
            # quantity is 0 - no need to place a stop order
            return None
예제 #18
0
    def _generate_stop_order(
            self, signal,
            contract_to_market_order: Dict[Contract,
                                           Order]) -> Optional[Order]:
        """
        As each of the stop orders relies on the precomputed stop_price, which considers a.o. last available price of
        the security, orders are being created separately for each of the signals.
        """
        contract = self._contract_ticker_mapper.ticker_to_contract(
            signal.ticker)

        # stop_quantity = existing position size + recent market orders quantity
        stop_quantity = self._get_existing_position_quantity(contract)

        try:
            market_order = contract_to_market_order[contract]
            stop_quantity += market_order.quantity
        except KeyError:
            # Generated Market Order was equal to None
            pass

        if stop_quantity != 0:
            stop_price = self._calculate_stop_price(signal)
            if not is_finite_number(stop_price):
                self.logger.info("Stop price should be a finite number")
                return None

            stop_price = self._cap_stop_price(stop_price, signal)

            # put minus before the quantity as stop order has to go in the opposite direction
            stop_orders = self._order_factory.orders(
                {contract: -stop_quantity}, StopOrder(stop_price),
                TimeInForce.GTC)

            assert len(stop_orders) == 1, "Only one order should be generated"
            return stop_orders[0]
        else:
            # quantity is 0 - no need to place a stop order
            return None
예제 #19
0
    def setUp(self):
        MarketOpenEvent.set_trigger_time({
            "hour": 13,
            "minute": 30,
            "second": 0,
            "microsecond": 0
        })
        MarketCloseEvent.set_trigger_time({
            "hour": 20,
            "minute": 0,
            "second": 0,
            "microsecond": 0
        })

        self.start_date = str_to_date("2018-02-04")
        self.number_of_minutes = 5

        before_close = self.start_date + MarketCloseEvent.trigger_time(
        ) - RelativeDelta(minutes=self.number_of_minutes)

        self.msft_contract = Contract(self.MSFT_TICKER_STR,
                                      security_type='STK',
                                      exchange='TEST')
        self.msft_ticker = BloombergTicker(self.MSFT_TICKER_STR)

        contracts_to_tickers_mapper = SimulatedBloombergContractTickerMapper()
        self.timer = SettableTimer(initial_time=before_close)

        self.data_handler = Mock(spec=DataHandler)

        scheduler = Mock(spec=Scheduler)
        ScheduleOrderExecutionEvent.clear()

        # Set the periodic bar events to intraday trading
        IntradayBarEvent.frequency = Frequency.MIN_1

        commission_model = FixedCommissionModel(commission=0.0)
        self.monitor = Mock(spec=AbstractMonitor)
        self.portfolio = Mock(spec=Portfolio)

        slippage_model = PriceBasedSlippage(0.0, self.data_handler,
                                            contracts_to_tickers_mapper)
        self.exec_handler = SimulatedExecutionHandler(
            self.data_handler, self.timer, scheduler, self.monitor,
            commission_model, contracts_to_tickers_mapper, self.portfolio,
            slippage_model, RelativeDelta(minutes=self.number_of_minutes))

        self._set_last_available_price(100.0)
        self.stop_loss_order_1 = Order(self.msft_contract,
                                       quantity=-1,
                                       execution_style=StopOrder(95.0),
                                       time_in_force=TimeInForce.GTC)
        self.stop_loss_order_2 = Order(self.msft_contract,
                                       quantity=-1,
                                       execution_style=StopOrder(90.0),
                                       time_in_force=TimeInForce.GTC)

        self.stop_loss_order_3 = Order(self.msft_contract,
                                       quantity=-1,
                                       execution_style=StopOrder(50.0),
                                       time_in_force=TimeInForce.DAY)

        self.exec_handler.assign_order_ids([
            self.stop_loss_order_1, self.stop_loss_order_2,
            self.stop_loss_order_3
        ])