import pandas as pd # Dataframe
from datetime import datetime # Date conversion
import math # some algo required
import requests # to help scrapping yahoo webpage
import numpy as np # some calculation and nan value checking
from bs4 import BeautifulSoup # for scrapping and interpret web scrap result
import [Link] as plt # plotting of charts
import [Link] as mdates
from [Link] import DateFormatter
import yfinance as yf # download yahoo finance data
### Scrapping the Yahoo page
# I want the program to scrap the yahoo screener page so I use this routine which I have introduced
# in my another article about intrinsic value calculation
def read_html_table(source):
header = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/
res = [Link](source,headers=header, timeout=20)
if res.status_code != 200:
res = [Link](source,headers=header, timeout=20) #try 1 more time
return None, res.status_code, [Link]
# soup = BeautifulSoup([Link], "lxml")
soup = BeautifulSoup([Link], "[Link]")
if 'Select All' in [Link]:
for tag in soup.find_all("span", {'class':'Fz(0)'}): #remove those select checkboxes if any
[Link]('')
table = soup.find_all('table')
if len(table)==0:
print ('something very wrong!')
return None
# return symbol list
df = pd.read_html(str(table))[0]
return df
def stock_screener(link,startdate):
symbol_list =read_html_table(link)
if symbol_list.empty:
raise RuntimeError('yahoo trending-tickers error')
figrow=[Link]([Link](len(symbol_list)))
figcol=[Link]([Link](len(symbol_list)))
if figrow*figcol-len(symbol_list) >= figrow: # find the best fit square array of charts
figrow-=1
dynamic_dpi = min(figrow * figcol * 10, 1200)
dynamic_fontsize = max(8-figcol,4) #max(100/(figcol*figrow),5)
# prepare the chart
fig, axes = [Link](figrow,figcol, figsize=(figcol, figrow), dpi=600, squeeze=False, sharey=False,sharex
# Read finance data from Yahoo
all_stock_data=[Link](symbol_list.Symbol.to_list(),start=startdate,interval='1d')
set(all_stock_data.columns.get_level_values(0))
all_stock_data=all_stock_data.reset_index()
for i,s in enumerate(symbol_list.Symbol): # iterate for every stock indices
tickerDf=[Link]()
ax = axes[int(i%figrow),int(i/figrow)]
tickerDf['Date']=all_stock_data['Date']
tickerDf['Close']=all_stock_data['Close'][s]
""" """
""" +------- SUBPLOT each symbol chart -----+ """
""" """
company_name_len=16
title_name=(symbol_list[symbol_list['Symbol']==s].iloc[0])['Name']
title_name=title_name[:company_name_len]
titlecolor='black'
facecolor='white'
# Plot stock chart
[Link](tickerDf['Date'],tickerDf['Close'],color='black',linewidth=0.6, alpha=1)
pct_change=0
# Here we try to use background color to indicate stock changes
if len(tickerDf)>3 : # try to avoid new stock with less than 3 days of data
if [Link](tickerDf['Close'].iloc[-1]): #sometimes yahoo returns current date data as NaN as the marke
current_price=tickerDf['Close'].iloc[-2] #[Link]('ask')
previous_price=tickerDf['Close'].iloc[-3]
else:
current_price=tickerDf['Close'].iloc[-1] #[Link]('ask')
previous_price=tickerDf['Close'].iloc[-2]
pct_change=((current_price-previous_price)/previous_price)*100
# Colour condition #
if (pct_change>=0): # change background colour depends on % change
todaytrendsymbol='⇧'
titlecolor='darkgreen'
facecolor='palegreen'
else:
todaytrendsymbol='⇩'
titlecolor='red'
facecolor='mistyrose'
# use facecolor to indicate Up/Down for easy visualization
[Link].set_facecolor(facecolor)
# let's beautify the chart a bit
[Link](True, color='silver',linewidth=0.5)
ax.tick_params(axis='x',labelrotation=90)
[Link].set_major_formatter([Link]('%Y/%m'))
[Link].set_tick_params(labelsize=dynamic_fontsize)
[Link].set_tick_params(labelsize=dynamic_fontsize)
# Finally, add a title to the figure
title=title_name+'\n('+s+')'+\
str('%.2f'%current_price)+\
todaytrendsymbol+str('%.2f'%pct_change)+'%'
ax.set_title(title, fontweight='bold',color=titlecolor,fontsize=dynamic_fontsize)
if (i==0): # at each bottom row set the xaxis as date tick
for j in range(len(symbol_list),int(figrow*figcol)):
ax = axes[ int(j%figrow),int(j/figrow)]
ax.tick_params(axis='x',labelrotation=90)
[Link].set_major_formatter([Link]('%Y/%m'))
[Link].set_tick_params(labelsize=dynamic_fontsize)
[Link].set_tick_params(labelsize=dynamic_fontsize)
plt.subplots_adjust(wspace=0.12, hspace=0.1)
today=[Link]().strftime("%Y-%m-%d")
[Link](link+'\n'+startdate+'~'+today, fontweight ="bold",y=1, fontsize=dynamic_fontsize)
fig.tight_layout()
[Link]('/Users/user/Downloads/stock_screener.jpg',dpi=400,bbox_inches='tight')
return True
if __name__ == '__main__':
url='[Link]
stock_screener(url,startdate='2023-01-01')
[*********************100%%**********************] 30 of 30 completed
---------------------------------------------------------------------------
FileNotFoundError Traceback (most recent call last)
Cell In[4], line 3
1 if __name__ == '__main__':
2 url='[Link]
----> 3 stock_screener(url,startdate='2023-01-01')
Cell In[3], line 100, in stock_screener(link, startdate)
98 [Link](link+'\n'+startdate+'~'+today, fontweight ="bold",y=1, fontsize=dynamic_fontsize)
99 fig.tight_layout()
--> 100 [Link]('/Users/user/Downloads/stock_screener.jpg',dpi=400,bbox_inches='tight')
102 return True
File ~/anaconda3/lib/python3.11/site-packages/matplotlib/[Link], in [Link](self, fname, transpa
rent, **kwargs)
3374 for ax in [Link]:
3375 stack.enter_context(
3376 [Link]._cm_set(facecolor='none', edgecolor='none'))
-> 3378 [Link].print_figure(fname, **kwargs)
File ~/anaconda3/lib/python3.11/site-packages/matplotlib/backend_bases.py:2366, in FigureCanvasBase.print_figur
e(self, filename, dpi, facecolor, edgecolor, orientation, format, bbox_inches, pad_inches, bbox_extra_artists,
backend, **kwargs)
2362 try:
2363 # _get_renderer may change the figure dpi (as vector formats
2364 # force the figure dpi to 72), so we need to set it again here.
2365 with cbook._setattr_cm([Link], dpi=dpi):
-> 2366 result = print_method(
2367 filename,
2368 facecolor=facecolor,
2369 edgecolor=edgecolor,
2370 orientation=orientation,
2371 bbox_inches_restore=_bbox_inches_restore,
2372 **kwargs)
2373 finally:
2374 if bbox_inches and restore_bbox:
File ~/anaconda3/lib/python3.11/site-packages/matplotlib/backend_bases.py:2232, in FigureCanvasBase._switch_can
vas_and_return_print_method.<locals>.<lambda>(*args, **kwargs)
2228 optional_kws = { # Passed by print_figure for other renderers.
2229 "dpi", "facecolor", "edgecolor", "orientation",
2230 "bbox_inches_restore"}
2231 skip = optional_kws - {*[Link](meth).parameters}
-> 2232 print_method = [Link](meth)(lambda *args, **kwargs: meth(
2233 *args, **{k: v for k, v in [Link]() if k not in skip}))
2234 else: # Let third-parties do as they see fit.
2235 print_method = meth
File ~/anaconda3/lib/python3.11/site-packages/matplotlib/backends/backend_agg.py:526, in FigureCanvasAgg.print_
jpg(self, filename_or_obj, pil_kwargs)
521 def print_jpg(self, filename_or_obj, *, pil_kwargs=None):
522 # savefig() has already applied [Link]; we now set it to
523 # white to make imsave() blend semi-transparent figures against an
524 # assumed white background.
525 with mpl.rc_context({"[Link]": "white"}):
--> 526 self._print_pil(filename_or_obj, "jpeg", pil_kwargs)
File ~/anaconda3/lib/python3.11/site-packages/matplotlib/backends/backend_agg.py:458, in FigureCanvasAgg._print
_pil(self, filename_or_obj, fmt, pil_kwargs, metadata)
453 """
454 Draw the canvas, then save it using `.[Link]` (to which
455 *pil_kwargs* and *metadata* are forwarded).
456 """
457 [Link](self)
--> 458 [Link](
459 filename_or_obj, self.buffer_rgba(), format=fmt, origin="upper",
460 dpi=[Link], metadata=metadata, pil_kwargs=pil_kwargs)
File ~/anaconda3/lib/python3.11/site-packages/matplotlib/[Link], in imsave(fname, arr, vmin, vmax, cmap,
format, origin, dpi, metadata, pil_kwargs)
1687 pil_kwargs.setdefault("format", format)
1688 pil_kwargs.setdefault("dpi", (dpi, dpi))
-> 1689 [Link](fname, **pil_kwargs)
File ~/anaconda3/lib/python3.11/site-packages/PIL/[Link], in [Link](self, fp, format, **params)
2426 fp = [Link](filename, "r+b")
2427 else:
-> 2428 fp = [Link](filename, "w+b")
2430 try:
2431 save_handler(self, fp, filename)
FileNotFoundError: [Errno 2] No such file or directory: '/Users/user/Downloads/stock_screener.jpg'
Loading [MathJax]/jax/output/CommonHTML/fonts/TeX/[Link]