The e-trade people provided some sample API code which provides a working example of fetching a portfolio, which I implemented, and which met my needs, until I owned >50 stocks, then suddenly I started noticing incomplete portfolio retrievals.
How can I get more than 50 stocks at a time?
This is a pagination issue.
Their API documentation describes a "count" parameter that lets you increase the page size:
https://apisb.etrade.com/docs/api/account/api-portfolio-v1.html
I simply want to increase it to 60 so I can get my complete portfolio, but for the life of me, adding "?count=60" to the URL gives me a Response [401]
and 0 portfolio info at all.
Any idea what I'm doing wrong?
def portfolio(self):
"""
Call portfolio API to retrieve a list of positions held in the specified account
:param self: Passes in parameter authenticated session and information on selected account
"""
# URL for the API endpoint
url =self.base_url + "/v1/accounts/" + self.account["accountIdKey"] + "/portfolio.json"
**#url += "?count=60" This failed miserably!**
# Make API call for GET request
response = self.session.get(url, header_auth=True)
logger.debug("Request Header: %s", response.request.headers)
print("\nPortfolio:")
# Handle and parse response
if response is not None and response.status_code == 200:
parsed = json.loads(response.text)
logger.debug("Response Body: %s", json.dumps(parsed, indent=4, sort_keys=True))
data = response.json()
if data is not None and "PortfolioResponse" in data and "AccountPortfolio" in data["PortfolioResponse"]:
# Display balance information
for acctPortfolio in data["PortfolioResponse"]["AccountPortfolio"]:
if acctPortfolio is not None and "Position" in acctPortfolio:
for position in acctPortfolio["Position"]:
print_str = ""
if position is not None and "symbolDescription" in position:
print_str = print_str + "Symbol: " + str(position["symbolDescription"])
if position is not None and "quantity" in position:
print_str = print_str + " | " + "Quantity #: " + str(position["quantity"])
if position is not None and "Quick" in position and "lastTrade" in position["Quick"]:
print_str = print_str + " | " + "Last Price: " \
+ str('${:,.2f}'.format(position["Quick"]["lastTrade"]))
if position is not None and "pricePaid" in position:
print_str = print_str + " | " + "Price Paid $: " \
+ str('${:,.2f}'.format(position["pricePaid"]))
if position is not None and "totalGain" in position:
print_str = print_str + " | " + "Total Gain $: " \
+ str('${:,.2f}'.format(position["totalGain"]))
if position is not None and "marketValue" in position:
print_str = print_str + " | " + "Value $: " \
+ str('${:,.2f}'.format(position["marketValue"]))
print(print_str)
else:
print("None")
else:
# Handle errors
logger.debug("Response Body: %s", response.text)
if response is not None and "headers" in response and "Content-Type" in response.headers \
and response.headers['Content-Type'] == 'application/json' \
and "Error" in response.json() and "message" in response.json()["Error"] \
and response.json()["Error"]["message"] is not None:
print("Error: " + response.json()["Error"]["message"])
else:
print("Error: Portfolio API service error")
elif response is not None and response.status_code == 204:
print("None")
else:
# Handle errors
logger.debug("Response Body: %s", response.text)
if response is not None and "headers" in response and "Content-Type" in response.headers \
and response.headers['Content-Type'] == 'application/json' \
and "Error" in response.json() and "message" in response.json()["Error"] \
and response.json()["Error"]["message"] is not None:
print("Error: " + response.json()["Error"]["message"])
else:
print("Error: Portfolio API service error")