tse-client (Rust)
A Rust library crate and port of the tse-client npm package, providing a client for accessing data from the Tehran Stock Exchange Technology Management Company (TSETMC). The crate supports fetching OHLC (Open/High/Low/Close) candlestick data, intraday trading data, market indices, and the complete list of tradable instruments across all major Iranian capital markets, including the Tehran Stock Exchange (TSE / بورس تهران), Iran Fara Bourse (IFB / فرابورس ایران), and the Base Market (بازار پایه). Supported indices include the Total Index (شاخص کل) and IFB Total Index (شاخص کل فرابورس).
[!NOTE] This crate must be called on a server located inside Iran. TSE data servers are not accessible from outside the country.
Features
- 📈 Fetch OHLC candlestick data for any TSE instrument
- 📋 Get the full list of TSE-listed instruments
- 🕯️ Supports Daily, Weekly, and Monthly timeframes with automatic resampling
- ⚡ Fetch intraday trading data
- 📅 Jalali (Solar Hijri) calendar support for correct weekly/monthly grouping
- 🔧 Adjusted prices support
- 🦀 High-performance Rust implementation and port of
tse-client
Public API
Mirrors the JS module:
use ;
async
Weekly / monthly timeframe (Jalali calendar)
get_prices can resample daily data into weekly or monthly OHLCV bars using
Jalali (Solar Hijri) calendar boundaries. Weeks run Saturday–Friday (the Iranian
trading week); months follow the Jalali calendar. Set the period field on
PriceSettings:
use ;
# async
You can also group already-parsed ClosingPrice rows directly with the free
function:
use ;
// `daily` is a slice of ClosingPrice rows sorted ascending by date.
let daily: = /* ... */ vec!;
let weekly = group;
let monthly = group;
let unchanged = group; // returns the input as-is
Aggregation per group: open = first open, close = last close, high = max high,
low = min low, and volume/value/count are summed. See
examples/group_prices.rs for a runnable demo.
Configuration that used to be mutable globals (PRICES_UPDATE_CHUNK,
INTRADAY_URL, etc.) now lives on Client::config_mut() via the Config
struct.
Notable differences from the JS version (bug / leak fixes)
The original JS kept several module-level mutable maps that were never cleared between calls:
storedPrices— accumulated every instrument's full price history ever fetched, for the lifetime of the process.lastdevens— accumulated last-update markers.stored(intraday) — accumulated every intraday record ever fetched.
In a short-lived CLI run this is harmless, but in a long-running process (a server importing the module) it is an unbounded memory leak: memory grew with every distinct symbol requested and was never reclaimed.
In this port, all of that working state is owned locally per call
(PricesState in client.rs, and the stored map in intraday.rs) and is
dropped when the call returns. No cross-call accumulation, no leak.
Other cleanups:
- Mutable URL/config globals replaced by an owned
Config(nostatic mut). - The
setTimeout/pollcallback state machines (pricesUpdateManager,itdUpdateManager) are expressed as plain boundedasync/awaitloops with explicit retry rounds, removing the timer/Map<id, timeout>bookkeeping. - Price adjustment uses
rust_decimalwithMidpointNearestEvenrounding to matchdecimal.js'sROUND_HALF_EVEN.
Build & test
cargo build
cargo test
cargo clippy --all-targets