Ejemplo n.º 1
0
    def get_portfolio_and_data_handler(self):
        data_handler = Mock(spec=DataHandler)
        data_handler.get_last_available_price.side_effect = lambda tickers: self.data_handler_prices[tickers] \
            if tickers else None

        timer = SettableTimer()
        timer.set_current_time(self.start_time)

        portfolio = Portfolio(data_handler, self.initial_cash, timer)
        return portfolio, data_handler, timer
Ejemplo n.º 2
0
    def get_portfolio_and_data_handler(self):
        data_handler = Mock(spec=DataHandler)
        data_handler.get_last_available_price.side_effect = lambda tickers: self.data_handler_prices[tickers] \
            if tickers else None

        contract_mapper = Mock(spec=ContractTickerMapper)
        contract_mapper.contract_to_ticker.side_effect = lambda contract: DummyTicker(contract.symbol)

        timer = SettableTimer()
        timer.set_current_time(self.start_time)

        portfolio = Portfolio(data_handler, self.initial_cash, timer, contract_mapper)
        return portfolio, data_handler, timer
Ejemplo n.º 3
0
    def _get_assets_number_series(portfolio: Portfolio):
        """
        Returns series indexed by dates, containing the number of assets in the portfolio (where e.g. all Heating Oil
        contracts correspond to one asset)
        """
        positions_history = portfolio.positions_history()

        def contract_to_ticker(c: Contract):
            return portfolio.contract_ticker_mapper. \
                contract_to_ticker(c, strictly_to_specific_ticker=False)

        assets_history = positions_history.rename(columns=contract_to_ticker)
        assets_history = assets_history.groupby(
            level=0,
            axis=1).apply(func=(lambda x: x.notna().any(axis=1).astype(int)))

        return assets_history.sum(axis=1)
Ejemplo n.º 4
0
def main():
    start_date = str_to_date('2018-01-01')
    initial_value = 1000

    portfolio = Portfolio(None, initial_value, None, None)
    backtest_result = BacktestResult(portfolio,
                                     'Monitor Test',
                                     start_date=start_date)
    backtest_result.start_time = start_date

    settings = container.resolve(Settings)  # type: Settings
    pdf_exporter = container.resolve(PDFExporter)  # type: PDFExporter
    xlsx_exporter = container.resolve(ExcelExporter)  # type: ExcelExporter
    monitor = BacktestMonitor(backtest_result, settings, pdf_exporter,
                              xlsx_exporter)

    # put first point
    # noinspection PyProtectedMember
    portfolio.dates.append(start_date)
    # noinspection PyProtectedMember
    portfolio.portfolio_values.append(initial_value)

    # create an Transaction
    timestamp = str_to_date("2010-01-01")
    contract = Contract("MSFT US Equity", security_type="STK", exchange="NYSE")
    quantity = 13
    price = 100.5
    commission = 1.2
    transaction = Transaction(timestamp, contract, quantity, price, commission)

    for i in range(50):
        date = start_date + timedelta(days=i)
        # noinspection PyProtectedMember
        past_value = portfolio.portfolio_values[-1]
        rand = randint(0, 100) - 50

        # noinspection PyProtectedMember
        portfolio.dates.append(date)
        # noinspection PyProtectedMember
        portfolio.portfolio_values.append(past_value + rand)

        monitor.end_of_day_update(date)
        monitor.record_transaction(transaction)
        time.sleep(0.1)

    monitor.end_of_trading_update()
Ejemplo n.º 5
0
    def _get_assets_number_series(self, portfolio: Portfolio):
        """
        Returns series indexed by dates, containing the number of assets in the portfolio (where e.g. all Heating Oil
        contracts correspond to one asset)
        """
        positions_history = portfolio.positions_history()

        def map_to_traded_ticker(ticker):
            for fut_ticker in [
                    t for t in self.tickers
                    if isinstance(t, BloombergFutureTicker)
            ]:
                if fut_ticker.belongs_to_family(ticker):
                    return fut_ticker
            return ticker

        assets_history = positions_history.rename(columns=map_to_traded_ticker)
        assets_history = assets_history.groupby(
            level=0,
            axis=1).apply(func=(lambda x: x.notna().any(axis=1).astype(int)))

        return assets_history.sum(axis=1)
Ejemplo n.º 6
0
 def setUp(self):
     self.portfolio = Portfolio(Mock(), 100000, Mock(), Mock())
     self.trades_generator = TradesGenerator()
Ejemplo n.º 7
0
class TestTrades(unittest.TestCase):
    @classmethod
    def setUpClass(cls):
        cls.contract = Contract('AAPL US Equity',
                                security_type='STK',
                                exchange='SIM_EXCHANGE')
        cls.start_time = str_to_date('2019-01-01')
        cls.time = str_to_date('2020-01-01')

    def setUp(self):
        self.portfolio = Portfolio(Mock(), 100000, Mock(), Mock())
        self.trades_generator = TradesGenerator()

    def test_long_trade(self):
        transactions = [
            Transaction(self.start_time, self.contract, 5, 10.0, 3.0),
            Transaction(self.time, self.contract, 5, 11.0, 4.0),
            Transaction(self.time, self.contract, -1, 13.0, 5.0),
            Transaction(self.time, self.contract, 1, 14.0, 5.0),
            Transaction(self.time, self.contract, -4, 15.0, 2.0),
            Transaction(self.time, self.contract, -6, 16.0, 1.0),
        ]

        for t in transactions:
            self.portfolio.transact_transaction(t)

        # The position should be closed after executing all transactions
        self.assertCountEqual(self.portfolio.open_positions_dict, {})

        all_closed_positions_for_contract = [
            p for p in self.portfolio.closed_positions()
            if p.contract() == self.contract
        ]
        self.assertEqual(len(all_closed_positions_for_contract), 1)
        position = all_closed_positions_for_contract[
            0]  # type: BacktestPosition

        trade_1 = self.trades_generator.create_trades_from_backtest_positions(
            position)
        trade_2 = self.trades_generator.create_trades_from_transactions(
            transactions)[0]
        commission = sum(t.commission for t in transactions)

        self.assertEqual(trade_1, trade_2)

        self.assertEqual(trade_1.commission, commission)
        self.assertEqual(trade_1.pnl, 50.0 - commission)
        self.assertEqual(trade_1.direction, 1.0)
        self.assertEqual(trade_1.start_time, self.start_time)
        self.assertEqual(trade_1.end_time, self.time)

    def test_short_trade(self):
        transactions = [
            Transaction(self.start_time, self.contract, -5, 10.0, 3.0),
            Transaction(self.time, self.contract, 1, 11.0, 4.0),
            Transaction(self.time, self.contract, -9, 10.0, 5.0),
            Transaction(self.time, self.contract, 4, 14.0, 5.0),
            Transaction(self.time, self.contract, 8, 10.0, 2.0),
            Transaction(self.time, self.contract, 1, 9.0, 1.0),
        ]

        for t in transactions:
            self.portfolio.transact_transaction(t)

        # The position should be closed after executing all transactions
        self.assertCountEqual(self.portfolio.open_positions_dict, {})

        all_closed_positions_for_contract = [
            p for p in self.portfolio.closed_positions()
            if p.contract() == self.contract
        ]
        self.assertEqual(len(all_closed_positions_for_contract), 1)
        position = all_closed_positions_for_contract[0]

        trade_1 = self.trades_generator.create_trades_from_backtest_positions(
            position)
        trade_2 = self.trades_generator.create_trades_from_transactions(
            transactions)[0]
        commission = sum(t.commission for t in transactions)

        self.assertEqual(trade_1, trade_2)

        self.assertEqual(trade_1.commission, commission)
        self.assertEqual(trade_1.pnl, -16.0 - commission)
        self.assertEqual(trade_1.direction, -1.0)
        self.assertEqual(trade_1.start_time, self.start_time)
        self.assertEqual(trade_1.end_time, self.time)
    def build(self, start_date: datetime, end_date: datetime) -> BacktestTradingSession:
        self._timer = SettableTimer(start_date)
        self._notifiers = Notifiers(self._timer)
        self._events_manager = self._create_event_manager(self._timer, self._notifiers)

        self._data_handler = DataHandler(self._data_provider, self._timer)

        self._portfolio = Portfolio(self._data_handler, self._initial_cash, self._timer, self._contract_ticker_mapper)
        self._backtest_result = BacktestResult(self._portfolio, self._backtest_name, start_date, end_date)
        self._monitor = self._monitor_setup()

        self._portfolio_handler = PortfolioHandler(self._portfolio, self._monitor, self._notifiers.scheduler)
        self._execution_handler = SimulatedExecutionHandler(
            self._data_handler, self._timer, self._notifiers.scheduler, self._monitor, self._commission_model,
            self._contract_ticker_mapper, self._portfolio, self._slippage_model)

        self._time_flow_controller = BacktestTimeFlowController(
            self._notifiers.scheduler, self._events_manager, self._timer,
            self._notifiers.empty_queue_event_notifier, end_date)

        self._broker = BacktestBroker(self._portfolio, self._execution_handler)
        self._order_factory = OrderFactory(self._broker, self._data_handler, self._contract_ticker_mapper)
        self._position_sizer = self._position_sizer_setup()

        setup_logging(self._logging_level)

        self._logger.info(
            "\n".join([
                "Creating Backtest Trading Session.",
                "\tBacktest Name: {}".format(self._backtest_name),
                "\tData Provider: {}".format(self._data_provider.__class__.__name__),
                "\tContract - Ticker Mapper: {}".format(self._contract_ticker_mapper.__class__.__name__),
                "\tStart Date: {}".format(start_date),
                "\tEnd Date: {}".format(end_date),
                "\tInitial Cash: {:.2f}".format(self._initial_cash)
            ])
        )

        self._logger.info(
            "\n".join([
                "Configuration of components:",
                "\tPosition sizer: {:s}".format(self._position_sizer.__class__.__name__),
                "\tTimer: {:s}".format(self._timer.__class__.__name__),
                "\tData Handler: {:s}".format(self._data_handler.__class__.__name__),
                "\tBacktest Result: {:s}".format(self._backtest_result.__class__.__name__),
                "\tMonitor: {:s}".format(self._monitor.__class__.__name__),
                "\tExecution Handler: {:s}".format(self._execution_handler.__class__.__name__),
                "\tSlippage Model: {:s}".format(self._slippage_model.__class__.__name__),
                "\tCommission Model: {:s}".format(self._commission_model.__class__.__name__),
                "\tBroker: {:s}".format(self._broker.__class__.__name__),
            ])
        )

        ts = BacktestTradingSession(
            contract_ticker_mapper=self._contract_ticker_mapper,
            start_date=start_date,
            end_date=end_date,
            position_sizer=self._position_sizer,
            data_handler=self._data_handler,
            timer=self._timer,
            notifiers=self._notifiers,
            portfolio=self._portfolio,
            events_manager=self._events_manager,
            monitor=self._monitor,
            broker=self._broker,
            order_factory=self._order_factory
        )
        return ts
Ejemplo n.º 9
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
    def build(self, start_date: datetime,
              end_date: datetime) -> BacktestTradingSession:
        """Builds a backtest trading session.

        Parameters
        -----------
        start_date: datetime
            starting date of the backtest
        end_date: datetime
            last date of the backtest

        Returns
        ---------
        BacktestTradingSession
            trading session containing all the necessary parameters
        """
        self._timer = SettableTimer(start_date)
        self._notifiers = Notifiers(self._timer)
        self._events_manager = self._create_event_manager(
            self._timer, self._notifiers)

        self._data_handler = self._create_data_handler(self._data_provider,
                                                       self._timer)
        signals_register = self._signals_register if self._signals_register else BacktestSignalsRegister(
        )

        self._portfolio = Portfolio(self._data_handler, self._initial_cash,
                                    self._timer, self._contract_ticker_mapper)

        self._backtest_result = BacktestResult(self._portfolio,
                                               signals_register,
                                               self._backtest_name, start_date,
                                               end_date, self._initial_risk)
        self._monitor = self._monitor_setup()

        self._slippage_model = self._slippage_model_setup()
        self._commission_model = self._commission_model_setup()
        self._execution_handler = SimulatedExecutionHandler(
            self._data_handler,
            self._timer,
            self._notifiers.scheduler,
            self._monitor,
            self._commission_model,
            self._contract_ticker_mapper,
            self._portfolio,
            self._slippage_model,
            scheduling_time_delay=self._scheduling_time_delay,
            frequency=self._frequency)

        self._time_flow_controller = BacktestTimeFlowController(
            self._notifiers.scheduler, self._events_manager, self._timer,
            self._notifiers.empty_queue_event_notifier, end_date)

        self._broker = BacktestBroker(self._portfolio, self._execution_handler)
        self._order_factory = OrderFactory(self._broker, self._data_handler,
                                           self._contract_ticker_mapper)
        self._position_sizer = self._position_sizer_setup(signals_register)
        self._orders_filters = self._orders_filter_setup()

        self._logger.info("\n".join([
            "Creating Backtest Trading Session.", "\tBacktest Name: {}".format(
                self._backtest_name), "\tData Provider: {}".format(
                    self._data_provider.__class__.__name__),
            "\tContract - Ticker Mapper: {}".format(
                self._contract_ticker_mapper.__class__.__name__),
            "\tStart Date: {}".format(start_date),
            "\tEnd Date: {}".format(end_date),
            "\tInitial Cash: {:.2f}".format(self._initial_cash)
        ]))

        self._logger.info("\n".join([
            "Configuration of components:",
            "\tPosition sizer: {:s}".format(
                self._position_sizer.__class__.__name__),
            "\tTimer: {:s}".format(self._timer.__class__.__name__),
            "\tData Handler: {:s}".format(
                self._data_handler.__class__.__name__),
            "\tBacktest Result: {:s}".format(
                self._backtest_result.__class__.__name__),
            "\tMonitor: {:s}".format(self._monitor.__class__.__name__),
            "\tExecution Handler: {:s}".format(
                self._execution_handler.__class__.__name__),
            "\tSlippage Model: {:s}".format(
                self._slippage_model.__class__.__name__),
            "\tCommission Model: {:s}".format(
                self._commission_model.__class__.__name__),
            "\tBroker: {:s}".format(self._broker.__class__.__name__),
        ]))

        ts = BacktestTradingSession(
            contract_ticker_mapper=self._contract_ticker_mapper,
            start_date=start_date,
            end_date=end_date,
            position_sizer=self._position_sizer,
            orders_filters=self._orders_filters,
            data_handler=self._data_handler,
            timer=self._timer,
            notifiers=self._notifiers,
            portfolio=self._portfolio,
            events_manager=self._events_manager,
            monitor=self._monitor,
            broker=self._broker,
            order_factory=self._order_factory,
            frequency=self._frequency,
            backtest_result=self._backtest_result)

        return ts