Example #1
0
    def test_getLastWorkDay(self):
        '''run some local code'''
        now = dt.datetime.today()
        # fmt = "%a, %B %d"

        for i in range(7):
            d = now - dt.timedelta(i)
            dd = util.getLastWorkDay(d)

            # print(f'{d.strftime(fmt)} ... : ... {util.getLastWorkDay(d).strftime(fmt)}')
            self.assertTrue(dd.isoweekday() < 6)
            self.assertTrue(dd.isoweekday() > 0)
Example #2
0
    def test_apiChooser(self):
        '''
        Test the method FinPlot.apiChooser for the same interface in each api
        '''
        chooser = APIChooser(self.apiset)
        yesterday = dt.datetime.today() - dt.timedelta(1)
        biz = util.getLastWorkDay(yesterday)
        start = dt.datetime(biz.year, biz.month, biz.day, 12, 30)
        end = dt.datetime(biz.year, biz.month, biz.day, 16, 1)
        minutes = 1
        apis = chooser.preferences
        symbol = 'SQ'
        for api in apis:
            chooser.api = api
            result = chooser.apiChooserList(start, end, api)
            if result[0]:
                dummy, df, maDict = chooser.apiChooser()(symbol,
                                                         start=start,
                                                         end=end,
                                                         minutes=minutes,
                                                         showUrl=True)
                self.assertEqual(
                    len(df.columns), 5,
                    f"Failed to retrieve data with the {chooser.api} api.")
                self.assertTrue(
                    isinstance(df.index[0], dt.datetime),
                    f'Failed to set index to datetime in {chooser.api} api')
                cols = ['open', 'high', 'low', 'close', 'volume']
                for col in cols:
                    # print(col, type(df[col][0]), isinstance(df[col][0], (np.float, np.integer)))
                    self.assertTrue(col in df.columns)
                    self.assertTrue(
                        isinstance(df[col][0], (np.float, np.integer)))

                # This call should retrieve data within 1 bar of the requested start and finish.
                # Idiosyncracies of the APIs vary as to inclusion of first and last time index
                delt = df.index[0] - \
                    start if df.index[0] > start else start - df.index[0]
                self.assertLessEqual(delt.seconds, minutes * 60)

                # print('Retrieved {} candles from {} to {} for {}'.format(
                #     len(df), df.index[0], df.index[-1], symbol))
                # print()
            else:
                print(f'Skipped {api} at {start} to {end} because...')
                for rule in result[1]:
                    print(rule)
Example #3
0
def getib_intraday(symbol, start=None, end=None, minutes=1, showUrl='dummy', key=None):
    '''
    An interface API to match the other getters. In this case its a substantial
    dumbing down of the capabilities to our one specific need. Output will be resampled
    if necessary to return a df with intervals 1~60 minutes
    :params symbol: The stock to get
    :params start: A timedate object or time string for when to start. Defaults to the most recent
        weekday at open.
    :params end: A timedate object or time string for when to end. Defaults to the most recent biz
        day at close
    :params minutes: The length of the candle, 1~60 minutes. Defaults to 1 minute
    :return (length, df):A DataFrame of the requested stuff and its length
    '''
    apiset = QSettings('zero_substance/stockapi', 'structjour')
    if not apiset.value('gotibapi', type=bool):
        return {'message': 'ibapi is not installed', 'code': 666}, pd.DataFrame(), None
    logging.info('***** IB *****')
    biz = getLastWorkDay()
    if not end:
        end = pd.Timestamp(biz.year, biz.month, biz.day, 16, 0)
    if not start:
        start = pd.Timestamp(biz.year, biz.month, biz.day, 9, 30)
    start = pd.Timestamp(start)
    end = pd.Timestamp(end)

    dur = ''
    fullstart = end
    fullstart = fullstart - pd.Timedelta(days=5)
    if start < fullstart:
        delt = end - start
        fullstart = end - delt

    if (end - fullstart).days < 1:
        if ((end - fullstart).seconds // 3600) > 8:
            dur = '2 D'
        else:
            dur = f'{(end-fullstart).seconds} S'
    elif (end - fullstart).days < 7:
        dur = f'{(end-fullstart).days + 1} D'
    else:
        dur = f'{(end-fullstart).days} D'
        # return 0, pd.DataFrame([], [])

    # if the end = 9:31 and dur = 3 minutes, ib will retrieve a start of the preceding day @ 15:58
    # This is unique behavior in implemeted apis. We will just let ib do whatever and cut off any
    # data prior to the requested data. In that we get no after hours, a request for 7 will begin
    # at 9:30 (instead of the previous day at 1330)

    symb = symbol
    (resamp, (interval, minutes, origminutes)) = ni(minutes)

    # ib = TestApp(7496, 7878, '127.0.0.1')
    # ib = TestApp(4002, 7979, '127.0.0.1')
    x = IbSettings()
    ibs = x.getIbSettings()
    if not ibs:
        return 0, pd.DataFrame(), None
    ib = TestApp(ibs['port'], ibs['id'], ibs['host'])
    df = ib.getHistorical(symb, end=end, dur=dur, interval=interval, exchange='NASDAQ')
    lendf = len(df)
    if lendf == 0:
        return 0, df, None

    # Normalize the date to our favorite format
    df.index = pd.to_datetime(df.index)
    if resamp:
        srate = f'{origminutes}T'
        df_ohlc = df[['open']].resample(srate).first()
        df_ohlc['high'] = df[['high']].resample(srate).max()
        df_ohlc['low'] = df[['low']].resample(srate).min()
        df_ohlc['close'] = df[['close']].resample(srate).last()
        df_ohlc['volume'] = df[['volume']].resample(srate).sum()
        df = df_ohlc.copy()

    maDict = movingAverage(df.close, df, end)

    if start > df.index[0]:
        msg = f"Cutting off beginning: {df.index[0]} to begin at {start}"
        logging.info(msg)
        df = df.loc[df.index >= start]
        if not df.high.any():
            logging.warning('All data has been removed')
            return 0, pd.DataFrame(), None
        for ma in maDict:
            maDict[ma] = maDict[ma].loc[maDict[ma].index >= start]
    removeMe = list()
    for key in maDict:
        # VWAP is a reference that begins at market open. If the open trade precedes VWAP
        # we will exclude it from the chart. Other possibilities: give VWAP a start time or
        # pick an arbitrary premarket time to begin it. The former would be havoc to implement
        # the latter probably better but inaccurate; would not reflect what the trader was using
        # Better suggestions?
        if key == 'vwap':
            if len(maDict['vwap']) < 1 or (df.index[0] < maDict['vwap'].index[0]):
                removeMe.append(key)
                # del maDict['vwap']
        else:
            if len(df) != len(maDict[key]):
                removeMe.append(key)
                # del maDict[key]
    for key in removeMe:
        del maDict[key]

    ib.disconnect()
    return len(df), df, maDict
Example #4
0
    def test_getmav_intraday(self, count=None):
        '''
        This will provide time based failures on market holidays. If you are woking on a holiday,
        it serves you right :)
        '''

        biz = util.getLastWorkDay()
        bizMorn = dt.datetime(biz.year, biz.month, biz.day, 7, 0)
        bizAft = dt.datetime(biz.year, biz.month, biz.day, 16, 1)
        bef = util.getLastWorkDay(bizMorn - dt.timedelta(1))
        befAft = dt.datetime(bef.year, bef.month, bef.day, 16, 1)
        specificStart = dt.datetime(biz.year, biz.month, biz.day, 9, 37)
        specificEnd = dt.datetime(biz.year, biz.month, biz.day, 11, 37)
        longBef = util.getLastWorkDay(bizMorn - dt.timedelta(10))
        # longBefAft = dt.datetime(longBef.year, longBef.month, longBef.day, 16, 1)

        # dateArray = [(biz, bizAft), (biz, None), (None, bizAft) ]
        minutes = 2

        dateArray = [(bizMorn, bizAft),
                     (bizMorn, None),
                     (bef, befAft),
                     (specificStart, specificEnd),
                     (befAft, None),
                     (longBef, None),
                     (None, None)]
        # dateArray2 = [(bizAft, None)]
        # now = pd.Timestamp.today()

        # Prevent more than 5 calls per minute, sleep after 5 for the remainder
        nextt = time() + 80
        # count = 0
        for start, end in dateArray:

            # Each of these should get results every time,beginning times are either before 9:31 or
            # between 9:30 (short days won't produce failures)
            dummy, df, maDict = mav.getmav_intraday("SQ", start=start, end=end,
                                            minutes=minutes, showUrl=True)

            # print("Requested...", start, end)
            # print("Received ...", df.index[0], df.index[-1])
            # print("     ", len(df))
            if df is None:
                continue
            self.assertGreater(len(df), 0)

            if not start and not end:
                # This will retrieve the full set available. It should cover 5 days data.
                #  We will just test that the results cover 4 days and ends on the last biz day.
                # We are at the mercy of AV-- if they change, this should fail. (that's good)
                lt = df.index[-1]
                self.assertGreater((lt - df.index[0]).days, 3)
                lastDay = dt.datetime(lt.year, lt.month, lt.day)
                bizDay = pd.Timestamp(biz.year, biz.month, biz.day)
                self.assertEqual(lastDay, bizDay)
                start = df.index[0]

            # If the requested start time is before 9:31, start should be 9:31
            d = df.index[0]
            expected = dt.datetime(d.year, d.month, d.day, 9, 30)
            if start < expected:
                self.assertEqual(d, expected)
            else:
                # The start should be within the amount of the candle length
                # if d != start:
                delt = pd.Timedelta(minutes=minutes)
                delt2 = d - start if d > start else start - d
                self.assertLessEqual(delt2, delt)

            # Could add some tests for what happens when request is for today during market hours

            if count[0] % 5 == 4:
                # After 5 calls, sleep. 5 calls per minute is the max for the free API
                newnextt = nextt - time()
                nx = max(int(newnextt), 80)
                print(f'''Waiting for {nx} seconds. 5 calls per minute max
                       from AVantage free API''')
                if newnextt < 0:
                    # It took a minute plus to get through those 5 calls- reset for the next 5
                    nextt = time() + 80
                    count[0] += 1
                    continue
                nextt = newnextt
                sleep(nextt)

            count[0] += 1
Example #5
0
    def test_getbc_intraday(self):
        '''
        This API will not retrieve todays data until 15 minutes after close. It may not retrieve
        all of yesterday till after close today
        '''

        # def test_getbc_intraday(self):
        now = dt.datetime.today()
        nowbiz = util.getLastWorkDay(
        )  # We want to retrieve a day with data for testing here
        bizclose = pd.Timestamp(nowbiz.year, nowbiz.month, nowbiz.day, 16, 0)
        tomorrow = now + dt.timedelta(1)
        y = now - dt.timedelta(1)
        ymorn = dt.datetime(y.year, y.month, y.day, 7, 30)
        yaft = dt.datetime(y.year, y.month, y.day, 17, 30)
        ymorn = getPrevTuesWed(ymorn)
        yaft = getPrevTuesWed(yaft)
        beginDay = dt.datetime(now.year, now.month, now.day, 9, 30)
        endDay = dt.datetime(now.year, now.month, now.day, 16, 0)

        # These should all retrieve the same data. unless the day is today before 4:30. No start
        # date and today trigger a 1day query
        # for the most current biz day (which may be yesterday if its before 16:30 on Tuesday)
        dateArray = [(None, None), (beginDay, None), (None, endDay),
                     (beginDay, endDay), (None, tomorrow), (ymorn, yaft),
                     (None, yaft), (ymorn, None)]  # Same as both None

        dateArray2 = [(ymorn, None), (ymorn, yaft)]

        # These should retrive 0 results with no Exception
        dateArray3 = [(None, yaft), (tomorrow, None)]

        # edays=list()
        interval = 5
        for start, end in dateArray:
            x, df, maList = bc.getbc_intraday('SQ',
                                              start=start,
                                              end=end,
                                              showUrl=True)
            if x['code'] == 666:
                print('Abandon all hope of retrieving barchart data today.\n',
                      'You have run out of free queries until midnight')
                return

            if not start or start.date() == now.date():
                # Retrieveing todays will retrieve butkis until the magictime
                mt = util.getLastWorkDay()

                # 4:45 EST = 2:45 MST
                magictime = pd.Timestamp(mt.year, mt.month, mt.day, 14, 45)
                if now < magictime:
                    msg = 'This query should be empty because barchart does not retrieve todays'
                    msg += 'data till after close. If its not empty, either we are in the cracks.'
                    msg += '(wait a minute), or something is wrong (probably with the code).'
                    self.assertTrue(df.empty, msg)
                    continue

            else:
                self.assertGreater(len(df), 0)

            # Given start == None, barchart returns data from previous weekday (holidays ignored)
            now = pd.Timestamp.today()
            if not start and not df.empty:
                start = df.index[0]

                if now.isoweekday() > 5:
                    self.assertLess(df.index[0].isoweekday(), 6,
                                    "Is it a holiday? Go party now!")
            if not start:
                start = now
            if start and end and start > end or start > bizclose:
                assert df.empty
                continue

            s = pd.Timestamp(start.year, start.month, start.day, 9, 29)
            e = pd.Timestamp(start.year, start.month, start.day, 16, 1)
            if start > s and start < e:
                self.assertEqual(df.index[0], start)

            msg = f'\nInput: {end} \nTest:  <> {e} \nIndex{df.index[-1]}'
            # print(msg)
            # Very internal noodly but barchart last index is always the next to the last time aka end - interval
            if end and end > s and end < e:
                # end2 = end - pd.Timedelta(minutes=interval)
                msg = f'\nInput: {end} \nTest:  {e} \nIndex: {df.index[-1]}'
                delt = df.index[-1] - end if df.index[
                    -1] > end else end - df.index[-1]

                self.assertLessEqual(int(delt.total_seconds()), interval * 60)
                # self.assertEqual(df.index[-1], end2, msg)

        for start, end in dateArray2:
            x, df, maList = bc.getbc_intraday('SQ', start=start, end=end)
            self.assertGreater(len(df), 0)

        for start, end in dateArray3:
            x, df, maList = bc.getbc_intraday('SQ', start=start, end=end)
            # print(df)
            # print(len(df.index))
            print(x['message'])
            self.assertEqual(len(df), 0)
Example #6
0
def getbc_intraday(symbol,
                   start=None,
                   end=None,
                   minutes=5,
                   showUrl=False,
                   key=None):
    '''
    Note that getHistory will return previous day's prices until 15 minutes after the market
        closes. We will generate a warning if our start or end date differ from the date of the
        response. Given todays date at 14:00, it will retrive the previous business days stuff.
        Given not start parameter, we will return data for the last weekday. Today or earlier.
        We will return everything we between start and end. It may be incomplete.
        Its now limiting yesterdays data. At 3:00, the latest I get is yesterday
        up to 12 noon.
    Retrieve candle data measured in minutes as given in the minutes parameter
    :params start: A datetime object or time string to indicate the begin time for the data. By
        default, start will be set to the most recent weekday at market open.
    :params end: A datetime object or time string to indicate the end time for the data
    :params minutes: An int for the candle time, 5 minute, 15 minute etc
    :return (status, data): A tuple of (status as dictionary, data as a DataFrame ) This status is
        seperate from request status_code.
    :raise: ValueError if response.status_code is not 200.
    '''
    if getLimitReached('bc'):
        msg = 'BarChart limit was reached'
        logging.info(msg)
        return {'code': 666, 'message': msg}, pd.DataFrame(), None

    logging.info(
        '======= Called Barchart -- 150 call limit, data available after market close ======='
    )
    if not end:
        tdy = dt.datetime.today()
        end = dt.datetime(tdy.year, tdy.month, tdy.day, 17, 0)
    # end

    if not start:
        tdy = dt.datetime.today()
        start = dt.datetime(tdy.year, tdy.month, tdy.day, 6, 0)
        start = getLastWorkDay(start)
    end = pd.to_datetime(end)
    start = pd.to_datetime(start)
    # startDay = start.strftime("%Y%m%d")

    # Get the maximum data in order to set the 200 MA on a 60 minute chart
    fullstart = pd.Timestamp.today()
    fullstart = fullstart - pd.Timedelta(days=40)
    fullstart = fullstart.strftime("%Y%m%d")

    params = setParams(symbol, minutes, fullstart, key=key)

    response = requests.get(BASE_URL, params=params)
    if showUrl:
        logging.info(response.url)

    if response.status_code != 200:
        raise Exception(
            f"{response.status_code}: {response.content.decode('utf-8')}")
    meta = {'code': 200}
    if (response.text and isinstance(response.text, str)
            and response.text.startswith('You have reached')):
        d = pd.Timestamp.now()
        dd = pd.Timestamp(d.year, d.month, d.day + 1, 3, 0, 0)
        setLimitReached('bc', dd)

        logging.warning(f'API max queries: {response.text}')
        meta['message'] = response.text
        return meta, pd.DataFrame(), None

    result = response.json()
    if not result['results']:
        logging.warning(
            '''Failed to retrieve any data. Barchart sends the following greeting: {result['status']}'''
        )
        return result['status'], pd.DataFrame(), None

    meta['message'] = result['status']['message']
    df = pd.DataFrame(result['results'])

    for i, row in df.iterrows():
        d = pd.Timestamp(row['timestamp'])
        newd = pd.Timestamp(d.year, d.month, d.day, d.hour, d.minute, d.second)
        df.at[i, 'timestamp'] = newd

    df.set_index(df.timestamp, inplace=True)
    df.index.rename('date', inplace=True)
    maDict = movingAverage(df.close, df, start)

    if start > df.index[0]:
        rstart = df.index[0]
        rend = df.index[-1]
        df = df.loc[df.index >= start]
        for ma in maDict:
            maDict[ma] = maDict[ma].loc[maDict[ma].index >= start]

        lendf = len(df)
        if lendf == 0:
            msg = '\nWARNING: all data has been removed.'
            msg = msg + f'\nThe Requested start was({start}).'
            msg = msg + f'\nBarchart returned data beginning {rstart} and ending {rend}'
            msg += '''If you are seeking a chart from today, its possible Barchart has not made'''
            msg += 'the data available yet. (Should be available by 4:45PM but they are occasionally late)'
            msg += 'You can copy the image yourself, wait, or try a different API. Open File->StockAPI'
            logging.warning(msg)
            meta['code2'] = 199
            meta['message'] = meta['message'] + msg
            return meta, df, maDict

    if end < df.index[-1]:
        df = df.loc[df.index <= end]
        for ma in maDict:
            maDict[ma] = maDict[ma].loc[maDict[ma].index <= end]

        # If we just sliced off all our data. Set warning message
        lendf = len(df)
        if lendf == 0:
            msg = '\nWARNING: all data has been removed.'
            msg = msg + f'\nThe Requested end was({end}).'
            meta['code2'] = 199
            meta['message'] = meta['message'] + msg
            logging.warning(f'{meta}')
            return meta, df, maDict

    deleteMe = list()
    for key in maDict:
        if key == 'vwap':
            continue
        if len(df) != len(maDict[key]):
            deleteMe.append(key)
    for key in deleteMe:
        del maDict[key]

    # Note we are dropping columns  ['symbol', 'timestamp', 'tradingDay[] in favor of ohlcv
    df = df[['open', 'high', 'low', 'close', 'volume']].copy(deep=True)
    return meta, df, maDict
Example #7
0
    def test_getib_intraday(self):
        '''
        This will provide time based failures on market holidays. If you are woking on a holiday,
        it serves you right :)
        '''
        msg = '''

            IB is not connected. To continue connect IB Gateway.
            'test_getib_intraday cannont runMyib cannot run.
            '''
        if not ib.isConnected():
            msg = '''

            IB is not connected. To continue connect IB Gateway.
            'test_getib_intraday cannont runMyib cannot run.
            '''
            print(msg)
            return

        self.assertTrue(ib.isConnected(), msg)

        biz = util.getLastWorkDay()
        bizMorn = dt.datetime(biz.year, biz.month, biz.day, 7, 0)
        bizAft = dt.datetime(biz.year, biz.month, biz.day, 16, 1)
        bef = util.getLastWorkDay(bizMorn - dt.timedelta(1))
        befAft = dt.datetime(bef.year, bef.month, bef.day, 16, 1)
        specificStart = dt.datetime(biz.year, biz.month, biz.day, 9, 37)
        specificEnd = dt.datetime(biz.year, biz.month, biz.day, 11, 37)
        longBef = util.getLastWorkDay(bizMorn - dt.timedelta(10))

        dateArray = [(bizMorn, bizAft), (bizMorn, None), (bef, befAft),
                     (specificStart, specificEnd), (befAft, None),
                     (longBef, None), (None, None)]

        for start, end in dateArray:
            minutes = random.randint(1, 10)

            # Each of these should get results every time,beginning times are either before 9:31 or
            # between 9:30 (short days won't produce failures)
            lendf, df, maDict = ib.getib_intraday("SQ",
                                                  start=start,
                                                  end=end,
                                                  minutes=minutes,
                                                  showUrl=True)
            if lendf == 0:
                continue

            print("Requested...", start, end)
            print("Received ...", df.index[0], df.index[-1])
            print("     ", lendf)
            if not start:
                start = df.index[0]

            self.assertGreater(lendf, 0)
            delt = int((df.index[1] - df.index[0]).total_seconds() / 60)
            self.assertEqual(delt, minutes)

            # If the requested start time is before 9:30, start should be 9:30
            # This is no longer true. IB retrieves pre and post
            d = df.index[0]
            # expected = dt.datetime(d.year, d.month, d.day, 9, 30)

            # # With resampled data, the alignment could be up to a candle interval away,
            # if start < expected:
            #     delt = expected - d if expected > d else d - expected
            #     self.assertLessEqual(delt.total_seconds(), minutes * 60)
            # else:
            # The start should be within the amount of the candle length
            # WARNING afterhours data was assumed when theses tests were created.  If afterhours
            # is not set  in settings, there will be failures here. At some point, ccould update the
            # tests ... for now just keep after hours data
            if d != start:
                # Can't tell with pre market data-- it may just start later than requested
                if start.time() < dt.time(9, 30):
                    delt = (pd.Timestamp('9:30') -
                            pd.Timedelta(minutes=minutes)).time()
                    delt2 = (d - pd.Timedelta(minutes=minutes)).time()
                    self.assertLessEqual(delt2, delt)
                    continue

                delt = pd.Timedelta(minutes=minutes)
                delt2 = d - start if d > start else start - d
                self.assertLessEqual(delt2, delt)
Example #8
0
def getWTD_intraday(symbol, start=None, end=None, minutes=5, showUrl=False):
    '''
    Implement the interface to retrieve intraday data. showUrl is not part of this api.
    Note that the requested range will always be the maximum to get the maximum size MA.
    :symbol: The ticker symbol
    :start: Timestamp or time string. The beginning of requested data
    :end: Timestamp or time string. The end of requested data
    :minutes: int between 1 and 60
    :showUrl: not used
    :return: meta, df, maDict
    :depends: On the settings of 'zero_substance/chart' for moving average settings
    '''
    # Intraday base differs from others. It has the intrday subdomain instead of api subdomain
    if getLimitReached('wtd'):
        msg = 'World Trade Data limit was reached'
        logging.info(msg)
        return {'code': 666, 'message': msg}, pd.DataFrame(), None

    logging.info(
        '======= called WorldTradingData. 25 calls per day limit =======')
    base = 'https://intraday.worldtradingdata.com/api/v1/intraday?'

    original_minutes = minutes
    if not isinstance(original_minutes, int):
        original_minutes = 5
    minutes = ni(minutes)
    if not isinstance(minutes, int) or minutes < 0 or minutes > 60:
        raise ValueError(
            'Only candle intervals between 1 and 60 are supported')

    if not start:
        tdy = pd.Timestamp.now()
        tdy = getLastWorkDay(tdy)
        start = pd.Timestamp(tdy.year, tdy.month, tdy.day, 9, 25)
    else:
        start = pd.Timestamp(start)

    if not end:
        tdy = pd.Timestamp.now()
        tdy = getLastWorkDay(tdy)
        end = pd.Timestamp(tdy.year, tdy.month, tdy.day, 16, 5)
    else:
        end = pd.Timestamp(end)

    # Retrieve the maximum data to get the longest possible moving averages
    daRange = 30
    if minutes == 1:
        daRange = 7
    params = getParams(symbol, minutes, daRange)
    response = requests.get(base, params=params)

    meta = {'code': response.status_code}
    if response.status_code != 200:
        meta = {'code': 666, 'message': response.text}
        return meta, pd.DataFrame(), None
    result = response.json()
    if 'intraday' not in result.keys():
        if 'message' in result.keys():
            d = pd.Timestamp.now()
            dd = pd.Timestamp(d.year, d.month, d.day + 1, 3, 0, 0)
            setLimitReached('wtd', dd)
            logging.warning(
                f"WorldTradeData limit reached: {result['message']}")
            meta['message'] = result['message']
        else:
            meta['message'] = 'Failed to retrieve data from WorldTradingData'
        return meta, pd.DataFrame(), None

    if result['timezone_name'] != 'America/New_York':
        msg = f'''Time zone returned a non EST zone: {result['timezone_name']}'''
        raise ValueError(msg)
    meta['message'] = result['symbol'] + ': ' + result[
        'stock_exchange_short'] + ': ' + result['timezone_name']
    df = pd.DataFrame(data=result['intraday'].values(),
                      index=result['intraday'].keys())

    df.open = pd.to_numeric(df.open)
    df.high = pd.to_numeric(df.high)
    df.low = pd.to_numeric(df.low)
    df.close = pd.to_numeric(df.close)
    df.volume = pd.to_numeric(df.volume)

    df.index = pd.to_datetime(df.index)
    # resample for requested interval if necessary

    if original_minutes != minutes:
        srate = f'{original_minutes}T'
        df_ohlc = df[['open']].resample(srate).first()
        df_ohlc['high'] = df[['high']].resample(srate).max()
        df_ohlc['low'] = df[['low']].resample(srate).min()
        df_ohlc['close'] = df[['close']].resample(srate).last()
        df_ohlc['volume'] = df[['volume']].resample(srate).sum()
        df = df_ohlc.copy()

    # Get requested moving averages
    maDict = movingAverage(df.close, df, start)

    # Trim off times not requested
    if start > pd.Timestamp(df.index[0]):
        # rstart = df.index[0]
        # rend = df.index[-1]
        df = df.loc[df.index >= start]
        for ma in maDict:
            maDict[ma] = maDict[ma].loc[maDict[ma].index >= start]

        lendf = len(df)
        if lendf == 0:
            msg = '\nWARNING: all data has been removed.'
            msg += f'\nThe Requested start was({start}).'

            meta['code2'] = 199
            meta['message'] = meta['message'] + msg
            return meta, df, maDict

    if end < df.index[-1]:
        df = df.loc[df.index <= end]
        for ma in maDict:
            maDict[ma] = maDict[ma].loc[maDict[ma].index <= end]

        # If we just sliced off all our data. Set warning message
        lendf = len(df)
        if lendf == 0:
            msg = '\nWARNING: all data has been removed.'
            msg = msg + f'\nThe Requested end was({end}).'
            meta['code2'] = 199
            meta['message'] = meta['message'] + msg
            logging.error(f'{meta}')
            return meta, df, maDict

    # If we don't have a full ma, delete -- Later:, implement a 'delayed start' ma in graphstuff and remove this stuff
    keys = list(maDict.keys())
    for key in keys:
        if len(df) != len(maDict[key]):
            del maDict[key]

    # Note we are dropping columns  ['symbol', 'timestamp', 'tradingDay[] in favor of ohlcv
    df = df.copy(deep=True)
    return meta, df, maDict