def run_gather_data():
    #code that gets and logs performance data
    print("Gathering Data")
    success = True

    rh = Robinhood()
    now = datetime.datetime.utcnow()
    try:
        success = rh.marketOpenCheck()
        if not success:
            print('markets are closed')
        else:
            print('markets are open')
    except Exception as e:
        success = False
        print('rh market check error ', str(e))
        send_email(mailgun_domain, mailgun_api_key, diag_email_dest,
                   ('resiliant-trader data gather error ' +
                    str(datetime.datetime.now())),
                   ("rh market check error. Unexpected error: " + str(e)))

    if success:
        try:
            success = rh.login(username=rhuser, password=rhpass)
            if success:
                print('robinhood login succesful')
            else:
                print('robinhood login unsuccesful')
        except Exception as e:
            success = False
            print('rh login error ', str(e))
            send_email(mailgun_domain, mailgun_api_key, diag_email_dest,
                       ('resiliant-trader data gather error ' +
                        str(datetime.datetime.now())),
                       ("rh login error. Unexpected error: " + str(e)))

    if success:
        try:
            client = MongoClient(mongodb_uri)
            db = client.get_database()
        except Exception as e:
            print('mongo login error ', str(e))
            success = False
            send_email(mailgun_domain, mailgun_api_key, diag_email_dest,
                       ('resiliant-trader data gather error ' +
                        str(datetime.datetime.now())),
                       ("mongo login error. Unexpected error: " + str(e)))

    if success:
        try:
            #get pricing data
            spyAskPrice = rh.ask_price('SPY')
            spyBidPrice = rh.bid_price('SPY')
            spyAvgCost = (spyAskPrice + spyBidPrice) / 2
            print('spyAvgCost = ', spyAvgCost)

            tltAskPrice = rh.ask_price('TLT')
            tltBidPrice = rh.bid_price('TLT')
            tltAvgCost = (tltAskPrice + tltBidPrice) / 2
            print('tltAvgCost = ', tltAvgCost)
        except Exception as e:
            print('etf price error ', str(e))
            success = False
            send_email(mailgun_domain, mailgun_api_key, diag_email_dest,
                       ('resiliant-trader data gather error ' +
                        str(datetime.datetime.now())),
                       ("etf price error. Unexpected error: " + str(e)))

    if success:
        try:
            #get portfolioValue
            portfolioValue = rh.equity()
            tltPosition = 0
            spyPosition = 0
            print('portfolioValue =', portfolioValue)
            openPositions = rh.securities_owned()['results']
            for position in openPositions:
                instrumentURL = position['instrument']
                positionTicker = rh.get_url(instrumentURL)['symbol']
                positionQuantity = float(position['quantity'])
                if (positionTicker == 'SPY'):
                    spyPosition = positionQuantity
                if (positionTicker == 'TLT'):
                    tltPosition = positionQuantity
            print('spyPosition = ', spyPosition)
            print('tltPosition = ', tltPosition)
        except Exception as e:
            print('portfolio value error ', str(e))
            success = False
            send_email(mailgun_domain, mailgun_api_key, diag_email_dest,
                       ('resiliant-trader data gather error ' +
                        str(datetime.datetime.now())),
                       ("portfolio value error. Unexpected error: " + str(e)))

    if success:
        try:
            #get treasury risk free rate
            quandl.ApiConfig.api_key = quandl_key
            riskFree = (quandl.get("USTREASURY/BILLRATES.3",
                                   rows=1,
                                   returns='numpy')[0])[1]
            print('riskFree =', riskFree)
        except Exception as e:
            print('risk free error ', str(e))
            success = False
            send_email(mailgun_domain, mailgun_api_key, diag_email_dest,
                       ('resiliant-trader data gather error ' +
                        str(datetime.datetime.now())),
                       ("risk free error. Unexpected error: " + str(e)))

    if success:
        try:
            #get last data
            lastData = db.rawPrices.find_one(sort=[("timestamp", -1)])
            lastTimestamp = lastData['timestamp']
            lastSpy = lastData['spy']
            lastTlt = lastData['tlt']
            lastPortfolio = lastData['portfolio']
            lastRiskFree = lastData['annualized90day']
        except Exception as e:
            print('error getting previous data ', str(e))
            success = False
            send_email(
                mailgun_domain, mailgun_api_key, diag_email_dest,
                ('resiliant-trader data gather error ' +
                 str(datetime.datetime.now())),
                ("error getting previous data. Unexpected error: " + str(e)))

    if success:
        try:
            # save data
            rawData = {
                "timestamp": now,
                "spy": spyAvgCost,
                "tlt": tltAvgCost,
                "portfolio": portfolioValue,
                "annualized90day": riskFree
            }
            data_id = db.rawPrices.insert_one(rawData).inserted_id
            print("data saved to", data_id)
        except Exception as e:
            print('data save error ', str(e))
            success = False
            send_email(
                mailgun_domain, mailgun_api_key, diag_email_dest,
                ('resiliant-trader data gather error ' +
                 str(datetime.datetime.now())),
                ("error calculating change. Unexpected error: " + str(e)))

    if success:
        try:
            # calculate percentage changes
            spyChange = (spyAvgCost - lastSpy) / lastSpy
            print('spyChange = ', spyChange)
            tltChange = (tltAvgCost - lastTlt) / lastTlt
            print('tltChange = ', tltChange)
            portfolioChange = (portfolioValue - lastPortfolio) / lastPortfolio
            print('portfolioChange = ', portfolioChange)
            elapsedTime = now - lastTimestamp
            year = datetime.timedelta(days=365)
            treasuryChange = ((1 + (((lastRiskFree + riskFree) / 2)) / 100)
                              **(divtd(elapsedTime, year))) - 1
            print('treasuryChange = ', treasuryChange)
        except Exception as e:
            print('error calculating change ', str(e))
            success = False
            send_email(
                mailgun_domain, mailgun_api_key, diag_email_dest,
                ('resiliant-trader data gather error ' +
                 str(datetime.datetime.now())),
                ("error calculating change. Unexpected error: " + str(e)))

    if success:
        try:
            # save data
            percentageData = {
                "timestamp": now,
                "spy": spyChange,
                "tlt": tltChange,
                "portfolio": portfolioChange,
                "90dayTreasury": treasuryChange
            }
            data_id = db.percentageMove.insert_one(percentageData).inserted_id
            print("data saved to", data_id)
        except Exception as e:
            print('data save error ', str(e))
            success = False
            send_email(mailgun_domain, mailgun_api_key, diag_email_dest,
                       ('resiliant-trader data gather error ' +
                        str(datetime.datetime.now())),
                       ("data save error. Unexpected error: " + str(e)))

    if success:
        try:
            # calculate tracking
            spyTarget = calcAlloc(rh)
            print('spyTarget = ', spyTarget)
            tltTarget = 1 - spyTarget
            print('tltTarget = ', tltTarget)

            spyActual = (spyPosition * spyAvgCost) / portfolioValue
            tltActual = (tltPosition * tltAvgCost) / portfolioValue
            print('spyActual = ', spyActual)
            print('tltActual = ', tltActual)
        except Exception as e:
            print('error calculating tracking ', str(e))
            success = False
            send_email(
                mailgun_domain, mailgun_api_key, diag_email_dest,
                ('resiliant-trader data gather error ' +
                 str(datetime.datetime.now())),
                ("error calculating tracking. Unexpected error: " + str(e)))

    if success:
        try:
            # save tracking data
            trackingData = {
                "timestamp": now,
                "spyActual": spyActual,
                "tltActual": tltActual,
                "spyTarget": spyTarget,
                "tltTarget": tltTarget
            }
            data_id = db.tracking.insert_one(trackingData).inserted_id
            print("data saved to", data_id)
        except Exception as e:
            print('tracking data save error ', str(e))
            success = False
            send_email(
                mailgun_domain, mailgun_api_key, diag_email_dest,
                ('resiliant-trader data gather error ' +
                 str(datetime.datetime.now())),
                ("tracking data save error. Unexpected error: " + str(e)))
    portfolioValue = rh.equity()
    print('portfolioValue =', portfolioValue)

    #allocate portfolio
    spyAllocationPercentage = calcAlloc(rh)
    tltAllocationPercentage = 1 - spyAllocationPercentage
    print('spyAllocationPercentage = ', spyAllocationPercentage)
    print('tltAllocationPercentage = ', tltAllocationPercentage)

    spyTargetAllocation = spyAllocationPercentage * portfolioValue
    tltTargetAllocation = tltAllocationPercentage * portfolioValue
    print('spyTargetAllocation = ', spyTargetAllocation)
    print('tltTargetAllocation = ', tltTargetAllocation)

    #get pricing data
    spyAskPrice = rh.ask_price('SPY')
    spyBidPrice = rh.bid_price('SPY')
    spyAvgCost = (spyAskPrice + spyBidPrice) / 2
    spyBuyPrice = spyAskPrice + (spyAskPrice - spyBidPrice)
    spySellPrice = spyBidPrice - (spyAskPrice - spyBidPrice)
    print('spyAskPrice = ', spyAskPrice)
    print('spyBidPrice = ', spyBidPrice)

    tltAskPrice = rh.ask_price('TLT')
    tltBidPrice = rh.bid_price('TLT')
    tltAvgCost = (tltAskPrice + tltBidPrice) / 2
    tltBuyPrice = tltAskPrice + (tltAskPrice - tltBidPrice)
    tltSellPrice = tltBidPrice - (tltAskPrice - tltBidPrice)
    print('tltAskPrice = ', tltAskPrice)
    print('tltBidPrice = ', tltBidPrice)
def run_trader():
    try:
        print("running trader at: " + str(datetime.datetime.now()))
        message = "running trader at: " + str(datetime.datetime.now())
        success = True

        rh = Robinhood()
        success = rh.marketOpenCheck()
        if not success:
            print('markets are closed')
            message += '\nmarkets are closed'
        else:
            print('markets are open')
            message += '\nmarkets are open'

        if success:
            success = rh.login(username=rhuser, password=rhpass)

        if success:
            print('login succesful')
            message += '\nlogin succesful'
        else:
            print('login unsuccesful')
            message += '\nlogin unsuccesful'

        if success:
            #exit extra postions
            openPositions = rh.securities_owned()['results']

            sellOrders = {}
            for position in openPositions:
                instrumentURL = position['instrument']
                positionTicker = rh.get_url(instrumentURL)['symbol']
                positionQuantity = position['quantity']
                if (positionTicker != 'SPY') and (positionTicker != 'TLT'):
                    print('position in ', positionTicker,
                          ' is not needed, selling')
                    stock_instrument = rh.instruments(positionTicker)[0]
                    sellOrders[
                        positionTicker] = rh.place_immediate_market_order(
                            instrumentURL, positionTicker, 'gfd',
                            positionQuantity, 'sell')
            if sellOrders == {}:
                print('no extra positions found to close')
                message += '\nno extra positions found to close'
            else:
                print(sellOrders)

            orderOutcome = 'unresolved'

            while orderOutcome != 'resolved':
                remainingUnresolved = False
                for order in sellOrders:
                    orderDetail = sellOrders[order]
                    orderDetail['status'] = rh.check_order_status(
                        orderDetail['url'])
                    if orderDetail['status'] == 'unresolved':
                        remainingUnresolved = True
                if not remainingUnresolved:
                    orderOutcome = 'resolved'
                else:
                    print('remaining unresolved orders, waiting')
                    message += '\nremaining unresolved orders, waiting'
                    time.sleep(60)

            for order in sellOrders:
                orderDetail = sellOrders[order]
                if orderDetail['status'] == 'failure':
                    success = False

        if not success:
            print('unable to sell extra positions correctly')
            message += '\nunable to sell extra positions correctly'

        if success:
            #get portfolio current value
            portfolioValue = rh.equity()
            print('portfolioValue =', portfolioValue)
            message += '\nportfolioValue = '
            message += str(portfolioValue)

            #allocate portfolio
            spyAllocationPercentage = calcAlloc(rh)
            tltAllocationPercentage = 1 - spyAllocationPercentage
            print('spyAllocationPercentage = ', spyAllocationPercentage)
            message += '\nspyAllocationPercentage = '
            message += str(spyAllocationPercentage)
            print('tltAllocationPercentage = ', tltAllocationPercentage)
            message += '\ntltAllocationPercentage = '
            message += str(tltAllocationPercentage)

            spyTargetAllocation = spyAllocationPercentage * portfolioValue
            tltTargetAllocation = tltAllocationPercentage * portfolioValue
            print('spyTargetAllocation = ', spyTargetAllocation)
            message += '\nspyTargetAllocation = '
            message += str(spyTargetAllocation)
            print('tltTargetAllocation = ', tltTargetAllocation)
            message += '\ntltTargetAllocation = '
            message += str(tltTargetAllocation)

            #get pricing data
            spyAskPrice = rh.ask_price('SPY')
            spyBidPrice = rh.bid_price('SPY')
            spyAvgCost = (spyAskPrice + spyBidPrice) / 2
            spyBuyPrice = spyAskPrice + (spyAskPrice - spyBidPrice)
            spySellPrice = spyBidPrice - (spyAskPrice - spyBidPrice)
            print('spyAskPrice = ', spyAskPrice)
            message += '\nspyAskPrice = '
            message += str(spyAskPrice)
            print('spyBidPrice = ', spyBidPrice)
            message += '\nspyBidPrice = '
            message += str(spyBidPrice)

            tltAskPrice = rh.ask_price('TLT')
            tltBidPrice = rh.bid_price('TLT')
            tltAvgCost = (tltAskPrice + tltBidPrice) / 2
            tltBuyPrice = tltAskPrice + (tltAskPrice - tltBidPrice)
            tltSellPrice = tltBidPrice - (tltAskPrice - tltBidPrice)
            print('tltAskPrice = ', tltAskPrice)
            message += '\ntltAskPrice = '
            message += str(tltAskPrice)
            print('tltBidPrice = ', tltBidPrice)
            message += '\ntltBidPrice = '
            message += str(tltBidPrice)

            #recommend position sizes
            #[spyTargetShares,tltTargetShares] = recommendTarget(portfolioValue,spyAllocationPercentage,tltAllocationPercentage,spyBuyPrice,tltBuyPrice)
            [spyTargetShares, tltTargetShares] = recommendInitialTarget(
                portfolioValue, spyAllocationPercentage,
                tltAllocationPercentage, spyBuyPrice, tltBuyPrice)

            print('spyTargetShares = ', spyTargetShares)
            message += '\nspyTargetShares = '
            message += str(spyTargetShares)
            print('tltTargetShares = ', tltTargetShares)
            message += '\ntltTargetShares = '
            message += str(tltTargetShares)

            targetPurchaseCost = targetTotalCost(spyTargetShares,
                                                 tltTargetShares, spyBuyPrice,
                                                 tltBuyPrice)

            spyTargetAllocationPercentage = allocationPercentage(
                spyTargetShares, spyBuyPrice, targetPurchaseCost)
            tltTargetAllocationPercentage = allocationPercentage(
                tltTargetShares, tltBuyPrice, targetPurchaseCost)
            print('spyTargetAllocationPercentage = ',
                  spyTargetAllocationPercentage)
            message += '\nspyTargetAllocationPercentage = '
            message += str(spyTargetAllocationPercentage)
            print('tltTargetAllocationPercentage = ',
                  tltTargetAllocationPercentage)
            message += '\ntltTargetAllocationPercentage = '
            message += str(tltTargetAllocationPercentage)

            targetLoss = allocationLoss(spyTargetAllocationPercentage,
                                        spyAllocationPercentage,
                                        tltTargetAllocationPercentage,
                                        tltAllocationPercentage)
            print('target loss = ', targetLoss)

            targetRemainingCash = portfolioValue - targetPurchaseCost
            print('targetPurchaseCost = ', targetPurchaseCost)
            message += '\ntargetPurchaseCost = '
            message += str(targetPurchaseCost)
            print('targetRemainingCash = ', targetRemainingCash)
            message += '\ntargetRemainingCash = '
            message += str(targetRemainingCash)

            #detemine required rebalancing
            spyRequired = spyTargetShares
            tltRequired = tltTargetShares
            for position in openPositions:
                instrumentURL = position['instrument']
                positionTicker = rh.get_url(instrumentURL)['symbol']
                positionQuantity = float(position['quantity'])
                if (positionTicker == 'SPY'):
                    spyRequired = spyTargetShares - positionQuantity
                if (positionTicker == 'TLT'):
                    tltRequired = tltTargetShares - positionQuantity

            print('spyRequired = ', spyRequired)
            message += '\nspyRequired = '
            message += str(spyRequired)
            print('tltRequired = ', tltRequired)
            message += '\ntltRequired = '
            message += str(tltRequired)

            spyInstrumentUrl = (rh.instruments('SPY')[0])['url']
            tltInstrumentUrl = (rh.instruments('TLT')[0])['url']

        if success:
            #sell positions
            if spyRequired < 0.0:
                print('selling ', -spyRequired, ' of SPY')
                spySellOrder = rh.place_immediate_market_order(
                    spyInstrumentUrl, 'SPY', 'gfd', -spyRequired, 'sell')
                print(spySellOrder)

                orderOutcome = 'unresolved'

                while orderOutcome != 'resolved':
                    remainingUnresolved = False
                    orderResponse = rh.check_order_status(spySellOrder['url'])
                    if orderResponse == 'unresolved':
                        remainingUnresolved = True
                    if not remainingUnresolved:
                        orderOutcome = 'resolved'
                    else:
                        print('remaining unresolved spySell, waiting')
                        message += '\nremaining unresolved spySell, waiting'
                        time.sleep(60)

                if orderResponse == 'failure':
                    success = False

        if not success:
            print('unable to sell required spy')
            message += '\nunable to sell required spy'

        if success:
            if tltRequired < 0.0:
                print('selling ', -tltRequired, ' of TLT')
                tltSellOrder = rh.place_immediate_market_order(
                    tltInstrumentUrl, 'TLT', 'gfd', -tltRequired, 'sell')
                print(tltSellOrder)

                orderOutcome = 'unresolved'

                while orderOutcome != 'resolved':
                    remainingUnresolved = False
                    orderResponse = rh.check_order_status(tltSellOrder['url'])
                    if orderResponse == 'unresolved':
                        remainingUnresolved = True
                    if not remainingUnresolved:
                        orderOutcome = 'resolved'
                    else:
                        print('remaining unresolved tltSell, waiting')
                        message += '\nremaining unresolved tltSell, waiting'
                        time.sleep(60)

                if orderResponse == 'failure':
                    success = False

        if not success:
            print('unable to sell required tlt')
            message += '\nunable to sell required tlt'

        #buy positions
        if success:
            if spyRequired > 0.0:
                print('buying ', spyRequired, ' of SPY')
                spyBuyOrder = rh.place_immediate_market_order(
                    spyInstrumentUrl, 'SPY', 'gfd', spyRequired, 'buy',
                    round(spyBuyPrice, 3))
                print(spyBuyOrder)

                orderOutcome = 'unresolved'

                while orderOutcome != 'resolved':
                    remainingUnresolved = False
                    orderResponse = rh.check_order_status(spyBuyOrder['url'])
                    if orderResponse == 'unresolved':
                        remainingUnresolved = True
                    if not remainingUnresolved:
                        orderOutcome = 'resolved'
                    else:
                        print('remaining unresolved spyBuy, waiting')
                        message += '\nremaining unresolved spyBuy, waiting'
                        time.sleep(60)

                if orderResponse == 'failure':
                    success = False
        if not success:
            print('unable to buy required spy')
            message += '\nunable to buy required spy'

        if success:
            if tltRequired > 0.0:
                print('buying ', tltRequired, ' of TLT')
                tltBuyOrder = rh.place_immediate_market_order(
                    tltInstrumentUrl, 'TLT', 'gfd', tltRequired, 'buy',
                    round(tltBuyPrice, 3))
                print(tltBuyOrder)

                orderOutcome = 'unresolved'

                while orderOutcome != 'resolved':
                    remainingUnresolved = False
                    orderResponse = rh.check_order_status(tltBuyOrder['url'])
                    if orderResponse == 'unresolved':
                        remainingUnresolved = True
                    if not remainingUnresolved:
                        orderOutcome = 'resolved'
                    else:
                        print('remaining unresolved tltBuy, waiting')
                        message += '\nremaining unresolved tltBuy, waiting'
                        time.sleep(60)

                if orderResponse == 'failure':
                    success = False

        if not success:
            print('unable to buy required tlt')
            message += '\nunable to buy required tlt'

        if success:
            success = rh.logout()
        if not success:
            print('unable to logout')
            message += '\nunable to logout'
        else:
            print('succesfully logged out')
            message += '\nsuccesfully logged out'
        send_email(mailgun_domain, mailgun_api_key, diag_email_dest,
                   ('resiliant-trader log ' + str(datetime.datetime.now())),
                   message)
    except Exception as e:
        print("Unexpected error:", str(e))
        send_email(mailgun_domain, mailgun_api_key, diag_email_dest,
                   ('resiliant-trader log ' + str(datetime.datetime.now())),
                   ("Unexpected error: " + str(e)))
        raise