예제 #1
0
    def test_transact_transaction_3(self):
        position = BacktestPositionFactory.create_position(self.contract)

        quantity1 = 50
        price1 = 100
        commission1 = 5
        position.transact_transaction(
            Transaction(self.random_time, self.contract, quantity1, price1,
                        commission1))

        quantity2 = 30
        price2 = 120
        commission2 = 7
        position.transact_transaction(
            Transaction(self.random_time, self.contract, quantity2, price2,
                        commission2))

        quantity3 = -40
        price3 = 150
        commission3 = 11
        transaction3 = Transaction(self.random_time, self.contract, quantity3,
                                   price3, commission3)
        position.transact_transaction(transaction3)

        self.assertEqual(position.contract(), self.contract)
        self.assertEqual(position._is_closed, False)
        self.assertEqual(position.quantity(),
                         quantity1 + quantity2 + quantity3)
        self.assertEqual(position.direction(), 1)
        self.assertEqual(position.start_time, self.random_time)
예제 #2
0
    def test_transact_transaction_close_position_2_transactions(self):

        for quantity in (-50, 50):
            portfolio, dh, _ = self.get_portfolio_and_data_handler()
            contract = self.fut_contract
            ticker = portfolio.contract_ticker_mapper.contract_to_ticker(contract)

            all_commissions = 0.0

            transaction_1 = Transaction(self.random_time, contract, quantity=quantity, price=200, commission=7)
            portfolio.transact_transaction(transaction_1)
            all_commissions += transaction_1.commission
            self.data_handler_prices = self.prices_series
            portfolio.update()

            new_price = dh.get_last_available_price(ticker)
            transaction_2 = Transaction(self.end_time, contract, quantity=-transaction_1.quantity,
                                        price=new_price,
                                        commission=transaction_1.commission)
            portfolio.transact_transaction(transaction_2)
            all_commissions += transaction_2.commission
            portfolio.update()

            pnl = (new_price - transaction_1.price) * transaction_1.quantity * contract.contract_size \
                - all_commissions

            self.assertEqual(portfolio.initial_cash, self.initial_cash)
            self.assertEqual(portfolio.net_liquidation, self.initial_cash + pnl)
            self.assertEqual(portfolio.gross_exposure_of_positions, 0)
            self.assertEqual(portfolio.current_cash, self.initial_cash + pnl)
            self.assertEqual(len(portfolio.open_positions_dict), 0)
예제 #3
0
    def test_market_opens_at_much_higher_price_than_it_closed_at_yesterday(
            self):
        self.buy_stop_loss_order = Order(self.msft_contract,
                                         quantity=1,
                                         execution_style=StopOrder(120.0),
                                         time_in_force=TimeInForce.GTC)

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

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

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

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

        self.assertEqual(self.monitor.record_transaction.call_count, 3)
        self.assertEqual(self.portfolio.transact_transaction.call_count, 3)
예제 #4
0
    def test_transact_transaction_5(self):
        position = BacktestFuturePosition(self.ticker)

        quantity1 = 50
        price1 = 100
        commission1 = 5
        cash_move1 = position.transact_transaction(
            Transaction(self.random_time, self.ticker, quantity1, price1,
                        commission1))
        self.assertEqual(cash_move1, -commission1)

        quantity1 = 50
        price1 = 110
        commission1 = 5
        cash_move1 = position.transact_transaction(
            Transaction(self.random_time, self.ticker, quantity1, price1,
                        commission1))
        self.assertEqual(cash_move1, -commission1)

        quantity2 = -30
        price2 = 120
        commission2 = 7
        cash_move2 = position.transact_transaction(
            Transaction(self.random_time, self.ticker, quantity2, price2,
                        commission2))
        expected_move = (price2 -
                         105) * (-quantity2) * self.point_value - commission2
        self.assertEqual(cash_move2, expected_move)
예제 #5
0
    def test_execute_orders(self):
        mocked_fill_volume = 30
        mocked_fill_price = 100.0

        simulated_executor = self._set_up_simulated_executor(
            mocked_fill_price=mocked_fill_price,
            mocked_fill_volume=mocked_fill_volume)
        simulated_executor.execute_orders()

        # No open orders were available, thus the list of transactions should be empty
        self.assertCountEqual(self.recorded_transactions, [])

        simulated_executor.assign_order_ids(self.orders)
        simulated_executor.accept_orders(self.orders)
        simulated_executor.execute_orders()

        # Both open orders were available
        expected_transactions = [
            Transaction(
                self.backtest_date,
                self.contract_ticker_mapper.ticker_to_contract(
                    self.example_ticker), mocked_fill_volume,
                mocked_fill_price, 0.0),
            Transaction(
                self.backtest_date,
                self.contract_ticker_mapper.ticker_to_contract(
                    self.example_ticker_2), mocked_fill_volume,
                mocked_fill_price, 0.0),
        ]
        self.assertCountEqual(self.recorded_transactions,
                              expected_transactions)
예제 #6
0
    def test_portfolio_eod_series(self):
        expected_portfolio_eod_series = PricesSeries()

        # Empty portfolio
        portfolio, dh, timer = self.get_portfolio_and_data_handler()
        portfolio.update(record=True)
        expected_portfolio_eod_series[timer.time] = self.initial_cash

        contract = self.fut_contract
        ticker = portfolio.contract_ticker_mapper.contract_to_ticker(contract)

        # Buy contract
        self._shift_timer_to_next_day(timer)
        transaction_1 = Transaction(timer.time, contract, quantity=50, price=250, commission=7)
        portfolio.transact_transaction(transaction_1)
        self.data_handler_prices = self.prices_series
        portfolio.update(record=True)

        position = portfolio.open_positions_dict[contract]

        price_1 = dh.get_last_available_price(ticker)
        pnl = contract.contract_size * transaction_1.quantity * (price_1 - transaction_1.price)
        nav = self.initial_cash + pnl - transaction_1.commission
        expected_portfolio_eod_series[timer.time] = nav

        # Contract goes up in value
        self._shift_timer_to_next_day(timer)
        self.data_handler_prices = self.prices_up
        portfolio.update(record=True)

        price_2 = dh.get_last_available_price(ticker)  # == 270
        pnl = contract.contract_size * transaction_1.quantity * (price_2 - price_1)
        nav += pnl
        expected_portfolio_eod_series[timer.time] = nav

        # Sell part of the contract
        self._shift_timer_to_next_day(timer)
        transaction_2 = Transaction(timer.time, contract, quantity=-25, price=price_2, commission=19)
        portfolio.transact_transaction(transaction_2)
        self.data_handler_prices = self.prices_up
        portfolio.update(record=True)

        pnl = (transaction_2.price - price_2) * transaction_2.quantity * contract.contract_size - transaction_2.commission
        nav += pnl
        expected_portfolio_eod_series[timer.time] = nav

        # Price goes down
        self._shift_timer_to_next_day(timer)
        self.data_handler_prices = self.prices_down
        portfolio.update(record=True)

        price_3 = dh.get_last_available_price(ticker)  # == 210
        pnl2 = contract.contract_size * position.quantity() * (price_3 - price_2)
        nav += pnl2
        expected_portfolio_eod_series[timer.time] = nav

        tms = portfolio.portfolio_eod_series()
        assert_series_equal(expected_portfolio_eod_series, tms)
예제 #7
0
 def test_position_close(self):
     position = BacktestPosition(self.contract)
     self.assertEqual(position.is_closed, False)
     position.transact_transaction(Transaction(self.time, self.contract, 20, 100, 0))
     self.assertEqual(position.is_closed, False)
     position.transact_transaction(Transaction(self.time, self.contract, -10, 120, 20))
     self.assertEqual(position.is_closed, False)
     position.transact_transaction(Transaction(self.time, self.contract, -10, 110, 20))
     self.assertEqual(position.is_closed, True)
예제 #8
0
    def test_transact_transaction_2(self):
        portfolio, dh, _ = self.get_portfolio_and_data_handler()
        contract = self.contract
        ticker = portfolio.contract_ticker_mapper.contract_to_ticker(contract)

        # First transaction
        transaction_1 = Transaction(self.random_time,
                                    contract,
                                    quantity=50,
                                    price=100,
                                    commission=5)
        portfolio.transact_transaction(transaction_1)

        # Set new prices
        self.data_handler_prices = self.prices_series
        portfolio.update()

        # Get the new price of the contract
        new_price = dh.get_last_available_price(ticker)

        pnl_1 = (new_price - transaction_1.price) * transaction_1.quantity * transaction_1.contract.contract_size \
            - transaction_1.commission
        cash_move1 = self._cash_move(transaction_1)

        self.assertEqual(portfolio.initial_cash, self.initial_cash)
        self.assertEqual(portfolio.net_liquidation, self.initial_cash + pnl_1)
        self.assertEqual(portfolio.gross_exposure_of_positions,
                         new_price * transaction_1.quantity)
        self.assertEqual(portfolio.current_cash,
                         self.initial_cash + cash_move1)
        self.assertEqual(len(portfolio.open_positions_dict), 1)

        # Second transaction
        transaction_2 = Transaction(self.random_time,
                                    contract,
                                    quantity=-20,
                                    price=110,
                                    commission=5)
        portfolio.transact_transaction(transaction_2)
        portfolio.update()

        pnl_2 = (new_price - transaction_2.price) * transaction_2.quantity * transaction_2.contract.contract_size \
            - transaction_2.commission
        cash_move_2 = self._cash_move(transaction_2)

        self.assertEqual(portfolio.initial_cash, self.initial_cash)
        self.assertEqual(portfolio.net_liquidation,
                         self.initial_cash + pnl_1 + pnl_2)

        position = portfolio.open_positions_dict[contract]
        self.assertEqual(
            portfolio.gross_exposure_of_positions,
            new_price * position.quantity() * contract.contract_size)
        self.assertEqual(portfolio.current_cash,
                         self.initial_cash + cash_move1 + cash_move_2)
        self.assertEqual(len(portfolio.open_positions_dict), 1)
예제 #9
0
    def test_transact_transaction_split_and_close(self):
        portfolio, dh, _ = self.get_portfolio_and_data_handler()
        contract = self.fut_contract
        ticker = portfolio.contract_ticker_mapper.contract_to_ticker(contract)

        # Transact the initial transaction
        transactions = []
        quantity = 50

        # Set initial price for the given ticker
        self.data_handler_prices = self.prices_down
        price_1 = dh.get_last_available_price(ticker)  # == 210

        initial_transaction = Transaction(self.random_time,
                                          contract,
                                          quantity=quantity,
                                          price=price_1,
                                          commission=10)
        portfolio.transact_transaction(initial_transaction)
        transactions.append(initial_transaction)
        portfolio.update()

        # Change of price for the given ticker
        self.data_handler_prices = self.prices_series
        price_2 = dh.get_last_available_price(ticker)  # == 250

        transaction_to_split = Transaction(self.random_time,
                                           contract,
                                           quantity=(-2) * quantity,
                                           price=price_2,
                                           commission=18)
        portfolio.transact_transaction(transaction_to_split)
        transactions.append(transaction_to_split)
        portfolio.update()

        trade_pnl = (price_2 - price_1) * contract.contract_size * quantity
        trade_pnl -= initial_transaction.commission
        trade_pnl -= transaction_to_split.commission * abs(
            initial_transaction.quantity / transaction_to_split.quantity)

        # Change of price for the given ticker
        self.data_handler_prices = self.prices_series
        price_3 = dh.get_last_available_price(ticker)  # == 270
        closing_transaction = Transaction(self.random_time,
                                          contract,
                                          quantity=quantity,
                                          price=price_3,
                                          commission=5)
        portfolio.transact_transaction(closing_transaction)
        transactions.append(closing_transaction)
        portfolio.update()

        # All positions should be closed at this moment
        self.assertEqual(len(portfolio.open_positions_dict), 0)
예제 #10
0
 def test_position_direction1(self):
     position = BacktestPositionFactory.create_position(self.contract)
     self.assertEqual(position.direction(), 0)
     position.transact_transaction(
         Transaction(self.start_time, self.contract, 20, 100, 0))
     self.assertEqual(position.direction(), 1)
     position.transact_transaction(
         Transaction(self.start_time, self.contract, -10, 100, 0))
     self.assertEqual(position.direction(), 1)
     position.transact_transaction(
         Transaction(self.start_time, self.contract, -10, 100, 0))
     self.assertEqual(position.direction(), 1)
예제 #11
0
 def test_position_close(self):
     position = BacktestPositionFactory.create_position(self.ticker)
     self.assertEqual(position._is_closed, False)
     position.transact_transaction(
         Transaction(self.start_time, self.ticker, 20, 100, 0))
     self.assertEqual(position._is_closed, False)
     position.transact_transaction(
         Transaction(self.start_time, self.ticker, -10, 120, 20))
     self.assertEqual(position._is_closed, False)
     position.transact_transaction(
         Transaction(self.start_time, self.ticker, -10, 110, 20))
     self.assertEqual(position._is_closed, True)
예제 #12
0
    def test_closed_position(self):
        position = BacktestPosition(self.contract)
        position.transact_transaction(Transaction(self.time, self.contract, 20, 100, 0))
        position.transact_transaction(Transaction(self.time, self.contract, -20, 100, 0))

        with self.assertRaises(AssertionError):
            position.transact_transaction(Transaction(self.time, self.contract, 1, 100, 0))

        with self.assertRaises(AssertionError):
            position.transact_transaction(Transaction(self.time, self.contract, -1, 100, 0))

        with self.assertRaises(AssertionError):
            position.update_price(110, 120)
예제 #13
0
    def test_position_stats_on_close(self):
        position = BacktestPosition(self.contract)
        position.transact_transaction(Transaction(self.time, self.contract, 20, 100, 0))
        position.update_price(110, 120)
        position.transact_transaction(Transaction(self.time, self.contract, -20, 120, 0))

        self.assertEqual(position.contract(), self.contract)
        self.assertEqual(position.quantity(), 0)
        self.assertEqual(position.current_price, 110)
        self.assertEqual(position.market_value, 0)
        self.assertAlmostEqual(position.cost_basis(), 0, places=6)
        self.assertEqual(position.avg_cost_per_share(), 0)
        self.assertAlmostEqual(position.unrealised_pnl(), 0, places=6)
        self.assertEqual(position.realized_pnl(), 20*20)
예제 #14
0
    def test_transact_transaction_split_position(self):
        portfolio, dh, _ = self.get_portfolio_and_data_handler()
        contract = self.fut_contract
        ticker = portfolio.contract_ticker_mapper.contract_to_ticker(contract)

        # Transact two transaction, which will result in transactions splitting
        quantity_after_first_transaction = 50
        quantity_after_second_transaction = -10
        initial_price = 200
        commission = 7

        # Transact the initial transaction
        transaction_1 = Transaction(self.random_time, contract,
                                    quantity_after_first_transaction,
                                    initial_price, commission)
        portfolio.transact_transaction(transaction_1)

        # Set new prices
        self.data_handler_prices = self.prices_series
        new_price = dh.get_last_available_price(ticker)  # == 250
        portfolio.update()

        # Transact the second transaction
        transaction_quantity = -quantity_after_first_transaction + quantity_after_second_transaction
        transaction_2 = Transaction(self.end_time, contract,
                                    transaction_quantity, new_price,
                                    commission)
        portfolio.transact_transaction(transaction_2)
        portfolio.update()

        # Compute the pnl of the position, which was closed
        quantity = max(abs(quantity_after_first_transaction),
                       abs(quantity_after_second_transaction))
        quantity *= sign(quantity_after_first_transaction)
        all_commissions = transaction_1.commission + transaction_2.commission
        pnl = (new_price - initial_price
               ) * quantity * contract.contract_size - all_commissions

        position = list(portfolio.open_positions_dict.values())[0]
        self.assertEqual(position.quantity(), -10)

        self.assertEqual(portfolio.current_cash, self.initial_cash + pnl)
        self.assertEqual(portfolio.net_liquidation, self.initial_cash + pnl)

        self.assertEqual(
            portfolio.gross_exposure_of_positions,
            abs(quantity_after_second_transaction * self.contract_size *
                new_price))
        self.assertEqual(len(portfolio.open_positions_dict), 1)
예제 #15
0
    def test_market_opens_at_much_lower_price_than_it_closed_at_yesterday(self):
        self._set_bar_for_today(open_price=70.0, high_price=100.0, low_price=68.0, close_price=90.0, volume=100000000.0)
        self._trigger_single_time_event()
        self.exec_handler.on_market_close(...)

        assert_lists_equal([], self.exec_handler.get_open_orders())
        expected_transactions = [
            Transaction(self.timer.now(), self.msft_ticker, -1, 70.0, 0),
            Transaction(self.timer.now(), self.msft_ticker, -1, 70.0, 0),
        ]
        self.monitor.record_transaction.assert_has_calls(call(t) for t in expected_transactions)
        self.portfolio.transact_transaction.assert_has_calls(call(t) for t in expected_transactions)

        self.assertEqual(self.monitor.record_transaction.call_count, 2)
        self.assertEqual(self.portfolio.transact_transaction.call_count, 2)
예제 #16
0
    def test_transact_transaction_3(self):
        portfolio, dh, _ = self.get_portfolio_and_data_handler()
        contract = self.fut_contract
        ticker = portfolio.contract_ticker_mapper.contract_to_ticker(contract)

        # First transaction
        transaction_1 = Transaction(self.random_time, contract, quantity=50, price=200, commission=7)
        portfolio.transact_transaction(transaction_1)

        # Set new prices
        self.data_handler_prices = self.prices_series
        portfolio.update()

        # Get the new price of the contract
        new_price = dh.get_last_available_price(ticker)

        pnl_1 = (new_price - transaction_1.price) * transaction_1.quantity * transaction_1.contract.contract_size \
            - transaction_1.commission
        cash_move_1 = -transaction_1.commission

        self.assertEqual(portfolio.net_liquidation, self.initial_cash + pnl_1)
        self.assertEqual(portfolio.gross_exposure_of_positions,
                         transaction_1.quantity * contract.contract_size * new_price)
        self.assertEqual(portfolio.current_cash, self.initial_cash + cash_move_1)
        self.assertEqual(len(portfolio.open_positions_dict), 1)

        # Second transaction
        transaction_2 = Transaction(self.random_time, contract, quantity=-20, price=new_price, commission=15)
        portfolio.transact_transaction(transaction_2)
        portfolio.update()

        # Computed the realized pnl, which is already included in the portfolio current cash - it may not be the same as
        # the pnl of the trade, as the commission trades
        trade_size = min(abs(transaction_1.quantity), abs(transaction_2.quantity))

        realised_pnl = (-1) * transaction_1.price * trade_size * sign(transaction_1.quantity) * contract.contract_size
        realised_pnl += (-1) * transaction_2.price * trade_size * sign(transaction_2.quantity) * contract.contract_size
        realised_pnl -= transaction_2.commission  # Only transaction2 commission is yet realised

        self.assertEqual(portfolio.current_cash, self.initial_cash + cash_move_1 + realised_pnl)

        position = portfolio.open_positions_dict[contract]
        position_unrealised_pnl = position.unrealised_pnl
        self.assertEqual(portfolio.net_liquidation, portfolio.current_cash + position_unrealised_pnl)

        exposure = position.quantity() * contract.contract_size * new_price
        self.assertEqual(portfolio.gross_exposure_of_positions, position.total_exposure())
        self.assertEqual(exposure, position.total_exposure())
예제 #17
0
    def test_portfolio_history(self):
        # empty portfolio
        portfolio, dh, timer = self.get_portfolio_and_data_handler()
        portfolio.update(record=True)

        # buy contract
        quantity = 50
        price = 250
        commission1 = 7
        new_time = timer.time + RelativeDelta(days=1)

        portfolio.transact_transaction(
            Transaction(new_time, self.fut_contract, quantity, price,
                        commission1))
        timer.set_current_time(new_time)
        self.data_handler_prices = self.prices_series
        portfolio.update(record=True)

        # buy another instrument - price goes up
        portfolio.transact_transaction(
            Transaction(new_time, self.contract, 20, 120, commission1))
        new_time = timer.time + RelativeDelta(days=1)
        timer.set_current_time(new_time)
        self.data_handler_prices = self.prices_up
        portfolio.update(record=True)

        # sell part of the contract
        quantity = -30
        price = 270
        commission2 = 9
        new_time = timer.time + RelativeDelta(days=1)
        portfolio.transact_transaction(
            Transaction(new_time, self.fut_contract, quantity, price,
                        commission2))
        timer.set_current_time(new_time)
        self.data_handler_prices = self.prices_up
        portfolio.update(record=True)

        # price goes down
        new_time = timer.time + RelativeDelta(days=1)
        timer.set_current_time(new_time)
        self.data_handler_prices = self.prices_down
        portfolio.update(record=True)

        asset_history = portfolio.positions_history()
        self.assertEqual(asset_history.shape, (5, 2))
        self.assertEqual(asset_history.iloc[4, 0].total_exposure, 315000)
        self.assertEqual(asset_history.iloc[4, 1].total_exposure, 2000)
예제 #18
0
    def _remove_acquired_or_not_active_positions(self):
        """
        Generate an artificial transaction to address closing a position from portfolio, which was inactive for at least
        a week (during this time not a single price for the asset was available). The price of this transaction is the
        last price of the asset recorded by the portfolio and the commission is set to 0, as no real order is created.
        """
        all_tickers_in_portfolio = list(
            self.portfolio.open_positions_dict.keys())
        current_prices_series = self.data_handler.get_last_available_price(
            tickers=all_tickers_in_portfolio)
        positions_to_be_removed = [
            p for p in self.portfolio.open_positions_dict.values()
            if np.isnan(current_prices_series[p.ticker()])
        ]

        for position in positions_to_be_removed:
            closing_transaction = Transaction(self.timer.now(),
                                              position.ticker(),
                                              -position.quantity(),
                                              position.current_price, 0)
            self.monitor.record_transaction(closing_transaction)
            self.portfolio.transact_transaction(closing_transaction)
            self.logger.warning(
                f"{self.timer.now()}: position assigned to Ticker {position.ticker()} removed due to "
                f"incomplete price data.")
예제 #19
0
    def test_position_stats_on_close(self):
        position = BacktestPositionFactory.create_position(self.contract)
        position.transact_transaction(
            Transaction(self.start_time, self.contract, 20, 100, 50))
        position.update_price(110, 120)

        closing_transaction = Transaction(self.start_time, self.contract, -20,
                                          120, 50)
        position.transact_transaction(closing_transaction)

        self.assertEqual(position.contract(), self.contract)
        self.assertEqual(position._is_closed, True)
        self.assertEqual(position.quantity(), 0)
        self.assertEqual(position.current_price, 110)  # set by update_price
        self.assertEqual(position.direction(), 1)
        self.assertEqual(position.start_time, self.start_time)
예제 #20
0
    def _parse_transactions_file(
            self, path_to_transactions_file: str) -> List[Transaction]:
        """ Parse the Transactions csv file created by the Monitor and generate a list of transactions objects. """
        ticker_params_to_ticker = {(ticker.name, ticker.security_type,
                                    ticker.point_value): ticker
                                   for ticker in self.tickers}

        def get_matching_ticker(row: QFSeries) -> Ticker:
            """ Returns the matching specific ticker. In case if the ticker does not belong to the list of tickers
            passed as the parameter, the transaction is excluded. """
            ticker_str = row.loc["Contract symbol"]
            name = row.loc["Asset Name"]
            sec_type = SecurityType(row.loc["Security type"])
            point_value = row.loc["Contract size"]
            ticker = ticker_params_to_ticker.get((name, sec_type, point_value),
                                                 None)
            if isinstance(ticker, FutureTicker):
                ticker_type = ticker.supported_ticker_type()
                ticker = ticker_type(ticker_str, sec_type, point_value)
            return ticker

        transactions_df = pd.read_csv(path_to_transactions_file)
        transactions = [
            Transaction(time=pd.to_datetime(row.loc["Timestamp"]),
                        ticker=get_matching_ticker(row),
                        quantity=row.loc["Quantity"],
                        price=row.loc["Price"],
                        commission=row.loc["Commission"])
            for _, row in transactions_df.iterrows()
        ]
        transactions = [t for t in transactions if t.ticker is not None]
        return transactions
예제 #21
0
    def _record_trade_and_transaction(
            self, prev_position_quantity: int, prev_position_avg_price: float, transaction: Transaction):
        """
        Trade is defined as a transaction that goes in the direction of making your position smaller.
        For example:
           selling part or entire long position is a trade
           buying back part or entire short position is a trade
           buying additional shares of existing long position is NOT a trade
        """
        self.transactions.append(transaction)

        is_a_trade = sign(transaction.quantity) * sign(prev_position_quantity) == -1
        if is_a_trade:
            time = transaction.time
            contract = transaction.contract

            # only the part that goes in the opposite direction is considered as a trade
            quantity = min([abs(transaction.quantity), abs(prev_position_quantity)])
            quantity *= sign(prev_position_quantity)  # sign of the position should be preserved

            entry_price = prev_position_avg_price
            exit_price = transaction.average_price_including_commission()
            trade = Trade(time=time,
                          contract=contract,
                          quantity=quantity,
                          entry_price=entry_price,
                          exit_price=exit_price)
            self.trades.append(trade)
예제 #22
0
    def test_market_value(self):
        position = BacktestFuturePosition(self.ticker)
        quantity = 50
        price = 100
        commission = 5
        position.transact_transaction(
            Transaction(self.random_time, self.ticker, quantity, price,
                        commission))

        self.assertEqual(position.market_value(), 0)  # before update_price

        position.update_price(bid_price=100, ask_price=100 + 1)
        self.assertEqual(position.market_value(),
                         0)  # price did not change yet

        bid_price = 110
        position.update_price(bid_price=bid_price, ask_price=bid_price + 1)

        market_value = (bid_price - price) * quantity * self.point_value
        self.assertEqual(position.market_value(), market_value)

        bid_price = 120
        position.update_price(bid_price=bid_price, ask_price=bid_price + 1)
        market_value = (bid_price - price) * quantity * self.point_value
        self.assertEqual(position.market_value(), market_value)
예제 #23
0
    def test_transact_transaction_2(self):
        position = BacktestFuturePosition(self.contract)
        quantity = -50
        price = 100
        commission = 5

        cash_move = position.transact_transaction(Transaction(self.random_time, self.contract, quantity, price, commission))
        self.assertEqual(cash_move, -commission)
예제 #24
0
    def test_transact_transaction_4(self):
        position = BacktestEquityPosition(self.contract)

        quantity1 = -50
        price1 = 100
        commission1 = 5
        cash_move1 = position.transact_transaction(Transaction(self.random_time, self.contract, quantity1, price1,
                                                               commission1))

        quantity2 = 30
        price2 = 120
        commission2 = 7
        cash_move2 = position.transact_transaction(Transaction(self.random_time, self.contract, quantity2, price2,
                                                               commission2))

        self.assertEqual(cash_move1, -(quantity1 * price1 + commission1))
        self.assertEqual(cash_move2, -(quantity2 * price2 + commission2))
예제 #25
0
    def test_transact_transaction_1(self):
        position = BacktestEquityPosition(self.contract)
        quantity = 50
        price = 100
        commission = 5

        cash_move = position.transact_transaction(Transaction(self.random_time, self.contract, quantity, price, commission))
        self.assertEqual(cash_move, -(quantity * price + commission))
예제 #26
0
    def test_both_orders_executed_when_both_stop_prices_hit(self):
        self._set_bar_for_today(open_price=100.0, high_price=110.0, low_price=90.0, close_price=105.0,
                                volume=100000000.0)
        self._trigger_single_time_event()
        self.exec_handler.on_market_close(...)

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

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

        self.assertEqual(self.monitor.record_transaction.call_count, 2)
        self.assertEqual(self.portfolio.transact_transaction.call_count, 2)
예제 #27
0
    def test_transact_transaction_4(self):
        position = BacktestFuturePosition(self.contract)

        quantity1 = -50
        price1 = 100
        commission1 = 5
        cash_move1 = position.transact_transaction(Transaction(self.random_time, self.contract, quantity1, price1,
                                                               commission1))
        self.assertEqual(cash_move1, -commission1)

        quantity2 = 30
        price2 = 120
        commission2 = 7
        cash_move2 = position.transact_transaction(Transaction(self.random_time, self.contract, quantity2, price2,
                                                               commission2))
        expected_move = (price2 - price1) * (-quantity2) * self.contract_size - commission2
        self.assertEqual(cash_move2, expected_move)
예제 #28
0
    def test_without_commission_position(self):
        position = BacktestPositionFactory.create_position(self.contract)

        transactions = [
            Transaction(self.start_time, self.contract, 50, 100, 0),
            Transaction(self.start_time, self.contract, 30, 120, 0),
            Transaction(self.start_time, self.contract, -20, 175, 0),
            Transaction(self.start_time, self.contract, -30, 160, 0),
            Transaction(self.start_time, self.contract, 10, 150, 0),
            Transaction(self.start_time, self.contract, 10, 170, 0),
            Transaction(self.start_time, self.contract, -20, 150, 0)
        ]

        for transaction in transactions:
            position.transact_transaction(transaction)

        current_price = 110
        position.update_price(current_price, 120)

        self.assertEqual(position.contract(), self.contract)

        position_quantity = sum(t.quantity for t in transactions)
        self.assertEqual(position.quantity(), position_quantity)

        self.assertEqual(position.current_price, current_price)
예제 #29
0
    def test_position(self):
        position = BacktestPositionFactory.create_position(self.contract)

        transactions = (Transaction(self.start_time, self.contract, 50, 100,
                                    5),
                        Transaction(self.start_time, self.contract, 30, 120,
                                    3),
                        Transaction(self.start_time, self.contract, -20, 175,
                                    2),
                        Transaction(self.start_time, self.contract, -30, 160,
                                    1),
                        Transaction(self.start_time, self.contract, 10, 150,
                                    7),
                        Transaction(self.start_time, self.contract, 10, 170,
                                    4),
                        Transaction(self.start_time, self.contract, -20, 150,
                                    5))

        for transaction in transactions:
            position.transact_transaction(transaction)
        position.update_price(110, 120)

        self.assertEqual(position.contract(), self.contract)
        self.assertEqual(position.quantity(), 30)
        self.assertEqual(position.current_price, 110)
예제 #30
0
    def test_closed_position(self):
        position = BacktestPositionFactory.create_position(self.contract)
        position.transact_transaction(
            Transaction(self.start_time, self.contract, 20, 100, 0))
        position.transact_transaction(
            Transaction(self.start_time, self.contract, -20, 100, 0))

        with self.assertRaises(AssertionError):
            # position is now closed and should not accept new transactions
            position.transact_transaction(
                Transaction(self.start_time, self.contract, 1, 100, 0))

        with self.assertRaises(AssertionError):
            # position is now closed and should not accept new transactions
            position.transact_transaction(
                Transaction(self.start_time, self.contract, -1, 100, 0))

        with self.assertRaises(AssertionError):
            # position is now closed
            position.update_price(110, 120)