-
Notifications
You must be signed in to change notification settings - Fork 0
/
async_main.py
135 lines (111 loc) · 5.65 KB
/
async_main.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
import aiohttp
import asyncio
from bs4 import BeautifulSoup
HEADERS = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36'}
async def fetch_data_from_api(url):
"""
Async function to call the API and fetch data from the endpoint.
It raises an except if time out.
Returns:
response(text): Data received from the API.
"""
conn = aiohttp.TCPConnector(limit=50) # allows 50 concurrent connections
timeout = aiohttp.ClientTimeout(total=20) # timeout duration
async with aiohttp.ClientSession(connector= conn, timeout= timeout) as session:
try:
async with session.get(url, headers= HEADERS) as resp:
response = await resp.text()
return response
except asyncio.TimeoutError:
# Handle a timeout error here
print("Request timed out.")
async def get_symbols():
"""
Async function to parse data from the html into a beautifulsoup object.
Scrap the content for the stock symbols.
Returns:
symbols(list): A list of the first 50 symbols in the S&P 500 companies table.
"""
url = "https://en.wikipedia.org/wiki/List_of_S%26P_500_companies"
response = await fetch_data_from_api(url)
# parse data from the html into a beautifulsoup object
soup = BeautifulSoup(response, 'html.parser')
companies_table=soup.find('table',{'id':'constituents','class':"wikitable sortable"})
a = companies_table.find_all('a',{'class':"external text"})
symbols = [symbol.text.strip() for symbol in a[:50]]
return symbols
async def previous_close(symbols):
"""
Async function to feacth data from the API to each symbol.
Parse data from html into a beautifulsoup object.
Scrap the content for the Stock Previous Close Value;
Returns:
previous_close_values(list): A list with the previous close value to each stock.
"""
previous_close_values = []
for symbol in symbols:
url = f'https://finance.yahoo.com/quote/{symbol}?p={symbol}tsrc=fin-srch'
response = await fetch_data_from_api(url)
page = BeautifulSoup(response, 'html.parser')
previous_close_value = page.find('td', {'data-test':"PREV_CLOSE-value"})
previous_close_values.append(float(previous_close_value.text))
#print(f"P: {previous_close_value.text}")
print("Got all previous close values.")
return previous_close_values
async def moving_average(symbols):
"""
Async function to feacth data from the API to each symbol.
Parse data from html into a beautifulsoup object.
Scrap the content for the Stock 200-Day Moving Average value.
Returns:
moving_average_values(list): A list with the moving average value to each stock.
"""
moving_average_values = []
for symbol in symbols:
url = f'https://finance.yahoo.com/quote/{symbol}/key-statistics?p={symbol}'
response = await fetch_data_from_api(url)
page = BeautifulSoup(response, 'html.parser')
two_columns = page.find('div',{'id':'Col1-0-KeyStatistics-Proxy'})
right_column = two_columns.find('div', {'class':'Fl(end) W(50%) smartphone_W(100%)'})
td = right_column.find_all('td',{'class':'Fw(500) Ta(end) Pstart(10px) Miw(60px)'})
moving_average_value = td[6]
#print(f"M: {moving_average_value.text}")
moving_average_values.append(float(moving_average_value.text))
print("Got all moving average values.")
return moving_average_values
async def get_stock_value():
"""
Async function to await for the get_symbols to finish.
And run both previous_close and moving_avera function concurrently and collect their results.
Returns:
tuple[list,list,list]: A tuple with three elements,
the stock symbols list,
the previous close values list and moving average values list.
"""
ticker_values = await get_symbols()
print("Got all tickers.")
previous_close_values, moving_average_values = await asyncio.gather(previous_close(ticker_values), moving_average(ticker_values))
return ticker_values, previous_close_values, moving_average_values
def create_data_frame(ticker_values, previous_close_values, moving_average_values):
"""
Method to format the processed data as a dataframe.
Create a column called "is_cheap".
And plot a bar graph with only the values where the "is_cheap" is True.
Args:
ticker_values(list): A list with each stock symbol.
previous_close_values(list): A list with each stock previous close value.
moving_average_values(list): A list with each stock moving average value.
"""
df = pd.DataFrame(list(zip(previous_close_values, ticker_values)),
columns =['Previous Close', 'Ticker'])
df['200-Day Moving Average 3'] = moving_average_values
df['is_cheap'] = np.where(df['Previous Close'] < df['200-Day Moving Average 3'], True, False)
condition = df['is_cheap'] == True
hist = df[condition].plot(kind='bar', x='Ticker', y='Previous Close').get_figure()
hist.savefig('async_plot.png')
print("The plot was save as an image named async_plot.png")
return
if __name__ == '__main__':
stock_values = asyncio.run(get_stock_value())
ticker_values, previous_close_values, moving_average_values = stock_values[0], stock_values[1], stock_values[2]
create_data_frame(ticker_values,previous_close_values, moving_average_values)