Yahoo Finance: Pulling Options Chain

In one of my first posts, I showed how to pull the options chain using TD Ameritrade. This version will also get the options chain, but this time from Yahoo Finance. This is more of a webscraping solution.

A copy of the notebook can be found on my GitHub and the bulk of the code will be shown below.

The code below gets the tickers of the S&P 500 using Wikipedia. In addition, I provide an example of how additional tickers could also be used.

def get_tickers():
    sp_df = pd.read_html('https://en.wikipedia.org/wiki/List_of_S%26P_500_companies')[0]
    sp_tickers = list(sp_df['Symbol'])[:]

    other_tickers = ['SPY','QQQ']

    unique_tickers = sorted(list(set(sp_tickers + other_tickers)))
    
    return unique_tickers

The code below gets for the ticker(s)

  • The current price
  • The options chain for the next 12 expiration dates. I set it to 12, but it can be any number (or even not set)
def get_current_price(ticker):
    try:
        stock_info = yf.Ticker(ticker).info
        current_price = stock_info.get('ask') or stock_info.get('lastPrice')

        if current_price is not None:
            return current_price
        else:
            # If ask or lastPrice is not available, fetch today's closing price
            ticker_object = yf.Ticker(ticker)
            todays_data = ticker_object.history(period='1d')

            if not todays_data.empty and 'Close' in todays_data.columns:
                return todays_data['Close'][0]
            else:
                print(f"Warning: Unable to fetch current price for {ticker}.")
                return None

    except Exception as e:
        print(f"Error fetching current price for {ticker}: {str(e)}")
        return None



def get_options_chain(tickers):
    all_data = []

    for ticker in tickers:
        print (ticker)
        try:
            # Get the next 12 available expiration dates
            expiration_dates = yf.Ticker(ticker).options[:1]

            for expiration_date in expiration_dates:
                option_chain = yf.Ticker(ticker).option_chain(expiration_date)

                call_data = option_chain.calls
                put_data = option_chain.puts

                # Extract relevant information for calls
                call_info = call_data[['contractSymbol', 'strike', 'openInterest', 'volume', 'bid', 'ask']]
                call_info['type'] = 'Call'  # Add a column to specify call option

                # Extract relevant information for puts
                put_info = put_data[['contractSymbol', 'strike', 'openInterest', 'volume', 'bid', 'ask']]
                put_info['type'] = 'Put'  # Add a column to specify put option

                # Combine call and put information
                options_data = pd.concat([call_info, put_info], ignore_index=True)

                # Add 'Ticker' and 'ExpirationDate' columns to the DataFrame
                options_data['Ticker'] = ticker
                options_data['ExpirationDate'] = expiration_date

                # Fetch current price for the ticker
                current_price = get_current_price(ticker)

                if current_price is not None:
                    # Add current price to the DataFrame
                    options_data['CurrentPrice'] = current_price

                all_data.append(options_data)

        except Exception as e:
            print(f"Error fetching options data for {ticker}: {str(e)}")

    if all_data:
        return pd.concat(all_data, ignore_index=True)
    else:
        return None

The code below takes all of the results from the above and saves the results as csv with a standardized name

def save_combined_data_to_csv(combined_data, folder_path='Options_Data'):
    try:
        os.makedirs(folder_path, exist_ok=True)

        # Create a timestamp for the filename in military time format
        timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")

        # If 'CurrentPrice' column exists, format it to have 4 decimal places
        if 'CurrentPrice' in combined_data.columns:
            combined_data['CurrentPrice'] = combined_data['CurrentPrice'].apply(lambda x: f'{x:.4f}' if pd.notna(x) else x)

        # Save the DataFrame to a CSV file
        filename = f"{folder_path}/combined_data_{timestamp}.csv"
        combined_data.to_csv(filename, index=False)

        print(f"Data saved to {filename}")

    except Exception as e:
        print(f"Error saving combined data to CSV: {str(e)}")

Putting it all together and running the code every hour

# Run
def run_hourly_job(tickers):
    # Run the job immediately
    options_chain_df = get_options_chain(tickers)
    save_combined_data_to_csv(options_chain_df)

    while True:
        # Calculate the time until the next hour
        current_time = datetime.now()
        next_hour = current_time.replace(hour=current_time.hour + 1, minute=0, second=0,     microsecond=0)
        time_to_wait = (next_hour - current_time).total_seconds()

        # Wait until the next hour
        time.sleep(time_to_wait)

        # Run the job
        options_chain_df = get_options_chain(tickers)
        save_combined_data_to_csv(options_chain_df)


# List of tickers to monitor
tickers_to_monitor = get_tickers()

# Run the hourly job
run_hourly_job(tickers_to_monitor)

Sharing

Related Articles

  • All Post
  • Articles
  • Blog Post
  • General Business Automation
  • Portfolio
  • Stock Market & Finance