"""Contains information in regards to stocks."""
from functools import lru_cache as cache
from robin_stocks.robinhood.helper import *
from robin_stocks.robinhood.urls import *
[docs]def get_quotes(inputSymbols, info=None):
"""Takes any number of stock tickers and returns information pertaining to its price.
:param inputSymbols: May be a single stock ticker or a list of stock tickers.
:type inputSymbols: str or list
:param info: Will filter the results to have a list of the values that correspond to key that matches info.
:type info: Optional[str]
:returns: [list] If info parameter is left as None then the list will contain a dictionary of key/value pairs for each ticker. \
Otherwise, it will be a list of strings where the strings are the values of the key that corresponds to info.
:Dictionary Keys: * ask_price
* ask_size
* bid_price
* bid_size
* last_trade_price
* last_extended_hours_trade_price
* previous_close
* adjusted_previous_close
* previous_close_date
* symbol
* trading_halted
* has_traded
* last_trade_price_source
* updated_at
* instrument
"""
symbols = inputs_to_set(inputSymbols)
url = quotes_url()
payload = {'symbols': ','.join(symbols)}
data = request_get(url, 'results', payload)
if (data == None or data == [None]):
return data
for count, item in enumerate(data):
if item is None:
print(error_ticker_does_not_exist(symbols[count]), file=get_output())
data = [item for item in data if item is not None]
return(filter_data(data, info))
[docs]def get_fundamentals(inputSymbols, info=None):
"""Takes any number of stock tickers and returns fundamental information
about the stock such as what sector it is in, a description of the company, dividend yield, and market cap.
:param inputSymbols: May be a single stock ticker or a list of stock tickers.
:type inputSymbols: str or list
:param info: Will filter the results to have a list of the values that correspond to key that matches info.
:type info: Optional[str]
:returns: [list] If info parameter is left as None then the list will contain a dictionary of key/value pairs for each ticker. \
Otherwise, it will be a list of strings where the strings are the values of the key that corresponds to info.
:Dictionary Keys: * open
* high
* low
* volume
* average_volume_2_weeks
* average_volume
* high_52_weeks
* dividend_yield
* float
* low_52_weeks
* market_cap
* pb_ratio
* pe_ratio
* shares_outstanding
* description
* instrument
* ceo
* headquarters_city
* headquarters_state
* sector
* industry
* num_employees
* year_founded
* symbol
"""
symbols = inputs_to_set(inputSymbols)
url = fundamentals_url()
payload = {'symbols': ','.join(symbols)}
data = request_get(url, 'results', payload)
if (data == None or data == [None]):
return data
for count, item in enumerate(data):
if item is None:
print(error_ticker_does_not_exist(symbols[count]), file=get_output())
else:
item['symbol'] = symbols[count]
data = [item for item in data if item is not None]
return(filter_data(data, info))
[docs]def get_instruments_by_symbols(inputSymbols, info=None):
"""Takes any number of stock tickers and returns information held by the market
such as ticker name, bloomberg id, and listing date.
:param inputSymbols: May be a single stock ticker or a list of stock tickers.
:type inputSymbols: str or list
:param info: Will filter the results to have a list of the values that correspond to key that matches info.
:type info: Optional[str]
:returns: [list] If info parameter is left as None then the list will a dictionary of key/value pairs for each ticker. \
Otherwise, it will be a list of strings where the strings are the values of the key that corresponds to info.
:Dictionary Keys: * id
* url
* quote
* fundamentals
* splits
* state
* market
* simple_name
* name
* tradeable
* tradability
* symbol
* bloomberg_unique
* margin_initial_ratio
* maintenance_ratio
* country
* day_trade_ratio
* list_date
* min_tick_size
* type
* tradable_chain_id
* rhs_tradability
* fractional_tradability
* default_collar_fraction
"""
symbols = inputs_to_set(inputSymbols)
url = instruments_url()
data = []
for item in symbols:
payload = {'symbol': item}
itemData = request_get(url, 'indexzero', payload)
if itemData:
data.append(itemData)
else:
print(error_ticker_does_not_exist(item), file=get_output())
return(filter_data(data, info))
[docs]def get_instrument_by_url(url, info=None):
"""Takes a single url for the stock. Should be located at ``https://api.robinhood.com/instruments/<id>`` where <id> is the
id of the stock.
:param url: The url of the stock. Can be found in several locations including \
in the dictionary returned from get_instruments_by_symbols(inputSymbols,info=None)
:type url: str
:param info: Will filter the results to have a list of the values that correspond to key that matches info.
:type info: Optional[str]
:returns: [dict or str] If info parameter is left as None then will return a dictionary of key/value pairs for a specific url. \
Otherwise, it will be the string value of the key that corresponds to info.
:Dictionary Keys: * id
* url
* quote
* fundamentals
* splits
* state
* market
* simple_name
* name
* tradeable
* tradability
* symbol
* bloomberg_unique
* margin_initial_ratio
* maintenance_ratio
* country
* day_trade_ratio
* list_date
* min_tick_size
* type
* tradable_chain_id
* rhs_tradability
* fractional_tradability
* default_collar_fraction
"""
data = request_get(url, 'regular')
return(filter_data(data, info))
[docs]def get_latest_price(inputSymbols, priceType=None, includeExtendedHours=True):
"""Takes any number of stock tickers and returns the latest price of each one as a string.
:param inputSymbols: May be a single stock ticker or a list of stock tickers.
:type inputSymbols: str or list
:param priceType: Can either be 'ask_price' or 'bid_price'. If this parameter is set, then includeExtendedHours is ignored.
:type priceType: str
:param includeExtendedHours: Leave as True if you want to get extendedhours price if available. \
False if you only want regular hours price, even after hours.
:type includeExtendedHours: bool
:returns: [list] A list of prices as strings.
"""
symbols = inputs_to_set(inputSymbols)
quote = get_quotes(symbols)
prices = []
for item in quote:
if item:
if priceType == 'ask_price':
prices.append(item['ask_price'])
elif priceType == 'bid_price':
prices.append(item['bid_price'])
else:
if priceType:
print('WARNING: priceType should be "ask_price" or "bid_price". You entered "{0}"'.format(priceType), file=get_output())
if item['last_extended_hours_trade_price'] is None or not includeExtendedHours:
prices.append(item['last_trade_price'])
else:
prices.append(item['last_extended_hours_trade_price'])
else:
prices.append(None)
return(prices)
[docs]@cache
@convert_none_to_string
def get_name_by_symbol(symbol):
"""Returns the name of a stock from the stock ticker.
:param symbol: The ticker of the stock as a string.
:type symbol: str
:returns: [str] Returns the simple name of the stock. If the simple name does not exist then returns the full name.
"""
try:
symbol = symbol.upper().strip()
except AttributeError as message:
print(message, file=get_output())
return None
url = instruments_url()
payload = {'symbol': symbol}
data = request_get(url, 'indexzero', payload)
if not data:
return(None)
# If stock doesn't have a simple name attribute then get the full name.
filter = filter_data(data, info='simple_name')
if not filter or filter == "":
filter = filter_data(data, info='name')
return(filter)
[docs]@cache
@convert_none_to_string
def get_name_by_url(url):
"""Returns the name of a stock from the instrument url. Should be located at ``https://api.robinhood.com/instruments/<id>``
where <id> is the id of the stock.
:param url: The url of the stock as a string.
:type url: str
:returns: [str] Returns the simple name of the stock. If the simple name does not exist then returns the full name.
"""
data = request_get(url)
if not data:
return(None)
# If stock doesn't have a simple name attribute then get the full name.
filter = filter_data(data, info='simple_name')
if not filter or filter == "":
filter = filter_data(data, info='name')
return(filter)
[docs]@cache
@convert_none_to_string
def get_symbol_by_url(url):
"""Returns the symbol of a stock from the instrument url. Should be located at ``https://api.robinhood.com/instruments/<id>``
where <id> is the id of the stock.
:param url: The url of the stock as a string.
:type url: str
:returns: [str] Returns the ticker symbol of the stock.
"""
data = request_get(url)
return filter_data(data, info='symbol')
[docs]@convert_none_to_string
def get_ratings(symbol, info=None):
"""Returns the ratings for a stock, including the number of buy, hold, and sell ratings.
:param symbol: The stock ticker.
:type symbol: str
:param info: Will filter the results to contain a dictionary of values that correspond to the key that matches info. \
Possible values are summary, ratings, and instrument_id
:type info: Optional[str]
:returns: [dict] If info parameter is left as None then the list will contain a dictionary of key/value pairs for each ticker. \
Otherwise, it will contain the values that correspond to the keyword that matches info.
:Dictionary Keys: * summary - value is a dictionary
* ratings - value is a list of dictionaries
* instrument_id - value is a string
* ratings_published_at - value is a string
"""
try:
symbol = symbol.upper().strip()
except AttributeError as message:
print(message, file=get_output())
return None
url = ratings_url(symbol)
data = request_get(url)
if not data:
return(data)
if (len(data['ratings']) == 0):
return(data)
else:
for item in data['ratings']:
oldText = item['text']
item['text'] = oldText.encode('UTF-8')
return(filter_data(data, info))
[docs]def get_events(symbol, info=None):
"""Returns the events related to a stock that the user owns. For example, if you owned options for USO and that stock \
underwent a stock split resulting in you owning shares of newly created USO1, then that event will be returned when calling \
get_events('uso1')
:param symbol: The stock ticker.
:type symbol: str
:param info: Will filter the results to get a specific value.
:type info: Optional[str]
:returns: [list] If the info parameter is provided, then the function will extract the value of the key \
that matches the info parameter. Otherwise, the whole dictionary is returned.
:Dictionary Keys: * account
* cash_component
* chain_id
* created_at
* direction
* equity_components
* event_date
* id
* option
* position
* quantity
* state
* total_cash_amount
* type
* underlying_price
* updated_at
"""
try:
symbol = symbol.upper().strip()
except AttributeError as message:
print(message, file=get_output())
return None
payload = {'equity_instrument_id': id_for_stock(symbol)}
url = events_url()
data = request_get(url, 'results', payload)
return(filter_data(data, info))
[docs]def get_earnings(symbol, info=None):
"""Returns the earnings for the different financial quarters.
:param symbol: The stock ticker.
:type symbol: str
:param info: Will filter the results to get a specific value.
:type info: Optional[str]
:returns: [list] Returns a list of dictionaries. If info parameter is provided, \
a list of strings is returned where the strings are the value \
of the key that matches info.
:Dictionary Keys: * symbol
* instrument
* year
* quarter
* eps
* report
* call
"""
try:
symbol = symbol.upper().strip()
except AttributeError as message:
print(message, file=get_output())
return None
url = earnings_url()
payload = {'symbol': symbol}
data = request_get(url, 'results', payload)
return(filter_data(data, info))
[docs]def get_news(symbol, info=None):
"""Returns news stories for a stock.
:param symbol: The stock ticker.
:type symbol: str
:param info: Will filter the results to get a specific value.
:type info: Optional[str]
:returns: [list] Returns a list of dictionaries. If info parameter is provided, \
a list of strings is returned where the strings are the value \
of the key that matches info.
:Dictionary Keys: * api_source
* author
* num_clicks
* preview_image_url
* published_at
* relay_url
* source
* summary
* title
* updated_at
* url
* uuid
* related_instruments
* preview_text
* currency_id
"""
try:
symbol = symbol.upper().strip()
except AttributeError as message:
print(message, file=get_output())
return None
url = news_url(symbol)
data = request_get(url, 'results')
return(filter_data(data, info))
[docs]def get_splits(symbol, info=None):
"""Returns the date, divisor, and multiplier for when a stock split occureed.
:param symbol: The stock ticker.
:type symbol: str
:param info: Will filter the results to get a specific value. Possible options are \
url, instrument, execution_date, divsor, and multiplier.
:type info: Optional[str]
:returns: [list] Returns a list of dictionaries. If info parameter is provided, \
a list of strings is returned where the strings are the value \
of the key that matches info.
:Dictionary Keys: * url
* instrument
* execution_date
* multiplier
* divisor
"""
try:
symbol = symbol.upper().strip()
except AttributeError as message:
print(message, file=get_output())
return None
url = splits_url(symbol)
data = request_get(url, 'results')
return(filter_data(data, info))
[docs]def find_instrument_data(query):
"""Will search for stocks that contain the query keyword and return the instrument data.
:param query: The keyword to search for.
:type query: str
:returns: [list] Returns a list of dictionaries that contain the instrument data for each stock that matches the query.
:Dictionary Keys: * id
* url
* quote
* fundamentals
* splits
* state
* market
* simple_name
* name
* tradeable
* tradability
* symbol
* bloomberg_unique
* margin_initial_ratio
* maintenance_ratio
* country
* day_trade_ratio
* list_date
* min_tick_size
* type
* tradable_chain_id
* rhs_tradability
* fractional_tradability
* default_collar_fraction
"""
url = instruments_url()
payload = {'query': query}
data = request_get(url, 'pagination', payload)
if len(data) == 0:
print('No results found for that keyword', file=get_output())
return([None])
else:
print('Found ' + str(len(data)) + ' results', file=get_output())
return(data)
[docs]def get_stock_historicals(inputSymbols, interval='hour', span='week', bounds='regular', info=None):
"""Represents the historicl data for a stock.
:param inputSymbols: May be a single stock ticker or a list of stock tickers.
:type inputSymbols: str or list
:param interval: Interval to retrieve data for. Values are '5minute', '10minute', 'hour', 'day', 'week'. Default is 'hour'.
:type interval: Optional[str]
:param span: Sets the range of the data to be either 'day', 'week', 'month', '3month', 'year', or '5year'. Default is 'week'.
:type span: Optional[str]
:param bounds: Represents if graph will include extended trading hours or just regular trading hours. Values are 'extended', 'trading', or 'regular'. Default is 'regular'
:type bounds: Optional[str]
:param info: Will filter the results to have a list of the values that correspond to key that matches info.
:type info: Optional[str]
:returns: [list] Returns a list of dictionaries where each dictionary is for a different time. If multiple stocks are provided \
the historical data is listed one after another.
:Dictionary Keys: * begins_at
* open_price
* close_price
* high_price
* low_price
* volume
* session
* interpolated
* symbol
"""
interval_check = ['5minute', '10minute', 'hour', 'day', 'week']
span_check = ['day', 'week', 'month', '3month', 'year', '5year']
bounds_check = ['extended', 'regular', 'trading']
if interval not in interval_check:
print(
'ERROR: Interval must be "5minute","10minute","hour","day",or "week"', file=get_output())
return([None])
if span not in span_check:
print('ERROR: Span must be "day","week","month","3month","year",or "5year"', file=get_output())
return([None])
if bounds not in bounds_check:
print('ERROR: Bounds must be "extended","regular",or "trading"', file=get_output())
return([None])
if (bounds == 'extended' or bounds == 'trading') and span != 'day':
print('ERROR: extended and trading bounds can only be used with a span of "day"', file=get_output())
return([None])
symbols = inputs_to_set(inputSymbols)
url = historicals_url()
payload = {'symbols': ','.join(symbols),
'interval': interval,
'span': span,
'bounds': bounds}
data = request_get(url, 'results', payload)
if (data == None or data == [None]):
return data
histData = []
for count, item in enumerate(data):
if (len(item['historicals']) == 0):
print(error_ticker_does_not_exist(symbols[count]), file=get_output())
continue
stockSymbol = item['symbol']
for subitem in item['historicals']:
subitem['symbol'] = stockSymbol
histData.append(subitem)
return(filter_data(histData, info))
[docs]def get_stock_quote_by_id(stock_id, info=None):
"""
Represents basic stock quote information
:param stock_id: robinhood stock id
:type stock_id: str
:param info: Will filter the results to get a specific value. Possible options are url, instrument, execution_date, \
divsor, and multiplier.
:type info: Optional[str]
:return: [dict] If the info parameter is provided, then the function will extract the value of the key \
that matches the info parameter. Otherwise, the whole dictionary is returned.
:Dictionary Keys: * ask_price
* ask_size
* bid_price
* bid_size
* last_trade_price
* last_extended_hours_trade_price
* previous_close
* adjusted_previous_close
* previous_close_date
* symbol
* trading_halted
* has_traded
* last_trade_price_source
* updated_at
* instrument
"""
url = marketdata_quotes_url(stock_id)
data = request_get(url)
return (filter_data(data, info))
[docs]def get_stock_quote_by_symbol(symbol, info=None):
"""
Represents basic stock quote information
:param symbol: robinhood stock id
:type stock_id: str
:param info: Will filter the results to get a specific value. Possible options are url, instrument, execution_date, \
divsor, and multiplier.
:type info: Optional[str]
:return: [dict] If the info parameter is provided, then the function will extract the value of the key \
that matches the info parameter. Otherwise, the whole dictionary is returned.
:Dictionary Keys: * ask_price
* ask_size
* bid_price
* bid_size
* last_trade_price
* last_extended_hours_trade_price
* previous_close
* adjusted_previous_close
* previous_close_date
* symbol
* trading_halted
* has_traded
* last_trade_price_source
* updated_at
* instrument
"""
return get_stock_quote_by_id(id_for_stock(symbol))
[docs]def get_pricebook_by_id(stock_id, info=None):
"""
Represents Level II Market Data provided for Gold subscribers
:param stock_id: robinhood stock id
:type stock_id: str
:param info: Will filter the results to get a specific value. Possible options are url, instrument, execution_date, \
divsor, and multiplier.
:type info: Optional[str]
:return: Returns a dictionary of asks and bids.
"""
url = marketdata_pricebook_url(stock_id)
data = request_get(url)
return (filter_data(data, info))
[docs]def get_pricebook_by_symbol(symbol, info=None):
"""
Represents Level II Market Data provided for Gold subscribers
:param symbol: symbol id
:type symbol: str
:param info: Will filter the results to get a specific value. Possible options are url, instrument, execution_date, \
divsor, and multiplier.
:type info: Optional[str]
:return: Returns a dictionary of asks and bids.
"""
return get_pricebook_by_id(id_for_stock(symbol))