settfex 0.1.0
Async Python library for fetching real-time and historical data from the Stock Exchange of Thailand (SET) and Thailand Futures Exchange (TFEX)
License: MIT
Requires Python: >=3.11
Keywords: api, async, exchange, finance, futures, market-data, set, stock, tfex, thai-stocks, thailand, trading

# settfex

> Your friendly Python library for fetching Thai stock market data 🇹🇭

[![PyPI version](https://badge.fury.io/py/settfex.svg)](https://badge.fury.io/py/settfex)
[![Python 3.11+](https://img.shields.io/badge/python-3.11+-blue.svg)](https://www.python.org/downloads/)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/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

```bash
pip install settfex
```

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

```bash
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 (30 min):** Start with these three notebooks to get comfortable:
- [Stock List](examples/set/01_stock_list.ipynb) - Discover all Thai stocks
- [Highlight Data](examples/set/02_highlight_data.ipynb) - Get key metrics like P/E, market cap, dividends
- [Corporate Actions](examples/set/05_corporate_action.ipynb) - Track dividends and shareholder meetings

**Fundamental Analysis (2 hrs):** Build a complete stock analysis workflow:
- [Stock List](examples/set/01_stock_list.ipynb) → [Highlight Data](examples/set/02_highlight_data.ipynb) → [Price Performance](examples/set/10_price_performance.ipynb) → [Financial Statements](examples/set/11_financial.ipynb)

**Professional Trading (3 hrs):** 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](examples/set/01_stock_list.ipynb)** - Fetch and filter all stocks, build portfolio universes
2. **[Highlight Data](examples/set/02_highlight_data.ipynb)** - Value screeners, dividend portfolios, risk-adjusted returns
3. **[Stock Profile](examples/set/03_stock_profile.ipynb)** - Listing details, IPO data, foreign ownership
4. **[Company Profile](examples/set/04_company_profile.ipynb)** - ESG ratings, governance scores, management
5. **[Corporate Actions](examples/set/05_corporate_action.ipynb)** - Dividend calendars, shareholder meetings
6. **[Shareholder Data](examples/set/06_shareholder.ipynb)** - Ownership analysis, free float monitoring
7. **[NVDR Holders](examples/set/07_nvdr_holder.ipynb)** - NVDR ownership tracking and analysis
8. **[Board of Directors](examples/set/08_board_of_director.ipynb)** - Board composition and management structure
9. **[Trading Statistics](examples/set/09_trading_statistics.ipynb)** - Multi-period performance and volatility
10. **[Price Performance](examples/set/10_price_performance.ipynb)** - Sector comparison and alpha calculation
11. **[Financial Statements](examples/set/11_financial.ipynb)** - Balance sheet, income, cash flow analysis

### 📈 TFEX Examples (Thailand Futures Exchange)

Professional derivatives trading workflows with margin calculations and risk management:

1. **[Series List](examples/tfex/01_series_list.ipynb)** - Discover futures/options, rollover monitoring, options chains
2. **[Trading Statistics](examples/tfex/02_trading_statistics.ipynb)** - Margin requirements, position sizing, P/L tracking

**[📂 View All Examples](examples/)** - Complete index with learning guides

## 📚 Full Documentation

Want to dig deeper? Check out our detailed guides:

### SET Services

- **[Stock List Service](docs/settfex/services/set/list.md)** - Get all stocks on SET/mai
- **[Highlight Data Service](docs/settfex/services/set/highlight_data.md)** - Market metrics and valuations
- **[Stock Profile Service](docs/settfex/services/set/profile_stock.md)** - Listing details and share structure
- **[Company Profile Service](docs/settfex/services/set/profile_company.md)** - Full company information
- **[Corporate Action Service](docs/settfex/services/set/corporate_action.md)** - Dividends, meetings, and events
- **[Shareholder Service](docs/settfex/services/set/shareholder.md)** - Major shareholders and ownership data
- **[NVDR Holder Service](docs/settfex/services/set/nvdr_holder.md)** - NVDR holder information and ownership
- **[Board of Director Service](docs/settfex/services/set/board_of_director.md)** - Board of directors and management structure
- **[Trading Statistics Service](docs/settfex/services/set/trading_stat.md)** - Historical trading performance and metrics
- **[Price Performance Service](docs/settfex/services/set/price_performance.md)** - Stock, sector, and market price performance comparison
- **[Financial Service](docs/settfex/services/set/financial.md)** - Balance sheet, income statement, and cash flow data

### TFEX Services

- **[TFEX Series List Service](docs/settfex/services/tfex/list.md)** - Get all futures and options series on TFEX
- **[TFEX Trading Statistics Service](docs/settfex/services/tfex/trading_statistics.md)** - Trading statistics, settlement prices, and margin requirements

### Utilities

- **[AsyncDataFetcher](docs/settfex/utils/data_fetcher.md)** - Low-level async HTTP client
- **[Session Caching](docs/settfex/utils/session_caching.md)** - How we make things 25x faster

## 🎯 What Can You Do?

### SET (Stock Exchange of Thailand)

#### 📋 Get Stock List

Want to see all stocks trading on SET? Easy!

```python
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](docs/settfex/services/set/list.md)**

---

#### 💰 Get Stock Highlight Data

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

```python
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](docs/settfex/services/set/highlight_data.md)**

---

#### 📊 Get Stock Profile

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

```python
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](docs/settfex/services/set/profile_stock.md)**

---

#### 🏢 Get Company Profile

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

```python
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](docs/settfex/services/set/profile_company.md)**

---

#### 📅 Get Corporate Actions

Track dividends, shareholder meetings, and other corporate events:

```python
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](docs/settfex/services/set/corporate_action.md)**

---

#### 👥 Get Shareholder Data

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

```python
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](docs/settfex/services/set/shareholder.md)**

---

#### 📜 Get NVDR Holder Data

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

```python
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](docs/settfex/services/set/nvdr_holder.md)**

---

#### 👔 Get Board of Directors

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

```python
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](docs/settfex/services/set/board_of_director.md)**

---

#### 📊 Get Trading Statistics

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

```python
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](docs/settfex/services/set/trading_stat.md)**

---

#### 📈 Get Price Performance

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

```python
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](docs/settfex/services/set/price_performance.md)**

---

#### 💰 Get Financial Statements

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

```python
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](docs/settfex/services/set/financial.md)**

---

### TFEX (Thailand Futures Exchange)

#### 📋 Get TFEX Series List

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

```python
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](docs/settfex/services/tfex/list.md)**

---

#### 📊 Get TFEX Trading Statistics

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

```python
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](docs/settfex/services/tfex/trading_statistics.md)**

---

## 🚀 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](docs/settfex/utils/session_caching.md)**

### 🇹🇭 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:

```python
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!

```python
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](docs/settfex/utils/data_fetcher.md)**

## 🧪 Optional: Configure Logging

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

```python
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.

## 🤝 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?

- 📖 Check the [detailed documentation](docs/settfex/)
- 🐛 Found a bug? [Open an issue](https://github.com/lumduan/settfex/issues)

---