TSLA @ USD 571.62
📈 up +31.22 (last 15 minutes)
BTC-USD @ USD 91'494.52
📈 up +5'188.43 (last 11 hours)
TSLA @ USD 571.62
📈 up +31.22 (last 15 minutes)
BTC-USD @ USD 91'494.52
📈 up +5'188.43 (last 11 hours)
| #!/usr/bin/env python | |
| # -*- coding: utf-8 -*- | |
| # ~~~~~ | |
| # Telegram Bot API configs for stock_notifications.py | |
| # ~~~~~ | |
| token='' | |
| chat='' |
| #!/usr/bin/env python | |
| # -*- coding: utf-8 -*- | |
| # ~~~~~ | |
| # == Setup == | |
| # % pip3 install [--user] requests | |
| # % pip3 install [--user] yfinance | |
| # | |
| # Add and make Python-scripts executable: | |
| # % chmod +x ./stock_price_notifier.py | |
| # % chmod +x ./botconfigs.py | |
| # | |
| # == Usage == | |
| # one time (repeat every minute): | |
| # % python3 ./stock_price_notifier.py "BTC-USD" | |
| # | |
| # running as a service (every 1 hour): | |
| # % nohup python3 ./stock_price_notifier.py "TSLA" 3600 & | |
| # | |
| # running as a service (every 11 hours, if threshold above 99. 9): | |
| # % nohup python3 ./stock_price_notifier.py "TSLA" 3600 99.9 & | |
| # | |
| # ~~~~~ | |
| # Original source: https://codeburst.io/indian-stock-market-price-notifier-bot-telegram-92e376b0c33a | |
| # Resources: | |
| # - Symbol: https://finance. yahoo.com/quote/TSLA?p=TSLA | |
| # - YF for Python: https://pypi.org/project/fix-yahoo-finance/0.1.30/ | |
| # - YF4P docu: https://aroussi.com/post/python-yahoo-finance | |
| # - Telegram Bot API: https://core.telegram.org/bots/api#sendmessage | |
| # ~~~~~ | |
| import sys | |
| import gc | |
| import time | |
| import requests | |
| import urllib.parse | |
| import yfinance as yf | |
| import botconfigs as bot | |
| # Check for stock symbol passed as script parameter | |
| if len(sys.argv) <= 1: | |
| print("Missing a valid symbol as parameter. Use something like 'TSLA' or 'BTC-USD'...") | |
| sys.exit(1) | |
| else: | |
| symbol = sys.argv[1] | |
| # Check for passed timer seconds parameter | |
| if len(sys.argv) <= 2: | |
| # Default: 1 minute = 60 seconds | |
| repeat = 60 | |
| elif int(sys.argv[2]) >= 1: | |
| repeat = int(sys.argv[2]) | |
| else: | |
| print("Invalid second parameter: must be a number representing seconds to re-run script.") | |
| sys.exit(1) | |
| # Check for optional price notification threshold as 3rd parameter | |
| if len(sys.argv) <= 3: | |
| # Default: very low threshold of 0. 01 (so it needs at least a change) | |
| price_threshold = 0.01 | |
| elif float(sys.argv[3]) > 0.00: | |
| price_threshold = float(sys.argv[3]) | |
| else: | |
| print("Invalid 3rd parameter: must be a positive number as price change threshold (e.g. 1.00).") | |
| sys. exit(1) | |
| # Global vars | |
| currency = '' | |
| price_initial = 0 | |
| price = 0 | |
| # Check for valid Telegram Bot Configs from botconfigs.py | |
| if len(bot.token) > 40 and len(bot.chat) > 5: | |
| bot_token = bot.token | |
| bot_chatID = bot.chat | |
| else: | |
| print("Missing botconfigs!") | |
| sys.exit(1) | |
| # Get currency for symbol | |
| if currency == '': | |
| try: | |
| ticker_meta = yf.Ticker(symbol) | |
| ticker_info = ticker_meta.info | |
| # Try different ways to get currency | |
| if 'currency' in ticker_info: | |
| currency = ticker_info['currency'] | |
| elif 'financialCurrency' in ticker_info: | |
| currency = ticker_info['financialCurrency'] | |
| else: | |
| # Default currency if none found | |
| print(f"No currency info found for {symbol}, using USD") | |
| currency = 'USD' | |
| except Exception as e: | |
| print(f"Error getting currency for {symbol}: {e}") | |
| currency = 'USD' | |
| def getStock(): | |
| global symbol | |
| global price_threshold | |
| global currency | |
| global price_initial | |
| global price | |
| try: | |
| # Get ticker data | |
| ticker = yf.download(symbol, period="1d", auto_adjust=True) | |
| # Check if we got data | |
| if ticker.empty: | |
| print(f"No data received for {symbol}") | |
| return | |
| # Get the latest close price (last row, Close column) | |
| price = float(ticker['Close'].iloc[-1].iloc[0]) | |
| # Get initial price if not set | |
| if price_initial == 0: | |
| price_initial = float(ticker['Open']. iloc[0].iloc[0]) | |
| # Round after conversion | |
| price = round(price, 2) | |
| price_initial = round(price_initial, 2) | |
| if price == price_initial: | |
| price_diff = 0 | |
| price_diff_str = '' | |
| elif price > price_initial: | |
| price_diff = round(price - price_initial, 2) | |
| price_diff_str = f"📈 up {str("+{0:,.2f}".format(price_diff)).replace(',', '\'')}" | |
| else: | |
| price_diff = round(price_initial - price, 2) | |
| price_diff_str = f"📉 dip {str("-{0:,.2f}".format(price_diff)).replace(',', '\'')}" | |
| # Price diff above given threshold AND change of stock price | |
| if abs(price_diff) >= price_threshold: | |
| time_checks_str = '' | |
| if repeat >= 86400: | |
| time_checks = int(repeat // 86400) | |
| time_checks_str = f" (last {time_checks} {'day' if time_checks == 1 else 'days'})" | |
| elif repeat >= 3600: | |
| time_checks = int(repeat // 3600) | |
| time_checks_str = f" (last {time_checks} {'hour' if time_checks == 1 else 'hours'})" | |
| elif repeat >= 60: | |
| time_checks = int(repeat // 60) | |
| time_checks_str = f" (last {time_checks} {'minute' if time_checks == 1 else 'minutes'})" | |
| else: | |
| time_checks_str = f" (last {repeat} {'second' if repeat == 1 else 'seconds'})" | |
| message = symbol+" @ *"+currency+" "+str("{0:,.2f}". format(price)).replace(',', '\'')+"*\n"+price_diff_str+time_checks_str | |
| reserved_chars = ['(', ')', '?', '+', '-', '.', '^', '$'] | |
| for char in reserved_chars: | |
| message = message.replace(char, f"\\{char}") | |
| message = urllib.parse.quote_plus(message) | |
| send = 'https://api.telegram.org/bot' + bot_token + '/sendMessage?parse_mode=MarkdownV2&disable_notification=true&chat_id=' + bot_chatID + '&text=' + message | |
| try: | |
| response = requests.get(send) | |
| response.raise_for_status() # Raise an exception for bad status codes | |
| # Set new price_initial to check against future changes | |
| price_initial = price | |
| except requests.exceptions.RequestException as e: | |
| print(f"Error sending Telegram message: {e}") | |
| return | |
| except Exception as e: | |
| print(f"Error in yfinance: {e}") | |
| return | |
| finally: | |
| # Clean up memory | |
| del ticker | |
| gc.collect() # Force garbage collection | |
| while True: | |
| getStock() | |
| time. sleep(repeat) | |
| gc. collect() # Additional garbage collection after each iteration |
| MIT License | |
| Copyright (c) 2025 Oliver <https://github.com/oliveratgithub> | |
| Permission is hereby granted, free of charge, to any person obtaining a copy | |
| of this software and associated documentation files (the "Software"), to deal | |
| in the Software without restriction, including without limitation the rights | |
| to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
| copies of the Software, and to permit persons to whom the Software is | |
| furnished to do so, subject to the following conditions: | |
| The above copyright notice and this permission notice shall be included in all | |
| copies or substantial portions of the Software. | |
| THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
| IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
| FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
| AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
| LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
| OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |
| SOFTWARE. |
😭 Help...
Update yfinance to 0.2.3, turns to this:
OK, solved.
Here is how:
Reconfige and reinstall the Pyhone 3 with sqlite.
Update to latest yfinance 0.1.94 , seems working again now~
😀