Exemplo n.º 1
0
    def test_place_order_with_api_exception(self):
        with patch.object(td_ameritrade, 'get_credentials',
                          return_value=("aaa", "bbb", "ccc")), \
                patch.object(td_ameritrade, 'login', return_value=None), \
                patch.object(td_ameritrade, 'request', side_effect=TradeError("Some Error", None, None)):

            with self.assertRaises(TradeError):
                td_ameritrade.place_order("SELL", "xxx", 1, "SHARES")
Exemplo n.º 2
0
    def test_place_order_with_invalid_param_values(self):
        with patch.object(td_ameritrade, 'get_credentials',
                          return_value=("aaa", "bbb", "ccc")), \
                patch.object(td_ameritrade, 'login', return_value=None), \
                patch.object(td_ameritrade, 'request', return_value=({}, None)):

            with self.assertRaises(ValidationError):
                td_ameritrade.place_order("Something Else", "xxx", 1, "SHARES")

            with self.assertRaises(ValidationError):
                td_ameritrade.place_order("SELL", "xxx", 1, "NOT_VALID")
Exemplo n.º 3
0
    def test_place_order_with_invalid_headers(self):
        with patch.object(td_ameritrade, 'get_credentials',
                          return_value=("aaa", "bbb", "ccc")), \
                patch.object(td_ameritrade, 'login', return_value=None), \
                patch.object(td_ameritrade, 'request', return_value=({}, None)):

            order_id = td_ameritrade.place_order("SELL", "xxx", 1, "SHARES")
            self.assertEqual(len(order_id), 2)
Exemplo n.º 4
0
    def test_place_order_with_valid_headers(self):
        with patch.object(td_ameritrade, 'get_credentials',
                          return_value=("aaa", "bbb", "ccc")), \
                patch.object(td_ameritrade, 'login', return_value=None), \
                patch.object(td_ameritrade, 'request', return_value=({
                    'Location': 'https://api.tdameritrade.com/v1/accounts/123456789/orders/0987654321'
                }, None)):

            order_id = td_ameritrade.place_order("SELL", "xxx", 1, "SHARES")
            self.assertEqual(order_id, '0987654321')
Exemplo n.º 5
0
    def trade(self, action: str, trade_instructions: list,
              new_portfolio: dict):
        '''
            Executes all trades for the supplied list and action (BUY/SELL).
            'new_portfolio' is optional and if supplied, will be updated
            the details of the transaction.

            Parameters
            ----------
            action: str
                Trade action (BUY or SELL)
            trade_instructions: list
                list of tuples (ticker, shares_amt) that must be traded.
            new_portfolio: Portfolio
                Optional portfolio object. When buying securities it will
                be updated with the trade details.
        '''
        def fill_order(order_id: str, quantity: int, purchase_time: str):
            '''
                If the order is a BUY, then update the portfolio with the
                details of the trade.
            '''
            if order_id in order_ids:
                order_ids.remove(order_id)

            if new_portfolio is None or action == 'SELL':
                return

            for sec in new_portfolio.model['current_portfolio']['securities']:
                if sec['order_id'] == order_id:
                    sec['purchase_date'] = util.datetime_to_iso_utc_string(
                        parser.parse(purchase_time))
                    sec['trade_state'] = 'FILLED'
                    sec['quantity'] = quantity
                    break

        def track_order(ticker: str, order_id: str):
            '''
                associates the supplied order ID with a specific security listed
                in the portfolio
            '''
            order_ids.append(order_id)

            if new_portfolio is None or action == 'SELL':
                return

            new_portfolio.get_position(ticker)['order_id'] = order_id

        #
        # Executes all trades
        #

        log.info("About to %s: %s" % (action, str(trade_instructions)))

        order_ids = []

        if (len(trade_instructions) == 0):
            log.info("There are no securities to be traded")
            return True

        for (ticker, quantity) in trade_instructions:
            try:
                log.info("Placing order: %s %.2f %s" %
                         (action, quantity, ticker))
                order_id = td_ameritrade.place_order(action, ticker, quantity,
                                                     'SHARES')
                track_order(ticker, order_id)
            except TradeError as te:
                log.warning("Could not execute order, because: %s" % str(te))
                order_ids.append('ERROR')

        #
        # Wait for trades to complete and update portfolio accordingly
        #
        for i in range(0, 5):
            log.info("Waiting for all trades to execute")
            recent_orders = td_ameritrade.list_recent_orders()

            completed = True
            for order_id in recent_orders.keys():
                status = recent_orders[order_id]['status']
                close_time = recent_orders[order_id]['closeTime']

                log.debug("Order %s is in %s state" % (order_id, status))
                if close_time is None:
                    log.info("Order %s is not completed" % order_id)
                    completed = False
                elif status == 'FILLED':
                    log.info(
                        "Order %s was filled and will no longer be tracked" %
                        order_id)
                    fill_order(order_id, recent_orders[order_id]['quantity'],
                               recent_orders[order_id]['closeTime'])
                else:
                    log.info("Order %s completed with an error state" %
                             order_id)
                    if order_id in order_ids:
                        order_ids.remove(order_id)

            if completed:
                log.info("All orders are closed.")
                break
            else:
                log.info(
                    "One or more orders are still being processed. Sleeping for 1 minute"
                )
                time.sleep(60)

        if len(order_ids) == 0:
            log.info("All securities were succefully [%s] traded" % action)
            return True
        else:
            log.info("%d security could not be [%s] traded" %
                     (len(order_ids), action))
            return False