fix(HEL-356): preserve derived limit streaks
Co-authored-by: multica-agent <github@multica.ai>
This commit is contained in:
@@ -169,7 +169,16 @@ class DailyMarketMixin:
|
|||||||
current = item.get(key)
|
current = item.get(key)
|
||||||
if incoming in (None, "", "--"):
|
if incoming in (None, "", "--"):
|
||||||
continue
|
continue
|
||||||
if current in (None, "", "--", 0, 0.0):
|
# The daily fallback and the board pool can arrive at different
|
||||||
|
# times. Keep the stronger streak instead of freezing the
|
||||||
|
# provisional default at one or letting a stale pool lower it.
|
||||||
|
if key == "limit_times":
|
||||||
|
item[key] = max(
|
||||||
|
1,
|
||||||
|
int(_number(current, 1)),
|
||||||
|
int(_number(incoming, 1)),
|
||||||
|
)
|
||||||
|
elif current in (None, "", "--", 0, 0.0):
|
||||||
item[key] = incoming
|
item[key] = incoming
|
||||||
merged.append(item)
|
merged.append(item)
|
||||||
return merged
|
return merged
|
||||||
|
|||||||
@@ -55,16 +55,24 @@ class DashboardMixin:
|
|||||||
if not limit_rows:
|
if not limit_rows:
|
||||||
limit_data_source = "derived"
|
limit_data_source = "derived"
|
||||||
notices.append("涨跌停高级接口当日数据尚未更新,已使用日线数据推算。")
|
notices.append("涨跌停高级接口当日数据尚未更新,已使用日线数据推算。")
|
||||||
limit_rows = self._derive_limits(trade_date, daily)
|
limit_rows = self._derive_limits(
|
||||||
|
trade_date,
|
||||||
|
daily,
|
||||||
|
previous_limit_rows=previous_limit_rows,
|
||||||
|
)
|
||||||
except TushareError as exc:
|
except TushareError as exc:
|
||||||
limit_data_source = "derived"
|
limit_data_source = "derived"
|
||||||
notices.append(f"涨跌停高级接口不可用,已使用日线数据推算:{exc}")
|
notices.append(f"涨跌停高级接口不可用,已使用日线数据推算:{exc}")
|
||||||
limit_rows = self._derive_limits(trade_date, daily)
|
|
||||||
previous_daily = self._load_daily(previous_trade_date)
|
previous_daily = self._load_daily(previous_trade_date)
|
||||||
previous_limit_rows = [
|
previous_limit_rows = [
|
||||||
row for row in self._derive_limits(previous_trade_date, previous_daily)
|
row for row in self._derive_limits(previous_trade_date, previous_daily)
|
||||||
if row.get("limit_type") == "U"
|
if row.get("limit_type") == "U"
|
||||||
]
|
]
|
||||||
|
limit_rows = self._derive_limits(
|
||||||
|
trade_date,
|
||||||
|
daily,
|
||||||
|
previous_limit_rows=previous_limit_rows,
|
||||||
|
)
|
||||||
|
|
||||||
up_rows = [row for row in limit_rows if row.get("limit_type") == "U"]
|
up_rows = [row for row in limit_rows if row.get("limit_type") == "U"]
|
||||||
down_rows = [row for row in limit_rows if row.get("limit_type") == "D"]
|
down_rows = [row for row in limit_rows if row.get("limit_type") == "D"]
|
||||||
|
|||||||
@@ -498,8 +498,8 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"path": "backend/data/providers/tushare_dashboard.py",
|
"path": "backend/data/providers/tushare_dashboard.py",
|
||||||
"bytes": 34777,
|
"bytes": 35001,
|
||||||
"lines": 797
|
"lines": 805
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"path": "database.py",
|
"path": "database.py",
|
||||||
@@ -601,6 +601,11 @@
|
|||||||
"bytes": 9876,
|
"bytes": 9876,
|
||||||
"lines": 224
|
"lines": 224
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"path": "backend/data/providers/tushare_daily.py",
|
||||||
|
"bytes": 9539,
|
||||||
|
"lines": 241
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"path": "backend/features/market/insights_themes.py",
|
"path": "backend/features/market/insights_themes.py",
|
||||||
"bytes": 9348,
|
"bytes": 9348,
|
||||||
@@ -611,11 +616,6 @@
|
|||||||
"bytes": 9139,
|
"bytes": 9139,
|
||||||
"lines": 199
|
"lines": 199
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"path": "backend/data/providers/tushare_daily.py",
|
|
||||||
"bytes": 9076,
|
|
||||||
"lines": 232
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"path": "backend/data/providers/tushare_dragon_tiger.py",
|
"path": "backend/data/providers/tushare_dragon_tiger.py",
|
||||||
"bytes": 9059,
|
"bytes": 9059,
|
||||||
|
|||||||
@@ -80,6 +80,50 @@ class LimitOverlayTests(unittest.TestCase):
|
|||||||
self.assertEqual(rows[0]["fd_amount"], 82000000)
|
self.assertEqual(rows[0]["fd_amount"], 82000000)
|
||||||
self.assertEqual(rows[0]["turnover_ratio"], 18.4)
|
self.assertEqual(rows[0]["turnover_ratio"], 18.4)
|
||||||
|
|
||||||
|
def test_overlay_replaces_provisional_first_board_with_observed_streak(self) -> None:
|
||||||
|
mixin = DailyMarketMixin()
|
||||||
|
mixin._load_limit_lists = lambda trade_date: []
|
||||||
|
mixin.try_limit_pool = lambda trade_date: [
|
||||||
|
{"ts_code": "000737.SZ", "limit_times": 3}
|
||||||
|
]
|
||||||
|
|
||||||
|
rows = mixin._overlay_board_fields(
|
||||||
|
[{"ts_code": "000737.SZ", "limit_times": 1, "limit_type": "U"}],
|
||||||
|
"20260909",
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertEqual(rows[0]["limit_times"], 3)
|
||||||
|
|
||||||
|
def test_daily_fallback_extends_yesterday_streak(self) -> None:
|
||||||
|
mixin = DailyMarketMixin()
|
||||||
|
mixin.query = lambda *args, **kwargs: []
|
||||||
|
mixin._load_limit_lists = lambda trade_date: []
|
||||||
|
|
||||||
|
rows = mixin._derive_limits(
|
||||||
|
"20260909",
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"ts_code": "000737.SZ",
|
||||||
|
"trade_date": "20260909",
|
||||||
|
"close": 11.0,
|
||||||
|
"high": 11.0,
|
||||||
|
"pct_chg": 10.0,
|
||||||
|
"amount": 100000,
|
||||||
|
}
|
||||||
|
],
|
||||||
|
price_limits=[
|
||||||
|
{"ts_code": "000737.SZ", "up_limit": 11.0, "down_limit": 9.0}
|
||||||
|
],
|
||||||
|
basic_rows=[
|
||||||
|
{"ts_code": "000737.SZ", "name": "北方铜业", "industry": "有色"}
|
||||||
|
],
|
||||||
|
previous_limit_rows=[
|
||||||
|
{"ts_code": "000737.SZ", "limit_times": 2}
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertEqual(rows[0]["limit_times"], 3)
|
||||||
|
|
||||||
|
|
||||||
class ShenwanRealtimeSourceTests(unittest.TestCase):
|
class ShenwanRealtimeSourceTests(unittest.TestCase):
|
||||||
def test_transport_refuses_rt_sw_k(self) -> None:
|
def test_transport_refuses_rt_sw_k(self) -> None:
|
||||||
|
|||||||
Reference in New Issue
Block a user