Ejemplo n.º 1
0
def get_top_movers_sp500(direction, info=None):
    """Returns a list of the top S&P500 movers up or down for the day.

    :param direction: The direction of movement either 'up' or 'down'
    :type direction: str
    :param info: Will filter the results to get a specific value.
    :type info: Optional[str]
    :returns: Returns a list of dictionaries of key/value pairs for each mover. 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: * instrument_url
                      * symbol
                      * updated_at
                      * price_movement
                      * description

    """
    try:
        direction = direction.lower().strip()
    except AttributeError as message:
        print(message, file=helper.get_output())
        return None

    if (direction != 'up' and direction != 'down'):
        print('Error: direction must be "up" or "down"',
              file=helper.get_output())
        return ([None])

    url = urls.movers_sp500()
    payload = {'direction': direction}
    data = helper.request_get(url, 'pagination', payload)

    return (helper.filter(data, info))
Ejemplo n.º 2
0
def download_all_documents(doctype=None, dirpath=None):
    """Downloads all the documents associated with an account and saves them as a PDF.
    If no name is given, document is saved as a combination of the data of creation, type, and id.
    If no directory is given, document is saved in the root directory of code.

    :param doctype: The type of document to download, such as account_statement.
    :type doctype: Optional[str]
    :param dirpath: The directory of where to save the documents.
    :type dirpath: Optional[str]
    :returns: Returns the list of documents from get_documents(info=None)

    """
    documents = get_documents()

    downloaded_files = False
    if dirpath:
        directory = dirpath
    else:
        directory = 'robin_documents/'

    counter = 0
    for item in documents:
        if doctype == None:
            data = helper.request_document(item['download_url'])
            if data:
                name = item['created_at'][0:10] + '-' + \
                    item['type'] + '-' + item['id']
                filename = directory + name + '.pdf'
                os.makedirs(os.path.dirname(filename), exist_ok=True)
                open(filename, 'wb').write(data.content)
                downloaded_files = True
                counter += 1
                print('Writing PDF {}...'.format(counter), file=helper.get_output())
        else:
            if item['type'] == doctype:
                data = helper.request_document(item['download_url'])
                if data:
                    name = item['created_at'][0:10] + '-' + \
                        item['type'] + '-' + item['id']
                    filename = directory + name + '.pdf'
                    os.makedirs(os.path.dirname(filename), exist_ok=True)
                    open(filename, 'wb').write(data.content)
                    downloaded_files = True
                    counter += 1
                    print('Writing PDF {}...'.format(counter), file=helper.get_output())

    if downloaded_files == False:
        print('WARNING: Could not find files of that doctype to download', file=helper.get_output())
    else:
        if counter == 1:
            print('Done - wrote {} file to {}'.format(counter,
                                                      os.path.abspath(directory)), file=helper.get_output())
        else:
            print('Done - wrote {} files to {}'.format(counter,
                                                       os.path.abspath(directory)), file=helper.get_output())

    return(documents)
Ejemplo n.º 3
0
def find_tradable_options(symbol,
                          expirationDate=None,
                          strikePrice=None,
                          optionType=None,
                          info=None):
    """Returns a list of all available options for a stock.

    :param symbol: The ticker of the stock.
    :type symbol: str
    :param expirationDate: Represents the expiration date in the format YYYY-MM-DD.
    :type expirationDate: str
    :param strikePrice: Represents the strike price of the option.
    :type strikePrice: str
    :param optionType: Can be either 'call' or 'put' or left blank to get both.
    :type optionType: Optional[str]
    :param info: Will filter the results to get a specific value.
    :type info: Optional[str]
    :returns: Returns a list of dictionaries of key/value pairs for all calls of the stock. If info parameter is provided, \
    a list of strings is returned where the strings are the value of the key that matches info.

    """
    try:
        symbol = symbol.upper().strip()
    except AttributeError as message:
        print(message, file=helper.get_output())
        return [None]

    url = urls.option_instruments()
    if not helper.id_for_chain(symbol):
        print("Symbol {} is not valid for finding options.".format(symbol),
              file=helper.get_output())
        return [None]

    payload = {
        'chain_id': helper.id_for_chain(symbol),
        'chain_symbol': symbol,
        'state': 'active'
    }

    if expirationDate:
        payload['expiration_dates'] = expirationDate
    if strikePrice:
        payload['strike_price'] = strikePrice
    if optionType:
        payload['type'] = optionType

    data = helper.request_get(url, 'pagination', payload)
    return (helper.filter_data(data, info))
Ejemplo n.º 4
0
def get_option_instrument_data(symbol, expirationDate, strikePrice, optionType, info=None):
    """Returns the option instrument data for the stock option.

    :param symbol: The ticker of the stock.
    :type symbol: str
    :param expirationDate: Represents the expiration date in the format YYYY-MM-DD.
    :type expirationDate: str
    :param strikePrice: Represents the price of the option.
    :type strikePrice: str
    :param optionType: Can be either 'call' or 'put'.
    :type optionType: str
    :param info: Will filter the results to get a specific value.
    :type info: Optional[str]
    :returns: Returns a dictionary of key/value pairs for the stock. \
    If info parameter is provided, the value of the key that matches info is extracted.

    """
    try:
        symbol = symbol.upper().strip()
        optionType = optionType.lower().strip()
    except AttributeError as message:
        print(message, file=helper.get_output())
        return [None]

    optionID = helper.id_for_option(symbol, expirationDate, strikePrice, optionType)
    url = urls.option_instruments(optionID)
    data = helper.request_get(url)

    return(helper.filter(data, info))
Ejemplo n.º 5
0
def get_option_market_data(inputSymbols, expirationDate, strikePrice, optionType, info=None):
    """Returns the option market data for the stock option, including the greeks,
    open interest, change of profit, and adjusted mark price.

    :param inputSymbols: The ticker of the stock.
    :type inputSymbols: str
    :param expirationDate: Represents the expiration date in the format YYYY-MM-DD.
    :type expirationDate: str
    :param strikePrice: Represents the price of the option.
    :type strikePrice: str
    :param optionType: Can be either 'call' or 'put'.
    :type optionType: str
    :param info: Will filter the results to get a specific value.
    :type info: Optional[str]
    :returns: Returns a dictionary of key/value pairs for the stock. \
    If info parameter is provided, the value of the key that matches info is extracted.

    """
    try:
        symbols = helper.inputs_to_set(inputSymbols)
        if optionType:
            optionType = optionType.lower().strip()
    except AttributeError as message:
        print(message, file=helper.get_output())
        return [None]

    data = []
    for symbol in symbols:
        optionID = helper.id_for_option(symbol, expirationDate, strikePrice, optionType)
        marketData = get_option_market_data_by_id(optionID)
        data.append(marketData)

    return(helper.filter(data, info))
Ejemplo n.º 6
0
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=helper.get_output())
        return None

    url = urls.earnings()
    payload = {'symbol': symbol}
    data = helper.request_get(url, 'results', payload)

    return (helper.filter(data, info))
Ejemplo n.º 7
0
def find_options_by_strike(inputSymbols, strikePrice, optionType=None, info=None):
    """Returns a list of all the option orders that match the seach parameters

    :param inputSymbols: The ticker of either a single stock or a list of stocks.
    :type inputSymbols: str
    :param strikePrice: Represents the strike price to filter for.
    :type strikePrice: str
    :param optionType: Can be either 'call' or 'put' or leave blank to get both.
    :type optionType: Optional[str]
    :param info: Will filter the results to get a specific value.
    :type info: Optional[str]
    :returns: Returns a list of dictionaries of key/value pairs for all options of the stock that match the search parameters. \
    If info parameter is provided, a list of strings is returned where the strings are the value of the key that matches info.

    """
    try:
        symbols = helper.inputs_to_set(inputSymbols)
        if optionType:
            optionType = optionType.lower().strip()
    except AttributeError as message:
        print(message, file=helper.get_output())
        return [None]

    data = []
    for symbol in symbols:
        filteredOptions = find_tradable_options(symbol, None, strikePrice, optionType, None)

        for item in filteredOptions:
            marketData = get_option_market_data_by_id(item['id'])
            item.update(marketData)
            write_spinner()

        data.extend(filteredOptions)

    return(helper.filter(data, info))
Ejemplo n.º 8
0
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=helper.get_output())
        return None

    url = urls.splits(symbol)
    data = helper.request_get(url, 'results')
    return (helper.filter(data, info))
Ejemplo n.º 9
0
def download_document(url, name=None, dirpath=None):
    """Downloads a document and saves as it as a PDF. If no name is given, document is saved as
    the name that Robinhood has for the document. If no directory is given, document is saved in the root directory of code.

    :param url: The url of the document. Can be found by using get_documents(info='download_url').
    :type url: str
    :param name: The name to save the document as.
    :type name: Optional[str]
    :param dirpath: The directory of where to save the document.
    :type dirpath: Optional[str]
    :returns: Returns the data from the get request.

    """
    data = helper.request_document(url)

    print('Writing PDF...', file=helper.get_output())
    if not name:
        name = url[36:].split('/', 1)[0]

    if dirpath:
        directory = dirpath
    else:
        directory = 'robin_documents/'

    filename = directory + name + ' .pdf'
    os.makedirs(os.path.dirname(filename), exist_ok=True)

    open(filename, 'wb').write(data.content)
    print('Done - Wrote file {}.pdf to {}'.format(name,
                                                  os.path.abspath(filename)))

    return (data)
Ejemplo n.º 10
0
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=helper.get_output())
        return None

    url = urls.ratings(symbol)
    data = helper.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 (helper.filter(data, info))
Ejemplo n.º 11
0
def write_spinner():
    """ Function to create a spinning cursor to tell user that the code is working on getting market data. """
    if helper.get_output()==sys.stdout:
        marketString = 'Loading Market Data '
        sys.stdout.write(marketString)
        sys.stdout.write(next(spinner))
        sys.stdout.flush()
        sys.stdout.write('\b'*(len(marketString)+1))
Ejemplo n.º 12
0
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 = urls.instruments()
    payload = {'query': query}

    data = helper.request_get(url, 'pagination', payload)

    if len(data) == 0:
        print('No results found for that keyword', file=helper.get_output())
        return ([None])
    else:
        print('Found ' + str(len(data)) + ' results', file=helper.get_output())
        return (data)
Ejemplo n.º 13
0
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 = helper.inputs_to_set(inputSymbols)
    url = urls.fundamentals()
    payload = {'symbols': ','.join(symbols)}
    data = helper.request_get(url, 'results', payload)

    if (data == None or data == [None]):
        return data

    for count, item in enumerate(data):
        if item is None:
            print(helper.error_ticker_does_not_exist(symbols[count]),
                  file=helper.get_output())
        else:
            item['symbol'] = symbols[count]

    data = [item for item in data if item is not None]

    return (helper.filter(data, info))
Ejemplo n.º 14
0
def get_historical_portfolio(interval=None,
                             span='week',
                             bounds='regular',
                             info=None):
    interval_check = ['5minute', '10minute', 'hour', 'day', 'week']
    span_check = ['day', 'week', 'month', '3month', 'year', '5year', 'all']
    bounds_check = ['extended', 'regular', 'trading']

    if interval not in interval_check:
        if interval is None and (bounds != 'regular' and span != 'all'):
            print(
                'ERROR: Interval must be None for "all" span "regular" bounds',
                file=helper.get_output())
            return ([None])
        print(
            'ERROR: Interval must be "5minute","10minute","hour","day",or "week"',
            file=helper.get_output())
        return ([None])
    if span not in span_check:
        print(
            'ERROR: Span must be "day","week","month","3month","year",or "5year"',
            file=helper.get_output())
        return ([None])
    if bounds not in bounds_check:
        print('ERROR: Bounds must be "extended","regular",or "trading"')
        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=helper.get_output())
        return ([None])

    account = profiles.load_account_profile('account_number')
    url = urls.portfolis_historicals(account)
    payload = {'interval': interval, 'span': span, 'bounds': bounds}
    data = helper.request_get(url, 'regular', payload)

    return (helper.filter(data, info))
Ejemplo n.º 15
0
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 = helper.inputs_to_set(inputSymbols)
    url = urls.instruments()
    data = []
    for item in symbols:
        payload = {'symbol': item}
        itemData = helper.request_get(url, 'indexzero', payload)

        if itemData:
            data.append(itemData)
        else:
            print(helper.error_ticker_does_not_exist(item),
                  file=helper.get_output())

    return (helper.filter(data, info))
Ejemplo n.º 16
0
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 = helper.inputs_to_set(inputSymbols)
    url = urls.quotes()
    payload = {'symbols': ','.join(symbols)}
    data = helper.request_get(url, 'results', payload)

    if (data == None or data == [None]):
        return data

    for count, item in enumerate(data):
        if item is None:
            print(helper.error_ticker_does_not_exist(symbols[count]),
                  file=helper.get_output())

    data = [item for item in data if item is not None]

    return (helper.filter(data, info))
Ejemplo n.º 17
0
def get_chains(symbol, info=None):
    """Returns the chain information of an option.

    :param symbol: The ticker of the stock.
    :type symbol: str
    :param info: Will filter the results to get a specific value.
    :type info: Optional[str]
    :returns: Returns a dictionary of key/value pairs for the option. If info parameter is provided, \
    a list of strings is returned where the strings are the value of the key that matches info.

    """
    try:
        symbol = symbol.upper().strip()
    except AttributeError as message:
        print(message, file=helper.get_output())
        return None

    url = urls.chains(symbol)
    data = helper.request_get(url)

    return(helper.filter(data, info))
Ejemplo n.º 18
0
def get_margin_calls(symbol=None):
    """Returns either all margin calls or margin calls for a specific stock.

    :param symbol: Will determine which stock to get margin calls for.
    :type symbol: Optional[str]
    :returns: Returns a list of dictionaries of key/value pairs for each margin call.

    """
    url = urls.margin()
    if symbol:
        try:
            symbol = symbol.upper().strip()
        except AttributeError as message:
            print(message, file=helper.get_output())
            return None
        payload = {'equity_instrument_id', helper.id_for_stock(symbol)}
        data = helper.request_get(url, 'results', payload)
    else:
        data = helper.request_get(url, 'results')

    return (data)
Ejemplo n.º 19
0
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=helper.get_output())
        return None

    payload = {'equity_instrument_id': helper.id_for_stock(symbol)}
    url = urls.events()
    data = helper.request_get(url, 'results', payload)

    return (helper.filter(data, info))
Ejemplo n.º 20
0
def get_all_stocks_from_market_tag(tag, info=None):
    """Returns all the stock quote information that matches a tag category.

    :param tag: The category to filter for. Examples include 'biopharmaceutical', 'upcoming-earnings', 'most-popular-under-25', and 'technology'.
    :type tag: str
    :param info: Will filter the results to get a specific value.
    :type info: Optional[str]
    :returns: Returns a list of dictionaries of key/value pairs for each mover. 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: * 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 = urls.market_category(tag)
    data = helper.request_get(url, 'regular')
    data = helper.filter(data, 'instruments')

    if not data:
        print('ERROR: "{}" is not a valid tag'.format(tag),
              file=helper.get_output())
        return [None]

    symbols = [stocks.get_symbol_by_url(x) for x in data]
    data = stocks.get_quotes(symbols)

    return (helper.filter(data, info))
Ejemplo n.º 21
0
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=helper.get_output())
        return None

    url = urls.news(symbol)
    data = helper.request_get(url, 'results')

    return (helper.filter(data, info))
Ejemplo n.º 22
0
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=helper.get_output())
        return None

    url = urls.instruments()
    payload = {'symbol': symbol}
    data = helper.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 = helper.filter(data, info='simple_name')
    if not filter or filter == "":
        filter = helper.filter(data, info='name')
    return (filter)
Ejemplo n.º 23
0
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 = helper.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=helper.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)
Ejemplo n.º 24
0
def find_options_by_specific_profitability(inputSymbols, expirationDate=None, strikePrice=None, optionType=None, typeProfit="chance_of_profit_short", profitFloor=0.0, profitCeiling=1.0, info=None):
    """Returns a list of option market data for several stock tickers that match a range of profitability.

    :param inputSymbols: May be a single stock ticker or a list of stock tickers.
    :type inputSymbols: str or list
    :param expirationDate: Represents the expiration date in the format YYYY-MM-DD. Leave as None to get all available dates.
    :type expirationDate: str
    :param strikePrice: Represents the price of the option. Leave as None to get all available strike prices.
    :type strikePrice: str
    :param optionType: Can be either 'call' or 'put' or leave blank to get both.
    :type optionType: Optional[str]
    :param typeProfit: Will either be "chance_of_profit_short" or "chance_of_profit_long".
    :type typeProfit: str
    :param profitFloor: The lower percentage on scale 0 to 1.
    :type profitFloor: int
    :param profitCeiling: The higher percentage on scale 0 to 1.
    :type profitCeiling: int
    :param info: Will filter the results to get a specific value.
    :type info: Optional[str]
    :returns: Returns a list of dictionaries of key/value pairs for all stock option market data. \
    If info parameter is provided, a list of strings is returned where the strings are the value of the key that matches info.

    """
    symbols = helper.inputs_to_set(inputSymbols)
    data = []

    if (typeProfit != "chance_of_profit_short" and typeProfit != "chance_of_profit_long"):
        print("Invalid string for 'typeProfit'. Defaulting to 'chance_of_profit_short'.", file=helper.get_output())
        typeProfit = "chance_of_profit_short"

    for symbol in symbols:
        tempData = find_tradable_options(symbol, expirationDate, strikePrice, optionType, info=None)
        for option in tempData:
            if expirationDate and option.get("expiration_date") != expirationDate:
                continue

            market_data = get_option_market_data_by_id(option['id'])
            option.update(market_data)
            write_spinner()

            try:
                floatValue = float(option[typeProfit])
                if (floatValue >= profitFloor and floatValue <= profitCeiling):
                    data.append(option)
            except:
                pass

    return(helper.filter(data, info))
Ejemplo n.º 25
0
def get_option_historicals(symbol, expirationDate, strikePrice, optionType, interval='hour', span='week', bounds='regular', info=None):
    """Returns the data that is used to make the graphs.

    :param symbol: The ticker of the stock.
    :type symbol: str
    :param expirationDate: Represents the expiration date in the format YYYY-MM-DD.
    :type expirationDate: str
    :param strikePrice: Represents the price of the option.
    :type strikePrice: str
    :param optionType: Can be either 'call' or 'put'.
    :type optionType: str
    :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', '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 'regular', 'trading', and 'extended'. \
    regular hours are 6 hours long, trading hours are 9 hours long, and extended hours are 16 hours long. 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: Returns a list that contains a list for each symbol. \
    Each list contains a dictionary where each dictionary is for a different time.

    """
    try:
        symbol = symbol.upper().strip()
        optionType = optionType.lower().strip()
    except AttributeError as message:
        print(message, file=helper.get_output())
        return [None]

    interval_check = ['5minute', '10minute', 'hour', 'day', 'week']
    span_check = ['day', 'week', '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=helper.get_output())
        return([None])
    if span not in span_check:
        print('ERROR: Span must be "day", "week", "year", or "5year"', file=helper.get_output())
        return([None])
    if bounds not in bounds_check:
        print('ERROR: Bounds must be "extended","regular",or "trading"', file=helper.get_output())
        return([None])

    optionID = helper.id_for_option(symbol, expirationDate, strikePrice, optionType)

    url = urls.option_historicals(optionID)
    payload = {'span': span,
               'interval': interval,
               'bounds': bounds}
    data = helper.request_get(url, 'regular', payload)
    if (data == None or data == [None]):
        return data

    histData = []
    for subitem in data['data_points']:
        subitem['symbol'] = symbol
        histData.append(subitem)

    return(helper.filter(histData, info))
Ejemplo n.º 26
0
def get_crypto_historicals(symbol,
                           interval='hour',
                           span='week',
                           bounds='24_7',
                           info=None):
    """Gets historical information about a crypto including open price, close price, high price, and low price.

    :param symbol: The crypto ticker.
    :type symbol: str
    :param interval: The time between data points. Can be '15second', '5minute', '10minute', 'hour', 'day', or 'week'. Default is 'hour'.
    :type interval: str
    :param span: The entire time frame to collect data points. Can be 'hour', 'day', 'week', 'month', '3month', 'year', or '5year'. Default is 'week'
    :type span: str
    :param bound: The times of day to collect data points. 'Regular' is 6 hours a day, 'trading' is 9 hours a day, \
    'extended' is 16 hours a day, '24_7' is 24 hours a day. Default is '24_7'
    :type bound: 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] 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: * begins_at
                      * open_price
                      * close_price
                      * high_price
                      * low_price
                      * volume
                      * session
                      * interpolated
                      * symbol

    """
    interval_check = ['15second', '5minute', '10minute', 'hour', 'day', 'week']
    span_check = ['hour', 'day', 'week', 'month', '3month', 'year', '5year']
    bounds_check = ['24_7', 'extended', 'regular', 'trading']

    if interval not in interval_check:
        print(
            'ERROR: Interval must be "15second","5minute","10minute","hour","day",or "week"',
            file=helper.get_output())
        return ([None])
    if span not in span_check:
        print(
            'ERROR: Span must be "hour","day","week","month","3month","year",or "5year"',
            file=helper.get_output())
        return ([None])
    if bounds not in bounds_check:
        print('ERROR: Bounds must be "24_7","extended","regular",or "trading"',
              file=helper.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=helper.get_output())
        return ([None])

    symbol = helper.inputs_to_set(symbol)
    id = get_crypto_info(symbol[0], info='id')
    url = urls.crypto_historical(id)
    payload = {'interval': interval, 'span': span, 'bounds': bounds}
    data = helper.request_get(url, 'regular', payload)

    histData = []
    cryptoSymbol = data['symbol']
    for subitem in data['data_points']:
        subitem['symbol'] = cryptoSymbol
        histData.append(subitem)

    return (helper.filter_data(histData, info))
Ejemplo n.º 27
0
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=helper.get_output())
        return ([None])
    if span not in span_check:
        print(
            'ERROR: Span must be "day","week","month","3month","year",or "5year"',
            file=helper.get_output())
        return ([None])
    if bounds not in bounds_check:
        print('ERROR: Bounds must be "extended","regular",or "trading"',
              file=helper.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=helper.get_output())
        return ([None])

    symbols = helper.inputs_to_set(inputSymbols)
    url = urls.historicals()
    payload = {
        'symbols': ','.join(symbols),
        'interval': interval,
        'span': span,
        'bounds': bounds
    }

    data = helper.request_get(url, 'results', payload)
    if (data == None or data == [None]):
        return data

    histData = []
    for count, item in enumerate(data):
        histData_single = []
        if (len(item['historicals']) == 0):
            print(helper.error_ticker_does_not_exist(symbols[count]),
                  file=helper.get_output())
            continue
        stockSymbol = item['symbol']
        for subitem in item['historicals']:
            subitem['symbol'] = stockSymbol
            histData_single.append(subitem)
        histData.append(histData_single)

    return (helper.filter(histData, info))
Ejemplo n.º 28
0
def login():
    """This function will effectively log the user into robinhood by getting an
    authentication token and saving it to the session header. By default, it
    will store the authentication token in a pickle file and load that value
    on subsequent logins.
    :param username: The username for your robinhood account, usually your email.
        Not required if credentials are already cached and valid.
    :type username: Optional[str]
    :param password: The password for your robinhood account. Not required if
        credentials are already cached and valid.
    :type password: Optional[str]
    :param expiresIn: The time until your login session expires. This is in seconds.
    :type expiresIn: Optional[int]
    :param scope: Specifies the scope of the authentication.
    :type scope: Optional[str]
    :param by_sms: Specifies whether to send an email(False) or an sms(True)
    :type by_sms: Optional[boolean]
    :param store_session: Specifies whether to save the log in authorization
        for future log ins.
    :type store_session: Optional[boolean]
    :param mfa_code: MFA token if enabled.
    :type mfa_code: Optional[str]
    :returns:  A dictionary with log in information. The 'access_token' keyword contains the access token, and the 'detail' keyword \
    contains information on whether the access token was generated or loaded from pickle file.
    """
    print('logging in')
    username = None
    password = None
    expiresIn = 86400
    scope = 'internal'
    by_sms = True
    store_session = True
    mfa_code = None

    device_token = generate_device_token()
    # home_dir = path if path else os.path.expanduser("~")
    home_dir = os.path.expanduser("~")
    data_dir = os.path.join(home_dir, ".tokens")
    if not os.path.exists(data_dir):
        os.makedirs(data_dir)
    creds_file = "robinhood.pickle"
    pickle_path = os.path.join(data_dir, creds_file)
    print(pickle_path)
    # Challenge type is used if not logging in with two-factor authentication.
    if by_sms:
        challenge_type = "sms"
    else:
        challenge_type = "email"

    url = urls.login_url()
    payload = {
        'client_id': 'c82SH0WZOsabOXGP2sxqcj34FxkvfnWRZBKlBjFS',
        'expires_in': expiresIn,
        'grant_type': 'password',
        'password': password,
        'scope': scope,
        'username': username,
        'challenge_type': challenge_type,
        'device_token': device_token
    }

    if mfa_code:
        payload['mfa_code'] = mfa_code

    # If authentication has been stored in pickle file then load it. Stops login server from being pinged so much.
    if os.path.isfile(pickle_path):
    # if blob_pickle_path:
        # If store_session has been set to false then delete the pickle file, otherwise try to load it.
        # Loading pickle file will fail if the acess_token has expired.
        if store_session:
            try:
                with open(pickle_path, 'rb') as f:
                # if blob_pickle_path:
                    pickle_data = pickle.load(f)
                    print('loaded pickle')
                    # pickle_data = pickle.loads(blob_pickle)
                    # print('loaded blob_pickle')
                    access_token = pickle_data['access_token']
                    token_type = pickle_data['token_type']
                    refresh_token = pickle_data['refresh_token']
                    # Set device_token to be the original device token when first logged in.
                    pickle_device_token = pickle_data['device_token']
                    payload['device_token'] = pickle_device_token
                    # Set login status to True in order to try and get account info.
                    helper.set_login_state(True)
                    helper.update_session(
                        'Authorization', '{0} {1}'.format(token_type, access_token))
                    # Try to load account profile to check that authorization token is still valid.
                    res = helper.request_get(
                        urls.portfolio_profile(), 'regular', payload, jsonify_data=False)
                    # Raises exception is response code is not 200.
                    res.raise_for_status()
                    return({'access_token': access_token, 'token_type': token_type,
                            'expires_in': expiresIn, 'scope': scope, 'detail': 'logged in using authentication in {0}'.format(creds_file),
                            'backup_code': None, 'refresh_token': refresh_token})
            except:
                print(
                    "ERROR: There was an issue loading pickle file. Authentication may be expired - logging in normally.", file=helper.get_output())

                helper.set_login_state(False)
                helper.update_session('Authorization', None)
        else:
            os.remove(pickle_path)

    # Try to log in normally.
    if not username:
        # username = input("Robinhood username: "******"RB_USER")

    if not password:
        # password = getpass.getpass("Robinhood password: "******"RB_PASS")

    data = helper.request_post(url, payload)
    # Handle case where mfa or challenge is required.
    if data:
        if 'mfa_required' in data:
            # totp = str(pyotp.TOTP(access_secret_version('quantwannabe', 'RB_TOKEN', 'latest')).now())
            totp = str(pyotp.TOTP(os.environ.get("RB_TOKEN")).now())
            print(f"logging in with {totp} at {str(datetime.now())}")
            # mfa_token = input("Please type in the MFA code: ")
            mfa_token=totp
            payload['mfa_code'] = mfa_token
            res = helper.request_post(url, payload, jsonify_data=False)
            while (res.status_code != 200):
                mfa_token = input(
                    "That MFA code was not correct. Please type in another MFA code: ")
                payload['mfa_code'] = mfa_token
                res = helper.request_post(url, payload, jsonify_data=False)
            data = res.json()
        elif 'challenge' in data:
            challenge_id = data['challenge']['id']
            sms_code = input('Enter Robinhood code for validation: ')
            res = respond_to_challenge(challenge_id, sms_code)
            while 'challenge' in res and res['challenge']['remaining_attempts'] > 0:
                sms_code = input('That code was not correct. {0} tries remaining. Please type in another code: '.format(
                    res['challenge']['remaining_attempts']))
                res = respond_to_challenge(challenge_id, sms_code)
            helper.update_session(
                'X-ROBINHOOD-CHALLENGE-RESPONSE-ID', challenge_id)
            data = helper.request_post(url, payload)
        # Update Session data with authorization or raise exception with the information present in data.
        if 'access_token' in data:
            token = '{0} {1}'.format(data['token_type'], data['access_token'])
            helper.update_session('Authorization', token)
            helper.set_login_state(True)
            data['detail'] = "logged in with brand new authentication code."
            if store_session:
                with open(pickle_path, 'wb') as f:
                    pickle.dump({'token_type': data['token_type'],
                                 'access_token': data['access_token'],
                                 'refresh_token': data['refresh_token'],
                                 'device_token': device_token}, f)
                print(f'updated pickle in {pickle_path}')
                # blob = bucket.blob(blob_pickle_path)
                # print(f'upload blob from {pickle_path} to {blob_pickle_path}')
                # with open(pickle_path, 'rb') as f:
                #     new_pickle = f.read()
                # blob.upload_from_string(new_pickle)
        else:
            raise Exception(data['detail'])
    else:
        raise Exception('Error: Trouble connecting to robinhood API. Check internet connection.')
    return data