Example #1
0
def build_user_profile():
    """Builds a dictionary of important information regarding the user account.

    :returns: Returns a dictionary that has total equity, extended hours equity, cash, and divendend total.

    """
    user = {}

    portfolios_data = profiles.load_portfolio_profile()
    accounts_data = profiles.load_account_profile()

    if portfolios_data:
        user['equity'] = portfolios_data['equity']
        user['extended_hours_equity'] = portfolios_data[
            'extended_hours_equity']

    if accounts_data:
        cash = "{0:.2f}".format(
            float(accounts_data['cash']) +
            float(accounts_data['uncleared_deposits']))
        user['cash'] = cash

    user['dividend_total'] = get_total_dividends()

    return (user)
Example #2
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')
            return ([None])
        print(
            'ERROR: Interval must be "5minute","10minute","hour","day",or "week"')
        return([None])
    if span not in span_check:
        print('ERROR: Span must be "day","week","month","3month","year",or "5year"')
        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"')
        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))
Example #3
0
def order(symbol, quantity, orderType, trigger, side, limitPrice = None, stopPrice = None, timeInForce = 'gtc', extendedHours = False):
    """A generic order function. All parameters must be supplied.

    :param symbol: The stock ticker of the stock to sell.
    :type symbol: str
    :param quantity: The number of stocks to sell.
    :type quantity: int
    :param orderType: Either 'market' or 'limit'
    :type orderType: str
    :param trigger: Either 'immediate' or 'stop'
    :type trigger: str
    :param side: Either 'buy' or 'sell'
    :type side: str
    :param limitPrice: The price to trigger the market order.
    :type limitPrice: float
    :param stopPrice: The price to trigger the limit or market order.
    :type stopPrice: float
    :param timeInForce: Changes how long the order will be in effect for. 'gtc' = good until cancelled. \
    'gfd' = good for the day. 'ioc' = immediate or cancel. 'opg' execute at opening.
    :type timeInForce: str
    :param extendedHours: Premium users only. Allows trading during extended hours. Should be true or false.
    :type extendedHours: Optional[str]
    :returns: Dictionary that contains information regarding the purchase or selling of stocks, \
    such as the order id, the state of order (queued,confired,filled, failed, canceled, etc.), \
    the price, and the quantity.

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

    if stopPrice:
        stopPrice = helper.round_price(stopPrice)

    if limitPrice:
        limitPrice = helper.round_price(limitPrice)
    else:
        limitPrice = helper.round_price(stocks.get_latest_price(symbol)[0])
    payload = {
    'account': profiles.load_account_profile(info='url'),
    'instrument': stocks.get_instruments_by_symbols(symbol, info='url')[0],
    'symbol': symbol,
    'price': limitPrice,
    'quantity': quantity,
    'ref_id': str(uuid4()),
    'type': orderType,
    'stop_price': stopPrice,
    'time_in_force': timeInForce,
    'trigger': trigger,
    'side': side,
    'extended_hours': extendedHours
    }

    url = urls.orders()
    data = helper.request_post(url, payload)

    return(data)
Example #4
0
def order_option_spread(direction, price, symbol, quantity, spread, timeInForce='gfd'):
    """Submits a limit order for an option spread. i.e. place a debit / credit spread

    :param direction: credit or debit spread
    :type direction: str
    :param price: The limit price to trigger a trade of the option.
    :type price: float
    :param symbol: The stock ticker of the stock to trade.
    :type symbol: str
    :param quantity: The number of options to trade.
    :type quantity: int
    :param spread: A dictionary of spread options with the following keys: \n
        - expirationDate: The expiration date of the option in 'YYYY-MM-DD' format.\n
        - strike: The strike price of the option.\n
        - optionType: This should be 'call' or 'put'
    :type spread: dict
    :param timeInForce: Changes how long the order will be in effect for.
     'gtc' = good until cancelled. \
     'gfd' = good for the day. 'ioc' = immediate or cancel. 'opg' execute at opening.
    :type timeInForce: Optional[str]
    :returns: Dictionary that contains information regarding the selling of options, \
    such as the order id, the state of order (queued,confired,filled, failed, canceled, etc.), \
    the price, and the quantity.
    """
    try:
        symbol = symbol.upper().strip()
    except AttributeError as message:
        print(message)
        return None
    legs = []
    for each in spread:
        optionID = helper.id_for_option(symbol,
                                        each['expirationDate'],
                                        each['strike'],
                                        each['optionType'])
        legs.append({'position_effect': each['effect'],
                     'side' : each['action'],
                     'ratio_quantity': 1,
                     'option': urls.option_instruments(optionID)})

    payload = {
        'account': profiles.load_account_profile(info='url'),
        'direction': direction,
        'time_in_force': timeInForce,
        'legs': legs,
        'type': 'limit',
        'trigger': 'immediate',
        'price': price,
        'quantity': quantity,
        'override_day_trade_checks': False,
        'override_dtbp_checks': False,
        'ref_id': str(uuid4()),
    }

    url = urls.option_orders()
    data = helper.request_post(url,payload, json=True)

    return(data)
Example #5
0
def order_sell_stop_limit(symbol,
                          quantity,
                          limitPrice,
                          stopPrice,
                          timeInForce='gtc',
                          extendedHours=False):
    """Submits a stop order to be turned into a limit order once a certain stop price is reached.

    :param symbol: The stock ticker of the stock to sell.
    :type symbol: str
    :param quantity: The number of stocks to sell.
    :type quantity: int
    :param limitPrice: The price to trigger the market order.
    :type limitPrice: float
    :param stopPrice: The price to trigger the limit order.
    :type stopPrice: float
    :param timeInForce: Changes how long the order will be in effect for. 'gtc' = good until cancelled. \
    'gfd' = good for the day. 'ioc' = immediate or cancel. 'opg' execute at opening.
    :type timeInForce: Optional[str]
    :param extendedHours: Premium users only. Allows trading during extended hours. Should be true or false.
    :type extendedHours: Optional[str]
    :returns: Dictionary that contains information regarding the selling of stocks, \
    such as the order id, the state of order (queued,confired,filled, failed, canceled, etc.), \
    the price, and the quantity.

    """
    try:
        symbol = symbol.upper().strip()
        latestPrice = helper.round_price(stocks.get_latest_price(symbol)[0])
        stopPrice = helper.round_price(stopPrice)
        limitPrice = helper.round_price(limitPrice)
    except AttributeError as message:
        print(message)
        return None

    if (latestPrice < stopPrice):
        print('Error: stopPrice must be below the current price.')
        return (None)

    payload = {
        'account': profiles.load_account_profile(info='url'),
        'instrument': stocks.get_instruments_by_symbols(symbol, info='url')[0],
        'symbol': symbol,
        'price': limitPrice,
        'quantity': quantity,
        'ref_id': str(uuid4()),
        'type': 'limit',
        'stop_price': stopPrice,
        'time_in_force': timeInForce,
        'trigger': 'stop',
        'side': 'sell',
        'extended_hours': extendedHours
    }

    url = urls.orders()
    data = helper.request_post(url, payload)

    return (data)
Example #6
0
def order_sell_option_limit(positionEffect, price, symbol, quantity, expirationDate, strike, optionType='both', timeInForce='gfd'):
    """Submits a limit order for an option. i.e. place a short call or a short put.

    :param positionEffect: Either 'open' for a sell to open effect or 'close' for a sell to close effect.
    :type positionEffect: str
    :param price: The limit price to trigger a sell of the option.
    :type price: float
    :param symbol: The stock ticker of the stock to trade.
    :type symbol: str
    :param quantity: The number of options to sell.
    :type quantity: int
    :param expirationDate: The expiration date of the option in 'YYYY-MM-DD' format.
    :type expirationDate: str
    :param strike: The strike price of the option.
    :type strike: float
    :param optionType: This should be 'call' or 'put'
    :type optionType: str
    :param timeInForce: Changes how long the order will be in effect for. 'gtc' = good until cancelled. \
    'gfd' = good for the day. 'ioc' = immediate or cancel. 'opg' execute at opening.
    :type timeInForce: Optional[str]
    :returns: Dictionary that contains information regarding the selling of options, \
    such as the order id, the state of order (queued,confired,filled, failed, canceled, etc.), \
    the price, and the quantity.

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

    optionID = helper.id_for_option(symbol, expirationDate, strike, optionType)
	
    if (positionEffect == 'close'):
        direction = 'debit'
    else:
        direction = 'credit'

    payload = {
    'account': profiles.load_account_profile(info='url'),
    'direction': direction,
    'time_in_force': timeInForce,
    'legs': [
        {'position_effect': positionEffect, 'side' : 'sell', 'ratio_quantity': 1, 'option': urls.option_instruments(optionID) },
    ],
    'type': 'limit',
    'trigger': 'immediate',
    'price': price,
    'quantity': quantity,
    'override_day_trade_checks': False,
	'override_dtbp_checks': False,
    'ref_id': str(uuid4()),
    }

    url = urls.option_orders()
    data = helper.request_post(url, payload, json=True)

    return(data)
Example #7
0
def build_holdings():
    """Builds a dictionary of important information regarding the stocks and positions owned by the user.

    :returns: Returns a dictionary where the keys are the stock tickers and the value is another dictionary \
    that has the stock price, quantity held, equity, percent change, equity change, type, name, id, pe ratio, \
    percentage of portfolio, and average buy price.

    """
    positions_data = get_current_positions()
    portfolios_data = profiles.load_portfolio_profile()
    accounts_data = profiles.load_account_profile()

    if not positions_data or not portfolios_data or not accounts_data:
        return({})

    if portfolios_data['extended_hours_equity'] is not None:
        total_equity = max(float(portfolios_data['equity']),float(portfolios_data['extended_hours_equity']))
    else:
        total_equity = float(portfolios_data['equity'])

    cash = "{0:.2f}".format(float(accounts_data['cash'])+float(accounts_data['uncleared_deposits']))

    holdings = {}
    for item in positions_data:
        # It is possible for positions_data to be [None]
        if not item:
            continue

        try:
            instrument_data = stocks.get_instrument_by_url(item['instrument'])
            symbol = instrument_data['symbol']
            fundamental_data = stocks.get_fundamentals(symbol)[0]

            price           = stocks.get_latest_price(instrument_data['symbol'])[0]
            quantity        = item['quantity']
            equity          = float(item['quantity'])*float(price)
            equity_change   = (float(quantity)*float(price))-(float(quantity)*float(item['average_buy_price']))
            percentage      = float(item['quantity'])*float(price)*100/(float(total_equity)-float(cash))
            if (float(item['average_buy_price']) == 0.0):
                percent_change = 0.0
            else:
                percent_change  = (float(price)-float(item['average_buy_price']))*100/float(item['average_buy_price'])

            holdings[symbol]=({'price': price })
            holdings[symbol].update({'quantity': quantity})
            holdings[symbol].update({'average_buy_price': item['average_buy_price']})
            holdings[symbol].update({'equity':"{0:.2f}".format(equity)})
            holdings[symbol].update({'percent_change': "{0:.2f}".format(percent_change)})
            holdings[symbol].update({'equity_change':"{0:2f}".format(equity_change)})
            holdings[symbol].update({'type': instrument_data['type']})
            holdings[symbol].update({'name': stocks.get_name_by_symbol(symbol)})
            holdings[symbol].update({'id': instrument_data['id']})
            holdings[symbol].update({'pe_ratio': fundamental_data['pe_ratio'] })
            holdings[symbol].update({'percentage': "{0:.2f}".format(percentage)})
        except:
            pass

    return(holdings)
Example #8
0
def order_option_by_id(option_id,
                       price,
                       quantity,
                       direction='credit',
                       effect='close',
                       side='sell',
                       time_in_force='gfd'):
    """

    :param option_id:
    :param price:
    :param quantity:
    :param direction:
    :param effect:
    :param side:
    :param time_in_force:
    :return:
    """

    payload = {
        'account':
        profiles.load_account_profile(info='url'),
        'direction':
        direction,
        'time_in_force':
        time_in_force,
        'legs': [
            {
                'position_effect': effect,
                'side': side,
                'ratio_quantity': 1,
                'option': urls.option_instruments(option_id)
            },
        ],
        'type':
        'limit',
        'trigger':
        'immediate',
        'price':
        price,
        'quantity':
        quantity,
        'override_day_trade_checks':
        False,
        'override_dtbp_checks':
        False,
        'ref_id':
        str(uuid4()),
    }

    url = urls.option_orders()
    data = helper.request_post(url, payload, json=True)
    print(data)
    return data
Example #9
0
def get_day_trades(info=None):
    """Returns recent day trades.

    :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 day trade. If info parameter is provided, \
    a list of strings is returned where the strings are the value of the key that matches info.

    """
    account = profiles.load_account_profile('account_number')
    url = urls.daytrades(account)
    data = helper.request_get(url, 'pagination')
    return(helper.filter(data, info))
Example #10
0
def order_buy_stop_limit(symbol,quantity,limitPrice,stopPrice,timeInForce='gtc'):
    """Submits a stop order to be turned into a limit order once a certain stop price is reached.

    :param symbol: The stock ticker of the stock to purchase.
    :type symbol: str
    :param quantity: The number of stocks to buy.
    :type quantity: int
    :param limitPrice: The price to trigger the market order.
    :type limitPrice: float
    :param stopPrice: The price to trigger the limit order.
    :type stopPrice: float
    :param timeInForce: Changes how long the order will be in effect for. 'gtc' = good until cancelled. \
    'gfd' = good for the day. 'ioc' = immediate or cancel. 'opg' execute at opening.
    :type timeInForce: Optional[str]
    :returns: Dictionary that contains information regarding the purchase of stocks, \
    such as the order id, the state of order (queued,confired,filled, failed, canceled, etc.), \
    the price, and the quantity.

    """
    try:
        symbol = symbol.upper().strip()
        latestPrice = float(stocks.get_latest_price(symbol)[0])
        stopPrice = float(stopPrice)
        limitPrice = float(limitPrice)
    except AttributeError as message:
        print(message)
        return None

    if (latestPrice > stopPrice):
        print('Error: stopPrice must be above the current price.')
        return(None)

    payload = {
    'account': profiles.load_account_profile(info='url'),
    'instrument': stocks.get_instruments_by_symbols(symbol,info='url')[0],
    'symbol': symbol,
    'price': limitPrice,
    'quantity': quantity,
    'ref_id': helper.get_device_token(),
    'type': 'limit',
    'stop_price': stopPrice,
    'time_in_force': timeInForce,
    'trigger': 'stop',
    'side': 'buy'
    }

    url = urls.orders()
    data = helper.request_post(url,payload)

    return(data)
Example #11
0
def order_buy_market(symbol,
                     quantity,
                     timeInForce='gtc',
                     extendedHours='false'):
    """Submits a market order to be executed immediately.

    :param symbol: The stock ticker of the stock to purchase.
    :type symbol: str
    :param quantity: The number of stocks to buy.
    :type quantity: int
    :param timeInForce: Changes how long the order will be in effect for. 'gtc' = good until cancelled. \
    'gfd' = good for the day. 'ioc' = immediate or cancel. 'opg' execute at opening.
    :type timeInForce: Optional[str]
    :param extendedHours: Premium users only. Allows trading during extended hours. Should be true or false.
    :type extendedHours: str
    :returns: Dictionary that contains information regarding the purchase of stocks, \
    such as the order id, the state of order (queued,confired,filled, failed, canceled, etc.), \
    the price, and the quantity.

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

    payload = {
        'account': profiles.load_account_profile(info='url'),
        'instrument': stocks.get_instruments_by_symbols(symbol, info='url')[0],
        'symbol': symbol,
        'price': float(stocks.get_latest_price(symbol)[0]),
        'quantity': quantity,
        'ref_id': str(uuid4()),
        'type': 'market',
        'stop_price': None,
        'time_in_force': timeInForce,
        'trigger': 'immediate',
        'side': 'buy',
        "extended_hours": extendedHours
    }

    url = urls.orders()
    data = helper.request_post(url, payload)

    return (data)
Example #12
0
def order_sell_limit(symbol,quantity,limitPrice,timeInForce='gtc'):
    """Submits a limit order to be executed once a certain price is reached.

    :param symbol: The stock ticker of the stock to sell.
    :type symbol: str
    :param quantity: The number of stocks to sell.
    :type quantity: int
    :param limitPrice: The price to trigger the sell order.
    :type limitPrice: float
    :param timeInForce: Changes how long the order will be in effect for. 'gtc' = good until cancelled. \
    'gfd' = good for the day. 'ioc' = immediate or cancel. 'opg' execute at opening.
    :type timeInForce: Optional[str]
    :returns: Dictionary that contains information regarding the selling of stocks, \
    such as the order id, the state of order (queued,confired,filled, failed, canceled, etc.), \
    the price, and the quantity.

    """
    try:
        symbol = symbol.upper().strip()
        limitPrice = helper.round_price(limitPrice)
    except AttributeError as message:
        print(message)
        return None

    payload = {
    'account': profiles.load_account_profile(info='url'),
    'instrument': stocks.get_instruments_by_symbols(symbol,info='url')[0],
    'symbol': symbol,
    'price': limitPrice,
    'quantity': quantity,
    'ref_id': str(uuid4()),
    'type': 'limit',
    'stop_price': None,
    'time_in_force': timeInForce,
    'trigger': 'immediate',
    'side': 'sell'
    }

    url = urls.orders()
    data = helper.request_post(url,payload)

    return(data)
Example #13
0
def build_holdings(access_token, with_dividends=False):
    """Builds a dictionary of important information regarding the stocks and positions owned by the user.

    :param with_dividends: True if you want to include divident information.
    :type with_dividends: bool
    :returns: Returns a dictionary where the keys are the stock tickers and the value is another dictionary \
    that has the stock price, quantity held, equity, percent change, equity change, type, name, id, pe ratio, \
    percentage of portfolio, and average buy price.

    """
    positions_data = get_open_stock_positions(access_token)
    portfolios_data = profiles.load_portfolio_profile(access_token)
    accounts_data = profiles.load_account_profile(access_token)

    # user wants dividend information in their holdings
    if with_dividends is True:
        dividend_data = get_dividends()

    if not positions_data or not portfolios_data or not accounts_data:
        return ({})

    if portfolios_data['extended_hours_equity'] is not None:
        total_equity = max(float(portfolios_data['equity']),
                           float(portfolios_data['extended_hours_equity']))
    else:
        total_equity = float(portfolios_data['equity'])

    cash = "{0:.2f}".format(
        float(accounts_data['cash']) +
        float(accounts_data['uncleared_deposits']))

    holdings = {}
    for item in positions_data:
        # It is possible for positions_data to be [None]
        if not item:
            continue

        try:
            instrument_data = stocks.get_instrument_by_url(item['instrument'],
                                                           access_token,
                                                           info=None)
            symbol = instrument_data['symbol']
            # fundamental_data = stocks.get_fundamentals(symbol, access_token, info=None)[0]

            price = stocks.get_latest_price(instrument_data['symbol'],
                                            access_token=access_token)[0]
            quantity = item['quantity']
            equity = float(item['quantity']) * float(price)
            equity_change = (float(quantity) * float(price)) - \
                (float(quantity) * float(item['average_buy_price']))
            percentage = float(item['quantity']) * float(price) * \
                100 / (float(total_equity) - float(cash))
            if (float(item['average_buy_price']) == 0.0):
                percent_change = 0.0
            else:
                percent_change = (float(price) - float(
                    item['average_buy_price'])) * 100 / float(
                        item['average_buy_price'])

            holdings[symbol] = ({'price': price})
            holdings[symbol].update({'quantity': quantity})
            holdings[symbol].update(
                {'average_buy_price': item['average_buy_price']})
            holdings[symbol].update({'equity': "{0:.2f}".format(equity)})
            holdings[symbol].update(
                {'percent_change': "{0:.2f}".format(percent_change)})
            holdings[symbol].update(
                {'equity_change': "{0:2f}".format(equity_change)})
            holdings[symbol].update(
                {'percentage': "{0:2f}".format(percentage)})
            holdings[symbol].update({'type': instrument_data['type']})
            holdings[symbol].update(
                {'name': stocks.get_name_by_symbol(symbol)})
            holdings[symbol].update({'id': instrument_data['id']})
            # holdings[symbol].update(
            #     {'percentage': "{0:2f}".format(percentage)})
            # holdings[symbol].update({'pe_ratio': fundamental_data['pe_ratio']})

            if with_dividends is True:
                # dividend_data was retrieved earlier
                holdings[symbol].update(
                    get_dividends_by_instrument(item['instrument'],
                                                dividend_data))

        except:
            pass

    return (holdings)
Example #14
0
    def rh_pull_portfolio_data(user_id, passwd):
        r.login(username=user_id, password=passwd)

        if DbAccess.is_update_needed():
            obj = portfolio_summary.objects.all()
            if not obj:
                obj = portfolio_summary()
                obj.timestamp = timezone.now()
            else:
                obj = obj[0]
            obj.portfolio_cash  = float(profiles.load_account_profile()['portfolio_cash'])
            obj.save()

            # remove current entries
            stocks_held.objects.all().delete()
            # get current owned securites and save to db
            positions_data = r.get_open_stock_positions()
            for item in positions_data:
                quantity = float(item['quantity'])
                if not quantity:
                    continue
                # check if instrument is present in robinhood_traded_stocks table
                obj                     = stocks_held()
                obj.symbol, obj.name    = RhWrapper.rh_pull_symbol_from_instrument_url(item['instrument'])
                obj.quantity            = quantity
                obj.average_price       = float(item['average_buy_price'])
                obj.latest_price        = float(r.get_latest_price(obj.symbol)[0])
                obj.open_price          = float(r.get_fundamentals(obj.symbol)[0]['open'])
                try:
                    obj.prev_close_price    = float(StockUtils.getStockInfo(obj.symbol)['previousClose'])
                except Exception as e:
                    logging.error(str(e) + ' encountered when fetching yahoo data for ' + obj.symbol)
                    obj.prev_close_price = obj.open_price
                obj.save()

            # remove current entries
            options_held.objects.all().delete()
            # get current owned securites and save to db
            options_position_data = r.get_open_option_positions()
            for item in options_position_data:
                quantity = float(item['quantity'])
                if not quantity:
                    continue
                obj                        = options_held()
                obj.option_id              = item['option_id']
                contract_into              = r.get_option_instrument_data_by_id(obj.option_id)
                obj.strike_price           = float(contract_into['strike_price'])
                obj.expiration_date        = contract_into['expiration_date']
                obj.option_type            = contract_into['type']
                obj.symbol                 = item['chain_symbol']
                obj.trade_value_multiplier = float(item['trade_value_multiplier'])
                obj.average_price          = float(item['average_price']) / obj.trade_value_multiplier
                obj.quantity               = float(item['quantity'])
                # adjust value for sold calls
                if obj.average_price < 0:
                    obj.average_price      = (-1) * obj.average_price
                    obj.quantity           = (-1) * obj.quantity
                market_data                = r.get_option_market_data_by_id(obj.option_id)
                obj.previous_close_price   = float(market_data['previous_close_price'])
                obj.current_price          = float(market_data['adjusted_mark_price'])
                # print('symbol: %5s strike_price: %7.2f option_type: %4s expiration_date: %12s trade_value_multiplier: %d average_price: %7.2f quantity: %d previous_close_price: %7.2f current_price: %7.2f' % (obj.symbol, obj.strike_price, obj.option_type, obj.expiration_date, obj.trade_value_multiplier, obj.average_price, obj.quantity, obj.previous_close_price, obj.current_price))
                obj.save()