Skip to content
Open

test #14

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# Auto detect text files and perform LF normalization
* text=auto
153 changes: 153 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
config.py
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class

# C extensions
*.so

# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
share/python-wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST

# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec

# Installer logs
pip-log.txt
pip-delete-this-directory.txt

# Unit test / coverage reports
htmlcov/
.tox/
.nox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
*.py,cover
.hypothesis/
.pytest_cache/
cover/

# Translations
*.mo
*.pot

# Django stuff:
*.log
local_settings.py
db.sqlite3
db.sqlite3-journal

# Flask stuff:
instance/
.webassets-cache

# Scrapy stuff:
.scrapy

# Sphinx documentation
docs/_build/

# PyBuilder
.pybuilder/
target/

# Jupyter Notebook
.ipynb_checkpoints

# IPython
profile_default/
ipython_config.py

# pyenv
# For a library or package, you might want to ignore these files since the code is
# intended to run in multiple environments; otherwise, check them in:
# .python-version

# pipenv
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
# However, in case of collaboration, if having platform-specific dependencies or dependencies
# having no cross-platform support, pipenv may install dependencies that don't work, or not
# install all needed dependencies.
#Pipfile.lock

# poetry
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
# This is especially recommended for binary packages to ensure reproducibility, and is more
# commonly ignored for libraries.
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
#poetry.lock

# PEP 582; used by e.g. github.com/David-OConnor/pyflow
__pypackages__/

# Celery stuff
celerybeat-schedule
celerybeat.pid

# SageMath parsed files
*.sage.py

# Environments
.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/

# Spyder project settings
.spyderproject
.spyproject

# Rope project settings
.ropeproject

# mkdocs documentation
/site

# mypy
.mypy_cache/
.dmypy.json
dmypy.json

# Pyre type checker
.pyre/

# pytype static type analyzer
.pytype/

# Cython debug symbols
cython_debug/

# PyCharm
# JetBrains specific template is maintainted in a separate JetBrains.gitignore that can
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
# and can be added to the global gitignore or merged into this file. For a more nuclear
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
#.idea/
108 changes: 108 additions & 0 deletions main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
import requests
import config
from datetime import date, timedelta


Copy link

@Arjun-berko Arjun-berko Oct 16, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In general your code is very well organised and clear to read, with the way you've added comments at the start of each block and separated them out

# --------- GENERAL -----------
# IFTTT Webhooks credentials, for now
event_name = ""

# Calculate the start and end dates in YYYY-MM-DD format for the 7-day period,

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

character limit for comments is 72

# with end_date being yesterday and start_date being 7 days ago.
today = date.today()

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe put the finding of start dates and end dates in a function, that would increase clarity

end_date = today - timedelta(days=1)
start_date = end_date - timedelta(days=6)

# --------- 7 DAY AVERAGE -----------
# Function to get the stock data from the last 7 days and return JSON response
def get_previous_7_days(api, start_date, today):
tickers = ["TSLA", "AAPL", "MSFT", "GOOG", "NKE"]
response = {}
for ticker in tickers:
url = f"https://api.twelvedata.com/time_series?symbol={ticker}&interval=1day&start_date={start_date}&end_date={today}&apikey={api}"

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

character limit for code is 79

response[ticker] = requests.get(url).json()
return response

# Calculate the 7-day average price for each ticker
data_7_days = get_previous_7_days(config.api_key1, start_date, today)

for ticker, stock_data in data_7_days.items():
closing_prices = [float(day['close']) for day in stock_data['values']]
average = sum(closing_prices) / len(closing_prices)
print(f"{ticker} Average Closing Price: {average:.2f}")


# --------- REAL-TIME PRICE -----------
# Function to retrieve real-time price
def get_realtime_price(api):
tickers = ["TSLA", "AAPL", "MSFT", "GOOG", "NKE"]
response = {}
for ticker in tickers:
url = f"https://api.twelvedata.com/price?symbol={ticker}&apikey={api}"

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can add error handling when making API requests, I didn't do that for my code either, but its worth looking into

response[ticker] = requests.get(url).json()
return response

# Store real-time price data
data_realtime = get_realtime_price(config.api_key2)


# --------- MARKET OPEN PRICE -----------

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Very good comment structure

# Function to get the market open, to compare real-time price to
def get_market_open(api, today):
tickers = ["TSLA", "AAPL", "MSFT", "GOOG", "NKE"]
response = {}
for ticker in tickers:
url = f"https://api.twelvedata.com/time_series?symbol={ticker}&interval=1day&outputsize=1&apikey={api}"
response[ticker] = requests.get(url).json()
return response

# Store market open price data
data_marketopen = get_market_open(config.api_key3, today)

# print for visualisation purposes:
for ticker, stock_data in data_marketopen.items():
open_prices = [float(day['open']) for day in stock_data['values']]
print(f"{ticker} Market Open: {open_prices}")

# --------- TRIGGER WEBHOOK IF CONDITION IS MET -----------
# Function to trigger IFTTT event
def trigger(event_name):
url = f'https://maker.ifttt.com/trigger/{event_name}/with/key/{config.ifttt_key}'
Copy link

@Arjun-berko Arjun-berko Oct 16, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You have your secret keys in a config file, which is good practice, something I wish I'd done.
Another suggestion for when you build programmes that are only meant to run on your computer are environment variables.

response = requests.post(url)
if response.status_code == 200:
print(f"Triggered the IFTTT applet for {event_name} successfully.")
else:
print(f"Failed to trigger the IFTTT applet for {event_name}.")

# Map of tickers to event names

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using dictionaries to map the stock names to their event names is such a smart idea, really centralises all event handling. Wish I'd though of that.

ticker_to_event = {
"TSLA": "TSLA_Price_Drop",
"AAPL": "AAPL_Price_Drop",
"MSFT": "MSFT_Price_Drop",
"GOOG": "GOOG_Price_Drop",
"NKE": "NKE_Price_Drop"
}

# Converting £0.25 to USD with current exchange rate
Copy link

@Arjun-berko Arjun-berko Oct 16, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a valid and smart idea for currency conversion, simply converting £0.25 to USD, and going through all the conditionals in dollars. Although, converting all the API data from USD to GBP would be better for the client, as you can then send them stock data in GBP through IFTTT.

# and assigning it a variable to calculate the variance between real time and market open
def currency_conversion(api):
response = {}
url = f"https://api.twelvedata.com/currency_conversion?symbol=GBP/USD&amount=0.25&apikey={api}"
response = requests.get(url).json()
return response

pence_to_cents = currency_conversion(config.api_key1)
pence_to_cents = pence_to_cents['amount']
print(f"Current USD value of £0.25: {pence_to_cents:.2f}")

# Check conditions and trigger the corresponding event
for ticker, stock_data in data_realtime.items():
current_price = float(stock_data['price'])
event_name = ticker_to_event.get(ticker)
market_open_price = float(data_marketopen[ticker]['values'][0]['open'])
print(f"{ticker} Current Price: {current_price:.2f}")

if current_price <= market_open_price - pence_to_cents:
trigger(event_name)
elif current_price < average:
trigger(event_name)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You need an if name == main block at the end. Any code inside this block is what gets executed whenever you run this file in the terminal

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also you could've written some tests. For example, to check:

  • if data is being fetched from the API correctly as required
  • if the function calculating the weekly average is working as required