From c6cef8bb4c0f882f6d39f88a68220c08ab06b315 Mon Sep 17 00:00:00 2001 From: Sakurasan <26715255+Sakurasan@users.noreply.github.com> Date: Tue, 7 Jul 2026 17:51:28 +0800 Subject: [PATCH] =?UTF-8?q?update:=20=E6=9D=BF=E5=9D=97=E7=BC=93=E5=AD=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/services/eastmoney.py | 58 ++++++++++++++++++++++++++++++++--- 1 file changed, 54 insertions(+), 4 deletions(-) diff --git a/backend/services/eastmoney.py b/backend/services/eastmoney.py index 9d14ea8..e75aa6e 100644 --- a/backend/services/eastmoney.py +++ b/backend/services/eastmoney.py @@ -6,11 +6,13 @@ import httpx import json import os import re -from datetime import datetime +from datetime import datetime, time as dtime, timedelta, timezone from typing import Optional, List from services.cache import get_cache, set_cache +from services.cache import get_cache, set_cache + # ---- API Key 轮询(MX 备选源用)---- @@ -277,6 +279,35 @@ async def get_em_ut(force_refresh: bool = False) -> str: return _em_ut +# ---- 板块数据(市场时间感知缓存)---- + +_CST = timezone(timedelta(hours=8)) # 北京时间 +_TRADING_MORNING = (dtime(9, 30), dtime(11, 30)) +_TRADING_AFTERNOON = (dtime(13, 0), dtime(15, 0)) + + +def _cst_now() -> datetime: + return datetime.now(_CST) + + +def _is_trading_time() -> bool: + """判断当前是否为 A 股交易时段(周一至周五 9:30-11:30 / 13:00-15:00)""" + now = _cst_now() + if now.weekday() >= 5: + return False + t = now.time() + return (_TRADING_MORNING[0] <= t <= _TRADING_MORNING[1] + or _TRADING_AFTERNOON[0] <= t <= _TRADING_AFTERNOON[1]) + + +def _sector_ttl_hours() -> int: + """根据是否在交易时段返回缓存 TTL + - 交易时段: 2 分钟(数据持续变化) + - 非交易时段: 18 小时(覆盖到下一个交易日) + """ + return 0 if _is_trading_time() else 18 + + # curl_cffi 模拟 Chrome TLS 指纹 from curl_cffi.requests import AsyncSession @@ -299,26 +330,45 @@ def _get_sector_session() -> AsyncSession: return _sector_session -# 内存缓存 +# 内存缓存(加速交易时段频繁请求) _sector_cache: dict[str, tuple[list[dict], float]] = {} -_SECTOR_CACHE_TTL = 60 +_SECTOR_MEM_TTL = 60 async def fetch_sector_list(sector_type: str) -> list[dict]: + # 1. 内存缓存(仅交易时段有效,60s 避免重复请求) now = time.time() if sector_type in _sector_cache: data, ts = _sector_cache[sector_type] - if now - ts < _SECTOR_CACHE_TTL: + if now - ts < _SECTOR_MEM_TTL: return data + cache_key = f"sector_list:{sector_type}" + + # 2. 非交易时段:走磁盘持久缓存,不请求 API + if not _is_trading_time(): + cached = get_cache(cache_key) + if cached is not None: + data = json.loads(cached) + _sector_cache[sector_type] = (data, now) + return data + + # 3. 请求 API data = await _fetch_push2(sector_type) if data: _sector_cache[sector_type] = (data, now) + ttl = _sector_ttl_hours() + # 交易时段 ttl=0 → 不写磁盘(内存缓存已够) + if ttl > 0: + set_cache(cache_key, json.dumps(data, ensure_ascii=False), ttl_hours=ttl) return data data = await _fetch_akshare(sector_type) if data: _sector_cache[sector_type] = (data, now) + ttl = _sector_ttl_hours() + if ttl > 0: + set_cache(cache_key, json.dumps(data, ensure_ascii=False), ttl_hours=ttl) return data