Creating an application to pull stock data from yfinance

Working on creating a dataframe from pulled data from yahoo finance. Can’t seem to resolve the IndexError: index 10 is out of bounds for axis 0 with size 10

Any help is appreciated

import datetime
import pandas as pd
import yfinance as yf

# Allow the full width of the data frame to show.
pd.set_option('display.max_columns', None)
pd.set_option('display.width', 1000)


def getStock(stk, date_dif):
    # Set and show dates
    dt = datetime.date.today()
    dtPast = dt + datetime.timedelta(days=-date_dif)
    
    
    df = yf.download(stk,
        start=datetime.datetime(dtPast.year, dtPast.month, dtPast.day),
        end=datetime.datetime(dt.year, dt.month, dt.day), interval="1d")

    start = datetime.datetime(dtPast.year, dtPast.month, dtPast.day)
    end = datetime.datetime(dt.year, dt.month, dt.day)
    print('************************************************************')
    print()
    print('Daily Percent Changes -', str(dt), "to", str(dtPast), '*', stk.upper(), '*')
    print()
    print('************************************************************')

    return df

def percent_change(prev, curr):
    per_change = (curr - prev) / prev

    return per_change

def overall_change(start, end):
    overall = (end - start) /  start

    return overall


option = ''
while option != '2':
    print("************************************************************")
    print()
    print("Stock Report Menu Options")
    print()
    print("************************************************************")
    print("1. Report changes for a stock")
    print('2. Quit')
    option = input()

    if option == '1':
       symbol = input('Please enter the stock symbol:\n')
       num_of_days = int(input('Please enter the number of days for the analysis:\n'))
       df = getStock(symbol.upper(), num_of_days)
       column_names = ['Close', 'Volume', 'Volume % Change', 'Close % Change']

       # Define empty data frame structure.
       stock_dat = pd.DataFrame(columns=column_names)
       for i in range(num_of_days):
            if i != 0:
                # Add rows of data.
                stock_dat =  stock_dat.append({'Close': df.iat[i, 3],
                                               'Volume': df.iat[i, 5],
                                               'Volume % Change': round(percent_change(df.iat[i - 1, 5], 
                                                                     df.iat[i, 5]), 4),
                                               'Close % Change': round(percent_change(df.iat[i - 1, 3], 
                                                                     df.iat[i, 3]), 4)},
                                             ignore_index=True
                                            )
                stock_dat.reset_index(drop=True)
                stock_dat.reindex_like(df)

            else:
                stock_dat =  stock_dat.append({'Close': df.iat[i, 3],
                                             'Volume': df.iat[i, 5],
                                             'Volume % Change': 0.0000,
                                             'Close % Change': 0.0000},
                                             ignore_index=True
                                             )
                stock_dat.reset_index(drop=True)
                stock_dat.reindex_like(df)
    print(stock_dat)


    dt = datetime.date.today()
    dtPast= dt - datetime.timedelta(days= -num_of_days)

    print("------------------------------------------------------------")
    print('Summary of Cumulative Changes for ' + symbol.lower())
    print("------------------------------------------------------------")
    print(str(dt), 'to', str(dtPast))
    close_overall = overall_change(start=df['Close'][0], end=['Close'][num_of_days - 1])
    vol_overall =  overall_change(start=df['Volume'][0], end=['Volume'][num_of_days - 1])
    print("% Volume Change:     ", flush=True)
    print(round(vol_overall, 3))
    print("% Close Price Change:", flush=True)
    print(round(close_overall, 3))

1 Like

When you ask for help on a problem like this, it is very handy to give us all the data Python gives you to solve the problem. The data starts with the word “Traceback”, end with the error and tells you how your program failed.

In this case I guess it is because you enter a number_of_days greater than 10. When i is 10, it will fail, because there is no such row in your dataframe: index 10 is out of bounds for axis 0 with size 10.

1 Like

I would guess that’s you have counted to 10, but the axis is numbered
0 through to 9. Your code seems well aware that indices start from 0, so
i would guess there’s some place where you have neglected to allow for
that, or where you have accidentally counted too far (eg 11 iterations
for a 10 item thing).

However, while you have supplied your code you have not supplied the
full traceback, which is critical for knowing where the error occurred.

Cheers,
Cameron Simpson cs@cskk.id.au

1 Like

Thank you! The full traceback is:

Traceback (most recent call last):

File “C:\Users\mairi\Downloads\untitled3.py”, line 63, in
stock_dat = stock_dat.append({‘Close’: df.iat[i, 3],

File “C:\Users\mairi\Anaconda3\lib\site-packages\pandas\core\indexing.py”, line 2103, in getitem
return self.obj._get_value(*key, takeable=self._takeable)

File “C:\Users\mairi\Anaconda3\lib\site-packages\pandas\core\frame.py”, line 3127, in _get_value
return series._values[index]

IndexError: index 10 is out of bounds for axis 0 with size 10

I would also like to note that the number of rows in the df could be anything as the second question for user input is how many days they want to pull data from yahoo.

Thank you!

1 Like

Updated code to simplify, but still getting an error on defining the dataframe :confused:

import datetime
import pandas as pd
import yfinance as yf

# Allow the full width of the data frame to show.
pd.set_option('display.max_columns', None)
pd.set_option('display.width', 1000)

def getStock(stk, date_dif):
    # Set and show dates
    dt = datetime.date.today()
    dtPast = dt + datetime.timedelta(days=-date_dif)
    df = yf.download(stk,
                     start=datetime.datetime(dtPast.year, dtPast.month, dtPast.day),
                     end=datetime.datetime(dt.year, dt.month, dt.day), interval="1d")

    start = datetime.datetime(dtPast.year, dtPast.month, dtPast.day)
    end = datetime.datetime(dt.year, dt.month, dt.day)
    print('************************************************************')
    print()
    print('Daily Percent Changes -', str(dt), "to", str(dtPast), '*', stk.upper(), '*')
    print()
    print('************************************************************')
    return df

def percent_change(prev, curr):
    per_change = (curr - prev) / prev
    return per_change

def overall_change(start, end):
    overall = (end - start) / start
    return round(overall, 2) # Placed round here.

option = ''
while option != '2':
    print("************************************************************")
    print()
    print("Stock Report Menu Options")
    print()
    print("************************************************************")
    print("1. Report changes for a stock")
    print('2. Quit')
    option = input()
 
    if option == '1':
        symbol = input('Please enter the stock symbol:\n')
        num_of_days = int(input('Please enter the number of days for the analysis:\n'))
        df = getStock(symbol.upper(), num_of_days)
        column_names = ['Close', 'Volume', 'Volume % Change', 'Close % Change']
 
        # Define empty data frame structure.
        stock_dat = pd.DataFrame()
 
        # The count starts at 0 and this is okay since
        # the 'if' statement handles it later.
        for i in range(0, len(df)): # We really want to iterate
                                    # through all rows of the dataframe.
            if i != 0:
                  # There is no need to re-index.
                  # stock_dat.reindex_like(df) # Removed.
                  # Add rows of data.
                  # To avoid overly complex instructions it helps to break up the
                  # instructions into multiple (and simpler) steps.
                  currentVolume       = df.iloc[i]['Volume']
                  pastVolume          = df.iloc[i-1]['Volume']
                  volumePercentChange = percent_change(pastVolume, currentVolume)
 
                  stock_dat = stock_dat.append({'Close': df.iloc[i]['Close'],
                                              'Volume': df.iloc[i]['Volume'],
                                              'Volume % Change': volumePercentChange},
                                                ignore_index=True
                                             )
            else:
                  print("This condition needs to be added back once things are working.")
        print(stock_dat)
1 Like

I’ve since worked on the code to try and add the summary, but keep getting an error on the list index being out of range…help!

Traceback (most recent call last):

File “C:\Users\mairi\Downloads\untitled3.py”, line 89, in
close_overall = overall_change(start=df[‘Close’][0], end=[‘Close’][num_of_days - 1])

IndexError: list index out of range

import datetime
import pandas as pd
import yfinance as yf

# Allow the full width of the data frame to show.
pd.set_option('display.max_columns', None)
pd.set_option('display.width', 1000)


def getStock(stk, date_dif):
    # Set and show dates
    dt = datetime.date.today()
    dtPast = dt + datetime.timedelta(days=-date_dif)
    
    
    df = yf.download(stk,
        start=datetime.datetime(dtPast.year, dtPast.month, dtPast.day),
        end=datetime.datetime(dt.year, dt.month, dt.day), interval="1d")

    start = datetime.datetime(dtPast.year, dtPast.month, dtPast.day)
    end = datetime.datetime(dt.year, dt.month, dt.day)
    print('************************************************************')
    print()
    print('Daily Percent Changes -', str(dt), "to", str(dtPast), '*', stk.upper(), '*')
    print()
    print('************************************************************')
    return df

def percent_change(prev, curr):
    per_change = (curr - prev) / prev
    return per_change

def overall_change(start, end):
    overall = (start - end) /  end
    return overall

option = ''
while option != '2':
    print("************************************************************")
    print()
    print("Stock Report Menu Options")
    print()
    print("************************************************************")
    print("1. Report changes for a stock")
    print('2. Quit')
    option = input()

    if option == '1':
       symbol = input('Please enter the stock symbol:\n')
       num_of_days = int(input('Please enter the number of days for the analysis:\n'))
       df = getStock(symbol.upper(), num_of_days)
       column_names = ['Date', 'Close', 'Volume', 'Volume % Change', 'Close % Change']

       # Define empty data frame structure.
       stock_dat = pd.DataFrame(columns=column_names)
    for i in range(0, len(df)):
        if i != 0:
            currentVolume       = df.iloc[i]['Volume']
            pastVolume          = df.iloc[i-1]['Volume']
            volumePercentChange = percent_change(pastVolume, currentVolume)
            currentClose      = df.iloc[i]['Close']
            pastClose          = df.iloc[i-1]['Close']
            closePercentChange = percent_change(pastClose, currentClose)
            stock_dat = stock_dat.append({'Close': df.iloc[i]['Close'],
                                        'Volume': df.iloc[i]['Volume'],
                                        'Volume % Change': volumePercentChange,
                                        'Close % Change' : closePercentChange},
                                        ignore_index=True
                                        )
        else:
            stock_dat =  stock_dat.append({'Close': df.iloc[i, 3],
                                         'Volume': df.iloc[i, 5],
                                         'Volume % Change': 0.0000,
                                         'Close % Change': 0.0000},
                                         ignore_index=True
                                         )
            stock_dat.reset_index(drop=True)
            stock_dat.reindex_like(df)
    print(stock_dat)


    dt = datetime.date.today()
    dtPast= dt - datetime.timedelta(days= -num_of_days)

    print("------------------------------------------------------------")
    print('Summary of Cumulative Changes for ' + symbol.upper())
    print("------------------------------------------------------------")
    print(str(dt), 'to', str(dtPast))
    close_overall = overall_change(start=df['Close'][0], end=['Close'][num_of_days - 1])
    vol_overall =  overall_change(start=df['Volume'][0], end=['Volume'][num_of_days - 1])
    print("% Volume Change:     ", flush=True)
    print(round(vol_overall, 3))
    print("% Close Price Change:", flush=True)
    print(round(close_overall, 3))

1 Like

I would at this point pull that line apart and inspect the pieces:

close_overall = overall_change(start=df['Close'][0], end=['Close'][num_of_days - 1])

Ah but on going to do that I see what looks like a syntax error but is
not:

df_close = df['Close']
print(df_close)
close_overall = overall_change(start=df['Close'][0], end=['Close'][num_of_days - 1])

Look at the “end=” argument:

end=['Close'][num_of_days - 1]

You’re missing the “df” of “df[‘Close’]”. So that is in fact a single
element list containing the string ‘Close’. That list is only 1 element
long!

Note that this becomes obvious as soon as you start pulling the
expression apart. Gogin to do the “end=” bit piece by piece it starts
with:

['Close']

and the probem is clear.

Cheers,
Cameron Simpson cs@cskk.id.au

2 Likes