設為首頁收藏本站

艾歐踢論壇

 找回密碼
 立即註冊

QQ登錄

只需一步,快速開始

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

Create a Watchlist of Trending Stocks with Python

[複製鏈接]
跳轉到指定樓層
樓主
發表於 2023-4-17 07:44:27 | 只看該作者 回帖獎勵 |倒序瀏覽 |閱讀模式
it's important to have a system in place to pare down the number of charts that are worth a closer look.
my search for trends is always for rising stocks.
this doesn't generate a list of recommended positions, but a list of tickers worth a closer look via charts, fundamentals, and macro/broader market conditions.
the basic idea is to apply conditional checks and filtering to your entire ticker universe of prices, returning only those tickers that have short-term simple moving averages (SMAs) that are higher than longer-term ones, across a specified range of days.
we also filter out any ticker that has had a gap in either direction greater than 10% (using absolute value) within the date range.
The specific conditions to be coded are:
  • 20-period SMA > 50-period SMA for the last 100 days
  • 50-period SMA > 200-period SMA for the last 100 days
  • No gaps (up or down) for the last 100 days between a day's opening price and the prior day's close > 10% (abs value)
  • Each day's trading volume >= 200,000 shares
1) a single csv file of the entire Quandl/Sharadar EOD Equity Prices data  by importing it into my Python environment as a pandas data frame.

  1. import pandas as pd


  2. #read in the data set, drop the columns not needed, and make sure 'tradeDate' col
  3. #is datetime data type

  4. df = pd.read_csv('..\\appData\\dailyEquityData.csv')
  5. df = df[['ticker', 'tradeDate', 'open', 'close', 'volume']]
  6. df['tradeDate'] = pd.to_datetime(df['tradeDate'])
複製代碼
2)to get the latest date of the tradeDate column, and then filter the data to return rows where the trade date equals that value.
  1. #get the tickers that have the maxDate in their tradeDate column

  2. latest_tickers = df[df['tradeDate']==maxDate].ticker
  3. df = df[df['ticker'].isin(latest_tickers)]
複製代碼
Now we set the ticker and tradeDate columns as a multi-level index.
  1. #set the multindex, without dropping the columns

  2. df.set_index(['ticker', 'tradeDate'], inplace=True, drop=False)
  3. df.sort_index(inplace=True)
複製代碼
3)to add the moving averages, and get a lagged value of the prior day's close, which we use to filter out price gaps.
  1. #add the moving average columns and the prior close to each row

  2. df['sma20'] = df.groupby(level=0).close.apply(lambda x: x.rolling(20).mean())
  3. df['sma50'] = df.groupby(level=0).close.apply(lambda x: x.rolling(50).mean())
  4. df['sma200'] = df.groupby(level=0).close.apply(lambda x: x.rolling(200).mean())
  5. df['priorClose'] = df.groupby(level=0).close.shift(1)
複製代碼
The moving average calculations need their respective number of data points before they can return values.
For this reason, there are a bunch of NaN values in the data frame.

These rows aren't needed anyway, so we'll remove them.
4)The next step after that is to get the latest 100 data points for each ticker.
  1. #drop all na values, and get the latest 100 data points for each ticker

  2. df.dropna(inplace=True)
  3. df = df.groupby(level=0).tail(100)
複製代碼
use the tail function on the data frame to show that we're working with the latest data points.

And now the moment of truth, literally...
5)add a boolean column to the data frame for each condition we wish to check.
The last one confirms that all of the conditions required are true.
  1. #add a boolean column for each filter condition as well as a check that all = True

  2. df['notBigGapOpen'] = abs(((df['open'] / df['priorClose']) - 1) < 0.10)
  3. df['sma20gtsma50'] = df['sma20'] > df['sma50']
  4. df['sma50gtsma200'] = df['sma50'] > df['sma200']
  5. df['adequateVol'] = df['volume'] >= 200000
  6. df['rowPassed'] = (df['notBigGapOpen'] & df['sma20gtsma50'] & df['sma50gtsma200'] &
  7.                     df['adequateVol'])
複製代碼

At this point, our data set has the latest 100 data points for each ticker. The conditional checks are in place for each data point.
All that is left to do is reduce the data to those tickers that have a rowPassed = True for every one of the 100 rows.
We can do this by aggregating on the ticker, and calling the sum function on the rowPassed column.
Since numerically, each False value equals 0, and each True value equals 1, each ticker that has a True in all of the rows will have a sum of 100.
Those tickers are our watchlist of trending stocks.
  1. #for each ticker, see if the rowPassed col is true for each data point. sum the boolean
  2. #values, and then filter for those tickers that have a sum = 100 (the count of the rows
  3. #for each ticker)

  4. df_sums = pd.DataFrame(df.groupby(level=0).rowPassed.sum())
  5. trending_tickers = df_sums[df_sums['rowPassed']==100].index
複製代碼

We started with over 6,000 tickers, and reduced it to a mere 34.
Admittedly, this is a fairly strict definition of an uptrend. It's likely that there are many nice potential trade setups that have been filtered out; but 34 charts to review on a daily basis is more realistic than 6,000+, and the coded parameters can be adjusted and optimized.
While writing this, I used two data sets I knew to have strong trends, Apple (AAPL) and Google (GOOG).
Both made the cut, and are in the final list. The charts await:





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

使用道具 舉報

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

本版積分規則

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

GMT+8, 2024-5-16 22:36 , Processed in 0.235483 second(s), 18 queries .

Powered by Discuz! X3.2

© 2001-2013 Comsenz Inc.

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