admin 發表於 2022-3-24 10:04:38

Making a Stock Screener with Python!

Stock Screeners are a wonderful way to find the perfect stocks for your specific trading strategy. However, when I tried looking to find a stock screener using Python, I could hardly find any functional, automated code.
So I created this article to help others make an easy-to-follow stock screener Python program based on Mark Minervini’s Trend Template (the 8 principles on selecting the best stocks). Especially with the volatility in the current market, I hope this code will help you in your trading endeavors.Before I get into the code, I want to touch upon the stock screening criteria.
[*]The current price of the security must be greater than the 150 and 200-day simple moving averages.
[*]The 150-day simple moving average must be greater than the 200-day simple moving average.
[*]The 200-day simple moving average must be trending up for at least 1 month.
[*]The 50-day simple moving average must be greater than the 150 simple moving average and the 200 simple moving average.
[*]The current price must be greater than the 50-day simple moving average.
[*]The current price must be at least 30% above the 52 week low.
[*]The current price must be within 25% of the 52 week high.
[*]The IBD RS-Rating must be greater than 70 (the higher, the better). The RS rating is a metric of a stock’s price performance over the last year compared to all other stocks and the overall market. Check out this article to learn more.

You can read more about this template in Mark Minervini’s blog post.Now that you are familiar with the criteria, we can get into the code. First, import the following dependencies. If you do not have one of the following modules installed on your machine, use “pip install (module name)” in your terminal to download them.n
note: pip install openpyxl   is needed .# Imports
from pandas_datareader import data as pdr
from yahoo_fin import stock_info as si
from pandas import ExcelWriter
import yfinance as yf
import pandas as pd
import datetime
import time
yf.pdr_override()

# Variables
tickers = si.tickers_sp500()
tickers = # Yahoo Finance uses dashes instead of dots
index_name = '^GSPC' # S&P 500
start_date = datetime.datetime.now() - datetime.timedelta(days=365)
end_date = datetime.date.today()
exportList = pd.DataFrame(columns=['Stock', "RS_Rating", "50 Day MA", "150 Day Ma", "200 Day MA", "52 Week Low", "52 week High"])
returns_multiples = []First, we must import the dependencies we will use in the program such as yahoo_fin (to get the list of tickers) and pandas_datareader.data (to get historical stock data).Next, we must set up the variables for the rest of the program. I outlined below what each variable refers to.
[*]tickers : All of the tickers in the S&P 500
[*]index_name : S&P 500 Yahoo Finance symbol
[*]start_date : The beginning date for historical data (exactly one year ago)
[*]end_date : The end date for historical data (today)
[*]exportList : The values we will be collecting for each stock
[*]returns_multiples : A list to see how each stock performed relative to the market (will be used for calculating the RS rating)
# Index Returns
index_df = pdr.get_data_yahoo(index_name, start_date, end_date)
index_df['Percent Change'] = index_df['Adj Close'].pct_change()
index_return = (index_df['Percent Change'] + 1).cumprod()[-1]

# Find top 30% performing stocks (relative to the S&P 500)
for ticker in tickers:
    # Download historical data as CSV for each stock (makes the process faster)
    df = pdr.get_data_yahoo(ticker, start_date, end_date)
    df.to_csv(f'{ticker}.csv')

    # Calculating returns relative to the market (returns multiple)
    df['Percent Change'] = df['Adj Close'].pct_change()
    stock_return = (df['Percent Change'] + 1).cumprod()[-1]
   
    returns_multiple = round((stock_return / index_return), 2)
    returns_multiples.extend()
   
    print (f'Ticker: {ticker}; Returns Multiple against S&P 500: {returns_multiple}\n')
    time.sleep(1)

# Creating dataframe of only top 30%
rs_df = pd.DataFrame(list(zip(tickers, returns_multiples)), columns=['Ticker', 'Returns_multiple'])
rs_df['RS_Rating'] = rs_df.Returns_multiple.rank(pct=True) * 100
rs_df = rs_dfNow, we can calculate the cumulative return of the S&P 500 index over the past year and compare that value to the cumulative return for each stock in the S&P 500 during the same period. The IBD Relative Strength metric essentially calculates how a stock is performing relative to the market and other stocks during a specific time period. Since the metric is exclusively used in IBD services, we can estimate the IBD RS by dividing the cumulative return of each stock over the cumulative return of the index and then create a percentile ranking for each stock out of 100. For example, if AAPL outperformed the market greater than MSFT in a specified time period, it would have a higher RS. In Mark Minervini’s Trend Template, he looks for stocks with an RS value of 70 or higher (the top 30% performing stocks in the market).Since in this program the RS metric is calculated with a percentile value relative to other stocks in the given list, it is better to have a list of a greater amount of stocks to make the RS value more accurate. In this program, we have chosen a list of the ~500 stocks in the S&P 500 index so that is a large enough sample size.To make the process faster, we can download the historical data for each stock over the past year instead of continually making requests to Yahoo Finance (which could cause errors). The time.sleep(1) at the end of the for loop can also help curb potential errors with the influx of requests. Finally, after the data manipulation with quantiles, we have a dataframe with the top 30% performing stocks in the given list as well as their respective RS values.# Checking Minervini conditions of top 30% of stocks in given list
rs_stocks = rs_df['Ticker']
for stock in rs_stocks:   
    try:
      df = pd.read_csv(f'{stock}.csv', index_col=0)
      sma =
      for x in sma:
            df["SMA_"+str(x)] = round(df['Adj Close'].rolling(window=x).mean(), 2)
      
      # Storing required values
      currentClose = df["Adj Close"][-1]
      moving_average_50 = df["SMA_50"][-1]
      moving_average_150 = df["SMA_150"][-1]
      moving_average_200 = df["SMA_200"][-1]
      low_of_52week = round(min(df["Low"][-260:]), 2)
      high_of_52week = round(max(df["High"][-260:]), 2)
      RS_Rating = round(rs_df==stock].RS_Rating.tolist())
      
      try:
            moving_average_200_20 = df["SMA_200"][-20]
      except Exception:
            moving_average_200_20 = 0

      # Condition 1: Current Price > 150 SMA and > 200 SMA
      condition_1 = currentClose > moving_average_150 > moving_average_200
      
      # Condition 2: 150 SMA and > 200 SMA
      condition_2 = moving_average_150 > moving_average_200

      # Condition 3: 200 SMA trending up for at least 1 month
      condition_3 = moving_average_200 > moving_average_200_20
      
      # Condition 4: 50 SMA> 150 SMA and 50 SMA> 200 SMA
      condition_4 = moving_average_50 > moving_average_150 > moving_average_200
         
      # Condition 5: Current Price > 50 SMA
      condition_5 = currentClose > moving_average_50
         
      # Condition 6: Current Price is at least 30% above 52 week low
      condition_6 = currentClose >= (1.3*low_of_52week)
         
      # Condition 7: Current Price is within 25% of 52 week high
      condition_7 = currentClose >= (.75*high_of_52week)
      
      # If all conditions above are true, add stock to exportList
      if(condition_1 and condition_2 and condition_3 and condition_4 and condition_5 and condition_6 and condition_7):
            exportList = exportList.append({'Stock': stock, "RS_Rating": RS_Rating ,"50 Day MA": moving_average_50, "150 Day Ma": moving_average_150, "200 Day MA": moving_average_200, "52 Week Low": low_of_52week, "52 week High": high_of_52week}, ignore_index=True)
            print (stock + " made the Minervini requirements")
    except Exception as e:
      print (e)
      print(f"Could not gather data on {stock}")

exportList = exportList.sort_values(by='RS_Rating', ascending=False)
print('\n', exportList)
writer = ExcelWriter("ScreenOutput.xlsx")
exportList.to_excel(writer, "Sheet1")
writer.save()Instead of calculating the metrics for each one of the stocks, we can just include the top 30% of stocks that pass condition 8 of Minervini’s Trend Template (an RS value greater than 70). From here, we can calculate the metrics we need to create the conditions. The current close price is used by taking the adjusted close price for the last day. The high and lows of the past year are taken by finding the maximum and minimum values in the DataFrame for the past 260 trading days (about a year). The moving averages are used by calculating the rolling averages over the respective amount of days. The rest of the code actually executes the screener with the principles that were mentioned earlier. If a stock passes every one of the conditions, we can add it to our exportList of stocks that passed Minervini’s Trend Template!Lastly, this code will print out a DataFrame of all the stocks that made the requirements and download the stocks to an excel file for your convenience. Now you know how how to create the stock screener used by one of the best traders of all time!The GitHub Gist below contains all the code for the program. I hope this algorithm will prove useful to you in the future. Thank you so much for reading!
source from :Making a Stock Screener with Python! | Towards Data Science

頁: [1]
查看完整版本: Making a Stock Screener with Python!