Skip to main content

Client & core functions

psxdata exposes two usage patterns. You can call module-level convenience functions directly — no class instantiation needed — or create a PSXClient instance when you need a dedicated cache directory or want to manage the client lifetime explicitly.
Both patterns share the same underlying scrapers and caching logic. All functions that accept a cache parameter respect a 15-minute TTL for intraday data; historical rows (before today) are cached indefinitely.

PSXClient

Public Python API for Pakistan Stock Exchange data. All scrapers are instantiated once in __init__ and reused across calls. Caching is managed by the client — scrapers never touch the cache directly.

Constructor

cache_dir
str
default:"~/.psxdata/cache/"
Path to the on-disk cache directory. A tilde (~) is expanded to the current user’s home directory. The directory is created automatically if it does not exist.

Module-level functions

psxdata.stocks()

Fetch historical OHLCV data for a PSX-listed symbol. PSX returns the full price history in a single HTTP request. The response is split at today’s boundary and stored under two cache keys:
  • {SYMBOL}_historical — rows before today, never expires.
  • {SYMBOL}_today — rows from today, expires after 15 minutes.
Successive calls for the same symbol within the TTL window return the cached data without a network request.

Parameters

symbol
str
required
PSX ticker symbol, e.g. "ENGRO". Case-insensitive — converted to uppercase internally.
start
date | str | None
default:"None"
Start date (inclusive). Accepts a datetime.date, an ISO-format string such as "2024-01-01", or None. None means the earliest available date for the symbol.
end
date | str | None
default:"None"
End date (inclusive). Accepts the same types as start. None means today.
cache
bool
default:"True"
If False, bypass the local cache and always fetch fresh data from PSX.

Return value

Returns a pd.DataFrame. Returns an empty DataFrame if no data is available for the given date range.
date
datetime64[ns]
required
Trading date.
open
float64
required
Opening price.
high
float64
required
Intraday high price.
low
float64
required
Intraday low price.
close
float64
required
Closing price.
volume
int64
required
Number of shares traded.
is_anomaly
bool
required
True if the row was flagged as anomalous during scraping (e.g. zero-volume days with unchanged prices). Useful for filtering before analysis.

Exceptions


psxdata.quote()

Fetch the latest screener snapshot for a symbol. The full screener (approximately 729 symbols) is fetched in a single request and cached for 15 minutes. Successive calls for different symbols reuse the same cached screener, so only the first call within a 15-minute window incurs a network request.

Parameters

symbol
str
required
PSX ticker symbol, e.g. "ENGRO". Case-insensitive.
cache
bool
default:"True"
If False, bypass the local cache and always fetch the full screener.

Return value

Returns a single-row pd.DataFrame with screener columns. Returns an empty DataFrame if the symbol is not present in the screener.
symbol
object
required
PSX ticker symbol.
sector
object
required
Sector name as listed on PSX.
ldcp
float64
required
Last day’s closing price.
price
float64
required
Current market price.
market_cap
float64
required
Market capitalisation in PKR.
pe_ratio
float64
required
Price-to-earnings ratio. May be NaN for loss-making companies.
dividend_yield
float64
required
Trailing dividend yield as a decimal, e.g. 0.045 for 4.5 %.
change
float64
required
Absolute price change from LDCP.
change_pct
float64
required
Percentage price change from LDCP.

Exceptions


psxdata.tickers()

Return PSX ticker symbols, optionally filtered to a named index.
tickers(index="KSE100") and indices("KSE100") share the same cache key (indices_KSE100), so calling both methods never results in a double network request.

Parameters

index
str | None
default:"None"
Index name, e.g. "KSE100". None returns all listed symbols. See psxdata/constants.py (INDEX_NAMES) for the full list of valid names.
cache
bool
default:"True"
If False, bypass the local cache.

Return value

Returns list[str] — ticker strings, e.g. ["ENGRO", "LUCK", ...]. Returns an empty list if no symbols are found.

Exceptions


psxdata.symbols()

Return all listed PSX symbols with sector names. Reuses the symbols_all cache key shared with tickers(index=None), so calling both functions never results in a double network request.

Parameters

cache
bool
default:"True"
If False, bypass the local cache and always fetch fresh data from PSX.

Return value

Returns a pd.DataFrame. Returns an empty DataFrame if PSX returns no data.
symbol
object
required
PSX ticker symbol.
name
object
required
Full company or instrument name.
sector_name
object
required
Full sector name, e.g. "CEMENT". Useful for filtering symbols by sector.
is_etf
bool
required
True if the symbol is an exchange-traded fund.
is_debt
bool
required
True if the symbol is a debt instrument (e.g. a TFC).
is_gem
bool
required
True if the symbol is listed on the Growth Enterprise Market (GEM) board.

Exceptions


psxdata.indices()

Fetch constituent data for a PSX index. Returns detailed per-stock data for every constituent of the named index, including index weights and market capitalisation figures.

Parameters

name
str
required
Index name, e.g. "KSE100". See psxdata/constants.py (INDEX_NAMES) for valid values.
cache
bool
default:"True"
If False, bypass the local cache.

Return value

Returns a pd.DataFrame. Returns an empty DataFrame if PSX returns no data for the given index name.
symbol
object
required
PSX ticker symbol.
current_index
float64
required
Current index level contributed by this constituent.
idx_weight
float64
required
Weight of the constituent in the index, as a percentage.
idx_point
float64
required
Index points contributed by this constituent.
market_cap_m
float64
required
Market capitalisation in millions of PKR.
freefloat_m
float64
Free-float market capitalisation in millions of PKR. Present for free-float-weighted indices (e.g. KSE100). Absent for indices that use total shares.
shares_m
float64
Total shares in millions. Present for indices that use total shares weighting. Absent when freefloat_m is present.

Exceptions


psxdata.sectors()

Fetch the PSX sector summary. Returns one row per sector with advance/decline breadth and aggregate market capitalisation figures.

Parameters

cache
bool
default:"True"
If False, bypass the local cache.

Return value

Returns a pd.DataFrame.
sector_code
object
required
Short sector identifier code used internally by PSX.
sector_name
object
required
Full sector name.
advance
int64
required
Number of stocks that advanced (price increased) in the session.
decline
int64
required
Number of stocks that declined (price decreased) in the session.
unchanged
int64
required
Number of stocks with no price change in the session.
turnover
float64
required
Total sector turnover in PKR for the session.
market_cap_b
float64
required
Aggregate sector market capitalisation in billions of PKR.

Exceptions


psxdata.fundamentals()

Fetch the PSX financial reports filing list. PSX returns all filings in a single request. When symbol is provided, the result is filtered in memory — no additional network requests are made.

Parameters

symbol
str | None
default:"None"
If provided, return only filings for this ticker. Case-insensitive. None returns all available filings.
cache
bool
default:"True"
If False, bypass the local cache.

Return value

Returns a pd.DataFrame. Returns an empty DataFrame if outside the reporting season or if PSX returns no data.
symbol
object
required
PSX ticker symbol of the filing company.
year
int64
required
Financial year to which the filing belongs.
type
object
required
Report type, e.g. "Annual", "Half Yearly", "Quarterly".
period_ended
object
required
End date of the reporting period (formatted string as returned by PSX).
posting_date
object
required
Date the filing was posted to PSX.
posting_time
object
required
Time the filing was posted to PSX.
document
object
required
URL or filename of the filing document.

Exceptions


psxdata.debt_market()

Fetch all PSX debt market instrument tables. Returns 4 tables covering the various instrument categories listed on the PSX debt market page. The page does not include <h2> headings before its tables, so the keys are positional rather than descriptive.

Parameters

cache
bool
default:"True"
If False, bypass the local cache and always fetch from PSX.

Return value

Returns dict[str, pd.DataFrame] — a mapping of table keys to DataFrames. Returns an empty dict if no tables are found on the page.
These key names are load-bearing. Do not rely on positional integer indexing — always use the string keys "table_0" through "table_3".

Exceptions


psxdata.eligible_scrips()

Fetch all PSX margin-trading eligible scrip tables. Returns 9 tables covering the instrument categories listed on the PSX eligible scrips page. The <h2> headings on that page are not direct siblings of the <table> elements, so keys are positional rather than descriptive.

Parameters

cache
bool
default:"True"
If False, bypass the local cache and always fetch from PSX.

Return value

Returns dict[str, pd.DataFrame] — a mapping of table keys to DataFrames. Returns an empty dict if no tables are found on the page.
These key names are load-bearing. Do not rely on positional integer indexing — always use the string keys "table_0" through "table_8".

Exceptions