In this tutorial, I will build a TTM Squeeze scanner using Python and Mongodb
Let us first import the necessary packages for pandas and pymongo.
importpymongofrompymongoimportMongoClientimportdatetimeimportpandasaspd
I have stocks data for all stocks in mongodb.
Let us initiate the mongo DB Connection.
client=MongoClient('mongodb://localhost:27017')db=client['stocksdb']
Let us look at our stock document. Document is similar to a row in MySQL.
db.stock_data.find_one()
{'_id': ObjectId('6202f99a80d4ed2d9c536156'), 'date': datetime.datetime(2020, 1, 2, 0, 0), 'open': 21.86, 'high': 21.86, 'low': 21.315, 'close': 21.42, 'adjusted_close': 21.3733, 'volume': 3062541, 'ticker': 'AA', 'perchange': None}
From the collection/table in mongodb, we can retrieve the data by date. For that we need to provide from and to date.
Let us get the data for the last 100 days. To get this data, we will filter the data by date from "today" to 100 days back.
Let us get the today's date in Python datetime format.
today=datetime.datetime.strptime(datetime.datetime.today().strftime('%Y-%m-%d'),'%Y-%m-%d')
Below, i am extracting the date which is 100 days ago from mongoDB.
ticker='AAPL'date_100_days_ago=db.stock_data.find({'ticker':ticker,'date':{"$lte":today}}).sort([('date',pymongo.DESCENDING)]).limit(100)[99]['date']
Let us get the data for the ticker 'AAPL' using above dates.
fdocs=db.stock_data.find({'ticker':ticker,"$and":[{'date':{"$lte":today}},{'date':{"$gte":date_100_days_ago}}]},{'_id':0,'adjusted_close':0,'volume':0,'ticker':0,'perchange':0}).sort([('_id',pymongo.DESCENDING)])df=pd.DataFrame(list(fdocs))df=df[::-1]
df.head(1)
date | open | high | low | close | |
---|---|---|---|---|---|
0 | 2022-11-16 | 149.13 | 149.87 | 147.29 | 148.79 |
(Optional) - Let us rename the columns to make first lettter upper case.
df.rename(columns={'date':'Date','open':'Open','high':'High','low':'Low','close':'Close'},inplace=True)
Let us wrap the above code inside a function so that we can run it for any stock.
defget_stocks_dataframe(ticker):fdocs=db.stock_data.find({'ticker':ticker,"$and":[{'date':{"$lte":today}},{'date':{"$gte":date_100_days_ago}}]},{'_id':0,'adjusted_close':0,'volume':0,'ticker':0,'perchange':0}).sort([('_id',pymongo.DESCENDING)])df=pd.DataFrame(list(fdocs))df.rename(columns={'date':'Date','open':'Open','high':'High','low':'Low','close':'Close'},inplace=True)df=df[::-1]return(df)
Lastly, the below snippet of code will calculate the bollinger band, keltner channel and prints the stocks which are in and out of ttm squeeze.
Note the criteria to find "out of squeeze" stocks can be changed in the following code...
df.iloc[-2]['squeeze_on'] and not df.iloc[-1]['squeeze_on'].
In above code snippet, I am checking whether the previous day, stock was in "in squeeze".
defin_squeeze(df):returndf['lband']>df['lkeltner']anddf['uband']<df['ukeltner']dataframes={}#loop through all the stocksfordocindb.stock_data.find():symbol=doc['symbol']#get dataframe from mongoDBdf=get_stocks_dataframe(symbol)try:df['20sma']=df['Close'].rolling(window=20).mean()df['stddev']=df['Close'].rolling(window=20).std()#lower banddf['lband']=df['20sma']-(2*df['stddev'])#upper banddf['uband']=df['20sma']+(2*df['stddev'])df['TR']=abs(df['High']-df['Low'])df['ATR']=df['TR'].rolling(window=20).mean()#lower keltner channeldf['lkeltner']=df['20sma']-(df['ATR']*1.5)#upper keltner channeldf['ukeltner']=df['20sma']+(df['ATR']*1.5)df['squeeze_on']=df.apply(in_squeeze,axis=1)ifdf.iloc[-2]['squeeze_on']andnotdf.iloc[-1]['squeeze_on']:print(symbol,"out of squeeze")ifdf.iloc[-1]['squeeze_on']:print(symbol,"in squeeze")except:continuedataframes[symbol]=df