Provider System
Pulsar uses an extensible provider architecture for data sources. Each provider implements the MarketDataProvider abstract base class and is registered at startup.
Base Class
python
class MarketDataProvider(abc.ABC):
@property
@abc.abstractmethod
def name(self) -> str: ...
@property
@abc.abstractmethod
def pubsub_channel(self) -> str: ...
@abc.abstractmethod
def start(self, loop: asyncio.AbstractEventLoop) -> None: ...
@abc.abstractmethod
async def stop(self) -> None: ...
@property
def symbols(self) -> list[str]:
return []Provider Registry
python
registry = ProviderRegistry()
registry.register(AlpacaProvider(symbols))
registry.register(DovizProvider())
registry.register(CryptoProvider())
registry.start_all(loop)Implemented Providers
AlpacaProvider
- Source: Alpaca SIP WebSocket feed
- Channel:
quotes:stock - Data: Trades, quotes, bars for 80+ US stocks
- Auth: API key/secret
DovizProvider
- Source: doviz.com WebSocket
- Channel:
quotes:doviz - Data: Turkish gold (17 variants), silver, USD/EUR/GBP from 38 banks
- Protocol: Custom JSON with room subscription
CryptoProvider
- Source: Binance REST API
- Channel:
quotes:crypto - Data: 30+ cryptocurrency pairs with 24h change data
- Polling: Every 10 seconds
Adding a New Provider
- Create a new file in
services/providers/ - Extend
MarketDataProvider - Implement
start()with WebSocket/polling logic - Publish normalized data to Redis via
_publish() - Register in
events/main.py - Add a
BroadcastManagerinstance inws.py - Create REST endpoints in a new
api/router
The normalized data format:
json
{
"type": "crypto_quote",
"provider": "binance",
"exchange": "binance",
"ticker": "BTC/USD",
"name": "Bitcoin",
"price": 66354.96,
"bid": 66350.0,
"ask": 66360.0,
"change": -520.15,
"changePercent": -0.78,
"volume": 7500,
"timestamp": "2026-03-31T10:00:00Z"
}