You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

475 lines
13 KiB
Markdown

# yfinance-plus 🚀
A drop-in replacement for `yfinance` with improved rate limiting, intelligent caching, and 401 error handling. Works exactly like the original yfinance but faster, more reliable, and with zero breaking changes.
[![Python 3.8+](https://img.shields.io/badge/python-3.8+-blue.svg)](https://www.python.org/downloads/)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
## ✨ Key Features
### 🎯 **100% Drop-in Replacement**
- Import as `import yfinance_plus as yf`
- All yfinance functionality works identically
- **99% API coverage** (97/98 features supported)
- Zero code changes required
### 🛡️ **Enhanced Rate Limiting & Error Handling**
- **Automatic 401 error handling** with session refresh
- **Browser-like headers** with 7 different User-Agent strings
- **Exponential backoff** with intelligent retry logic
- **Session rotation** every 10 minutes or 50 requests
### ⚡ **Intelligent Caching System**
- **247x faster** repeated requests with file-based caching
- **Smart period matching** - longer periods serve shorter requests
- **Automatic cache invalidation** after 1 hour
- **CLI cache management** with detailed file information
### 🔧 **Enhanced CLI Tools**
- **`yfp` command** for cache and configuration management
- **Detailed cache inspection** with symbol, period, and date range info
- **Performance benchmarking** and connection testing
- **Configuration management** with easy-to-use commands
## 📦 Installation
### Method 1: Install from Source (Recommended)
```bash
# Clone and install
git clone https://gitea.yirugi.synology.me/yirugi/yfinance_plus.git
cd yfinance-plus
pip install -e .
```
### Method 2: Local Development
```bash
# Install dependencies
pip install yfinance>=0.2.65 curl_cffi>=0.5.0 pandas>=1.3.0 numpy>=1.20.0
```
## 🚀 Quick Start
### Drop-in Replacement Usage
```python
# Simply replace your import - everything else stays the same!
import yfinance_plus as yf
# All original yfinance functionality works identically
ticker = yf.Ticker("AAPL")
hist = ticker.history(period="1mo")
info = ticker.info # Note: property, not method
data = yf.download(["AAPL", "GOOGL"], period="1mo")
# Multiple tickers
tickers = yf.Tickers("MSFT AAPL GOOG")
msft_info = tickers.tickers['MSFT'].info
# New cache management features
yf.clear_cache()
cache_info = yf.get_cache_info()
```
### Performance Comparison
```python
import time
import yfinance_plus as yf
# First request (downloads and caches)
start = time.time()
data1 = yf.Ticker("AAPL").history(period="1mo")
first_time = time.time() - start
print(f"First request: {first_time:.3f}s")
# Second request (from cache)
start = time.time()
data2 = yf.Ticker("AAPL").history(period="1mo")
second_time = time.time() - start
print(f"Second request: {second_time:.3f}s")
print(f"Speedup: {first_time/second_time:.1f}x")
# Output:
# First request: 0.186s
# Second request: 0.001s
# Speedup: 247.9x
```
## 🔧 Command Line Interface
### Available Commands
```bash
yfp --help # Show all available commands
yfp cache info # Show detailed cache information
yfp cache info --limit 5 # Show only 5 most recent files
yfp cache clear # Clear cache with confirmation
yfp cache clear --force # Clear cache without confirmation
yfp config show # Show current configuration
yfp test # Test connection to Yahoo Finance
yfp benchmark # Run performance benchmark
```
### Enhanced Cache Information
```bash
$ yfp cache info
🗂️ YFinance Plus Cache Information
==================================================
Cache Directory: /Users/username/.yfinance_cache
Number of Files: 8
Total Size: 30.5 KB
📁 Cache Files:
----------------------------------------------------------------------------------------------------
📄 06dbc103b9a8af2faddce6c95b2caaef 5.4 KB 2025-08-01 21:59:40
Symbol: NVDA Period: 3mo Interval: 1d Rows: 63
Date Range: 2025-05-02 to 2025-08-01
📄 0d84bd5865d16d346aabcaed64cf02f0 2.8 KB 2025-08-01 21:59:40
Symbol: NVDA Period: 1mo Interval: 1d Rows: 22
Date Range: 2025-07-02 to 2025-08-01
```
### Configuration Management
```bash
$ yfp config show
⚙️ YFinance Plus Configuration
========================================
Max Retries: 3
Base Delay: 1.0s
Max Delay: 60.0s
Jitter Enabled: True
Cache Enabled: True
Cache Directory: /Users/username/.yfinance_cache
User Agents: 7 configured
```
### Connection Testing
```bash
$ yfp test
🔗 Testing connection to Yahoo Finance...
Creating test ticker...
Fetching basic info...
Fetching historical data...
✅ Connection test successful!
Company: Apple Inc.
Historical data points: 5
Cache status: 8 files
```
## 💾 Intelligent Caching System
### How Smart Caching Works
```python
import yfinance_plus as yf
# 1. First request caches data
ticker = yf.Ticker("AAPL")
data_1mo = ticker.history(period="1mo") # Downloads and caches
# 2. Second identical request uses cache
data_1mo_again = ticker.history(period="1mo") # Instant from cache
# 3. Longer period downloads new data
data_3mo = ticker.history(period="3mo") # Downloads 3mo, caches it
# 4. Shorter request extracts from longer cached data
data_1mo_from_3mo = ticker.history(period="1mo") # Extracted from 3mo cache
```
### What Gets Cached
**Cached:**
- Historical price data (`history()`)
- All standard periods (1d, 1mo, 3mo, 1y, etc.)
- All intervals (1m, 5m, 1h, 1d)
- **Smart overlap detection** - longer periods serve shorter requests
**Not Cached:**
- Real-time data
- News articles (`news`)
- Extended hours data (`prepost=True`)
- Data older than 1 hour (auto-expires)
### Cache Management
```python
import yfinance_plus as yf
# Check cache status
cache_info = yf.get_cache_info()
print(f"Cache files: {cache_info['file_count']}")
print(f"Cache size: {cache_info['total_size_mb']:.2f} MB")
# Clear cache
yf.clear_cache()
# Configure caching
yf.set_config(
enable_cache=True,
cache_dir="~/my_custom_cache"
)
```
## ⚙️ Configuration
### Global Configuration
```python
import yfinance_plus as yf
# Configure global settings
yf.set_config(
max_retries=5, # Number of retry attempts
base_delay=1.0, # Base delay between retries (seconds)
max_delay=60.0, # Maximum delay (seconds)
jitter=True, # Add randomness to delays
enable_cache=True, # Enable intelligent caching
cache_dir="~/my_cache" # Custom cache directory
)
# Get current configuration
config = yf.get_config()
print(f"Max retries: {config.max_retries}")
```
### Configuration Parameters
| Parameter | Default | Description |
|-----------|---------|-------------|
| `max_retries` | 3 | Maximum retry attempts for failed requests |
| `base_delay` | 1.0 | Base delay between retries (seconds) |
| `max_delay` | 60.0 | Maximum delay between retries (seconds) |
| `jitter` | True | Add random jitter to delays |
| `enable_cache` | True | Enable intelligent caching system |
| `cache_dir` | `~/.yfinance_cache` | Cache directory location |
| `user_agents` | 7 agents | List of User-Agent strings to rotate |
## 🔄 Migration Guide
### From yfinance to yfinance-plus
Migration is **100% seamless** - just change your import:
```python
# Before
import yfinance as yf
# After
import yfinance_plus as yf
# Everything else works identically!
ticker = yf.Ticker("AAPL")
data = yf.download(["AAPL", "GOOGL"], period="1mo")
tickers = yf.Tickers("MSFT AAPL GOOG")
info = tickers.tickers['MSFT'].info
```
### Common yfinance Patterns That Work
```python
import yfinance_plus as yf
# All standard patterns work identically
ticker = yf.Ticker("AAPL")
# Properties (not methods!)
info = ticker.info # ✅ Correct
dividends = ticker.dividends # ✅ Correct
splits = ticker.splits # ✅ Correct
financials = ticker.financials # ✅ Correct
balance_sheet = ticker.balance_sheet # ✅ Correct
cashflow = ticker.cashflow # ✅ Correct
# Methods
history = ticker.history(period="1mo") # ✅ Correct
options = ticker.options # ✅ Correct
option_chain = ticker.option_chain("2024-01-19") # ✅ Correct
# Bulk operations
data = yf.download(["AAPL", "GOOGL", "MSFT"],
period="1y", interval="1d")
# Multiple tickers
tickers = yf.Tickers("AAPL GOOGL MSFT")
for symbol in tickers.symbols:
hist = tickers.tickers[symbol].history(period="1mo")
```
## 🚀 Enhanced Features
### 401 Error Handling
```python
# Automatic 401 error recovery
import yfinance_plus as yf
ticker = yf.Ticker("AAPL")
# If Yahoo returns 401, automatically:
# 1. Creates new session with fresh headers
# 2. Retries with exponential backoff
# 3. Rotates User-Agent strings
# 4. Works silently in background
info = ticker.info # Just works!
```
### Advanced Rate Limiting
```python
# The wrapper automatically:
# - Detects rate limit errors (429, 401)
# - Refreshes sessions every 10 minutes
# - Uses 7 different User-Agent strings
# - Adds realistic browser cookies
# - Implements exponential backoff
# - No user intervention required
```
### Performance Optimization
```python
import yfinance_plus as yf
# Smart cache usage
ticker = yf.Ticker("AAPL")
# Downloads 1 year of data
hist_1y = ticker.history(period="1y") # ~0.5s, cached
# Uses cached data for shorter periods
hist_6mo = ticker.history(period="6mo") # ~0.001s, from cache
hist_3mo = ticker.history(period="3mo") # ~0.001s, from cache
hist_1mo = ticker.history(period="1mo") # ~0.001s, from cache
# Result: 4 requests in ~0.5s instead of ~2.0s
```
## 📊 API Compatibility
### 100% Compatible Functions
| Function | yfinance | yfinance-plus | Enhancements |
|----------|----------|-------------------|--------------|
| `Ticker(symbol)` | ✅ | ✅ | + Caching + Rate limiting |
| `download(tickers)` | ✅ | ✅ | + Better error handling |
| `Tickers(symbols)` | ✅ | ✅ | + Enhanced performance |
| `ticker.history()` | ✅ | ✅ | + Intelligent caching |
| `ticker.info` | ✅ | ✅ | + 401 error handling |
| `ticker.financials` | ✅ | ✅ | + Automatic retries |
| `ticker.dividends` | ✅ | ✅ | + Session management |
| `ticker.splits` | ✅ | ✅ | + Rate limiting |
| All other methods | ✅ | ✅ | + Enhanced reliability |
### New Enhanced Functions
| Function | Description |
|----------|-------------|
| `yf.clear_cache()` | Clear all cached data |
| `yf.get_cache_info()` | Get detailed cache statistics |
| `yf.set_config(**kwargs)` | Configure global settings |
| `yf.get_config()` | Get current configuration |
## 🔍 Technical Details
### Browser Emulation
```python
# Automatically rotates between realistic headers:
user_agents = [
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.2.1 Safari/605.1.15',
'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:121.0) Gecko/20100101 Firefox/121.0',
# ... 3 more variants
]
# Plus realistic browser cookies:
cookies = {
'A1': 'd=AQABBC123456YLoCIgEBwQJ7vgAB&S=AQAAAg',
'GUC': 'AQEBAQFm1234k0L',
'B': 'c=1234567&b=3&s=4u',
# ... more realistic cookies
}
```
### Intelligent Cache Strategy
```python
# Cache key generation
cache_key = hash(f"{symbol}_{period}_{interval}_{start}_{end}")
# Smart period matching
if requested_period <= cached_period:
return cached_data.tail(requested_rows) # Extract from cache
else:
fetch_new_data() # Download longer period
```
### Error Recovery
```python
# Automatic error handling
if "401" in error or "unauthorized" in error:
refresh_session() # New headers and cookies
exponential_backoff() # Wait before retry
retry_request() # Try again
```
## 🧪 Testing
### Running Tests
```bash
# Run comprehensive tests
python test_drop_in_replacement.py
python test_comprehensive_wrapping.py
# CLI tests
yfp test
yfp benchmark
yfp cache info
```
### Test Results
```
🚀 Comprehensive yfinance Enhanced Wrapping Test
======================================================================
📊 Functionality coverage: 97/98 (99.0%)
✅ EXCELLENT: Nearly all yfinance functionality is working!
Cache speedup: 247.9x
Bulk download speedup: 4.36x
```
## 🤝 Contributing
1. Fork the repository
2. Create a feature branch (`git checkout -b feature/amazing-feature`)
3. Commit your changes (`git commit -m 'Add amazing feature'`)
4. Push to the branch (`git push origin feature/amazing-feature`)
5. Open a Pull Request
## 📝 License
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
## ⚠️ Disclaimer
This project is for educational and research purposes. Please respect Yahoo Finance's terms of service and rate limits. The yfinance-plus wrapper is designed to be more respectful of their servers while providing better reliability for legitimate use cases.
## 🙏 Acknowledgments
- Built on top of the excellent [yfinance](https://github.com/ranaroussi/yfinance) library
- Uses [curl_cffi](https://github.com/yifeikong/curl_cffi) for advanced browser emulation
- Inspired by the need for more reliable financial data access
---
**Made with ❤️ for the Python financial data community**