Metadata-Version: 2.4
Name: a-ledger
Version: 0.1.0
Summary: Application-neutral double-entry ledger SDK backed by SQLite
Author: realqiyan
License-Expression: MIT
Project-URL: Homepage, https://github.com/realqiyan/a-ledger
Project-URL: Repository, https://github.com/realqiyan/a-ledger
Project-URL: Issues, https://github.com/realqiyan/a-ledger/issues
Keywords: ledger,accounting,double-entry,sqlite,bookkeeping
Classifier: Development Status :: 4 - Beta
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Office/Business :: Financial :: Accounting
Requires-Python: >=3.11
Description-Content-Type: text/markdown
License-File: LICENSE
Provides-Extra: dev
Requires-Dist: build>=1; extra == "dev"
Requires-Dist: pytest>=8; extra == "dev"
Requires-Dist: twine>=5; extra == "dev"
Dynamic: license-file

# a-ledger

`a-ledger` is an application-neutral, SQLite-backed double-entry ledger SDK.
It owns accounting primitives and persistence; calling applications own business
commands, broker integration, market calendars, projections, APIs, and pages.

## Accounting convention

- Money is stored as integer minor units; posted amounts never use `float`.
- A positive posting is a debit and a negative posting is a credit.
- Every posted transaction balances exactly to zero.
- Accounts use one of `ASSET`, `LIABILITY`, `EQUITY`, `INCOME`, or `EXPENSE`.
- Security quantities and cost lots are replayed from immutable lot events. There
  are no persisted balance or position snapshots.
- Posted transactions, postings, lots, lot events, and audit events cannot be
  updated or deleted. Corrections use linked reversal and replacement entries.
- Reservations are mutable authorization state, not accounting entries.

## Transaction ownership

The caller supplies a `sqlite3.Connection`, enables a short transaction, and
decides whether to commit or roll back. Write APIs reject calls without an active
caller-owned transaction. The SDK never calls `commit()` or `rollback()` and
never runs network or application callbacks.

```python
import sqlite3

from a_ledger import AccountCategory, Ledger, PostingDraft, TransactionDraft

connection = sqlite3.connect("application.sqlite3")
ledger = Ledger(connection)  # enables and verifies SQLite foreign keys

connection.execute("BEGIN IMMEDIATE")
ledger.install_schema()
ledger.create_portfolio("portfolio-uuid", code="main", currency="CNY")
ledger.create_account(
    "cash-account-uuid",
    portfolio_id="portfolio-uuid",
    code="ASSET:CASH",
    category=AccountCategory.ASSET,
    currency="CNY",
)
ledger.create_account(
    "capital-account-uuid",
    portfolio_id="portfolio-uuid",
    code="EQUITY:CONTRIBUTED_CAPITAL",
    category=AccountCategory.EQUITY,
    currency="CNY",
)
ledger.post(
    TransactionDraft(
        portfolio_id="portfolio-uuid",
        source_namespace="app.capital",
        idempotency_key="capital-flow-uuid",
        event_code="CAPITAL_FLOW",
        business_date="2026-08-03",
        currency="CNY",
        postings=(
            PostingDraft("cash-account-uuid", 100_00),
            PostingDraft("capital-account-uuid", -100_00),
        ),
    )
)
connection.commit()
```

## Non-goals

The package does not define trading strategies, orders, options, QMT behavior,
HTTP APIs, UI, market prices, settlement calendars, or bank/broker transfers.
Generic `event_code`, `source_type`, and JSON dimensions let each application
attach its own domain semantics without coupling those semantics to the SDK.
