feat(datasource): 实现加密货币数据获取功能
- 新增 ccxt_source.py: CCXT + OKX 加密货币数据源 - 新增 socks2http.py: SOCKS5 转 HTTP 代理转换器 - 修改 universal_fetcher.py: 添加 _fetch_crypto 方法,支持 timeframe 参数 - 修改 flask_server.py: API 支持 timeframe 参数,加密货币不缓存 支持的 timeframe: 1d, 1h, 4h, 15m, 1m 测试验证: BTC 数据获取成功
This commit is contained in:
@@ -230,20 +230,22 @@ def fetch_data_with_ttl(
|
||||
code: str,
|
||||
start: str,
|
||||
end: str,
|
||||
nocache: bool = False
|
||||
nocache: bool = False,
|
||||
timeframe: str = '1d'
|
||||
) -> Tuple[Optional[Dict], bool]:
|
||||
"""
|
||||
获取数据,支持 TTL 缓存(加密货币不缓存)
|
||||
|
||||
缓存策略:
|
||||
- 日级别数据(股票/指数/ETF/期货): Key=(code, today), 缓存全量数据,切片返回
|
||||
- 加密货币: 每次实时下载,不缓存
|
||||
- 加密货币: 每次实时下载,不缓存,必须指定 timeframe
|
||||
|
||||
Args:
|
||||
code: 标的代码
|
||||
start: 用户请求的开始日期
|
||||
end: 用户请求的结束日期
|
||||
nocache: 是否跳过缓存
|
||||
timeframe: K线周期(仅加密货币需要)
|
||||
|
||||
Returns:
|
||||
(data, is_cached): 数据和是否命中缓存
|
||||
@@ -254,12 +256,12 @@ def fetch_data_with_ttl(
|
||||
# 检查资产类型
|
||||
asset_type = AssetTypeDetector.detect(code)
|
||||
|
||||
# 加密货币:直接下载,不缓存
|
||||
# 加密货币:直接下载,不缓存,必须指定 timeframe
|
||||
if asset_type == AssetType.CRYPTO:
|
||||
f = get_fetcher()
|
||||
try:
|
||||
with f:
|
||||
df = f.fetch(code, start, end)
|
||||
df = f.fetch(code, start, end, timeframe=timeframe)
|
||||
if df is None or len(df) == 0:
|
||||
return None, False
|
||||
result = dataframe_to_json(df)
|
||||
@@ -267,6 +269,7 @@ def fetch_data_with_ttl(
|
||||
result['asset_type'] = asset_type.value
|
||||
result['cache_strategy'] = 'no_cache_crypto'
|
||||
result['requested_range'] = {'start': start, 'end': end}
|
||||
result['timeframe'] = timeframe
|
||||
return result, False
|
||||
except Exception as e:
|
||||
return {'error': str(e), 'code': code, 'asset_type': asset_type.value}, False
|
||||
@@ -459,12 +462,20 @@ def index():
|
||||
"asset_type": "/api/v1/asset-type?code={code}",
|
||||
"ohlcv": "/api/v1/ohlcv?code={code}&start={YYYY-MM-DD}&end={YYYY-MM-DD}&asset_type={type}",
|
||||
"ohlcv_nocache": "/api/v1/ohlcv?code={code}&nocache=true",
|
||||
"ohlcv_crypto": "/api/v1/ohlcv?code=BTC&timeframe=1d (加密货币必须指定 timeframe)",
|
||||
"ohlcv_asset_type": "/api/v1/ohlcv?code={code}&asset_type=china_index (强制覆盖类型)",
|
||||
"batch": "POST /api/v1/ohlcv/batch",
|
||||
"etf_nav": "/api/v1/etf/nav?code={code}",
|
||||
"cache_clear": "POST /api/v1/cache/clear",
|
||||
"cache_stats": "/api/v1/cache/stats",
|
||||
},
|
||||
"crypto_timeframes": {
|
||||
"1d": "日线",
|
||||
"1h": "小时线",
|
||||
"4h": "4小时线",
|
||||
"15m": "15分钟线",
|
||||
"1m": "分钟线",
|
||||
},
|
||||
"asset_types": {
|
||||
"china_index": "中国指数 (000300.SH, 399006.SZ等)",
|
||||
"china_etf": "中国ETF (159915.SZ, 513100.SH等)",
|
||||
@@ -534,12 +545,19 @@ def get_ohlcv():
|
||||
- futures: 期货
|
||||
- crypto: 加密货币
|
||||
注:指定后会覆盖自动检测,用于修复检测逻辑问题
|
||||
timeframe: K线周期 (optional, 仅加密货币需要)
|
||||
- 1d: 日线(默认)
|
||||
- 1h: 小时线
|
||||
- 4h: 4小时线
|
||||
- 15m: 15分钟线
|
||||
- 1m: 分钟线
|
||||
nocache: 是否跳过缓存 (optional, 默认false)
|
||||
"""
|
||||
code = request.args.get('code', '').strip()
|
||||
start = request.args.get('start', '').strip()
|
||||
end = request.args.get('end', '').strip()
|
||||
asset_type_param = request.args.get('asset_type', '').strip().lower()
|
||||
timeframe = request.args.get('timeframe', '1d').strip().lower()
|
||||
nocache = request.args.get('nocache', 'false').lower() == 'true'
|
||||
|
||||
# 参数验证
|
||||
@@ -577,8 +595,18 @@ def get_ohlcv():
|
||||
"valid_types": [t.value for t in AssetType],
|
||||
}), 400
|
||||
|
||||
# 使用缓存获取数据
|
||||
result, is_cached = fetch_data_with_ttl(code, start, end, nocache)
|
||||
# 加密货币必须指定 timeframe(无论自动检测还是手动指定)
|
||||
if final_type == AssetType.CRYPTO:
|
||||
valid_timeframes = ['1d', '1h', '4h', '15m', '1m', 'daily', 'hourly']
|
||||
if timeframe not in valid_timeframes:
|
||||
return jsonify({
|
||||
"error": f"Invalid timeframe for crypto: {timeframe}",
|
||||
"valid_timeframes": valid_timeframes,
|
||||
"hint": "加密货币必须指定 timeframe 参数",
|
||||
}), 400
|
||||
|
||||
# 使用缓存获取数据(加密货币不缓存)
|
||||
result, is_cached = fetch_data_with_ttl(code, start, end, nocache, timeframe)
|
||||
|
||||
if result is None:
|
||||
return jsonify({
|
||||
|
||||
Reference in New Issue
Block a user