Stand: AP26.
Der regulaere Betrieb nutzt nur noch die modularen CLIs und das kanonische
Schema aus init.sql. Legacy-CLIs sind kein Operator-Standardpfad mehr.
Dieses Kapitel ist der kuerzeste Einstieg fuer den regulaeren Betrieb.
Merkkarte:
Status = jetztPerformance = VerlaufMonthly = offizieller Rebalance-Stand
Die operative Pipeline ist:
neue Marktdaten holen
-> taeglichen Strategie-Stand berechnen
-> monatlich neue Zielportfolios und Trade-Plan erzeugen
-> Ist-Zustand gegen Shadow/Model pruefen
-> Kaeufe/Verkaeufe manuell buchen
-> Real Portfolio gegen Shadow und Benchmark vergleichen
Die drei Portfolio-Sichten sind:
Model: das reine Strategie-Ergebnis fuer den Stichtag.Shadow: das tradierbare Zielportfolio nach Halte- und Trade-Regeln.Real: das tatsaechlich manuell gebuchte Portfolio.
Fuer den Alltag sind diese Befehle die wichtigsten:
python -m cli.daily_runHolt neue Daten und berechnet den aktuellen Strategie-Stand fuer den Tag.python -m cli.monthly_run --persistFriert zum Monatslauf Model, Shadow, Rebalance, Decisions und Trade-Plan ein.python -m cli.live_status --all --limit 10Zeigt, wo Real gegen Shadow/Model abweicht.python -m cli.live_performance --curve-limit 5Zeigt Real vs. Shadow vs. Benchmark ueber die Zeit.python -m cli.live_cash --type deposit|withdrawal ...Bucht Ein- oder Auszahlungen.python -m cli.live_trade ...Bucht einen manuellen Kauf oder Verkauf.
Wenn nur ein schneller Tagesablauf noetig ist, ist die Reihenfolge meist:
python -m cli.daily_runpython -m cli.live_status --limit 10- Falls Monatsanfang oder Rebalance-Tag:
python -m cli.monthly_run --persist - Danach geplante Trades mit
python -m cli.live_trade ...buchen - Zum Schluss
python -m cli.live_performance --curve-limit 5
daily_run ist der Tageslauf:
- aktualisiert Rohdaten ueber den modularen Sync
- berechnet Indikatoren neu
- laesst die Strategie gegen den neuesten Handelstag laufen
- zeigt das aktuelle Model Portfolio
- ist der passende manuelle Befehl, wenn man denselben Ablauf wie den Daily-Cron starten will
monthly_run ist der Monatslauf:
- nutzt den neuesten verfuegbaren Handelstag oder
--as-of-date - erzeugt das Model Portfolio fuer den Monatsstichtag
- erzeugt das tradierbare Shadow Portfolio
- erzeugt Rebalance- und Decision-Artefakte
- erzeugt den Trade-Plan fuer manuelle Ausfuehrung
- schreibt diese Artefakte nur mit
--persistdauerhaft in die Datenbank
Merksatz:
daily_runbeantwortet: "Wie sieht die Strategie heute aus?"monthly_run --persistbeantwortet: "Was ist mein offizieller Monatsstand und was soll ich handeln?"
Regulaerer Tagesbefehl:
docker compose run --rm app python -m cli.daily_runNur pruefen, was synchronisiert wuerde:
docker compose run --rm app python -m cli.daily_run --dry-run-sync --model-limit 5
docker compose run --rm app python -m cli.sync_data --dry-runDie letzten echten Sync-Laeufe inklusive Audit-Status, Zaehlern und Fehlern anzeigen:
docker compose run --rm app python -m cli.data_status --detailsGezielt nur Preise oder Fundamentals pruefen:
docker compose run --rm app python -m cli.sync_prices --dry-run --plan-limit 5
docker compose run --rm app python -m cli.sync_fundamentals --dry-run --plan-limit 5Kurzstatus der Portfolios:
docker compose run --rm app python -m cli.live_status --limit 10Voller Status inklusive ausgerichteter Zeilen:
docker compose run --rm app python -m cli.live_status --all --limit 10Portfolio gegen Markt vergleichen:
docker compose run --rm app python -m cli.live_performance --curve-limit 5Wenn nur ein kompakter Systemcheck noetig ist:
docker compose run --rm app python -m cli.operator_smoke --ranking-limit 5 --trade-limit 5Nur ansehen, noch nichts schreiben:
docker compose run --rm app python -m cli.monthly_run --model-limit 7Offiziellen Monatsstand mit Trade-Plan schreiben:
docker compose run --rm app python -m cli.monthly_run --persist --model-limit 7Cash einzahlen:
docker compose run --rm app python -m cli.live_cash --type deposit --amount 1000 --as-of-date 2026-05-22Cash-Abgang als Test:
docker compose run --rm app python -m cli.live_cash --type withdrawal --amount 250 --as-of-date 2026-05-22 --dry-runKauf oder Verkauf manuell buchen:
docker compose run --rm app python -m cli.live_trade --helpDer normale Weg ist:
monthly_run --persisterzeugt den Trade-Planlive_statuszeigt die Luecken zwischen Shadow und Reallive_tradebucht die manuelle Umsetzunglive_performancezeigt danach den Vergleich gegen Shadow und Benchmark
cli.live_status ist der schnellste Befehl fuer den operativen Ist-Zustand.
Er zeigt:
- wie viele Positionen in
Model,ShadowundRealliegen - wie viel Cash im Real Portfolio vorhanden ist
- investierten und gesamten Portfoliowert
- welche Titel im Real Portfolio fehlen, zusaetzlich vorhanden sind oder vom Shadow abweichen
Praktische Kurzform:
docker compose run --rm app python -m cli.live_status --limit 10Wenn nur die Problemstellen wichtig sind, reicht diese Kurzform meist aus.
Frische Datenbank mit kanonischem Schema:
./setup.sh init --start-capital 10000 --load-fixturesetup.sh init loescht das Docker-DB-Volume und initialisiert MySQL neu. Das
ist der regulaere Weg, wenn sich MYSQL_ROOT_PASSWORD in .env geaendert hat
und das neue Passwort auch in der laufenden Datenbank aktiv werden soll.
Ohne Fixture werden nur Schema, Default-Strategie und Cash angelegt:
./setup.sh init --start-capital 10000Live-/Operational-State zuruecksetzen, Rohdaten behalten:
./setup.sh rebuild --start-capital 10000setup.sh rebuild setzt kein MySQL-Root-Passwort zurueck und baut die
Datenbank nicht neu auf.
Automatisierter Entwicklungscheck:
scripts/dev_check.shDer schnelle Default laeuft im Docker-App-Container und prueft compileall
sowie die schnelle Pytest-Suite ohne DB-Integration. Die DB-Integrationstests
laufen gegen den isolierten Compose-Service db_test:
scripts/db_integration_tests.shDer Runner verwendet standardmaessig quant4free_test auf db_test, laedt
Fixture und Schema pro Testsession neu und loescht nur diese Testdatenbank.
Die normale Entwicklungsdatenbank db wird nicht beruehrt.
Der isolierte End-to-End-Smoke nutzt ebenfalls eine eigene Testdatenbank:
scripts/dev_check.sh --smokeEchte Smoke-Trade-Buchungen nur in der isolierten Testdatenbank:
scripts/dev_check.sh --smoke --execute-smoke-tradesdocker compose run --rm app python -m cli.data_status --details
docker compose run --rm app python -m cli.operator_smoke --ranking-limit 5 --trade-limit 5
docker compose run --rm app python -m cli.live_status --all --limit 10
docker compose run --rm app python -m cli.live_performance --curve-limit 5cli.operator_smoke prueft DB-Ping, kanonische Rohdatentabellen, Universum,
Benchmark, AP20-Capability-/Provider-Bindings, Strategie-Ranking und
Benchmark-Backtest.
Mit der AP15-Fixture und den Default-Parametern aus der README sind im Live-Status als Fixture-Beispiel diese fehlenden Real-Positionen bzw. Kaufkandidaten zu erwarten:
APA
CB
CF
INCY
NEM
TRV
Diese Liste ist nur ein reproduzierbares Testsignal fuer die Fixture. Sie ist keine aktuelle Anlageempfehlung und kann sich mit anderer Fixture, anderem Stichtag oder anderen Strategieparametern aendern.
Frischer Client-Smoke gegen eine isolierte Testdatenbank:
scripts/client_smoke.sh --db-name ap15_client_smoke --mysql-root-password mypasswordDer Smoke legt nur die angegebene Testdatenbank neu an, laedt
fixtures/raw_market_data.sql, wendet init.sql an, setzt Startkapital und
Strategieparameter, laeuft cli.operator_smoke, persistiert
cli.monthly_run --persist, prueft cli.live_status, validiert Cash- und
Trade-Dry-Runs und bucht standardmaessig die erzeugten BUYs in dieser
isolierten Testdatenbank.
Ohne echte Trade-Buchungen:
scripts/client_smoke.sh --db-name ap15_client_smoke --skip-trade-executionAP16 stellt den operativen Performance-Report als read-only CLI bereit:
docker compose run --rm app python -m cli.live_performance --curve-limit 10Der Report vergleicht Real Portfolio, Shadow Portfolio und Benchmark. Der
Benchmark wird ueber --benchmark gewaehlt und ist standardmaessig spy. Wenn
kein Zeitraum angegeben wird, endet der Report am letzten verfuegbaren
Benchmark-Preis und startet 365 Tage davor:
docker compose run --rm app python -m cli.live_performance --benchmark spy --start-date 2026-01-02 --end-date 2026-05-22Real wird aus live_positions, live_cash_balances und historischen
asset_price_bars bewertet. Shadow wird als target-weight Portfolio aus den
persistierten portfolio_target_items mit snapshot_type='shadow'
fortgeschrieben. Der Benchmark wird auf denselben Startwert normalisiert. Die
Option --base-value setzt optional die gemeinsame Normierungsbasis aller
Wertreihen. Die CLI gibt Rendite, Benchmark-Rendite, Outperformance,
Max Drawdown, Diagnosezaehler und den Tail der Wertreihe aus.
Wer die langen Docker-Befehle nicht jedes Mal tippen will, kann sich lokal diese Shell-Shortcuts setzen:
alias qrun='docker compose run --rm app python -m'
alias qdaily='docker compose run --rm app python -m cli.daily_run'
alias qmonth='docker compose run --rm app python -m cli.monthly_run'
alias qstatus='docker compose run --rm app python -m cli.live_status --limit 10'
alias qperf='docker compose run --rm app python -m cli.live_performance --curve-limit 5'Dann werden die wichtigsten Alltagsbefehle kurz:
qdaily
qstatus
qmonth --persist --model-limit 7
qperf
qrun cli.live_cash --type deposit --amount 1000 --as-of-date 2026-05-22- Vor manuellen Trades immer zuerst
cli.monthly_run --persistund danachcli.live_statuslaufen lassen. cli.live_trademoeglichst mit Werten auslive_trade_plan_itemsfuettern statt freie Zahlen zu raten.- Nach Cash-Buchungen oder Trades den Ist-Zustand direkt mit
cli.live_status --limit 10pruefen. - Fuer den Marktvergleich
cli.live_performanceals Abschlussbefehl verwenden. - Fuer den regulaeren Betrieb dieselben Befehle wie im Cronpfad nutzen, damit manueller Lauf und Scheduler nicht auseinanderlaufen.
Der regulaere Cronpfad nutzt ausschliesslich die modularen CLIs. Legacy-CLIs werden nicht als Cron-Fallback dokumentiert.
Log- und Lock-Verzeichnisse anlegen:
mkdir -p var/log var/lockDaily-Run manuell mit Lock und Log testen:
flock -n var/lock/daily_run.lock scripts/cron_daily.sh >> var/log/daily_run.log 2>&1Monthly-Run manuell mit Lock und Log testen:
flock -n var/lock/monthly_run.lock scripts/cron_monthly.sh >> var/log/monthly_run.log 2>&1Parallelausfuehrung pruefen:
flock -n var/lock/daily_run.lock sleep 60 &
flock -n var/lock/daily_run.lock scripts/cron_daily.sh >> var/log/daily_run.log 2>&1Der zweite Befehl muss sofort abbrechen, solange der erste Lock haelt.
Beispiel fuer crontab -e auf dem Host:
# Werktags nach US-Marktschluss, lokale Host-Zeitzone.
15 23 * * 1-5 cd /home/piccard/tmp/quant4free && mkdir -p var/log var/lock && flock -n var/lock/daily_run.lock scripts/cron_daily.sh >> var/log/daily_run.log 2>&1
# Monatlicher persistierter Rebalance-Lauf am zweiten Kalendertag.
30 8 2 * * cd /home/piccard/tmp/quant4free && mkdir -p var/log var/lock && flock -n var/lock/monthly_run.lock scripts/cron_monthly.sh >> var/log/monthly_run.log 2>&1Die Skripte schreiben Start, Ende und Fehlerzeile in stdout/stderr; die Crontab leitet beides in feste Logdateien um. Logs pruefen:
tail -n 100 var/log/daily_run.log
tail -n 100 var/log/monthly_run.logDry-Run ohne externe API-Calls:
docker compose run --rm app python -m cli.daily_run --dry-run-sync --model-limit 5Regulaerer Daily-Run:
docker compose run --rm app python -m cli.daily_runGezielte Sync-Pruefung:
docker compose run --rm app python -m cli.sync_prices --dry-run --plan-limit 5
docker compose run --rm app python -m cli.sync_fundamentals --dry-run --plan-limit 5
docker compose run --rm app python -m cli.sync_data --dry-runEchte Syncs schreiben seit AP24 Audit-Zeilen in data_sync_runs. Dry-Runs
bleiben read-only und erscheinen deshalb nicht als Sync-Run.
Seit AP25 kann der Audit-Trail gezielt gefiltert und diagnostiziert werden:
docker compose run --rm app python -m cli.data_status --details --sync-status failed --since-days 7
docker compose run --rm app python -m cli.data_status --details --sync-type prices --provider yfinance --sync-limit 20Seit AP26 zeigt derselbe Befehl zusaetzlich data_quality.*-Zeilen. Diese
unterscheiden:
- fehlende Rohdaten (
missing) - veraltete Rohdaten (
stale) - fehlende Provider-Identifier fuer den gewaehlten Provider
- fehlgeschlagene oder stale gestartete Provider-Syncs
Die Defaults sind bewusst konservativ: Preisreihen gelten nach 5 Tagen als stale, TTM-Fundamentals nach 550 Tagen und Market Caps nach 10 Tagen.
docker compose run --rm app python -m cli.data_status --details --universe sp500_active --benchmark-ticker SPY
docker compose run --rm app python -m cli.data_status --details --provider yfinance --identifier-provider yfinance --diagnostic-limit 20Die Yahoo/yfinance-Syncs sind konservativ haertbar. Fuer freie inoffizielle
Provider sollten echte Init-Laeufe kleine Batches, Pausen und Retry/Backoff
nutzen; Retention fuer data_sync_runs bleibt bewusst manuell, damit Audit-
Historie nicht automatisch verloren geht.
docker compose run --rm app python -m cli.sync_prices --mode init --batch-size 10 --throttle-seconds 2 --max-retries 3 --backoff-seconds 2 --circuit-breaker-failures 4
docker compose run --rm app python -m cli.sync_fundamentals --batch-size 5 --throttle-seconds 2 --max-retries 3 --backoff-seconds 2 --circuit-breaker-failures 4Read-only Monthly-Run:
docker compose run --rm app python -m cli.monthly_run --model-limit 7Persistierter Monthly-Run fuer Model, Shadow, Rebalance, Decision Items und Trade Plan:
docker compose run --rm app python -m cli.monthly_run --persist --model-limit 7Expliziter Stichtag:
docker compose run --rm app python -m cli.monthly_run --as-of-date 2026-05-22 --persistPersistenz bricht kontrolliert ab, wenn fuer den Stichtag bereits eingefrorene Artefakte existieren.
docker compose run --rm app python -m cli.live_cash --type deposit --amount 1000 --as-of-date 2026-05-22
docker compose run --rm app python -m cli.live_cash --type withdrawal --amount 250 --as-of-date 2026-05-22 --dry-runCash wird in live_cash_ledger gebucht und in live_cash_balances
fortgeschrieben.
BUY dry-run:
Der folgende Bash-Block liest automatisch die erste ausfuehrbare BUY-Zeile aus
live_trade_plan_items und speichert as_of_date, ticker, planned_shares,
estimated_price und fee in Shell-Variablen. Diese Variablen werden danach
im cli.live_trade --dry-run verwendet.
read -r TRADE_AS_OF_DATE TRADE_TICKER TRADE_SHARES TRADE_PRICE TRADE_FEE < <(
docker compose exec -T db sh -lc 'mysql -uroot -p"$MYSQL_ROOT_PASSWORD" "$MYSQL_DATABASE" -B -N -e "
SELECT as_of_date, ticker, planned_shares, estimated_price, fee
FROM live_trade_plan_items
WHERE action = '\''BUY'\'' AND is_executable = 1
ORDER BY as_of_date DESC, execution_order, ticker
LIMIT 1;
"'
)
docker compose run --rm app python -m cli.live_trade \
--execution-type BUY \
--ticker "${TRADE_TICKER}" \
--shares "${TRADE_SHARES}" \
--price "${TRADE_PRICE}" \
--fee "${TRADE_FEE}" \
--as-of-date "${TRADE_AS_OF_DATE}" \
--trade-plan-action BUY \
--dry-runDie Werte fuer shares, price, fee und as-of-date aus dem persistierten
Trade-Plan nehmen:
SELECT as_of_date, execution_order, action, ticker, planned_shares, estimated_price, fee, is_executable
FROM live_trade_plan_items
WHERE action = 'BUY'
ORDER BY as_of_date DESC, execution_order, ticker;SELL erfassen, wenn vorher eine reale Position gebucht wurde:
docker compose run --rm app python -m cli.live_trade --execution-type SELL --ticker "${TRADE_TICKER}" --shares 1 --price 200 --fee 1 --as-of-date "${TRADE_AS_OF_DATE}"Rohdaten:
assetsasset_provider_identifiersuniversesuniverse_membersasset_price_barsasset_fundamental_reportsasset_market_caps
Live/Operations:
strategy_instancesstrategy_config_snapshotsportfolio_target_itemslive_rebalance_itemslive_decision_itemslive_trade_planslive_trade_plan_itemslive_trade_executionslive_cash_ledgerlive_cash_balanceslive_positions
Bei fehlenden Rohdaten:
docker compose exec -T db sh -lc 'mysql -uroot -p"$MYSQL_ROOT_PASSWORD" "$MYSQL_DATABASE"' < fixtures/raw_market_data.sql
docker compose exec -T db sh -lc 'mysql -uroot -p"$MYSQL_ROOT_PASSWORD" "$MYSQL_DATABASE"' < init.sqlDanach erneut:
docker compose run --rm app python -m cli.data_status --details
docker compose run --rm app python -m cli.operator_smoke