Слои налогового учёта: от ledger до Form 8949 — Блог
$ cat sloi-nalogovogo-uchyota-ot-ledger-do-form-8949.md

Слои налогового учёта: от ledger до Form 8949

Слои налогового учёта: от ledger до Form 8949

Семь скиллов про учёт трейдинга и налоги выглядят как явное дублирование, но на самом деле это спроектированная иерархия слоёв: compute → tax → decision → output. Два из них действительно можно безопасно объединить, остальные пять занимают разные ниши в pipeline.


Контекст: 7 скиллов, 4 слоя

В коллекции лежат семь скиллов, связанных с учётом сделок и налогами. На первый взгляд — дублирование: и trade-accounting, и tax-liability-tracking, и cost-basis-engine умеют считать P&L. Но если посмотреть на входы, выходы и guarantees, видно чёткую иерархию:

┌─────────────────────────┐
│ trade-accounting        │  Слой 1: двойная запись, общий бизнес-учёт
│ (P&L, balance sheet,    │         (для любого бизнеса, не только трейдинг)
│  cash flow)             │
└──────────┬──────────────┘

┌─────────────────────────┐
│ cost-basis-engine       │  Слой 2: compute — 5 методов
│ (FIFO, LIFO, HIFO,      │         (чистая функция: дата, символ, кол-во → basis)
│  Specific ID, Average)  │
└──────────┬──────────────┘
           ▼ импортируется
┌─────────────────────────┐
│ tax-liability-tracking  │  Слой 3: tax layer
│ (real-time tax ledger,  │         (берёт cost-basis, добавляет short/long-term,
│  gain classification)   │          quarterly projections, tax-aware signals)
└──────────┬──────────────┘
           ▼ вызывает
┌─────────────────────────┐
│ tax-loss-harvesting     │  Слой 4: decision layer
│ (TLH opportunity        │         (анализирует tax-layer, ищет harvesting
│  scoring, 61-day        │          opportunities, учитывает wash-sale risk)
│  window)                │
└─────┬───────────────────┘
      │ вызывает

┌─────────────────────────┐
│ wash-sale-detection     │  Слой 4a: scanner (вложен в TLH)
│ (61-day window,         │         (один конкретный риск, может быть
│  basis adjustment)      │          standalone или модулем внутри TLH)
└─────────────────────────┘

┌─────────────────────────┐
│ crypto-tax-export       │  Слой 5: output layer
│ (Koinly, CoinTracker,   │         (берёт данные из всех вышестоящих,
│  CoinLedger, Form 8949) │          генерит CSVs в формат провайдеров)
└─────────────────────────┘
┌─────────────────────────┐
│ regulatory-reporting    │  Слой 5a: STUB, дублирует Form 8949
│ (только Form 8949)      │         (→ MERGE в crypto-tax-export)
└─────────────────────────┘

Эта иерархия не случайна — она отражает нормальную архитектуру учётной системы: raw events → normalized compute → tax classification → decision logic → export.

Состав кластера

trade-accounting (двойная запись, 365 строк)

Универсальный скилл двойной записи для любого бизнеса, не только трейдинга. Содержит:

  • trading_ledger.py — реализация debit/credit с проверкой баланса
  • P&L statement, balance sheet, cash flow
  • Multi-currency support

Уникален тем, что это общий учёт, а не налоговый. Подходит для LLC, фрилансера, любого бизнеса с регулярными транзакциями.

cost-basis-engine (5 методов, 358 строк)

Чистый compute layer: принимает список сделок (buy/sell), возвращает cost basis по каждому sell. Без знаний о налогах, без UI, без decision logic. Просто функции:

  • FIFO (First In, First Out) — дефолт IRS для stocks, обязателен для crypto
  • LIFO (Last In, First Out) — минимизирует taxable gain на растущем рынке
  • HIFO (Highest In, First Out) — оптимален для tax-loss harvesting
  • Specific Identification — выбираете конкретные лоты (нужна документация на момент покупки)
  • Proportional Average — средневзвешенная (разрешена IRS только для mutual funds)

Уникален тем, что реализует все 5 методов с unit-тестами на edge cases (partial sells, corporate actions, splits).

tax-liability-tracking (real-time, 221 строка)

Tax layer поверх cost-basis: импортирует cost-basis-engine, добавляет:

  • Short-term vs long-term classification (≥365 дней)
  • Quarterly estimated tax projections
  • Tax-aware trading signals (предупреждает: «эта сделка создаст short-term gain»)
  • Real-time P&L с уже учтённым налогом

Уникален тем, что это real-time: при каждой новой сделке пересчитывает годовой projection и предупреждает о превышении порога.

tax-loss-harvesting (decision layer, 294 строки)

Ищет opportunities для tax-loss harvesting: позиции в убытке, продажа которых создаст deductible loss. Scoring учитывает:

  • Величину убытка
  • Wash-sale risk (61-day window, controlled substances)
  • Carryforward от прошлых лет
  • Replacement security logic (что купить вместо)

Артефакт: список ranked opportunities с конкретными суммами.

wash-sale-detection (scanner, 200 строк)

Узкий scanner для одного конкретного правила IRS: если вы продали в убытке и в течение 30 дней до/после купили «substantially identical» security, убыток disallow’ится. Скилл:

  • Сканирует портфель на 61-day window (30 до + 30 после + 1 день сделки)
  • Считает basis adjustment (disallowed loss добавляется к basis replacement security)
  • Safe re-entry countdown (когда можно купить обратно без wash-sale)

crypto-tax-export (output, 267 строк)

Output layer: берёт данные из cost-basis + tax-liability, генерит CSVs в форматах:

  • Koinly (Universal CSV)
  • CoinTracker (Universal CSV)
  • CoinLedger (Universal CSV)
  • TokenTax (Universal CSV)
  • IRS Form 8949 (line items: (a) description, (b) date acquired, (c) date sold, (d) proceeds, (e) cost basis, (h) gain/loss)

Уникален тем, что понимает Solana transactions: умеет классифицировать swaps, transfers, liquidity events, NFT mints.

regulatory-reporting (STUB, 196 строк)

Помечен как [STUB]. Содержит form_8949_generator.py, который генерит ровно ту же Form 8949, что и crypto-tax-export. Дубликат по сути.

Задачи, которые они покрывают

Типичный день трейдера с обязательствами по налогам:

  1. «Запиши мне эту сделку»trade-accounting (двойная запись)
  2. «Какой у меня cost basis по RELIANCE?»cost-basis-engine (FIFO/HIFO/etc.)
  3. «Сколько я должен заплатить налогов за Q3?»tax-liability-tracking (projection)
  4. «Что мне стоит продать в убыток до 31 декабря?»tax-loss-harvesting (opportunities)
  5. «Если я продам AAPL в убытке сейчас, можно ли купить обратно через 2 недели?»wash-sale-detection (safe re-entry)
  6. «Сгенерируй мне файл для Koinly»crypto-tax-export (output)

Каждый скилл решает свою задачу на своём слое.

Метод: что общего и что уникально

Принцип 1: импорт сверху вниз, не дублирование

Правильная архитектура:

# tax-liability-tracking импортирует cost-basis
from cost_basis_engine import calculate_basis, FIFOMethod, HIFOMethod

# tax-loss-harvesting импортирует tax-liability
from tax_liability import TaxLedger

# crypto-tax-export импортирует tax-liability
from tax_liability import TaxLedger

Реальное дублирование возникает только когда скиллы не импортируют друг друга, а копипастят логику. И именно это происходит в двух местах:

  1. tax-liability-tracking имеет свою реализацию FIFO/LIFO/Specific ID (а не импортирует из cost-basis-engine)
  2. regulatory-reporting имеет свою Form 8949 генерацию (а не использует crypto-tax-export)

Принцип 2: wash_sale_risk — это параметр, а не отдельный скилл

В tax-loss-harvesting уже есть wash_sale_risk: float как scoring parameter. wash-sale-detection — это детальная реализация одного аспекта, который TLH использует. Сейчас TLH вызывает wash-sale-detection как модуль, но исторически они разрабатывались отдельно.

Уникальные знания в каждом скилле

cost-basis-engine (тонкости IRS)

  • Wash-sale adjustment math: disallowed loss = min(realized_loss, replacement_cost) — это не интуитивно
  • Crypto-specific gotchas: при staking rewards, airdrops, hard forks — что считать basis? (IRS Notice 2014-21)
  • Corporate actions: при split или merger старый cost basis переходит на новые акции, нужно пересчитать
  • Method switch: IRS не позволяет «переключаться» между методами retroactively, выбор делается в момент sell

tax-loss-harvesting (scoring formula)

Уникальная scoring formula для ranking opportunities:

TLH_score = |unrealized_loss| × tax_rate × (1 - wash_sale_risk) + carryforward_value

Это ad-hoc формула, не из IRS guidelines. Чем выше score, тем приоритетнее opportunity.

wash-sale-detection (61-day window math)

Уникальные знания:

  • 61-day window = 30 days before + day of sale + 30 days after (не 60!)
  • Spousal accounts: IRS считает вас и супруга/у за «one taxpayer» — покупка супруга тоже триггерит wash-sale
  • Options & futures: покупка call option на ту же security — это wash-sale, даже если акцию не покупали
  • Safe harbors: dividend reinvestment plans (DRIP) в IRA не триггерят wash-sale (Pub 550)

crypto-tax-export (Solana tx classification)

  • Token swaps на Raydium/Orca классифицируются как taxable event, даже если это «просто обмен токенов»
  • Liquidity provision: добавление в LP — не taxable; remove — taxable на долю fees
  • NFT mints создают basis по mint price; airdrops создают ordinary income по fair market value
  • Bridge transactions (Solana → Ethereum) — это transfer, не taxable; но swap перед bridge — taxable

Рекомендация по объединению

✅ MERGE 1: regulatory-reporting → crypto-tax-export

crypto-tax-export уже генерит Form 8949 (один из форматов экспорта). regulatory-reporting дублирует эту логику. Без потерьregulatory-reporting папка удаляется, её form_8949_generator.py сливается с crypto-tax-export (или просто удаляется, если дубликат 1:1).

✅ MERGE 2: wash-sale-detection → tax-loss-harvesting (как модуль)

TLH уже включает wash_sale_risk как scoring parameter. wash-sale-detection можно:

  • Вариант A (merge): удалить отдельный скилл, добавить wash_sale.py как модуль внутри tax-loss-harvesting/scripts/
  • Вариант B (оставить, но перелинковать): добавить в TLH description явный handoff на wash-sale-detection

Вариант A чище, но требует рефакторинга TLH. Вариант B — zero-risk.

🟡 DEDUP: cost-basis-engine ↔ tax-liability-tracking

Не merge, но важно: убедиться, что tax-liability-tracking импортирует cost-basis-engine, а не имеет свою реализацию FIFO/LIFO. Если дубликат есть — вычистить.

Что НЕЛЬЗЯ объединять (и почему)

trade-accounting + tax-liability-tracking

trade-accounting — общий бизнес-учёт, не только трейдинг. У него другие use-cases (баланс, cash flow, multi-currency). Если слить — раздуется до 600+ строк, потеряется фокус.

cost-basis-engine + tax-liability-tracking

cost-basis-engineчистая функция (compute layer). tax-liability-trackingstateful ledger с quarter projections. Разные guarantees, разные входы. Cost-basis можно вызвать на списке сделок один раз, tax-liability — это persistent state на весь год.

tax-loss-harvesting + wash-sale-detection (если выбран вариант B)

Если оставлять как отдельные скиллы, TLH — это opportunity finder (ranking, scoring), wash-sale — это rule checker (конкретный IRS rule). Разные входы, разные артефакты. Hand-off явный: TLH находит кандидата, wash-sale проверяет, не нарушим ли мы 61-day window.


Итоги

Из 7 скиллов кластера 2 можно безопасно объединить (regulatory-reporting → crypto-tax-export, wash-sale-detection → tax-loss-harvesting), и 1 dedup-задача (cost-basis ↔ tax-liability). Остальные 4 — это намеренно разделённые слои с разными guarantees: compute / stateful ledger / decision / output.

Главный инсайт: если у вас много скиллов на одну тему, проверьте, не пишут ли они одни и те же функции заново, вместо того чтобы импортировать. Если пишут — это кандидат на merge. Если импортируют — это здоровая иерархия слоёв, и её не надо трогать.


Ссылки