Refactor code for improved readability and consistency
- Cleaned up whitespace and formatting in various files including http.py, language.py, logger.py, safe_exec.py, and SQL migration scripts. - Consolidated import statements and removed unnecessary blank lines. - Updated logging configuration for better clarity. - Enhanced the safe execution code with improved error handling and logging. - Removed commented-out code and unnecessary variables in backfill_zero_trades.py and other scripts. - Added a pyproject.toml for Ruff and Vulture configuration. - Introduced requirements-dev.txt for development dependencies. - Removed commented-out stock entries in init.sql for cleaner migration scripts.
This commit is contained in:
@@ -1,41 +1,37 @@
|
||||
"""
|
||||
K-line data service
|
||||
"""
|
||||
from typing import Dict, List, Any, Optional
|
||||
|
||||
from typing import Any, Dict, List, Optional
|
||||
|
||||
from app.config import CacheConfig
|
||||
from app.data_sources import DataSourceFactory
|
||||
from app.utils.cache import CacheManager
|
||||
from app.utils.logger import get_logger
|
||||
from app.config import CacheConfig
|
||||
|
||||
logger = get_logger(__name__)
|
||||
|
||||
|
||||
class KlineService:
|
||||
"""K-line data service"""
|
||||
|
||||
|
||||
def __init__(self):
|
||||
self.cache = CacheManager()
|
||||
self.cache_ttl = CacheConfig.KLINE_CACHE_TTL
|
||||
|
||||
|
||||
def get_kline(
|
||||
self,
|
||||
market: str,
|
||||
symbol: str,
|
||||
timeframe: str,
|
||||
limit: int = 300,
|
||||
before_time: Optional[int] = None
|
||||
self, market: str, symbol: str, timeframe: str, limit: int = 300, before_time: Optional[int] = None
|
||||
) -> List[Dict[str, Any]]:
|
||||
"""
|
||||
Get K-line data
|
||||
|
||||
|
||||
Args:
|
||||
market: market type (Crypto, USStock, Forex, Futures)
|
||||
symbol: trading pair/stock code
|
||||
timeframe: time period
|
||||
limit: number of data items
|
||||
before_time: Get data before this time
|
||||
|
||||
|
||||
Returns:
|
||||
K-line data list
|
||||
"""
|
||||
@@ -46,40 +42,36 @@ class KlineService:
|
||||
if cached:
|
||||
# logger.info(f"Hit cache: {cache_key}")
|
||||
return cached
|
||||
|
||||
|
||||
# Get data
|
||||
klines = DataSourceFactory.get_kline(
|
||||
market=market,
|
||||
symbol=symbol,
|
||||
timeframe=timeframe,
|
||||
limit=limit,
|
||||
before_time=before_time
|
||||
market=market, symbol=symbol, timeframe=timeframe, limit=limit, before_time=before_time
|
||||
)
|
||||
|
||||
|
||||
# Set cache (latest data only)
|
||||
if klines and not before_time:
|
||||
ttl = self.cache_ttl.get(timeframe, 300)
|
||||
self.cache.set(cache_key, klines, ttl)
|
||||
# logger.info(f"Cache settings: {cache_key}, TTL: {ttl}s")
|
||||
|
||||
|
||||
return klines
|
||||
|
||||
|
||||
def get_latest_price(self, market: str, symbol: str) -> Optional[Dict[str, Any]]:
|
||||
"""Get the latest price (use 1-minute K-line, deprecated, it is recommended to use get_realtime_price)"""
|
||||
klines = self.get_kline(market, symbol, '1m', 1)
|
||||
klines = self.get_kline(market, symbol, "1m", 1)
|
||||
if klines:
|
||||
return klines[-1]
|
||||
return None
|
||||
|
||||
|
||||
def get_realtime_price(self, market: str, symbol: str, force_refresh: bool = False) -> Dict[str, Any]:
|
||||
"""
|
||||
Get real-time prices (priority to use ticker API, downgrade to minute K-line)
|
||||
|
||||
|
||||
Args:
|
||||
market: market type (Crypto, USStock, Forex, Futures)
|
||||
symbol: trading pair/stock code
|
||||
force_refresh: whether to force refresh (skip cache)
|
||||
|
||||
|
||||
Returns:
|
||||
Real-time price data: {
|
||||
'price': latest price,
|
||||
@@ -94,97 +86,96 @@ class KlineService:
|
||||
"""
|
||||
# Build a cache key (short-term cache to avoid frequent requests)
|
||||
cache_key = f"realtime_price:{market}:{symbol}"
|
||||
|
||||
|
||||
# If it is not a forced refresh, try using caching
|
||||
if not force_refresh:
|
||||
cached = self.cache.get(cache_key)
|
||||
if cached:
|
||||
return cached
|
||||
|
||||
|
||||
result = {
|
||||
'price': 0,
|
||||
'change': 0,
|
||||
'changePercent': 0,
|
||||
'high': 0,
|
||||
'low': 0,
|
||||
'open': 0,
|
||||
'previousClose': 0,
|
||||
'source': 'unknown'
|
||||
"price": 0,
|
||||
"change": 0,
|
||||
"changePercent": 0,
|
||||
"high": 0,
|
||||
"low": 0,
|
||||
"open": 0,
|
||||
"previousClose": 0,
|
||||
"source": "unknown",
|
||||
}
|
||||
|
||||
|
||||
# First try to use the ticker API to get real-time prices
|
||||
try:
|
||||
ticker = DataSourceFactory.get_ticker(market, symbol)
|
||||
if ticker and ticker.get('last', 0) > 0:
|
||||
if ticker and ticker.get("last", 0) > 0:
|
||||
result = {
|
||||
'price': ticker.get('last', 0),
|
||||
'change': ticker.get('change', 0),
|
||||
'changePercent': ticker.get('changePercent', 0),
|
||||
'high': ticker.get('high', 0),
|
||||
'low': ticker.get('low', 0),
|
||||
'open': ticker.get('open', 0),
|
||||
'previousClose': ticker.get('previousClose', 0),
|
||||
'source': 'ticker'
|
||||
"price": ticker.get("last", 0),
|
||||
"change": ticker.get("change", 0),
|
||||
"changePercent": ticker.get("changePercent", 0),
|
||||
"high": ticker.get("high", 0),
|
||||
"low": ticker.get("low", 0),
|
||||
"open": ticker.get("open", 0),
|
||||
"previousClose": ticker.get("previousClose", 0),
|
||||
"source": "ticker",
|
||||
}
|
||||
# Cache for 30 seconds
|
||||
self.cache.set(cache_key, result, 30)
|
||||
return result
|
||||
except Exception as e:
|
||||
logger.debug(f"Ticker API failed for {market}:{symbol}, falling back to kline: {e}")
|
||||
|
||||
|
||||
# Downgrade: Use 1 minute candlestick
|
||||
try:
|
||||
klines = self.get_kline(market, symbol, '1m', 2)
|
||||
klines = self.get_kline(market, symbol, "1m", 2)
|
||||
if klines and len(klines) > 0:
|
||||
latest = klines[-1]
|
||||
prev_close = klines[-2]['close'] if len(klines) > 1 else latest.get('open', 0)
|
||||
current_price = latest.get('close', 0)
|
||||
|
||||
prev_close = klines[-2]["close"] if len(klines) > 1 else latest.get("open", 0)
|
||||
current_price = latest.get("close", 0)
|
||||
|
||||
change = round(current_price - prev_close, 4) if prev_close else 0
|
||||
change_pct = round(change / prev_close * 100, 2) if prev_close and prev_close > 0 else 0
|
||||
|
||||
|
||||
result = {
|
||||
'price': current_price,
|
||||
'change': change,
|
||||
'changePercent': change_pct,
|
||||
'high': latest.get('high', 0),
|
||||
'low': latest.get('low', 0),
|
||||
'open': latest.get('open', 0),
|
||||
'previousClose': prev_close,
|
||||
'source': 'kline_1m'
|
||||
"price": current_price,
|
||||
"change": change,
|
||||
"changePercent": change_pct,
|
||||
"high": latest.get("high", 0),
|
||||
"low": latest.get("low", 0),
|
||||
"open": latest.get("open", 0),
|
||||
"previousClose": prev_close,
|
||||
"source": "kline_1m",
|
||||
}
|
||||
# Cache for 30 seconds
|
||||
self.cache.set(cache_key, result, 30)
|
||||
return result
|
||||
except Exception as e:
|
||||
logger.debug(f"1m kline failed for {market}:{symbol}, trying daily: {e}")
|
||||
|
||||
|
||||
# Last downgrade: using daily data (applies to non-trading hours)
|
||||
try:
|
||||
klines = self.get_kline(market, symbol, '1D', 2)
|
||||
klines = self.get_kline(market, symbol, "1D", 2)
|
||||
if klines and len(klines) > 0:
|
||||
latest = klines[-1]
|
||||
prev_close = klines[-2]['close'] if len(klines) > 1 else latest.get('open', 0)
|
||||
current_price = latest.get('close', 0)
|
||||
|
||||
prev_close = klines[-2]["close"] if len(klines) > 1 else latest.get("open", 0)
|
||||
current_price = latest.get("close", 0)
|
||||
|
||||
change = round(current_price - prev_close, 4) if prev_close else 0
|
||||
change_pct = round(change / prev_close * 100, 2) if prev_close and prev_close > 0 else 0
|
||||
|
||||
|
||||
result = {
|
||||
'price': current_price,
|
||||
'change': change,
|
||||
'changePercent': change_pct,
|
||||
'high': latest.get('high', 0),
|
||||
'low': latest.get('low', 0),
|
||||
'open': latest.get('open', 0),
|
||||
'previousClose': prev_close,
|
||||
'source': 'kline_1d'
|
||||
"price": current_price,
|
||||
"change": change,
|
||||
"changePercent": change_pct,
|
||||
"high": latest.get("high", 0),
|
||||
"low": latest.get("low", 0),
|
||||
"open": latest.get("open", 0),
|
||||
"previousClose": prev_close,
|
||||
"source": "kline_1d",
|
||||
}
|
||||
# Daily data cache for 5 minutes
|
||||
self.cache.set(cache_key, result, 300)
|
||||
return result
|
||||
except Exception as e:
|
||||
logger.error(f"All price sources failed for {market}:{symbol}: {e}")
|
||||
|
||||
return result
|
||||
|
||||
return result
|
||||
|
||||
Reference in New Issue
Block a user