| import os
|
| import logging
|
| import ccxt
|
| from logging.handlers import RotatingFileHandler
|
| from datetime import datetime
|
| import json
|
| from typing import List, Dict, Any
|
|
|
| def setup_logger():
|
| """Configure and set up the logger"""
|
|
|
| os.makedirs("logs", exist_ok=True)
|
|
|
|
|
| logger = logging.getLogger("crypto_data_source")
|
| logger.setLevel(logging.INFO)
|
|
|
|
|
| console_handler = logging.StreamHandler()
|
| console_handler.setLevel(logging.INFO)
|
|
|
|
|
| log_file = f"logs/crypto_data_source_{datetime.now().strftime('%Y%m%d')}.log"
|
| file_handler = RotatingFileHandler(
|
| log_file, maxBytes=10*1024*1024, backupCount=5
|
| )
|
| file_handler.setLevel(logging.INFO)
|
|
|
|
|
| formatter = logging.Formatter(
|
| '%(asctime)s - %(name)s - %(levelname)s - %(message)s'
|
| )
|
|
|
|
|
| console_handler.setFormatter(formatter)
|
| file_handler.setFormatter(formatter)
|
|
|
|
|
| logger.addHandler(console_handler)
|
| logger.addHandler(file_handler)
|
|
|
| return logger
|
|
|
| def get_available_exchanges() -> List[str]:
|
| """Get list of available exchanges with OHLCV support"""
|
| exchanges = []
|
|
|
|
|
| preferred_exchanges = [
|
| 'binance', 'kucoin', 'coinbase', 'kraken', 'okx', 'bybit'
|
| ]
|
|
|
| for exchange_id in preferred_exchanges:
|
| try:
|
| exchange_class = getattr(ccxt, exchange_id)
|
| exchange = exchange_class()
|
|
|
|
|
| if exchange.has['fetchOHLCV']:
|
| exchanges.append(exchange_id)
|
| except:
|
|
|
| continue
|
|
|
| return exchanges
|
|
|
| def format_timestamp(timestamp_ms: int) -> str:
|
| """Format timestamp to ISO string"""
|
| return datetime.fromtimestamp(timestamp_ms / 1000).isoformat()
|
|
|
| def safe_json_serialize(obj):
|
| """Custom JSON serializer for handling non-serializable types"""
|
| if isinstance(obj, (datetime)):
|
| return obj.isoformat()
|
| raise TypeError(f"Type {type(obj)} not serializable")
|
|
|