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
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
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)
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()
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)
def setUp(self): self.portfolio = Portfolio(Mock(), 100000, Mock(), Mock()) self.trades_generator = TradesGenerator()
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
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