Разработка системы формирования налоговой отчетности по крипто
Налоговая отчётность — финальный шаг в цикле крипто-учёта. Система должна преобразовать рассчитанные tax events в форматы, принимаемые налоговыми органами или готовые для передачи бухгалтеру.
Форматы по юрисдикциям
class TaxReportGenerator {
// USA: IRS Form 8949 + Schedule D
async generateUS(userId: string, taxYear: number): Promise<Buffer> {
const events = await this.getTaxEvents(userId, taxYear);
const shortTerm = events.filter(e => !e.isLongTerm && e.category === "disposal");
const longTerm = events.filter(e => e.isLongTerm && e.category === "disposal");
// Form 8949 строки
const form8949Rows = events.filter(e => e.category === "disposal").map(e => ({
description: `${e.amount} ${e.asset}`,
dateAcquired: e.acquiredAt ? format(e.acquiredAt, "MM/dd/yyyy") : "Various",
dateSold: format(e.disposedAt, "MM/dd/yyyy"),
proceeds: e.proceedsUSD.toFixed(2),
costBasis: e.costBasisUSD.toFixed(2),
adjustments: "0",
gainLoss: e.gainLossUSD.toFixed(2),
code: e.isLongTerm ? "E" : "A", // код для brokerage reported
}));
const scheduleD = {
shortTermTotal: { proceeds: sum(shortTerm, "proceedsUSD"), costBasis: sum(shortTerm, "costBasisUSD"), gainLoss: sum(shortTerm, "gainLossUSD") },
longTermTotal: { proceeds: sum(longTerm, "proceedsUSD"), costBasis: sum(longTerm, "costBasisUSD"), gainLoss: sum(longTerm, "gainLossUSD") },
};
return this.pdf.generate("form8949", { rows: form8949Rows, scheduleD, taxYear, userId });
}
// UK: HMRC Capital Gains Summary
async generateUK(userId: string, taxYear: string): Promise<Buffer> {
// UK tax year: 6 April - 5 April
const { from, to } = parseUKTaxYear(taxYear); // "2023-24"
const events = await this.getTaxEvents(userId, null, from, to);
// UK использует Section 104 pool, применяем UK rules
const ukEvents = await this.applyUKPoolingRules(events);
const summary = {
taxYear,
totalProceeds: sum(ukEvents, "proceeds"),
allowableCosts: sum(ukEvents, "costBasis"),
gainsBeforeLosses: sum(ukEvents.filter(e => e.gain > 0), "gain"),
losses: Math.abs(sum(ukEvents.filter(e => e.gain < 0), "gain")),
netGains: sum(ukEvents, "gain"),
annualExemptAmount: 6000, // UK 2023-24 annual exempt amount
taxableGain: Math.max(0, sum(ukEvents, "gain") - 6000),
};
return this.pdf.generate("hmrc_cgt", { summary, events: ukEvents, taxYear });
}
// Germany: Anlage SO
async generateGermany(userId: string, taxYear: number): Promise<Buffer> {
const events = await this.getTaxEvents(userId, taxYear);
// Германия: tax free после 1 года владения
const taxableEvents = events.filter(e => !e.isLongTerm);
const exemptEvents = events.filter(e => e.isLongTerm);
// Freigrenze €600: если все gains < €600 — не облагается
const totalGain = sum(taxableEvents.filter(e => e.gain > 0), "gain");
const exemptUnderFreigrenze = totalGain < 600;
return this.pdf.generate("anlage_so", {
taxableEvents,
exemptEvents,
totalGain,
exemptUnderFreigrenze,
taxYear,
});
}
// CSV для бухгалтера (универсальный)
async generateCSV(userId: string, taxYear: number): Promise<string> {
const events = await this.getTaxEvents(userId, taxYear);
const headers = [
"Date", "Asset", "Type", "Amount", "Proceeds USD", "Cost Basis USD",
"Gain/Loss USD", "Is Long Term", "Acquired At", "Holding Days", "Notes"
];
const rows = events.map(e => [
format(e.disposedAt, "yyyy-MM-dd"),
e.asset,
e.category,
e.amount,
e.proceedsUSD?.toFixed(2) ?? "",
e.costBasisUSD?.toFixed(2) ?? "",
e.gainLossUSD?.toFixed(2) ?? e.incomeUSD?.toFixed(2) ?? "",
e.isLongTerm ?? "",
e.acquiredAt ? format(e.acquiredAt, "yyyy-MM-dd") : "",
e.holdingDays ?? "",
e.notes ?? "",
]);
return [headers, ...rows].map(r => r.join(",")).join("\n");
}
}
Koinly-compatible export
Для пользователей кто хочет дальше импортировать в Koinly:
async function generateKoinlyCSV(transactions: UnifiedTransaction[]): Promise<string> {
const headers = ["Date", "Sent Amount", "Sent Currency", "Received Amount", "Received Currency",
"Fee Amount", "Fee Currency", "Net Worth Amount", "Net Worth Currency",
"Label", "Description", "TxHash"];
const rows = transactions.map(tx => [
format(tx.timestamp, "yyyy-MM-dd HH:mm:ss"),
tx.amountOut ?? "",
tx.assetOut ?? "",
tx.amountIn ?? "",
tx.assetIn ?? "",
tx.feeAmount ?? "",
tx.feeCurrency ?? "",
tx.valueUSD ?? "",
"USD",
mapToKoinlyLabel(tx.category),
tx.notes ?? "",
tx.txHash ?? "",
]);
return [headers, ...rows].map(r => r.join(",")).join("\n");
}
Система формирования налоговой отчётности с поддержкой IRS 8949, HMRC CGT, Anlage SO и Koinly-compatible CSV — 3-4 недели разработки.







