Skip to content

Commit efd2bce

Browse files
authored
fix: handle efinance index open column fallback (#1051)
* fix: handle efinance index open column fallback
1 parent 0e8728f commit efd2bce

3 files changed

Lines changed: 93 additions & 2 deletions

File tree

data_provider/efinance_fetcher.py

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -842,7 +842,7 @@ def get_main_indices(self, region: str = "cn") -> Optional[List[Dict[str, Any]]]
842842
price_col = '最新价' if '最新价' in df.columns else 'price'
843843
pct_col = '涨跌幅' if '涨跌幅' in df.columns else 'pct_chg'
844844
chg_col = '涨跌额' if '涨跌额' in df.columns else 'change'
845-
open_col = '开盘' if '开盘' in df.columns else 'open'
845+
open_cols = [column for column in ('今开', '开盘', 'open') if column in df.columns]
846846
high_col = '最高' if '最高' in df.columns else 'high'
847847
low_col = '最低' if '最低' in df.columns else 'low'
848848
vol_col = '成交量' if '成交量' in df.columns else 'volume'
@@ -851,14 +851,22 @@ def get_main_indices(self, region: str = "cn") -> Optional[List[Dict[str, Any]]]
851851

852852
current = safe_float(item.get(price_col, 0))
853853
change_amount = safe_float(item.get(chg_col, 0))
854+
open_price = 0.0
855+
for column in open_cols:
856+
candidate = safe_float(item.get(column), default=None)
857+
if candidate not in (None, 0.0):
858+
open_price = candidate
859+
break
860+
if open_price == 0.0 and open_cols:
861+
open_price = safe_float(item.get(open_cols[0], 0), 0)
854862

855863
results.append({
856864
'code': full_code,
857865
'name': name,
858866
'current': current,
859867
'change': change_amount,
860868
'change_pct': safe_float(item.get(pct_col, 0)),
861-
'open': safe_float(item.get(open_col, 0)),
869+
'open': open_price,
862870
'high': safe_float(item.get(high_col, 0)),
863871
'low': safe_float(item.get(low_col, 0)),
864872
'prev_close': current - change_amount if current or change_amount else 0,

docs/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/).
1313
<!-- 每条独立一行追加到本段末尾,无需分类标题,合并时冲突最小 -->
1414

1515
- [修复] 大盘复盘链路接入 `REPORT_LANGUAGE``REPORT_LANGUAGE=en` 时,A 股/合并复盘的 Prompt、章节标题、模板兜底文案与通知包装标题统一改为英文,避免出现英文正文外包中文标题的问题。
16+
- [修复] `EfinanceFetcher.get_main_indices()` 对东方财富指数实时行情的开盘价映射改为兼容 `今开 -> 开盘 -> open`,修复部分 `efinance` 版本下指数开盘价被读成缺失值的问题(fixes #1043
1617
- [修复] `AGENT_MAX_STEPS` 在 orchestrator 多 Agent 模式下统一明确为“默认作为各子 Agent 的步数上限而非硬覆盖;TechnicalAgent 等高默认值 Agent 会被封顶、低默认值 Agent 保持原值;当用户主动调高(>10)时,再统一覆盖所有子 Agent 采用全局值”,同时修复用户设置 12 但 TechnicalAgent 仍以默认 6 步运行并报 "Agent exceeded max steps" 的问题(fixes #1026
1718
- [修复] Specialist(Skill)Agent 失败不再中断整个分析管线,改为与 intel/risk 相同的优雅降级策略
1819
- [改进] Agent 超步数错误信息增加 AGENT_MAX_STEPS 调整提示,帮助用户自助排查
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
import os
2+
import sys
3+
import types
4+
import unittest
5+
from unittest.mock import patch
6+
7+
import pandas as pd
8+
9+
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), "..")))
10+
11+
from data_provider.efinance_fetcher import EfinanceFetcher
12+
13+
14+
class TestEfinanceMainIndices(unittest.TestCase):
15+
def test_get_main_indices_prefers_jinkai_column_for_open_price(self):
16+
fetcher = EfinanceFetcher()
17+
fake_df = pd.DataFrame(
18+
{
19+
"股票代码": ["000001"],
20+
"最新价": [3200.0],
21+
"涨跌幅": [0.63],
22+
"涨跌额": [20.0],
23+
"今开": [3188.0],
24+
"开盘": [0.0],
25+
"最高": [3215.0],
26+
"最低": [3170.0],
27+
"成交量": [123456789],
28+
"成交额": [9876543210.0],
29+
"振幅": [1.2],
30+
}
31+
)
32+
fake_efinance = types.SimpleNamespace(
33+
stock=types.SimpleNamespace(get_realtime_quotes=lambda *args, **kwargs: fake_df)
34+
)
35+
36+
with patch.dict(sys.modules, {"efinance": fake_efinance}):
37+
with patch.object(fetcher, "_set_random_user_agent", return_value=None), patch.object(
38+
fetcher, "_enforce_rate_limit", return_value=None
39+
):
40+
data = fetcher.get_main_indices(region="cn")
41+
42+
self.assertIsNotNone(data)
43+
self.assertEqual(len(data), 1)
44+
self.assertEqual(data[0]["code"], "sh000001")
45+
self.assertEqual(data[0]["name"], "上证指数")
46+
self.assertAlmostEqual(data[0]["open"], 3188.0)
47+
self.assertAlmostEqual(data[0]["current"], 3200.0)
48+
49+
def test_get_main_indices_falls_back_to_kaipan_when_jinkai_is_missing(self):
50+
fetcher = EfinanceFetcher()
51+
fake_df = pd.DataFrame(
52+
{
53+
"股票代码": ["000001"],
54+
"最新价": [3200.0],
55+
"涨跌幅": [0.63],
56+
"涨跌额": [20.0],
57+
"今开": [""],
58+
"开盘": [3186.0],
59+
"最高": [3215.0],
60+
"最低": [3170.0],
61+
"成交量": [123456789],
62+
"成交额": [9876543210.0],
63+
"振幅": [1.2],
64+
}
65+
)
66+
fake_efinance = types.SimpleNamespace(
67+
stock=types.SimpleNamespace(get_realtime_quotes=lambda *args, **kwargs: fake_df)
68+
)
69+
70+
with patch.dict(sys.modules, {"efinance": fake_efinance}):
71+
with patch.object(fetcher, "_set_random_user_agent", return_value=None), patch.object(
72+
fetcher, "_enforce_rate_limit", return_value=None
73+
):
74+
data = fetcher.get_main_indices(region="cn")
75+
76+
self.assertIsNotNone(data)
77+
self.assertEqual(len(data), 1)
78+
self.assertAlmostEqual(data[0]["open"], 3186.0)
79+
80+
81+
if __name__ == "__main__":
82+
unittest.main()

0 commit comments

Comments
 (0)