Beispiel #1
0
def request(method: str, url: str, params: dict, payload: dict):
    '''
        Value add wrapper around the "request" method. Add auth header, timeout,
        and throws an exception if the response is not valid

        Parameters
        ----------
        method : str
            the HTTP method (GET, PUT, etc) of the request
        url : str
            URL of the API
        params : dict
            request parameters
        payload : dict
            request payload (data)
    '''
    try:
        api_response = requests.request(method,
                                        url,
                                        params=params,
                                        json=payload,
                                        headers=auth_header(),
                                        timeout=REQUEST_TIMEOUT)
    except Exception as e:
        raise TradeError("Could not execute %s to %s" % (method, url), e, None)

    __validate_response(url, api_response)

    try:
        body = api_response.json()
        log.debug("API Response: %s" % util.format_dict(body))
        return (api_response.headers, body)
    except:
        log.debug("API Response: None")
        return (api_response.headers, {})
Beispiel #2
0
def login():
    '''
        Calls the https://api.tdameritrade.com/v1/oauth2/token Api and
        requests a temporary access token, effectively logging into TDAmeritrade
    '''
    (td_account_id, td_client_id, td_refresh_token) = get_credentials()

    auth_url = 'https://api.tdameritrade.com/v1/oauth2/token'

    log.info("Generating TDAmeritrade refresh token")
    try:
        creds_response = requests.post(auth_url,
                                       data={
                                           'grant_type':
                                           'refresh_token',
                                           'refresh_token':
                                           td_refresh_token,
                                           'client_id':
                                           '*****@*****.**' % td_client_id
                                       },
                                       timeout=REQUEST_TIMEOUT)
    except Exception as e:
        raise TradeError("Could not execute POST to %s" % auth_url, e, None)

    __validate_response(auth_url, creds_response)

    global TD_ACCESS_TOKEN
    TD_ACCESS_TOKEN = creds_response.json()['access_token']
Beispiel #3
0
    def test_trade_buy_multiple_securities_with_exception(self):

        buy_positions = [('BA', 1.0), ('GE', 1.0), ('XOM', 1.0)]

        # portfolio has 3 positions
        portfolio = deepcopy(self.base_portfolio)

        portfolio = Portfolio.from_dict(portfolio)

        with patch.object(td_ameritrade, 'place_order', side_effect=[
                'order-1', 'order-2', TradeError("Some Error", None, None)]), \
                patch.object(td_ameritrade, 'list_recent_orders', return_value={
                    "order-1": {
                        "status": "FILLED",
                        "symbol": "BA",
                        "quantity": 1,
                        "closeTime": "2020-05-04T03:21:04+0000",
                        "tag": "AA_myuser"
                    },
                    "order-2": {
                        "status": "FILLED",
                        "symbol": "GE",
                        "quantity": 1,
                        "closeTime": "2020-05-04T03:21:04+0000",
                        "tag": "AA_myuser"
                    }
                }):

            broker = Broker()
            self.assertFalse(broker.trade('BUY', buy_positions, portfolio))
Beispiel #4
0
    def test_test_tdameritrade_connectivity_with_exception(self):
        with patch.object(td_ameritrade,
                          'equity_market_open',
                          side_effect=TradeError("Some Error", None, None)):

            with self.assertRaises(TradeError):
                connector_test.test_tdameritrade_connectivity()
Beispiel #5
0
    def materialize_portfolio(self, broker_positions: dict, portfolio: object):
        '''
            Materializes the porfolio by executing the trades necessary to do so.
            Specifically:

            1) Sell all securities not in the portfolio
            2) Buy all existing securities not already owned
        '''

        (sell_trades, buy_trades) = self._generate_trade_instructions(
            broker_positions, portfolio)

        if len(sell_trades) > 0:
            if (self.trade('SELL', sell_trades, None) == False):
                log.warning(
                    "There was error unwinding positions. Portfolio could not be materialized"
                )
                raise TradeError(
                    "Could not unwind (sell) all positions from portfolio",
                    None, None)
        '''
            Get the cash available for trading and split it evenly acorss all securities
            to be bought.
        '''
        if len(buy_trades) > 0:
            current_broker_positions = td_ameritrade.positions_summary()
            try:
                available_cash = current_broker_positions['cash'][
                    'cashAvailableForTrading']
            except KeyError:
                available_cash = 0

            # trade 90% of available cash
            trade_dollar_amount = (available_cash / len(buy_trades)) * 0.9

            buy_instructions = []
            for buy_ticker in buy_trades:
                latest_price = td_ameritrade.get_latest_equity_price(
                    buy_ticker)

                shares = int(trade_dollar_amount / latest_price)

                if shares > 0:
                    buy_instructions.append((buy_ticker, shares))
                else:
                    log.warning(
                        "Will not purchase %s, because there aren't enough funds"
                        % buy_ticker)

            if len(buy_instructions) == 0:
                log.warning("Could not afford to purchase any securities")
                return

            if self.trade('BUY', buy_instructions, portfolio) == False:
                log.warning(
                    "There was an error adding positions to the portoflio. Portfolio could not be materialized"
                )
        else:
            log.info("There are no securities to buy")
Beispiel #6
0
    def test_get_latest_equity_price_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.get_latest_equity_price("SPY")
Beispiel #7
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")
Beispiel #8
0
def __validate_response(url: str, response: object):
    '''
        validates a request's status code and throws a TradeError
        if not a 200 or 201
    '''
    if not response.ok:
        raise TradeError(
            "Invalid response while calling %s: %s" % (url, response.text),
            None, response)
    def test_trade_error_with_api_response(self):

        response = Response()
        response.reason = "Server Error"
        response.status_code = 500

        trade_error = TradeError("Some Error", None, response)

        self.assertEqual(str(trade_error),
                         "Trade Error (500) [Server Error]: Some Error")
Beispiel #10
0
def test_tdameritrade_connectivity():
    '''
        Makes a direct call to the intrio API (bypassing the cache) to verify the API
        key is still valid
    '''
    log.info("Testing TDAmeritrade connectivity")
    try:
        td_ameritrade.equity_market_open(datetime.now())
        log.info("TDAmeritrade connectivity test successful")
    except TradeError as de:
        raise TradeError("TDAmeritrade Connectivity Test failed", de.cause,
                         None)
Beispiel #11
0
    def test_cancel_all_open_orders_with_exception(self):
        '''
            Test that given a list of orders, some cancelable, some not,
            that only the cancelable ones are being considered
        '''
        with patch.object(td_ameritrade, 'cancel_order', side_effect=TradeError("SomeError", None, None)), \
                patch.object(td_ameritrade, 'list_recent_orders', return_value={
                    "order-1": {
                        "status": "FILLED",
                        "symbol": "BA",
                        "quantity": 1,
                        "closeTime": "2020-05-04T03:21:04+0000",
                        "tag": "AA_myuser",
                        "cancelable": True
                    }
                }):

            broker = Broker()
            broker.cancel_all_open_orders()
    def test_trade_error_without_api_response(self):

        trade_error = TradeError("Some Error", None, None)

        self.assertEqual(str(trade_error), "Trade Error: Some Error")