Skip to main content

Async Python library for fetching real-time and historical data from the Stock Exchange of Thailand (SET) and Thailand Futures Exchange (TFEX)

Project description

settfex

Your friendly Python library for fetching Thai stock market data ๐Ÿ‡น๐Ÿ‡ญ

PyPI version Python 3.11+ License: MIT

settfex makes it super easy to get stock market data from the Stock Exchange of Thailand (SET) and Thailand Futures Exchange (TFEX). Whether you're building a trading bot, doing market analysis, or just curious about Thai stocks, we've got you covered!

โšก Quick Install

pip install settfex

Optional: To run the Jupyter notebook examples, install with:

pip install settfex[examples]

This includes pandas, matplotlib, and jupyter notebook support.

๐Ÿ““ Interactive Examples

New to settfex? Start here! We have comprehensive Jupyter notebook examples that teach you everything step-by-step:

๐ŸŽ“ Learning Path

Beginners : Start with these three notebooks to get comfortable:

Fundamental Analysis : Build a complete stock analysis workflow:

Professional Trading : Master all features for institutional use:

  • All 11 SET notebooks + 2 TFEX notebooks (see below)

๐Ÿ“Š SET Examples (Stock Exchange of Thailand)

All examples include beginner explanations, professional trading use cases, and data export examples:

  1. Stock List - Fetch and filter all stocks, build portfolio universes
  2. Highlight Data - Value screeners, dividend portfolios, risk-adjusted returns
  3. Stock Profile - Listing details, IPO data, foreign ownership
  4. Company Profile - ESG ratings, governance scores, management
  5. Corporate Actions - Dividend calendars, shareholder meetings
  6. Shareholder Data - Ownership analysis, free float monitoring
  7. NVDR Holders - NVDR ownership tracking and analysis
  8. Board of Directors - Board composition and management structure
  9. Trading Statistics - Multi-period performance and volatility
  10. Price Performance - Sector comparison and alpha calculation
  11. Financial Statements - Balance sheet, income, cash flow analysis
  12. Earnings Call (Opportunity Day) - OPPDAY calendar, YouTube links, Thai transcripts for AI
  13. Chart Quotation & Latest Price - Intraday series and the latest traded price relative to now
  14. Latest Historical Trading - Latest trading-day summary: OHLCV, P/E, P/BV, market cap

๐Ÿ“ˆ TFEX Examples (Thailand Futures Exchange)

Professional derivatives trading workflows with margin calculations and risk management:

  1. Series List - Discover futures/options, rollover monitoring, options chains
  2. Trading Statistics - Margin requirements, position sizing, P/L tracking

๐Ÿ“‚ View All Examples - Complete index with learning guides

๐Ÿ“š Full Documentation

Want to dig deeper? Check out our detailed guides:

SET Services

TFEX Services

Utilities

๐ŸŽฏ What Can You Do?

SET (Stock Exchange of Thailand)

๐Ÿ“‹ Get Stock List

Want to see all stocks trading on SET? Easy!

from settfex.services.set import get_stock_list

stock_list = await get_stock_list()
print(f"Found {stock_list.count} stocks!")

# Filter by market
set_stocks = stock_list.filter_by_market("SET")
mai_stocks = stock_list.filter_by_market("mai")

๐Ÿ‘‰ Learn more about Stock Lists


๐Ÿ’ฐ Get Stock Highlight Data

Need market cap, P/E ratio, dividend yield? We got you!

from settfex.services.set import Stock

stock = Stock("CPALL")
data = await stock.get_highlight_data()

print(f"Market Cap: {data.market_cap:,.0f} THB")
print(f"P/E Ratio: {data.pe_ratio}")
print(f"Dividend Yield: {data.dividend_yield}%")

๐Ÿ‘‰ Learn more about Highlight Data


๐Ÿ“Š Get Stock Profile

Want to know when a company was listed? Its IPO price? Foreign ownership limits?

from settfex.services.set import get_profile

profile = await get_profile("PTT")

print(f"Listed: {profile.listed_date}")
print(f"IPO Price: {profile.ipo} {profile.currency}")
print(f"Foreign Limit: {profile.percent_foreign_limit}%")

๐Ÿ‘‰ Learn more about Stock Profiles


๐Ÿข Get Company Profile

Curious about company details, management, auditors, or ESG ratings?

from settfex.services.set import get_company_profile

company = await get_company_profile("CPN")

print(f"Company: {company.name}")
print(f"Website: {company.url}")
print(f"CG Score: {company.cg_score}/5")
print(f"ESG Rating: {company.setesg_rating}")
print(f"Executives: {len(company.managements)}")

๐Ÿ‘‰ Learn more about Company Profiles


๐Ÿ“… Get Corporate Actions

Track dividends, shareholder meetings, and other corporate events:

from settfex.services.set import get_corporate_actions

actions = await get_corporate_actions("AOT")

for action in actions:
    if action.ca_type == "XD":
        print(f"Dividend: {action.dividend} {action.currency}")
        print(f"XD Date: {action.x_date}")
        print(f"Payment Date: {action.payment_date}")
    elif action.ca_type == "XM":
        print(f"Meeting: {action.meeting_type}")
        print(f"Agenda: {action.agenda}")

๐Ÿ‘‰ Learn more about Corporate Actions


๐Ÿ‘ฅ Get Shareholder Data

See who owns what! Get major shareholders, free float, and ownership distribution:

from settfex.services.set import get_shareholder_data

data = await get_shareholder_data("MINT")

print(f"Total Shareholders: {data.total_shareholder:,}")
print(f"Free Float: {data.free_float.percent_free_float:.2f}%")

for sh in data.major_shareholders[:5]:
    print(f"{sh.sequence}. {sh.name}: {sh.percent_of_share:.2f}%")

๐Ÿ‘‰ Learn more about Shareholder Data


๐Ÿ“œ Get NVDR Holder Data

Track Non-Voting Depository Receipt (NVDR) holders and their ownership:

from settfex.services.set import get_nvdr_holder_data

data = await get_nvdr_holder_data("MINT")

print(f"Symbol: {data.symbol}")  # MINT-R
print(f"Total NVDR Holders: {data.total_shareholder:,}")

for holder in data.major_shareholders[:5]:
    print(f"{holder.sequence}. {holder.name}: {holder.percent_of_share:.2f}%")

๐Ÿ‘‰ Learn more about NVDR Holder Data


๐Ÿ‘” Get Board of Directors

See who's running the show! Get board of directors and management information:

from settfex.services.set import get_board_of_directors

directors = await get_board_of_directors("MINT")

for director in directors:
    positions = ", ".join(director.positions)
    print(f"{director.name}: {positions}")

# Find the Chairman
chairman = next((d for d in directors if "CHAIRMAN" in d.positions), None)
if chairman:
    print(f"Chairman: {chairman.name}")

๐Ÿ‘‰ Learn more about Board of Directors


๐Ÿ“Š Get Trading Statistics

Track historical trading performance with comprehensive statistics across multiple time periods:

from settfex.services.set import get_trading_stats

stats = await get_trading_stats("MINT")

# YTD performance
ytd = next(s for s in stats if s.period == "YTD")
print(f"YTD Performance: {ytd.percent_change:.2f}%")
print(f"Current Price: {ytd.close:.2f} THB")
print(f"P/E Ratio: {ytd.pe}, Market Cap: {ytd.market_cap:,.0f} THB")

# Compare different periods
for stat in stats:
    print(f"{stat.period}: {stat.close:.2f} THB ({stat.percent_change:+.2f}%)")

๐Ÿ‘‰ Learn more about Trading Statistics


๐Ÿ“ˆ Get Price Performance

Compare stock performance against sector and market with comprehensive price change data:

from settfex.services.set import get_price_performance

data = await get_price_performance("MINT")

# Stock performance
print(f"Stock: {data.stock.symbol}")
print(f"  YTD: {data.stock.ytd_percent_change:+.2f}%")
print(f"  P/E: {data.stock.pe_ratio}, P/B: {data.stock.pb_ratio}")

# Sector comparison
print(f"Sector ({data.sector.symbol}): {data.sector.ytd_percent_change:+.2f}%")

# Market comparison
print(f"Market ({data.market.symbol}): {data.market.ytd_percent_change:+.2f}%")

๐Ÿ‘‰ Learn more about Price Performance


โฑ๏ธ Get the Latest Traded Price (Intraday)

Fetch the intraday chart-quotation series, or jump straight to the latest traded price relative to now (the null future/lunch/no-trade buckets are excluded automatically):

from settfex.services.set import get_latest_price, get_chart_quotation

# The latest TRADED quotation right now (or None if nothing has traded yet)
quote = await get_latest_price("CPALL")
if quote:
    print(f"{quote.local_datetime}: {quote.price} (vol {quote.volume:,.0f})")

# Or work with the full series; the model also exposes a prior-fallback scalar
data = await get_chart_quotation("CPALL", period="1D")
print(f"Prior close: {data.prior}, latest price: {data.get_latest_price()}")

๐Ÿ‘‰ Learn more about Chart Quotation & Latest Price


๐Ÿ’ฐ Get Financial Statements

Fetch comprehensive financial data including balance sheet, income statement, and cash flow:

from settfex.services.set import (
    get_balance_sheet,
    get_income_statement,
    get_cash_flow
)

# Balance sheet
balance_sheets = await get_balance_sheet("CPALL")
latest = balance_sheets[0]
print(f"Period: {latest.quarter} {latest.year}")
print(f"Total Assets: {latest.accounts[0].amount:,.0f}K")

# Income statement
income_statements = await get_income_statement("CPALL")
for stmt in income_statements[:3]:
    print(f"{stmt.quarter} {stmt.year}: {stmt.status}")

# Cash flow
cash_flows = await get_cash_flow("CPALL")

๐Ÿ‘‰ Learn more about Financial Service


๐Ÿ“‰ Get Chart Quotation

Fetch intraday and historical price chart data for any stock across multiple time periods:

from settfex.services.set import get_chart_quotation

# Get 1-day intraday chart (1-minute intervals)
chart = await get_chart_quotation("CPALL", period="1D")
print(f"Data points: {len(chart.quotations)}")
print(f"Latest: {chart.quotations[-1].close:.2f} THB")

# Get 1-year historical chart (daily intervals)
chart_1y = await get_chart_quotation("CPALL", period="1Y")
print(f"1Y data points: {len(chart_1y.quotations)}")

๐Ÿ‘‰ Learn more about Chart Quotation


๐Ÿ“Š Get Latest Historical Trading

Get the latest trading day summary with OHLCV, P/E, P/BV, dividend yield, and market cap:

from settfex.services.set import get_latest_historical_trading

trading = await get_latest_historical_trading("CPALL")

print(f"Date: {trading.date}")
print(f"Close: {trading.close:.2f} THB ({trading.percent_change:+.2f}%)")
print(f"P/E: {trading.pe}, P/BV: {trading.pbv}")
print(f"Market Cap: {trading.market_cap:,.0f} THB")

๐Ÿ‘‰ Learn more about Latest Historical Trading


๐ŸŽค Get Earnings Call (Opportunity Day) Calendar

Fetch the SET Opportunity Day earnings-call calendar โ€” symbol, company, date, clip duration, and a ready-to-use YouTube link โ€” as typed models or a pandas DataFrame:

from settfex.services.set import get_earnings_calls, get_earnings_calls_dataframe

# Typed models
response = await get_earnings_calls()
for item in response.items[:5]:
    print(item.symbol, item.company_name_clean, item.youtube_url)

# โ€ฆor straight to a DataFrame (requires: pip install "settfex[dataframe]")
df = await get_earnings_calls_dataframe()
# columns: stock_name, company_name, earnings_call_date, video_clip_time, youtube_url

# Search one company, or filter by quarter/type
hann = await get_earnings_calls(keyword="HANN")

# Grab the WHOLE archive fast โ€” pages are fetched concurrently, with an optional progress bar
# (pip install "settfex[progress]"):
from settfex.services.set import get_all_earnings_calls
everything = await get_all_earnings_calls(progress=True)   # ~9520 records in ~15s (~10x faster)

# Thai subtitles as raw text for AI/LLM use (pip install "settfex[transcript]"):
from settfex.services.set import fetch_transcripts, get_earnings_call_transcript
await fetch_transcripts(hann.items)               # fills item.transcript (Thai) per video
text = await get_earnings_call_transcript(6319)   # โ€ฆor one presentation's transcript by id

โš ๏ธ Transcripts & YouTube limits. YouTube rate-limits / IP-blocks aggressively (especially from cloud servers), so transcript fetching is built for a filtered set (a company / quarter) โ€” not the full ~9,520-video archive โ€” and defaults to low concurrency (3). A blocked/missing/disabled transcript simply comes back as None; if your host IP is blocked, pass proxies={"http": ..., "https": ...}. Results can vary by IP.

๐Ÿ‘‰ Learn more about the Earnings Call Service


TFEX (Thailand Futures Exchange)

๐Ÿ“‹ Get TFEX Series List

Want to see all futures and options trading on TFEX? Easy!

from settfex.services.tfex import get_series_list

series_list = await get_series_list()
print(f"Found {series_list.count} series!")

# Filter active futures only
active_futures = [s for s in series_list.get_futures() if s.active]
print(f"Active futures: {len(active_futures)}")

# Filter by underlying
set50_series = series_list.filter_by_underlying("SET50")
print(f"SET50 contracts: {len(set50_series)}")

๐Ÿ‘‰ Learn more about TFEX Series List


๐Ÿ“Š Get TFEX Trading Statistics

Get comprehensive trading statistics including settlement prices, margin requirements, and days to maturity!

from settfex.services.tfex import get_trading_statistics

stats = await get_trading_statistics("S50Z25")

print(f"Settlement Price: {stats.settlement_price:.5f}")
print(f"Days to Maturity: {stats.day_to_maturity}")
print(f"Initial Margin: {stats.im:,.2f} THB")
print(f"Maintenance Margin: {stats.mm:,.2f} THB")

# Calculate margin coverage
capital = 500000
max_contracts = int(capital / stats.im)
print(f"Can trade {max_contracts} contracts with {capital:,.0f} THB")

๐Ÿ‘‰ Learn more about TFEX Trading Statistics


๐Ÿš€ Why settfex?

โšก Blazing Fast

First request takes ~2 seconds (warming up). After that? 100ms! That's 25x faster thanks to smart session caching.

Dual-Site Support: Separate cached sessions for SET and TFEX - each optimized for its own API!

๐Ÿ‘‰ Learn about Session Caching

๐Ÿ‡น๐Ÿ‡ญ Thai Language Support

Full UTF-8 support for Thai characters. Company names, sectors, everything just works!

๐Ÿ”’ Type Safe

Everything is type-hinted and validated with Pydantic. Your IDE will love it!

๐Ÿชต Smart Logging

Beautiful logs with loguru. Debug issues easily or turn them off in production.

๐Ÿ’ก Quick Example

Here's everything in action:

import asyncio
from settfex.services.set import (
    get_stock_list,
    get_profile,
    get_company_profile,
    get_corporate_actions,
    get_board_of_directors,
    get_trading_stats,
    Stock
)

async def analyze_stock(symbol: str):
    # Get basic info from stock list
    stock_list = await get_stock_list()
    stock_info = stock_list.get_symbol(symbol)

    if not stock_info:
        print(f"Stock {symbol} not found!")
        return

    print(f"๐Ÿ“Š {stock_info.name_en} ({symbol})")
    print(f"Market: {stock_info.market}")
    print(f"Sector: {stock_info.sector}")

    # Get detailed metrics
    stock = Stock(symbol)
    highlight = await stock.get_highlight_data()

    print(f"\n๐Ÿ’ฐ Valuation:")
    print(f"Market Cap: {highlight.market_cap:,.0f} THB")
    print(f"P/E Ratio: {highlight.pe_ratio}")
    print(f"Dividend Yield: {highlight.dividend_yield}%")

    # Get listing details
    profile = await get_profile(symbol)
    print(f"\n๐Ÿ“… Listed: {profile.listed_date}")
    print(f"IPO: {profile.ipo} {profile.currency}")

    # Get company info
    company = await get_company_profile(symbol)
    print(f"\n๐Ÿข {company.name}")
    print(f"Website: {company.url}")
    print(f"ESG Rating: {company.setesg_rating}")

    # Get corporate actions
    actions = await get_corporate_actions(symbol)
    print(f"\n๐Ÿ“… Corporate Actions: {len(actions)}")
    for action in actions[:3]:  # Show first 3
        if action.ca_type == "XD":
            print(f"  Dividend: {action.dividend} {action.currency}")
        elif action.ca_type == "XM":
            print(f"  Meeting: {action.meeting_type}")

    # Get board of directors
    directors = await get_board_of_directors(symbol)
    print(f"\n๐Ÿ‘” Board of Directors: {len(directors)}")
    chairman = next((d for d in directors if "CHAIRMAN" in d.positions), None)
    if chairman:
        print(f"  Chairman: {chairman.name}")

    # Get trading statistics
    stats = await get_trading_stats(symbol)
    ytd = next((s for s in stats if s.period == "YTD"), None)
    if ytd:
        print(f"\n๐Ÿ“Š Trading Statistics (YTD):")
        print(f"  Performance: {ytd.percent_change:+.2f}%")
        print(f"  Volume: {ytd.total_volume:,.0f} shares")
        print(f"  Turnover: {ytd.turnover_ratio:.2f}%")

# Run it!
asyncio.run(analyze_stock("PTT"))

๐Ÿ› ๏ธ Advanced Usage

Need more control? We've got you covered!

from settfex.utils.data_fetcher import AsyncDataFetcher, FetcherConfig

# Custom configuration
config = FetcherConfig(
    timeout=60,           # Longer timeout
    max_retries=5,        # More retries
    browser_impersonate="safari17_0"  # Different browser
)

# Use with any service
from settfex.services.set.stock import StockHighlightDataService

service = StockHighlightDataService(config=config)
data = await service.fetch_highlight_data("CPALL")

๐Ÿ‘‰ Learn more about AsyncDataFetcher

๐Ÿงช Optional: Configure Logging

By default, settfex only shows ERROR-level logs to keep your terminal clean. Want to see more?

from settfex.utils.logging import setup_logger

# Turn on detailed logs for debugging
setup_logger(level="DEBUG", log_file="logs/settfex.log")

# Or just INFO level for general monitoring
setup_logger(level="INFO")

# Now run your code - you'll see what's happening!
stock_list = await get_stock_list()

Great for debugging or monitoring in production. Default is ERROR level for clean output.

๐Ÿ“‹ Changelog

See CHANGELOG.md for the full, versioned release history (this project follows Keep a Changelog and Semantic Versioning).

๐Ÿค Contributing

We'd love your help making settfex better! Here's how:

  1. Fork the repo
  2. Create a feature branch: git checkout -b feature/cool-new-thing
  3. Make your changes with proper type hints and tests
  4. Run tests: pytest
  5. Run linting: ruff check .
  6. Commit: git commit -m 'Add cool new thing'
  7. Push: git push origin feature/cool-new-thing
  8. Open a Pull Request

๐Ÿ“œ License

MIT License - feel free to use this in your projects!

โš ๏ธ Disclaimer

This library is not officially affiliated with the Stock Exchange of Thailand or Thailand Futures Exchange. Use at your own risk for educational and informational purposes.

๐Ÿ™‹ Need Help?


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

settfex-0.7.1.tar.gz (557.2 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

settfex-0.7.1-py3-none-any.whl (96.3 kB view details)

Uploaded Python 3

File details

Details for the file settfex-0.7.1.tar.gz.

File metadata

  • Download URL: settfex-0.7.1.tar.gz
  • Upload date:
  • Size: 557.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for settfex-0.7.1.tar.gz
Algorithm Hash digest
SHA256 ad33e9003b6717b09322c89c0dc4ac9120956ef7aa0ae99136b084057e2db836
MD5 05a7ae0c77c790759abbc9295bcd3dd5
BLAKE2b-256 054c2459a50f246f1a44944abceb3d10299997ee1052229aea08bc499968b9ad

See more details on using hashes here.

Provenance

The following attestation bundles were made for settfex-0.7.1.tar.gz:

Publisher: release.yml on lumduan/settfex

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file settfex-0.7.1-py3-none-any.whl.

File metadata

  • Download URL: settfex-0.7.1-py3-none-any.whl
  • Upload date:
  • Size: 96.3 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for settfex-0.7.1-py3-none-any.whl
Algorithm Hash digest
SHA256 7b6e9aa093c0241618b6b23200d18788b845e8e878a0ec2bad0fbe064bba2fe9
MD5 a02df37458c35b62299b842a61794d2b
BLAKE2b-256 b138399a57a37e59afd13fe0d3ddaebf9bcb42a2cd1974dd4abf082c6e4d4d78

See more details on using hashes here.

Provenance

The following attestation bundles were made for settfex-0.7.1-py3-none-any.whl:

Publisher: release.yml on lumduan/settfex

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page