diff --git a/data_provider/efinance_fetcher.py b/data_provider/efinance_fetcher.py index bce958098..70048c0bb 100644 --- a/data_provider/efinance_fetcher.py +++ b/data_provider/efinance_fetcher.py @@ -842,7 +842,7 @@ class EfinanceFetcher(BaseFetcher): price_col = '最新价' if '最新价' in df.columns else 'price' pct_col = '涨跌幅' if '涨跌幅' in df.columns else 'pct_chg' chg_col = '涨跌额' if '涨跌额' in df.columns else 'change' - open_col = '开盘' if '开盘' in df.columns else 'open' + open_cols = [column for column in ('今开', '开盘', 'open') if column in df.columns] high_col = '最高' if '最高' in df.columns else 'high' low_col = '最低' if '最低' in df.columns else 'low' vol_col = '成交量' if '成交量' in df.columns else 'volume' @@ -851,6 +851,14 @@ class EfinanceFetcher(BaseFetcher): current = safe_float(item.get(price_col, 0)) change_amount = safe_float(item.get(chg_col, 0)) + open_price = 0.0 + for column in open_cols: + candidate = safe_float(item.get(column), default=None) + if candidate not in (None, 0.0): + open_price = candidate + break + if open_price == 0.0 and open_cols: + open_price = safe_float(item.get(open_cols[0], 0), 0) results.append({ 'code': full_code, @@ -858,7 +866,7 @@ class EfinanceFetcher(BaseFetcher): 'current': current, 'change': change_amount, 'change_pct': safe_float(item.get(pct_col, 0)), - 'open': safe_float(item.get(open_col, 0)), + 'open': open_price, 'high': safe_float(item.get(high_col, 0)), 'low': safe_float(item.get(low_col, 0)), 'prev_close': current - change_amount if current or change_amount else 0, diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index 7859be377..c3db3ab34 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -13,6 +13,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/). - [修复] 大盘复盘链路接入 `REPORT_LANGUAGE`:`REPORT_LANGUAGE=en` 时,A 股/合并复盘的 Prompt、章节标题、模板兜底文案与通知包装标题统一改为英文,避免出现英文正文外包中文标题的问题。 +- [修复] `EfinanceFetcher.get_main_indices()` 对东方财富指数实时行情的开盘价映射改为兼容 `今开 -> 开盘 -> open`,修复部分 `efinance` 版本下指数开盘价被读成缺失值的问题(fixes #1043) - [修复] `AGENT_MAX_STEPS` 在 orchestrator 多 Agent 模式下统一明确为“默认作为各子 Agent 的步数上限而非硬覆盖;TechnicalAgent 等高默认值 Agent 会被封顶、低默认值 Agent 保持原值;当用户主动调高(>10)时,再统一覆盖所有子 Agent 采用全局值”,同时修复用户设置 12 但 TechnicalAgent 仍以默认 6 步运行并报 "Agent exceeded max steps" 的问题(fixes #1026) - [修复] Specialist(Skill)Agent 失败不再中断整个分析管线,改为与 intel/risk 相同的优雅降级策略 - [改进] Agent 超步数错误信息增加 AGENT_MAX_STEPS 调整提示,帮助用户自助排查 diff --git a/tests/test_efinance_main_indices.py b/tests/test_efinance_main_indices.py new file mode 100644 index 000000000..78a0cfcb8 --- /dev/null +++ b/tests/test_efinance_main_indices.py @@ -0,0 +1,82 @@ +import os +import sys +import types +import unittest +from unittest.mock import patch + +import pandas as pd + +sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), ".."))) + +from data_provider.efinance_fetcher import EfinanceFetcher + + +class TestEfinanceMainIndices(unittest.TestCase): + def test_get_main_indices_prefers_jinkai_column_for_open_price(self): + fetcher = EfinanceFetcher() + fake_df = pd.DataFrame( + { + "股票代码": ["000001"], + "最新价": [3200.0], + "涨跌幅": [0.63], + "涨跌额": [20.0], + "今开": [3188.0], + "开盘": [0.0], + "最高": [3215.0], + "最低": [3170.0], + "成交量": [123456789], + "成交额": [9876543210.0], + "振幅": [1.2], + } + ) + fake_efinance = types.SimpleNamespace( + stock=types.SimpleNamespace(get_realtime_quotes=lambda *args, **kwargs: fake_df) + ) + + with patch.dict(sys.modules, {"efinance": fake_efinance}): + with patch.object(fetcher, "_set_random_user_agent", return_value=None), patch.object( + fetcher, "_enforce_rate_limit", return_value=None + ): + data = fetcher.get_main_indices(region="cn") + + self.assertIsNotNone(data) + self.assertEqual(len(data), 1) + self.assertEqual(data[0]["code"], "sh000001") + self.assertEqual(data[0]["name"], "上证指数") + self.assertAlmostEqual(data[0]["open"], 3188.0) + self.assertAlmostEqual(data[0]["current"], 3200.0) + + def test_get_main_indices_falls_back_to_kaipan_when_jinkai_is_missing(self): + fetcher = EfinanceFetcher() + fake_df = pd.DataFrame( + { + "股票代码": ["000001"], + "最新价": [3200.0], + "涨跌幅": [0.63], + "涨跌额": [20.0], + "今开": [""], + "开盘": [3186.0], + "最高": [3215.0], + "最低": [3170.0], + "成交量": [123456789], + "成交额": [9876543210.0], + "振幅": [1.2], + } + ) + fake_efinance = types.SimpleNamespace( + stock=types.SimpleNamespace(get_realtime_quotes=lambda *args, **kwargs: fake_df) + ) + + with patch.dict(sys.modules, {"efinance": fake_efinance}): + with patch.object(fetcher, "_set_random_user_agent", return_value=None), patch.object( + fetcher, "_enforce_rate_limit", return_value=None + ): + data = fetcher.get_main_indices(region="cn") + + self.assertIsNotNone(data) + self.assertEqual(len(data), 1) + self.assertAlmostEqual(data[0]["open"], 3186.0) + + +if __name__ == "__main__": + unittest.main()