from __future__ import annotations import argparse from datetime import datetime from zoneinfo import ZoneInfo from _bootstrap import add_src_to_path add_src_to_path() from lhbfx.config import load_config from lhbfx.mailer import send_email from lhbfx.pdf_export import generate_daily_report_pdf from lhbfx.pipeline import generate_warnings, import_daily, rematch_traders from lhbfx.reporting import build_daily_report, build_email_body, default_report_output_path SHANGHAI_TZ = ZoneInfo("Asia/Shanghai") def parse_args() -> argparse.Namespace: parser = argparse.ArgumentParser(description="Run lhbfx after-market update workflow") parser.add_argument("--trade-date", help="Trade date in YYYY-MM-DD format, defaults to Asia/Shanghai today") parser.add_argument("--send-email", action="store_true", help="Send completion email after report generation") parser.add_argument("--force", action="store_true", help="Run even if the target date is not a weekday") return parser.parse_args() def default_trade_date() -> str: return datetime.now(SHANGHAI_TZ).date().isoformat() def is_weekday(trade_date: str) -> bool: return datetime.fromisoformat(trade_date).weekday() < 5 def build_update_email_body( *, trade_date: str, overview_count: int, detail_count: int, rematch_updated: int, warning_total: int, report_body: str, ) -> str: lines = [ f"lhbfx 收盘后更新完成 - {trade_date}", "", f"龙虎榜概览更新数: {overview_count}", f"席位明细更新数: {detail_count}", f"游资重新匹配数: {rematch_updated}", f"预警总数: {warning_total}", "", ] lines.append(report_body) return "\n".join(lines) def main() -> None: args = parse_args() config = load_config() trade_date = args.trade_date or default_trade_date() if not args.force and not is_weekday(trade_date): print(f"Skip {trade_date}: not a weekday, assumed non-trading day.") return import_result = import_daily(trade_date, config=config) if import_result.overview_count <= 0: print(f"Skip {trade_date}: no overview rows imported, source data may not be ready or market may be closed.") return rematch_result = rematch_traders(config=config) warning_result = generate_warnings(config=config) report = build_daily_report(config=config, trade_date=trade_date) pdf_path = default_report_output_path(trade_date) generate_daily_report_pdf(report, pdf_path) print( "After-market update finished:", { "trade_date": trade_date, "overview_count": import_result.overview_count, "detail_count": import_result.detail_count, "rematch_updated": rematch_result["updated"], "warning_total": warning_result["total"], "pdf_path": str(pdf_path), }, ) if args.send_email: if config.mail is None: raise RuntimeError("Mail config is missing") report_body = build_email_body(report) body_text = build_update_email_body( trade_date=trade_date, overview_count=import_result.overview_count, detail_count=import_result.detail_count, rematch_updated=rematch_result["updated"], warning_total=warning_result["total"], report_body=report_body, ) subject = f"lhbfx 收盘后更新完成 - {trade_date}" send_email( mail_config=config.mail, subject=subject, body_text=body_text, attachments=[pdf_path], ) print(f"Email sent to: {', '.join(config.mail.recipients)}") if __name__ == "__main__": main()