Skip to content
All library documents

Point-in-Time Congressional Disclosure Replay with Risk Gates

Code Lumibot

Summary

This code describes a deterministic replay process for trading on congressional disclosures. It uses each disclosure’s public publication time to decide whether the information was available, explicitly avoiding the transaction date as the signal timestamp. For each visible record, it checks disclosure age, price availability, dollar-volume liquidity, transaction direction, and whether a long position exists before permitting a trade.

Accepted purchases are sized under per-position and total-exposure limits, constrained by available cash; accepted sales close the existing long holding. The replay records decisions, orders, a trace, ending cash and equity, then writes summary, trade, trace, and HTML report artifacts. Its evidence is a reproducible fixture replay rather than a performance study, and the displayed fill price is a market snapshot rather than a simulated execution model. The code also warns that disclosure publication can lag the underlying transaction by as much as 45 days, limiting how timely such a signal can be.

Key ideas

  • Signal availability is based on public disclosure time rather than transaction time.
  • The replay applies freshness, price, liquidity, transaction clarity, and position checks before trading.
  • Purchases are bounded by position size, total exposure, and available cash.
  • The outputs provide an auditable trace and trade artifacts, but do not establish strategy profitability.
  • Disclosure reporting can lag the original transaction by up to 45 days.

Tags

Full text
# disclosure_replay.py


```py
"""Deterministic proof harness for point-in-time congressional disclosures."""

from __future__ import annotations

import csv
import hashlib
import html
import json
from datetime import datetime, timezone
from pathlib import Path
from typing import Any, Iterable

from lumibot.components.disclosure_signals import visible_congress_disclosures


def _dt(value: Any) -> datetime:
    text = str(value).replace("Z", "+00:00")
    parsed = datetime.fromisoformat(text)
    if parsed.tzinfo is None:
        parsed = parsed.replace(tzinfo=timezone.utc)
    return parsed.astimezone(timezone.utc)


def replay_congress_disclosures(
    records: Iterable[dict[str, Any]],
    market_snapshots: dict[str, dict[str, Any]],
    *,
    as_of: Any,
    initial_cash: float,
    max_disclosure_age_days: int = 90,
    max_position_pct: float = 5,
    max_total_exposure_pct: float = 20,
    minimum_average_dollar_volume: float = 1_000_000,
) -> dict[str, Any]:
    """Replay public availability and deterministic risk gates without an LLM."""
    ceiling = _dt(as_of)
    visible = visible_congress_disclosures(records, as_of=ceiling)
    cash = float(initial_cash)
    positions: dict[str, int] = {}
    orders: list[dict[str, Any]] = []
    decisions: list[dict[str, Any]] = []
    trace: list[dict[str, Any]] = []

    for record in visible:
        published = _dt(record["published_at"])
        symbol = record["ticker"]
        trace.append(
            {
                "role": "disclosure_researcher",
                "at": published.isoformat(),
                "disclosure_id": record["id"],
                "evidence": {
                    "source": record["source"],
                    "published_at": record["published_at"],
                    "transaction_date": record["transaction_date"],
                    "ticker": symbol,
                    "transaction": record["transaction"],
                },
            }
        )
        reason = "accepted"
        snapshot = market_snapshots.get(symbol) or {}
        price = float(snapshot.get("price") or 0)
        volume = float(snapshot.get("average_daily_volume") or 0)
        average_dollar_volume = price * volume
        age_days = (ceiling - published).total_seconds() / 86_400
        if age_days > max(int(max_disclosure_age_days), 0):
            reason = "stale_disclosure"
        elif price <= 0:
            reason = "missing_price"
        elif average_dollar_volume < float(minimum_average_dollar_volume):
            reason = "liquidity_below_minimum"

        transaction = str(record.get("transaction") or "").strip().lower()
        side = "buy" if "purchase" in transaction or "buy" in transaction else "sell" if "sale" in transaction else None
        if reason == "accepted" and side is None:
            reason = "ambiguous_transaction"
        if reason == "accepted" and side == "sell" and positions.get(symbol, 0) <= 0:
            reason = "no_long_position_to_sell"

        equity = cash + sum(
            quantity * float((market_snapshots.get(position_symbol) or {}).get("price") or 0)
            for position_symbol, quantity in positions.items()
        )
        total_exposure = sum(
            max(quantity, 0) * float((market_snapshots.get(position_symbol) or {}).get("price") or 0)
            for position_symbol, quantity in positions.items()
        )
        quantity = 0
        if reason == "accepted" and side == "buy":
            position_cap = equity * float(max_position_pct) / 100
            total_cap_remaining = max(equity * float(max_total_exposure_pct) / 100 - total_exposure, 0)
            notional_cap = min(position_cap, total_cap_remaining, cash)
            quantity = int(notional_cap // price)
            if quantity <= 0:
                reason = "risk_cap_allows_no_shares"
        elif reason == "accepted" and side == "sell":
            quantity = positions.get(symbol, 0)

        decision = {
            "role": "trading_risk_manager",
            "at": published.isoformat(),
            "disclosure_id": record["id"],
            "ticker": symbol,
            "decision": "order" if reason == "accepted" else "hold",
            "reason": reason,
            "risk": {
                "price": price,
                "average_dollar_volume": average_dollar_volume,
                "max_position_pct": float(max_position_pct),
                "max_total_exposure_pct": float(max_total_exposure_pct),
                "available_cash_before": cash,
            },
        }
        if reason == "accepted":
            order_key = f"{record['id']}|{side}|{quantity}|{published.isoformat()}"
            order_id = hashlib.sha256(order_key.encode()).hexdigest()[:20]
            notional = round(quantity * price, 8)
            order = {
                "order_id": order_id,
                "origin_role": "trading_risk_manager",
                "disclosure_id": record["id"],
                "ticker": symbol,
                "side": side,
                "quantity": quantity,
                "fill_price": price,
                "notional": notional,
                "submitted_at": published.isoformat(),
                "status": "filled_fixture_replay",
            }
            if side == "buy":
                cash -= notional
                positions[symbol] = positions.get(symbol, 0) + quantity
            else:
                cash += notional
                positions[symbol] = max(positions.get(symbol, 0) - quantity, 0)
            orders.append(order)
            decision["order_id"] = order_id
        decisions.append(decision)
        trace.append(decision)

    ending_equity = cash + sum(
        quantity * float((market_snapshots.get(symbol) or {}).get("price") or 0)
        for symbol, quantity in positions.items()
    )
    return {
        "schema_version": 1,
        "as_of": ceiling.isoformat(),
        "availability_rule": "ReportDate/published_at, never TransactionDate",
        "reporting_lag_warning": "Congressional disclosures may arrive up to 45 days after the transaction.",
        "initial_cash": float(initial_cash),
        "ending_cash": cash,
        "ending_equity": ending_equity,
        "positions": positions,
        "orders": orders,
        "decisions": decisions,
        "trace": trace,
    }


def _artifact(path: Path) -> dict[str, str]:
    return {"path": str(path), "sha256": hashlib.sha256(path.read_bytes()).hexdigest()}


def write_replay_artifacts(result: dict[str, Any], output_dir: str | Path) -> dict[str, dict[str, str]]:
    output = Path(output_dir)
    output.mkdir(parents=True, exist_ok=True)
    summary_path = output / "summary.json"
    trace_path = output / "agent-trace.json"
    trades_path = output / "trades.csv"
    tearsheet_path = output / "tearsheet.html"
    summary_path.write_text(
        json.dumps({key: value for key, value in result.items() if key != "trace"}, indent=2, sort_keys=True) + "\n",
        encoding="utf-8",
    )
    trace_path.write_text(json.dumps(result["trace"], indent=2, sort_keys=True) + "\n", encoding="utf-8")
    with trades_path.open("w", encoding="utf-8", newline="") as handle:
        fieldnames = [
            "order_id",
            "origin_role",
            "disclosure_id",
            "ticker",
            "side",
            "quantity",
            "fill_price",
            "notional",
            "submitted_at",
            "status",
        ]
        writer = csv.DictWriter(handle, fieldnames=fieldnames)
        writer.writeheader()
        writer.writerows(result["orders"])
    rows = "".join(
        "<tr>"
        + "".join(
            f"<td>{html.escape(str(order[field]))}</td>"
            for field in ("ticker", "side", "quantity", "fill_price", "submitted_at")
        )
        + "</tr>"
        for order in result["orders"]
    )
    tearsheet_path.write_text(
        "<!doctype html><html><head><meta charset='utf-8'><title>Congress disclosure replay</title></head>"
        "<body><h1>Congress disclosure replay</h1>"
        f"<p>{html.escape(result['availability_rule'])}</p>"
        "<p><strong>45-day reporting-lag warning:</strong> a trade is never visible before its public disclosure.</p>"
        f"<p>Initial cash: ${result['initial_cash']:,.2f} &middot; Ending equity: ${result['ending_equity']:,.2f}</p>"
        "<table><thead><tr><th>Ticker</th><th>Side</th><th>Quantity</th><th>Price</th><th>Public time</th></tr></thead>"
        f"<tbody>{rows}</tbody></table></body></html>\n",
        encoding="utf-8",
    )
    return {
        "summary": _artifact(summary_path),
        "trace": _artifact(trace_path),
        "trades": _artifact(trades_path),
        "tearsheet": _artifact(tearsheet_path),
    }

```

Shown in full with attribution under the source's licence. Licence: GPL-3.0

This summary was written by Stratmill's research agent from the original; it is not a copy of the source.