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
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
klse_screener_py-3.3.0.tar.gz
(44.7 kB
view details)
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.3.0.tar.gz.
File metadata
- Download URL: klse_screener_py-3.3.0.tar.gz
- Upload date:
- Size: 44.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/6.2.0 CPython/3.10.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
89c6fcb7f68a7301185a9e7eecffb42c75dd001a8dd9cc1e100dc8232d3e46d2
|
|
| MD5 |
6a98350c36b87f5cb41a2274af94b6af
|
|
| BLAKE2b-256 |
bf8a8174cb1859033dbda47bb205d0c0ca9ac32147cbed2a4ef4570912944fa0
|
File details
Details for the file klse_screener_py-3.3.0-py3-none-any.whl.
File metadata
- Download URL: klse_screener_py-3.3.0-py3-none-any.whl
- Upload date:
- Size: 37.8 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/6.2.0 CPython/3.10.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
25e5f4d2b575fc9c81e0d4e860db2dc11a053dbf4e73547a90a909c706241b3d
|
|
| MD5 |
b806e544c025c9f6d189bc0c58ba074b
|
|
| BLAKE2b-256 |
1948179eab4ac0be973249e0a7db042cf56ce6d227368f5319d8968ed11693a1
|