"""CLI unifiée : python -m finlab.cli .""" from __future__ import annotations import argparse import pandas as pd def main() -> None: pd.set_option("display.max_columns", None, "display.max_colwidth", None, "display.width", 240) parser = argparse.ArgumentParser(prog="finlab", description="Boîte à outils d'analyse de marché") sub = parser.add_subparsers(dest="cmd", required=True) sub.add_parser("portfolio", help="Suivi du portefeuille (valeur, P&L, secteurs)") t = sub.add_parser("tech", help="Analyse technique") t.add_argument("tickers", nargs="*", help="vide = tout le portefeuille") t.add_argument("--period", default="1y") f = sub.add_parser("fundamentals", help="Ratios fondamentaux") f.add_argument("tickers", nargs="*", help="vide = tout le portefeuille") s = sub.add_parser("scan", help="Scanner d'opportunités sur un thème") s.add_argument("theme", nargs="?", default="all", help="thème de watchlists.yaml, 'all' ou 'portfolio'") s.add_argument("--target", type=float, default=5.0, help="cible de perf hebdo en %%") s.add_argument("--bullish", action="store_true", help="ne montrer que les setups haussiers") d = sub.add_parser("digest", help="Digest compact (portefeuille + opportunités + alertes)") d.add_argument("theme", nargs="?", default="all") d.add_argument("--target", type=float, default=5.0) a = sub.add_parser("alerts", help="Alertes déclenchées du jour") a.add_argument("watch", nargs="?", default=None, help="thème, 'all' ou 'portfolio'") p = sub.add_parser("plan", help="Plan de trade chiffré (entrée/stop/objectif/taille)") p.add_argument("tickers", nargs="+") p.add_argument("--capital", type=float, default=1427.0) c = sub.add_parser("cache", help="Gestion du cache disque") c.add_argument("action", choices=["clear", "info"], default="info", nargs="?") args = parser.parse_args() if args.cmd == "portfolio": from . import tracker print(tracker.report()) elif args.cmd == "tech": from . import technical df = technical.scan(args.tickers, args.period) if args.tickers else technical.scan_portfolio(args.period) print(df.to_string(index=False)) elif args.cmd == "fundamentals": from . import fundamental df = fundamental.compare(args.tickers) if args.tickers else fundamental.compare_portfolio() print(df.to_string(index=False)) elif args.cmd == "scan": from . import scanner if args.theme == "portfolio": df = scanner.scan_portfolio(args.target) else: df = scanner.scan_theme(args.theme, args.target, bullish_only=args.bullish) print(df.to_string(index=False)) elif args.cmd == "digest": from . import digest path = digest.write(args.theme, args.target) print(path.read_text(encoding="utf-8")) print(f"\n[écrit dans {path}]") elif args.cmd == "alerts": from . import alerts print(alerts.render(alerts.run(args.watch))) elif args.cmd == "plan": from . import plan for tk in args.tickers: try: print(plan.render(plan.plan(tk, args.capital))) except Exception as e: print(f"{tk}: erreur {e}") print() elif args.cmd == "cache": from . import data if args.action == "clear": n = data.clear_cache() print(f"Cache vidé : {n} fichier(s).") else: files = list(data.CACHE_DIR.glob("*.pkl")) if data.CACHE_DIR.exists() else [] print(f"{len(files)} fichier(s) en cache dans {data.CACHE_DIR}") if __name__ == "__main__": main()