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. |
It works! Thanks! 👍
Awesome 😎 I have to upgrade on my server as well then…
Help, I just found many stocks in Shanghai market, symbol likes '600307.ss' '600282.ss' and so on can't fetch the data.
@ruleroller can you try making a „simple“ Python Script to not do more than trying to fetch one of these symbols, in order to see if it‘s a Yfinance data issue? Here‘s a short guide that you could adapt: https://analyticsindiamag.com/hands-on-guide-to-using-yfinance-api-in-python/
Help, I just found many stocks in Shanghai market, symbol likes '600307.ss' '600282.ss' and so on can't fetch the data.
@ruleroller can you try making a „simple“ Python Script to not do more than trying to fetch one of these symbols, in order to see if it‘s a Yfinance data issue? Here‘s a short guide that you could adapt: https://analyticsindiamag.com/hands-on-guide-to-using-yfinance-api-in-python/
@oliveratgithub, thanks for your advise, but I know little python.
I googled, found that maybe the the VPS's IP reached the limit of the yfinance, or just yfinance data has temporary issue, or something else.
I also tried this script in another server and run the script for several hours, everything is fine for now (image below).

👍
I get this error message
File "", line 1
python3 ./stock_notifications.py "TSLA"
^
SyntaxError: invalid syntax
and when i run it as normal it shows
Missing a valid symbol as parameter. Use something like 'TSLA' or 'BTC-USD'...
repl process died unexpectedly:
I get this error message
File "", line 1 python3 ./stock_notifications.py "TSLA" ^ SyntaxError: invalid syntax and when
@aoi2010 That sounds super strange.
Can you run other python scripts successfully?
And have you installed all required prerequisites (libraries) using pip?
Is the path to the stock_notifications.py actually correct (when you do ./ you should be in the same directory as the Script is stored in…)?
Hi, again~
Mine is not working for about one week, with Python 3.8.16, and the modules are also up to date, but still can't help.
Any idea to solve this?
Thanks for bringing this to my attention @ruleroller – I think it’s related to this issue within the yfinance library, respectively that Yahoo started obfuscating the data: ranaroussi/yfinance#1246
I will need to adapt the decryption (there’s a python example in the Issue discussion linked above).
Update: a Fix is already in the works on level of the yfinance Library (where this issue should be handeld anyway IMHO). Let’s wait for this patch to be applied. ranaroussi/yfinance#1253
Hi, again~
Mine is not working for about one week, with Python 3.8.16, and the modules are also up to date, but still can't help.
Any idea to solve this?Thanks for bringing this to my attention @ruleroller – I think it’s related to this issue within the yfinance library, respectively that Yahoo started obfuscating the data: ranaroussi/yfinance#1246
I will need to adapt the decryption (there’s a python example in the Issue discussion linked above).Update: a Fix is already in the works on level of the yfinance Library (where this issue should be handeld anyway IMHO). Let’s wait for this patch to be applied. ranaroussi/yfinance#1253
Update to latest yfinance 0.1.94 , seems working again now~
😀
😭 Help...
Update yfinance to 0.2.3, turns to this:
OK, solved.
Here is how:
Reconfige and reinstall the Pyhone 3 with sqlite.
It works! Thanks! 👍