Skip to main content

bdshare

StyleCI Documentation Status PyPI Python License

bdshare is a Python library for fetching live and historical market data from the Dhaka Stock Exchange (DSE). It handles scraping, retries, caching, and rate limiting so you can focus on your analysis.


Table of Contents


Installation

Requirements: Python 3.7+

pip install bdshare

Install from source (latest development version):

pip install -U git+https://github.com/rochi88/bdshare.git

Dependencies installed automatically: pandas, requests, beautifulsoup4, lxml


Quick Start

from bdshare import get_current_trade_data, get_historical_data

# Live prices for all instruments
df = get_current_trade_data()
print(df.head())

# Historical data for a specific symbol
df = get_historical_data('2024-01-01', '2024-01-31', 'GP')
print(df.head())

Or use the object-oriented client:

from bdshare import BDShare

with BDShare() as bd:
    print(bd.get_market_summary())
    print(bd.get_current_trades('ACI'))

Demo App

Three full-feature demos live in demo/ — live prices, historical charts with technical indicators, market movers, news, a portfolio tracker, live tick polling, and an interactive AI-agent (MCP) tool explorer:

cd demo
docker compose up --build streamlit   # pure Python — open http://localhost:8501
docker compose up --build node node-api mcp stream  # cross-language via REST/MCP/WebSocket — open http://localhost:3000
docker compose up --build app         # Flask/Plotly candlestick-only demo — open http://localhost:9999

The Node.js demo is the interesting one if you're integrating bdshare from outside Python: it's an Express UI that never imports bdshare — it talks to a FastAPI backend over REST, to bdshare-mcp over HTTP using the official MCP SDK, and to bdshare-stream over WebSocket, showing three different ways another program can consume this library.

See demo/README.md for local (non-Docker) setup for each.


Core Concepts

Concept Details
Retries All network calls retry up to 3 times with exponential back-off
Two DSE sites Data comes from the current DSE site's JSON API (dse.com.bd) first; if that fails, bdshare falls back to the legacy site (old.dsebd.org) with the same columns. Set BDSHARE_SOURCE=legacy or BDSHARE_SOURCE=new (or bdshare.util.vars.DSE_SOURCE at runtime) to use only one site. get_price_sensitive_news(), get_company_details() and get_dividend_declarations() work only on the current site. The legacy-only get_agm_news() and get_company_info() are deprecated
Large ranges All-instrument history is fetched page by page in parallel; a month of every instrument takes about 10 seconds
Caching The BDShare client caches responses automatically (configurable TTL)
Rate limiting Built-in sliding-window limiter (5 calls/second) prevents being blocked
Errors All failures raise BDShareError — never silent

Usage Guide

Live Trading Data

from bdshare import get_current_trade_data, get_dsex_data, get_current_trading_code

# All instruments — returns columns: symbol, ltp, high, low, close, ycp, change, trade, value, volume
df = get_current_trade_data()

# Single instrument (case-insensitive)
df = get_current_trade_data('GP')

# DSEX index entries
df = get_dsex_data()

# Just the list of tradeable symbols
codes = get_current_trading_code()
print(codes['symbol'].tolist())

Historical Data

from bdshare import get_historical_data, get_basic_historical_data, get_close_price_data
import datetime as dt

start = '2024-01-01'
end   = '2024-03-31'

# Full historical data (ltp, open, high, low, close, volume, trade, value…)
# Indexed by date, sorted newest-first
df = get_historical_data(start, end, 'ACI')

# Simplified OHLCV — sorted oldest-first, ready for TA libraries
df = get_basic_historical_data(start, end, 'ACI')

# Set date as index explicitly
df = get_basic_historical_data(start, end, 'ACI', index='date')

# Rolling 2-year window
end   = dt.date.today()
start = end - dt.timedelta(days=2 * 365)
df    = get_basic_historical_data(str(start), str(end), 'GP')

# Close prices only
df = get_close_price_data(start, end, 'ACI')

Column order note: get_basic_historical_data intentionally returns OHLCV in standard order (open, high, low, close, volume) to be compatible with libraries like ta, pandas-ta, and backtrader.

Deprecated aliases: get_hist_data() and get_basic_hist_data() still work but emit a DeprecationWarning — migrate to get_historical_data() / get_basic_historical_data().

Market & Index Data

from bdshare import (
    get_market_status,
    get_market_info,
    get_market_info_more_data,
    get_market_depth_data,
    get_latest_pe,
    get_top_ten_gainers_losers,
    get_top_twenty_shares,
    get_company_details,
)

# Current market status: Open, Closed, Holiday, etc.
status = get_market_status()

# Last 30 days of market summary (DSEX, DSES, DS30, DGEN, volumes, market cap)
df = get_market_info()

# Historical market summary between two dates
df = get_market_info_more_data('2024-01-01', '2024-03-31')

# Order book (buy/sell depth) for a symbol
df = get_market_depth_data('ACI')

# P/E ratios for all listed companies
df = get_latest_pe()

# Top 10 gainers and losers (adjust limit as needed)
df = get_top_ten_gainers_losers(limit=10)

# Top 20 shares by traded volume (adjust limit as needed)
df = get_top_twenty_shares(limit=20)

# Detailed company profile (dict; tabular parts are DataFrames)
details = get_company_details('GP')
details['agmDate'], details['dividendHistory']

News & Announcements

from bdshare import get_news, get_dividend_declarations, get_all_news

# Unified dispatcher — news_type: 'all' | 'dividend' | 'corporate' | 'psn'
df = get_news(news_type='all')
df = get_news(news_type='dividend')
df = get_news(news_type='corporate', code='GP')
df = get_news(news_type='psn', code='ACI')   # price-sensitive news

# Direct function calls
df = get_dividend_declarations()             # Dividends + AGM/record dates, last 180 days
df = get_dividend_declarations('2026-01-01', '2026-06-30', code='GP')
df = get_all_news()                          # Latest news feed
df = get_all_news('2024-01-01', '2024-03-31')  # All news in a date range
df = get_all_news(code='BEXIMCO')            # All news for one symbol
df = get_all_news('2024-01-01', '2024-03-31', 'GP')  # Filtered by date + symbol

Saving to CSV

from bdshare import get_basic_historical_data, Store
import datetime as dt

end   = dt.date.today()
start = end - dt.timedelta(days=365)

df = get_basic_historical_data(str(start), str(end), 'GP')
Store(df).save()   # saves to current directory as a CSV

OOP Client (BDShare)

The BDShare class wraps all functions with automatic caching and rate limiting.

from bdshare import BDShare

bd = BDShare(cache_enabled=True)   # cache_enabled=True is the default

Context manager (auto-cleans cache and session)

with BDShare() as bd:
    data = bd.get_current_trades('GP')

Market methods

bd.get_market_summary()                    # DSEX/DSES/DS30 indices + stats  (1-min TTL)
bd.get_company_details('ACI')             # Company details                  (1-hr TTL)
bd.get_latest_pe_ratios()                 # All P/E ratios                   (1-hr TTL)
bd.get_top_movers(limit=10)               # Top gainers/losers               (5-min TTL)

get_market_status() and get_top_twenty_shares() don't have BDShare wrapper methods yet — call the module-level functions directly (see API Reference).

Trading methods

bd.get_current_trades()                   # All live prices                  (30-sec TTL)
bd.get_current_trades('GP')               # Single symbol
bd.get_dsex_index()                       # DSEX index entries               (1-min TTL)
bd.get_trading_codes()                    # All tradeable symbols            (24-hr TTL)
bd.get_historical_data('GP', '2024-01-01', '2024-03-31')    # OHLCV history

News methods

bd.get_news(news_type='all')              # All news                         (5-min TTL)
bd.get_news(news_type='corporate', code='GP')
bd.get_news(news_type='psn')             # Price-sensitive news

Utility methods

bd.clear_cache()                          # Flush all cached data
bd.configure(proxy_url='http://proxy:8080')
print(bd.version)                         # Package version string

Error Handling

All failures raise BDShareError. Never catch bare Exception — you'll miss bugs.

from bdshare import BDShare, BDShareError

bd = BDShare()

try:
    df = bd.get_historical_data('INVALID', '2024-01-01', '2024-01-31')
except BDShareError as e:
    print(f"DSE error: {e}")
    # safe fallback logic here

Common causes of BDShareError:

  • Symbol not found in the response table
  • DSE site returned a non-200 status after all retries
  • Table structure changed on the DSE page (report as a bug)
  • Network timeout

Deprecated Functions

These read only the legacy site (old.dsebd.org). They still work but emit a DeprecationWarning, and will be removed in 2.0.0.

Deprecated Use instead Why
get_agm_news() get_dividend_declarations() The legacy AGM page has not been updated since 2020
get_news(news_type='agm') get_news(news_type='dividend') Same as above
get_company_info(symbol) get_company_details(symbol) Returns a dict with DataFrames instead of the legacy page's list of tables
get_company_inf(symbol) get_company_details(symbol) Old alias of get_company_info
BDShare.get_company_profile(symbol) BDShare.get_company_details(symbol) Wraps get_company_info
get_hist_data(), get_basic_hist_data() get_historical_data(), get_basic_historical_data() Old short names
get_market_inf(), get_market_inf_more_data() get_market_info(), get_market_info_more_data() Old short names

API Reference

Trading Functions

Function Parameters Returns Description
get_current_trade_data(symbol?) symbol: str DataFrame Live prices (all or one symbol)
get_dsex_data(symbol?) symbol: str DataFrame DSEX index entries
get_current_trading_code() — DataFrame All tradeable symbols
get_historical_data(start, end, code?) str, str, str DataFrame Full historical OHLCV
get_basic_historical_data(start, end, code?, index?) str, str, str, str DataFrame Simplified OHLCV (TA-ready)
get_close_price_data(start, end, code?) str, str, str DataFrame Close + prior close
get_last_trade_price_data() — DataFrame Last trade price per symbol (symbol, ltp)

Deprecated aliases (removed in 2.0.0): get_hist_data() → get_historical_data(), get_basic_hist_data() → get_basic_historical_data().

Market Functions

Function Parameters Returns Description
get_market_status() — str Current market status (Open, Closed, Holiday, etc.)
get_market_info() — DataFrame 30-day market summary
get_market_info_more_data(start, end) str, str DataFrame Historical market summary
get_market_depth_data(symbol) str DataFrame Order book (buy/sell depth)
get_latest_pe() — DataFrame P/E ratios for all companies
get_company_details(symbol) str dict Company profile, capital, AGM date, shareholding, dividends, financials (current site only)
get_top_ten_gainers_losers(limit?) int (default 10) DataFrame Top movers by price change
get_top_twenty_shares(limit?) int (default 20) DataFrame Top shares by traded volume

News Functions

Function Parameters Returns Description
get_news(news_type?, code?) str, str DataFrame Unified news dispatcher
get_dividend_declarations(start?, end?, code?) str, str, str DataFrame Dividend declarations with year end, AGM date, time, venue, record date (current site only)
get_all_news(start?, end?, code?) str, str, str DataFrame All DSE news; latest feed when called with no arguments
get_corporate_announcements(code?) str DataFrame Corporate actions
get_price_sensitive_news(code?) str DataFrame Price-sensitive news (current site only)

get_news news_type values

Value Equivalent direct function
'all' get_all_news()
'dividend' get_dividend_declarations()
'corporate' get_corporate_announcements()
'psn' get_price_sensitive_news()

Examples

Stock performance summary

import datetime as dt
from bdshare import BDShare, BDShareError

def summarize(symbol: str, days: int = 30) -> dict:
    end   = dt.date.today()
    start = end - dt.timedelta(days=days)

    with BDShare() as bd:
        try:
            df = bd.get_historical_data(symbol, str(start), str(end))
        except BDShareError as e:
            print(f"Could not fetch data: {e}")
            return {}

    return {
        'symbol':       symbol,
        'current':      df['close'].iloc[0],
        'period_high':  df['high'].max(),
        'period_low':   df['low'].min(),
        'avg_volume':   df['volume'].mean(),
        'change_pct':   (df['close'].iloc[0] - df['close'].iloc[-1])
                        / df['close'].iloc[-1] * 100,
    }

result = summarize('GP', days=30)
print(f"{result['symbol']}: {result['change_pct']:.2f}% over 30 days")

Simple portfolio tracker

from bdshare import BDShare, BDShareError

PORTFOLIO = {
    'GP':      {'qty': 100, 'cost': 450.50},
    'ACI':     {'qty':  50, 'cost': 225.75},
    'BEXIMCO': {'qty': 200, 'cost': 125.25},
}

with BDShare() as bd:
    total_cost = total_value = 0

    for symbol, pos in PORTFOLIO.items():
        try:
            row = bd.get_current_trades(symbol).iloc[0]
            price        = row['ltp']
            market_value = pos['qty'] * price
            cost         = pos['qty'] * pos['cost']
            pnl          = market_value - cost

            print(f"{symbol:10s}  price={price:8.2f}  P&L={pnl:+10.2f}")
            total_cost  += cost
            total_value += market_value

        except BDShareError as e:
            print(f"{symbol}: fetch error — {e}")

    print(f"\nPortfolio P&L: {total_value - total_cost:+.2f} "
          f"({(total_value/total_cost - 1)*100:+.2f}%)")

Fetch and screen top gainers above 5 %

from bdshare import get_top_ten_gainers_losers

df = get_top_ten_gainers_losers(limit=20)
big_movers = df[df['change'] > 5]
print(big_movers[['symbol', 'close', 'change']])

Advanced Features

Technical Indicators

Wraps the ta library to add indicator columns directly onto bdshare's OHLCV DataFrames.

pip install "bdshare[ta]"
from bdshare import get_basic_historical_data
from bdshare.indicators import add_indicators, add_rsi

df = get_basic_historical_data('2024-01-01', '2024-06-30', 'GP')

# Add everything (sma_20, ema_20, rsi_14, macd/macd_signal/macd_diff, bb_high/bb_mid/bb_low)
df = add_indicators(df)

# Or just one, with custom parameters
df = add_rsi(df, window=21)

Also available: add_sma(), add_ema(), add_macd(), add_bollinger_bands(). Each returns a new DataFrame (the input is never mutated).

Portfolio Tracking

Portfolio tracks cost basis and values holdings against live prices — no extra dependency required (pure pandas), and valuation() makes exactly one live call for all instruments regardless of how many positions you hold.

from bdshare.portfolio import Portfolio

pf = Portfolio()
pf.add_position('GP', quantity=100, avg_cost=450.50)
pf.add_position('ACI', quantity=50, avg_cost=225.75)

print(pf.holdings().to_string())    # cost basis only, no network call
print(pf.valuation().to_string())   # + ltp, market_value, pnl, pnl_pct per position
print(pf.summary())                 # {'positions': 2, 'total_cost': ..., 'total_pnl': ...}

Adding to an existing position blends the cost basis like a real buy; a negative quantity reduces it, and netting to zero drops the position. Unknown/delisted symbols get None valuation fields instead of raising, so one bad symbol doesn't block valuing the rest.

Real-Time Streaming (WebSocket)

DSE has no public push/streaming API — this polls get_current_trade_data() on an interval and broadcasts changed rows over WebSocket, so another program can subscribe instead of polling bdshare itself.

pip install "bdshare[stream]"

Run the bundled server:

bdshare-stream --symbols GP,ACI --interval 5

Any other program connects as a plain WebSocket client:

import asyncio, json, websockets

async def main():
    async with websockets.connect('ws://localhost:8765') as ws:
        async for message in ws:
            print(json.loads(message))   # {"type": "ticks", "data": [...]}

asyncio.run(main())

Or skip the server and use the polling generator directly inside your own asyncio program:

from bdshare.stream import stream_ticks

async def main():
    async for changed in stream_ticks(symbols=['GP', 'ACI'], interval=5.0):
        print(changed)

asyncio.run(main())

Using bdshare with AI Agents (MCP Server)

bdshare ships an MCP server so AI agents running in another program — Claude Desktop, Claude Code, or any other MCP-compatible client — can call live DSE data as tools, without you writing any glue code.

Install

pip install "bdshare[mcp]"

Run

bdshare-mcp
# or
python -m bdshare.mcp_server

By default it speaks MCP over stdio, which is what desktop/CLI agent clients expect.

Connect it to a client

Claude Code:

claude mcp add bdshare -- bdshare-mcp

Claude Desktop (claude_desktop_config.json):

{
  "mcpServers": {
    "bdshare": {
      "command": "bdshare-mcp"
    }
  }
}

Any other MCP client is configured the same way — point it at the bdshare-mcp command (or python -m bdshare.mcp_server), stdio transport.

Running it over the network instead of stdio

Stdio only works when the client can spawn the server as a local child process (Claude Desktop/Code). For a program in another container, another machine, or another language entirely — nothing that speaks Python — run it over HTTP instead:

bdshare-mcp --transport streamable-http --host 0.0.0.0 --port 8000

Any MCP client library can connect to http://host:8000/mcp; see demo/node/ for a full example using the official @modelcontextprotocol/sdk from Node.js. Binding beyond 127.0.0.1/localhost automatically disables DNS-rebinding protection, since every legitimate client then arrives with a non-localhost Host header — only do this on a trusted network (an internal Docker network, not the public internet).

What the agent gets

17 tools covering the same data this README documents — market_status, market_summary, market_summary_range, market_depth, latest_pe_ratios, top_ten_gainers_losers, top_twenty_shares, company_details, current_trades, dsex_index, trading_codes, historical_data, basic_historical_data, news, dividend_declarations, and the deprecated company_info and agm_news. Each tool returns JSON — DataFrames are converted to lists of row records — and a BDShareError (bad symbol, DSE outage, parse failure) surfaces as a clean tool error message instead of a raw traceback.

Notes for agent use

  • No caching in the MCP server itself. Every tool call scrapes dsebd.org live. If your agent calls the same tool repeatedly in one turn (e.g. checking a price several times), consider fronting it with the BDShare client's caching in a custom wrapper — the bundled server intentionally stays stateless and simple.
  • Rate limits are the agent's responsibility. The BDShare OOP client has a built-in 5 calls/second limiter; the MCP tools call the plain module-level functions, which don't. Avoid tight loops of tool calls.
  • Source: bdshare/mcp_server.py — a plain FastMCP server, easy to fork if you want a different tool surface.

Contributing

Contributions are welcome! To get started:

git clone https://github.com/rochi88/bdshare.git
cd bdshare
pip install -e ".[dev]"
pytest

Please open an issue before submitting a pull request for significant changes. See CONTRIBUTING.md for the full guide.


Roadmap

  • WebSocket streaming for real-time ticks (polling-based — see Real-Time Streaming)
  • Built-in technical indicators (ta integration)
  • Portfolio management helpers
  • Docker demo examples
  • Shared session with exponential back-off
  • lxml-based fast parsing
  • BDShareError for clean error handling
  • Unified get_news() dispatcher
  • Rate limiter and response caching
  • MCP server for AI agent integration

Support


License

MIT — see LICENSE for details.

Disclaimer

bdshare is intended for educational and research use. Always respect DSE's terms of service. The authors are not responsible for financial decisions made using this library.

Change log

All notable changes to bdshare are documented here.

Format follows Keep a Changelog. Versioning follows Semantic Versioning.


[1.2.8] - 2026-10-09

Added

  • get_dividend_declarations(start?, end?, code?) (and BDShare.get_dividend_declarations(), get_news(news_type='dividend'), plus a dividend_declarations MCP tool): dividend declarations with year end, dividend, AGM date, time, venue and record date, read from the "Dividend Declaration" items in the current site's news feed. Defaults to the last 180 days. Fields an announcement leaves out are None.
  • get_company_details(symbol) (and BDShare.get_company_details(), plus a company_details MCP tool): a company's details from the current DSE site, as a dict. It includes profile and contact fields, capital, market data, AGM date and year end, with DataFrames for the shareholding pattern, dividend history, multi-year and interim financials, P/E trend and recent announcements. Fields DSE has no data for are left out, so read optional ones with .get(). get_company_info() still returns the legacy site's tables.

Changed

  • get_last_trade_price_data() now reads the current site's price feed first and falls back to the legacy quotes.txt, like the other data functions. Both give the same figures.
  • DSE_URL in bdshare/util/vars.py now points to https://dse.com.bd/ (was https://dsebd.org/).
  • Faster all-instrument history from dsebd.org: get_historical_data(), get_basic_historical_data() and get_close_price_data() now page through the day-end archive (500 rows per page, pages fetched in parallel) instead of fetching every instrument past the row cap one at a time. A month of all instruments drops from about 90s and ~200 requests to about 10s and ~28 requests. Rows within a date now come back in symbol order.
  • Legacy-site HTML is parsed with lxml directly instead of BeautifulSoup, which cuts parse time about 5–10x (for example, the latest-share-price page from ~250ms to ~40ms of CPU). get_company_info() converts only the data tables after the page's ~400 layout tables, which brings parsing from ~0.6s to ~0.03s.
  • Date ranges that dsebd.org truncates (news, extended market info) are split and re-fetched in parallel rather than one half at a time.
  • The shared HTTP session keeps up to 8 connections per host open, so parallel requests reuse connections.
  • get_price_sensitive_news() works only on dsebd.org. The legacy news archive does not mark price-sensitive items, so with BDSHARE_SOURCE=legacy it now raises BDShareError saying so, instead of "No price-sensitive news found."

Deprecated

These read only the legacy site. Each still works, and now emits a DeprecationWarning naming its replacement. They will be removed in 2.0.0.

  • get_agm_news() → get_dividend_declarations(). The legacy AGM page has not been updated since 2020, so it returns six-year-old data.
  • get_news(news_type='agm') → get_news(news_type='dividend').
  • get_company_info() → get_company_details(). The returned shape differs: a dict with DataFrames for the tabular parts, not the legacy page's list of tables.
  • get_company_inf() (already deprecated) now points to get_company_details().
  • BDShare.get_company_profile() → BDShare.get_company_details().
  • The agm_news and company_info MCP tools → dividend_declarations and company_details. Their descriptions say so; MCP tools have no warning mechanism.

Fixed

  • get_last_trade_price_data() returned a single garbled column whose header was the first instrument's row (e.g. 1JANATAMF \t 3.4). It now returns symbol and ltp columns with one row per instrument.
  • On the legacy site, get_all_news() returned no rows unless called with a symbol. With no arguments it now reads the latest-news feed, and with a date range it sends both dates (filling in a missing one), which the archive needs. Dates passed with a symbol are now applied as a filter, as on dsebd.org.

Removed

  • DSE_ALT_URL and DSE_LEGACY_ALT_URL from bdshare/util/vars.py. Requests now go only to DSE_URL (https://dse.com.bd/) and DSE_LEGACY_URL (https://old.dsebd.org/), with no alternate host tried within an attempt.

[1.2.7] - 2026-09-25

Added

  • Support for the redesigned dsebd.org site. The new site no longer serves the legacy .php pages (they return 404) and loads its data from a JSON API instead. Every data function now tries the dsebd.org API first and falls back to the legacy site (old.dsebd.org) if that fails, returning the same columns either way: current trade data, trading codes, DSEX data, historical/basic historical/close price data, market status, market info (and extended market info), latest P/E, market depth, top gainers, top twenty shares, and news (all, corporate, price-sensitive).
  • BDSHARE_SOURCE environment variable (or bdshare.util.vars.DSE_SOURCE at runtime) to choose the site: auto (default: dsebd.org, then legacy), new, or legacy.

Changed

  • DSE_URL / DSE_ALT_URL in bdshare/util/vars.py now hold the current site (https://dsebd.org/, https://dse.com.bd/). The legacy hosts moved to the new DSE_LEGACY_URL / DSE_LEGACY_ALT_URL. Code that read DSE_URL expecting the legacy site should switch to DSE_LEGACY_URL.
  • get_agm_news() and get_company_info() work only on the legacy site, because dsebd.org has no equivalent data.
  • Fetching all instruments' history from dsebd.org is slower than from the legacy site. The API returns at most 500 rows per request, and one day has about 650 instruments, so bdshare fetches the instruments past the cutoff one at a time (in parallel).

Fixed

  • _safe_num() removed the minus sign from negative numbers ("-1.20" → 1.2), so falling prices showed up as positive changes, for example in the change column of get_dsex_data(). Negative values now keep their sign. Cells containing only dashes ("-", "--") still parse as None.
  • get_top_twenty_shares() read the wrong columns: trade held the close price and volume held the trade count. It now reads the TRADE and VOLUME columns.

[1.2.6] - 2026-09-25

Fixed

  • Pointed DSE_URL and DSE_ALT_URL in bdshare/util/vars.py at the legacy DSE sites (https://old.dsebd.org/ and https://old.dse.com.bd/). The legacy pages (latest_share_price_scroll_l.php, day_end_archive.php, etc.) that the scrapers parse are now served from these hosts.

[1.2.5] - 2026-09-08

Fixed

  • Pinned the optional mcp extra to >=1.0.0,<2 so installs keep using the v1 API expected by bdshare/mcp_server.py; this avoids the mcp 2.x FastMCP → MCPServer breakage that caused bdshare-mcp to fail immediately after installation.

[1.2.3] - 2026-07-22

Added

  • bdshare/indicators.py — technical indicator helpers (add_sma, add_ema, add_rsi, add_macd, add_bollinger_bands, add_indicators) built on the ta library, operating on the OHLCV DataFrames returned by get_basic_historical_data(); install with pip install bdshare[ta]
  • bdshare/portfolio.py — Portfolio/Position classes for tracking cost basis and valuing holdings against live prices (holdings(), valuation(), summary()); one live call for all instruments regardless of portfolio size
  • bdshare/stream.py — polling-based WebSocket tick streaming (stream_ticks(), TickServer); broadcasts changed rows from get_current_trade_data() to connected clients so another program can subscribe over ws:// instead of polling itself. DSE has no push API, so this is poll-and-diff under a WebSocket-shaped interface, not true push. Install with pip install bdshare[stream], run with bdshare-stream
  • demo/streamlit/streamlit_app.py — full-feature Streamlit dashboard showcasing every public feature in one app: live trading data, historical charts with bdshare.indicators overlays, market movers, news, bdshare.portfolio tracking, live-tick polling, and an interactive AI-agent (MCP) tool explorer. Runs via docker compose up --build streamlit (demo/streamlit/Dockerfile, builds bdshare from local source so unreleased features are included) or locally with pip install -e ".[ta,stream]" + streamlit run demo/streamlit/streamlit_app.py
  • demo/ reorganized into demo/flask/, demo/streamlit/, and demo/node/, all built from demo/docker-compose.yml with a repo-root build context; documented in demo/README.md (previously an unrelated generic Flask/Plotly readme with no mention of bdshare or Docker)
  • bdshare-mcp --transport streamable-http --host 0.0.0.0 --port 8000 — the MCP server can now run over the network instead of only stdio, for clients that can't spawn it as a local child process (a different language, another container). Binding beyond loopback auto-disables DNS-rebinding protection, since every legitimate client then arrives with a non-localhost Host header
  • demo/node/ — a four-service showcase of consuming bdshare from outside Python: an Express UI (demo/node/server, never imports bdshare) talking to a FastAPI backend (demo/node/api, bdshare functions as JSON REST) over REST, to bdshare-mcp --transport streamable-http over MCP via the official @modelcontextprotocol/sdk, and to bdshare-stream over WebSocket (relayed to the browser). Run via docker compose up --build node node-api mcp stream or locally per demo/README.md

Fixed

  • bdshare.BDShareError (the publicly exported/documented exception) was a different class from bdshare.util.helper.BDShareError, the one every scraping function actually raises — except bdshare.BDShareError silently never caught real errors. bdshare/__init__.py now re-exports the same class instead of redefining it
  • demo/app.py: convert_to_native_types() called pd.isna(obj) before checking whether obj was a list/dict, crashing with ValueError: The truth value of an array... is ambiguous on any chart request; container types are now checked first
  • demo/app.py: get_available_tickers() checked for a trading_code column that doesn't exist on get_current_trade_data()'s output (symbol does), so it always silently fell back to the hardcoded stock list
  • demo/Dockerfile: base image python:3.11-slim-buster is EOL (Debian Buster archived), so apt-get update would fail on a fresh build; switched to python:3.11-slim

[1.2.2] - 2026-07-22

Added

  • Optional as_polars=True parameter across all data-fetching functions to return polars.DataFrame instead of pandas.DataFrame (requires pip install bdshare[polars])
  • get_market_status() — current market status (Open, Closed, Holiday, etc.)
  • get_top_twenty_shares() — top twenty shares by traded volume
  • MCP (Model Context Protocol) server (bdshare/mcp_server.py) exposing 15 tools so AI agents (Claude Desktop, Claude Code, etc.) can call live DSE data directly; install with pip install bdshare[mcp], run with bdshare-mcp

Changed

  • Renamed get_top_gainers_losers() → get_top_ten_gainers_losers(); returned columns changed from symbol, ltp, change to symbol, close, high, low, ycp, change

Removed

  • get_sector_performance() (module function and BDShare.get_sector_performance()) — no aliased replacement; use get_top_twenty_shares() instead

Fixed

  • Bundled the missing Sectigo DV R36 intermediate certificate so requests to dsebd.org verify correctly instead of relying on an incomplete chain
  • Corrected DSE_ALT_URL fallback domain to dse.com.bd
  • get_corporate_announcements() and get_price_sensitive_news() always raised BDShareError — the row parser assumed each news item was one <tr> with 4 <td>s, but DSE renders each field (Trading Code:, News Title:, News:, Post Date:) as its own <th>/<td> row pair
  • as_polars=True could crash with unexpected value while building Series of type String; found value of type Float64: NaN on tables mixing strings and missing values (e.g. get_company_info()); NaN now converts to a proper polars null instead
  • Corrected usage.rst/README documentation that had get_historical_data()/get_basic_historical_data() mislabeled as the deprecated aliases — get_hist_data()/get_basic_hist_data() are the deprecated ones

[1.2.1] - 2026-02-22

Added

  • Added code filter on market index

[1.2.0] - 2026-02-21

Changed

  • Updated

[1.1.6] - 2026-02-20

Changed

  • Updated readthedocs structure

[1.1.5] - 2026-02-20

Changed

  • Renamed get_hist_data() → get_historical_data() (improved readability)
  • Renamed get_basic_hist_data() → get_basic_historical_data() (improved readability)
  • Renamed get_market_inf() → get_market_info() (improved readability)
  • Renamed get_market_inf_more_data() → get_market_info_more_data() (improved readability)
  • Renamed get_company_inf() → get_company_info() (improved readability)

Deprecated

  • get_hist_data() — still callable but emits DeprecationWarning; will be removed in 2.0.0
  • get_basic_hist_data() — still callable but emits DeprecationWarning; will be removed in 2.0.0
  • get_market_inf() — still callable but emits DeprecationWarning; will be removed in 2.0.0
  • get_market_inf_more_data() — still callable but emits DeprecationWarning; will be removed in 2.0.0
  • get_company_inf() — still callable but emits DeprecationWarning; will be removed in 2.0.0

Added

  • BDShareError custom exception — all network and scraping failures now raise this instead of silently printing and returning None
  • Shared requests.Session (_session) across all modules — reuses TCP connections for significantly faster repeated calls
  • Exponential back-off retry logic in safe_get() — pauses 0.2 s → 0.4 s → 0.8 s between attempts before raising BDShareError
  • Fallback URL support in safe_get() — primary and alternate DSE endpoints tried within the same retry attempt
  • lxml-based HTML parsing in _fetch_table() with html.parser fallback — replaces html5lib (~10× faster)
  • _safe_num() helper — all scraped values now returned as typed numerics (float/int) instead of raw strings
  • _parse_trade_rows() and _filter_symbol() internal helpers in trading.py — eliminate duplicated parsing logic between get_current_trade_data() and get_dsex_data()
  • get_news() unified dispatcher — accepts news_type of 'all', 'agm', 'corporate', or 'psn'
  • get_corporate_announcements() and get_price_sensitive_news() — previously missing functions now fully implemented
  • Column count guards (len(cols) < N) across all table parsers — malformed rows are skipped rather than raising IndexError
  • Backward-compatibility aliases for all renamed functions with DeprecationWarning
  • Type hints throughout all public functions
  • Comprehensive docstrings with parameter and return documentation

Fixed

  • get_agm_news(): corrected field name typo agmData → agmDate
  • get_agm_news(): corrected field name typo vanue → venue
  • get_market_depth_data(): no longer creates a new requests.Session on every retry iteration
  • get_basic_hist_data(): redundant double sort_index() call removed
  • get_hist_data() and get_close_price_data(): no longer silently return None on empty results
  • RateLimiter in __init__.py: switched from time.time() to time.monotonic() for reliable elapsed-time measurement

Removed

  • html5lib as the default parser — replaced by lxml with html.parser fallback
  • Silent print(e) error handling — all error paths now raise BDShareError
  • Dead timeout parameter from BDShare.configure() — it had no effect

[1.1.4] - 2025-09-16

Added

  • Enhanced error handling and robustness across all functions
  • Improved parameter handling for news functions
  • Better file path resolution for utility functions
  • Comprehensive fallback mechanisms for network issues

Changed

  • Fixed get_all_news() function to support date range parameters as documented
  • Enhanced market info functions with better error handling
  • Improved Store utility with proper file saving mechanism
  • Fixed Tickers utility with correct file path resolution

Fixed

  • All major function issues identified in testing (18/18 functions now working)
  • Parameter signature mismatches in news functions
  • HTML parsing errors in market data functions
  • File saving issues in Store utility
  • Missing tickers.json file dependency

[1.1.2] - 2024-12-31

Added

  • n/a

Changed

  • update tests

Fixed

  • n/a

[1.1.1] - 2024-12-31

Added

  • n/a

Changed

  • update runner

Fixed

  • n/a

[1.1.0] - 2024-12-31

Added

  • new function for getting company info

Changed

  • n/a

Fixed

  • n/a

[1.0.4] - 2024-12-30

Added

  • n/a

Changed

  • changed lint

Fixed

  • fixed typo

[1.0.3] - 2024-07-29

Added

  • n/a

Changed

  • n/a

Fixed

  • check fix for latest P/E url [#6]

[1.0.2] - 2024-07-29

Added

  • n/a

Changed

  • n/a

Fixed

  • fixed latest P/E url [#6]

[1.0.0] - 2024-03-04

Added

  • Updated docs

Changed

  • n/a

[0.7.2] - 2024-03-04

Added

  • Updated docs

Changed

  • n/a

[0.7.1] - 2024-03-04

Added

  • n/a

Changed

  • fixed market depth data api

[0.7.0] - 2024-03-04

Added

  • n/a

Changed

  • n/a

[0.6.0] - 2024-03-03

Added

  • n/a

Changed

  • n/a

[0.5.1] - 2024-02-29

Added

  • n/a

Changed

  • n/a

[0.5.0] - 2024-02-29

Added

  • fixed store datafrave to csv file method

Changed

  • n/a

[0.4.0] - 2023-03-12

Added

  • n/a

Changed

  • changed package manager

[0.3.2] - 2022-10-10

Added

  • n/a

Changed

  • n/a

[0.3.1] - 2022-06-15

Added

  • n/a

Changed

  • n/a

[0.2.1] - 2021-08-01

Added

Changed

  • get_current_trading_code()

[0.2.0] - 2021-06-01

Added

  • added get_market_depth_data
  • added get_dsex_data
  • added 'dse.com.bd' as redundant

Changed

  • Changed documentation
  • changed get_agm_news
  • changed get_all_news

[0.1.4] - 2020-08-22

Added

  • added get_market_inf_more_data

Changed

  • Changed documentation

[0.1.3] - 2020-08-20

Added

  • html5lib
  • added get params

Changed

  • post request to get

[0.1.2] - 2020-05-21

Added

  • modified index declaration

[0.1.1] - 2020-05-20

Added

  • modified index declaration

[0.1.0] - 2020-04-08

Added

  • added git tag
  • VERSION.txt

Changed

  • setup.py
  • HISTORY.md to CHANGELOG.md

[0.0.1] - 2020-04-06

Added

  • get_hist_data(), get_current_trade_data()
  • HISTORY.md

Metadata

Release files for bdshare 1.2.8

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

Source distribution (sdist)

Source distribution for bdshare 1.2.8
File Size Uploaded
bdshare-1.2.8.tar.gz 98.2 kB Details

Built distribution (wheel)

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

Total release size: 180.8 kB

Release files / bdshare-1.2.8.tar.gz

Download URL bdshare-1.2.8.tar.gz
Size 98.2 kB
Tags Source
SHA-256 checksum
How to use checksums
54d3f2d5493dddc96c1d20ac8ee9cf04d559aa213617891a1bd95690220fb406
BLAKE2b-256 checksum
How to use checksums
56e58c1473464c76d682a2f342e1d1e49c1cba9848c630852eb121ff0da5e670
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.14

Release files / bdshare-1.2.8-py3-none-any.whl

Download URL bdshare-1.2.8-py3-none-any.whl
Size 82.6 kB
Tags Python 3
SHA-256 checksum
How to use checksums
6d30f827bf8480e6ed16435859902eb9218a3a441ef882d63fb68409aa5bd9b3
BLAKE2b-256 checksum
How to use checksums
dcdcdc3ff5545e3ade24e7c7de9d0e8338a194c8307ad4cb1006845444e424e5
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.14

Release history Release notifications | RSS feed

This release

1.2.8 This release

2 release files

1.2.7

2 release files

1.2.6

2 release files

1.2.5

2 release files

1.2.3

2 release files

1.2.2

2 release files

1.2.1

2 release files

1.2.0

2 release files

1.1.6

2 release files

1.1.5

2 release files

1.1.4

2 release files

1.1.2

2 release files

1.1.0

2 release files

1.0.3

2 release files

1.0.2

2 release files

1.0.1

2 release files

1.0.0

2 release files

0.6.0

2 release files

0.5.0

2 release files

0.4.0

2 release files

0.3.1

1 release file

0.2.0

2 release files

0.1.4

2 release files

0.1.3

2 release files

0.1.1

2 release files

0.1.0

2 release files

0.0.1

2 release files

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