114 lines
2.9 KiB
JavaScript
114 lines
2.9 KiB
JavaScript
const csvToJson = require('convert-csv-to-json')
|
|
const converter = require('json-2-csv')
|
|
const fs = require('fs')
|
|
const BN = require('bignumber.js')
|
|
|
|
const txs = csvToJson.fieldDelimiter(',').getJsonFromCsv(`../Ledger.csv`)
|
|
let utxos = []
|
|
let dispositions = []
|
|
|
|
const handleBuy = (tx, i) => {
|
|
const { Date: date, Asset, Received, Price } = tx
|
|
utxos.push({
|
|
Date: date,
|
|
Id: i,
|
|
Asset,
|
|
Amount: Received,
|
|
Price,
|
|
Remaining: new BN(Received),
|
|
})
|
|
}
|
|
|
|
const createDisposition = (tx, utxo, amount) => {
|
|
const st = new Date(tx.Date).valueOf() - new Date(utxo.Date).valueOf() < 31556926000
|
|
const costBasis = amount.times(utxo.Price)
|
|
const proceeds = amount.times(tx.Price)
|
|
const gainLoss = proceeds.minus(costBasis)
|
|
const disposition = {
|
|
Date: tx.Date,
|
|
Asset: tx.Asset,
|
|
Utxo: utxo.Id,
|
|
Amount: amount.toFixed(8),
|
|
PurchasePrice: utxo.Price,
|
|
DateAcquired: utxo.Date,
|
|
SalePrice: tx.Price,
|
|
CostBasis: costBasis.toFixed(2),
|
|
Proceeds: proceeds.toFixed(2),
|
|
GainLoss: gainLoss.toFixed(2),
|
|
ShortTerm: st ? 'true' : '',
|
|
Tax: gainLoss.gt(0) ? gainLoss.times(st ? .24 : .15).toFixed(2) : 0
|
|
}
|
|
dispositions.push(disposition)
|
|
}
|
|
|
|
const consumeUtxos = (tx) => {
|
|
for (let i = 0; i < utxos.length; i++) {
|
|
let utxo = utxos[i]
|
|
|
|
if (!utxo) {
|
|
console.error(`WARNING: No utxo available! Assuming $0 cost basis:\n-Date:${tx.Date}\n-Asset: ${tx.Asset}\n-Sent: ${tx.Sent}\n-Remaining: ${tx.Remaining.toFixed(8)}\n`)
|
|
utxo = {
|
|
Date: '2017-01-01',
|
|
Id: -1,
|
|
Asset: tx.Asset,
|
|
Amount: tx.Remaining.toFixed(8),
|
|
Price: '0',
|
|
Remaining: tx.Remaining,
|
|
}
|
|
}
|
|
|
|
if (utxo.Asset !== tx.Asset || utxo.Remaining.isZero()) continue
|
|
|
|
if (utxo.Remaining.gte(tx.Remaining)) {
|
|
createDisposition(tx, utxo, tx.Remaining)
|
|
utxo.Remaining = utxo.Remaining.minus(tx.Remaining)
|
|
return
|
|
} else {
|
|
createDisposition(tx, utxo, utxo.Remaining)
|
|
tx.Remaining = tx.Remaining.minus(utxo.Remaining)
|
|
utxo.Remaining = new BN(0)
|
|
return consumeUtxos(tx)
|
|
}
|
|
}
|
|
}
|
|
|
|
txs.forEach((tx, i) => {
|
|
if (tx.Received) return handleBuy(tx, i)
|
|
tx.Remaining = new BN(tx.Sent)
|
|
return consumeUtxos(tx)
|
|
})
|
|
|
|
let balances = utxos.reduce((prev, curr) => {
|
|
const asset = curr.Asset
|
|
if (prev[asset]) {
|
|
prev[asset] = prev[asset].plus(curr.Remaining)
|
|
} else {
|
|
prev[asset] = curr.Remaining
|
|
}
|
|
return prev
|
|
}, {})
|
|
|
|
utxos = utxos.map(u => ({
|
|
...u,
|
|
Remaining: u.Remaining.toFixed(8),
|
|
}))
|
|
|
|
balances = Object.keys(balances)
|
|
.filter(asset => !balances[asset].isZero())
|
|
.map(asset => ({
|
|
Asset: asset,
|
|
balance: balances[asset].toFixed(8)
|
|
}))
|
|
|
|
converter.json2csv(utxos).then(csv =>
|
|
fs.appendFileSync(`./utxos.csv`, csv)
|
|
)
|
|
|
|
converter.json2csv(dispositions).then(csv =>
|
|
fs.appendFileSync(`./dispositions.csv`, csv)
|
|
)
|
|
|
|
converter.json2csv(balances).then(csv =>
|
|
fs.appendFileSync(`./balances.csv`, csv)
|
|
)
|