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.
15 KiB
15 KiB
Stock Oracle Python Client Documentation
Installation
Option 1: Direct File Usage
# Copy the client file to your project
cp stock_oracle_client.py /path/to/your/project/
# Install dependencies
pip install requests python-dateutil
Option 2: Install as Package (Future)
# Will be available on PyPI
pip install stock-oracle-client
Option 3: Development Installation
# Clone the repository
git clone <repo-url>
cd stock-oracle
# Install client dependencies
pip install -r requirements-client.txt
# Run examples
python examples/client_usage.py
Quick Start
from stock_oracle_client import StockOracleClient
# Initialize client
client = StockOracleClient("http://localhost:18001")
# Get financial data
financial = client.get_financial_data("AAPL", period="1y")
print(f"Company: {financial['company']['name']}")
# Get price data
prices = client.get_price_data("MSFT", period="3m")
print(f"Latest close: ${prices['price_data'][-1]['close']:.2f}")
# Get ETF holdings
etf = client.get_etf_holdings("QQQ")
print(f"Holdings: {etf['data']['holdings_count']}")
Core Features
1. Client Initialization
from stock_oracle_client import StockOracleClient
# Basic initialization
client = StockOracleClient("http://localhost:18001")
# With options
client = StockOracleClient(
base_url="http://localhost:18001",
api_key=None, # For future authentication
timeout=30, # Request timeout in seconds
auto_retry=True, # Automatic retry on failure
max_retries=3 # Maximum retry attempts
)
2. Financial Data
# Using period (recommended)
data = client.get_financial_data("AAPL", period="1y")
# Using date range
from datetime import date
data = client.get_financial_data(
"AAPL",
start_date=date(2023, 1, 1),
end_date=date(2023, 12, 31),
period_type=PeriodType.QUARTERLY
)
# Using quarters
data = client.get_financial_data(
"AAPL",
quarters=["2024Q1", "2024Q2"],
include_metrics=True
)
3. Price Data
from stock_oracle_client import PriceInterval
# Daily prices for last year
prices = client.get_price_data(
"TSLA",
period="1y",
interval=PriceInterval.ONE_DAY
)
# Weekly prices for specific range
prices = client.get_price_data(
"TSLA",
start_date="2024-01-01",
end_date="2024-06-30",
interval=PriceInterval.ONE_WEEK
)
4. ETF Holdings
# Current holdings
etf = client.get_etf_holdings("QQQ")
# Historical holdings
etf = client.get_etf_holdings("SPY", as_of_date="2023-12-31")
# Without detailed holdings (faster)
etf = client.get_etf_holdings("ARKK", include_holdings=False)
# With automatic fallback
try:
etf = client.get_etf_holdings_with_fallback("QQQM", "2020-01-01")
except ETFDataNotAvailableError as e:
print(f"Error: {e}")
if e.availability_info:
print(f"Available from: {e.availability_info['available_date_range']['start']}")
5. Bulk Operations
# Bulk financial data
bulk_financial = client.get_bulk_financial_data(
["AAPL", "MSFT", "GOOGL"],
period="6m",
period_type=PeriodType.QUARTERLY
)
# Bulk price data
bulk_prices = client.get_bulk_price_data(
["TSLA", "NIO", "RIVN"],
period="1m",
interval=PriceInterval.ONE_DAY
)
# Bulk ETF holdings
bulk_etf = client.get_bulk_etf_holdings(
["QQQ", "SPY", "IWM"],
include_holdings=False # For performance
)
6. Alpaca Market Data
import requests
BASE = "http://localhost:18001/api/v1"
# Check Alpaca connection
status = requests.get(f"{BASE}/alpaca/status").json()
print(f"Alpaca configured: {status['configured']}")
# ── 과거 분봉 (SIP 피드, DB 저장, 어제까지) ──────────────────────────
# 백테스트, 과거 OHLCV 분석용. 거래량 100% 정확.
hist = requests.get(f"{BASE}/alpaca/intraday", params={
"tickers": "AAPL,MSFT,NVDA",
"interval": "5m",
"start_date": "2025-01-02",
"end_date": "2025-01-31",
}).json()
print(f"Historical bars: {hist['count']} tickers")
for ticker, bars in hist["bars"].items():
print(f" {ticker}: {len(bars)} bars")
# ── 당일 실시간 분봉 (IEX 피드, 오늘만) ─────────────────────────────
# 당일 ORB 전략, 실시간 장 중 모니터링.
# 거래량은 실제의 2~5% (IEX 거래소 거래만 집계).
today = requests.get(f"{BASE}/alpaca/intraday/today", params={
"tickers": "AAPL,MSFT,NVDA",
"interval": "5m",
}).json()
for ticker, bars in today["bars"].items():
if bars:
latest = bars[-1]
print(f" {ticker}: last bar {latest['timestamp']} close={latest['close']}")
# ── 실시간 스냅샷 (IEX 피드, 캐시 없음) ─────────────────────────────
# 단일 종목도 tickers= 쿼리 파라미터로 조회 가능.
snap = requests.get(f"{BASE}/alpaca/snapshot", params={"tickers": "SPY,QQQ,AAPL"}).json()
for s in snap["snapshots"]:
print(f" {s['ticker']}: {s['price']} ({s['change_pct']:+.2f}%) bid={s['bid']} ask={s['ask']}")
7. FINRA Short Volume
import requests
BASE = "http://localhost:18001/api/v1"
# Get short volume (auto-ingests if missing)
sv = requests.get(f"{BASE}/finra/short-volume/AAPL", params={"days": 30}).json()
print(f"AAPL short volume entries: {sv['total_count']}")
for entry in sv["entries"][:3]:
print(f" {entry['date']}: ratio={entry['short_ratio']:.2%}")
# Get short ratio history (aggregated across markets)
ratio = requests.get(f"{BASE}/finra/short-ratio/AAPL", params={"days": 60}).json()
print(f"Average short ratio: {ratio['avg_short_ratio']:.2%}")
# Manual ingest
ingest = requests.post(f"{BASE}/finra/admin/ingest", params={"date": "2025-03-10"}).json()
print(f"Ingested: {ingest['records_ingested']} records")
Advanced Usage
Error Handling
from stock_oracle_client import (
StockOracleClient,
StockOracleAPIError,
ETFDataNotAvailableError
)
client = StockOracleClient("http://localhost:18001")
try:
# Try to get data
data = client.get_financial_data("INVALID")
except StockOracleAPIError as e:
print(f"API Error: {e}")
print(f"Status Code: {e.status_code}")
print(f"Response: {e.response_data}")
except ETFDataNotAvailableError as e:
print(f"ETF Data Not Available: {e}")
if e.availability_info:
print(f"Launch Date: {e.availability_info.get('etf_launch_date')}")
print(f"Available Range: {e.availability_info.get('available_date_range')}")
Availability Checking
# Check if ETF data is available
availability = client.check_etf_availability("QQQM", "2020-01-01")
if not availability.get('exists_for_date'):
print(f"ETF didn't exist on requested date")
print(f"Launch date: {availability.get('etf_launch_date')}")
print(f"First available: {availability['available_date_range']['start']}")
Using Enums
from stock_oracle_client import PriceInterval, PeriodType
# Price intervals
intervals = [
PriceInterval.ONE_MINUTE,
PriceInterval.FIVE_MINUTES,
PriceInterval.ONE_HOUR,
PriceInterval.ONE_DAY,
PriceInterval.ONE_WEEK,
PriceInterval.ONE_MONTH
]
# Period types
period_types = [
PeriodType.QUARTERLY,
PeriodType.ANNUAL,
PeriodType.ALL
]
Utility Methods
# Validate ticker
is_valid = client.validate_ticker("AAPL") # Returns True
is_valid = client.validate_ticker("INVALID123") # Returns False
# Get latest filing date
filing_date = client.get_latest_filing_date("MSFT")
# Search tickers (client-side)
results = client.search_tickers("AA") # Returns ["AAPL", ...]
# Get supported ETFs
supported = client.get_supported_etfs()
print(f"Total ETFs: {supported['total_etfs']}")
# Get data catalog
catalog = client.get_data_catalog()
Convenience Functions
For quick one-off requests without creating a client instance:
from stock_oracle_client import get_financial_data, get_price_data, get_etf_holdings
# Quick financial data
financial = get_financial_data("AAPL", period="1y")
# Quick price data
prices = get_price_data("TSLA", period="3m")
# Quick ETF holdings
etf = get_etf_holdings("QQQ", as_of_date="2024-01-01")
Best Practices
1. Use Period Strings
Period strings are the most convenient way to specify time ranges:
"1d","5d","1m","3m","6m","1y","2y","5y","10y","ytd","max"
2. Batch Requests
Use bulk endpoints when fetching data for multiple tickers:
# Good - single bulk request
bulk_data = client.get_bulk_financial_data(["AAPL", "MSFT", "GOOGL"])
# Bad - multiple individual requests
data1 = client.get_financial_data("AAPL")
data2 = client.get_financial_data("MSFT")
data3 = client.get_financial_data("GOOGL")
3. Handle ETF Availability
Always check availability when requesting historical ETF data:
def get_etf_data_safe(client, ticker, date):
try:
return client.get_etf_holdings(ticker, as_of_date=date)
except ETFDataNotAvailableError as e:
if e.availability_info:
# Try with earliest available date
start_date = e.availability_info['available_date_range']['start']
return client.get_etf_holdings(ticker, as_of_date=start_date)
raise
4. Use Session Reuse
The client automatically reuses HTTP sessions for better performance:
# Good - reuse client instance
client = StockOracleClient("http://localhost:18001")
for ticker in tickers:
data = client.get_financial_data(ticker)
# Bad - create new client each time
for ticker in tickers:
client = StockOracleClient("http://localhost:18001")
data = client.get_financial_data(ticker)
5. Error Recovery
Enable auto-retry for better reliability:
client = StockOracleClient(
"http://localhost:18001",
auto_retry=True,
max_retries=3
)
Examples
Complete Example: Portfolio Analysis
from stock_oracle_client import StockOracleClient, PeriodType
from datetime import datetime, timedelta
def analyze_portfolio(tickers, client):
"""Analyze a portfolio of stocks and ETFs"""
results = {
'stocks': {},
'etfs': {},
'errors': []
}
for ticker in tickers:
try:
# Try as ETF first
etf_data = client.get_etf_holdings(ticker, include_holdings=False)
if etf_data['success']:
results['etfs'][ticker] = {
'type': 'ETF',
'holdings_count': etf_data['data']['holdings_count'],
'as_of_date': etf_data['as_of_date']
}
continue
except:
pass
try:
# Try as stock
financial = client.get_financial_data(
ticker,
period="1y",
period_type=PeriodType.QUARTERLY
)
if financial['financial_data']:
latest = financial['financial_data'][0]
results['stocks'][ticker] = {
'type': 'Stock',
'company': financial['company']['name'],
'latest_filing': latest['date'],
'pe_ratio': latest.get('metrics', {}).get('pe_ratio'),
'market_cap': latest.get('market_cap')
}
except Exception as e:
results['errors'].append({
'ticker': ticker,
'error': str(e)
})
return results
# Usage
client = StockOracleClient("http://localhost:18001")
portfolio = ["AAPL", "QQQ", "MSFT", "SPY", "TSLA", "ARKK"]
analysis = analyze_portfolio(portfolio, client)
print("Stocks:")
for ticker, data in analysis['stocks'].items():
print(f" {ticker}: {data['company']}")
print("\nETFs:")
for ticker, data in analysis['etfs'].items():
print(f" {ticker}: {data['holdings_count']} holdings")
Data Export Example
import pandas as pd
from stock_oracle_client import StockOracleClient
client = StockOracleClient("http://localhost:18001")
# Get data
financial = client.get_financial_data("AAPL", period="2y")
# Convert to DataFrame
df = pd.DataFrame(financial['financial_data'])
# Export to CSV
df.to_csv("aapl_financial_data.csv", index=False)
# Export to Excel
df.to_excel("aapl_financial_data.xlsx", index=False)
print(f"Exported {len(df)} records")
Troubleshooting
Common Issues
-
Connection Error
# Check if API is running try: health = client.get_health() except: print("API is not accessible") -
ETF Data Not Available
- Check availability first using
check_etf_availability() - Use
get_etf_holdings_with_fallback()for automatic fallback - Check the
availability_infoin the exception
- Check availability first using
-
Rate Limiting
- Add delays between requests if needed
- Use bulk endpoints for multiple tickers
- Enable caching on the server side
-
Timeout Issues
# Increase timeout for large requests client = StockOracleClient("http://localhost:18001", timeout=60)
API Response Structure
Financial Data Response
{
"ticker": "AAPL",
"company": {
"name": "Apple Inc.",
"sector": "Technology",
"industry": "Consumer Electronics"
},
"financial_data": [
{
"date": "2024-03-31",
"revenue": 119575000000,
"net_income": 23636000000,
"metrics": {
"pe_ratio": 26.5,
"return_on_equity": 1.47,
"gross_margin": 0.455
}
}
]
}
ETF Holdings Response
{
"ticker": "QQQ",
"as_of_date": "2024-12-31",
"success": true,
"data": {
"filing_info": {
"filing_date": "2024-12-31",
"cik": "1067839",
"total_value": 250000000000,
"total_holdings": 102
},
"holdings": [
{
"name": "MICROSOFT CORP",
"cusip": "594918104",
"value": 25000000000,
"shares": 50000000,
"percentage": 10.0
}
],
"holdings_count": 102
},
"availability": null
}
Error Response with Availability
{
"ticker": "QQQM",
"as_of_date": "2020-01-01",
"success": false,
"error": "ETF QQQM did not exist on 2020-01-01",
"availability": {
"exists_for_date": false,
"etf_launch_date": "2020-10-13",
"first_nport_date": "2021-01-31",
"available_date_range": {
"start": "2021-01-31",
"end": "present"
}
}
}
Version History
v2.0.0 (Current)
- Added comprehensive ETF holdings support
- Improved error handling with custom exceptions
- Added availability checking for ETF data
- Bulk operations for all data types
- Enum support for intervals and period types
- Automatic retry logic
- Utility methods for validation and search
v3.0.0
- Added Alpaca Market Data integration (bars, intraday, DB storage)
- Added FINRA Short Volume data (auto-ingest, short ratio history)
- New data sources: Alpaca (optional API key), FINRA (public CDN)
v1.0.0
- Initial release
- Basic financial and price data retrieval
- Period string support
- Bulk financial data
Support
For issues, questions, or contributions:
- GitHub Issues: [Report bugs or request features]
- Documentation: API Documentation
- Examples: See
examples/directory