Output:
Chunk ID: 028b30
Wall time: 0.0001 seconds
Process exited with code 0
Original token count: 5529
Output:
def _latest_snapshot(conn: Connection, account_id: str, snapshot_type: str):
    return conn.execute(
        """
        SELECT * FROM cash_account_snapshots
        WHERE account_id=? AND snapshot_type=?
        ORDER BY balance_date DESC, created_at DESC
        LIMIT 1
        """,
        (account_id, snapshot_type),
    ).fetchone()

def _cash_movements_after_anchor(conn: Connection, account_id: str, anchor_date: str | None) -> Decimal:
    if not anchor_date:
        return Decimal("0")
    row = conn.execute(
        """
        SELECT COALESCE(SUM(CAST(net_amount_chf AS TEXT)), '0') AS movement
        FROM transactions
        WHERE account_id=? AND COALESCE(is_voided,0)=0 AND COALESCE(is_confirmed,1)=1
          AND source_type LIKE '%csv%'
          AND trade_date > ?
        """,
        (account_id, anchor_date),
    ).fetchone()
    return Decimal(str(row["movement"] or "0"))

def _calculated_balance(conn: Connection, account_id: str) -> Decimal:
    anchor = _latest_snapshot(conn, account_id, "csv_anchor_balance")
    if anchor:
        return Decimal(str(anchor["amount_chf"])) + _cash_movements_after_anchor(conn, account_id, anchor["balance_date"])
    rows = conn.execute(
        "SELECT amount_chf FROM cash_balances WHERE account_id=?",
        (account_id,),
    ).fetchall()
    if rows:
        return sum(
            (
                Decimal(str(row["amount_chf"]))
                for row in rows
                if row["amount_chf"] is not None
            ),
            Decimal("0"),
        )
    # Legacy/demo datasets can have a transaction ledger without materialized
    # cash_balances. Keep the shared read model compatible without overriding an
    # explicit snapshot projection.
    ledger = calculate_cash_balances(conn, persist_alerts=False)
    return sum(
        (
            balance.amount_chf
            for (ledger_account_id, _currency), balance in ledger.balances.items()
            if ledger_account_id == account_id and balance.amount_chf is not None
        ),
        Decimal("0"),
    )

def _last_imported_booking(conn: Connection, account_id: str) -> str | None:
    row = conn.execute("SELECT MAX(trade_date) AS last_date FROM transactions WHERE account_id=? AND source_type LIKE '%csv%'", (account_id,)).fetchone()
    return row["last_date"] if row else None

def _post_snapshot_cash_deltas(
    conn: Connection,
    account_id: str,
    snapshot_date: str,
) -> dict[str, tuple[Decimal, Decimal | None]]:
    rows = conn.execute(
        """SELECT * FROM transactions
           WHERE account_id=? AND trade_date>?
             AND COALESCE(is_confirmed,0)=1 AND COALESCE(is_voided,0)=0
           ORDER BY trade_date,created_at,transaction_id""",
        (account_id, snapshot_date),
    ).fetchall()
    deltas: dict[str, tuple[Decimal, Decimal | None]] = {}
    for row in rows:
        original, amount_chf = _signed_cash_delta(row)
        if original == 0 and amount_chf in {None, Decimal("0")}:
            continue
        currency = str(row["currency_original"])
        previous_original, previous_chf = deltas.get(
            currency,
            (Decimal("0"), Decimal("0")),
        )
        deltas[currency] = (
            previous_original + original,
            None
            if previous_chf is None or amount_chf is None
            else previous_chf + amount_chf,
        )
    return deltas

def list_cash_positions(conn: Connection) -> list[CashPosition]:
    ledger = calculate_cash_balances(conn, persist_alerts=False)
    rows = conn.execute(
        """
        SELECT a.account_id, a.account_name, a.account_type, a.currency, COALESCE(a.balance_mode,'manual') AS balance_mode, p.name AS platform
        FROM accounts a JOIN platforms p ON p.platform_id=a.platform_id
        WHERE a.is_active=1
          AND (
              a.account_type='cash'
              OR a.account_id IN (
                  SELECT account_id FROM postfinance_account_roles
                  WHERE role='etrading_cash'
              )
          )
        ORDER BY p.name, a.account_name
        """
    ).fetchall()
    positions: list[CashPosition] = []
    official_components = latest_official_postfinance_cash(conn)
    official_by_account: dict[str, list] = {}
    for component in official_components:
        official_by_account.setdefault(component.account_id, []).append(component)
    for row in rows:
        account_id = row["account_id"]
        if account_id in official_by_account:
            components = {
                component.currency: component
                for component in official_by_account[account_id]
            }
            snapshot_date = next(iter(components.values())).snapshot_date
            deltas = _post_snapshot_cash_deltas(conn, account_id, snapshot_date)
            for currency in sorted(set(components) | set(deltas)):
                component = components.get(currency)
                delta_original, delta_chf = deltas.get(
                    currency,
                    (Decimal("0"), Decimal("0")),
                )
                amount_original = (
                    component.amount_original if component else Decimal("0")
                ) + delta_original
                baseline_chf = component.amount_chf if component else Decimal("0")
                amount_chf = (
                    baseline_chf + delta_chf if delta_chf is not None else baseline_chf
                )
                status = (
                    "Abgleich offen"
                    if delta_chf is None
                    else "Offiziell abgeglichen + Bewegungen"
                    if delta_original or delta_chf
                    else "Offiziell abgeglichen"
                )
                positions.append(
                    CashPosition(
                        id=f"{account_id}:{currency}",
                        account_id=account_id,
                        platform=row["platform"],
                        account_label=row["account_name"],
                        account_type=row["account_type"],
                        currency=currency,
                        balance_mode="official_components",
                        amount=decimal_text(amount_original, 2),
                        amount_chf=decimal_text(amount_chf, 2),
                        calculated_balance_chf=decimal_text(amount_chf, 2),
                        manual_balance_chf=None,
                        csv_anchor_balance_chf=None,
                        used_value_chf=decimal_text(amount_chf, 2),
                        difference_chf="0.00",
                        last_manual_reconciliation=snapshot_date,
                        last_imported_booking=_last_imported_booking(conn, account_id),
                        status=status,
                    )
                )
            continue
        manual = _latest_snapshot(conn, account_id, "manual_balance")
        anchor = _latest_snapshot(conn, account_id, "csv_anchor_balance")
        mode = row["balance_mode"] or "manual"
        default_currency = str(row["currency"])
        ledger_currencies = {
            currency
            for ledger_account_id, currency in ledger.balances
            if ledger_account_id == account_id
        }
        # Manual balances and CSV anchors are account-level CHF controls. They must
        # not be added to per-currency ledger rows from the same account.
        currencies = (
            {default_currency}
            if manual or anchor
            else set(ledger_currencies) or {default_currency}
        )
        for currency in sorted(currencies):
            ledger_balance = ledger.balances.get((account_id, currency))
            if manual or anchor:
                calculated = _calculated_balance(conn, account_id)
                amount_original = (
                    calculated if currency.upper() == "CHF" else Decimal("0")
                )
            elif ledger_balance is not None:
                calculated = ledger_balance.amount_chf or Decimal("0")
                amount_original = ledger_balance.amount_original
            else:
                calculated = _calculated_balance(conn, account_id)
                amount_original = (
                    calculated if currency.upper() == "CHF" else Decimal("0")
                )
            manual_amount = (
                Decimal(str(manual["amount_chf"]))
                if manual and currency == default_currency
                else None
            )
            used = (
                manual_amount
                if mode == "manual" and manual_amount is not None
                else calculated
            )
            difference = (
                manual_amount - calculated
                if manual_amount is not None
                else Decimal("0")
            )
            status = "Abgleich offen" if manual_amount is not None and difference != 0 else "Aktuell"
            positions.append(
                CashPosition(
                    id=f"{account_id}:{currency}",
                    account_id=account_id,
                    platform=row["platform"],
                    account_label=row["account_name"],
                    account_type=row["account_type"],
                    currency=currency,
                    balance_mode=mode,
                    amount=decimal_text(amount_original, 2),
                    amount_chf=decimal_text(used, 2),
                    calculated_balance_chf=decimal_text(calculated, 2),
                    manual_balance_chf=(
                        decimal_text(manual_amount, 2)
                        if manual_amount is not None
                        else None
                    ),
                    csv_anchor_balance_chf=(
                        decimal_text(anchor["amount_chf"], 2)
                        if anchor and currency == default_currency
                        else None
                    ),
                    used_value_chf=decimal_text(used, 2),
                    difference_chf=decimal_text(difference, 2),
                    last_manual_reconciliation=(
                        manual["balance_date"]
from __future__ import annotations

import json
from collections.abc import Mapping
from decimal import Decimal
from sqlite3 import Connection

from fastapi import HTTPException

from jarvis_finance.api.schemas.positions import EquityPortfolioSummary, EquityPosition
from jarvis_finance.dashboard import data as dashboard_data
from jarvis_finance.services.api_helpers import optional_decimal_text

def _asset_class_label(value: object) -> str:
    return "ETF" if str(value or "").lower() == "etf" else "Aktie"

def _account_label(row: dict[str, str]) -> str:
    platform = str(row.get("platform") or "").strip()
    account = str(row.get("account_name") or "").strip()
    if "postfinance" in platform.lower():
        if not account or "manual" in account.lower():
            return "PostFinance E-Trading"
        return account if "postfinance" in account.lower() or "e-trading" in account.lower() else f"PostFinance · {account}"
    return account or platform

def _latest_analysis(conn: Connection) -> tuple[dict[str, object] | None, dict[tuple[str, str], dict[str, object]], dict[str, str]]:
    row = conn.execute(
        """SELECT pas.*,mdr.completed_at,mdr.missing_instruments_json
             FROM portfolio_analysis_snapshots pas
             JOIN market_data_runs mdr ON mdr.run_id=pas.run_id
            ORDER BY pas.as_of DESC,pas.created_at DESC LIMIT 1"""
    ).fetchone()
    if not row:
        return None, {}, {}
    try:
        payload = json.loads(row["summary_json"] or "{}")
    except json.JSONDecodeError:
        payload = {}
    values = {
        (str(item.get("account_id") or ""), str(item.get("instrument_id") or "")): item
        for item in payload.get("positions", [])
        if isinstance(item, dict)
    }
    try:
        missing_rows = json.loads(row["missing_instruments_json"] or "[]")
    except json.JSONDecodeError:
        missing_rows = []
    missing = {
        str(item.get("instrument_id") or ""): str(item.get("reason_code") or "price_missing")
        for item in missing_rows
        if isinstance(item, dict)
    }
    return dict(row), values, missing

def _status_reason(code: str) -> str:
    labels = {
        "fmp_endpoint_restricted": "Der primäre Provider beschränkt diesen historischen Kurs im aktuellen Tarif.",
        "plan_restricted": "Der Provider beschränkt diesen historischen Kurs im aktuellen Tarif.",
        "fmp_rate_limited": "Das Provider-Limit wurde erreicht. Der Lauf kann kontrolliert fortgesetzt werden.",
        "rate_limited": "Das Provider-Limit wurde erreicht. Der Lauf kann kontrolliert fortgesetzt werden.",
        "currency_mismatch": "Die Kurswährung stimmt nicht mit der bestätigten Instrumentwährung überein.",
        "exchange_mismatch": "Der Handelsplatz des Provider-Ergebnisses ist nicht bestätigt.",
        "future_price_rejected": "Der gelieferte Kurs liegt nach dem zulässigen Börsenstichtag.",
        "stale_price": "Der letzte bestätigte Kurs ist für den Börsenstichtag zu alt und wird nicht bewertet.",
        "mapping_required": "Die Provider-Zuordnung ist noch nicht eindeutig bestätigt.",
        "fx_rate_missing": "Für die CHF-Bewertung fehlt ein bestätigter FX-Kurs.",
    }
    return labels.get(code, "Für den Börsenstichtag konnte noch kein bestätigter Kurs geladen werden.")

def _position_status(row: Mapping[str, object]) -> str:
    """Compatibility status when no audited market-analysis snapshot exists yet."""

    if "quantity" in row and Decimal(str(row.get("quantity") or "0")) <= 0:
        return "Einstand unvollständig"
    market_value = row.get("market_value_chf")
    warnings = str(row.get("quality_warnings") or "")
    if market_value not in {None, ""}:
        if "missing_cost_basis" in warnings or "missing_fx" in warnings:
            return "Einstand unvollständig"
        return "Bewertet"
    if str(row.get("price_status") or "") != "ok":
        return "Kurs fehlt"
    if str(row.get("fx_status") or "") == "missing_fx":
        return "FX fehlt für Bewertung"
    return "Bewertung unvollständig"

def _mapping_details(conn: Connection, instrument_id: str) -> dict[str, str | None]:
    row = conn.execute(
        """SELECT provider,provider_symbol,provider_market,upper(COALESCE(trading_currency,currency,'')) currency
             FROM instrument_price_mappings
            WHERE instrument_id=? AND mapping_status='mapped'
            ORDER BY updated_at DESC,mapping_id LIMIT 1""",
        (instrument_id,),
    ).fetchone()
    return dict(row) if row else {"provider": None, "provider_symbol": None, "provider_market": None, "currency": None}

def list_equity_positions(conn: Connection) -> list[EquityPosition]:
    source_rows = [
        row for row in dashboard_data.get_positions(conn)
        if row.get("asset_class", "").lower() in {"stock", "equity", "etf"}
        and row.get("instrument_status", "").lower() != "inactive"
    ]
    analysis, values, missing = _latest_analysis(conn)
    effective_values: dict[tuple[str, str], Decimal | None] = {}
    for row in source_rows:
        key = (str(row.get("account_id") or ""), str(row.get("instrument_id") or ""))
        candidate = values.get(key)
        row_is_audited = row.get("valuation_source") in {
            "postfinance_official_import",
            "audited_market_run",
        }
        candidate_is_newer = bool(
            analysis
            and candidate
            and str(analysis.get("as_of") or "") > str(row.get("valuation_as_of") or row.get("price_date") or "")
            and candidate.get("quality_status") == "fresh"
        )
        raw = (
            candidate.get("value_chf")
            if candidate_is_newer and candidate
            else row.get("market_value_chf") if analysis is None or row_is_audited else None
        )
        effective_values[key] = Decimal(str(raw)) if raw not in {None, ""} else None
    complete = bool(source_rows) and all(value is not None for value in effective_values.values())
    total = sum((value or Decimal("0") for value in effective_values.values()), Decimal("0"))
    positions: list[EquityPosition] = []
    for row in source_rows:
        account_id = str(row.get("account_id") or "")
        instrument_id = str(row.get("instrument_id") or "")
        snapshot_value = values.get((account_id, instrument_id))
        value = (
            snapshot_value
            if analysis
            and snapshot_value
            and snapshot_value.get("quality_status") == "fresh"
            and str(analysis.get("as_of") or "") > str(row.get("valuation_as_of") or row.get("price_date") or "")
            else None
        )
        row_fallback_allowed = analysis is None or row.get("valuation_source") in {
            "postfinance_official_import",
            "audited_market_run",
        }
        mapping = _mapping_details(conn, instrument_id)
        raw_market_value = (
            value.get("value_chf")
            if value
            else row.get("market_value_chf") if row_fallback_allowed else None
        )
        if Decimal(str(row.get("quantity") or "0")) <= 0:
            raw_market_value = None
        market_value = Decimal(str(raw_market_value)) if raw_market_value not in {None, ""} else None
        share = (market_value / total * Decimal("100")) if complete and market_value is not None and total > 0 else None
        code = "valued" if market_value is not None else ("stale_price" if snapshot_value else missing.get(instrument_id, "price_missing"))
        status = "Bewertet" if market_value is not None else ("Kurs veraltet" if snapshot_value else _position_status(row))
        provenance = value.get("price_input_provenance") if value else None
        provenance_provider = provenance.get("provider") if isinstance(provenance, dict) else None
        positions.append(EquityPosition(
            position_id=f"{account_id}:{instrument_id}",
            instrument_id=instrument_id,
            name=str(row.get("name") or ""),
            ticker=str(row.get("ticker") or ""),
            isin=str(row.get("isin") or ""),
            account=_account_label(row),
            asset_class=_asset_class_label(row.get("asset_class")),
            quantity=optional_decimal_text(row.get("quantity")) or "0",
            currency=str(value.get("currency") if value else mapping.get("currency") or row.get("price_currency") or row.get("currency") or ""),
            price=(
                optional_decimal_text(value.get("close"))
                if value
                else optional_decimal_text(row.get("market_price_original") or row.get("price"))
                if row_fallback_allowed
                else None
            ),
            market_value_chf=optional_decimal_text(market_value, 2) if market_value is not None else None,
            portfolio_share_pct=optional_decimal_text(share, 2) if share is not None else None,
            price_date=(
                str(analysis.get("as_of"))
                if value and analysis
                else str(row.get("valuation_as_of") or row.get("price_date") or "") or None
                if row_fallback_allowed
                else str(analysis.get("as_of")) if analysis else None
            ),
            provider=str((value.get("provider") if value else None) or provenance_provider or row.get("price_provider") or mapping.get("provider") or ""),
            provider_symbol=str(mapping.get("provider_symbol") or ""),
            exchange=str(mapping.get("provider_market") or ""),
            price_currency=str(value.get("currency") if value else mapping.get("currency") or row.get("price_currency") or row.get("currency") or ""),
            data_status="fresh" if market_value is not None else "missing",
            status_code=code,
            status_reason=None if market_value is not None else _status_reason(code),
            status=status,
        ))
    return sorted(positions, key=lambda item: Decimal(item.market_value_chf or "-1"), reverse=True)

def get_equity_summary(conn: Connection) -> EquityPortfolioSummary:
    positions = list_equity_positions(conn)
    valued = [item for item in positions if item.market_value_chf is not None]
    partial = sum((Decimal(item.market_value_chf or "0") for item in valued), Decimal("0"))
    complete = bool(positions) and len(valued) == len(positions)
    analysis, _, _ = _latest_analysis(conn)
    status = "complete" if complete else ("partial" if positions else "unavailable")
    effective_as_of = max((item.price_date or "" for item in valued), default="") or None
    analysis_as_of = str(analysis.get("as_of") or "") if analysis else ""
    response_as_of = effective_as_of or analysis_as_of or None
    last_successful = (
        str(analysis.get("completed_at"))
        if analysis and (not effective_as_of or analysis_as_of >= str(effective_as_of)[:10])
        else effective_as_of
    )
    return EquityPortfolioSummary(
        total_positions=len(positions),
        valued_positions=len(valued),
        unvalued_positions=len(positions) - len(valued),
        coverage_complete=complete,
        equity_value_chf=optional_decimal_text(partial, 2) if complete else None,
        valued_partial_chf=optional_decimal_text(partial, 2) or "0.00",
        value_label="Aktien-/ETF-Gesamtwert" if complete else "Bewerteter Teilwert",
        as_of=response_as_of,
        last_successful_run=last_successful,
        status=status,
        status_label=f"{len(valued)}/{len(positions)} bewertet" if positions else "Keine Aktien-/ETF-Positionen",
        unvalued_tickers=[item.ticker for item in positions if item.market_value_chf is None],
    )

def get_equity_position(conn: Connection, position_id: str) -> EquityPosition:
    position = next((p for p in list_equity_positions(conn) if p.position_id == position_id), None)
    if position is None:
        raise HTTPException(status_code=404, detail="Equity position not found")
    return position


sed -n '260,380p' src/jarvis_finance/services/cash_service.py && git diff --unified=80 -- src/jarvis_finance/services/equity_service.py


Output:
Chunk ID: 1a82d0
Wall time: 0.0000 seconds
Process exited with code 0
Original token count: 4606
Output:
                    "Abgleich offen"
                    if delta_chf is None
                    else "Offiziell abgeglichen + Bewegungen"
                    if delta_original or delta_chf
                    else "Offiziell abgeglichen"
                )
                positions.append(
                    CashPosition(
                        id=f"{account_id}:{currency}",
                        account_id=account_id,
                        platform=row["platform"],
                        account_label=row["account_name"],
                        account_type=row["account_type"],
                        currency=currency,
                        balance_mode="official_components",
                        amount=decimal_text(amount_original, 2),
                        amount_chf=decimal_text(amount_chf, 2),
                        calculated_balance_chf=decimal_text(amount_chf, 2),
                        manual_balance_chf=None,
                        csv_anchor_balance_chf=None,
                        used_value_chf=decimal_text(amount_chf, 2),
                        difference_chf="0.00",
                        last_manual_reconciliation=snapshot_date,
                        last_imported_booking=_last_imported_booking(conn, account_id),
                        status=status,
                    )
                )
            continue
        manual = _latest_snapshot(conn, account_id, "manual_balance")
        anchor = _latest_snapshot(conn, account_id, "csv_anchor_balance")
        mode = row["balance_mode"] or "manual"
        default_currency = str(row["currency"])
        ledger_currencies = {
            currency
            for ledger_account_id, currency in ledger.balances
            if ledger_account_id == account_id
        }
        # Manual balances and CSV anchors are account-level CHF controls. They must
        # not be added to per-currency ledger rows from the same account.
        currencies = (
            {default_currency}
            if manual or anchor
            else set(ledger_currencies) or {default_currency}
        )
        for currency in sorted(currencies):
            ledger_balance = ledger.balances.get((account_id, currency))
            if manual or anchor:
                calculated = _calculated_balance(conn, account_id)
                amount_original = (
                    calculated if currency.upper() == "CHF" else Decimal("0")
                )
            elif ledger_balance is not None:
                calculated = ledger_balance.amount_chf or Decimal("0")
                amount_original = ledger_balance.amount_original
            else:
                calculated = _calculated_balance(conn, account_id)
                amount_original = (
                    calculated if currency.upper() == "CHF" else Decimal("0")
                )
            manual_amount = (
                Decimal(str(manual["amount_chf"]))
                if manual and currency == default_currency
                else None
            )
            used = (
                manual_amount
                if mode == "manual" and manual_amount is not None
                else calculated
            )
            difference = (
                manual_amount - calculated
                if manual_amount is not None
                else Decimal("0")
            )
            status = "Abgleich offen" if manual_amount is not None and difference != 0 else "Aktuell"
            positions.append(
                CashPosition(
                    id=f"{account_id}:{currency}",
                    account_id=account_id,
                    platform=row["platform"],
                    account_label=row["account_name"],
                    account_type=row["account_type"],
                    currency=currency,
                    balance_mode=mode,
                    amount=decimal_text(amount_original, 2),
                    amount_chf=decimal_text(used, 2),
                    calculated_balance_chf=decimal_text(calculated, 2),
                    manual_balance_chf=(
                        decimal_text(manual_amount, 2)
                        if manual_amount is not None
                        else None
                    ),
                    csv_anchor_balance_chf=(
                        decimal_text(anchor["amount_chf"], 2)
                        if anchor and currency == default_currency
                        else None
                    ),
                    used_value_chf=decimal_text(used, 2),
                    difference_chf=decimal_text(difference, 2),
                    last_manual_reconciliation=(
                        manual["balance_date"]
                        if manual and currency == default_currency
                        else None
                    ),
                    last_imported_booking=_last_imported_booking(conn, account_id),
                    status=status,
                )
            )
    return positions

def get_cash_summary(conn: Connection) -> CashSummary:
    # Read paths must never seed or refresh accounts; setup is an explicit Confirm action.
    positions = list_cash_positions(conn)
    total = sum(Decimal(p.used_value_chf) for p in positions)
    last_dates = [p.last_manual_reconciliation for p in positions if p.last_manual_reconciliation]
    return CashSummary(
        base_currency="CHF",
        cash_chf=decimal_text(total, 2),
        manual_accounts_count=sum(1 for p in positions if p.balance_mode == "manual"),
        csv_calculated_accounts_count=sum(1 for p in positions if p.balance_mode == "csv_calculated"),
diff --git a/src/jarvis_finance/services/equity_service.py b/src/jarvis_finance/services/equity_service.py
index 614e76b..acb3fca 100644
--- a/src/jarvis_finance/services/equity_service.py
+++ b/src/jarvis_finance/services/equity_service.py
@@ -31,154 +31,207 @@ def _latest_analysis(conn: Connection) -> tuple[dict[str, object] | None, dict[t
         """SELECT pas.*,mdr.completed_at,mdr.missing_instruments_json
              FROM portfolio_analysis_snapshots pas
              JOIN market_data_runs mdr ON mdr.run_id=pas.run_id
             ORDER BY pas.as_of DESC,pas.created_at DESC LIMIT 1"""
     ).fetchone()
     if not row:
         return None, {}, {}
     try:
         payload = json.loads(row["summary_json"] or "{}")
     except json.JSONDecodeError:
         payload = {}
     values = {
         (str(item.get("account_id") or ""), str(item.get("instrument_id") or "")): item
         for item in payload.get("positions", [])
         if isinstance(item, dict)
     }
     try:
         missing_rows = json.loads(row["missing_instruments_json"] or "[]")
     except json.JSONDecodeError:
         missing_rows = []
     missing = {
         str(item.get("instrument_id") or ""): str(item.get("reason_code") or "price_missing")
         for item in missing_rows
         if isinstance(item, dict)
     }
     return dict(row), values, missing

 def _status_reason(code: str) -> str:
     labels = {
         "fmp_endpoint_restricted": "Der primäre Provider beschränkt diesen historischen Kurs im aktuellen Tarif.",
         "plan_restricted": "Der Provider beschränkt diesen historischen Kurs im aktuellen Tarif.",
         "fmp_rate_limited": "Das Provider-Limit wurde erreicht. Der Lauf kann kontrolliert fortgesetzt werden.",
         "rate_limited": "Das Provider-Limit wurde erreicht. Der Lauf kann kontrolliert fortgesetzt werden.",
         "currency_mismatch": "Die Kurswährung stimmt nicht mit der bestätigten Instrumentwährung überein.",
         "exchange_mismatch": "Der Handelsplatz des Provider-Ergebnisses ist nicht bestätigt.",
         "future_price_rejected": "Der gelieferte Kurs liegt nach dem zulässigen Börsenstichtag.",
         "stale_price": "Der letzte bestätigte Kurs ist für den Börsenstichtag zu alt und wird nicht bewertet.",
         "mapping_required": "Die Provider-Zuordnung ist noch nicht eindeutig bestätigt.",
         "fx_rate_missing": "Für die CHF-Bewertung fehlt ein bestätigter FX-Kurs.",
     }
     return labels.get(code, "Für den Börsenstichtag konnte noch kein bestätigter Kurs geladen werden.")

 def _position_status(row: Mapping[str, object]) -> str:
     """Compatibility status when no audited market-analysis snapshot exists yet."""

     if "quantity" in row and Decimal(str(row.get("quantity") or "0")) <= 0:
         return "Einstand unvollständig"
     market_value = row.get("market_value_chf")
     warnings = str(row.get("quality_warnings") or "")
     if market_value not in {None, ""}:
         if "missing_cost_basis" in warnings or "missing_fx" in warnings:
             return "Einstand unvollständig"
         return "Bewertet"
     if str(row.get("price_status") or "") != "ok":
         return "Kurs fehlt"
     if str(row.get("fx_status") or "") == "missing_fx":
         return "FX fehlt für Bewertung"
     return "Bewertung unvollständig"

 def _mapping_details(conn: Connection, instrument_id: str) -> dict[str, str | None]:
     row = conn.execute(
         """SELECT provider,provider_symbol,provider_market,upper(COALESCE(trading_currency,currency,'')) currency
              FROM instrument_price_mappings
             WHERE instrument_id=? AND mapping_status='mapped'
             ORDER BY updated_at DESC,mapping_id LIMIT 1""",
         (instrument_id,),
     ).fetchone()
     return dict(row) if row else {"provider": None, "provider_symbol": None, "provider_market": None, "currency": None}

 def list_equity_positions(conn: Connection) -> list[EquityPosition]:
     source_rows = [
         row for row in dashboard_data.get_positions(conn)
         if row.get("asset_class", "").lower() in {"stock", "equity", "etf"}
         and row.get("instrument_status", "").lower() != "inactive"
     ]
     analysis, values, missing = _latest_analysis(conn)
-    use_cache_fallback = analysis is None
-    expected_keys = {(str(row.get("account_id") or ""), str(row.get("instrument_id") or "")) for row in source_rows}
-    complete = bool(analysis and analysis.get("quality_status") == "complete" and set(values) == expected_keys)
-    total = sum((Decimal(str(item.get("value_chf") or "0")) for item in values.values()), Decimal("0"))
+    effective_values: dict[tuple[str, str], Decimal | None] = {}
+    for row in source_rows:
+        key = (str(row.get("account_id") or ""), str(row.get("instrument_id") or ""))
+        candidate = values.get(key)
+        row_is_audited = row.get("valuation_source") in {
+            "postfinance_official_import",
+            "audited_market_run",
+        }
+        candidate_is_newer = bool(
+            analysis
+            and candidate
+            and str(analysis.get("as_of") or "") > str(row.get("valuation_as_of") or row.get("price_date") or "")
+            and candidate.get("quality_status") == "fresh"
+        )
+        raw = (
+            candidate.get("value_chf")
+            if candidate_is_newer and candidate
+            else row.get("market_value_chf") if analysis is None or row_is_audited else None
+        )
+        effective_values[key] = Decimal(str(raw)) if raw not in {None, ""} else None
+    complete = bool(source_rows) and all(value is not None for value in effective_values.values())
+    total = sum((value or Decimal("0") for value in effective_values.values()), Decimal("0"))
     positions: list[EquityPosition] = []
     for row in source_rows:
         account_id = str(row.get("account_id") or "")
         instrument_id = str(row.get("instrument_id") or "")
         snapshot_value = values.get((account_id, instrument_id))
-        value = snapshot_value if snapshot_value and snapshot_value.get("quality_status") == "fresh" else None
+        value = (
+            snapshot_value
+            if analysis
+            and snapshot_value
+            and snapshot_value.get("quality_status") == "fresh"
+            and str(analysis.get("as_of") or "") > str(row.get("valuation_as_of") or row.get("price_date") or "")
+            else None
+        )
+        row_fallback_allowed = analysis is None or row.get("valuation_source") in {
+            "postfinance_official_import",
+            "audited_market_run",
+        }
         mapping = _mapping_details(conn, instrument_id)
-        raw_market_value = value.get("value_chf") if value else (row.get("market_value_chf") if use_cache_fallback else None)
-        if use_cache_fallback and Decimal(str(row.get("quantity") or "0")) <= 0:
+        raw_market_value = (
+            value.get("value_chf")
+            if value
+            else row.get("market_value_chf") if row_fallback_allowed else None
+        )
+        if Decimal(str(row.get("quantity") or "0")) <= 0:
             raw_market_value = None
         market_value = Decimal(str(raw_market_value)) if raw_market_value not in {None, ""} else None
         share = (market_value / total * Decimal("100")) if complete and market_value is not None and total > 0 else None
         code = "valued" if market_value is not None else ("stale_price" if snapshot_value else missing.get(instrument_id, "price_missing"))
-        status = "Bewertet" if value else ("Kurs veraltet" if snapshot_value else (_position_status(row) if use_cache_fallback else "Kurs fehlt"))
+        status = "Bewertet" if market_value is not None else ("Kurs veraltet" if snapshot_value else _position_status(row))
         provenance = value.get("price_input_provenance") if value else None
         provenance_provider = provenance.get("provider") if isinstance(provenance, dict) else None
         positions.append(EquityPosition(
             position_id=f"{account_id}:{instrument_id}",
             instrument_id=instrument_id,
             name=str(row.get("name") or ""),
             ticker=str(row.get("ticker") or ""),
             isin=str(row.get("isin") or ""),
             account=_account_label(row),
             asset_class=_asset_class_label(row.get("asset_class")),
             quantity=optional_decimal_text(row.get("quantity")) or "0",
             currency=str(value.get("currency") if value else mapping.get("currency") or row.get("price_currency") or row.get("currency") or ""),
-            price=optional_decimal_text(value.get("close")) if value else (optional_decimal_text(row.get("market_price_original") or row.get("price")) if use_cache_fallback else None),
+            price=(
+                optional_decimal_text(value.get("close"))
+                if value
+                else optional_decimal_text(row.get("market_price_original") or row.get("price"))
+                if row_fallback_allowed
+                else None
+            ),
             market_value_chf=optional_decimal_text(market_value, 2) if market_value is not None else None,
             portfolio_share_pct=optional_decimal_text(share, 2) if share is not None else None,
-            price_date=str(value.get("as_of")) if value else (str(analysis.get("as_of")) if analysis else None),
-            provider=str((value.get("provider") if value else None) or provenance_provider or mapping.get("provider") or ""),
+            price_date=(
+                str(analysis.get("as_of"))
+                if value and analysis
+                else str(row.get("valuation_as_of") or row.get("price_date") or "") or None
+                if row_fallback_allowed
+                else str(analysis.get("as_of")) if analysis else None
+            ),
+            provider=str((value.get("provider") if value else None) or provenance_provider or row.get("price_provider") or mapping.get("provider") or ""),
             provider_symbol=str(mapping.get("provider_symbol") or ""),
             exchange=str(mapping.get("provider_market") or ""),
             price_currency=str(value.get("currency") if value else mapping.get("currency") or row.get("price_currency") or row.get("currency") or ""),
             data_status="fresh" if market_value is not None else "missing",
             status_code=code,
             status_reason=None if market_value is not None else _status_reason(code),
             status=status,
         ))
     return sorted(positions, key=lambda item: Decimal(item.market_value_chf or "-1"), reverse=True)

 def get_equity_summary(conn: Connection) -> EquityPortfolioSummary:
     positions = list_equity_positions(conn)
     valued = [item for item in positions if item.market_value_chf is not None]
     partial = sum((Decimal(item.market_value_chf or "0") for item in valued), Decimal("0"))
     complete = bool(positions) and len(valued) == len(positions)
     analysis, _, _ = _latest_analysis(conn)
     status = "complete" if complete else ("partial" if positions else "unavailable")
+    effective_as_of = max((item.price_date or "" for item in valued), default="") or None
+    analysis_as_of = str(analysis.get("as_of") or "") if analysis else ""
+    response_as_of = effective_as_of or analysis_as_of or None
+    last_successful = (
+        str(analysis.get("completed_at"))
+        if analysis and (not effective_as_of or analysis_as_of >= str(effective_as_of)[:10])
+        else effective_as_of
+    )
     return EquityPortfolioSummary(
         total_positions=len(positions),
         valued_positions=len(valued),
         unvalued_positions=len(positions) - len(valued),
         coverage_complete=complete,
         equity_value_chf=optional_decimal_text(partial, 2) if complete else None,
         valued_partial_chf=optional_decimal_text(partial, 2) or "0.00",
         value_label="Aktien-/ETF-Gesamtwert" if complete else "Bewerteter Teilwert",
-        as_of=str(analysis.get("as_of")) if analysis else None,
-        last_successful_run=str(analysis.get("completed_at")) if analysis else None,
+        as_of=response_as_of,
+        last_successful_run=last_successful,
         status=status,
         status_label=f"{len(valued)}/{len(positions)} bewertet" if positions else "Keine Aktien-/ETF-Positionen",
         unvalued_tickers=[item.ticker for item in positions if item.market_value_chf is None],
     )

 def get_equity_position(conn: Connection, position_id: str) -> EquityPosition:
     position = next((p for p in list_equity_positions(conn) if p.position_id == position_id), None)
     if position is None:
         raise HTTPException(status_code=404, detail="Equity position not found")
     return position


Output:
Chunk ID: 5c8c34
Wall time: 2.2605 seconds
Process exited with code 0
Original token count: 25
Output:
........                                                                 [100%]
8 passed in 2.01s


grep -R "CREATE TABLE postfinance_account_roles\|postfinance_account_roles\|postfinance_snapshot_cash\|postfinance_snapshots" -n src tests | head -80


Output:
Chunk ID: 002dfd
Wall time: 0.0000 seconds
Process exited with code 0
Original token count: 1677
Output:
grep: src/jarvis_finance/storage/__pycache__/postfinance_schema.cpython-311.pyc: binary file matches
grep: src/jarvis_finance/dashboard/__pycache__/data.cpython-312.pyc: binary file matches
grep: src/jarvis_finance/dashboard/__pycache__/data.cpython-311.pyc: binary file matches
grep: src/jarvis_finance/services/__pycache__/postfinance_service.cpython-311.pyc: binary file matches
grep: src/jarvis_finance/services/__pycache__/portfolio_data.cpython-311.pyc: binary file matches
grep: src/jarvis_finance/services/__pycache__/cash_service.cpython-311.pyc: binary file matches
grep: src/jarvis_finance/services/__pycache__/portfolio_aggregation.cpython-311.pyc: binary file matches
grep: src/jarvis_finance/services/__pycache__/portfolio_analytics.cpython-312.pyc: binary file matches
grep: src/jarvis_finance/services/__pycache__/portfolio_aggregation.cpython-312.pyc: binary file matches
grep: src/jarvis_finance/services/__pycache__/portfolio_analytics.cpython-311.pyc: binary file matches
grep: src/jarvis_finance/services/__pycache__/postfinance_service.cpython-312.pyc: binary file matches
grep: tests/__pycache__/test_postfinance_sprint13.cpython-311-pytest-9.1.1.pyc: binary file matches
grep: tests/__pycache__/test_postfinance_sprint13.cpython-311.pyc: binary file matches
grep: tests/__pycache__/test_postfinance_sprint13.cpython-311-pytest-9.0.2.pyc: binary file matches
src/jarvis_finance/storage/postfinance_schema.py:15:        CREATE TABLE IF NOT EXISTS postfinance_account_roles (
src/jarvis_finance/storage/postfinance_schema.py:56:        CREATE TABLE IF NOT EXISTS postfinance_snapshots (
src/jarvis_finance/storage/postfinance_schema.py:77:            snapshot_id TEXT NOT NULL REFERENCES postfinance_snapshots(snapshot_id),
src/jarvis_finance/storage/postfinance_schema.py:95:        CREATE TABLE IF NOT EXISTS postfinance_snapshot_cash (
src/jarvis_finance/storage/postfinance_schema.py:97:            snapshot_id TEXT NOT NULL REFERENCES postfinance_snapshots(snapshot_id),
src/jarvis_finance/storage/postfinance_schema.py:172:        CREATE TRIGGER IF NOT EXISTS postfinance_snapshots_immutable BEFORE UPDATE ON postfinance_snapshots
src/jarvis_finance/storage/postfinance_schema.py:174:        CREATE TRIGGER IF NOT EXISTS postfinance_snapshots_no_delete BEFORE DELETE ON postfinance_snapshots
src/jarvis_finance/storage/postfinance_schema.py:180:        CREATE TRIGGER IF NOT EXISTS postfinance_snapshot_cash_immutable BEFORE UPDATE ON postfinance_snapshot_cash
src/jarvis_finance/storage/postfinance_schema.py:182:        CREATE TRIGGER IF NOT EXISTS postfinance_snapshot_cash_no_delete BEFORE DELETE ON postfinance_snapshot_cash
src/jarvis_finance/dashboard/data.py:16:    postfinance_account_roles,
src/jarvis_finance/dashboard/data.py:564:    roles = postfinance_account_roles(conn)
src/jarvis_finance/services/portfolio_aggregation.py:65:def postfinance_account_roles(conn: Connection) -> dict[str, str]:
src/jarvis_finance/services/portfolio_aggregation.py:71:            "SELECT role,account_id FROM postfinance_account_roles ORDER BY role"
src/jarvis_finance/services/portfolio_aggregation.py:100:    roles = postfinance_account_roles(conn)
src/jarvis_finance/services/portfolio_aggregation.py:115:            FROM postfinance_snapshots {where}
src/jarvis_finance/services/portfolio_aggregation.py:123:           FROM postfinance_snapshot_cash WHERE snapshot_id=? ORDER BY currency""",
src/jarvis_finance/services/portfolio_aggregation.py:153:    roles = postfinance_account_roles(conn)
src/jarvis_finance/services/portfolio_aggregation.py:168:            FROM postfinance_snapshots {where}
src/jarvis_finance/services/portfolio_aggregation.py:223:    roles = postfinance_account_roles(conn)
src/jarvis_finance/services/portfolio_data.py:34:    postfinance_account_roles,
src/jarvis_finance/services/portfolio_data.py:1599:    pf_roles = postfinance_account_roles(conn)
src/jarvis_finance/services/portfolio_analytics.py:31:    postfinance_account_roles,
src/jarvis_finance/services/portfolio_analytics.py:238:    trading_cash_id = postfinance_account_roles(conn).get("etrading_cash")
src/jarvis_finance/services/postfinance_service.py:541:                "INSERT OR IGNORE INTO postfinance_account_roles(role,account_id,source_reference_hash,created_at) VALUES(?,?,NULL,?)",
src/jarvis_finance/services/postfinance_service.py:545:                "SELECT account_id FROM postfinance_account_roles WHERE role=?", (role,)
src/jarvis_finance/services/postfinance_service.py:602:            """INSERT INTO postfinance_snapshots(snapshot_id,batch_id,account_id,snapshot_at,total_chf,securities_chf,cash_chf,stocks_chf,etfs_chf,component_total_chf,difference_chf,tolerance_chf,position_count,cash_count,open_orders,reconciliation_status,created_at) VALUES(?,?,?,?,?,?,?,?,?,?,?,? ,?,?,?,?,?)""",
src/jarvis_finance/services/postfinance_service.py:797:                "INSERT INTO postfinance_snapshot_cash(snapshot_cash_id,snapshot_id,currency,amount_original,fx_rate_to_chf,value_chf,created_at) VALUES(?,?,?,?,?,?,?)",
src/jarvis_finance/services/postfinance_service.py:873:           FROM postfinance_snapshots ORDER BY snapshot_at DESC,created_at DESC LIMIT 1"""
src/jarvis_finance/services/postfinance_service.py:937:               FROM postfinance_import_batches b JOIN postfinance_snapshots s ON s.batch_id=b.batch_id
src/jarvis_finance/services/cash_service.py:225:                  SELECT account_id FROM postfinance_account_roles
tests/test_postfinance_sprint13.py:281:    assert conn.execute("SELECT COUNT(*) FROM postfinance_snapshots").fetchone()[0] == 1
tests/test_postfinance_sprint13.py:283:    assert conn.execute("SELECT COUNT(*) FROM postfinance_account_roles").fetchone()[0] == 3
tests/test_postfinance_sprint13.py:284:    roles = dict(conn.execute("SELECT role,account_id FROM postfinance_account_roles"))
tests/test_postfinance_sprint13.py:451:            "UPDATE postfinance_snapshots SET total_chf='0' WHERE snapshot_id=?",
tests/test_postfinance_sprint13.py:456:            "DELETE FROM postfinance_snapshots WHERE snapshot_id=?", (result["snapshot_id"],)
tests/test_postfinance_sprint13.py:461:        "postfinance_snapshot_cash": "created_at=created_at",
tests/test_postfinance_sprint13.py:726:    source_snapshot = dict(conn.execute("SELECT * FROM postfinance_snapshots LIMIT 1").fetchone())
tests/test_postfinance_sprint13.py:742:        f"INSERT INTO postfinance_snapshots({','.join(columns)}) VALUES({','.join('?' for _ in columns)})",
tests/test_postfinance_sprint13.py:759:        """INSERT INTO postfinance_snapshot_cash(
tests/test_postfinance_sprint13.py:763:           FROM postfinance_snapshot_cash WHERE snapshot_id<> 'future-snapshot'"""


sed -n '1,130p' src/jarvis_finance/storage/postfinance_schema.py && sed -n '500,620p' src/jarvis_finance/services/postfinance_service.py


Output:
Chunk ID: 003300
Wall time: 0.0000 seconds
Process exited with code 0
Original token count: 3211
Output:
from __future__ import annotations

from sqlite3 import Connection

def create_postfinance_ledger_import_v1(conn: Connection) -> None:
    """Create immutable PostFinance source, ledger, snapshot and cost-basis tables."""
    position_columns = {row[1] for row in conn.execute("PRAGMA table_info(positions_snapshot)")}
    if "source_type" not in position_columns:
        conn.execute("ALTER TABLE positions_snapshot ADD COLUMN source_type TEXT")
    if "source_reference" not in position_columns:
        conn.execute("ALTER TABLE positions_snapshot ADD COLUMN source_reference TEXT")
    conn.executescript(
        """
        CREATE TABLE IF NOT EXISTS postfinance_account_roles (
            role TEXT PRIMARY KEY CHECK(role IN ('efinance','etrading_depot','etrading_cash')),
            account_id TEXT NOT NULL REFERENCES accounts(account_id),
            source_reference_hash TEXT,
            created_at TEXT NOT NULL,
            UNIQUE(account_id, role)
        );
        CREATE TABLE IF NOT EXISTS postfinance_import_batches (
            batch_id TEXT PRIMARY KEY,
            bundle_sha256 TEXT NOT NULL UNIQUE CHECK(length(bundle_sha256)=64),
            zip_sha256 TEXT NOT NULL CHECK(length(zip_sha256)=64),
            overview_sha256 TEXT NOT NULL CHECK(length(overview_sha256)=64),
            parser_id TEXT NOT NULL,
            parser_version TEXT NOT NULL,
            db_revision TEXT NOT NULL,
            archive_reference TEXT NOT NULL,
            snapshot_at TEXT NOT NULL,
            status TEXT NOT NULL CHECK(status='confirmed'),
            audit_id TEXT NOT NULL,
            confirmed_at TEXT NOT NULL,
            confirmed_by TEXT NOT NULL DEFAULT 'user'
        );
        CREATE TABLE IF NOT EXISTS postfinance_documents (
            document_hash TEXT PRIMARY KEY CHECK(length(document_hash)=64),
            filename_hash TEXT NOT NULL CHECK(length(filename_hash)=64),
            semantic_identity TEXT NOT NULL UNIQUE CHECK(length(semantic_identity)=64),
            semantic_reference_hash TEXT NOT NULL CHECK(length(semantic_reference_hash)=64),
            document_type TEXT NOT NULL,
            document_date TEXT,
            account_reference_hash TEXT,
            account_role TEXT NOT NULL CHECK(account_role IN ('efinance','etrading_depot','etrading_cash')),
            page_count INTEGER NOT NULL CHECK(page_count > 0),
            archive_reference TEXT NOT NULL,
            parser_version TEXT NOT NULL,
            created_at TEXT NOT NULL
        );
        CREATE TABLE IF NOT EXISTS postfinance_batch_documents (
            batch_id TEXT NOT NULL REFERENCES postfinance_import_batches(batch_id),
            document_hash TEXT NOT NULL REFERENCES postfinance_documents(document_hash),
            PRIMARY KEY(batch_id, document_hash)
        );
        CREATE TABLE IF NOT EXISTS postfinance_snapshots (
            snapshot_id TEXT PRIMARY KEY,
            batch_id TEXT NOT NULL UNIQUE REFERENCES postfinance_import_batches(batch_id),
            account_id TEXT NOT NULL REFERENCES accounts(account_id),
            snapshot_at TEXT NOT NULL,
            total_chf TEXT NOT NULL,
            securities_chf TEXT NOT NULL,
            cash_chf TEXT NOT NULL,
            stocks_chf TEXT NOT NULL,
            etfs_chf TEXT NOT NULL,
            component_total_chf TEXT NOT NULL,
            difference_chf TEXT NOT NULL,
            tolerance_chf TEXT NOT NULL,
            position_count INTEGER NOT NULL,
            cash_count INTEGER NOT NULL,
            open_orders INTEGER NOT NULL,
            reconciliation_status TEXT NOT NULL CHECK(reconciliation_status IN ('matched','within_tolerance')),
            created_at TEXT NOT NULL
        );
        CREATE TABLE IF NOT EXISTS postfinance_snapshot_positions (
            snapshot_position_id TEXT PRIMARY KEY,
            snapshot_id TEXT NOT NULL REFERENCES postfinance_snapshots(snapshot_id),
            source_row_reference TEXT NOT NULL,
            instrument_id TEXT NOT NULL REFERENCES instruments(instrument_id),
            asset_class TEXT NOT NULL CHECK(asset_class IN ('stock','etf')),
            quantity TEXT NOT NULL,
            provider_average_cost_original TEXT,
            provider_cost_total_original TEXT,
            price_original TEXT NOT NULL,
            price_currency TEXT NOT NULL,
            value_chf TEXT NOT NULL,
            weight_pct TEXT NOT NULL,
            computed_cost_basis_original TEXT,
            computed_cost_basis_status TEXT NOT NULL CHECK(computed_cost_basis_status IN ('complete','partial','unavailable')),
            provenance_json TEXT NOT NULL CHECK(json_valid(provenance_json)),
            created_at TEXT NOT NULL,
            UNIQUE(snapshot_id, source_row_reference),
            UNIQUE(snapshot_id, instrument_id)
        );
        CREATE TABLE IF NOT EXISTS postfinance_snapshot_cash (
            snapshot_cash_id TEXT PRIMARY KEY,
            snapshot_id TEXT NOT NULL REFERENCES postfinance_snapshots(snapshot_id),
            currency TEXT NOT NULL,
            amount_original TEXT NOT NULL,
            fx_rate_to_chf TEXT NOT NULL,
            value_chf TEXT NOT NULL,
            created_at TEXT NOT NULL,
            UNIQUE(snapshot_id, currency)
        );
        CREATE TABLE IF NOT EXISTS postfinance_ledger_events (
            event_id TEXT PRIMARY KEY,
            event_fingerprint TEXT NOT NULL UNIQUE CHECK(length(event_fingerprint)=64),
            document_hash TEXT NOT NULL REFERENCES postfinance_documents(document_hash),
            semantic_reference_hash TEXT NOT NULL CHECK(length(semantic_reference_hash)=64),
            event_type TEXT NOT NULL CHECK(event_type IN ('buy','sell','dividend','interest','fee','internal_transfer','fx','split','corporate_action')),
            account_role TEXT NOT NULL CHECK(account_role IN ('efinance','etrading_depot','etrading_cash')),
            account_id TEXT NOT NULL REFERENCES accounts(account_id),
            occurred_on TEXT NOT NULL,
            settlement_on TEXT,
            direction TEXT NOT NULL CHECK(direction IN ('in','out','neutral')),
            instrument_id TEXT REFERENCES instruments(instrument_id),
            quantity TEXT,
            price_original TEXT,
            gross_original TEXT,
            fee_original TEXT NOT NULL DEFAULT '0',
            tax_original TEXT NOT NULL DEFAULT '0',
            net_original TEXT,
            currency TEXT,
            fx_rate_to_chf TEXT,
            internal_transfer_group TEXT,
            quality_status TEXT NOT NULL CHECK(quality_status IN ('complete','partial')),
            reason_codes_json TEXT NOT NULL CHECK(json_valid(reason_codes_json)),
            created_at TEXT NOT NULL
        );
        CREATE INDEX IF NOT EXISTS idx_postfinance_events_time ON postfinance_ledger_events(occurred_on, event_type);
        row = conn.execute(
            "SELECT batch_id,audit_id FROM postfinance_import_batches WHERE bundle_sha256=?",
            (preview["bundle_sha256"],),
        ).fetchone()
        return {
            "status": "confirmed",
            "batch_id": row["batch_id"],
            "audit_id": row["audit_id"],
            "idempotent": True,
        }
    accounts = _resolve_accounts(conn, request)
    zip_raw, overview_raw = _source_bytes(request)
    bundle = parse_postfinance_bundle(zip_raw, overview_raw)  # mandatory byte reparse on confirm
    if (
        bundle.bundle_hash != preview["bundle_sha256"]
        or _revision(conn, accounts) != preview["db_revision"]
    ):
        raise ValueError("PostFinance source bytes or database revision changed after preview")
    position_map = _match_instruments(conn, bundle, accounts["etrading_depot"])
    event_instruments = {
        event.event_fingerprint: _event_instrument(event, bundle, position_map, conn)
        for event in bundle.events
    }
    archive_refs: list[tuple[str, bool]] = []
    zip_ref, created = _archive(zip_raw, bundle.zip_hash, "zip")
    archive_refs.append((zip_ref, created))
    overview_ref, created = _archive(overview_raw, bundle.overview_hash, "pdf")
    archive_refs.append((overview_ref, created))
    for document in bundle.documents:
        reference, created = _archive(document.raw, document.document_hash, "pdf")
        archive_refs.append((reference, created))
    now = _now()
    batch_id = _id("pfbatch")
    snapshot_id = _id("pfsnapshot")
    try:
        conn.execute("BEGIN IMMEDIATE")
        if _revision(conn, accounts) != preview["db_revision"]:
            raise ValueError("PostFinance database revision changed before persistence")
        _ensure_efinance_account(conn, accounts, now)
        for role, account_id in accounts.items():
            conn.execute(
                "INSERT OR IGNORE INTO postfinance_account_roles(role,account_id,source_reference_hash,created_at) VALUES(?,?,NULL,?)",
                (role, account_id, now),
            )
            mapped = conn.execute(
                "SELECT account_id FROM postfinance_account_roles WHERE role=?", (role,)
            ).fetchone()
            if not mapped or mapped["account_id"] != account_id:
                raise ValueError(
                    "PostFinance account-role mapping conflicts with confirmed mapping"
                )
        audit_id = _audit(conn, batch_id, bundle, now)
        conn.execute(
            """INSERT INTO postfinance_import_batches(batch_id,bundle_sha256,zip_sha256,overview_sha256,parser_id,parser_version,db_revision,archive_reference,snapshot_at,status,audit_id,confirmed_at,confirmed_by) VALUES(?,?,?,?,?,?,?,?,?,'confirmed',?,?,'user')""",
            (
                batch_id,
                bundle.bundle_hash,
                bundle.zip_hash,
                bundle.overview_hash,
                PARSER_ID,
                PARSER_VERSION,
                preview["db_revision"],
                zip_ref,
                bundle.snapshot.valuation_at,
                audit_id,
                now,
            ),
        )
        for document in bundle.documents:
            reference = f"postfinance/archive/{document.document_hash}.pdf"
            ref_hash = _hash(document.semantic_reference)
            existing = conn.execute(
                "SELECT document_hash FROM postfinance_documents WHERE semantic_identity=?",
                (document.semantic_identity,),
            ).fetchone()
            if existing and existing["document_hash"] != document.document_hash:
                raise ValueError("PostFinance semantic document conflict")
            conn.execute(
                """INSERT OR IGNORE INTO postfinance_documents(document_hash,filename_hash,semantic_identity,semantic_reference_hash,document_type,document_date,account_reference_hash,account_role,page_count,archive_reference,parser_version,created_at) VALUES(?,?,?,?,?,?,?,?,?,?,?,?)""",
                (
                    document.document_hash,
                    document.filename_hash,
                    document.semantic_identity,
                    ref_hash,
                    document.document_type,
                    document.document_date,
                    document.account_reference_hash,
                    document.account_role,
                    document.page_count,
                    reference,
                    PARSER_VERSION,
                    now,
                ),
            )
            conn.execute(
                "INSERT INTO postfinance_batch_documents(batch_id,document_hash) VALUES(?,?)",
                (batch_id, document.document_hash),
            )
        snapshot = bundle.snapshot
        component_total = snapshot.securities_total_chf + snapshot.cash_total_chf
        difference = snapshot.total_value_chf - component_total
        conn.execute(
            """INSERT INTO postfinance_snapshots(snapshot_id,batch_id,account_id,snapshot_at,total_chf,securities_chf,cash_chf,stocks_chf,etfs_chf,component_total_chf,difference_chf,tolerance_chf,position_count,cash_count,open_orders,reconciliation_status,created_at) VALUES(?,?,?,?,?,?,?,?,?,?,?,? ,?,?,?,?,?)""",
            (
                snapshot_id,
                batch_id,
                accounts["etrading_depot"],
                snapshot.valuation_at,
                _money(snapshot.total_value_chf),
                _money(snapshot.securities_total_chf),
                _money(snapshot.cash_total_chf),
                _money(snapshot.stock_total_chf),
                _money(snapshot.etf_total_chf),
                _money(component_total),
                _money(difference),
                _money(TOLERANCE),
                len(snapshot.positions),
                len(snapshot.cash),
                snapshot.open_orders,
                "matched" if difference == 0 else "within_tolerance",
                now,


grep -R "\"quantity\".*positions\|positions.*quantity" -n src/jarvis_finance/services/portfolio_analytics.py | head -40 && sed -n '650,850p' src/jarvis_finance/services/portfolio_analytics.py


Output:
Chunk ID: d629ee
Wall time: 0.0000 seconds
Process exited with code 0
Original token count: 2980
Output:
                reasons.add("benchmark_currency_mismatch")
                quote = None
            elif quote and not exchange_matches(str(benchmark_mapping["provider_market"] or ""), quote.provider_market):
                reasons.add("benchmark_exchange_mismatch")
                quote = None
            if not quote or quote.close is None or quote.close <= ZERO:
                reasons.add("benchmark_quote_missing")
            elif quote.currency.upper() not in rates:
                benchmark_currency = quote.currency.upper()
                try:
                    benchmark_rate, benchmark_rate_as_of = _fetch_fx_rate(fx, benchmark_currency, effective)
                except Exception:
                    benchmark_rate = None
                    benchmark_rate_as_of = None
                if benchmark_rate is None or benchmark_rate_as_of is None:
                    reasons.add("benchmark_fx_missing")
                else:
                    rates[benchmark_currency] = benchmark_rate
                    rate_dates[benchmark_currency] = benchmark_rate_as_of
                    if benchmark_currency not in currencies:
                        currencies.append(benchmark_currency)
                    existing_benchmark_rate = conn.execute(
                        """SELECT rate FROM fx_rates
                            WHERE base_currency=? AND quote_currency='CHF' AND rate_date=?
                              AND provider=? AND rate_type='close'""",
                        (
                            benchmark_currency,
                            benchmark_rate_as_of.isoformat(),
                            "identity" if benchmark_currency == "CHF" else getattr(fx, "name", "fx_provider"),
                        ),
                    ).fetchone()
                    if not existing_benchmark_rate or _decimal(existing_benchmark_rate["rate"]) != benchmark_rate:
                        upsert_fx_rate(
                            conn, base_currency=benchmark_currency, quote_currency="CHF", rate_date=benchmark_rate_as_of.isoformat(),
                            rate=benchmark_rate, provider="identity" if benchmark_currency == "CHF" else getattr(fx, "name", "fx_provider"),
                            rate_type="close", quality_status="fresh", fetched_at=now, run_id=run_id,
                        )
                        fx_writes += 1
            if quote and quote.close is not None and quote.close > ZERO and quote.currency.upper() in rates:
                return_type = "etf_proxy" if benchmark_mapping["asset_class"] == "etf" else ("total_return" if quote.adjusted_close is not None else "price_return")
                if return_type == "total_return":
                    assert quote.adjusted_close is not None
                    benchmark_level = quote.adjusted_close
                else:
                    benchmark_level = quote.close
                benchmark_value = benchmark_level * rates[quote.currency.upper()]
                conn.execute(
                    """INSERT OR REPLACE INTO benchmark_snapshots(
                        benchmark_snapshot_id,run_id,policy_id,benchmark_reference,provider,provider_symbol,
                        price_currency,close,adjusted_close,fx_rate_to_chf,value_chf,return_type,as_of,source_as_of,fetched_at,
                        quality_status,reason_codes_json) VALUES(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)""",
                    (stable_id("benchmark", run_id, policy["policy_id"], benchmark_mapping["reference"]), run_id,
                     policy["policy_id"], benchmark_mapping["reference"], quote.provider,
                     benchmark_mapping["provider_symbol"], quote.currency.upper(), _fmt(quote.close),
                     _fmt(quote.adjusted_close), _fmt(rates[quote.currency.upper()]), _fmt(benchmark_value),
                     return_type, effective.isoformat(), benchmark_quote_date.isoformat(), now, "fresh", "[]"),
                )
                benchmark_stored = 1

        price_total = len(positions)
        price_stored = price_writes
        fx_total = len(currencies)
        fx_stored = fx_writes
        current_prices = sum(1 for _, _, quote_as_of, _ in quotes.values() if 0 <= _business_day_age(quote_as_of, effective) <= 2)
        price_coverage = _pct(current_prices, price_total)
        fx_covered_positions = sum(
            1 for _, quote, _, _ in quotes.values()
            if quote.currency.upper() in rates and 0 <= _business_day_age(rate_dates[quote.currency.upper()], effective) <= 2
        )
        fx_coverage = _pct(fx_covered_positions, price_total)
        benchmark_coverage = _pct(benchmark_stored, benchmark_total) if benchmark_total else ZERO
        if price_total == 0:
            quality = "unavailable"
            reasons.add("no_confirmed_positions")
        elif price_coverage == HUNDRED and fx_coverage == HUNDRED and (benchmark_total == 0 or benchmark_coverage == HUNDRED):
            quality = "complete"
        else:
            quality = "partial"
        risk = _risk_summary(conn, values, account_values, missing)
        analysis_id = stable_id("portfolio-analysis", run_id)
        conn.execute(
            """INSERT OR REPLACE INTO portfolio_analysis_snapshots(
                analysis_snapshot_id,run_id,as_of,base_currency,total_value_chf,price_coverage_pct,
                fx_coverage_pct,benchmark_coverage_pct,quality_status,reason_codes_json,summary_json,created_at)
                VALUES(?,?,?,?,?,?,?,?,?,?,?,?)""",
            (analysis_id, run_id, effective.isoformat(), "CHF", _fmt(sum(account_values.values(), ZERO)),
             _fmt(price_coverage), _fmt(fx_coverage), _fmt(benchmark_coverage), quality,
             json.dumps(sorted(reasons)), json.dumps({"positions": values, "risk": risk}, sort_keys=True), now),
        )
        audit_id = record_audit_event(
            conn, source=SOURCE_KEY, action="daily_market_valuation_completed", entity_type="market_data_run",
            entity_id=run_id, old_values={}, new_values={"as_of": effective.isoformat(), "status": quality,
            "price_coverage_pct": _fmt(price_coverage), "fx_coverage_pct": _fmt(fx_coverage),
            "benchmark_coverage_pct": _fmt(benchmark_coverage), "price_inputs_accepted": len(quotes),
            "price_rows_written": price_writes, "fx_inputs_accepted": len(rates), "fx_rows_written": fx_writes,
            "cached_price_inputs": cached_price_inputs, "reason_codes": sorted(reasons)}, created_by="system",
        )
        conn.execute(
            """UPDATE market_data_runs SET status=?,completed_at=?,price_total=?,price_stored=?,fx_total=?,fx_stored=?,
               benchmark_total=?,benchmark_stored=?,valuation_stored=?,missing_instruments_json=?,reason_codes_json=?,audit_id=?
               WHERE run_id=?""",
            (quality if quality != "unavailable" else "partial", utc_now(), price_total, price_stored, fx_total,
             fx_stored, benchmark_total, benchmark_stored, valuation_stored, json.dumps(missing),
             json.dumps(sorted(reasons)), audit_id, run_id),
        )
        conn.commit()
        return _result_from_row(conn.execute("SELECT * FROM market_data_runs WHERE run_id=?", (run_id,)).fetchone(), idempotent=False)

def _latest_cash_entries(conn: Connection) -> list[dict[str, Any]]:
    rows = conn.execute(
        """WITH ranked AS (
               SELECT c.account_id,c.currency,c.amount_chf,
                      ROW_NUMBER() OVER (
                          PARTITION BY c.account_id,c.currency
                          ORDER BY c.created_at DESC,c.snapshot_id DESC
                      ) AS rn
               FROM cash_account_snapshots c
               JOIN accounts a ON a.account_id=c.account_id
               WHERE a.is_active=1
           )
           SELECT account_id,currency,amount_chf FROM ranked WHERE rn=1
           ORDER BY account_id,currency"""
    ).fetchall()
    return [
        {"account_id": str(row["account_id"]), "currency": str(row["currency"]).upper(), "amount_chf": _decimal(row["amount_chf"])}
        for row in rows
    ]

def _latest_cash_by_account(conn: Connection) -> dict[str, Decimal]:
    result: dict[str, Decimal] = defaultdict(lambda: ZERO)
    for entry in _latest_cash_entries(conn):
        result[entry["account_id"]] += entry["amount_chf"]
    return dict(result)

def _risk_summary(
    conn: Connection,
    values: list[dict[str, Any]],
    account_values: dict[str, Decimal],
    missing: list[dict[str, str]],
) -> dict[str, Any]:
    position_total = sum((_decimal(item["value_chf"]) for item in values), ZERO)
    cash_entries = _latest_cash_entries(conn)
    cash = sum((entry["amount_chf"] for entry in cash_entries), ZERO)
    total = position_total + cash
    sorted_values = sorted(values, key=lambda item: _decimal(item["value_chf"]), reverse=True)
    by_asset: dict[str, Decimal] = defaultdict(lambda: ZERO)
    by_currency: dict[str, Decimal] = defaultdict(lambda: ZERO)
    for item in values:
        value = _decimal(item["value_chf"])
        by_asset[item["asset_class"]] += value
        by_currency[item["currency"]] += value
    if cash:
        by_asset["cash"] += cash
        for entry in cash_entries:
            by_currency[entry["currency"]] += entry["amount_chf"]
    largest_pct = _pct(_decimal(sorted_values[0]["value_chf"]), total) if sorted_values else ZERO
    top5_pct = _pct(sum((_decimal(item["value_chf"]) for item in sorted_values[:5]), ZERO), total)
    cash_pct = _pct(cash, total)
    policy = _active_policy(conn)
    breaches: list[str] = []
    if policy and policy.get("max_single_position_pct") and largest_pct > _decimal(policy["max_single_position_pct"]):
        breaches.append("Positionslimit überschritten")
    allocations: list[dict[str, str]] = []
    if policy:
        allocations = [dict(row) for row in conn.execute("SELECT asset_class,lower_pct,upper_pct FROM portfolio_policy_allocations WHERE policy_id=?", (policy["policy_id"],)).fetchall()]
        for allocation in allocations:
            policy_asset = allocation["asset_class"].lower()
            if policy_asset == "equity":
                policy_value = sum((by_asset.get(key, ZERO) for key in ("equity", "stock", "etf")), ZERO)
            else:
                policy_value = by_asset.get(policy_asset, ZERO)
            actual = _pct(policy_value, total)
            if actual < _decimal(allocation["lower_pct"]) or actual > _decimal(allocation["upper_pct"]):
                breaches.append(f"{allocation['asset_class']}: Policy-Band verletzt")
        for restriction in policy.get("restrictions") or []:
            if not isinstance(restriction, str) or not restriction.startswith("max_currency_pct:"):
                continue
            try:
                currency, limit_text = restriction.removeprefix("max_currency_pct:").replace("=", ":").split(":", 1)
                actual = _pct(by_currency.get(currency.upper(), ZERO), total)
                if actual > _decimal(limit_text):
                    breaches.append(f"{currency.upper()}: Währungslimit überschritten")
            except (ValueError, InvalidOperation):
                continue
    valuation_dates = [row[0] for row in conn.execute(
        """SELECT DISTINCT valuation_at FROM portfolio_valuation_snapshots
           WHERE scope_kind='account' AND source=? ORDER BY valuation_at""", (SOURCE_KEY,),
    ).fetchall()]
    levels: list[Decimal] = []
    if len(valuation_dates) >= 30:
        start = valuation_dates[0]
        for value in valuation_dates:
            if value == start:
                levels.append(ONE)
                continue
            performance = build_portfolio_performance(conn, from_date=start, to_date=value, base_currency="CHF")
            summary = performance.get("summary")
            twr_raw = summary.get("twr") if isinstance(summary, dict) else None


grep -n "values.append\|\"value_chf\"" -n src/jarvis_finance/services/portfolio_analytics.py | head -80


Output:
Chunk ID: 43ec53
Wall time: 0.0000 seconds
Process exited with code 0
Original token count: 214
Output:
569:            values.append({
573:                "close": _fmt(close), "fx_rate_to_chf": _fmt(rate), "value_chf": _fmt(value_chf),
793:    position_total = sum((_decimal(item["value_chf"]) for item in values), ZERO)
797:    sorted_values = sorted(values, key=lambda item: _decimal(item["value_chf"]), reverse=True)
801:        value = _decimal(item["value_chf"])
808:    largest_pct = _pct(_decimal(sorted_values[0]["value_chf"]), total) if sorted_values else ZERO
809:    top5_pct = _pct(sum((_decimal(item["value_chf"]) for item in sorted_values[:5]), ZERO), total)
899:    benchmark_start = _decimal(benchmark_rows[dates[0]]["value_chf"])
913:        benchmark_norm = _decimal(benchmark_rows[value]["value_chf"]) / benchmark_start * HUNDRED
919:    benchmark_pct = (_decimal(benchmark_rows[dates[-1]]["value_chf"]) / benchmark_start - ONE) * HUNDRED


sed -n '530,590p' src/jarvis_finance/services/portfolio_analytics.py


Output:
Chunk ID: 2b33c2
Wall time: 0.0000 seconds
Process exited with code 0
Original token count: 864
Output:
            provider_name = "identity" if currency == "CHF" else getattr(fx, "name", "fx_provider")
            rate, rate_as_of = _fetch_fx_rate(fx, currency, effective)
            if rate is None or rate_as_of is None:
                reasons.add("fx_rate_missing")
                continue
            rates[currency] = rate
            rate_dates[currency] = rate_as_of
            rate_age = _business_day_age(rate_as_of, effective)
            rate_quality = "fresh" if 0 <= rate_age <= 2 else "stale"
            if rate_quality == "stale":
                reasons.add("stale_fx")
            existing_rate = conn.execute(
                """SELECT rate FROM fx_rates
                    WHERE base_currency=? AND quote_currency='CHF' AND rate_date=?
                      AND provider=? AND rate_type='close'""",
                (currency, rate_as_of.isoformat(), provider_name),
            ).fetchone()
            if not existing_rate or _decimal(existing_rate["rate"]) != rate:
                upsert_fx_rate(
                    conn, base_currency=currency, quote_currency="CHF", rate_date=rate_as_of.isoformat(),
                    rate=rate, provider=provider_name, rate_type="close", quality_status=rate_quality,
                    fetched_at=now, run_id=run_id,
                )
                fx_writes += 1
        conn.commit()

        values: list[dict[str, Any]] = []
        account_values: dict[str, Decimal] = defaultdict(lambda: ZERO)
        account_missing: set[str] = set()
        for (_, instrument_id), (position, quote, quote_as_of, _) in quotes.items():
            rate = rates.get(quote.currency.upper())
            close = quote.close
            if rate is None or close is None:
                missing.append({"instrument_id": instrument_id, "reason_code": "fx_rate_missing"})
                account_missing.add(position.account_id)
                continue
            value_original = position.quantity * close
            value_chf = value_original * rate
            account_values[position.account_id] += value_chf
            values.append({
                "account_id": position.account_id, "instrument_id": instrument_id, "isin": position.isin,
                "name": position.name, "asset_class": position.asset_class,
                "currency": quote.currency.upper(), "quantity": _fmt(position.quantity),
                "close": _fmt(close), "fx_rate_to_chf": _fmt(rate), "value_chf": _fmt(value_chf),
                "as_of": quote_as_of.isoformat(), "quality_status": "fresh" if 0 <= _business_day_age(quote_as_of, effective) <= 2 else "stale",
                "provider": quote.provider, "provider_symbol": quote.provider_symbol,
                "provider_market": quote.provider_market,
                **({"price_input_provenance": cached_price_inputs[instrument_id]} if instrument_id in cached_price_inputs else {}),
            })
        missing_ids = {item["instrument_id"] for item in missing}
        for position in positions:
            if position.instrument_id in missing_ids:
                account_missing.add(position.account_id)
        for account_id, amount in _latest_cash_by_account(conn).items():
            account_values[account_id] += amount
        for item in missing:
            position = position_details.get(item["instrument_id"])
            if position:
                item["label"] = position.name
                item["isin"] = position.isin or ""


sed -n '1,120p' src/jarvis_finance/ledger/cash.py && grep -R "transaction_type.*sell\|sell" -n src/jarvis_finance | head -60


Output:
Chunk ID: 53ac9a
Wall time: 0.0000 seconds
Process exited with code 0
Original token count: 3780
Output:
from __future__ import annotations

from dataclasses import dataclass, field
from decimal import Decimal
from sqlite3 import Connection

from jarvis_finance.audit.log import record_audit_event
from jarvis_finance.imports.common import stable_id, utc_now
from jarvis_finance.quality.alerts import create_alert

@dataclass
class CashBalance:
    account_id: str
    currency: str
    amount_original: Decimal = Decimal("0")
    amount_chf: Decimal | None = Decimal("0")
    quality_status: str = "ok"

@dataclass
class CashCalculationResult:
    balances: dict[tuple[str, str], CashBalance] = field(default_factory=dict)
    negative_cash_warnings: list[str] = field(default_factory=list)

def _d(value: object, default: str = "0") -> Decimal:
    if value is None or str(value).strip() == "":
        return Decimal(default)
    return Decimal(str(value))

def _signed_cash_delta(row) -> tuple[Decimal, Decimal | None]:
    t = row["transaction_type"]
    gross = _d(row["gross_amount_original"])
    net = _d(row["net_amount_original"]) if row["net_amount_original"] is not None else None
    fee = _d(row["fee_original"])
    tax = _d(row["tax_original"])
    fx = _d(row["fx_rate_to_chf"], "1") if row["fx_rate_to_chf"] is not None else None

    if t == "initial_cash_snapshot":
        original = net if net is not None else gross
    elif t == "cash_deposit":
        original = net if net is not None else gross
    elif t == "cash_withdrawal":
        original = -(net if net is not None else gross)
    elif t == "buy":
        original = -(net if net is not None else gross + fee + tax)
    elif t in {"sell", "partial_sell", "full_sell"}:
        original = net if net is not None else gross - fee - tax
    elif t in {"dividend", "etf_distribution"}:
        original = net if net is not None else gross - tax - fee
    elif t in {"fee", "tax"}:
        original = -(net if net is not None else gross or fee or tax)
    elif t == "fx_conversion":
        original = net if net is not None else gross
    elif t == "manual_cash_correction":
        original = net if net is not None else gross
    else:
        original = Decimal("0")
    chf = original * fx if fx is not None else None
    return original, chf

def calculate_cash_balances(
    conn: Connection, *, as_of_date: str | None = None, persist_alerts: bool = True
) -> CashCalculationResult:
    result = CashCalculationResult()
    params: tuple[object, ...] = ()
    where = "WHERE COALESCE(is_voided, 0) = 0"
    if as_of_date:
        where += " AND trade_date <= ?"
        params = (as_of_date,)
    rows = conn.execute(
        f"""
        SELECT * FROM transactions
        {where}
        ORDER BY account_id, currency_original, trade_date, created_at, transaction_id
        """,
        params,
    ).fetchall()
    for row in rows:
        account_id = row["account_id"]
        currency = row["currency_original"]
        key = (account_id, currency)
        balance = result.balances.setdefault(key, CashBalance(account_id, currency))
        original, chf = _signed_cash_delta(row)
        balance.amount_original += original
        if chf is None:
            balance.amount_chf = None
            balance.quality_status = "incomplete"
        elif balance.amount_chf is not None:
            balance.amount_chf += chf
    for key, balance in result.balances.items():
        if balance.amount_original < 0:
            msg = f"Negative cash balance for account={balance.account_id} currency={balance.currency}: {balance.amount_original}"
            result.negative_cash_warnings.append(msg)
            if persist_alerts:
                create_alert(
                    conn,
                    priority="warnung",
                    category="cash",
                    entity_type="account",
                    entity_id=balance.account_id,
                    rule_id="negative_cash",
                    message=msg,
                    evidence={"currency": balance.currency, "amount_original": str(balance.amount_original)},
                )
    if persist_alerts:
        conn.commit()
    return result

def apply_manual_cash_correction(
    conn: Connection,
    *,
    account_id: str,
    currency: str,
    amount: Decimal,
    note: str,
grep: src/jarvis_finance/crypto/__pycache__/holdings.cpython-312.pyc: binary file matches
grep: src/jarvis_finance/crypto/__pycache__/transactions.cpython-311.pyc: binary file matches
grep: src/jarvis_finance/crypto/__pycache__/holdings.cpython-311.pyc: binary file matches
grep: src/jarvis_finance/ledger/__pycache__/cost_basis.cpython-311.pyc: binary file matches
grep: src/jarvis_finance/ledger/__pycache__/positions.cpython-311.pyc: binary file matches
grep: src/jarvis_finance/ledger/__pycache__/positions.cpython-312.pyc: binary file matches
grep: src/jarvis_finance/ledger/__pycache__/cost_basis.cpython-312.pyc: binary file matches
grep: src/jarvis_finance/ledger/__pycache__/cash.cpython-311.pyc: binary file matches
grep: src/jarvis_finance/imports/__pycache__/transactions_importer.cpython-311.pyc: binary file matches
grep: src/jarvis_finance/imports/__pycache__/postfinance_documents.cpython-311.pyc: binary file matches
grep: src/jarvis_finance/imports/__pycache__/postfinance_documents.cpython-312.pyc: binary file matches
grep: src/jarvis_finance/imports/__pycache__/crypto_transactions_importer.cpython-311.pyc: binary file matches
grep: src/jarvis_finance/storage/__pycache__/postfinance_schema.cpython-311.pyc: binary file matches
grep: src/jarvis_finance/models/__pycache__/enums.cpython-311.pyc: binary file matches
grep: src/jarvis_finance/dashboard/views/__pycache__/page_13_equity_manage.cpython-311.pyc: binary file matches
grep: src/jarvis_finance/dashboard/views/__pycache__/page_03_equities_etfs.cpython-311.pyc: binary file matches
grep: src/jarvis_finance/api/routers/__pycache__/equity.cpython-311.pyc: binary file matches
src/jarvis_finance/crypto/transactions.py:114:    sign_net = gross_amount_original - fee_original if tx_type in {"partial_sell", "full_sell"} else gross_amount_original
src/jarvis_finance/crypto/transactions.py:290:def record_crypto_sell(
src/jarvis_finance/crypto/transactions.py:313:    provisional = stable_id("cryptosell", asset_id, from_wallet_id, quantity, utc_now())
src/jarvis_finance/crypto/transactions.py:316:        tx_type="partial_sell",
src/jarvis_finance/crypto/transactions.py:327:        tx_type="sell",
src/jarvis_finance/crypto/transactions.py:341:    # Sell fee is represented in the sell net amount; do not create a separate fee row.
src/jarvis_finance/crypto/transactions.py:350:            message="Crypto sell fee currency is unclear; fee remains embedded in sell transaction.",
src/jarvis_finance/crypto/transactions.py:356:        action="crypto_sell",
src/jarvis_finance/crypto/holdings.py:134:        elif t == "sell":
src/jarvis_finance/ledger/cash.py:49:    elif t in {"sell", "partial_sell", "full_sell"}:
src/jarvis_finance/ledger/cost_basis.py:51:    def sell(self, quantity: Decimal, proceeds_chf: Decimal) -> None:
src/jarvis_finance/ledger/cost_basis.py:53:            raise ValueError("sell quantity must be > 0")
src/jarvis_finance/ledger/cost_basis.py:55:            raise ValueError("sell quantity exceeds current position")
src/jarvis_finance/ledger/cost_basis.py:102:    """Apply FIFO to normalized buy/sell events in deterministic input order.
src/jarvis_finance/ledger/cost_basis.py:106:    sell fees/taxes reduce proceeds. Unsupported or incomplete events must be
src/jarvis_finance/ledger/cost_basis.py:124:        if kind != "sell":
src/jarvis_finance/ledger/positions.py:179:        elif t in {"partial_sell", "full_sell"}:
src/jarvis_finance/ledger/positions.py:182:                lot.sell(qty, proceeds_chf)
src/jarvis_finance/imports/postfinance_documents.py:322:            else "sell"
src/jarvis_finance/imports/crypto_transactions_importer.py:5:from jarvis_finance.crypto.transactions import record_crypto_buy, record_crypto_sell, record_crypto_transfer
src/jarvis_finance/imports/crypto_transactions_importer.py:55:            elif tx=='sell': record_crypto_sell(conn,account_id=account(conn,require_text(row,'account_name',line)),asset_id=aid,from_wallet_id=wallet(conn,require_text(row,'from_wallet_name',line)),quantity=qty,gross_amount_original=dec(row.get('gross_amount_original'),line,'gross_amount_original'),fee_original=feeo,fee_currency=clean(row.get('fee_currency')) or None,currency=require_text(row,'currency_original',line),fx_rate_to_chf=fx,note=note)
src/jarvis_finance/imports/transactions_importer.py:22:QUANTITY_REQUIRED_TYPES = {"buy", "partial_sell", "full_sell", "initial_position_snapshot"}
src/jarvis_finance/storage/postfinance_schema.py:110:            event_type TEXT NOT NULL CHECK(event_type IN ('buy','sell','dividend','interest','fee','internal_transfer','fx','split','corporate_action')),
src/jarvis_finance/models/enums.py:8:    PARTIAL_SELL = "partial_sell"
src/jarvis_finance/models/enums.py:9:    FULL_SELL = "full_sell"
src/jarvis_finance/models/enums.py:24:    CRYPTO_SELL = "crypto_sell"
src/jarvis_finance/dashboard/views/page_13_equity_manage.py:117:        pos_type = st.selectbox("Buchung", ["initial_snapshot", "buy", "partial_sell", "full_sell", "dividend", "etf_distribution", "manual_adjustment"], key="wizard_position_type")
src/jarvis_finance/dashboard/views/page_13_equity_manage.py:357:    transaction_form(tabs[4], "Teilverkauf erfassen", "partial_sell")
src/jarvis_finance/dashboard/views/page_13_equity_manage.py:358:    transaction_form(tabs[5], "Vollverkauf erfassen", "full_sell")
src/jarvis_finance/dashboard/views/page_03_equities_etfs.py:295:    e.button("Verkaufen", key=f"portfolio_action_sell_{row_key}", disabled=True, help="MVP: Verkaufsworkflow noch nicht freigeschaltet.")
src/jarvis_finance/api/routers/equity.py:10:from jarvis_finance.services.manual_entry_service import confirm_equity_dividend, confirm_equity_sell, preview_equity_dividend, preview_equity_sell
src/jargrep: src/jarvis_finance/equity/__pycache__/manage.cpython-311.pyc: binary file matches
grep: src/jarvis_finance/services/__pycache__/postfinance_service.cpython-311.pyc: binary file matches
grep: src/jarvis_finance/services/__pycache__/portfolio_performance.cpython-311.pyc: binary file matches
grep: src/jarvis_finance/services/__pycache__/portfolio_data.cpython-311.pyc: binary file matches
grep: src/jarvis_finance/services/__pycache__/portfolio_aggregation.cpython-311.pyc: binary file matches
grep: src/jarvis_finance/services/__pycache__/manual_entry_service.cpython-311.pyc: binary file matches
grep: src/jarvis_finance/services/__pycache__/portfolio_analytics.cpython-312.pyc: binary file matches
grep: src/jarvis_finance/services/__pycache__/portfolio_performance.cpython-312.pyc: binary file matches
grep: src/jarvis_finance/services/__pycache__/portfolio_analytics.cpython-311.pyc: binary file matches
grep: src/jarvis_finance/services/__pycache__/postfinance_service.cpython-312.pyc: binary file matches
vis_finance/api/routers/equity.py:30:@router.post("/equity/actions/sell/preview", response_model=PreviewResponse)
src/jarvis_finance/api/routers/equity.py:31:def equity_sell_preview(request: EquitySellPreviewRequest, conn: Connection = Depends(get_db)) -> PreviewResponse:
src/jarvis_finance/api/routers/equity.py:32:    return preview_equity_sell(conn, request)
src/jarvis_finance/api/routers/equity.py:35:@router.post("/equity/actions/sell/confirm", response_model=ConfirmResponse)
src/jarvis_finance/api/routers/equity.py:36:def equity_sell_confirm(request: EquitySellConfirmRequest, conn: Connection = Depends(get_db)) -> ConfirmResponse:
src/jarvis_finance/api/routers/equity.py:37:    return confirm_equity_sell(conn, request)
src/jarvis_finance/equity/manage.py:17:VALID_TRANSACTION_TYPES = {"buy", "partial_sell", "full_sell", "dividend", "etf_distribution", "fee", "manual_adjustment", "initial_snapshot", "initial_position_snapshot"}
src/jarvis_finance/equity/manage.py:546:    if transaction_type in {"buy", "partial_sell", "full_sell", "initial_position_snapshot"} and qty <= 0:
src/jarvis_finance/equity/manage.py:550:    if transaction_type in {"partial_sell", "full_sell"}:
src/jarvis_finance/equity/manage.py:554:            raise ValueError("sell would create negative position")
src/jarvis_finance/equity/manage.py:555:        if transaction_type == "full_sell" and qty != current_qty:
src/jarvis_finance/equity/manage.py:556:            raise ValueError("full_sell quantity must match current position")
src/jarvis_finance/equity/manage.py:668:    elif position_type in {"buy", "partial_sell", "full_sell", "dividend", "etf_distribution", "manual_adjustment"}:
src/jarvis_finance/equity/manage.py:671:        raise ValueError("position_type must be initial_snapshot, buy, partial_sell, full_sell, dividend, etf_distribution or manual_adjustment")
src/jarvis_finance/equity/manage.py:679:    if transaction_type in {"initial_position_snapshot", "buy", "partial_sell", "full_sell", "manual_adjustment"} and qty <= 0:
src/jarvis_finance/equity/manage.py:695:    if transaction_type in {"partial_sell", "full_sell"}:
src/jarvis_finance/equity/manage.py:699:            raise ValueError("sell would create negative position")
src/jarvis_finance/equity/manage.py:700:        if transaction_type == "full_sell" and qty != current_qty:
src/jarvis_finance/equity/manage.py:701:            raise ValueError("full_sell quantity must match current position")
src/jarvis_finance/services/manual_entry_service.py:876:def preview_equity_sell(conn: Connection, request: EquitySellPreviewRequest) -> PreviewResponse:
src/jarvis_finance/services/manual_entry_service.py:898:def confirm_equity_sell(conn: Connection, request: EquitySellConfirmRequest) -> ConfirmResponse:
src/jarvis_finance/services/manual_entry_service.py:901:    preview = preview_equity_sell(conn, request)
src/jarvis_finance/services/manual_entry_service.py:916:        VALUES (?, 'sell', ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 'vue_equity_sale', 1, ?, ?, ?)
src/jarvis_finance/services/manual_entry_service.py:920:    audit_id = _audit(conn, action="equity_sell_confirm", entity_type="position", entity_id=request.position_id, payload={**request.model_dump(), "net_amount_original": _format_decimal(net), "gross_amount_original": _format_decimal(gross)}, note=request.note, quality_status="ok" if fx_status != "missing" else "missing_fx")
src/jarvis_finance/services/portfolio_aggregation.py:219:    """Replay confirmed buys/sells after the official snapshot baseline."""
src/jarvis_finance/services/portfolio_aggregation.py:241:              AND lower(transaction_type) IN ('buy','sell','partial_sell','full_sell')
src/jarvis_finance/services/portfolio_aggregation.py:249:        if str(row["transaction_type"]) in {"sell", "partial_sell", "full_sell"}:
src/jarvis_finance/services/portfolio_data.py:44:    "cash_withdrawal", "internal_transfer", "transfer", "buy", "partial_sell", "full_sell",
src/jarvis_finance/services/portfolio_data.py:45:    "sell", "dividend", "etf_distribution", "distribution", "fee", "tax",


sed -n '880,930p' src/jarvis_finance/services/manual_entry_service.py && sed -n '155,210p' src/jarvis_finance/ledger/positions.py