From e2fc08e76eea51c6a233b58ec5cb778877812dc3 Mon Sep 17 00:00:00 2001 From: Ayoubkhalil97 <100157383+Ayoubkhalil97@users.noreply.github.com> Date: Fri, 25 Aug 2023 11:13:05 +0100 Subject: [PATCH] stock price alerts --- README.md | 43 +++--------------- __pycache__/price_alert_utils.cpython-311.pyc | Bin 0 -> 2329 bytes main.py | 24 ++++++++++ price_alert_utils.py | 27 +++++++++++ price_alert_utils_tests.py | 35 ++++++++++++++ 5 files changed, 92 insertions(+), 37 deletions(-) create mode 100644 __pycache__/price_alert_utils.cpython-311.pyc create mode 100644 main.py create mode 100644 price_alert_utils.py create mode 100644 price_alert_utils_tests.py diff --git a/README.md b/README.md index 9e6c192..79159f0 100644 --- a/README.md +++ b/README.md @@ -1,40 +1,9 @@ -# 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 +# Stock Price Alert System 📈 -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. +This project is designed to monitor stock prices of given symbols and alert via IFTTT if the stock price for a given day is significantly different from the average of the previous days. -#### 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. +## 📁 Files: -## 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! +- **`main.py`**: This is the primary script which periodically fetches the stock prices for the symbols, calculates the average, and checks if an alert needs to be triggered. +- **`price_alert_utils.py`**: Contains utility functions to fetch stock prices and to send notifications to IFTTT. +- **`price_alert_utils_tests.py`**: Contains unit tests for the utility functions provided in `price_alert_utils.py`. diff --git a/__pycache__/price_alert_utils.cpython-311.pyc b/__pycache__/price_alert_utils.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ce462db9bece8abd1aab3d2887ad0d621bb28595 GIT binary patch literal 2329 zcma)7%Wo4$7@vK5Z4;c-32%XslOmVk&7&nKgjAtG0ac+8s031FZFV=#CL6E2GmeS7 zh8(DrR!F515|IEYmr^4*%2KVBB313B+$`mSxU}D_<2B(SF&=;O&3uoY z{bqi@{iUrfgrJ?x{i~hg5&DNtnvLC1*7tyN2Wd!SOmqcl>dKGwSeH%qxq_Y{ z_5!9S9gDp@FJHpCjb&xQvL%nY5g>4OLGmrf!o|ju<9RW*1(DMoa?})tbwW77k45M4e7;_+_+|GM`S4n3k%T zcodYTBfSBbB481fI|dtl<RDodO@LR*5I6LdV&-&jGl`HZ;)S_M%XGI)Dv;06ucmUg>4vGI zWR29UzTirFM$1|>6gGjgRtD=XPj~N%UXidHCYGiwG)m?Mp6fC%mjwy@8{ASal zxzV>&*p7jPLKOGFwOK^95B8QLUqD}(Z;VgAZH$Yj>ugvUT#N3$J+dNIqKRrWu_V=` z_CKZle@Oc)QoJg~%Tl}++5ThkhvN6wZ(d*GYu*8sG&q+^$6&Q%a7nCf+p~P(_RLav zt#kXbxQtiWWqdDO>Flm{cK?h^hgajP1FP}JM=J-0st1NDokL5(T4dMqnR2A3EcLut z3rDNr?mA+GBQ3EewUxIXE^Pw=eYL+aR-~b-G*o`0zks$D?xNv?E#c+pr#T?JzakA( zrGav@*E#Tou)o4xOT(B#>E?0vcmzF*L_XWaJ=@!L{0R5#$Ue}2-^qYwvr*ln z-oHTs;s*G6v`fLx7X^oPIEUA`dt6a`Cj|?R_?UkHP<-SQZ!zEm-j9Yg^aiQHX3pQGyYqttVeFrHJ~FPHyHCwlcEyhcp)}TNEQ#v@|-fO+eu@J5RwF- z%fvR)Y2B6!Avtf5X&G+1oZwt>o}#0FV;tBR2NR6F8){bA-T-mNBF5AL#p#(-7cX8M zjwM994eTzTwJ@`uBEZa_2z(AELU9o{BVd3|!)vSvMq3Hm&xxHt{zrlN<& zaR5c{vGy*ywhsiR0D28hTN=Abd1>u~;6NXZAA$fJh0d2Ql|$!gA3fJl7C(c_UlN~u zSPqXtUp!G~1)-ZF>ex!O^l>@bSBdsjqkV6K6(9?`fBjhjFwhj<)je2Z%3BXYuSmUB zskbck0urkc8uePI_rEScFpQX1_tr-v=-0?tl6xB7F_z$-#u=(71ds{N-VYuv0SmO? z9&LEZ5iqtkF*qJ_-U5#4t4!S@eE&ek-%Bj(ic57= 0.25: + notify_ifttt(IFTTT_WEBHOOK_KEY, "price_alert", symbol, str(today_price), str(avg_7_day)) + sleep(900) + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/price_alert_utils.py b/price_alert_utils.py new file mode 100644 index 0000000..6559eb1 --- /dev/null +++ b/price_alert_utils.py @@ -0,0 +1,27 @@ +import requests + +def fetch_price_and_avg(symbol, base_iex_url, iex_api_key): + endpoint = f"{base_iex_url}/stock/{symbol}/chart/5d?token={iex_api_key}" + try: + response = requests.get(endpoint) + response.raise_for_status() + data = response.json() + prices = [entry['close'] for entry in data] + today_price = prices[-1] + avg_7_day = sum(prices[:-1]) / len(prices[:-1]) + return today_price, avg_7_day + except requests.RequestException as e: + print(f"Error fetching data for {symbol}: {e}") + except ValueError: + print(f"Error decoding JSON for {symbol}") + return None, None + +def notify_ifttt(ifttt_webhook_key, event, value1="", value2="", value3=""): + url = f"https://maker.ifttt.com/trigger/{event}/with/key/{ifttt_webhook_key}" + data = {"value1": value1, "value2": value2, "value3": value3} + try: + response = requests.post(url, data=data) + response.raise_for_status() + except requests.RequestException as e: + print(f"Error notifying IFTTT: {e}") + return response.status_code diff --git a/price_alert_utils_tests.py b/price_alert_utils_tests.py new file mode 100644 index 0000000..f2e8535 --- /dev/null +++ b/price_alert_utils_tests.py @@ -0,0 +1,35 @@ +import unittest +from unittest.mock import patch, Mock +import price_alert_utils + +class TestPriceAlertUtils(unittest.TestCase): + + @patch("price_alert_utils.requests.get") + def test_fetch_price_and_avg_success(self, mock_get): + mock_response = Mock() + mock_response.json.return_value = [ + {"close": 100}, + {"close": 105}, + {"close": 110}, + {"close": 115}, + {"close": 120}, + ] + mock_response.raise_for_status.return_value = None + mock_get.return_value = mock_response + + today_price, avg_7_day = price_alert_utils.fetch_price_and_avg("AAPL", "https://fakeurl.com", "fake_key") + self.assertEqual(today_price, 120) + self.assertEqual(avg_7_day, 107.5) + + @patch("price_alert_utils.requests.post") + def test_notify_ifttt_success(self, mock_post): + mock_response = Mock() + mock_response.raise_for_status.return_value = None + mock_post.return_value = mock_response + + result = price_alert_utils.notify_ifttt("fake_webhook_key", "test_event") + self.assertIsNone(result) + +if __name__ == "__main__": + unittest.main() +