- .vault-tools/trading-plattform-pruefung/LIESMICH.md - .vault-tools/trading-plattform-pruefung/abbau_alpaca_lesen.py - .vault-tools/trading-plattform-pruefung/abbau_glattstellen.sh - .vault-tools/trading-plattform-pruefung/abbau_ibkr_lesen.sh - .vault-tools/trading-plattform-pruefung/abbau_restbestand.py - .vault-tools/trading-plattform-pruefung/abbau_restbestand_angriffe.py - .vault-tools/trading-plattform-pruefung/abbau_restbestand_einrichten.ps1 - AI/Regelwerk/windows-shell.md Erzeugt vom PostToolUse-Hook .vault-tools/auto-push/auto_push.py. Co-Authored-By: Claude Opus 5 <[email protected]>
102 lines
4.2 KiB
Python
102 lines
4.2 KiB
Python
"""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 <alpaca-ordner>
|
|
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())
|