1
This commit is contained in:
parent
c03d5a88e8
commit
23dd333ae4
Binary file not shown.
Binary file not shown.
@ -61,8 +61,8 @@ async def intraday_market_temperature(prev_temp: MarketTemperature) -> MarketTem
|
||||
|
||||
# ── 用东方财富 clist API 统计涨停跌停(比腾讯涨停价字段更可靠) ──
|
||||
try:
|
||||
limit_up_count = 0
|
||||
limit_down_count = 0
|
||||
realtime_limit_up_count = 0
|
||||
realtime_limit_down_count = 0
|
||||
|
||||
for fs, threshold in [
|
||||
("m:0+t:6,m:0+t:80,m:0+t:81+s:2048", 9.9), # 主板 10%
|
||||
@ -84,7 +84,7 @@ async def intraday_market_temperature(prev_temp: MarketTemperature) -> MarketTem
|
||||
if pct == "-" or pct is None:
|
||||
continue
|
||||
if float(pct) >= threshold:
|
||||
limit_up_count += 1
|
||||
realtime_limit_up_count += 1
|
||||
|
||||
# 跌停:按涨幅升序取 top 200
|
||||
params_down = {
|
||||
@ -102,8 +102,10 @@ async def intraday_market_temperature(prev_temp: MarketTemperature) -> MarketTem
|
||||
if pct == "-" or pct is None:
|
||||
continue
|
||||
if float(pct) <= neg_threshold:
|
||||
limit_down_count += 1
|
||||
realtime_limit_down_count += 1
|
||||
|
||||
limit_up_count = realtime_limit_up_count
|
||||
limit_down_count = realtime_limit_down_count
|
||||
logger.info(f"东方财富盘中涨跌停: 涨停={limit_up_count} 跌停={limit_down_count}")
|
||||
except Exception as e:
|
||||
logger.warning(f"东方财富涨跌停统计失败,使用基线数据: {e}")
|
||||
|
||||
@ -26,6 +26,23 @@ def calculate_market_temperature(trade_date: str = None) -> MarketTemperature:
|
||||
# 1. 涨跌家数
|
||||
daily_df = tushare_client.get_daily_all(trade_date)
|
||||
if daily_df.empty:
|
||||
original_trade_date = trade_date
|
||||
trade_dates = tushare_client.get_trade_dates()
|
||||
fallback_dates = [d for d in trade_dates if d < trade_date][-5:]
|
||||
for fallback_date in reversed(fallback_dates):
|
||||
fallback_df = tushare_client.get_daily_all(fallback_date)
|
||||
if not fallback_df.empty:
|
||||
daily_df = fallback_df
|
||||
trade_date = fallback_date
|
||||
logger.warning(
|
||||
"市场温度 %s 日线数据为空,回退到最近有效交易日 %s",
|
||||
original_trade_date,
|
||||
fallback_date,
|
||||
)
|
||||
break
|
||||
|
||||
if daily_df.empty:
|
||||
logger.warning("市场温度 %s 无有效日线数据,返回占位温度", trade_date)
|
||||
return MarketTemperature(trade_date=trade_date, temperature=50)
|
||||
|
||||
up_count = len(daily_df[daily_df["pct_chg"] > 0])
|
||||
|
||||
Binary file not shown.
@ -21,6 +21,12 @@ _scan_lock = asyncio.Lock()
|
||||
_scan_running = False
|
||||
|
||||
|
||||
def _has_valid_market_breadth(market_temp: MarketTemperature | None) -> bool:
|
||||
if not market_temp:
|
||||
return False
|
||||
return (market_temp.up_count or 0) + (market_temp.down_count or 0) > 0
|
||||
|
||||
|
||||
async def refresh_recommendations(trade_date: str = None, scan_session: str = "manual") -> dict:
|
||||
"""刷新推荐列表(带扫描锁防止并发)"""
|
||||
global _scan_running
|
||||
@ -633,23 +639,32 @@ async def _save_to_db(result: dict):
|
||||
# 保存市场温度
|
||||
mt = result.get("market_temp")
|
||||
if mt:
|
||||
# 使用 INSERT OR REPLACE 确保重复扫描能更新数据
|
||||
stmt = text(
|
||||
"INSERT OR REPLACE INTO market_temperature "
|
||||
"(trade_date, up_count, down_count, limit_up_count, limit_down_count, "
|
||||
"max_streak, broken_rate, temperature) "
|
||||
"VALUES (:td, :up, :down, :lu, :ld, :ms, :br, :temp)"
|
||||
)
|
||||
await db.execute(stmt, {
|
||||
"td": mt.trade_date,
|
||||
"up": mt.up_count,
|
||||
"down": mt.down_count,
|
||||
"lu": mt.limit_up_count,
|
||||
"ld": mt.limit_down_count,
|
||||
"ms": mt.max_streak,
|
||||
"br": mt.broken_rate,
|
||||
"temp": mt.temperature,
|
||||
})
|
||||
if _has_valid_market_breadth(mt):
|
||||
# 使用 INSERT OR REPLACE 确保重复扫描能更新数据
|
||||
stmt = text(
|
||||
"INSERT OR REPLACE INTO market_temperature "
|
||||
"(trade_date, up_count, down_count, limit_up_count, limit_down_count, "
|
||||
"max_streak, broken_rate, temperature) "
|
||||
"VALUES (:td, :up, :down, :lu, :ld, :ms, :br, :temp)"
|
||||
)
|
||||
await db.execute(stmt, {
|
||||
"td": mt.trade_date,
|
||||
"up": mt.up_count,
|
||||
"down": mt.down_count,
|
||||
"lu": mt.limit_up_count,
|
||||
"ld": mt.limit_down_count,
|
||||
"ms": mt.max_streak,
|
||||
"br": mt.broken_rate,
|
||||
"temp": mt.temperature,
|
||||
})
|
||||
else:
|
||||
logger.warning(
|
||||
"跳过无效市场温度快照: trade_date=%s temperature=%s up=%s down=%s",
|
||||
mt.trade_date,
|
||||
mt.temperature,
|
||||
mt.up_count,
|
||||
mt.down_count,
|
||||
)
|
||||
|
||||
# 保存板块热度(先清除同一 trade_date 的旧数据,再批量插入)
|
||||
trade_date_val = mt.trade_date if mt else ""
|
||||
@ -769,7 +784,8 @@ async def _load_today_from_db() -> dict:
|
||||
result = await db.execute(
|
||||
text(
|
||||
"SELECT * FROM market_temperature "
|
||||
"ORDER BY REPLACE(trade_date, '-', '') DESC, id DESC LIMIT 1"
|
||||
"ORDER BY CASE WHEN COALESCE(up_count, 0) + COALESCE(down_count, 0) > 0 THEN 0 ELSE 1 END, "
|
||||
"REPLACE(trade_date, '-', '') DESC, id DESC LIMIT 1"
|
||||
)
|
||||
)
|
||||
mt_row = result.fetchone()
|
||||
|
||||
Binary file not shown.
Loading…
Reference in New Issue
Block a user