Skip to main content

mts1b-marketdata

Market-data adapters: FMP, Polygon, Finnhub, ThetaData, AlphaVantage, Tiingo, YFinance.

Repo: github.com/MTS1B/mts1b-marketdata Layer: 2 Depends on: foundation, platform, httpx Audience: mts1b-datalake, mts1b-research, any service needing live or historical bars/quotes/trades

What it is

Async adapters that implement mts1b_foundation.protocols.MarketDataProtocol for equities, options, fx, and futures data sources.

Supported providers

ProviderBarsQuotesTradesOptionsFxFuturesNotes
fmpFinancial Modeling Prep — primary equities feed
polygonPolygon.io
finnhubFinnhub
thetadataThetaData (options-focused)
alphavantageFree tier; rate-limited
tiingoTiingo
yfinanceFree; rate-limited; use for prototyping

Module layout

mts1b_marketdata/
├── __init__.py # PROVIDER_REGISTRY
├── fmp/
│ ├── client.py
│ └── normalizer.py
├── polygon/...
├── finnhub/...
├── thetadata/...
├── alphavantage/...
├── tiingo/...
├── yfinance/...
└── routing/
├── multi_source.py # MultiSourceProvider — failover + best-source-per-symbol
└── cache.py # cache layer (Redis + parquet fallback)

Top API

MarketDataProtocol

@runtime_checkable
class MarketDataProtocol(Protocol):
@property
def name(self) -> str: ...

async def get_quote(self, symbol: Symbol) -> Quote: ...
async def get_bars(
self,
symbol: Symbol,
interval: str, # "1m", "5m", "1h", "1d", ...
start: datetime,
end: datetime | None = None,
) -> list[Bar]: ...
async def get_trades(self, symbol: Symbol, asof: datetime) -> list[Trade]: ...
async def get_chain(self, root: Symbol, expiry: date | None = None) -> list[OptionContract]: ...

async def stream_quotes(self, symbols: list[Symbol]) -> AsyncIterator[Quote]: ...

Direct adapter use

from mts1b_marketdata import PROVIDER_REGISTRY
from mts1b_foundation.symbology import Symbol

async with PROVIDER_REGISTRY["fmp"](api_key="...") as md:
quote = await md.get_quote(Symbol("AAPL"))
bars = await md.get_bars(Symbol("AAPL"), interval="1d", start=datetime(2024, 1, 1))

Multi-source routing

from mts1b_marketdata.routing import MultiSourceProvider

md = MultiSourceProvider(
providers=["fmp", "polygon", "alphavantage"],
strategy="failover", # try in order; first success wins
# or "best_quote" — query all, return tightest bid-ask
# or "load_balance" — round-robin within rate-limits
)

quote = await md.get_quote(Symbol("AAPL"))

mts1b-datalake and mts1b-research use MultiSourceProvider by default — single point of failure goes away.

Symbology

All inputs are mts1b_foundation.symbology.Symbol (canonical BASE-QUOTE for crypto, ticker for equities, OCC-style for options). Each adapter renders its native format internally.

Rate-limiting

Every adapter uses mts1b_platform.ratelimit.RateLimiter configured per provider:

ProviderFree tierPaid
FMP250/day30k+/day
Polygon5/minunlimited
Finnhub60/min300+/min
YFinanceunofficial; flakyn/a

Adapters share the limiter across processes via Redis (or in-memory for single-host setups).

Caching

The cache layer (routing/cache.py):

TypeCacheTTL
QuotesRedis1-5s
Bars (intraday)Redisuntil next bar close
Bars (daily)Parquet on diskovernight refresh
Options chainsRedis30s

Cache hits don't hit the provider's rate limit. Cache misses do.

Capabilities matrix

Each adapter has a documented capabilities matrix in docs/repos/marketdata/<provider>.md listing exactly what's supported (intraday bar intervals, historical depth, options chain detail, etc.).

Live streaming

Three adapters support WebSocket streaming:

async with PROVIDER_REGISTRY["polygon"](api_key="...") as md:
async for quote in md.stream_quotes([Symbol("AAPL"), Symbol("MSFT")]):
print(f"{quote.symbol} bid={quote.bid} ask={quote.ask}")

For providers without WS, the adapter falls back to polling (configurable interval).

Build + test

pip install -e ".[dev]"
pytest -m unit # hermetic
pytest -m live --provider=fmp # requires API key

live tests run nightly in CI against staging API keys.

Roadmap

VersionItems
0.1 (Wave 1)7 adapters + MultiSourceProvider + Redis cache
0.2 (Wave 2)Tradier, IEX Cloud, Interactive Brokers historical
0.3 (Wave 2)News feed adapters (moved from altdata if heavyweight)
1.0 (LTS)Stable interface; new providers as plugins

See also