FMP Data Client
A Python client for the Financial Modeling Prep (FMP) API with comprehensive logging, rate limiting, and error handling.
Features
- 🚀 Simple and intuitive interface
- 🔒 Built-in rate limiting
- 📝 Comprehensive logging
- ⚡ Async support
- 🏷️ Type hints and validation with Pydantic
- 🔄 Automatic retries with exponential backoff
- 🎯 100% test coverage (excluding predefined endpoints)
- 🛡️ Secure API key handling
- 📊 Support for all major FMP endpoints
- 🔍 Detailed error messages
- 🚦 Configurable retry strategies
Installation
pip install fmp-data
poetry add fmp-data
Quick Start
from fmp_data import FMPDataClient, ClientConfig, LoggingConfig
from fmp_data.exceptions import FMPError, RateLimitError, AuthenticationError
client = FMPDataClient(api_key="your_api_key_here")
client = FMPDataClient.from_env()
config = ClientConfig(
api_key="your_api_key_here",
timeout=30,
max_retries=3,
base_url="https://financialmodelingprep.com/api",
logging=LoggingConfig(level="INFO")
)
client = FMPDataClient(config=config)
with FMPDataClient(api_key="your_api_key_here") as client:
try:
profile = client.company.get_profile("AAPL")
print(f"Company: {profile.company_name}")
print(f"Industry: {profile.industry}")
print(f"Market Cap: ${profile.mkt_cap:,.2f}")
results = client.company.search("Tesla", limit=5)
for company in results:
print(f"{company.symbol}: {company.name}")
except RateLimitError as e:
print(f"Rate limit exceeded. Wait {e.retry_after} seconds")
except AuthenticationError:
print("Invalid API key")
except FMPError as e:
print(f"API error: {e}")
Key Components
1. Company Information
from fmp_data import FMPDataClient
with FMPDataClient.from_env() as client:
profile = client.company.get_profile("AAPL")
executives = client.company.get_executives("AAPL")
results = client.company.search("Tesla", limit=5)
employees = client.company.get_employee_count("AAPL")
2. Financial Statements
from fmp_data import FMPDataClient
with FMPDataClient.from_env() as client:
income_stmt = client.fundamental.get_income_statement(
"AAPL",
period="quarter",
limit=4
)
balance_sheet = client.fundamental.get_balance_sheet(
"AAPL",
period="annual"
)
cash_flow = client.fundamental.get_cash_flow_statement("AAPL")
3. Market Data
from fmp_data import FMPDataClient
with FMPDataClient.from_env() as client:
quote = client.market.get_quote("TSLA")
history = client.market.get_historical_price(
"TSLA",
from_date="2023-01-01",
to_date="2023-12-31"
)
4. Async Support
import asyncio
from fmp_data import FMPDataClient
async def get_multiple_profiles(symbols):
async with FMPDataClient.from_env() as client:
tasks = [client.company.get_profile_async(symbol)
for symbol in symbols]
return await asyncio.gather(*tasks)
symbols = ["AAPL", "MSFT", "GOOGL"]
profiles = asyncio.run(get_multiple_profiles(symbols))
Configuration
Environment Variables
FMP_API_KEY=your_api_key_here
FMP_BASE_URL=https://financialmodelingprep.com/api
FMP_TIMEOUT=30
FMP_MAX_RETRIES=3
FMP_DAILY_LIMIT=250
FMP_REQUESTS_PER_SECOND=10
FMP_REQUESTS_PER_MINUTE=300
FMP_LOG_LEVEL=INFO
FMP_LOG_PATH=/path/to/logs
FMP_LOG_MAX_BYTES=10485760
FMP_LOG_BACKUP_COUNT=5
Custom Configuration
from fmp_data import FMPDataClient, ClientConfig, LoggingConfig, RateLimitConfig
config = ClientConfig(
api_key="your_api_key_here",
timeout=30,
max_retries=3,
base_url="https://financialmodelingprep.com/api",
rate_limit=RateLimitConfig(
daily_limit=250,
requests_per_second=10,
requests_per_minute=300
),
logging=LoggingConfig(
level="DEBUG",
handlers={
"console": {
"class_name": "StreamHandler",
"level": "INFO"
},
"file": {
"class_name": "RotatingFileHandler",
"level": "DEBUG",
"filename": "fmp.log",
"maxBytes": 10485760,
"backupCount": 5
}
}
)
)
client = FMPDataClient(config=config)
Error Handling
from fmp_data import FMPDataClient
from fmp_data.exceptions import (
FMPError,
RateLimitError,
AuthenticationError,
ValidationError,
ConfigError
)
try:
with FMPDataClient.from_env() as client:
profile = client.company.get_profile("INVALID")
except RateLimitError as e:
print(f"Rate limit exceeded. Wait {e.retry_after} seconds")
print(f"Status code: {e.status_code}")
print(f"Response: {e.response}")
except AuthenticationError as e:
print("Invalid API key or authentication failed")
print(f"Status code: {e.status_code}")
except ValidationError as e:
print(f"Invalid parameters: {e.message}")
except ConfigError as e:
print(f"Configuration error: {e.message}")
except FMPError as e:
print(f"General API error: {e.message}")
Development Setup
- Clone the repository:
git clone https://github.com/MehdiZare/fmp-data.git
cd fmp-data
- Install dependencies using Poetry:
poetry install
- Set up pre-commit hooks:
poetry run pre-commit install
Running Tests
poetry run pytest --cov=fmp_data
poetry run pytest tests/test_client.py
FMP_TEST_API_KEY=your_test_api_key poetry run pytest tests/integration/
View the latest test coverage report here.
Contributing
- Fork the repository
- Create a feature branch:
git checkout -b feature-name
- Make your changes
- Run tests:
poetry run pytest
- Create a pull request
Please ensure:
- Tests pass
- Code is formatted with black
- Type hints are included
- Documentation is updated
- Commit messages follow conventional commits
Releasing New Versions
To release a new version, follow these steps:
- Ensure all changes are committed and pushed to the
main
branch - Update the CHANGELOG.md with the new version changes
- Create and push a new version tag:
git tag -a v0.1.2 -m "Release version 0.1.2"
git push origin v0.1.2
The CI/CD pipeline will automatically:
Run all tests across Python versions 3.10-3.13
Run style, type and security checks
Publish the package to TestPyPI
Publish the package to PyPI (for non-alpha/beta tags)
Create a GitHub release
Notes:
Version tags must start with 'v' (e.g., v0.1.2)
Alpha/beta versions (e.g., v0.1.2-beta) will only be published to TestPyPI
The package uses poetry-dynamic-versioning to manage versions based on git tags
License
This project is licensed under the MIT License - see the LICENSE file for details.
Acknowledgments
- Financial Modeling Prep for providing the API
- Contributors to the project
- Open source packages used in this project
Support
Release Notes
See CHANGELOG.md for a list of changes in each release.