diff --git a/datasource/ccxt_source.py b/datasource/ccxt_source.py index 87b413b..e2344cd 100644 --- a/datasource/ccxt_source.py +++ b/datasource/ccxt_source.py @@ -250,10 +250,14 @@ class CCXTSource: return None df = pd.DataFrame(ohlcv, columns=['timestamp', 'open', 'high', 'low', 'close', 'volume']) + + # 转换时间戳为日期索引(UTC -> 北京时间) + # 注意:保留完整时间精度(包括分钟),用于分钟级 K 线数据 df['date'] = pd.to_datetime(df['timestamp'], unit='ms', utc=True).dt.tz_convert('Asia/Shanghai') df = df.set_index('date') df = df[['open', 'high', 'low', 'close', 'volume']] - df.index = df.index.normalize() + + # 注意:不再使用 normalize(),保留完整时间精度 return df diff --git a/datasource/flask_server.py b/datasource/flask_server.py index 96b948a..f6e936e 100644 --- a/datasource/flask_server.py +++ b/datasource/flask_server.py @@ -266,7 +266,7 @@ def fetch_data_with_ttl( df = f.fetch(code, start, end, timeframe=timeframe) if df is None or len(df) == 0: return None, False - result = dataframe_to_json(df) + result = dataframe_to_json(df, asset_type.value) result['code'] = code result['asset_type'] = asset_type.value result['cache_strategy'] = 'no_cache_crypto' @@ -369,9 +369,15 @@ class JSONEncoder(json.JSONEncoder): return super().default(obj) -def dataframe_to_json(df: pd.DataFrame) -> Dict: +def dataframe_to_json(df: pd.DataFrame, asset_type: Optional[str] = None) -> Dict: """将 DataFrame 转换为 JSON 可序列化的字典 + Args: + df: DataFrame 数据 + asset_type: 资产类型,用于决定日期格式精度 + - crypto: 使用分钟级格式 '%Y-%m-%d %H:%M:%S' + - 其他: 使用天级格式 '%Y-%m-%d' + 如果 df.attrs 中有 info 字段,会放到最外层返回 """ if df is None or len(df) == 0: @@ -384,12 +390,16 @@ def dataframe_to_json(df: pd.DataFrame) -> Dict: # 重置索引 df_reset = df.reset_index() - # 处理日期列 + # 处理日期列 - 根据资产类型决定格式精度 date_columns = ['date', 'Date', 'index', 'trade_date', 'datetime'] + + # 加密货币使用分钟级格式,其他使用天级格式 + date_format = '%Y-%m-%d %H:%M:%S' if asset_type == 'crypto' else '%Y-%m-%d' + for col in date_columns: if col in df_reset.columns: try: - df_reset[col] = pd.to_datetime(df_reset[col]).dt.strftime('%Y-%m-%d') + df_reset[col] = pd.to_datetime(df_reset[col]).dt.strftime(date_format) if col != 'date': df_reset = df_reset.rename(columns={col: 'date'}) break @@ -412,8 +422,8 @@ def dataframe_to_json(df: pd.DataFrame) -> Dict: "count": len(records), "columns": list(df_clean.columns), "date_range": { - "start": df.index.min().strftime('%Y-%m-%d') if len(df) > 0 else None, - "end": df.index.max().strftime('%Y-%m-%d') if len(df) > 0 else None, + "start": df.index.min().strftime(date_format) if len(df) > 0 else None, + "end": df.index.max().strftime(date_format) if len(df) > 0 else None, } }