"""Unified CLI entrypoint for AlphaX Agent jobs.""" import argparse import sys from app.services import altcoin_confirm, altcoin_screener, event_driven_screener, live_trading_smoke, market_overview, onchain_monitor, paper_trader, price_streamer, price_tracker, review_engine, sentiment_monitor def build_parser(): parser = argparse.ArgumentParser(description="AlphaX Agent unified CLI") subparsers = parser.add_subparsers(dest="command", required=True) screener = subparsers.add_parser("screener", help="运行粗筛/细筛") screener.add_argument("--compact", action="store_true", help="输出紧凑 JSON") confirm = subparsers.add_parser("confirm", help="运行确认流程") confirm.add_argument("--compact", action="store_true", help="输出紧凑 JSON") tracker = subparsers.add_parser("tracker", help="运行价格跟踪") paper = subparsers.add_parser("paper-trader", help="运行模拟交易账本同步") paper.add_argument("--limit", type=int, default=100, help="本轮最多处理的可执行推荐数量") subparsers.add_parser("price-streamer", help="运行 websocket 实时价格流") subparsers.add_parser("market", help="采集全市场快照") review = subparsers.add_parser("review", help="运行复盘") review.add_argument("--compact", action="store_true", help="输出紧凑 JSON") review.add_argument("--no-push", action="store_true", help="只运行复盘,不发飞书") event = subparsers.add_parser("event", help="运行事件驱动筛选") event.add_argument("--no-process-existing", action="store_true", help="只处理本轮新采集事件") event.add_argument("--limit", type=int, default=None, help="单轮最多处理事件数") event.add_argument("--max-seconds", type=int, default=None, help="单轮最大运行秒数") sentiment = subparsers.add_parser("sentiment", help="运行舆情任务") sentiment.add_argument("--collect", action="store_true", help="采集并存储") sentiment.add_argument("--check", action="store_true", help="输出舆情异动") sentiment.add_argument("--scores", action="store_true", help="输出评分") onchain = subparsers.add_parser("onchain", help="运行链上追踪任务") onchain.add_argument("--limit", type=int, default=60, help="本轮最多处理的 token 映射数量") llm = subparsers.add_parser("llm-insights", help="异步生成 LLM 缓存解释") llm.add_argument("--scope", choices=["recommendations", "sentiment", "sentiment-events", "review"], default="recommendations") llm.add_argument("--limit", type=int, default=30) live_smoke = subparsers.add_parser("live-trading-smoke", help="运行 Binance 合约接口 smoke test") live_smoke.add_argument("--account-id", type=int, required=True, help="live_trade_accounts.id") live_smoke.add_argument("--symbol", default="BTC/USDT", help="测试交易对") live_smoke.add_argument("--notional-usdt", type=float, default=10.0, help="测试名义金额,默认 10U") live_smoke.add_argument("--leverage", type=float, default=1.0, help="测试杠杆,默认 1x") return parser def main(): parser = build_parser() args = parser.parse_args() if args.command == "screener": return altcoin_screener.main(compact=args.compact) if args.command == "confirm": return altcoin_confirm.main(compact=args.compact) if args.command == "tracker": return price_tracker.main() if args.command == "paper-trader": return paper_trader.main(limit=args.limit) if args.command == "price-streamer": return price_streamer.main() if args.command == "market": result = market_overview.collect_market_snapshot() print(sentiment_monitor.json.dumps(result, ensure_ascii=False, indent=2)) return result if args.command == "review": return review_engine.run_review(push_enabled=not args.no_push, compact=args.compact) if args.command == "event": result = event_driven_screener.run_once( process_existing=not args.no_process_existing, limit=args.limit, max_seconds=args.max_seconds, ) print(event_driven_screener.json.dumps(result, ensure_ascii=False, indent=2, default=str)) return result if args.command == "sentiment": if args.collect: result = sentiment_monitor.collect_and_store() print(sentiment_monitor.json.dumps(result, ensure_ascii=False)) return result if args.scores: result = sentiment_monitor.get_sentiment_scores() print(sentiment_monitor.json.dumps(result, ensure_ascii=False, indent=2)) return result holdings = sentiment_monitor.get_active_holdings() alerts = sentiment_monitor.get_sentiment_alert(holdings=holdings) if args.check: print(sentiment_monitor.json.dumps(alerts, ensure_ascii=False, indent=2)) return alerts result = { "alerts": alerts, "sentiment_scores": sentiment_monitor.get_sentiment_scores(), "holdings_count": len(holdings), "check_time": sentiment_monitor.datetime.now().isoformat(), } print(sentiment_monitor.json.dumps(result, ensure_ascii=False, indent=2)) return result if args.command == "onchain": return onchain_monitor.run_once(limit=args.limit) if args.command == "llm-insights": from app.services import llm_insights result = llm_insights.run(scope=args.scope, limit=args.limit) print(sentiment_monitor.json.dumps(result, ensure_ascii=False, indent=2)) return result if args.command == "live-trading-smoke": return live_trading_smoke.main( account_id=args.account_id, symbol=args.symbol, notional_usdt=args.notional_usdt, leverage=args.leverage, ) parser.error(f"unknown command: {args.command}") if __name__ == "__main__": try: main() except Exception as exc: try: from app.db.system_logs import record_exception command = " ".join(sys.argv[1:]) or "unknown" record_exception(exc, source="cli", context={"argv": sys.argv, "command": command}) except Exception: pass raise