Quant Trading for Programmers 38: Index Daily Report Archives
· 12 min read · Views --
Last updated on

Quant Trading for Programmers 38: Index Daily Report Archives

Author: Alex Xiang


Quant Trading for Programmers 38: Index Daily Report Archives

Article 32 already wrote daily-run results into JSON. Article 33 added a simple historical summary.

Article 38 fills in a small tool between them: indexing the archive directory. Later, whether we build a CLI list, a page list, or a manual debugging view, the caller should not rewrite glob and JSON-reading logic every time.

ZiCode engineer inspecting a daily report archive index

What An Index Entry Contains

The daily report index does not need to copy the full report. It keeps only the fields a list page really needs.

FieldMeaning
trade_dateTrading day
statusHealth status for the day
pathArchive file path

The full report still lives in the JSON file and is read only when details are needed.

Index Object

Article 38 adds app/report_index.py.

@dataclass(frozen=True)
class ReportIndexEntry:
    trade_date: str
    status: str
    path: Path

This object can later feed a command-line table directly, or a simple web page.

Scan The Archive Directory

The implementation reuses the reader from article 32.

for path in sorted(Path(directory).glob("*-paper-report.json")):
    payload = read_archived_report(path)
    entries.append(
        ReportIndexEntry(
            trade_date=payload["trade_date"],
            status=payload["health"]["status"],
            path=path,
        )
    )

Sorting is based on file name. The archive file name starts with the trading date, so this order is stable and intuitive.

Get The Latest Report

When the index is empty, the helper returns None instead of forcing callers to handle index errors.

def latest_report_entry(entries: tuple[ReportIndexEntry, ...]) -> ReportIndexEntry | None:
    if not entries:
        return None
    return entries[-1]

Small functions like this look trivial, but they remove many repeated checks in production code.

Runnable Example

paper-run-plan writes three days of daily report archives into a temporary directory, then builds an index:

uv run python -m scripts.chapter_examples paper-run-plan

Report archive index generated by paper-run-plan

The index contains records for 2026-03-04, 2026-03-05, and 2026-03-06, with the middle day marked as blocker. The index does not read full report bodies. It keeps the minimum fields needed for list pages and debugging entry points.

Test Index Order

Run:

uv run pytest tests/test_report_index.py tests/test_report_archive.py tests/test_run_history.py

Key assertions:

assert [entry.trade_date for entry in entries] == ["2026-02-05", "2026-02-06"]
assert [entry.status for entry in entries] == ["ok", "blocker"]
assert latest_report_entry(entries) == entries[-1]

This proves the index can list archived reports in stable order and pick the latest entry.

Repository

This article adds:

  • app/report_index.py;
  • ReportIndexEntry;
  • report-index generation from an archive directory;
  • latest_report_entry();
  • paper-run-plan linked example, showing how three days of archive files become a queryable index;
  • tests/test_report_index.py, covering index order and empty index.

Repository:

https://github.com/ax2/zi-quant-platform

Code for this chapter:

git clone https://github.com/ax2/zi-quant-platform.git
cd zi-quant-platform
git checkout chapter-38
uv sync --extra dev
uv run pytest tests/test_report_index.py tests/test_report_archive.py tests/test_run_history.py

The article 38 commit is 6d848ce, and the tag is chapter-38.

Summary

Once daily report archives have an index, historical files are no longer loose JSON scattered in a directory.

Article 38 extracts trade date, status, and path into a lightweight list. The next article handles blocked results: after checks fail, the system should provide a clear remediation action instead of only saying that it failed.