"""Abbau Restbestand: liest Marktuhr, Positionen und offene Orders des Alpaca-Paper-Kontos, nur lesend. Ersteller: Pascal Michel Erstellt: 2026-10-07 Doku: LIESMICH.md in diesem Ordner, Abschnitt "Paket AB" Laeuft in WSL mit dem Venv des Alpaca-Ordners (~/venvs/trading); gestartet von abbau_restbestand.py ueber wsl.exe --exec. Ruft nur marktuhr(), positionen() und offene_orders() von AlpacaBroker (trading/broker/alpaca.py: GET /v2/clock, /v2/positions, /v2/orders?status=open). Nichts davon schreibt beim Broker oder auf der Platte. Ausgabe: genau eine JSON-Zeile auf stdout mit uhr {"offen": bool, "sekunden_bis_schluss": int} oder null uhr_fehler Text oder null positionen [{"symbol": str, "menge": int}] oder null; menge ist negativ bei short orders Zahl der offenen Orders oder null bestand_fehler Text oder null Nie ein Betrag: Von einer Position gehen nur Symbol und Stueckzahl weiter, von den Orders nur die Zahl. Fehlertexte laufen durch ohne_kontonummer() aus abendkontrolle_wsl.py (Kontonummern, dann maskiere()) und danach durch DEZIMAL: jede Dezimalzahl wird [x], ganze Zahlen bleiben. Den Projektordner nennt der Aufrufer (--projekt); hier steht kein echter Pfad. Aufruf: python abbau_alpaca_lesen.py --projekt Exit: 0 mit der JSON-Zeile (auch wenn darin Fehler stehen), 2 Bedienfehler. """ import argparse import json import os import re import sys from datetime import datetime from datetime import timezone from pathlib import Path HIER = Path(__file__).resolve().parent sys.path.insert(0, str(HIER)) from abendkontrolle_wsl import ohne_kontonummer # noqa: E402 GEHEIMNISSE = "/home/claude/.config/trading-plattform/secrets.toml" RISIKO = "config/risk.toml" FEHLERTEXT_MAX = 200 # Jede Dezimalzahl, auch ohne Geldwort davor; maskiere() faengt nur Zahlen hinter Geldwoertern, # vor Waehrungen oder mit vielen Stellen. DEZIMAL = re.compile(r"-?\d+[.,]\d+") def fehlertext(ausnahme: BaseException) -> str: """Typ und Text einer Ausnahme: Kontonummern als [konto], Betraege als [x], gekuerzt.""" text = ohne_kontonummer(f"{type(ausnahme).__name__}: {ausnahme}") return DEZIMAL.sub("[x]", text)[:FEHLERTEXT_MAX] def lies(broker, jetzt: datetime) -> dict: """Marktuhr und Bestand; jede Frage fuer sich, ein Fehler in der einen haelt die andere nicht auf.""" ergebnis = {"uhr": None, "uhr_fehler": None, "positionen": None, "orders": None, "bestand_fehler": None} try: uhr = broker.marktuhr() ergebnis["uhr"] = { "offen": bool(uhr.is_open), "sekunden_bis_schluss": int((uhr.next_close - jetzt).total_seconds()), } except Exception as ausnahme: ergebnis["uhr_fehler"] = fehlertext(ausnahme) try: positionen = broker.positionen() orders = broker.offene_orders() ergebnis["positionen"] = [ {"symbol": position.symbol, "menge": int(position.menge)} for position in positionen ] ergebnis["orders"] = len(orders) except Exception as ausnahme: ergebnis["positionen"] = None ergebnis["orders"] = None ergebnis["bestand_fehler"] = fehlertext(ausnahme) return ergebnis def main(argv=None) -> int: zerleger = argparse.ArgumentParser(description=__doc__.splitlines()[0], allow_abbrev=False) zerleger.add_argument("--projekt", required=True, help="Ordner der Alpaca-Instanz in WSL") argumente = zerleger.parse_args(argv) os.environ.setdefault("TRADING_GEHEIMNISSE", GEHEIMNISSE) try: os.chdir(argumente.projekt) sys.path.insert(0, str(Path(argumente.projekt).resolve())) from trading.broker.alpaca import AlpacaBroker from trading.risk.limits import lade_limits broker = AlpacaBroker.from_secrets(None, universum=lade_limits(RISIKO).universum) except Exception as ausnahme: grund = fehlertext(ausnahme) print(json.dumps( {"uhr": None, "uhr_fehler": grund, "positionen": None, "orders": None, "bestand_fehler": grund}, ensure_ascii=False, )) return 0 print(json.dumps(lies(broker, datetime.now(timezone.utc)), ensure_ascii=False)) return 0 if __name__ == "__main__": sys.exit(main())