def __init__(self, data_provider: GeneralPriceProvider, settings: Settings,
                 pdf_exporter: PDFExporter, excel_exporter: ExcelExporter):
        self._logger = qf_logger.getChild(self.__class__.__name__)

        self._backtest_name = "Backtest Results"
        self._initial_cash = 10000000
        self._initial_risk = None
        self._benchmark_tms = None
        self._monitor_settings = None

        self._contract_ticker_mapper = SimulatedBloombergContractTickerMapper()

        self._commission_model_type = FixedCommissionModel
        self._commission_model_kwargs = {"commission": 0.0}

        self._slippage_model_type = PriceBasedSlippage
        self._slippage_model_kwargs = {
            "slippage_rate": 0.0,
            "max_volume_share_limit": None
        }

        self._position_sizer_type = SimplePositionSizer
        self._position_sizer_kwargs = dict()

        self._orders_filter_types_params = [
        ]  # type: List[Tuple[Type[OrdersFilter], Dict]]

        self._signals_register = None
        self._data_provider = data_provider
        self._settings = settings
        self._pdf_exporter = pdf_exporter
        self._excel_exporter = excel_exporter

        self._frequency = None
        self._scheduling_time_delay = RelativeDelta(minutes=1)

        BeforeMarketOpenEvent.set_trigger_time({
            "hour": 8,
            "minute": 0,
            "second": 0,
            "microsecond": 0
        })
        MarketOpenEvent.set_trigger_time({
            "hour": 13,
            "minute": 30,
            "second": 0,
            "microsecond": 0
        })
        MarketCloseEvent.set_trigger_time({
            "hour": 20,
            "minute": 0,
            "second": 0,
            "microsecond": 0
        })
        AfterMarketCloseEvent.set_trigger_time({
            "hour": 23,
            "minute": 00,
            "second": 0,
            "microsecond": 0
        })
 def setUp(self):
     BeforeMarketOpenEvent.set_trigger_time({
         "hour": 8,
         "minute": 0,
         "second": 0,
         "microsecond": 0
     })
     MarketOpenEvent.set_trigger_time({
         "hour": 13,
         "minute": 30,
         "second": 0,
         "microsecond": 0
     })
     MarketCloseEvent.set_trigger_time({
         "hour": 20,
         "minute": 0,
         "second": 0,
         "microsecond": 0
     })
     AfterMarketCloseEvent.set_trigger_time({
         "hour": 21,
         "minute": 0,
         "second": 0,
         "microsecond": 0
     })
 def setUpClass(cls) -> None:
     """ Setup a preset data provider and a scenario, in which the sized orders will exceed the volume limits. """
     MarketCloseEvent.set_trigger_time({
         "hour": 20,
         "minute": 0,
         "second": 0,
         "microsecond": 0
     })
     cls.ticker = BloombergTicker("Example Index")
     cls.contract_ticker_mapper = SimulatedBloombergContractTickerMapper()
Exemple #4
0
    def setUpClass(cls):
        cls.YESTERDAY_OPEN = str_to_date("2018-01-29 13:30:00.000000", DateFormat.FULL_ISO)
        cls.YESTERDAY_CLOSE = str_to_date("2018-01-29 20:00:00.000000", DateFormat.FULL_ISO)
        cls.TODAY_BEFORE_OPEN = str_to_date("2018-01-30 06:00:00.000000", DateFormat.FULL_ISO)
        cls.TODAY_OPEN = str_to_date("2018-01-30 13:30:00.000000", DateFormat.FULL_ISO)
        cls.TODAY_MIDDLE_DAY = str_to_date("2018-01-30 15:00:00.000000", DateFormat.FULL_ISO)
        cls.TODAY_CLOSE = str_to_date("2018-01-30 20:00:00.000000", DateFormat.FULL_ISO)
        cls.TODAY_AFTER_CLOSE = str_to_date("2018-01-30 20:00:00.000000", DateFormat.FULL_ISO)

        MarketOpenEvent.set_trigger_time({"hour": 13, "minute": 30, "second": 0, "microsecond": 0})
        MarketCloseEvent.set_trigger_time({"hour": 20, "minute": 0, "second": 0, "microsecond": 0})
    def setUpClass(cls):
        cls.start_date = str_to_date('2008-10-08')
        cls.end_date = str_to_date('2018-12-20')

        cls.timer = SettableTimer()
        cls.timer.set_current_time(cls.end_date)

        cls.frequency = Frequency.DAILY
        cls.ticker_1 = BloombergFutureTicker("Euroswiss", "ES{} Index", 1, 3, 100, "HMUZ")
        cls.ticker_2 = BloombergFutureTicker("Corn", "C {} Comdty", 1, 3, 100, "HKNUZ")

        MarketCloseEvent.set_trigger_time({"hour": 20, "minute": 00, "second": 0, "microsecond": 0})
 def setUp(self):
     self.timer, self.tickers, self.data_handler = _get_test_case_set_up()
     MarketOpenEvent.set_trigger_time({
         "hour": 13,
         "minute": 30,
         "second": 0,
         "microsecond": 0
     })
     MarketCloseEvent.set_trigger_time({
         "hour": 20,
         "minute": 0,
         "second": 0,
         "microsecond": 0
     })
Exemple #7
0
    def _get_prices_df(self, ticker: Ticker, start_date: datetime, end_date: datetime) -> PricesDataFrame:
        """ Returns non-adjusted open and close prices, indexed with the Market Open and Market Close time."""
        if isinstance(ticker, FutureTicker):
            ticker.initialize_data_provider(SettableTimer(end_date), self._data_provider)
            tickers_chain = ticker.get_expiration_dates()

            if start_date >= tickers_chain.index[-1] or end_date <= tickers_chain.index[0]:
                # If the futures chain starts after the _end_date or ends before the _start_date - no data available
                return PricesDataFrame()

            # Get all tickers from the chain that were valid between the start_date and expiration date of the
            # currently valid ticker
            end_date = tickers_chain[tickers_chain == ticker.get_current_specific_ticker()].index[0]
            tickers_chain = tickers_chain.loc[start_date:end_date]
            tickers = tickers_chain.values.tolist()

            open_prices = self._data_provider.get_price(tickers, PriceField.Open, start_date, end_date)
            close_prices = self._data_provider.get_price(tickers, PriceField.Close, start_date, end_date)
        else:
            open_prices = self._data_provider.get_price([ticker], PriceField.Open, start_date, end_date)
            close_prices = self._data_provider.get_price([ticker], PriceField.Close, start_date, end_date)

        open_prices.index = [dt + MarketOpenEvent.trigger_time() for dt in open_prices.index]
        close_prices.index = [dt + MarketCloseEvent.trigger_time() for dt in close_prices.index]
        prices = concat([open_prices, close_prices]).sort_index()
        return prices
Exemple #8
0
    def _data_array_to_dataframe(self, prices_data_array: QFDataArray):
        """
        Converts a QFDataArray into a DataFrame by removing the "Price Field" axis.

        In order to remove it open and close prices get different time component in their corresponding datetimes
        (open prices will get the time of `MarketOpenEvent` and close prices will get the time of `MarketCloseEvent`).
        """
        original_dates = prices_data_array.dates.to_index()

        market_open_datetimes = [
            price_datetime + MarketOpenEvent.trigger_time()
            for price_datetime in original_dates
        ]
        market_close_datetimes = [
            price_datetime + MarketCloseEvent.trigger_time()
            for price_datetime in original_dates
        ]

        new_dates = set(market_open_datetimes + market_close_datetimes)

        prices_df = PricesDataFrame(index=new_dates,
                                    columns=prices_data_array.tickers)
        prices_df.loc[
            market_open_datetimes, :] = prices_data_array.loc[:, :, PriceField.
                                                              Open].values
        prices_df.loc[
            market_close_datetimes, :] = prices_data_array.loc[:, :,
                                                               PriceField.
                                                               Close].values

        prices_df.sort_index(inplace=True)
        return prices_df
 def setUp(self):
     self.timer, self.tickers, self.data_handler = _get_test_case_set_up()
     self.tickers_index = pd.Index(self.tickers, name='tickers')
     self.fields_index = pd.Index(PriceField.ohlcv(), name='fields')
     MarketOpenEvent.set_trigger_time({
         "hour": 13,
         "minute": 30,
         "second": 0,
         "microsecond": 0
     })
     MarketCloseEvent.set_trigger_time({
         "hour": 20,
         "minute": 0,
         "second": 0,
         "microsecond": 0
     })
Exemple #10
0
    def __init__(self,
                 tickers: Union[Ticker, Sequence[Ticker]],
                 start_date: datetime,
                 end_date: datetime,
                 data_handler: DataHandler,
                 alpha_models: Union[AlphaModel, Sequence[AlphaModel]],
                 settings: Settings,
                 pdf_exporter: PDFExporter,
                 only_entry_signals: bool = True,
                 title: str = "Signals Plotter"):

        super().__init__(settings, pdf_exporter, title)

        # Set the market open and close events in order to use the data handler (necessary to e.g. compute the market
        # close time of the previous day)
        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.tickers, _ = convert_to_list(tickers, Ticker)
        self.alpha_models, _ = convert_to_list(alpha_models, AlphaModel)

        self.start_date = start_date
        self.end_date = end_date

        self.data_handler = data_handler

        assert isinstance(self.data_handler.timer, SettableTimer)
        self.timer: SettableTimer = self.data_handler.timer

        self.only_entry_signals = only_entry_signals

        for ticker in tickers:
            if isinstance(ticker, FutureTicker):
                ticker.initialize_data_provider(
                    self.timer, self.data_handler.data_provider)
    def _make_mock_data_array(self, tickers, fields):
        all_dates_market_open = pd.date_range(
            start=self.data_start_date + MarketOpenEvent.trigger_time(),
            end=self.data_end_date + MarketOpenEvent.trigger_time(),
            freq="B")
        all_dates_market_close = pd.date_range(
            start=self.data_start_date + MarketCloseEvent.trigger_time() -
            Frequency.MIN_1.time_delta(),
            end=self.data_end_date + MarketCloseEvent.trigger_time() -
            Frequency.MIN_1.time_delta(),
            freq="B")

        num_of_dates = len(all_dates_market_open)
        num_of_tickers = len(tickers)
        num_of_fields = len(fields)

        start_value = 100.0
        values = np.arange(
            start_value,
            num_of_dates * num_of_tickers * num_of_fields + start_value)
        reshaped_values = np.reshape(
            values, (num_of_dates, num_of_tickers, num_of_fields))

        mocked_result_market_open = QFDataArray.create(all_dates_market_open,
                                                       tickers,
                                                       fields,
                                                       data=reshaped_values)

        mocked_result_market_close = QFDataArray.create(all_dates_market_close,
                                                        tickers,
                                                        fields,
                                                        data=reshaped_values)
        mocked_result_market_close.loc[:, :, PriceField.Low] -= 5.0
        mocked_result_market_close.loc[:, :, PriceField.High] += 5.0

        all_dates = all_dates_market_open.union(all_dates_market_close)

        mocked_result = QFDataArray.create(all_dates, tickers, fields)
        mocked_result.loc[
            all_dates_market_open, :, :] = mocked_result_market_open.loc[:, :, :]
        mocked_result.loc[
            all_dates_market_close, :, :] = mocked_result_market_close.loc[:, :, :]

        self._add_test_cases(mocked_result, tickers)
        return mocked_result
Exemple #12
0
    def _get_current_prices(self, tickers: Sequence[Ticker]):
        """
        Function used to obtain the current prices for the tickers in order to further calculate fill prices for orders.
        The function uses data provider and not data handler, as it is necessary to get the current bar at each point
        in time to compute the fill prices.
        """
        if not tickers:
            return QFSeries()

        assert self._frequency >= Frequency.DAILY, "Lower than daily frequency is not supported by the simulated" \
                                                   " executor"

        # Compute the time ranges, used further by the get_price function
        current_datetime = self._timer.now()

        market_close_time = current_datetime + MarketCloseEvent.trigger_time(
        ) == current_datetime
        market_open_time = current_datetime + MarketOpenEvent.trigger_time(
        ) == current_datetime

        # In case of daily frequency, current price may be returned only at the Market Open or Market Close time
        if self._frequency == Frequency.DAILY and not (market_open_time
                                                       or market_close_time):
            return QFSeries(index=tickers)

        if self._frequency == Frequency.DAILY:
            # Remove the time part from the datetime in case of daily frequency
            current_datetime = date_to_datetime(current_datetime.date())
            start_time_range = current_datetime - self._frequency.time_delta()
            end_time_range = current_datetime
        elif market_close_time:
            # At the market close, in order to get the current price we need to take a bar that ends at the current time
            # and use the close price value
            start_time_range = current_datetime - self._frequency.time_delta()
            end_time_range = current_datetime
            current_datetime = start_time_range
        else:
            # At any other time during the day, in order to get the current price we need to take the bar that starts at
            # the current time and use the open price value
            start_time_range = current_datetime
            end_time_range = current_datetime + self._frequency.time_delta()

        price_field = PriceField.Close if market_close_time else PriceField.Open
        prices_df = self._data_provider.get_price(tickers, price_field,
                                                  start_time_range,
                                                  end_time_range,
                                                  self._frequency)

        try:
            prices_series = prices_df.loc[current_datetime]
        except KeyError:
            prices_series = QFSeries(index=tickers)

        prices_series.name = "Current prices series"
        return prices_series
Exemple #13
0
    def test_get_price_when_end_date_is_today_after_market_close(self):
        self.timer.set_current_time(
            str_to_date("2018-01-31") + MarketCloseEvent.trigger_time() +
            RelativeDelta(hours=1))
        prices_tms = self.data_handler.get_price(self.spx_index_ticker,
                                                 PriceField.Close,
                                                 self.start_date,
                                                 self.end_date)

        self.assertEqual(self.start_date, prices_tms.index[0].to_pydatetime())
        self.assertEqual(self.end_date, prices_tms.index[-1].to_pydatetime())
Exemple #14
0
    def test_get_last_price_single_ticker(self):
        # just test if getting single ticker value works, when a single ticker (not wrapped in a list) is passed
        self.timer.set_current_time(
            str_to_date("2018-01-31") + MarketOpenEvent.trigger_time() +
            RelativeDelta(hours=1))
        single_price = self.data_handler.get_last_available_price(
            self.spx_index_ticker)
        self.assertTrue(isinstance(single_price, float))

        # at market open
        self.timer.set_current_time(
            str_to_date("2018-01-31") + MarketOpenEvent.trigger_time())
        at_market_open = self.data_handler.get_last_available_price(
            [self.spx_index_ticker])

        self.assertEqual(self.spx_index_ticker, at_market_open.index[0])
        self.assertEqual(single_price, at_market_open[0])

        # during the trading session
        self.timer.set_current_time(
            str_to_date("2018-01-31") + MarketOpenEvent.trigger_time() +
            RelativeDelta(hours=1))
        during_the_day_last_prices = self.data_handler.get_last_available_price(
            [self.spx_index_ticker])

        self.assertEqual(self.spx_index_ticker,
                         during_the_day_last_prices.index[0])
        self.assertEqual(single_price, during_the_day_last_prices[0])

        # after the trading session
        self.timer.set_current_time(
            str_to_date("2018-01-31") + MarketCloseEvent.trigger_time() +
            RelativeDelta(hours=1))
        after_close_last_prices = self.data_handler.get_last_available_price(
            [self.spx_index_ticker])

        self.assertEqual(self.spx_index_ticker,
                         after_close_last_prices.index[0])
        self.assertNotEqual(during_the_day_last_prices[0],
                            after_close_last_prices[0])

        # before the trading session
        self.timer.set_current_time(
            str_to_date("2018-01-31") + MarketOpenEvent.trigger_time() -
            RelativeDelta(hours=1))
        before_trading_session_prices = self.data_handler.get_last_available_price(
            [self.spx_index_ticker])

        self.assertEqual(self.spx_index_ticker,
                         before_trading_session_prices.index[0])
        self.assertNotEqual(during_the_day_last_prices[0],
                            before_trading_session_prices[0])
        self.assertNotEqual(after_close_last_prices[0],
                            before_trading_session_prices[0])
    def setUpClass(cls):
        cls.frequency = Frequency.DAILY
        cls.tickers = [
            BloombergFutureTicker("Cotton", "CTF0 Comdty", 1, 3),
            BloombergFutureTicker("Corn", 'C {} Comdty', 1, 5, 50, "HMUZ")
        ]

        timer.set_current_time(str_to_date('2017-12-20'))

        for ticker in cls.tickers:
            ticker.initialize_data_provider(timer, bbg_provider)

        cls.start_date = str_to_date('2015-10-08')
        cls.end_date = str_to_date('2017-12-20')

        MarketCloseEvent.set_trigger_time({
            "hour": 20,
            "minute": 00,
            "second": 0,
            "microsecond": 0
        })
Exemple #16
0
    def test_get_history_when_end_date_is_tomorrow(self):
        self.timer.set_current_time(
            str_to_date("2018-01-30") + MarketCloseEvent.trigger_time() +
            RelativeDelta(hours=1))
        prices_tms = self.data_handler.get_history(self.spx_index_ticker,
                                                   self.get_history_field,
                                                   self.start_date,
                                                   self.end_date_trimmed)

        self.assertEqual(self.start_date, prices_tms.index[0].to_pydatetime())
        self.assertEqual(self.end_date_trimmed,
                         prices_tms.index[-1].to_pydatetime())
Exemple #17
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_ticker = BloombergTicker(self.MSFT_TICKER_STR)

        self.timer = SettableTimer(initial_time=before_close)

        self.data_handler = Mock(spec=DataHandler)
        self.data_handler.data_provider = Mock(spec=DataProvider)

        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)
        self.exec_handler = SimulatedExecutionHandler(self.data_handler, self.timer, scheduler, self.monitor,
                                                      commission_model, 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_ticker, quantity=-1, execution_style=StopOrder(95.0),
                                       time_in_force=TimeInForce.GTC)
        self.stop_loss_order_2 = Order(self.msft_ticker, quantity=-1, execution_style=StopOrder(90.0),
                                       time_in_force=TimeInForce.GTC)

        self.stop_loss_order_3 = Order(self.msft_ticker, 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])
Exemple #18
0
    def setUp(self):
        try:
            self.price_data_provider = get_data_provider()
        except Exception as e:
            raise self.skipTest(e)

        self.timer = SettableTimer()
        self.data_handler = DailyDataHandler(self.price_data_provider,
                                             self.timer)

        MarketOpenEvent.set_trigger_time({
            "hour": 13,
            "minute": 30,
            "second": 0,
            "microsecond": 0
        })
        MarketCloseEvent.set_trigger_time({
            "hour": 20,
            "minute": 0,
            "second": 0,
            "microsecond": 0
        })
    def setUp(self):
        self.timer = SettableTimer()
        self.tickers = [
            QuandlTicker("MSFT", "WIKI"),
            QuandlTicker("AAPL", "WIKI")
        ]
        price_data_provider_mock = self._create_price_provider_mock(
            self.tickers)
        self.data_handler = DailyDataHandler(price_data_provider_mock,
                                             self.timer)

        MarketOpenEvent.set_trigger_time({
            "hour": 13,
            "minute": 30,
            "second": 0,
            "microsecond": 0
        })
        MarketCloseEvent.set_trigger_time({
            "hour": 20,
            "minute": 0,
            "second": 0,
            "microsecond": 0
        })
Exemple #20
0
    def _get_current_bars(self, tickers: Sequence[Ticker]) -> QFDataFrame:
        """
        Gets the current bars for given Tickers. If the bars are not available yet, NaNs are returned.
        The result is a QFDataFrame with Tickers as an index and PriceFields as columns.

        In case of daily trading, the current bar is returned only at the Market Close Event time, as the get_price
        function will not return data for the current date until the market closes.

        In case of intraday trading (for N minutes frequency) the current bar can be returned in the time between
        (inclusive) N minutes after MarketOpenEvent and the MarketCloseEvent. Important: If current time ("now")
        contains non-zero seconds or microseconds, NaNs will be returned.

        """
        if not tickers:
            return QFDataFrame()

        assert self._frequency >= Frequency.DAILY, "Lower than daily frequency is not supported by the simulated " \
                                                   "executor"
        current_datetime = self._timer.now()

        market_close_time = current_datetime + MarketCloseEvent.trigger_time(
        ) == current_datetime

        if self._frequency == Frequency.DAILY:
            # In case of daily trading, the current bar can be returned only at the Market Close
            if not market_close_time:
                return QFDataFrame(index=tickers, columns=PriceField.ohlcv())
            else:
                current_datetime = date_to_datetime(current_datetime.date())
                start_date = current_datetime - self._frequency.time_delta()
                current_bar_start = current_datetime
        else:
            # In case of intraday trading the current full bar is always indexed by the left side of the time range
            start_date = current_datetime - self._frequency.time_delta()
            current_bar_start = start_date

        prices_data_array = self._data_handler.get_price(
            tickers=tickers,
            fields=PriceField.ohlcv(),
            start_date=start_date,
            end_date=current_datetime,
            frequency=self._frequency)
        try:
            current_bars = cast_data_array_to_proper_type(
                prices_data_array.loc[current_bar_start])
        except KeyError:
            current_bars = QFDataFrame(index=tickers,
                                       columns=PriceField.ohlcv())
        return current_bars
Exemple #21
0
    def _get_end_date_without_look_ahead(self, end_date: datetime = None):
        # Consider the time of latest market close event
        # If end_date is None, it is assumed that it is equal to latest_available_market_close
        current_datetime = self.timer.now()

        today_market_event = current_datetime + MarketCloseEvent.trigger_time()
        yesterday_market_event = today_market_event - RelativeDelta(days=1)
        latest_available_market_close = yesterday_market_event if current_datetime < today_market_event \
            else today_market_event

        end_date = end_date + RelativeDelta(second=0, microsecond=0) if end_date is not None else \
            latest_available_market_close

        end_date_without_lookahead = min(latest_available_market_close,
                                         end_date)
        return end_date_without_lookahead
Exemple #22
0
    def _filter_transactions(self, ticker: Ticker, transactions: List[Transaction], start_date: datetime,
                             end_date: datetime) -> QFSeries:
        """ Filters out transactions, which do not correspond to the given ticker and returns a QFSeries of remaining
        transactions. Only transactions between start_date market open and end_date market close are considered. """
        transactions = [t for t in transactions if start_date + MarketOpenEvent.trigger_time()
                        <= t.time <= end_date + MarketCloseEvent.trigger_time()]

        if isinstance(ticker, FutureTicker):
            transactions_for_tickers = [t for t in transactions if ticker.belongs_to_family(t.ticker)]
        else:
            transactions_for_tickers = [t for t in transactions if ticker == t.ticker]

        transactions_records = [(t, t.time) for t in transactions_for_tickers]
        transactions_series = QFDataFrame.from_records(transactions_records, columns=["Transaction", "Index"]) \
            .set_index("Index").iloc[:, 0]
        return transactions_series
    def setUp(self):
        self.scheduling_time_delay = 1
        start_date = str_to_date("2018-02-04")

        before_close = start_date + MarketCloseEvent.trigger_time(
        ) - RelativeDelta(minutes=self.scheduling_time_delay)
        self.timer = SettableTimer(initial_time=before_close)

        contracts_to_tickers_mapper = SimulatedBloombergContractTickerMapper()
        msft_contract = Contract("MSFT US Equity",
                                 security_type='STK',
                                 exchange='TEST')
        self.msft_ticker = contracts_to_tickers_mapper.contract_to_ticker(
            msft_contract)

        self.data_handler = Mock(spec=DataHandler)
        self.scheduler = Mock(spec=Scheduler)

        self.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, self.scheduler, self.monitor,
            self.commission_model, contracts_to_tickers_mapper, self.portfolio,
            slippage_model, RelativeDelta(minutes=self.scheduling_time_delay))

        self.order_1 = Order(msft_contract,
                             quantity=10,
                             execution_style=MarketOrder(),
                             time_in_force=TimeInForce.OPG)
        self.order_2 = Order(msft_contract,
                             quantity=-5,
                             execution_style=MarketOrder(),
                             time_in_force=TimeInForce.OPG)
        self.order_3 = Order(msft_contract,
                             quantity=-7,
                             execution_style=MarketOrder(),
                             time_in_force=TimeInForce.OPG)

        self.order_4 = Order(msft_contract,
                             quantity=4,
                             execution_style=MarketOnCloseOrder(),
                             time_in_force=TimeInForce.DAY)
Exemple #24
0
    def setUp(self):
        self.scheduling_time_delay = 1
        start_date = str_to_date("2018-02-04")

        before_close = start_date + MarketCloseEvent.trigger_time(
        ) - RelativeDelta(minutes=self.scheduling_time_delay)
        self.timer = SettableTimer(initial_time=before_close)

        self.msft_ticker = BloombergTicker("MSFT US Equity")

        self.data_handler = Mock(spec=DataHandler)
        self.data_handler.frequency = Frequency.DAILY
        self.data_handler.data_provider = Mock(spec=DataProvider)

        self.scheduler = Mock(spec=Scheduler)

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

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

        self.order_1 = Order(self.msft_ticker,
                             quantity=10,
                             execution_style=MarketOrder(),
                             time_in_force=TimeInForce.OPG)
        self.order_2 = Order(self.msft_ticker,
                             quantity=-5,
                             execution_style=MarketOrder(),
                             time_in_force=TimeInForce.OPG)
        self.order_3 = Order(self.msft_ticker,
                             quantity=-7,
                             execution_style=MarketOrder(),
                             time_in_force=TimeInForce.OPG)

        self.order_4 = Order(self.msft_ticker,
                             quantity=4,
                             execution_style=MarketOnCloseOrder(),
                             time_in_force=TimeInForce.DAY)
    def get_last_available_price(
            self,
            tickers: Union[Ticker, Sequence[Ticker]],
            frequency: Frequency = None) -> Union[float, QFSeries]:
        """
        Gets the latest available price for given assets, even if the full bar is not yet available.

        The frequency parameter is always casted into 1 minute frequency, to represent the most recent price.

        It returns the CLOSE price of the last available bar. If "now" is after the market OPEN, and before the market
        CLOSE, the last available price is equal to the current price (CLOSE price of the bar, which right bound is
        equal to "now"). If the market did not open yet, the last available CLOSE price will be returned.
        Non-zero seconds or microseconds values are omitted (e.g. 13:40:01 is always treated as 13:40:00).

        Parameters
        -----------
        tickers: Ticker, Sequence[Ticker]
            tickers of the securities which prices should be downloaded
        frequency: Frequency
            frequency of the data

        Returns
        -------
        float, QFSeries
            last_prices series where:
            - last_prices.name contains a date of current prices,
            - last_prices.index contains tickers
            - last_prices.data contains latest available prices for given tickers
        """
        frequency = frequency or self.fixed_data_provider_frequency or Frequency.MIN_1

        if frequency <= Frequency.DAILY:
            raise ValueError(
                "The Intraday Data Handler can be used only with the Intraday Frequency"
            )

        tickers, was_single_ticker_provided = convert_to_list(tickers, Ticker)

        # if an empty tickers list was supplied then return an empty result
        if not tickers:
            return QFSeries()

        current_datetime = self.timer.now()

        # If the current_datetime represents the time after Market Close and before Market Open, shift it to the
        # Market Close of the day before
        if current_datetime + MarketOpenEvent.trigger_time(
        ) > current_datetime:
            current_datetime = current_datetime - RelativeDelta(days=1)
            current_datetime = current_datetime + MarketCloseEvent.trigger_time(
            )
        elif current_datetime + MarketCloseEvent.trigger_time(
        ) < current_datetime:
            current_datetime = current_datetime + MarketCloseEvent.trigger_time(
            )

        # If the current_datetime represents Saturday or Sunday, shift it to last Friday
        if current_datetime.weekday() in (5, 6):
            current_datetime = current_datetime - RelativeDelta(weekday=4,
                                                                weeks=1)

        # The time range denotes the current_datetime +- time delta related to the given frequency. The current price is
        # represented as the close price of (time_range_start, current_datetime) range, labeled using the time_range_
        # start value in most of the cases.
        #
        # The only exception is the price at the market open - in this case we do not have the bar directly
        # leading up to market open time. Thus, the open price from the time range (current_datetime, time_range_end)
        # is used to denote the price.

        time_range_start = current_datetime - frequency.time_delta()
        time_range_end = current_datetime + frequency.time_delta()

        # The start date is used to download older data, in case if there is no price available currently and we are
        # interested in the last available one. Therefore, at first we look one hour in the past. If this amount of data
        # would not be sufficient, we would look up to a few days in the past.

        download_start_date = current_datetime - Frequency.MIN_60.time_delta()

        def download_prices(start_time, end_time, multiple_days=False):
            # Function which downloads prices for the given tickers. In case if the time range spans over multiple days
            # and thus contains at least one Market Open Event, combine the Open price for the first bar after the
            # market open with the Close prices for all other bars from this day.
            if multiple_days:
                price_fields = [PriceField.Open, PriceField.Close]
                prices = self.data_provider.get_price(tickers, price_fields,
                                                      start_time, end_time,
                                                      frequency)
                return self._data_array_to_dataframe(prices, frequency)
            else:
                return self.data_provider.get_price(tickers, PriceField.Close,
                                                    start_time, end_time,
                                                    frequency)

        # If the data contains the Market Open Price, merge the prices
        if download_start_date <= MarketOpenEvent.trigger_time(
        ) + time_range_end <= time_range_end:
            contains_market_open = True
        elif download_start_date <= MarketOpenEvent.trigger_time(
        ) + download_start_date <= time_range_end:
            contains_market_open = True
        elif (time_range_end - download_start_date) > timedelta(days=1):
            contains_market_open = True
        else:
            contains_market_open = False

        prices_data_array = download_prices(download_start_date,
                                            time_range_end,
                                            contains_market_open)

        # Access the price bar starting at time_range_start and ending at current_datetime
        try:
            prices_series = prices_data_array.asof(time_range_start)
            prices_series.name = "Last available asset prices"

            if prices_series.isnull().values.any():
                # If any of the values is null, download more data, using a longer period of time
                raise IndexError

        except IndexError:
            # Download data using a longer period of time. In case of Monday or Tuesday, we download data from last 4
            # days in order to handle situations, were there was no price on Monday or Friday (and during the weekend).
            # In all other cases, we download data from the last 2 days.
            number_of_days_to_go_back = 2 if download_start_date.weekday(
            ) not in (0, 1) else 4
            prices_data_array = download_prices(
                download_start_date -
                RelativeDelta(days=number_of_days_to_go_back),
                time_range_end,
                multiple_days=True)

            prices_series = prices_data_array.asof(time_range_start)
            prices_series.name = "Last available asset prices"

        prices_series = cast_series(prices_series, QFSeries)
        if was_single_ticker_provided:
            return prices_series[0]
        else:
            return prices_series
Exemple #26
0
    def get_price(self, tickers: Union[Ticker, Sequence[Ticker]], fields: Union[PriceField, Sequence[PriceField]],
                  start_date: datetime, end_date: datetime = None, frequency: Frequency = None) -> \
            Union[PricesSeries, PricesDataFrame, QFDataArray]:
        """
        Runs DataProvider.get_price(...) but before makes sure that the query doesn't concern data from
        the future.

        In contrast to the DataHandler.get_history(...), it will return a valid Open price in the time between the
        Market Open and Market Close.

        Parameters
        ----------
        tickers: Ticker, Sequence[Ticker]
            tickers for securities which should be retrieved
        fields: PriceField, Sequence[PriceField]
            fields of securities which should be retrieved
        start_date: datetime
            date representing the beginning of historical period from which data should be retrieved
        end_date: datetime
            date representing the end of historical period from which data should be retrieved;
            if no end_date was provided, by default the current date will be used
        frequency: Frequency
            frequency of the data

        Returns
        -------
        None, PricesSeries, PricesDataFrame, QFDataArray
        """
        frequency = frequency or self.default_frequency
        assert frequency is not None, "Frequency cannot be equal to None"

        current_datetime = self.timer.now()
        end_date = current_datetime if end_date is None else end_date

        # end_date_without_look_ahead points to the latest market close in order to not return prices from the future
        # However, when the end_date falls between the market open and market close, the open price could also be
        # returned by the get_price function, therefore it is necessary to adjust the end_date_without_look_ahead
        end_date_without_look_ahead = self._get_end_date_without_look_ahead(
            end_date)

        open_prices_included = PriceField.Open == fields if isinstance(fields, PriceField) else \
            PriceField.Open in fields
        today_market_open = current_datetime + MarketOpenEvent.trigger_time()
        today_market_close = current_datetime + MarketCloseEvent.trigger_time()
        consider_additional_open_price = (
            frequency == Frequency.DAILY and open_prices_included
            and today_market_open <= end_date < today_market_close)

        if consider_additional_open_price:
            end_date_without_look_ahead = datetime(today_market_open.year,
                                                   today_market_open.month,
                                                   today_market_open.day)

        prices_data = self.data_provider.get_price(
            tickers, fields, start_date, end_date_without_look_ahead,
            frequency)

        # In case if the additional open price should be added, clean up the prices container to remove all data from
        # the future
        single_price_field = fields is not None and isinstance(
            fields, PriceField)
        if consider_additional_open_price and not single_price_field:
            single_ticker = tickers is not None and isinstance(tickers, Ticker)
            single_date = start_date.date() == end_date.date()
            prices_data = self._remove_data_from_the_future(
                prices_data, single_date, single_ticker,
                end_date_without_look_ahead)

        return prices_data
Exemple #27
0
 def setUp(self):
     self.timer = SettableTimer()
     MarketOpenEvent.set_trigger_time({"hour": 13, "minute": 30, "second": 0, "microsecond": 0})
     MarketCloseEvent.set_trigger_time({"hour": 20, "minute": 0, "second": 0, "microsecond": 0})
class TestMarketOnOpenExecutionStyle(TestCase):
    MarketOpenEvent.set_trigger_time({
        "hour": 13,
        "minute": 30,
        "second": 0,
        "microsecond": 0
    })
    MarketCloseEvent.set_trigger_time({
        "hour": 20,
        "minute": 0,
        "second": 0,
        "microsecond": 0
    })

    def setUp(self):
        self.scheduling_time_delay = 1
        start_date = str_to_date("2018-02-04")

        before_close = start_date + MarketCloseEvent.trigger_time(
        ) - RelativeDelta(minutes=self.scheduling_time_delay)
        self.timer = SettableTimer(initial_time=before_close)

        contracts_to_tickers_mapper = SimulatedBloombergContractTickerMapper()
        msft_contract = Contract("MSFT US Equity",
                                 security_type='STK',
                                 exchange='TEST')
        self.msft_ticker = contracts_to_tickers_mapper.contract_to_ticker(
            msft_contract)

        self.data_handler = Mock(spec=DataHandler)
        self.scheduler = Mock(spec=Scheduler)

        self.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, self.scheduler, self.monitor,
            self.commission_model, contracts_to_tickers_mapper, self.portfolio,
            slippage_model, RelativeDelta(minutes=self.scheduling_time_delay))

        self.order_1 = Order(msft_contract,
                             quantity=10,
                             execution_style=MarketOrder(),
                             time_in_force=TimeInForce.OPG)
        self.order_2 = Order(msft_contract,
                             quantity=-5,
                             execution_style=MarketOrder(),
                             time_in_force=TimeInForce.OPG)
        self.order_3 = Order(msft_contract,
                             quantity=-7,
                             execution_style=MarketOrder(),
                             time_in_force=TimeInForce.OPG)

        self.order_4 = Order(msft_contract,
                             quantity=4,
                             execution_style=MarketOnCloseOrder(),
                             time_in_force=TimeInForce.DAY)

    def _trigger_single_time_event(self):
        self.timer.set_current_time(self.timer.now() + RelativeDelta(
            minutes=self.scheduling_time_delay))
        event = ScheduleOrderExecutionEvent()
        self.exec_handler.on_orders_accept(event)

    def test_1_order_fill(self):
        self.exec_handler.assign_order_ids([self.order_1])
        self._set_current_price(101)
        self._trigger_single_time_event()
        self.exec_handler.on_market_open(...)

        self.monitor.record_transaction.assert_called_once()
        self.portfolio.transact_transaction.assert_called_once()

        actual_orders = self.exec_handler.get_open_orders()
        expected_orders = []
        assert_lists_equal(expected_orders, actual_orders)

    def test_3_orders_fill(self):
        self.exec_handler.assign_order_ids(
            [self.order_1, self.order_2, self.order_3])
        self._set_current_price(101)
        self._trigger_single_time_event()
        self.exec_handler.on_market_open(...)

        self.assertEqual(self.monitor.record_transaction.call_count, 3)
        self.assertEqual(self.portfolio.transact_transaction.call_count, 3)

        actual_orders = self.exec_handler.get_open_orders()
        expected_orders = []
        assert_lists_equal(expected_orders, actual_orders)

    def test_3_orders_fill_only_at_open(self):
        self.exec_handler.assign_order_ids(
            [self.order_1, self.order_2, self.order_3])
        self._set_current_price(101)
        self._trigger_single_time_event()
        self.exec_handler.on_market_close(...)

        self.portfolio.transact_transaction.assert_not_called()
        self.monitor.record_transaction.assert_not_called()

        actual_orders = self.exec_handler.get_open_orders()
        expected_orders = [self.order_1, self.order_2, self.order_3]
        self.assertCountEqual(expected_orders, actual_orders)

    def test_fill_open_and_close(self):
        self.exec_handler.assign_order_ids([self.order_1, self.order_2])
        self.exec_handler.assign_order_ids([self.order_2, self.order_3])
        self.exec_handler.assign_order_ids([self.order_3, self.order_4])
        self.exec_handler.assign_order_ids([self.order_4, self.order_4])

        self._set_current_price(101)
        self._trigger_single_time_event()
        self.exec_handler.on_market_open(...)

        self.assertEqual(self.monitor.record_transaction.call_count, 3)
        self.assertEqual(self.portfolio.transact_transaction.call_count, 3)

        actual_orders = self.exec_handler.get_open_orders()
        expected_orders = [self.order_4]
        assert_lists_equal(expected_orders, actual_orders)

        self.exec_handler.on_market_close(...)

        self.assertEqual(self.monitor.record_transaction.call_count, 4)
        self.assertEqual(self.portfolio.transact_transaction.call_count, 4)

        actual_orders = self.exec_handler.get_open_orders()
        expected_orders = []
        assert_lists_equal(expected_orders, actual_orders)

    def test_fill_close_and_open(self):
        self.exec_handler.assign_order_ids([self.order_1, self.order_2])
        self.exec_handler.assign_order_ids([self.order_2, self.order_3])
        self.exec_handler.assign_order_ids([self.order_3, self.order_4])
        self.exec_handler.assign_order_ids([self.order_4, self.order_4])

        self._set_current_price(101)

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

        # Transaction related to order 4 will be executed only once, as only one Order object was passed
        self.monitor.record_transaction.assert_called_once()
        self.portfolio.transact_transaction.assert_called_once()

        actual_orders = self.exec_handler.get_open_orders()
        expected_orders = [self.order_1, self.order_2, self.order_3]
        self.assertCountEqual(expected_orders, actual_orders)

        self.exec_handler.on_market_open(...)

        self.assertEqual(self.monitor.record_transaction.call_count, 4)
        self.assertEqual(self.portfolio.transact_transaction.call_count, 4)

        actual_orders = self.exec_handler.get_open_orders()
        expected_orders = []
        self.assertCountEqual(expected_orders, actual_orders)

    def test_market_open_transaction(self):
        order = self.order_1
        price = 102
        self.exec_handler.assign_order_ids([order])
        self._set_current_price(price)
        self._trigger_single_time_event()
        self.exec_handler.on_market_open(...)

        timestamp = self.timer.now()
        contract = order.contract
        quantity = order.quantity
        commission = self.commission_model.calculate_commission(order, price)
        expected_transaction = Transaction(timestamp, contract, quantity,
                                           price, commission)

        self.monitor.record_transaction.assert_called_once_with(
            expected_transaction)

    def test_market_close_transaction(self):
        order = self.order_4
        price = 102
        self.exec_handler.assign_order_ids([self.order_1, order])
        self._set_current_price(price)
        self._trigger_single_time_event()
        self.exec_handler.on_market_close(...)

        timestamp = self.timer.now()
        contract = order.contract
        quantity = order.quantity
        commission = self.commission_model.calculate_commission(order, price)
        expected_transaction = Transaction(timestamp, contract, quantity,
                                           price, commission)

        self.monitor.record_transaction.assert_called_once_with(
            expected_transaction)

    def test_market_close_does_not_trade(self):
        price = None
        self.exec_handler.assign_order_ids([self.order_1, self.order_4])
        self._set_current_price(price)
        self._trigger_single_time_event()
        self.exec_handler.on_market_close(...)

        self.portfolio.transact_transaction.assert_not_called()
        self.monitor.record_transaction.assert_not_called()

    def test_market_open_does_not_trade(self):
        price = None
        self.exec_handler.assign_order_ids([self.order_1, self.order_4])
        self._set_current_price(price)
        self._trigger_single_time_event()
        self.exec_handler.on_market_open(...)

        self.portfolio.transact_transaction.assert_not_called()
        self.monitor.record_transaction.assert_not_called()

    def _set_last_available_price(self, price):
        self.data_handler.get_last_available_price.side_effect = lambda t: QFSeries(
            data=[price], index=pd.Index([self.msft_ticker]))

    def _set_current_price(self, price):
        self.data_handler.get_current_price.side_effect = lambda t: QFSeries(
            data=[price], index=pd.Index([self.msft_ticker]))
Exemple #29
0
class TestFastAlphaModelsTester(TestCase):
    apple_ticker = QuandlTicker("AAPL", "WIKI")
    ibm_ticker = QuandlTicker("IBM", "WIKI")
    tickers = [apple_ticker, ibm_ticker]

    test_start_date = str_to_date("2015-01-01")
    test_end_date = str_to_date("2015-01-31")

    data_start_date = str_to_date("2014-12-25")
    data_end_date = test_end_date

    frequency = Frequency.DAILY

    MarketOpenEvent.set_trigger_time({
        "hour": 13,
        "minute": 30,
        "second": 0,
        "microsecond": 0
    })
    MarketCloseEvent.set_trigger_time({
        "hour": 20,
        "minute": 0,
        "second": 0,
        "microsecond": 0
    })

    def setUp(self):
        all_fields = PriceField.ohlcv()

        self._mocked_prices_arr = self._make_mock_data_array(
            self.tickers, all_fields)
        self._price_provider_mock = PresetDataProvider(self._mocked_prices_arr,
                                                       self.data_start_date,
                                                       self.data_end_date,
                                                       self.frequency)
        self.timer = SettableTimer()
        self.contract_ticker_mapper = DummyQuandlContractTickerMapper()

        self.alpha_model_type = DummyAlphaModel

    @classmethod
    def _make_mock_data_array(cls, tickers, fields):
        all_dates_index = pd.bdate_range(start=cls.data_start_date,
                                         end=cls.test_end_date)

        num_of_dates = len(all_dates_index)
        num_of_tickers = len(tickers)
        num_of_fields = len(fields)

        start_value = 100.0
        values = np.arange(
            start_value,
            num_of_dates * num_of_tickers * num_of_fields + start_value)
        reshaped_values = np.reshape(
            values, (num_of_dates, num_of_tickers, num_of_fields))

        mocked_result = QFDataArray.create(all_dates_index,
                                           tickers,
                                           fields,
                                           data=reshaped_values)
        mocked_result.loc[:, :, PriceField.Low] -= 50.0
        mocked_result.loc[:, :, PriceField.High] += 50.0

        return mocked_result

    def test_alpha_models_tester(self):
        first_param_set = (10, Exposure.LONG)
        second_param_set = (5, Exposure.SHORT)
        data_handler = FastDataHandler(self._price_provider_mock, self.timer)

        params = [
            FastAlphaModelTesterConfig(
                self.alpha_model_type, {
                    "period_length": 10,
                    "first_suggested_exposure": Exposure.LONG,
                    "risk_estimation_factor": None
                }, ("period_length", "first_suggested_exposure")),
            FastAlphaModelTesterConfig(
                self.alpha_model_type, {
                    "period_length": 5,
                    "first_suggested_exposure": Exposure.SHORT,
                    "risk_estimation_factor": None
                }, ("period_length", "first_suggested_exposure"))
        ]

        tester = FastAlphaModelTester(params, self.tickers,
                                      self.contract_ticker_mapper,
                                      self.test_start_date, self.test_end_date,
                                      data_handler, self.timer)

        backtest_summary = tester.test_alpha_models()
        self.assertEqual(self.tickers, backtest_summary.tickers)
        self.assertEqual(DummyAlphaModel, backtest_summary.alpha_model_type)

        backtest_summary_elements = backtest_summary.elements_list
        self.assertEqual(2 * (len(self.tickers) + 1),
                         len(backtest_summary_elements))

        # check first backtest summary element - trades
        first_elem = backtest_summary_elements[2]
        self.assertEqual(first_param_set, first_elem.model_parameters)

        expected_trades_data = [[
            self.apple_ticker,
            str_to_date("2015-01-02"),
            str_to_date("2015-01-16"), (260.0 / 160.0 - 1), 1.0
        ],
                                [
                                    self.ibm_ticker,
                                    str_to_date("2015-01-02"),
                                    str_to_date("2015-01-16"),
                                    (265.0 / 165.0 - 1), 1.0
                                ]]

        generated_trades_data = [[
            self.contract_ticker_mapper.contract_to_ticker(t.contract),
            t.start_time, t.end_time, t.pnl, t.direction
        ] for t in first_elem.trades]

        self.assertCountEqual(generated_trades_data, expected_trades_data)

        # check first backtest summary element - returns
        all_dates_index = pd.bdate_range(start=self.test_start_date + BDay(2),
                                         end=self.test_end_date)
        expected_returns = SimpleReturnsSeries(
            index=all_dates_index,
            data=[
                0.0615530, 0.0579832, 0.0548048, 0.0519568, 0.0493902,
                0.0470653, 0.0449495, 0.0430157, 0.0412415, 0.0396078,
                0.0000000, 0.0000000, 0.0000000, 0.0000000, 0.0000000,
                0.0000000, 0.0000000, 0.0000000, 0.0000000, 0.0000000
            ])
        assert_series_equal(expected_returns, first_elem.returns_tms)

        # check second backtest summary element
        second_elem = backtest_summary_elements[5]
        self.assertEqual(second_param_set, second_elem.model_parameters)

        expected_trades_data = [[
            self.apple_ticker,
            str_to_date("2015-01-02"),
            str_to_date("2015-01-09"), (1 - 210.0 / 160.0), -1.0
        ],
                                [
                                    self.apple_ticker,
                                    str_to_date("2015-01-16"),
                                    str_to_date("2015-01-23"),
                                    (310.0 / 260.0 - 1), 1.0
                                ],
                                [
                                    self.apple_ticker,
                                    str_to_date("2015-01-23"),
                                    str_to_date("2015-01-30"),
                                    (1 - 360.0 / 310.0), -1.0
                                ],
                                [
                                    self.ibm_ticker,
                                    str_to_date("2015-01-02"),
                                    str_to_date("2015-01-09"),
                                    (1 - 215.0 / 165.0), -1.0
                                ],
                                [
                                    self.ibm_ticker,
                                    str_to_date("2015-01-16"),
                                    str_to_date("2015-01-23"),
                                    (315.0 / 265.0 - 1), 1.0
                                ],
                                [
                                    self.ibm_ticker,
                                    str_to_date("2015-01-23"),
                                    str_to_date("2015-01-30"),
                                    (1 - 365.0 / 315.0), -1.0
                                ]]
        generated_trades_data = [[
            self.contract_ticker_mapper.contract_to_ticker(t.contract),
            t.start_time, t.end_time, t.pnl, t.direction
        ] for t in second_elem.trades]
        self.assertCountEqual(expected_trades_data, generated_trades_data)

        # check second backtest summary element - returns
        all_dates_index = pd.bdate_range(start=self.test_start_date + BDay(2),
                                         end=self.test_end_date)
        expected_returns = SimpleReturnsSeries(
            index=all_dates_index,
            data=[
                -0.0615530, -0.0579832, -0.0548048, -0.0519568, -0.0493902,
                0.0000000, 0.0000000, 0.0000000, 0.0000000, 0.0000000,
                0.0380987, 0.0367003, 0.0354010, 0.0341905, 0.0330601,
                -0.0320020, -0.0310096, -0.0300769, -0.0291986, -0.0283702
            ])
        assert_series_equal(expected_returns, second_elem.returns_tms)
class TradingSessionForTests(TradingSession):
    """
    Encapsulates the settings and components for carrying out a backtest session. Pulls for data every day.
    """

    # initialise market time
    BeforeMarketOpenEvent.set_trigger_time({"hour": 7, "minute": 30, "second": 0, "microsecond": 0})
    MarketOpenEvent.set_trigger_time({"hour": 13, "minute": 30, "second": 0, "microsecond": 0})
    MarketCloseEvent.set_trigger_time({"hour": 20, "minute": 0, "second": 0, "microsecond": 0})
    AfterMarketCloseEvent.set_trigger_time({"hour": 21, "minute": 0, "second": 0, "microsecond": 0})

    def __init__(self, data_provider: DataProvider, start_date, end_date, initial_cash,
                 frequency: Frequency = Frequency.MIN_1):
        """
        Set up the backtest variables according to what has been passed in.
        """
        super().__init__()
        self.logger = qf_logger.getChild(self.__class__.__name__)

        self.logger.info(
            "\n".join([
                "Testing the Backtester:",
                "Start date: {:s}".format(date_to_str(start_date)),
                "End date: {:s}".format(date_to_str(end_date)),
                "Initial cash: {:.2f}".format(initial_cash),
                "Frequency of the simulated execution handler: {}".format(frequency)
            ])
        )

        timer = SettableTimer(start_date)
        notifiers = Notifiers(timer)
        if frequency <= Frequency.DAILY:
            data_handler = DailyDataHandler(data_provider, timer)
        else:
            data_handler = IntradayDataHandler(data_provider, timer)

        contract_ticker_mapper = SimulatedBloombergContractTickerMapper()
        portfolio = Portfolio(data_handler, initial_cash, timer, contract_ticker_mapper)
        signals_register = BacktestSignalsRegister()
        backtest_result = BacktestResult(portfolio=portfolio, backtest_name="Testing the Backtester",
                                         start_date=start_date, end_date=end_date, signals_register=signals_register)

        monitor = Mock(spec=BacktestMonitor)
        commission_model = FixedCommissionModel(0.0)
        slippage_model = PriceBasedSlippage(0.0, data_provider, contract_ticker_mapper)

        execution_handler = SimulatedExecutionHandler(
            data_handler, timer, notifiers.scheduler, monitor, commission_model,
            contract_ticker_mapper, portfolio, slippage_model)

        broker = BacktestBroker(portfolio, execution_handler)
        order_factory = OrderFactory(broker, data_handler, contract_ticker_mapper)

        event_manager = self._create_event_manager(timer, notifiers)
        time_flow_controller = BacktestTimeFlowController(
            notifiers.scheduler, event_manager, timer, notifiers.empty_queue_event_notifier, end_date
        )
        position_sizer = SimplePositionSizer(broker, data_handler, order_factory, contract_ticker_mapper,
                                             signals_register)

        self.logger.info(
            "\n".join([
                "Configuration of components:",
                "Position sizer: {:s}".format(position_sizer.__class__.__name__),
                "Timer: {:s}".format(timer.__class__.__name__),
                "Data Provider: {:s}".format(data_provider.__class__.__name__),
                "Backtest Result: {:s}".format(backtest_result.__class__.__name__),
                "Monitor: {:s}".format(monitor.__class__.__name__),
                "Execution Handler: {:s}".format(execution_handler.__class__.__name__),
                "Commission Model: {:s}".format(commission_model.__class__.__name__),
                "Broker: {:s}".format(broker.__class__.__name__),
                "Contract-Ticker Mapper: {:s}".format(contract_ticker_mapper.__class__.__name__)
            ])
        )

        self.broker = broker
        self.notifiers = notifiers
        self.initial_cash = initial_cash
        self.start_date = start_date
        self.end_date = end_date
        self.event_manager = event_manager
        self.contract_ticker_mapper = contract_ticker_mapper
        self.data_handler = data_handler
        self.portfolio = portfolio
        self.execution_handler = execution_handler
        self.position_sizer = position_sizer
        self.orders_filters = []
        self.monitor = monitor
        self.timer = timer
        self.order_factory = order_factory
        self.time_flow_controller = time_flow_controller