From 76ec388dfa651e79b8506ff2496d0df2ab40f09a Mon Sep 17 00:00:00 2001 From: Volha Sakharevich Date: Tue, 22 Aug 2023 17:52:24 +0100 Subject: [PATCH 1/8] Implement real-time stock price monitoring with Alpha Vantage API --- .gitignore | 5 ++++ api_app.py | 71 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 76 insertions(+) create mode 100644 .gitignore create mode 100644 api_app.py diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..57f452d --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +venv/ + +.env + +draft.py diff --git a/api_app.py b/api_app.py new file mode 100644 index 0000000..bcd9bb9 --- /dev/null +++ b/api_app.py @@ -0,0 +1,71 @@ +import requests +import time +from json.decoder import JSONDecodeError +import os +from dotenv import load_dotenv + +load_dotenv() + + +class StockInfo: + def __init__(self, symbol): + self.symbol = symbol + self.current_price = None + self.previous_price = None + + def update_price(self, new_price): + self.previous_price = self.current_price + self.current_price = new_price + + def check_price_fall(self): + if self.current_price is not None and self.previous_price is not None: + price_diff = self.current_price - self.previous_price + if price_diff <= -0.25: + print( + f"ALERT: {self.symbol} has fallen by at least £0.25 GBP. Current price is ${self.current_price}. Time to buy!" + ) + + +def get_stock_price(symbol, api_token): + url = f"https://www.alphavantage.co/query?function=TIME_SERIES_INTRADAY&symbol={symbol}&interval=5min&apikey={api_token}" + response = requests.get(url) + if response.status_code == 200: + try: + data = response.json() + latest_close_price = list(data["Time Series (5min)"].values())[0][ + "4. close" + ] + return float(latest_close_price) + except JSONDecodeError: + print(f"Could not decode JSON response for symbol {symbol}.") + return None + except KeyError: + print(f"Could not find necessary data for symbol {symbol}.") + return None + else: + print( + f"Failed to retrieve stock data for {symbol}. HTTP Status Code: {response.status_code}" + ) + return None + + +if __name__ == "__main__": + api_token = os.getenv("API_KEY") + + monitored_stocks = [ + StockInfo("TSLA"), + StockInfo("AAPL"), + StockInfo("MSFT"), + StockInfo("GOOGL"), + StockInfo("NKE"), + ] + + while True: + for stock_info in monitored_stocks: + new_price = get_stock_price(stock_info.symbol, api_token) + if new_price is not None: + print(f"Current price of {stock_info.symbol}: ${new_price}") + stock_info.update_price(new_price) + stock_info.check_price_fall() + + time.sleep(60) # Pause for 60 seconds before the next round of checks From 7b90b6baf31fd32dc89ec4cff968ce04b80ac2ee Mon Sep 17 00:00:00 2001 From: Volha Sakharevich Date: Wed, 23 Aug 2023 22:38:17 +0100 Subject: [PATCH 2/8] Add webhook applets --- .gitignore | 3 +++ webhook.py | 15 +++++++++++++++ 2 files changed, 18 insertions(+) create mode 100644 webhook.py diff --git a/.gitignore b/.gitignore index 57f452d..cb72b58 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,6 @@ venv/ .env draft.py +test.py + +__pycache__ diff --git a/webhook.py b/webhook.py new file mode 100644 index 0000000..ec554c8 --- /dev/null +++ b/webhook.py @@ -0,0 +1,15 @@ +import requests + +import os +from dotenv import load_dotenv + +load_dotenv() + + +def send_ifttt_webhook(event, symbol, current_price, previous_price): + webhook_key = os.getenv("WEBHOOK_KEY") + url = f"https://maker.ifttt.com/trigger/{event}/with/key/{webhook_key}" + payload = {"value1": symbol, "value2": current_price, "value3": previous_price} + print(f"Sending payload: {payload}") + response = requests.post(url, json=payload) + print(f"Received response: {response.text}") From 4eb935bfad3859e1ac0b7cb00de81119157b0750 Mon Sep 17 00:00:00 2001 From: Volha Sakharevich Date: Thu, 24 Aug 2023 00:24:50 +0100 Subject: [PATCH 3/8] Fix webhook message --- .gitignore | 3 +- appi_app2.py | 98 ++++++++++++++++++++++++++++++++++++++++++++++++++++ test.py | 63 +++++++++++++++++++++++++++++++++ webhook.py | 14 +++++--- 4 files changed, 172 insertions(+), 6 deletions(-) create mode 100644 appi_app2.py create mode 100644 test.py diff --git a/.gitignore b/.gitignore index cb72b58..eae0d4c 100644 --- a/.gitignore +++ b/.gitignore @@ -3,6 +3,7 @@ venv/ .env draft.py -test.py +# test.py +data.txt __pycache__ diff --git a/appi_app2.py b/appi_app2.py new file mode 100644 index 0000000..3e3343b --- /dev/null +++ b/appi_app2.py @@ -0,0 +1,98 @@ +import requests +import time +from json.decoder import JSONDecodeError +import os +from dotenv import load_dotenv +from collections import deque + +load_dotenv() + + +class StockInfo: + def __init__(self, symbol): + self.symbol = symbol + self.current_price = None + self.previous_price = None + self.seven_day_prices = deque(maxlen=7) + + def update_price(self, new_price): + self.previous_price = self.current_price + self.current_price = new_price + + def update_seven_day_prices(self, daily_average): + self.seven_day_prices.append(daily_average) + + def calculate_seven_day_average(self): + if len(self.seven_day_prices) == 0: + return None + return sum(self.seven_day_prices) / len(self.seven_day_prices) + + def check_price_fall(self): + if self.current_price and self.previous_price: + if self.current_price < self.previous_price - 0.25: + print( + f"ALERT: {self.symbol} has fallen by at least £0.25 GBP. Current price is ${self.current_price}. Time to buy!" + ) + + def check_below_seven_day_avg(self): + seven_day_avg = self.calculate_seven_day_average() + if ( + seven_day_avg is not None + and self.current_price is not None + and self.current_price < seven_day_avg + ): + print( + f"ALERT: {self.symbol}'s current price of ${self.current_price} is below the 7-day average of ${seven_day_avg}. Consider buying!" + ) + + +def get_stock_price(symbol, api_token): + url = f"https://financialmodelingprep.com/api/v3/quote/{symbol}?apikey={api_token}" + response = requests.get(url) + if response.status_code == 200: + try: + data = response.json() + return float(data[0]["price"]) + except (JSONDecodeError, KeyError): + print(f"Failed to get price data for {symbol}.") + return None + + +def get_daily_average_price(symbol, api_token): + url = f"https://financialmodelingprep.com/api/v3/historical-price-full/{symbol}?timeseries=7&apikey={api_token}" + response = requests.get(url) + if response.status_code == 200: + try: + data = response.json()["historical"] + prices = [day["close"] for day in data] + return sum(prices) / len(prices) + except (JSONDecodeError, KeyError): + print(f"Failed to get historical data for {symbol}.") + return None + + +if __name__ == "__main__": + api_token = os.getenv("API_KEY") + + monitored_stocks = [ + StockInfo("TSLA"), + StockInfo("AAPL"), + StockInfo("MSFT"), + StockInfo("GOOGL"), + StockInfo("NKE"), + ] + + while True: + for stock_info in monitored_stocks: + new_price = get_stock_price(stock_info.symbol, api_token) + daily_avg = get_daily_average_price(stock_info.symbol, api_token) + + if new_price is not None: + stock_info.update_price(new_price) + if daily_avg is not None: + stock_info.update_seven_day_prices(daily_avg) + + stock_info.check_price_fall() + stock_info.check_below_seven_day_avg() + + time.sleep(60 * 5) # Sleep for 5 minutes diff --git a/test.py b/test.py new file mode 100644 index 0000000..085a29e --- /dev/null +++ b/test.py @@ -0,0 +1,63 @@ +import requests +import time +from json.decoder import JSONDecodeError +import os +from dotenv import load_dotenv +from webhook import ( + send_ifttt_webhook, +) # Assuming you have this function in a webhook.py file +import random # Import the random module for generating test data + +load_dotenv() + + +class StockInfo: + def __init__(self, symbol): + self.symbol = symbol + self.current_price = None + self.previous_price = None + + def update_price(self, new_price): + self.previous_price = self.current_price + self.current_price = new_price + + def check_price_fall(self): + if self.current_price is not None and self.previous_price is not None: + price_diff = self.current_price - self.previous_price + if price_diff <= -0.25: + print( + f"ALERT: {self.symbol} has fallen by at least £0.25 GBP. Current price is ${self.current_price}. Time to buy!" + ) + send_ifttt_webhook( + "stock_price_fell", + self.symbol, + self.current_price, + self.previous_price, + ) + + +# Mock the get_stock_price function to use test data +def get_stock_price(symbol, api_token): + return random.uniform(100, 200) # Random float between 100 and 200 + + +if __name__ == "__main__": + api_token = os.getenv("API_KEY") + + monitored_stocks = [ + StockInfo("TSLA"), + StockInfo("AAPL"), + StockInfo("MSFT"), + StockInfo("GOOGL"), + StockInfo("NKE"), + ] + + while True: + for stock_info in monitored_stocks: + new_price = get_stock_price(stock_info.symbol, api_token) + if new_price is not None: + print(f"Current price of {stock_info.symbol}: ${new_price}") + stock_info.update_price(new_price) + stock_info.check_price_fall() + + time.sleep(5) # Pause for 60 seconds before the next round of checks diff --git a/webhook.py b/webhook.py index ec554c8..43b1db2 100644 --- a/webhook.py +++ b/webhook.py @@ -2,14 +2,18 @@ import os from dotenv import load_dotenv +import json load_dotenv() def send_ifttt_webhook(event, symbol, current_price, previous_price): webhook_key = os.getenv("WEBHOOK_KEY") - url = f"https://maker.ifttt.com/trigger/{event}/with/key/{webhook_key}" - payload = {"value1": symbol, "value2": current_price, "value3": previous_price} - print(f"Sending payload: {payload}") - response = requests.post(url, json=payload) - print(f"Received response: {response.text}") + url = f"https://maker.ifttt.com/trigger/{event}/json/with/key/{webhook_key}" + headers = {"Content-Type": "application/json"} + payload = { + "symbol": symbol, + "previous_price": str(previous_price), + "current_price": str(current_price), + } + response = requests.post(url, data=json.dumps(payload), headers=headers) From e30878ba297012bbd107e0db1861e865e9aa5617 Mon Sep 17 00:00:00 2001 From: Volha Sakharevich Date: Thu, 24 Aug 2023 21:26:38 +0100 Subject: [PATCH 4/8] Improve webhook message --- webhook.py | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/webhook.py b/webhook.py index 43b1db2..b6942ad 100644 --- a/webhook.py +++ b/webhook.py @@ -2,18 +2,17 @@ import os from dotenv import load_dotenv -import json + load_dotenv() def send_ifttt_webhook(event, symbol, current_price, previous_price): webhook_key = os.getenv("WEBHOOK_KEY") - url = f"https://maker.ifttt.com/trigger/{event}/json/with/key/{webhook_key}" - headers = {"Content-Type": "application/json"} + url = f"https://maker.ifttt.com/trigger/{event}/with/key/{webhook_key}" payload = { - "symbol": symbol, - "previous_price": str(previous_price), - "current_price": str(current_price), + "value1": symbol, + "value2": str("{:.2f}".format(round(current_price, 2))), + "value3": str("{:.2f}".format(round(previous_price, 2))), } - response = requests.post(url, data=json.dumps(payload), headers=headers) + response = requests.post(url, json=payload) From 86b34d2c0e827588ec59c20595d9b56b02507f35 Mon Sep 17 00:00:00 2001 From: Volha Sakharevich Date: Thu, 24 Aug 2023 23:10:17 +0100 Subject: [PATCH 5/8] Add check if price is less than the 7-day average --- .gitignore | 4 --- api_app.py | 71 ----------------------------------------- appi_app2.py => main.py | 43 ++++++++++++------------- test.py | 63 ------------------------------------ webhook.py | 18 ++++++++--- 5 files changed, 34 insertions(+), 165 deletions(-) delete mode 100644 api_app.py rename appi_app2.py => main.py (71%) delete mode 100644 test.py diff --git a/.gitignore b/.gitignore index eae0d4c..5e71cc1 100644 --- a/.gitignore +++ b/.gitignore @@ -2,8 +2,4 @@ venv/ .env -draft.py -# test.py - -data.txt __pycache__ diff --git a/api_app.py b/api_app.py deleted file mode 100644 index bcd9bb9..0000000 --- a/api_app.py +++ /dev/null @@ -1,71 +0,0 @@ -import requests -import time -from json.decoder import JSONDecodeError -import os -from dotenv import load_dotenv - -load_dotenv() - - -class StockInfo: - def __init__(self, symbol): - self.symbol = symbol - self.current_price = None - self.previous_price = None - - def update_price(self, new_price): - self.previous_price = self.current_price - self.current_price = new_price - - def check_price_fall(self): - if self.current_price is not None and self.previous_price is not None: - price_diff = self.current_price - self.previous_price - if price_diff <= -0.25: - print( - f"ALERT: {self.symbol} has fallen by at least £0.25 GBP. Current price is ${self.current_price}. Time to buy!" - ) - - -def get_stock_price(symbol, api_token): - url = f"https://www.alphavantage.co/query?function=TIME_SERIES_INTRADAY&symbol={symbol}&interval=5min&apikey={api_token}" - response = requests.get(url) - if response.status_code == 200: - try: - data = response.json() - latest_close_price = list(data["Time Series (5min)"].values())[0][ - "4. close" - ] - return float(latest_close_price) - except JSONDecodeError: - print(f"Could not decode JSON response for symbol {symbol}.") - return None - except KeyError: - print(f"Could not find necessary data for symbol {symbol}.") - return None - else: - print( - f"Failed to retrieve stock data for {symbol}. HTTP Status Code: {response.status_code}" - ) - return None - - -if __name__ == "__main__": - api_token = os.getenv("API_KEY") - - monitored_stocks = [ - StockInfo("TSLA"), - StockInfo("AAPL"), - StockInfo("MSFT"), - StockInfo("GOOGL"), - StockInfo("NKE"), - ] - - while True: - for stock_info in monitored_stocks: - new_price = get_stock_price(stock_info.symbol, api_token) - if new_price is not None: - print(f"Current price of {stock_info.symbol}: ${new_price}") - stock_info.update_price(new_price) - stock_info.check_price_fall() - - time.sleep(60) # Pause for 60 seconds before the next round of checks diff --git a/appi_app2.py b/main.py similarity index 71% rename from appi_app2.py rename to main.py index 3e3343b..8142ab2 100644 --- a/appi_app2.py +++ b/main.py @@ -3,7 +3,8 @@ from json.decoder import JSONDecodeError import os from dotenv import load_dotenv -from collections import deque +from webhook import send_price_drop, send_avg_price_drop + load_dotenv() @@ -13,36 +14,34 @@ def __init__(self, symbol): self.symbol = symbol self.current_price = None self.previous_price = None - self.seven_day_prices = deque(maxlen=7) def update_price(self, new_price): self.previous_price = self.current_price self.current_price = new_price - def update_seven_day_prices(self, daily_average): - self.seven_day_prices.append(daily_average) - - def calculate_seven_day_average(self): - if len(self.seven_day_prices) == 0: - return None - return sum(self.seven_day_prices) / len(self.seven_day_prices) - def check_price_fall(self): if self.current_price and self.previous_price: if self.current_price < self.previous_price - 0.25: print( f"ALERT: {self.symbol} has fallen by at least £0.25 GBP. Current price is ${self.current_price}. Time to buy!" ) + send_price_drop( + "stock_price_fell", + self.symbol, + self.current_price, + self.previous_price, + ) - def check_below_seven_day_avg(self): - seven_day_avg = self.calculate_seven_day_average() - if ( - seven_day_avg is not None - and self.current_price is not None - and self.current_price < seven_day_avg - ): + def check_below_seven_day_avg(self, daily_avg): + if self.current_price < daily_avg: print( - f"ALERT: {self.symbol}'s current price of ${self.current_price} is below the 7-day average of ${seven_day_avg}. Consider buying!" + f"ALERT: {self.symbol}'s current price of ${self.current_price} is below the 7-day average of ${daily_avg}. Consider buying!" + ) + send_avg_price_drop( + "stock_price_fell", + self.symbol, + self.current_price, + daily_avg, ) @@ -85,14 +84,12 @@ def get_daily_average_price(symbol, api_token): while True: for stock_info in monitored_stocks: new_price = get_stock_price(stock_info.symbol, api_token) - daily_avg = get_daily_average_price(stock_info.symbol, api_token) if new_price is not None: stock_info.update_price(new_price) - if daily_avg is not None: - stock_info.update_seven_day_prices(daily_avg) - stock_info.check_price_fall() - stock_info.check_below_seven_day_avg() + + daily_avg = get_daily_average_price(stock_info.symbol, api_token) + stock_info.check_below_seven_day_avg(daily_avg) time.sleep(60 * 5) # Sleep for 5 minutes diff --git a/test.py b/test.py deleted file mode 100644 index 085a29e..0000000 --- a/test.py +++ /dev/null @@ -1,63 +0,0 @@ -import requests -import time -from json.decoder import JSONDecodeError -import os -from dotenv import load_dotenv -from webhook import ( - send_ifttt_webhook, -) # Assuming you have this function in a webhook.py file -import random # Import the random module for generating test data - -load_dotenv() - - -class StockInfo: - def __init__(self, symbol): - self.symbol = symbol - self.current_price = None - self.previous_price = None - - def update_price(self, new_price): - self.previous_price = self.current_price - self.current_price = new_price - - def check_price_fall(self): - if self.current_price is not None and self.previous_price is not None: - price_diff = self.current_price - self.previous_price - if price_diff <= -0.25: - print( - f"ALERT: {self.symbol} has fallen by at least £0.25 GBP. Current price is ${self.current_price}. Time to buy!" - ) - send_ifttt_webhook( - "stock_price_fell", - self.symbol, - self.current_price, - self.previous_price, - ) - - -# Mock the get_stock_price function to use test data -def get_stock_price(symbol, api_token): - return random.uniform(100, 200) # Random float between 100 and 200 - - -if __name__ == "__main__": - api_token = os.getenv("API_KEY") - - monitored_stocks = [ - StockInfo("TSLA"), - StockInfo("AAPL"), - StockInfo("MSFT"), - StockInfo("GOOGL"), - StockInfo("NKE"), - ] - - while True: - for stock_info in monitored_stocks: - new_price = get_stock_price(stock_info.symbol, api_token) - if new_price is not None: - print(f"Current price of {stock_info.symbol}: ${new_price}") - stock_info.update_price(new_price) - stock_info.check_price_fall() - - time.sleep(5) # Pause for 60 seconds before the next round of checks diff --git a/webhook.py b/webhook.py index b6942ad..f58d986 100644 --- a/webhook.py +++ b/webhook.py @@ -7,12 +7,22 @@ load_dotenv() -def send_ifttt_webhook(event, symbol, current_price, previous_price): +def send_ifttt_webhook(event, message): webhook_key = os.getenv("WEBHOOK_KEY") url = f"https://maker.ifttt.com/trigger/{event}/with/key/{webhook_key}" payload = { - "value1": symbol, - "value2": str("{:.2f}".format(round(current_price, 2))), - "value3": str("{:.2f}".format(round(previous_price, 2))), + "value1": message, + "value2": "", + "value3": "", } response = requests.post(url, json=payload) + + +def send_price_drop(event, symbol, current_price, previous_price): + message = f"ALERT: The stock {symbol} has fallen. Previous Price: ${previous_price:.2f}. Current Price: ${current_price:.2f}. Consider buying now!" + send_ifttt_webhook(event, message) + + +def send_avg_price_drop(event, symbol, current_price, daily_avg): + message = f"ALERT: {symbol}'s current price of ${current_price:.2f} is below the 7-day average of ${daily_avg:.2f}. Consider buying!" + send_ifttt_webhook(event, message) From deac398d1411209fe62ec257507da4f11274971b Mon Sep 17 00:00:00 2001 From: Volha Sakharevich Date: Thu, 24 Aug 2023 23:28:09 +0100 Subject: [PATCH 6/8] Add requirements.txt --- requirements.txt | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 requirements.txt diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..df7458c --- /dev/null +++ b/requirements.txt @@ -0,0 +1,2 @@ +requests +python-dotenv From 5c0cd445a20664fcd66ce2dfe9f00c1ef4e222a4 Mon Sep 17 00:00:00 2001 From: Volha Sakharevich Date: Thu, 24 Aug 2023 23:28:50 +0100 Subject: [PATCH 7/8] Add README.md --- README.md | 88 +++++++++++++++++++++++++++++++------------------------ 1 file changed, 49 insertions(+), 39 deletions(-) diff --git a/README.md b/README.md index 9e6c192..248175a 100644 --- a/README.md +++ b/README.md @@ -1,40 +1,50 @@ # API-Stock-Signalling -###### NOTE: this is a project to practice your Python industry skills. Please upload your solutions by opening a new branch to the main. All files that are instantly merged to the main will be deleted. -## Overview -A small consultancy who is currently delivering client work for a major bank wants to monitor the prices for the following stocks: Tesla, Apple, Microsoft, Google, and Nike. Once the stock falls below a certain price, they want to be immediately notified so that they can purchase more stocks. -## Goal -Write a real time Python application that monitors the prices then notifies the user when the price of any of these stocks falls by at least £0.25 GBP. The user should also be notified if today's price is less than the 7-day average of that stock price. -## Brief -To do this, the client has recommended using a popular automation website called IFTTT: https://ifttt.com/. They are willing to use a different provider or solution (use those consultancy skills!) if you believe there is a better option. -#### IFTTT Applet - -IFTTT stands for “If This Then That” and it’s an automation platform that allows you to connect different apps and services together. An applet is a connection between two or more apps or devices that enables you to do something that those services couldn’t do on their own. Applets consists of two parts triggers and actions. Triggers tell an applet to start, and actions are the end result of an applet run. To use an applet, you’ll need to create a free IFTTT account and connect your apps and devices to IFTTT so that they can talk to each other. - -#### Proposed Workflow -- Write a script that returns the stock prices. This will involve making an API request. -- Set up a IFTTT account and applet. This will be accessible via the mobile app which allows you to trigger the webhook service provided by IFTTT. -- You will need to configure the 'webhooks' service to receive web requests. You can find more details here: https://ifttt.com/maker_webhooks. -- From here you can write an application that utilises the requests package to make POST and GET requests. -- Think of what aspects or components of your proposed solution needs to be tested and what would these tests look like and attempt to implement such tests. - -## Main Considerations -- Choose an automation approach. Are you planning on using IFTTT or another workflow? -- What API are you going to use? You can use this as a starting point: https://github.com/public-apis/public-apis -- Remember, this is a proposed workflow. If you believe you have a more efficient approach please reach out to the Academy Team. -#### Requirements Gathering -The start to any project is to make sure you have clear and well-defined requirements for your project. Most projects start with a vague idea of what the stakeholder wants, and as a consultant, we will never have as much knowledge about their problem/business context as they do. Therefore, we need to get as much information out of them as possible, as they will subconsciously assume that we know everything. For this project, Alex Naylor will be the stakeholder. - -If you don't know the answer to any question then you should always ask - NEVER ASSUME. This will only risk the accuracy of your work and end up having to do everything all over again if you wrongly assume. - -Questions to ask yourself constantly throughout the project are: - -- What is the purpose of this project, why does the stakeholder want this and what is the desired outcome of the project? -- Is there any extra info that the stakeholder could tell you to help tailor the project to what they want? - -## Assessment -For the assessment, you will have a 15 minute technical interview. This will consist of a strict 5 minute presentation on your technical solution. There is no need to create slides for this but you may want to demo your code. For the second half of the session, you will be asked technical questions related to the project. You will be assessed on: -- Project Complexity -- Brief Completness i.e. have you managed to meet the client brief? -- Coding Standards - -Good Luck! + +This Python application monitors real-time stock prices and notifies users when specific conditions are met: + +1. When the stock price falls by at least $0.25 USD. +2. When today's stock price is less than the 7-day average. + +## Prerequisites + +- Python 3.x +- An API key from Financial Modeling Prep (FMP) +- IFTTT account and key for notifications + +## Getting Started + +### Step 1: Get Your FMP API Key + +1. Visit [Financial Modeling Prep](https://site.financialmodelingprep.com) website. +2. Sign up for an account and generate your API key. + +### Step 2: Set Up Your `.env` File + +1. Create a new file in the root directory of your project and name it `.env`. +2. Open `.env` and add the following lines: + + ``` + API_KEY=Your_FMP_API_Key_Here + WEBHOOK_KEY=Your_IFTTT_Key_Here + ``` + +### Step 3: Get Your IFTTT Key + +1. Visit the [IFTTT website](https://ifttt.com/) and create an account if you don't have one. +2. Generate your IFTTT key. + +### Step 4: Create an IFTTT Applet + +1. Log in to your IFTTT account. +2. Create a new applet. +3. Set the event name to `stock_price_fell`. +4. Configure the applet to receive notifications when this event is triggered. + +### Step 5: Install Required Python Packages + +If you haven't done so already, install the required Python packages by running: + +```bash +pip install -r requirements.txt + +``` From c37f35a6ce87c6a5e763c6f7b2ee1ad4398570bb Mon Sep 17 00:00:00 2001 From: Volha Sakharevich Date: Thu, 24 Aug 2023 23:40:13 +0100 Subject: [PATCH 8/8] Add code comments --- main.py | 7 +++++++ webhook.py | 3 +++ 2 files changed, 10 insertions(+) diff --git a/main.py b/main.py index 8142ab2..0824a66 100644 --- a/main.py +++ b/main.py @@ -15,10 +15,12 @@ def __init__(self, symbol): self.current_price = None self.previous_price = None + # Update the current and previous stock prices def update_price(self, new_price): self.previous_price = self.current_price self.current_price = new_price + # Check if the stock price has fallen by at least $0.25 GBP and send alert def check_price_fall(self): if self.current_price and self.previous_price: if self.current_price < self.previous_price - 0.25: @@ -32,6 +34,7 @@ def check_price_fall(self): self.previous_price, ) + # Check if current stock price is below its 7-day average and send alert def check_below_seven_day_avg(self, daily_avg): if self.current_price < daily_avg: print( @@ -45,6 +48,7 @@ def check_below_seven_day_avg(self, daily_avg): ) +# Fetch current stock price from FMP API def get_stock_price(symbol, api_token): url = f"https://financialmodelingprep.com/api/v3/quote/{symbol}?apikey={api_token}" response = requests.get(url) @@ -57,6 +61,7 @@ def get_stock_price(symbol, api_token): return None +# Fetch 7-day average stock price from FMP API def get_daily_average_price(symbol, api_token): url = f"https://financialmodelingprep.com/api/v3/historical-price-full/{symbol}?timeseries=7&apikey={api_token}" response = requests.get(url) @@ -73,6 +78,7 @@ def get_daily_average_price(symbol, api_token): if __name__ == "__main__": api_token = os.getenv("API_KEY") + # List of stocks to be monitored monitored_stocks = [ StockInfo("TSLA"), StockInfo("AAPL"), @@ -81,6 +87,7 @@ def get_daily_average_price(symbol, api_token): StockInfo("NKE"), ] + # Main loop for monitoring stock prices while True: for stock_info in monitored_stocks: new_price = get_stock_price(stock_info.symbol, api_token) diff --git a/webhook.py b/webhook.py index f58d986..c1950ca 100644 --- a/webhook.py +++ b/webhook.py @@ -7,6 +7,7 @@ load_dotenv() +# Function to send a webhook to IFTTT def send_ifttt_webhook(event, message): webhook_key = os.getenv("WEBHOOK_KEY") url = f"https://maker.ifttt.com/trigger/{event}/with/key/{webhook_key}" @@ -18,11 +19,13 @@ def send_ifttt_webhook(event, message): response = requests.post(url, json=payload) +# Function to send a price drop alert def send_price_drop(event, symbol, current_price, previous_price): message = f"ALERT: The stock {symbol} has fallen. Previous Price: ${previous_price:.2f}. Current Price: ${current_price:.2f}. Consider buying now!" send_ifttt_webhook(event, message) +# Function to send an alert when the price is below the 7-day average def send_avg_price_drop(event, symbol, current_price, daily_avg): message = f"ALERT: {symbol}'s current price of ${current_price:.2f} is below the 7-day average of ${daily_avg:.2f}. Consider buying!" send_ifttt_webhook(event, message)