#!/usr/bin/env python3 """多周期缓存刷新脚本 — 在开盘前预填充K线数据 为所有持仓+自选股预先拉取日/周/月K线,写入 multi_tf_cache.json, 这样收盘后全量重评(regenerate_all)运行时K线数据已有缓存,无需逐个拉取。 运行时间:每天9:00(开盘前),no_agent模式。 无输出 = 成功(避免每天收到无意义消息)。 """ import sys import os import json from datetime import datetime # 确保能找到 web-dashboard 模块 sys.path.insert(0, "/home/hmo/web-dashboard") # 控制台UTC日志 def log(msg): ts = datetime.utcnow().strftime("%H:%M:%S") print(f"[{ts}] {msg}", file=sys.stderr) def main(): from strategy_lifecycle import safe_json_load, PORTFOLIO_PATH, WATCHLIST_PATH # 收集所有股票代码 codes = [] for item in safe_json_load(PORTFOLIO_PATH, {}).get("holdings", []): code = item.get("code", "") if code: codes.append(("portfolio", code)) seen = set(c[1] for c in codes) for item in safe_json_load(WATCHLIST_PATH, {}).get("stocks", []): code = item.get("code", "") if code and code not in seen: codes.append(("watchlist", code)) seen.add(code) # 加入指数代码(用于多周期趋势研判) INDEXES = { "sh000001": "上证指数", "sz399001": "深证成指", "sz399006": "创业板指", "sh000688": "科创50", "hkHSI": "恒生指数", "hkHSTECH": "恒生科技", } for idx_code in INDEXES: if idx_code not in seen: codes.append(("index", idx_code)) seen.add(idx_code) log(f"Pre-populating multi-timeframe cache for {len(codes)} stocks...") # 检查当前缓存,只更新需要更新的 mtf_cache_path = "/home/hmo/web-dashboard/data/multi_tf_cache.json" try: with open(mtf_cache_path) as f: existing = json.load(f) except (FileNotFoundError, json.JSONDecodeError): existing = {} import time from multi_timeframe import full_multi_tf_analysis cached = 0 fetched = 0 errors = 0 for source, code in codes: cached_entry = existing.get(code, {}) updated_at = cached_entry.get("updated_at", 0) now = time.time() # 检查缓存是否新鲜:日K 1小时内,周/月K 1天内 has_daily = bool(cached_entry.get("daily")) has_weekly = bool(cached_entry.get("weekly")) has_monthly = bool(cached_entry.get("monthly")) cache_fresh = (updated_at > 0 and (now - updated_at) < 3600) if has_daily and has_weekly and has_monthly and cache_fresh: cached += 1 continue try: r = full_multi_tf_analysis(code) if any(k in r for k in ["daily", "weekly", "monthly"]): fetched += 1 log(f" OK {code} ({source})") else: errors += 1 log(f" EMPTY {code} ({source})") except Exception as e: errors += 1 log(f" FAIL {code} ({source}): {e}") log(f"Done: {cached} cached, {fetched} fetched, {errors} errors") if __name__ == "__main__": main()