設為首頁收藏本站

艾歐踢論壇

 找回密碼
 立即註冊

QQ登錄

只需一步,快速開始

搜索
熱搜: 活動 交友 discuz
查看: 659|回復: 0
打印 上一主題 下一主題

Making a Stock Screener with Python!

[複製鏈接]
跳轉到指定樓層
樓主
發表於 2022-3-24 10:04:38 | 只看該作者 回帖獎勵 |倒序瀏覽 |閱讀模式
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 .

  1. # Imports
  2. from pandas_datareader import data as pdr
  3. from yahoo_fin import stock_info as si
  4. from pandas import ExcelWriter
  5. import yfinance as yf
  6. import pandas as pd
  7. import datetime
  8. import time
  9. yf.pdr_override()

  10. # Variables
  11. tickers = si.tickers_sp500()
  12. tickers = [item.replace(".", "-") for item in tickers] # Yahoo Finance uses dashes instead of dots
  13. index_name = '^GSPC' # S&P 500
  14. start_date = datetime.datetime.now() - datetime.timedelta(days=365)
  15. end_date = datetime.date.today()
  16. exportList = pd.DataFrame(columns=['Stock', "RS_Rating", "50 Day MA", "150 Day Ma", "200 Day MA", "52 Week Low", "52 week High"])
  17. 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)
  1. # Index Returns
  2. index_df = pdr.get_data_yahoo(index_name, start_date, end_date)
  3. index_df['Percent Change'] = index_df['Adj Close'].pct_change()
  4. index_return = (index_df['Percent Change'] + 1).cumprod()[-1]

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

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

  19. # Creating dataframe of only top 30%
  20. rs_df = pd.DataFrame(list(zip(tickers, returns_multiples)), columns=['Ticker', 'Returns_multiple'])
  21. rs_df['RS_Rating'] = rs_df.Returns_multiple.rank(pct=True) * 100
  22. rs_df = rs_df[rs_df.RS_Rating >= rs_df.RS_Rating.quantile(.70)]
複製代碼

Now, 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.

  1. # Checking Minervini conditions of top 30% of stocks in given list
  2. rs_stocks = rs_df['Ticker']
  3. for stock in rs_stocks:   
  4.     try:
  5.         df = pd.read_csv(f'{stock}.csv', index_col=0)
  6.         sma = [50, 150, 200]
  7.         for x in sma:
  8.             df["SMA_"+str(x)] = round(df['Adj Close'].rolling(window=x).mean(), 2)
  9.         
  10.         # Storing required values
  11.         currentClose = df["Adj Close"][-1]
  12.         moving_average_50 = df["SMA_50"][-1]
  13.         moving_average_150 = df["SMA_150"][-1]
  14.         moving_average_200 = df["SMA_200"][-1]
  15.         low_of_52week = round(min(df["Low"][-260:]), 2)
  16.         high_of_52week = round(max(df["High"][-260:]), 2)
  17.         RS_Rating = round(rs_df[rs_df['Ticker']==stock].RS_Rating.tolist()[0])
  18.         
  19.         try:
  20.             moving_average_200_20 = df["SMA_200"][-20]
  21.         except Exception:
  22.             moving_average_200_20 = 0

  23.         # Condition 1: Current Price > 150 SMA and > 200 SMA
  24.         condition_1 = currentClose > moving_average_150 > moving_average_200
  25.         
  26.         # Condition 2: 150 SMA and > 200 SMA
  27.         condition_2 = moving_average_150 > moving_average_200

  28.         # Condition 3: 200 SMA trending up for at least 1 month
  29.         condition_3 = moving_average_200 > moving_average_200_20
  30.         
  31.         # Condition 4: 50 SMA> 150 SMA and 50 SMA> 200 SMA
  32.         condition_4 = moving_average_50 > moving_average_150 > moving_average_200
  33.            
  34.         # Condition 5: Current Price > 50 SMA
  35.         condition_5 = currentClose > moving_average_50
  36.            
  37.         # Condition 6: Current Price is at least 30% above 52 week low
  38.         condition_6 = currentClose >= (1.3*low_of_52week)
  39.            
  40.         # Condition 7: Current Price is within 25% of 52 week high
  41.         condition_7 = currentClose >= (.75*high_of_52week)
  42.         
  43.         # If all conditions above are true, add stock to exportList
  44.         if(condition_1 and condition_2 and condition_3 and condition_4 and condition_5 and condition_6 and condition_7):
  45.             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)
  46.             print (stock + " made the Minervini requirements")
  47.     except Exception as e:
  48.         print (e)
  49.         print(f"Could not gather data on {stock}")

  50. exportList = exportList.sort_values(by='RS_Rating', ascending=False)
  51. print('\n', exportList)
  52. writer = ExcelWriter("ScreenOutput.xlsx")
  53. exportList.to_excel(writer, "Sheet1")
  54. 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

本帖子中包含更多資源

您需要 登錄 才可以下載或查看,沒有帳號?立即註冊

x
分享到:  QQ好友和群QQ好友和群 QQ空間QQ空間 騰訊微博騰訊微博 騰訊朋友騰訊朋友
收藏收藏 轉播轉播 分享分享 分享淘帖
回復

使用道具 舉報

您需要登錄後才可以回帖 登錄 | 立即註冊

本版積分規則

小黑屋|Archiver|手機版|艾歐踢創新工坊    

GMT+8, 2024-5-15 23:01 , Processed in 0.285319 second(s), 20 queries .

Powered by Discuz! X3.2

© 2001-2013 Comsenz Inc.

快速回復 返回頂部 返回列表