A Python automation project that monitors selected stocks, including US and Indian BSE-listed companies. It checks daily price movements, looks for related news when a stock moves significantly, and sends a status update to Telegram for every company being monitored.
I started this project while working through Angela Yu's 100 Days of Code - The Complete Python Pro Bootcamp. After completing the original version, I added several things of my own, including API error handling, response caching, modular code structure, environment variables for secrets, GitHub Actions for scheduled execution, support for multiple markets, and handling for cases where an API returns no useful results.
The application checks a list of configured companies and follows this process:
┌─────────────────────────┐
│ Configured Stocks │
│ US tickers (TSLA...) │
│ BSE tickers (.BSE) │
└────────────┬────────────┘
│
▼
┌─────────────────────────┐
│ Alpha Vantage API │
│ Daily Stock Prices │
└────────────┬────────────┘
│
▼
┌─────────────────────────┐
│ Calculate % Change │
│ Between Latest Days │
└────────────┬────────────┘
│
Change >= 1% ?
/ \
No Yes
│ │
▼ ▼
😴 Status Update ┌───────────────┐
(Telegram) │ News API │
│ Relevant News │
└───────┬───────┘
│
┌─────────┴─────────┐
│ │
Articles Found No Articles
│ │
▼ ▼
News Details "Zero Articles Found"
│ │
└─────────┬─────────┘
▼
Telegram
Alert: Tesla Inc (TSLA): 🔺6%
Headline: ...
Brief: ...
Headline: ...
Brief: ...
Headline: ...
Brief: ...
Alert: Bajaj Auto Limited (BAJAJ-AUTO.BSE): 🔻1%
Zero Articles found for 'Bajaj Auto Limited'
😴 Nothing exciting for ZYDUSLIFE.BSE (Zydus Lifesciences Limited) today.
-
Retrieves daily stock data from the Alpha Vantage API.
-
Compares the two most recent available daily closing prices.
-
Calculates the percentage movement.
-
Handles both upward and downward movements.
-
Uses:
- 🔺 for an increase
- 🔻 for a decrease
-
Sends a price alert when the absolute movement reaches 1% or more.
The original project used US stock examples. I extended it to also work with Indian BSE-listed companies using exchange-specific ticker formats such as:
BAJAJ-AUTO.BSE
ZYDUSLIFE.BSE
AEROFLEX.BSE
APOLLO.BSE
Each stock keeps both the ticker and the full company name.
The ticker is used when requesting data from Alpha Vantage, while the full company name is used in Telegram messages so the alerts are easier to read.
The application does not request news for every company.
News is fetched only when the stock crosses the configured price-change threshold:
Normal stock movement
↓
No news request
Significant movement
↓
Fetch relevant news
↓
Send alert
The project uses the News API /v2/everything endpoint with:
searchIn=title,description- English-language filtering
- Relevancy sorting
- Maximum of 3 returned articles
For the news search, common company suffixes such as Limited, Ltd, and Inc are removed where appropriate. The original company name is still kept unchanged for Telegram messages.
This gives the search query a better chance of matching the way companies are actually mentioned in news headlines.
A stock can have a significant price movement without having any matching articles.
The application handles that case explicitly instead of assuming that news will always be available.
For example:
Alert: Bajaj Auto Limited (BAJAJ-AUTO.BSE): 🔻1%
Zero Articles found for 'Bajaj Auto Limited'
This makes the result clear to the user and avoids treating an empty news response as an application failure.
The bot now sends a Telegram result for every monitored company, not only the companies that cross the alert threshold.
For example:
😴 Nothing exciting for AEROFLEX.BSE (Aeroflex Industries Limited) today.
So every stock ends up in one of these states:
🔺 Significant increase → Price alert
🔻 Significant decrease → Price alert
😴 No significant movement → Status update
This also makes it easy to see that the application actually checked the whole watchlist.
Instead of only printing results to the console, the application sends them to Telegram through the Telegram Bot API.
The basic flow is:
API Data
↓
Business Logic
↓
Condition Detection
↓
Notification Service
↓
Telegram
Telegram-related code is kept inside NotificationManager.
There are two public notification methods:
send_price_alert()send_status_update()
Both use a private _send() method for the actual Telegram API request.
The Telegram bot token and chat ID are loaded through environment variables instead of being written directly into the source code.
The application can also be run automatically once a day using GitHub Actions.
Workflow file:
.github/workflows/daily_check.yml
The scheduled workflow uses:
on:
schedule:
- cron: '30 1 * * *' # 01:30 UTC
workflow_dispatch: # Manual trigger01:30 UTC is 07:00 AM IST.
The API credentials are stored in GitHub Actions secrets rather than inside the repository.
The workflow expects these secret names:
STOCK_API_KEY
NEWS_API_KEY
TELEGRAM_BOT_TOKEN
TELEGRAM_CHAT_ID
The same variable names are used locally through .env, which means the Python code does not need separate credential-handling logic for local and cloud execution.
GitHub scheduled workflows run from the repository's default branch. Scheduled executions can also be delayed during periods of high GitHub Actions load. For public repositories, GitHub can automatically disable scheduled workflows after 60 days without repository activity. The workflow_dispatch trigger is included so I can also start the workflow manually when testing it.
One of the extra things I added to the project was HTTP response caching.
The application uses one shared CachedSession:
session = CachedSession(
"api_cache",
urls_expire_after={
"*.alphavantage.co": 3600,
"*newsapi.org": 900,
},
)I used different cache durations because stock data and news have different refresh needs:
| API | Cache Duration | Reason |
|---|---|---|
| Alpha Vantage | 1 hour | Daily historical stock responses can be reused during development |
| News API | 15 minutes | News changes more frequently |
This reduces repeated API requests while testing and keeps the cache configuration in one place.
The shared session is defined in:
cache_config.py
and imported by the API modules.
These are some of the decisions I made while improving the original project.
News is requested only after a stock crosses the configured threshold.
That means the application does not spend another API request on every normal stock check.
If Alpha Vantage does not return usable data for one ticker, the application reports the problem and continues with the next company.
A bad or unsupported ticker therefore does not stop the entire monitoring process.
The stock and news modules use the same cached HTTP session instead of creating separate sessions.
This gives me:
- Fewer repeated network requests
- Faster repeated development runs
- One central cache configuration
- Different expiration times for different APIs
A short delay is placed between company checks.
The purpose is to keep requests spread out instead of sending everything at once. I have intentionally avoided making a specific provider quota part of the application's logic because API limits and plans can change.
The application is divided into a few focused modules:
main.py
│
├── StockData
│
├── NewsData
│
└── NotificationManager
│
├── send_price_alert()
└── send_status_update()
This keeps stock data, news retrieval, notification handling, and the main workflow separate instead of putting everything into one file.
Daily-Stock-Alert/
│
├── .github/
│ └── workflows/
│ └── daily_check.yml
│
├── main.py
├── stock_data.py
├── news_data.py
├── notification_manager.py
├── cache_config.py
│
├── Image/
│ ├── telegram_stock_alert_bot_1.png
│ ├── telegram_stock_alert_bot_2.png
│ └── telegram_stock_alert_bot_3.png
│
├── .gitignore
├── LICENSE
└── README.md
| File | Responsibility |
|---|---|
main.py |
Main application workflow and stock monitoring loop |
stock_data.py |
Alpha Vantage requests and price-change calculation |
news_data.py |
News API requests and article extraction |
notification_manager.py |
Telegram message creation and delivery |
cache_config.py |
Shared requests-cache session and cache settings |
.github/workflows/daily_check.yml |
Scheduled GitHub Actions execution |
.gitignore |
Keeps secrets, cache files, notes, and local test files out of Git |
Image/ |
Telegram alert screenshots |
API credentials are kept outside the source code.
For local execution, create a .env file:
STOCK_API_KEY=your_alpha_vantage_key
NEWS_API_KEY=your_news_api_key
TELEGRAM_BOT_TOKEN=your_telegram_bot_token
TELEGRAM_CHAT_ID=your_telegram_chat_idThe application loads these values using python-dotenv.
The .env file should never be committed to GitHub.
It is excluded using .gitignore.
For GitHub Actions, the same values are stored as encrypted repository secrets and passed to the workflow as environment variables.
Install the required packages:
pip install requests python-dotenv requests-cacheClone the repository:
git clone https://github.com/Anjan7797/Daily-Stock-Alert.gitMove into the project directory:
cd Daily-Stock-AlertInstall the dependencies:
pip install requests python-dotenv requests-cacheCreate your local .env file with the required credentials.
Then run:
python main.pyThe current version uses one configured TELEGRAM_CHAT_ID.
- Fork or clone this repository.
- Create your own Telegram bot using @BotFather.
- Send a message to your bot.
- Retrieve the bot's chat ID.
- Add your API keys and Telegram chat ID to
.env, or add them as GitHub Actions secrets for scheduled execution. - Run the application locally or use the scheduled workflow.
For one Telegram recipient, no changes to the main application are required.
Another person can interact with the existing bot and provide their chat ID.
The current implementation is designed around a single chat ID, so supporting multiple recipients would require changing NotificationManager to work with a list of chat IDs.
- Python
- Object-Oriented Programming
- REST APIs
- HTTP requests
- JSON data handling
- Alpha Vantage API
- News API
- Telegram Bot API
- requests
- requests-cache
- python-dotenv
- Environment variables
- GitHub Actions
- Scheduled automation
- Exception handling
- API response validation
- Modular application design
- Basic API/request optimization
- Classes and objects
- Constructors
- Methods
- Conditional logic
- Loops
- Lists and dictionaries
- String formatting
- Exception handling
- Type hints
- Modular imports
- HTTP GET requests
- HTTP POST requests
- Query parameters
- JSON responses
- API authentication
- HTTP status validation
- API error handling
- Working with multiple external APIs
- Handling missing and empty API results
- Separation of concerns
- Focused modules
- Reusable classes
- Shared HTTP sessions
- Centralized configuration
- Notification abstraction
- Multiple notification message types
- API keys stored outside source code
.envfor local development- GitHub Actions secrets for cloud execution
.gitignoreprotection for sensitive/local files
- GitHub Actions scheduled workflows
- Cron syntax
- Manual workflow execution with
workflow_dispatch - Environment-based secret injection
- Conditional news retrieval
- HTTP response caching
- Cache expiration policies
- Controlled request pacing
- Reduced redundant API calls
The project checks HTTP responses using:
response.raise_for_status()However, a successful HTTP status does not necessarily mean that Alpha Vantage returned the stock data we expected.
For example, an unavailable or invalid ticker can return a response without the normal daily time-series section.
The application therefore checks for the expected data:
if "Time Series (Daily)" not in data:
print(f"⚠️ No price data returned for '{self.ticker}':")
print(data)
return FalseWhen this happens, that company is skipped and the rest of the watchlist continues.
Telegram request failures are also caught through requests exception handling so that one failed notification does not stop the entire monitoring run.
This project was developed while progressing through:
Angela Yu's 100 Days of Code - The Complete Python Pro Bootcamp
The original project introduced the basic stock and news alert idea.
From there, I added and learned about:
- Shared API sessions
- HTTP response caching
- Cache expiration policies
- Telegram Bot API integration
- Environment-variable based secret management
- Scheduled execution with GitHub Actions
- US and Indian BSE ticker support
- Handling empty or missing API responses
- API error handling
- Conditional API requests
- Request pacing
- Modular application design
The main goal was to understand how the individual pieces work together rather than just getting the script to run once.
The biggest learning point from this project was connecting several independent services into one working automation:
Stock API
↓
Python Business Logic
↓
Percentage Calculation
↓
Threshold Detection
↓
News API
↓
Graceful Empty-Result Handling
↓
Message Construction
↓
Telegram Bot API
↓
GitHub Actions Scheduled Execution
It gave me practice with more than just making API calls. I also had to think about failed requests, missing data, API limits, caching, configuration, notifications, and running the application automatically.
This is a learning and automation project, not a financial trading system or investment recommendation tool.
- Stock-data availability depends on Alpha Vantage's coverage.
- Alpha Vantage currently states that its standard free service allows 25 API requests per day. It also states that verified open-source or educational projects may qualify for unlimited requests under its current policy.
- Not every Indian BSE-listed company is guaranteed to be available through Alpha Vantage.
- News coverage can be limited for smaller or regionally listed companies, so some significant stock movements may have no matching articles.
- The News API Developer plan is intended for development/testing rather than staging or production use.
- API quotas, pricing, coverage, and provider policies can change over time.
- The application uses daily stock data rather than real-time market prices.
- The watchlist is currently configured directly in
main.py. - The current Telegram implementation supports one configured chat ID.
- Every monitored company generates a Telegram message on each run, which can become noisy as the watchlist grows.
- Telegram message length and formatting are subject to Telegram API limits.
- GitHub Actions scheduled runs may be delayed slightly.
- Public GitHub repositories can have scheduled workflows disabled after 60 days without repository activity.
Some things I may add later:
- Move the stock list into a separate configuration file.
- Support multiple Telegram recipients.
- Combine normal-movement status messages into one summary.
- Replace most
print()calls with structured logging. - Add automated tests for price-change calculations.
- Add more specific handling for different API errors.
- Include article URLs in Telegram alerts.
- Automatically split long Telegram messages when necessary.
- Add another notification channel such as email.
- Containerize the application with Docker.
- Add automated testing and linting through GitHub Actions.
- Look into an India-focused news provider for better regional coverage.
Anjan Mistry
BCA Graduate | Python | SQL | Backend & Automation Learning Journey
GitHub:
Project Repository:
This project is licensed under the MIT License.
See the LICENSE file for details.


