def transact_transaction(self, transaction: Transaction): """ Adjusts positions to account for a transaction. Handles any new position or modification to a current position """ transaction_cost = 0.0 existing_position = self.open_positions_dict.get( transaction.ticker, None) if existing_position is None: # open new, empty position new_position = self._create_new_position(transaction) transaction_cost += new_position.transact_transaction(transaction) else: # there is already an existing position results_in_opposite_direction, basic_transaction, remaining_transaction \ = split_transaction_if_needed(existing_position.quantity(), transaction) transaction_cost += existing_position.transact_transaction( basic_transaction) if existing_position.is_closed(): ticker = transaction.ticker self.open_positions_dict.pop(ticker) self._closed_positions.append(existing_position) if results_in_opposite_direction: # means we were going from Long to Short in one transaction new_position = self._create_new_position(remaining_transaction) transaction_cost += new_position.transact_transaction( remaining_transaction) self.current_cash += transaction_cost
def _split_transactions_if_needed(self, transactions_series: QFSeries): """ Split these transactions, which change the direction of the position (e.g. the direction of the position """ # before the transaction was -1, after it is 1) split_transactions = [] # type: List[Transaction] total_quantity: int = 0 for transaction in transactions_series: split_required, closing_transaction, remaining_transaction = split_transaction_if_needed( total_quantity, transaction) total_quantity += transaction.quantity if split_required: split_transactions.extend( [closing_transaction, remaining_transaction]) else: split_transactions.append(transaction) return split_transactions