Cost Basis & Tax Lots
Track asset acquisitions as tax lots, select lots on disposal, and compute realized gains and losses.
Overview
When an entity acquires lot-tracked assets (equities, crypto, commodities), each acquisition is recorded as a tax lot — a record of the quantity, cost basis, and acquisition date. When those assets are later disposed of (sold, exchanged, or transferred out), the system selects which lots to consume and computes the realized gain or loss based on the difference between proceeds and cost basis.
Axiomatic supports three modes of lot creation and multiple lot selection methods, so it adapts to both broker-managed environments (traditional equities) and self-custody environments (crypto).
Lot Creation Modes
| Mode | Source | Method | When used |
|---|---|---|---|
| Native | NATIVE | ONCHAIN | Lots created automatically by the posting engine when it processes acquisition events (e.g. crypto_received, investment_made) |
| Imported | IMPORTED | BROKER_REPORTED | Lots imported from broker data (1099-B, CSV exports). Supports both open and already-disposed lots |
| Manual | MANUAL | USER_ENTERED | Lots created by the user through the Tax Lots UI for assets not covered by automation |
Native lots
When the posting engine processes an event that is classified as a lot acquisition event (e.g. crypto_received, investment_made, token_purchase), it automatically calls createLot() after the journal entry is created. The lot's cost basis is derived from the event payload's amount and quantity fields.
Imported lots
Broker-reported lots are imported via the API:
POST /api/tax-lots
{
"action": "import",
"entityId": "...",
"bookId": "...",
"brokerName": "Robinhood",
"lots": [
{
"asset": "AAPL",
"assetType": "EQUITY",
"quantity": "100",
"costBasis": "15000.00",
"acquiredDate": "2024-03-15"
},
{
"asset": "AAPL",
"assetType": "EQUITY",
"quantity": "50",
"costBasis": "8500.00",
"acquiredDate": "2024-01-10",
"disposedDate": "2024-11-20",
"proceeds": "9200.00"
}
]
}When disposedDate and proceeds are provided, the lot is created as FULLY_DISPOSED and a corresponding disposal record is inserted with the realized gain/loss already computed.
This is the recommended path for traditional brokerage accounts where the broker determines lot selection and reports results on tax forms.
Manual lots
Users can create lots manually through the Tax Lots inventory page for edge cases not covered by automation or imports.
Lot Selection Methods
When assets are disposed of, the system must decide which lots to consume. The method is configured per book via the costBasisMethod field:
| Method | Behavior |
|---|---|
| FIFO | First In, First Out — oldest lots are consumed first |
| LIFO | Last In, First Out — newest lots are consumed first |
| HIFO | Highest In, First Out — lots with the highest cost basis per unit are consumed first (tax-optimizing) |
| SPECIFIC | User selects exactly which lots to consume via the lot picker UI |
| WEIGHTED_AVERAGE | All open lots for the asset are averaged into a single effective cost basis per unit |
The default method for new books is FIFO.
Disposal flow
When the posting engine processes a lot disposal event (e.g. crypto_sent, investment_sold), it:
- Finds all open lots for the asset in the book
- Sorts them according to the book's
costBasisMethod - Consumes lots in order until the disposal quantity is fulfilled
- Creates
lot_disposalsrecords for each consumed lot (or portion) - Computes
realizedGainLoss = totalProceeds - costBasisDisposedfor each disposal - Determines holding period (short-term if held < 1 year, long-term otherwise)
- Appends realized gain/loss journal lines to the journal entry
Partial lot consumption
A single lot can be partially consumed across multiple disposals. The remainingQuantity field tracks how much is left. A lot's status transitions from OPEN → PARTIALLY_DISPOSED → FULLY_DISPOSED as its remaining quantity decreases.
Holding Period
The holding period is determined automatically based on the time between acquisition and disposal:
- Short-term: held for less than one year (≤ 365 days)
- Long-term: held for one year or more (> 365 days)
This classification affects tax treatment — long-term gains are typically taxed at lower rates.
Tax Lots UI
The Tax Lots page (/tax-lots) provides:
- Summary cards — total realized gain/loss, short-term vs. long-term breakdown, and total disposals count
- By Asset tab — per-asset summary showing total quantity, remaining quantity, cost basis, and open/disposed lot counts
- All Lots tab — full inventory of every tax lot with status, quantities, and cost basis details
- Disposals tab — history of all disposals with proceeds, gain/loss, and holding period
- Record Disposal — modal form for manually recording a disposal, with lot picker for SPECIFIC identification method
Data Model
tax_lots
| Column | Type | Description |
|---|---|---|
id | uuid | Primary key |
entity_id | uuid | Owning entity |
book_id | uuid | Owning book |
asset | text | Asset symbol (e.g. ETH, AAPL) |
asset_type | enum | EQUITY, CRYPTO, FIXED_INCOME, COMMODITY, DERIVATIVE, REAL_ESTATE, OTHER |
quantity | decimal | Original acquisition quantity |
remaining_quantity | decimal | Quantity not yet disposed |
cost_basis_per_unit | decimal | Per-unit acquisition cost |
total_cost_basis | decimal | Total cost (quantity × per-unit cost) |
acquired_date | date | Acquisition date |
source | enum | NATIVE, IMPORTED, MANUAL |
method | enum | ONCHAIN, BROKER_REPORTED, USER_ENTERED |
status | enum | OPEN, PARTIALLY_DISPOSED, FULLY_DISPOSED |
event_id | uuid | Originating event (nullable) |
external_ref | text | Broker lot reference (nullable) |
lot_disposals
| Column | Type | Description |
|---|---|---|
id | uuid | Primary key |
lot_id | uuid | FK to tax_lots |
entity_id | uuid | Owning entity |
book_id | uuid | Owning book |
quantity_disposed | decimal | Quantity consumed from the lot |
proceeds_per_unit | decimal | Sale price per unit |
total_proceeds | decimal | Total sale proceeds |
cost_basis_disposed | decimal | Cost basis of the consumed quantity |
realized_gain_loss | decimal | Proceeds minus cost basis |
holding_period | enum | SHORT_TERM or LONG_TERM |
disposal_date | date | Date of disposal |
method | enum | Selection method used (FIFO, LIFO, etc.) |
event_id | uuid | Originating event (nullable) |
books.cost_basis_method
The cost_basis_method column on the books table sets the default lot selection method for the book. Values: FIFO, LIFO, HIFO, SPECIFIC, WEIGHTED_AVERAGE. Defaults to FIFO.
Tax Reporting
Axiomatic generates IRS-format capital gains reports from lot disposal data.
Schedule D
The Schedule D report (/api/tax-reports?report=schedule_d) summarizes capital gains and losses for a tax year, split into:
- Part I — Short-term capital gains and losses (assets held one year or less)
- Part II — Long-term capital gains and losses (assets held more than one year)
Each part shows total proceeds, total cost basis, and net gain/loss. A summary section shows the combined net capital gain or loss.
Form 8949
The Form 8949 report (/api/tax-reports?report=form_8949) provides per-disposal detail rows with:
- Description (quantity and asset symbol)
- Date acquired
- Date sold or disposed
- Proceeds (sale price)
- Cost or other basis
- Gain or loss
Rows are grouped by holding period (short-term vs. long-term).
PDF Export
The Schedule D report supports PDF export via format=pdf. The generated PDF includes headers with entity name, tax year, and book type, and is formatted for print or filing.
API
GET /api/tax-reports?entityId=...&bookId=...&report=schedule_d&taxYear=2025
GET /api/tax-reports?entityId=...&bookId=...&report=schedule_d&taxYear=2025&format=pdf
GET /api/tax-reports?entityId=...&bookId=...&report=form_8949&taxYear=2025