KLSE Screener Python Library - Malaysian (KLSE/Bursa) stock data scraper with fundamentals, price history, and announcements
Project description
klse-screener-py
Malaysian (KLSE/Bursa Malaysia) stock data scraper. Fetch fundamentals, trading data, news, and announcements from KLSE Screener.
Features
- 17 data functions covering fundamentals, trading data, news, and announcements
- Rate-limited HTTP client (2-second intervals, respectful scraping)
- Market detection for KLSE tickers (*.KL format)
- No caching - host application controls caching strategy
- Dict-only responses - lightweight, no Pydantic dependency
- Sync-only - use with
asyncio.to_thread()or executor for async
Installation
pip install klse-screener-py
Quick Start
from klse_screener import (
get_klse_fundamentals,
get_klse_news,
get_klse_trade_summary,
get_klse_comments,
)
# Get fundamentals
data = get_klse_fundamentals("5132.KL")
print(f"P/E: {data.get('pe_ratio')}")
print(f"Dividend Yield: {data.get('dividend_yield')}")
# Get news
news = get_klse_news("5132.KL", limit=10)
print(news)
# Get order book depth
summary = get_klse_trade_summary("5132.KL")
print(f"Bid Volume: {summary.get('total_bid_volume'):,}")
print(f"Ask Volume: {summary.get('total_ask_volume'):,}")
API Reference
Fundamentals
| Function | Description | Returns |
|---|---|---|
get_klse_fundamentals(ticker) |
P/E, EPS, DY, NTA, P/B, ROE, RSI | Dict[str, Any] |
get_klse_enhanced_fundamentals(ticker) |
+ debt ratios, stochastic, volume | Dict[str, Any] |
get_klse_annual(ticker, limit=3) |
Annual revenue, profit, EPS | str |
get_klse_quarterly_history(ticker, limit=20) |
Multi-quarter history | str |
get_klse_dividends(ticker, limit=5) |
Dividend history with dates | str |
get_klse_capital_changes(ticker, limit=5) |
Splits, bonus issues | str |
Trading Data
| Function | Description | Returns |
|---|---|---|
get_klse_intraday_stats(ticker) |
High/Low/Open/Volume, Bid/Ask | Dict[str, Any] |
get_klse_trade_summary(ticker) |
Order book depth (15-min delayed) | Dict[str, Any] |
get_klse_trade_details(ticker, limit=50) |
Time-stamped trades | List[Dict] |
get_klse_warrants(ticker, limit=5) |
Warrant prices, volumes | str |
Sentiment & News
| Function | Description | Returns |
|---|---|---|
get_klse_news(ticker, limit=10) |
Stock-specific news | str |
get_klse_announcements(ticker, limit=10) |
Bursa Malaysia announcements | str |
get_klse_comments(ticker, limit=30) |
Forum discussions | List[Dict] |
get_klse_shareholding_changes(ticker, limit=20) |
Institutional transactions | str |
Market Data
| Function | Description | Returns |
|---|---|---|
get_klse_market_sentiment() |
Market overview | str |
get_klse_full_report(ticker) |
All data consolidated | Dict[str, Any] |
Formatted Wrappers
| Function | Description | Returns |
|---|---|---|
get_klse_comments_formatted(ticker, limit=30) |
Sentiment analysis + samples | str |
get_klse_trade_details_formatted(ticker, limit=50) |
Volume breakdown | str |
get_klse_trade_summary_formatted(ticker) |
Bid/ask pressure | str |
Usage Examples
Async Usage
import asyncio
from klse_screener import get_klse_fundamentals
async def get_data():
# Run sync function in thread pool
data = await asyncio.to_thread(get_klse_fundamentals, "5132.KL")
return data
asyncio.run(get_data())
Batch Processing
from concurrent.futures import ThreadPoolExecutor
from klse_screener import get_klse_fundamentals
stocks = ["5132.KL", "7152.KL", "9172.KL"]
with ThreadPoolExecutor(max_workers=5) as executor:
results = list(executor.map(get_klse_fundamentals, stocks))
for stock, data in zip(stocks, results):
print(f"{stock}: P/E={data.get('pe_ratio')}")
Error Handling
from klse_screener import get_klse_fundamentals
data = get_klse_fundamentals("5132.KL")
if "error" in data:
print(f"Error: {data['error']}")
else:
print(f"Success: {data}")
Rate Limiting
- 2-second interval between requests (enforced globally)
- 10 requests/minute maximum
- Automatic backoff on errors
Ticker Format
KLSE tickers use the format {code}.KL:
5132.KL- Deleum Berhad7152.KL- Yinson Holdings9172.KL- FPI Corporation
Non-KLSE tickers return empty results (no-op).
Limitations
- 15-minute delayed trading data (per Bursa Malaysia regulations)
- Market sentiment function has limited data (KLSE Screener removed some widgets)
- HTML parsing - may break if KLSE Screener changes layout
License
MIT License - see LICENSE file.
Contributing
- Fork the repository
- Create a feature branch
- Make your changes
- Run tests:
pytest tests/ - Submit a pull request
Development
# Install dev dependencies
pip install -e ".[dev]"
# Run tests
pytest tests/ -v
# Run linting
ruff check src/ tests/
Changelog
0.1.0 (2026-04-21)
- Initial release
- 17 data functions extracted from FinGenius
- Rate-limited HTTP client
- Market detection utility
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file klse_screener_py-3.1.2.tar.gz.
File metadata
- Download URL: klse_screener_py-3.1.2.tar.gz
- Upload date:
- Size: 39.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
3d1a3830c6ab4a094381f2065d2e38e656d0b53937254768f7ca63cf1b15a513
|
|
| MD5 |
00bc9c1d2c8b71b0ed272de7e0b70155
|
|
| BLAKE2b-256 |
c36bd3ff76c4a5eb4dd808c80f754cca340589ebe12c409ced7deac36b0b0d8b
|
File details
Details for the file klse_screener_py-3.1.2-py3-none-any.whl.
File metadata
- Download URL: klse_screener_py-3.1.2-py3-none-any.whl
- Upload date:
- Size: 34.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
d0f22bc27af1e8de647419d437e1f9b1ddb551f6d761e808da3b3d003c226e35
|
|
| MD5 |
9398de916f470f5b3706e4914a303cd3
|
|
| BLAKE2b-256 |
84588398849cdf78e42ebb5cf2805e5354e40ec6b09b5cd14741953d1ef1ac35
|