Udemy Python Notes

Day 36 - Stock Trading News Alert Project

헤일리유 2022. 12. 22. 16:34

Day36

 


Stock Trading News Alert Project

 

주가가 (전날과 그 전날 종가 기준) 5퍼센트 이상 상승 혹은 하락하면 알림을 보내주고 그 주식 관련 탑 뉴스 3가지의 헤드라인과 간략한 내용을 문자로 보내준다.

 

 

Another project Angela encouraged students to do it on their own. 

Levels : Normal / Hard / Extra Hard

 

I wanna be an overacheiver so I'm gonna try out Extra Hard level first. :P

 

 


So Angela has broke down this project into 3 steps in extra hard level.

 

 

 

STEP  1

## STEP 1: Use https://www.alphavantage.co
# When STOCK price increase/decreases by 5% between yesterday and the day before yesterday then print("Get News").
import requests
from datetime import date
from datetime import timedelta

# STOCK = "TSLA"
# COMPANY_NAME = "Tesla Inc"

STOCK = "NKE"
COMPANY_NAME = "Nike"
alpha_api_key = ""

stock_params = {
    "function": "TIME_SERIES_DAILY_ADJUSTED",
    "symbol": STOCK,
    "apikey": alpha_api_key
}

# replace the "demo" apikey below with your own key from https://www.alphavantage.co/support/#api-key
url = 'https://www.alphavantage.co/query?function=TIME_SERIES_DAILY_ADJUSTED&symbol=IBM&apikey=demo'
r = requests.get(url, stock_params)
data = r.json()

# get the dates
today = date.today()
yesterday = str(today - timedelta(days=1))
the_day_before = str(today - timedelta(days=2))

yesterday_stock = float(data["Time Series (Daily)"][yesterday]["4. close"])
the_day_before_stock = float(data["Time Series (Daily)"][the_day_before]["4. close"])
stock_change = ((yesterday_stock-the_day_before_stock)/the_day_before_stock)*100
print(yesterday_stock)
print(the_day_before_stock)
print(stock_change)


if stock_change <= -5 or stock_change >= 5:
    print("Get News")

 

 

처음에 테슬라로 되어있었는데 현재 테슬라 주가가 강보합권이라 5퍼센트 이상 움직인 나이키로 대채해 보았다.

위 코드의 결과:

115.78
103.21
12.179052417401422
Get News

 

 

It seems like it's working as intended.

 

 

 

 


 

 

 

STEP  2

## STEP 2: Use https://newsapi.org
# Instead of printing ("Get News"), actually get the first 3 news pieces for the COMPANY_NAME.

 

일단 뉴스 데이터를 가져온다.

news_api_key = ""
news_params = {
    "apiKey": news_api_key,
    "q": COMPANY_NAME
}

news_url = "https://newsapi.org/v2/top-headlines"
response = requests.get(news_url, news_params)
news_data = response.json()

news_1 = news_data["articles"][0]
print(news_1)

위 코드의 결과 값:

{'source': {'id': 'engadget', 'name': 'Engadget'}, 'author': 'https://www.engadget.com/about/editors/will-shanklin-1', 'title': 'Nike Training Club workout videos coming to Netflix on December 30th | Engadget', 'description': 'Over 30 hours of Nike Training Club content are heading to Netflix, starting on December 30th..', 'url': 'https://www.engadget.com/nike-training-club-netflix-workout-videos-215051444.html', 'urlToImage': 'https://s.yimg.com/os/creatr-uploaded-images/2022-12/9b4e53d0-8172-11ed-95b7-93d6b94904d6', 'publishedAt': '2022-12-21T22:07:19.9411819Z', 'content': 'Netflix announced today that Nike Training Club workout videos are heading to the streaming service. The first batch of videos will be available for all Netflix subscribers starting on December 30th.… [+1458 chars]'}

 

 

일단 뉴스 테이터 가져오기는 성공.

 

뉴스마다 각각 'title'과 'description'을 가져오려면 for loop을 써야할 것 같은 느낌이 든다.

 

 

저번 시간에 배운 slicing을 활용해서 뉴스의 데이터 중 3개만 분리해본다.

 

news_3 = news_data["articles"][:3]
print(news_3)
[{'source': {'id': 'engadget', 'name': 'Engadget'}, 'author': 'https://www.engadget.com/about/editors/will-shanklin-1', 'title': 'Nike Training Club workout videos coming to Netflix on December 30th | Engadget', 'description': 'Over 30 hours of Nike Training Club content are heading to Netflix, starting on December 30th..', 'url': 'https://www.engadget.com/nike-training-club-netflix-workout-videos-215051444.html', 'urlToImage': 'https://s.yimg.com/os/creatr-uploaded-images/2022-12/9b4e53d0-8172-11ed-95b7-93d6b94904d6', 'publishedAt': '2022-12-21T22:07:19.9411819Z', 'content': 'Netflix announced today that Nike Training Club workout videos are heading to the streaming service. The first batch of videos will be available for all Netflix subscribers starting on December 30th.… [+1458 chars]'}, {'source': {'id': 'techcrunch', 'name': 'TechCrunch'}, 'author': 'Aisha Malik', 'title': 'Netflix branches out into fitness content with upcoming launch of Nike Training Club classes', 'description': "Netflix is officially branching out into fitness content, as the company announced today that it's going to start streaming Nike Training Club classes next week.", 'url': 'https://techcrunch.com/2022/12/21/netflix-branches-out-into-fitness-content-nike-training-club-classes/', 'urlToImage': 'https://techcrunch.com/wp-content/uploads/2022/07/Netflix_1.jpg?resize=1200,800', 'publishedAt': '2022-12-21T21:48:52Z', 'content': 'Netflix is officially branching out into fitness content, as the company announced today that it’s going to start streaming Nike Training Club classes next week. The streaming service will release a … [+2425 chars]'}, {'source': {'id': 'australian-financial-review', 'name': 'Australian Financial Review'}, 'author': 'Vesna Poljak, Tom Richardson, Cecile Lefort, Alex Gluyas, Emma Rapaport', 'title': 'ASX to rally; US consumer confidence 8-month high', 'description': 'Futures have shares up 0.7pc at the open; US consumer feeling most confident in 8 months; Nike rallies 13pc in ordinary trading after second-quarter numbers; follow here.', 'url': 'http://www.afr.com/markets/equity-markets/asx-to-rally-us-consumer-confidence-8-month-high-20221222-p5c867', 'urlToImage': 'https://static.ffx.io/images/$zoom_0.4816%2C$multiply_2%2C$ratio_1.777778%2C$width_1059%2C$x_0%2C$y_0/t_crop_custom/c_scale%2Cw_800%2Cq_88%2Cf_jpg/t_afr_live_no_age_social_wm/9ad2281e02d4c8103ce2ed070e4d543cc6643cb9', 'publishedAt': '2022-12-21T20:34:04Z', 'content': 'Australian shares are expected to open higher after US investors digested better than expected earnings reports.\r\nASX futures were up 48 points or 0.7 per cent to 7118 near 730am AEDT on Thursday.\r\nT… [+850 chars]'}]

 

잘 되고 있는 것 같다.

근데 제일 밖에 있는 [] 리스트는 굳이 있을 필요 없는 것 같아서 아래처럼 [0]을 달아서 리스트를 없애 주었다.

news_3 = news_data["articles"][:4][0]

 

 

 

이제 for loop 사용해서 title과 description만 가져와 본다.

online json viewer 사용하면 더 쉽게 볼 수 있다

 

 

For loop 쓰기 전 첫번째 기사의 제목과 내용을 먼저 가져와본다.

news_3 = news_data["articles"][:4]
print(news_3[0]['title'])
print(news_3[0]['description'])

위 코드의 결과:

Nike Training Club workout videos coming to Netflix on December 30th | Engadget
Over 30 hours of Nike Training Club content are heading to Netflix, starting on December 30th..

 

 

첫 줄이 헤드라인이고 두번째 줄이 description인 것 같다.

 

 

위의 코드를 토대로 만든 for loop

news_3 = news_data["articles"][:3]

for news in news_3:
    headline = news["title"]
    brief = news["description"]
    print(headline)
    print(brief)

위 코드의 결과 :

 

Nike Training Club workout videos coming to Netflix on December 30th | Engadget
Over 30 hours of Nike Training Club content are heading to Netflix, starting on December 30th..
Netflix branches out into fitness content with upcoming launch of Nike Training Club classes
Netflix is officially branching out into fitness content, as the company announced today that it's going to start streaming Nike Training Club classes next week.

 

 

이렇게 돌려보니 기사가 두 개 밖에 나오지 않는데 아마 top headline에 나이키 관련 기사가 두개 뿐인 것 같다..

코드는 맞는 것 같은데.. i'm not 100% sure..

 

 

step2 전체 코드

news_api_key = ""
news_params = {
    "apiKey": news_api_key,
    "q": COMPANY_NAME
}

news_url = "https://newsapi.org/v2/top-headlines"
response = requests.get(news_url, news_params)
news_data = response.json()

news_3 = news_data["articles"][:3]

for news in news_3:
    headline = news["title"]
    brief = news["description"]
    print(headline)
    print(brief)

 

위 코드의 결과:

Nike Training Club workout videos coming to Netflix on December 30th | Engadget
Over 30 hours of Nike Training Club content are heading to Netflix, starting on December 30th..
Netflix branches out into fitness content with upcoming launch of Nike Training Club classes
Netflix is officially branching out into fitness content, as the company announced today that it's going to start streaming Nike Training Club classes next week.

 

 

 

 

 


 

 

 

 

 

STEP 3

## STEP 3: Use https://www.twilio.com
# Send a seperate message with the percentage change and each article's title and description to your phone number.

 

 

step3 중간 코드

import requests
from datetime import date
from datetime import timedelta

# STOCK = "TSLA"
# COMPANY_NAME = "Tesla Inc"

STOCK = "NKE"
COMPANY_NAME = "Nike"
alpha_api_key = "             "

stock_params = {
    "function": "TIME_SERIES_DAILY_ADJUSTED",
    "symbol": STOCK,
    "apikey": alpha_api_key
}

# replace the "demo" apikey below with your own key from https://www.alphavantage.co/support/#api-key
url = 'https://www.alphavantage.co/query?function=TIME_SERIES_DAILY_ADJUSTED&symbol=IBM&apikey=demo'
r = requests.get(url, stock_params)
data = r.json()

# get the dates
today = date.today()
yesterday = str(today - timedelta(days=1))
the_day_before = str(today - timedelta(days=2))

yesterday_stock = float(data["Time Series (Daily)"][yesterday]["4. close"])
the_day_before_stock = float(data["Time Series (Daily)"][the_day_before]["4. close"])
stock_change = ((yesterday_stock-the_day_before_stock)/the_day_before_stock)*100
# print(yesterday_stock)
# print(the_day_before_stock)
# print(stock_change)

change_direction = ""
change_percentage = int(stock_change)

if stock_change <= -5:
    change_direction = "🔻"
if stock_change >= 5:
    change_direction = "🔺"

## STEP 1: Use https://www.alphavantage.co
# When STOCK price increase/decreases by 5% between yesterday and the day before yesterday then print("Get News").

## STEP 2: Use https://newsapi.org
# Instead of printing ("Get News"), actually get the first 3 news pieces for the COMPANY_NAME.

news_api_key = "             "
news_params = {
    "apiKey": news_api_key,
    "q": COMPANY_NAME
}

news_url = "https://newsapi.org/v2/top-headlines"
response = requests.get(news_url, news_params)
news_data = response.json()

news_3 = news_data["articles"][:3]
context = []

for news in news_3:
    headline = news["title"]
    brief = news["description"]
    message = f"Headline: {headline}\n" \
              f"Brief: {brief}"
    context.append(message)


## STEP 3: Use https://www.twilio.com
# Send a seperate message with the percentage change and each article's title and description to your phone number.

message = f'''
{STOCK}: {change_direction} {change_percentage}%\n
{context[0]}\n
{STOCK}: {change_direction} {change_percentage}%\n
{context[1]}\n
'''

print(message)


#Optional: Format the SMS message like this:

"""
TSLA: 🔺2%
Headline: Were Hedge Funds Right About Piling Into Tesla Inc. (TSLA)?. 
Brief: We at Insider Monkey have gone over 821 13F filings that hedge funds and prominent investors are required to file by the SEC The 13F filings show the funds' and investors' portfolio positions as of March 31st, near the height of the coronavirus market crash.
or
"TSLA: 🔻5%
Headline: Were Hedge Funds Right About Piling Into Tesla Inc. (TSLA)?. 
Brief: We at Insider Monkey have gone over 821 13F filings that hedge funds and prominent investors are required to file by the SEC The 13F filings show the funds' and investors' portfolio positions as of March 31st, near the height of the coronavirus market crash.
"""

 

이렇게 해서 결과를 프린트 하면 아래와 같이 나온다.

 

NKE: 🔺 12%

Headline: Nike Training Club workout videos coming to Netflix on December 30th | Engadget
Brief: Over 30 hours of Nike Training Club content are heading to Netflix, starting on December 30th..

NKE: 🔺 12%

Headline: Netflix branches out into fitness content with upcoming launch of Nike Training Club classes
Brief: Netflix is officially branching out into fitness content, as the company announced today that it's going to start streaming Nike Training Club classes next week.

 

이걸 이제 활용해서 보내면 될 것 같다.

 

 

 

 


Final Code

 

import requests
from datetime import date
from datetime import timedelta
from twilio.rest import Client

# Step1

STOCK = "NKE"
COMPANY_NAME = "Nike"
alpha_api_key = ""

stock_params = {
    "function": "TIME_SERIES_DAILY_ADJUSTED",
    "symbol": STOCK,
    "apikey": alpha_api_key
}

url = 'https://www.alphavantage.co/query?function=TIME_SERIES_DAILY_ADJUSTED&symbol=IBM&apikey=demo'
r = requests.get(url, stock_params)
data = r.json()

today = date.today()
yesterday = str(today - timedelta(days=1))
the_day_before = str(today - timedelta(days=2))

yesterday_stock = float(data["Time Series (Daily)"][yesterday]["4. close"])
the_day_before_stock = float(data["Time Series (Daily)"][the_day_before]["4. close"])
stock_change = ((yesterday_stock-the_day_before_stock)/the_day_before_stock)*100

change_direction = ""
change_percentage = int(stock_change)

if stock_change <= -5:
    change_direction = "🔻"
if stock_change >= 5:
    change_direction = "🔺"

# Step2

news_api_key = ""
news_params = {
    "apiKey": news_api_key,
    "q": COMPANY_NAME
}

news_url = "https://newsapi.org/v2/top-headlines"
response = requests.get(news_url, news_params)
news_data = response.json()

news_3 = news_data["articles"][:3]
context = []

for news in news_3:
    headline = news["title"]
    brief = news["description"]
    message = f"Headline: {headline}\n" \
              f"Brief: {brief}"
    context.append(message)


# Step 3

message = f'''
{STOCK}: {change_direction} {change_percentage}%\n
{context[0]}\n
{STOCK}: {change_direction} {change_percentage}%\n
{context[1]}\n
'''

account_sid = ""
auth_token = ""
client = Client(account_sid, auth_token)

message = client.messages \
                .create(
                     body=f"{message}",
                     from_='+12403011296',
                     to='+8201035269299'
                 )

print(message.status)

결과

queued

 

그리고 나에게 온 text 

파이썬에서는 괜찮았는데 텍스트로 보내는 과정에서 약간 오류가 난 것 같다.. 이모지도 표시 안 되고

첫번째 기사는 외국 기사인가..?

 

 

 

 

그래도 얼레벌레 성공했다~!

완벽하지는 않지만 굴러가는 나의 코드 ㅎㅎ

이제 솔루션 보면서 고쳐야할 부분을 체크해야겠다.

 

 


 

Angela's Solution

 

STEP 1

 

After getting the data with API and json,

 

ME: Use the datetime module to get the stock price of yesterday and the day before

 

ANGELA: Use list comprehension to make a dictionary into a list so she can use the first and second data from a list 

 

 

STEP1에서 

나는 데이터를 가져온 후 어제와 그제의 주식 종가를 가져올때 datetime 모듈을 사용해서 날짜를 key로 입력해서 데이터를 가져왔다면

안젤라는 list comprehension 사용해서 딕셔너리를 리스트로 바꾼 후 필요한 첫번째(어제)와 두번째(그제) 데이터를 사용했다.

 

Angela's code

 

data = response.json()["Time Series (daily)"]

 

data_list = [new item for item in list]

List comprehension을 활용해서 아래와 같은 코드를 입력하면

data_list = [value for (key,value) in data.items()]

 

이렇게하면 딕셔너리가 리스트가 된다.

yesterday_data = data_list[0]

yesterday_closing_price = yesterday_data['4. close']



day_before_yesterday_data = data_list[1]

day_before_yesterday_closing_price = day_before_yesterday_data['4. close']

 

이렇게 하면 어제와 그제의 stock closing price 구할 수 있다.

 

 

이제 상승/하락 퍼센트를 알아보자.

difference = float(yesterday_closing_price) - float(day_before_yesterday_closing_price)

이렇게 할 경우 만약 어제 종가가 더 작다면 - 마이너스 값이 나온다.

만약 절대값을 구하고 싶다면 abs() 안에 수식을 넣어준다.

difference = abs(float(yesterday_closing_price) - float(day_before_yesterday_closing_price))

 

diff_percent = (difference / float(yesterday_closing_price)) * 100

 

if diff_percent > 5:
	print("get news")

 

 

STEP 2 

 

이제 news api를 가져올 차례

나는 headline을 가져와서 뉴스가 2개밖에 없었다.

Angela used everything api so there are more than 3 news related to the company.

 

뒷 부분은 나와 거의 비슷

 

 

STEP 3

 

three news 의 title과 description을 정리하기 위해서 나는 for loop을 썼지만 Angela는 list comprehension을 썼다.

솔루션을 보면서  list comprehension을 제대로 알고 있으면 얼마나 많은 곳에 활용할 수 있는지 새삼 깨닫는다.

꼭 다시 list comprehension 강의를 복습해보고 따로 유튜브 강의도 찾아보자!

 

my code:

context = []

for news in news_3:
    headline = news["title"]
    brief = news["description"]
    message = f"Headline: {headline}\n" \
              f"Brief: {brief}"
    context.append(message)

 

Angela's code:

 

[new items for item in list]

 

[f"{STOCK_NAME}: {up_down}{diff_percent}%\nHeadline: {article['title']}. \nBrief: {article['description']}" for article in three_articles]

 

formatted_articles = [f"{STOCK_NAME}: {up_down}{diff_percent}%\nHeadline: {article['title']}. \nBrief: {article['description']}" for article in three_articles]
print(formatted_articles)

 

 

 


 

 

 

 

Angela's final code (solution)

import requests
from twilio.rest import Client

VIRTUAL_TWILIO_NUMBER = "your virtual twilio number"
VERIFIED_NUMBER = "your own phone number verified with Twilio"

STOCK_NAME = "TSLA"
COMPANY_NAME = "Tesla Inc"

STOCK_ENDPOINT = "https://www.alphavantage.co/query"
NEWS_ENDPOINT = "https://newsapi.org/v2/everything"

STOCK_API_KEY = "YOUR OWN API KEY FROM ALPHAVANTAGE"
NEWS_API_KEY = "YOUR OWN API KEY FROM NEWSAPI"
TWILIO_SID = "YOUR TWILIO ACCOUNT SID"
TWILIO_AUTH_TOKEN = "YOUR TWILIO AUTH TOKEN"

## STEP 1: Use https://www.alphavantage.co/documentation/#daily
# When stock price increase/decreases by 5% between yesterday and the day before yesterday then print("Get News").

#Get yesterday's closing stock price
stock_params = {
    "function": "TIME_SERIES_DAILY",
    "symbol": STOCK_NAME,
    "apikey": STOCK_API_KEY,
}

response = requests.get(STOCK_ENDPOINT, params=stock_params)
data = response.json()["Time Series (Daily)"]
data_list = [value for (key, value) in data.items()]
yesterday_data = data_list[0]
yesterday_closing_price = yesterday_data["4. close"]
print(yesterday_closing_price)

#Get the day before yesterday's closing stock price
day_before_yesterday_data = data_list[1]
day_before_yesterday_closing_price = day_before_yesterday_data["4. close"]
print(day_before_yesterday_closing_price)

#Find the positive difference between 1 and 2. e.g. 40 - 20 = -20, but the positive difference is 20. Hint: https://www.w3schools.com/python/ref_func_abs.asp
difference = float(yesterday_closing_price) - float(day_before_yesterday_closing_price)
up_down = None
if difference > 0:
    up_down = "🔺"
else:
    up_down = "🔻"

#Work out the percentage difference in price between closing price yesterday and closing price the day before yesterday.
diff_percent = round((difference / float(yesterday_closing_price)) * 100)
print(diff_percent)


    ## STEP 2: Instead of printing ("Get News"), actually get the first 3 news pieces for the COMPANY_NAME.

#Instead of printing ("Get News"), use the News API to get articles related to the COMPANY_NAME.
#If difference percentage is greater than 5 then print("Get News").
if abs(diff_percent) > 1:
    news_params = {
        "apiKey": NEWS_API_KEY,
        "qInTitle": COMPANY_NAME,
    }

    news_response = requests.get(NEWS_ENDPOINT, params=news_params)
    articles = news_response.json()["articles"]

    #Use Python slice operator to create a list that contains the first 3 articles. Hint: https://stackoverflow.com/questions/509211/understanding-slice-notation
    three_articles = articles[:3]
    print(three_articles)

    ## STEP 3: Use Twilio to send a seperate message with each article's title and description to your phone number.

    #Create a new list of the first 3 article's headline and description using list comprehension.
    formatted_articles = [f"{STOCK_NAME}: {up_down}{diff_percent}%\nHeadline: {article['title']}. \nBrief: {article['description']}" for article in three_articles]
    print(formatted_articles)
    #Send each article as a separate message via Twilio.
    client = Client(TWILIO_SID, TWILIO_AUTH_TOKEN)

    #TODO 8. - Send each article as a separate message via Twilio.
    for article in formatted_articles:
        message = client.messages.create(
            body=article,
            from_=VIRTUAL_TWILIO_NUMBER,
            to=VERIFIED_NUMBER
        )

 

 

 

 

 

 

 

 

 

 

 

dd