Skip to main content

Description

This is a Python library based on beautifulsoup4, pandas & mplfinance.
You may use it to download price history and fundamental information of companies from Dhaka Stock Exchange and Chittagong Stock Exchange, as well as market index data (DSE: DSEX, DSES, DS30, DGEN, CDSET; CSE: CASPI, CSE30, CSCX, CSE50, CSI).
Data from both exchanges comes back in the same shape (columns, order and types), so an application written against DSE output works for CSE unchanged.
This can assist you to create further analyses based on fundamental, price history and index data.
Also create Candlestick charts to analyse the price history of stocks using this easy-to-use wrapper for mplfinance.

Installation

pip install stocksurferbd

Configuration (TLS / session / timeout)

All loaders (PriceData, FundamentalData, BlockTradeData) accept optional arguments to control the underlying HTTP request:

from stocksurferbd import PriceData

# DSE's certificate chain is incomplete in some environments; disable TLS
# verification, reuse a session, or set a custom timeout if needed.
loader = PriceData(verify=False, session=None, timeout=60)

Defaults (verify=True, a fresh requests.Session, 30s timeout) preserve the previous behaviour.

PriceData also accepts cache_dir=None. When set, closed CSE download chunks (past years/months) are stored there as pandas pickles and reused by later instances and processes, so a full CSE history is downloaded once per machine:

loader = PriceData(cache_dir='cse_cache')

Usage

Downloading historical price data of a single stock-

from stocksurferbd import PriceData

loader = PriceData()

loader.save_history_data(symbol='ACI', file_name='ACI_history.xlsx', market='DSE')

The above code will create a file named- ACI_history.xlsx. It'll contain historical price data for ACI Limited in Dhaka Stock Exchange (DSE).

There are 3 parameters for this method-

  1. symbol : Provide stock symbol of the company as string.
  2. file_name : Provide the name of the history data file as string.
  3. market: Provide the market name as string from which you want to download the data. Probable values are 'CSE' and 'DSE'
  4. start_date / end_date (optional): Bound the date range. Accept a date/datetime or any parseable string. Defaults are start_date=None and end_date=None (today). With no start_date, DSE returns the window its archive serves by default (about 2 years; a DSE server limit), while CSE returns its full archive from 2015-11-24 (with gaps before mid-2018).

How CSE history is fetched. CSE does not publish per-symbol history; it publishes one spreadsheet of all symbols per date range. The library therefore downloads calendar-year chunks (about 95k rows / 4 MB / 20 s each), caches them on the PriceData instance (and in cache_dir if set) and filters to the symbol you asked for. The first CSE symbol with no dates costs ~11 downloads (3-4 minutes); every further symbol on the same instance is served from the cache in well under a second. For many symbols use get_day_end_range_df once and split by TRADING_CODE (see below).

Getting price data as a pandas DataFrame (instead of a file)-

from stocksurferbd import PriceData

loader = PriceData()

# Historical OHLCV for one symbol (includes the open price, OPENP).
hist_df = loader.get_price_history_df('ACI', market='DSE',
                                      start_date='2026-01-01', end_date='2026-06-22')

# Snapshot of all listed symbols' latest prices.
current_df = loader.get_current_price_df(market='DSE')

# Day-end OHLCV for ALL instruments on a single day (includes OPENP).
day_end_df = loader.get_day_end_df(date='2026-06-22', market='DSE')

# Day-end OHLCV for ALL instruments over a date range (both markets).
# This is the efficient way to pull many CSE symbols: one download per chunk.
range_df = loader.get_day_end_range_df('2020-01-01', '2026-06-22', market='CSE')
for symbol, frame in range_df.groupby('TRADING_CODE'):
    frame.to_excel(f'{symbol}_history.xlsx')

get_day_end_range_df(start_date, end_date=None, market='DSE', symbols=None, chunk='year', progress=True, use_cache=True):

Parameter Default Meaning
start_date required inclusive lower bound
end_date today inclusive upper bound
market 'DSE' 'DSE' loops the day-end archive once per calendar day (slower, skips non-trading days); 'CSE' downloads calendar chunks
symbols all iterable of trading codes to keep (case-insensitive)
chunk 'year' 'year' or 'month' download granularity for CSE. Monthly means more but smaller requests: better retries, cheaper short recent ranges
progress True True prints one line per download, False is silent, or a callable progress(chunk_start, chunk_end, index, total)
use_cache True False bypasses (and does not populate) the CSE memory/disk caches, e.g. after the exchange restated a day

save_day_end_range_data(file_path, file_name, market, start_date, end_date, **kwargs) writes the same frame to one Excel file.

These mirror the DataFrame-returning methods on FundamentalData, BlockTradeData and IndexData. save_history_data / save_current_data are thin wrappers over them, so file output is unchanged.

Note: the live current-price feeds do not publish an open price, so get_current_price_df has no OPENP column for either market. For open prices use get_price_history_df (one symbol, date range) or get_day_end_df (all symbols, one day) — both read the day-end sources, which include OPENP.

The day-end sources are only populated after the session closes, so get_day_end_df(date=today) called mid-session (or on a non-trading day) returns an empty DataFrame. Use get_current_price_df for live intraday prices.

For CSE, DATE and CLOSEP in the current snapshot are taken from the exchange's same-day day-end download (CSE publishes a closing price distinct from the last trade). When that download has no rows yet, CLOSEP falls back to LTP and DATE to the last trade date shown on the exchange site. % CHANGE is the absolute change LTP - YCP, which is what DSE publishes under that name.

Downloading current market price data of all listed companies in DSE/CSE-

from stocksurferbd import PriceData

loader = PriceData()

loader.save_current_data(file_name='current_data.xlsx', market='DSE')

The above code will create a file named- current_history.xlsx in the current folder. It'll contain current price data for all symbols.

There are 2 parameters for this method-

  1. file_name : Provide the name of the current price data file as string.
  2. market: Provide the market name as string from which you want to download the data. Probable values ar 'CSE' and 'DSE'

Downloading fundamental data for a list of companies available in DSE-

from stocksurferbd import FundamentalData
loader = FundamentalData()

loader.save_company_data('ACI', path='company_info')

The above code will create two files named ACI_company_data.xlsx & ACI_financial_data.xlsx in the company_info folder relative to current directory. The file named ACI_company_data.xlsx contains the fundamental data of ACI Limited for the current year and ACI_financial_data.xlsx contains year-wise fundamental data according to DSE website.

There are 2 parameters save_company_data() this method-

  1. symbol : Provide stock symbol of the company as string.
  2. path : Provide the name of the directory as string to save the company data.

The ACI_company_data.xlsx file also includes company identity and disclosure columns: company_name, website, address, financial_statement_link and price_sensitive_info_link.

Downloading company news / disclosures (last 2 years) from DSE-

from stocksurferbd import FundamentalData
loader = FundamentalData()

loader.save_news_data('ACI', path='company_info', years=2)

The above code creates ACI_news_data.xlsx in the company_info folder with columns symbol, date, title and news, sorted newest first.

DSE only. Company fundamentals and news are sourced from the DSE website; CSE is not supported for these.

Parameters of save_news_data()-

  1. symbol : Provide stock symbol of the company as string.
  2. path : Provide the directory as string to save the news data.
  3. years : Rolling time window in years (default 2). Pass years=None to download all available news.

Downloading block trade data from DSE-

from stocksurferbd import BlockTradeData
loader = BlockTradeData()

# Current day's block transactions for all listed symbols
loader.save_block_trade_data(file_name='block_trade_data.xlsx', market='DSE')

# Block-market related disclosures for one company over the last 2 years
loader.save_block_trade_news_data('ACI', path='company_info', years=2)

DSE does not publish a historical block-trade archive, so save_block_trade_data() stores the current day's actual block transactions (DATE, TRADING_CODE, MAX_PRICE, MIN_PRICE, TRADES, QUANTITY, VALUE_MN) — run it daily to build history. save_block_trade_news_data() provides a historical per-company proxy from block-market related news.

Both methods also have get_block_trades_df() and get_block_trade_news_df() variants that return a pandas DataFrame instead of writing a file.

DSE only. Block trade data is available for DSE only (market='DSE'); CSE is not supported.

Downloading market index data (DSE: DSEX, DSES, DS30, DGEN, CDSET; CSE: CASPI, CSE30, CSCX, CSE50, CSI)-

from stocksurferbd import IndexData
loader = IndexData()

# Rolling ~30 trading days of day-wise index values (DSEX, DSES, DS30, DGEN)
loader.save_index_history(file_name='index_data.xlsx', market='DSE')

# Full historical archive for any date range (data available from ~2010 onward)
loader.save_index_history(
    file_name='dsex_2020.xlsx', market='DSE',
    start_date='2020-01-01', end_date='2020-12-31',
)

# Daily history for CDSET (or DS30) by month-count — CDSET goes back to ~2016
loader.save_index_graph(index='CDSET', months=120, file_name='CDSET_history.xlsx', market='DSE')

# Live snapshot of all indices, including CDSET
loader.save_current_indices(file_name='current_indices.xlsx', market='DSE')

# Current-day per-minute ticks for a single index (incl. CDSET)
loader.save_intraday(index='CDSET', file_name='CDSET_intraday.xlsx', market='DSE')

# CSE: same methods, same frame shapes
loader.save_current_indices(file_name='cse_indices.xlsx', market='CSE')
loader.save_index_history(file_name='cse_index_2025.xlsx', market='CSE',
                          start_date='2025-01-01', end_date='2025-12-31')

These scrape the aggregate index values (not per-company share tables). DSE serves the indices in a few different ways, so there are dedicated methods:

Method DSE indices CSE indices Coverage
save_index_history / get_index_history_df DSEX, DSES, DS30, DGEN CASPI, CSE30, CSCX, CSE50, CSI rolling ~30 days by default; archive when start_date/end_date are given (DSE ~2010+, CSE late 2015+)
save_index_graph / get_index_graph_df CDSET, DS30 not available daily close over the last months (CDSET back to ~2016)
save_current_indices / get_current_indices_df DSEX, DSES, DS30, CDSET CASPI, CSE30, CSCX, CSE50, CSI live snapshot
save_intraday / get_intraday_df any one of the above (incl. CDSET) not available current day, ~1-min ticks

start_date / end_date accept a date/datetime or any parseable string (e.g. '2024-01-01'). Passing only one bounds that side; the other defaults to ~2010 (start) or today (end). For save_index_graph, months is a count (e.g. 120 for ~10 years).

Index availability varies by launch date. DGEN is legacy (pre-2013, blank in recent rows); DSEX/DS30 start Jan 2013 and DSES starts Jan 2014 in the day-wise archive. CDSET is absent from that archive — use save_index_graph(index='CDSET', ...) for its daily history. CSE has no intraday or per-index graph source, so save_intraday / save_index_graph raise for market='CSE'.

Create Candlestick charts for analyzing price history-

from stocksurferbd import CandlestickPlot

cd_plot = CandlestickPlot(file_path='ACI_history.xlsx', symbol='ACI')
cd_plot.show_plot(
    data_n=120,
    resample=True,
    step='3D'
)

The above code will create a Candlestick plot like the ones provided by Stock broker trading panels.


There are 2 parameters __init__() method of CandlestickPlot class-

  1. file_path : Provide the path of history file as string to generate plot
  2. symbol : Provide stock symbol of the company as string.


There are also 3 parameters show_plot() method-

  1. data_n : Provide an integer value. It sets the count of how many recent data points needs to be plotted.
  2. resample : Provide boolean True or False. Set True if you want to plot daily data aggregated by multiple days.
  3. step: Only Active when resample=True. Valid values are in the form- '3D' and '7D' for 3 days plots and weekly plots respectively.

The following are some example images of Candlestick plots-

Candlestick Plot

Candlestick Plot 3days

Output data schema

Each method writes an .xlsx file (and the get_*_df variants return the same data as a pandas DataFrame). The columns of each output are listed below.

The schemas below are identical for market='DSE' and market='CSE'.

Price history — PriceData.save_history_data / get_price_history_df, day-end — get_day_end_df / get_day_end_range_df

DATE, TRADING_CODE, LTP, HIGH, LOW, OPENP, CLOSEP, YCP, TRADE, VALUE_MN, VOLUME

DATE is a YYYY-MM-DD string, TRADING_CODE a string, every other column a float; rows are newest first. VALUE_MN is in millions of Taka.

Current prices — PriceData.save_current_data / get_current_price_df

DATE, TRADING_CODE, LTP, HIGH, LOW, CLOSEP, YCP, % CHANGE, TRADE, VALUE_MN, VOLUME

DATE is a datetime.date; % CHANGE is the absolute change LTP - YCP.

Note: the price files are written with the DataFrame index, so they also contain a leading unnamed index column.

Company data — FundamentalData.save_company_data → <symbol>_company_data.xlsx

One row per company. Columns, grouped:

  • Identity / links (new in 1.0.0): company_name, website, address, financial_statement_link, price_sensitive_info_link
  • Basic: symbol, auth_capital, trade_start, paid_up_capital, instrument_type, face_value, market_lot, ltp, last_agm_date, market_cap, outstanding_share, sector, listing_year, market_category
  • Dividend / reserves: right_issue, year_end, reserve_w_oci, others_oci, cash_dividend_p, cash_dividend_year, stock_dividend_p, stock_dividend_year
  • Shareholding %: sh_director, sh_govt, sh_inst, sh_foreign, sh_public
  • Interim EPS (_q1, _q2, _hy, _q3, _9m, _yr suffixes): eps_basic_*, eps_diluted_*, eps_cop_basic_*, eps_cop_diluted_*

The identity/links columns are appended at the end, so existing column positions are unchanged (backward compatible).

Financial data — FundamentalData.save_company_data → <symbol>_financial_data.xlsx

One row per financial year: symbol, year, eps_original, eps_restated, eps_diluted, eps_cop_original, eps_cop_restated, eps_cop_diluted, nav_original, nav_restated, nav_diluted, pco, profit, tci, pe_original, pe_restated, pe_diluted, pe_cop_original, pe_cop_restated, pe_cop_diluted, dividend_p, dividend_yield_p

Company news — FundamentalData.save_news_data → <symbol>_news_data.xlsx (new in 1.0.0)

One row per news item, newest first: symbol, date, title, news

Block trades (current day) — BlockTradeData.save_block_trade_data (new in 1.0.0)

One row per block transaction for the latest trading day: DATE, TRADING_CODE, MAX_PRICE, MIN_PRICE, TRADES, QUANTITY, VALUE_MN

Market indices — IndexData

Method Columns
save_index_history DATE, TOTAL_TRADE, TOTAL_VOLUME, VALUE_MN, MARKET_CAP_MN, then one column per index: DSEX, DSES, DS30, DGEN (DSE) or CASPI, CSE30, CSCX, CSE50, CSI (CSE)
save_index_graph INDEX, DATE, POINTS
save_current_indices INDEX, POINTS, CHANGE, PCT_CHANGE (one row per index; CHANGE/PCT_CHANGE are blank for CDSET; both markets)
save_intraday INDEX, DATETIME, POINTS

Block-trade news proxy — BlockTradeData.save_block_trade_news_data → <symbol>_block_trade_news.xlsx (new in 1.0.0)

Block-market related disclosures (a filtered view of the news feed): symbol, date, title, news

If you want to contribute

Any contribution would be highly appreciated. Kindly go through the guidelines for contributing.

Metadata

Release files for stocksurferbd 2.0.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for stocksurferbd 2.0.0
File Size Uploaded
stocksurferbd-2.0.0.tar.gz 35.6 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for stocksurferbd 2.0.0
File Interpreter ABI Platform
stocksurferbd-2.0.0-py3-none-any.whl Python 3 none any Details

Total release size: 69.4 kB

Release files / stocksurferbd-2.0.0.tar.gz

Download URL stocksurferbd-2.0.0.tar.gz
Size 35.6 kB
Tags Source
SHA-256 checksum
How to use checksums
a6d7056179573f2de736f61dab1d175b21aad3a385234dd3e735511cb6913285
BLAKE2b-256 checksum
How to use checksums
132a2f4bd287daee075c52f0b76f9523cbec2a055c9de0b56ec3dc51eb3aac3b
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 16, 2026.

Transparency log

Release files / stocksurferbd-2.0.0-py3-none-any.whl

Download URL stocksurferbd-2.0.0-py3-none-any.whl
Size 33.8 kB
Tags Python 3
SHA-256 checksum
How to use checksums
f3ad6597cc950770820b7f913c0fe18b75cc61d1dac6f923ea2b010a9f53d269
BLAKE2b-256 checksum
How to use checksums
ac2670e6216bef2b88c9cf8fdd4dd5a3952067d672b2209ad4395cd981d67f9f
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 16, 2026.

Transparency log
Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page