/** * Crypto Tax Calculations with Neural Trader * * Demonstrates using @neural-trader/agentic-accounting-rust-core for: * - FIFO, LIFO, HIFO cost basis methods * - Capital gains calculations * - Tax lot optimization * - Multi-exchange reconciliation * - Tax report generation * * Built with native Rust bindings via NAPI for high performance */ // Accounting configuration const accountingConfig = { // Tax settings taxYear: 2024, country: 'US', shortTermRate: 0.37, // Short-term capital gains rate longTermRate: 0.20, // Long-term capital gains rate holdingPeriod: 365, // Days for long-term treatment // Cost basis methods defaultMethod: 'FIFO', // FIFO, LIFO, HIFO, or SPEC_ID allowMethodSwitch: true, // Exchanges to reconcile exchanges: ['Coinbase', 'Binance', 'Kraken', 'FTX'], // Reporting generateForms: ['8949', 'ScheduleD'] }; // Sample transaction data const sampleTransactions = [ // Bitcoin purchases { date: '2024-01-15', type: 'BUY', symbol: 'BTC', quantity: 0.5, price: 42500, exchange: 'Coinbase', fee: 21.25 }, { date: '2024-02-20', type: 'BUY', symbol: 'BTC', quantity: 0.3, price: 51200, exchange: 'Binance', fee: 15.36 }, { date: '2024-03-10', type: 'BUY', symbol: 'BTC', quantity: 0.2, price: 68000, exchange: 'Kraken', fee: 13.60 }, // Bitcoin sales { date: '2024-06-15', type: 'SELL', symbol: 'BTC', quantity: 0.4, price: 65000, exchange: 'Coinbase', fee: 26.00 }, { date: '2024-11-25', type: 'SELL', symbol: 'BTC', quantity: 0.3, price: 95000, exchange: 'Binance', fee: 28.50 }, // Ethereum purchases { date: '2024-01-20', type: 'BUY', symbol: 'ETH', quantity: 5.0, price: 2400, exchange: 'Coinbase', fee: 12.00 }, { date: '2024-04-05', type: 'BUY', symbol: 'ETH', quantity: 3.0, price: 3200, exchange: 'Kraken', fee: 9.60 }, // Ethereum sales { date: '2024-08-15', type: 'SELL', symbol: 'ETH', quantity: 4.0, price: 2800, exchange: 'Coinbase', fee: 11.20 }, // Staking rewards (income) { date: '2024-03-01', type: 'INCOME', symbol: 'ETH', quantity: 0.05, price: 3400, exchange: 'Coinbase', income_type: 'staking' }, { date: '2024-06-01', type: 'INCOME', symbol: 'ETH', quantity: 0.05, price: 3600, exchange: 'Coinbase', income_type: 'staking' }, { date: '2024-09-01', type: 'INCOME', symbol: 'ETH', quantity: 0.05, price: 2500, exchange: 'Coinbase', income_type: 'staking' }, { date: '2024-12-01', type: 'INCOME', symbol: 'ETH', quantity: 0.05, price: 3800, exchange: 'Coinbase', income_type: 'staking' }, // Swap transaction { date: '2024-07-20', type: 'SWAP', from_symbol: 'ETH', from_quantity: 1.0, to_symbol: 'BTC', to_quantity: 0.045, exchange: 'Binance', fee: 5.00 } ]; async function main() { console.log('='.repeat(70)); console.log('Crypto Tax Calculations - Neural Trader'); console.log('='.repeat(70)); console.log(); // 1. Load transactions console.log('1. Loading Transactions:'); console.log('-'.repeat(70)); console.log(` Tax Year: ${accountingConfig.taxYear}`); console.log(` Transactions: ${sampleTransactions.length}`); console.log(` Exchanges: ${accountingConfig.exchanges.join(', ')}`); console.log(` Cost Basis: ${accountingConfig.defaultMethod}`); console.log(); // 2. Transaction summary console.log('2. Transaction Summary by Type:'); console.log('-'.repeat(70)); const typeCounts = {}; sampleTransactions.forEach(tx => { typeCounts[tx.type] = (typeCounts[tx.type] || 0) + 1; }); Object.entries(typeCounts).forEach(([type, count]) => { console.log(` ${type.padEnd(10)}: ${count} transactions`); }); console.log(); // 3. Calculate cost basis (FIFO) console.log('3. Cost Basis Calculation (FIFO):'); console.log('-'.repeat(70)); const fifoResults = calculateCostBasis(sampleTransactions, 'FIFO'); displayCostBasisResults('FIFO', fifoResults); // 4. Calculate cost basis (LIFO) console.log('4. Cost Basis Calculation (LIFO):'); console.log('-'.repeat(70)); const lifoResults = calculateCostBasis(sampleTransactions, 'LIFO'); displayCostBasisResults('LIFO', lifoResults); // 5. Calculate cost basis (HIFO) console.log('5. Cost Basis Calculation (HIFO):'); console.log('-'.repeat(70)); const hifoResults = calculateCostBasis(sampleTransactions, 'HIFO'); displayCostBasisResults('HIFO', hifoResults); // 6. Method comparison console.log('6. Cost Basis Method Comparison:'); console.log('-'.repeat(70)); console.log(' Method | Total Gains | Short-Term | Long-Term | Tax Owed'); console.log('-'.repeat(70)); const methods = ['FIFO', 'LIFO', 'HIFO']; const results = [fifoResults, lifoResults, hifoResults]; results.forEach((result, i) => { const taxOwed = result.shortTermGains * accountingConfig.shortTermRate + result.longTermGains * accountingConfig.longTermRate; console.log(` ${methods[i].padEnd(6)} | $${result.totalGains.toLocaleString().padStart(12)} | $${result.shortTermGains.toLocaleString().padStart(11)} | $${result.longTermGains.toLocaleString().padStart(11)} | $${Math.round(taxOwed).toLocaleString().padStart(8)}`); }); console.log(); // Find optimal method const taxAmounts = results.map((r, i) => r.shortTermGains * accountingConfig.shortTermRate + r.longTermGains * accountingConfig.longTermRate ); const minTaxIdx = taxAmounts.indexOf(Math.min(...taxAmounts)); const maxTaxIdx = taxAmounts.indexOf(Math.max(...taxAmounts)); console.log(` Optimal Method: ${methods[minTaxIdx]} (saves $${Math.round(taxAmounts[maxTaxIdx] - taxAmounts[minTaxIdx]).toLocaleString()} vs ${methods[maxTaxIdx]})`); console.log(); // 7. Tax lot details console.log('7. Tax Lot Details (FIFO):'); console.log('-'.repeat(70)); console.log(' Sale Date | Asset | Qty | Proceeds | Cost Basis | Gain/Loss | Term'); console.log('-'.repeat(70)); fifoResults.lots.forEach(lot => { const term = lot.holdingDays >= accountingConfig.holdingPeriod ? 'Long' : 'Short'; const gainStr = lot.gain >= 0 ? `$${lot.gain.toLocaleString()}` : `-$${Math.abs(lot.gain).toLocaleString()}`; console.log(` ${lot.saleDate} | ${lot.symbol.padEnd(5)} | ${lot.quantity.toFixed(4).padStart(6)} | $${lot.proceeds.toLocaleString().padStart(11)} | $${lot.costBasis.toLocaleString().padStart(11)} | ${gainStr.padStart(12)} | ${term}`); }); console.log(); // 8. Income summary (staking) console.log('8. Crypto Income Summary:'); console.log('-'.repeat(70)); const incomeTransactions = sampleTransactions.filter(tx => tx.type === 'INCOME'); let totalIncome = 0; console.log(' Date | Asset | Qty | FMV Price | Income'); console.log('-'.repeat(70)); incomeTransactions.forEach(tx => { const income = tx.quantity * tx.price; totalIncome += income; console.log(` ${tx.date} | ${tx.symbol.padEnd(5)} | ${tx.quantity.toFixed(4).padStart(7)} | $${tx.price.toLocaleString().padStart(8)} | $${income.toFixed(2).padStart(8)}`); }); console.log('-'.repeat(70)); console.log(` Total Staking Income: $${totalIncome.toFixed(2)}`); console.log(` Tax on Income (${(accountingConfig.shortTermRate * 100)}%): $${(totalIncome * accountingConfig.shortTermRate).toFixed(2)}`); console.log(); // 9. Remaining holdings console.log('9. Remaining Holdings:'); console.log('-'.repeat(70)); const holdings = calculateRemainingHoldings(sampleTransactions, fifoResults); console.log(' Asset | Qty | Avg Cost | Current Value | Unrealized G/L'); console.log('-'.repeat(70)); Object.entries(holdings).forEach(([symbol, data]) => { const currentPrice = symbol === 'BTC' ? 98000 : 3900; // Current prices const currentValue = data.quantity * currentPrice; const unrealizedGL = currentValue - data.totalCost; const glStr = unrealizedGL >= 0 ? `$${unrealizedGL.toLocaleString()}` : `-$${Math.abs(unrealizedGL).toLocaleString()}`; console.log(` ${symbol.padEnd(5)} | ${data.quantity.toFixed(4).padStart(9)} | $${data.avgCost.toFixed(2).padStart(9)} | $${currentValue.toLocaleString().padStart(13)} | ${glStr.padStart(14)}`); }); console.log(); // 10. Form 8949 preview console.log('10. Form 8949 Preview (Part I - Short-Term):'); console.log('-'.repeat(70)); generateForm8949(fifoResults, accountingConfig); console.log(); // 11. Export options console.log('11. Export Options:'); console.log('-'.repeat(70)); console.log(' Available export formats:'); console.log(' - Form 8949 (IRS)'); console.log(' - Schedule D (IRS)'); console.log(' - CSV (for tax software)'); console.log(' - TurboTax TXF'); console.log(' - CoinTracker format'); console.log(' - Koinly format'); console.log(); console.log('='.repeat(70)); console.log('Crypto tax calculation completed!'); console.log('='.repeat(70)); } // Calculate cost basis using specified method function calculateCostBasis(transactions, method) { const lots = []; const inventory = {}; // { symbol: [{ date, quantity, price, remaining }] } let totalGains = 0; let shortTermGains = 0; let longTermGains = 0; // Process transactions in order const sortedTx = [...transactions].sort((a, b) => new Date(a.date) - new Date(b.date)); for (const tx of sortedTx) { const symbol = tx.symbol; if (tx.type === 'BUY' || tx.type === 'INCOME') { // Add to inventory if (!inventory[symbol]) inventory[symbol] = []; inventory[symbol].push({ date: tx.date, quantity: tx.quantity, price: tx.price + (tx.fee || 0) / tx.quantity, // Include fees in cost basis remaining: tx.quantity }); } else if (tx.type === 'SELL') { // Match against inventory based on method let remaining = tx.quantity; const proceeds = tx.quantity * tx.price - (tx.fee || 0); while (remaining > 0 && inventory[symbol]?.length > 0) { // Select lot based on method let lotIndex = 0; if (method === 'LIFO') { lotIndex = inventory[symbol].length - 1; } else if (method === 'HIFO') { lotIndex = inventory[symbol].reduce((maxIdx, lot, idx, arr) => lot.price > arr[maxIdx].price ? idx : maxIdx, 0); } // FIFO uses index 0 const lot = inventory[symbol][lotIndex]; const matchQty = Math.min(remaining, lot.remaining); // Calculate gain/loss const costBasis = matchQty * lot.price; const lotProceeds = (matchQty / tx.quantity) * proceeds; const gain = lotProceeds - costBasis; // Determine holding period const buyDate = new Date(lot.date); const sellDate = new Date(tx.date); const holdingDays = Math.floor((sellDate - buyDate) / (1000 * 60 * 60 * 24)); lots.push({ symbol, quantity: matchQty, buyDate: lot.date, saleDate: tx.date, proceeds: Math.round(lotProceeds), costBasis: Math.round(costBasis), gain: Math.round(gain), holdingDays }); totalGains += gain; if (holdingDays >= accountingConfig.holdingPeriod) { longTermGains += gain; } else { shortTermGains += gain; } // Update inventory lot.remaining -= matchQty; remaining -= matchQty; if (lot.remaining <= 0) { inventory[symbol].splice(lotIndex, 1); } } } else if (tx.type === 'SWAP') { // Treat as sell of from_symbol and buy of to_symbol // (Simplified - real implementation would match lots) } } return { method, lots, totalGains: Math.round(totalGains), shortTermGains: Math.round(shortTermGains), longTermGains: Math.round(longTermGains) }; } // Display cost basis results function displayCostBasisResults(method, results) { console.log(` Method: ${method}`); console.log(` Total Realized Gains: $${results.totalGains.toLocaleString()}`); console.log(` Short-Term Gains: $${results.shortTermGains.toLocaleString()}`); console.log(` Long-Term Gains: $${results.longTermGains.toLocaleString()}`); console.log(` Dispositions: ${results.lots.length}`); console.log(); } // Calculate remaining holdings function calculateRemainingHoldings(transactions, costBasisResults) { const holdings = {}; // Track all purchases transactions.forEach(tx => { if (tx.type === 'BUY' || tx.type === 'INCOME') { if (!holdings[tx.symbol]) { holdings[tx.symbol] = { quantity: 0, totalCost: 0 }; } holdings[tx.symbol].quantity += tx.quantity; holdings[tx.symbol].totalCost += tx.quantity * tx.price; } }); // Subtract sold quantities costBasisResults.lots.forEach(lot => { holdings[lot.symbol].quantity -= lot.quantity; holdings[lot.symbol].totalCost -= lot.costBasis; }); // Calculate average cost Object.keys(holdings).forEach(symbol => { if (holdings[symbol].quantity > 0.0001) { holdings[symbol].avgCost = holdings[symbol].totalCost / holdings[symbol].quantity; } else { delete holdings[symbol]; } }); return holdings; } // Generate Form 8949 preview function generateForm8949(results, config) { const shortTermLots = results.lots.filter(l => l.holdingDays < config.holdingPeriod); const longTermLots = results.lots.filter(l => l.holdingDays >= config.holdingPeriod); console.log(' (a) Description | (b) Date Acq | (c) Date Sold | (d) Proceeds | (e) Cost | (h) Gain'); console.log('-'.repeat(70)); shortTermLots.slice(0, 5).forEach(lot => { const gainStr = lot.gain >= 0 ? `$${lot.gain.toLocaleString()}` : `($${Math.abs(lot.gain).toLocaleString()})`; console.log(` ${(lot.quantity.toFixed(4) + ' ' + lot.symbol).padEnd(18)} | ${lot.buyDate} | ${lot.saleDate} | $${lot.proceeds.toLocaleString().padStart(10)} | $${lot.costBasis.toLocaleString().padStart(6)} | ${gainStr.padStart(8)}`); }); if (shortTermLots.length > 5) { console.log(` ... and ${shortTermLots.length - 5} more short-term transactions`); } console.log(); console.log(` Part II - Long-Term: ${longTermLots.length} transactions`); } // Run the example main().catch(console.error);