def test_deepcopy_first_n_items(self):
        stock_market_data = StockMarketData([Company.A, Company.B],
                                            [Period.TRAINING, Period.TESTING])

        # test copying zero items
        copy = stock_market_data.deepcopy_first_n_items(0)
        self.assertIsNotNone(copy)
        self.assertNotEqual(stock_market_data, copy)
        self.assertEqual(copy.get_number_of_companies(), 2)
        self.assertEqual(copy.get_row_count(), 0)

        # test copying one item
        copy = stock_market_data.deepcopy_first_n_items(1)
        self.assertIsNotNone(copy)
        self.assertNotEqual(stock_market_data, copy)
        self.assertEqual(copy.get_number_of_companies(), 2)
        self.assertEqual(copy.get_most_recent_trade_day(), Date(1962, 1, 2))
        self.assertEqual(copy.get_most_recent_price(Company.A), 0.059620)
        self.assertEqual(copy.get_most_recent_price(Company.B), 2.192523)
    def run(self,
            data: StockMarketData,
            traders: List[ITrader],
            offset: int = 0) -> Dict[ITrader, Dict[Date, Portfolio]]:
        """
        Runs the stock exchange over the given stock market data for the given traders.
        :param data: The complete stock market data
        :param traders: A list of all traders
        :param offset: The number of trading days which a will be skipped before (!) trading starts
        :return: The main data structure, which stores one portfolio per trade day, for each traders
        """
        assert data is not None
        assert traders is not None

        # initialize the main data structure: Dictionary over traders, that stores each traders's portfolio per day
        # data structure type is Dict[ITrader, Dict[Date, Portfolio]]
        trade_dates = data.get_trade_days()
        assert trade_dates  # must not be empty
        assert 0 <= offset < len(trade_dates)  # offset must be feasible
        self.__complete_stock_market_data = data
        self.__trader_portfolios = {
            trader: {
                trade_dates[offset]: Portfolio(self.__cash)
            }
            for trader in traders
        }

        # iterate over all trade days minus 1, because we don't trade on the last day
        for tick in range(offset, len(trade_dates) - 1):
            logger.debug(
                f"Stock Exchange: Current tick '{tick}' means today is '{trade_dates[tick]}'"
            )
            if tick % 365 == 1:
                print(trade_dates[tick])
            # build stock market data until today
            current_stock_market_data = data.deepcopy_first_n_items(tick + 1)

            # iterate over all traders
            for trader in traders:
                # get the traders's order list by giving him a copy (to prevent cheating) of today's portfolio
                todays_portfolio = self.__trader_portfolios[trader][
                    trade_dates[tick]]
                current_order_list = trader.trade(
                    copy.deepcopy(todays_portfolio), current_stock_market_data)

                # execute order list and save the result as tomorrow's portfolio
                tomorrows_portfolio = copy.deepcopy(todays_portfolio)
                tomorrows_portfolio.update_with_order_list(
                    current_stock_market_data, current_order_list)
                self.__trader_portfolios[trader][trade_dates[
                    tick + 1]] = tomorrows_portfolio

        return self.__trader_portfolios