forked from EvergreenCrypto/docker-finance
container: lib_taxes: cost-basis work-around for bitcoin.tax
Issue #51 describes at least a few undocumented bitcoin.tax issues: - Bicoin.tax gives unexpected cost-basis results when `Fee` is given with `Total` (when `Total` is given in place of `Price`). The expectation is that bitcoin.tax will perform the cost-basis calculation on `Total` when `Fee` is also given. However, bitcoin.tax *will* give expected cost-basis results if `Price` is given in place of `Total` (with `Fee` also given) *or* if `Total` is given *after* local cost-basis adjustments are made (but *without* `Fee` given). The rationale for why docker-finance doesn't use `Price`: * docker-finance has all of the `Total`s; so `Price` isn't necessary. * Local price information isn't available for most trades (and shouldn't be necessary since all `Total`s are available). - Additionally, when `Fee` is non-fiat (crypto), it now must be marked as a SPEND in order to be disposed (and to produce an accurate closing report). - Finally, if `FeeCurrency` *does* not match either `Symbol` or `Currency` (e.g., BTC-ETH w/ BNB fee), it's unknown if cost-basis must be calculated locally as well (if `Total` is given). Local calculations cannot be done because `Fee` price information is (almost certainly) not available for this type of trade. Until upstream can assert that attaching the `Fee` will subsequently adjust the cost-basis of `Total` *and* dispose of the `Fee` in the process (while also allowing `Total` to be used in place of `Price`), the `Fee` (and `FeeCurrency`) column(s) must not be populated and values instead moved to SPEND (as described above). Upstream is aware of these issues (since May) and they're in the process of resolution. In the meantime, docker-finance work-arounds should suffice for all trades that have a fiat `Fee` and/or a `Fee`/`FeeCurrency` that matches one side of the trading pair.
This commit is contained in:
@@ -421,8 +421,10 @@ function lib_taxes::__taxes_print()
|
||||
# since it's technically *not* income (such as card cashback rebates)
|
||||
#
|
||||
# - "RAW_TRADE" has no need for a parser/formatter since the comment
|
||||
# contains all of the trade but *MUST* contain tags found within
|
||||
# trades tags (BUY/SELL/FEE) in order to be printed and not skipped.
|
||||
# contains all of the trade but
|
||||
# * *MUST* contain tags found within trades tags (BUY/SELL/FEE)
|
||||
# in order to be printed and not skipped.
|
||||
# * TODO: HACK: *MUST* have cost-basis calculated here (for #51)
|
||||
|
||||
# TODO: AAVE/Compound income formatter (may be replaced by contract query)
|
||||
|
||||
@@ -477,11 +479,84 @@ function lib_taxes::__taxes_print()
|
||||
if (Total ~ /\./) {sub("0*$", "", Total); sub("\\.$", "", Total)}
|
||||
if (Fee ~ /\./) {sub("0*$", "", Fee); sub("\\.$", "", Fee)}
|
||||
|
||||
# TODO: HACK: cost-basis calculated here (instead of preprocess) for #51
|
||||
if (tag == "RAW_TRADE")
|
||||
{
|
||||
printf Date OFS Action OFS Account OFS
|
||||
|
||||
switch (Action)
|
||||
{
|
||||
case "SELL":
|
||||
if (FeeCurrency == Symbol)
|
||||
{
|
||||
if (Fee ~ /\./)
|
||||
{
|
||||
split(Fee, cost_basis, ".")
|
||||
rhs=length(cost_basis[2])
|
||||
CostBasis=sprintf("%." rhs "f", Volume - Fee)
|
||||
}
|
||||
else
|
||||
{
|
||||
CostBasis=Volume - Fee
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
CostBasis=Volume
|
||||
}
|
||||
|
||||
printf Currency OFS Total OFS Symbol OFS CostBasis OFS
|
||||
break
|
||||
|
||||
case "BUY":
|
||||
if (FeeCurrency == Currency)
|
||||
{
|
||||
if (Fee ~ /\./)
|
||||
{
|
||||
split(Fee, cost_basis, ".")
|
||||
rhs=length(cost_basis[2])
|
||||
CostBasis=sprintf("%." rhs "f", Total + Fee)
|
||||
}
|
||||
else
|
||||
{
|
||||
CostBasis=Total + Fee
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
CostBasis=Total
|
||||
}
|
||||
|
||||
printf Symbol OFS Volume OFS Currency OFS CostBasis OFS
|
||||
break
|
||||
|
||||
default:
|
||||
printf "FATAL: unsupported Action: " Action
|
||||
print $0
|
||||
exit
|
||||
}
|
||||
|
||||
printf OFS # FeeCurrency handled below
|
||||
# Fee handled below
|
||||
printf "\n"
|
||||
}
|
||||
|
||||
# TODO: HACK: print SPEND line for non-fiat fee (see #51)
|
||||
# NOTE: cost-basis *MUST* be calculated above or within preprocess
|
||||
if (is_trades && has_fee && FeeCurrency != "USD" && Fee)
|
||||
{
|
||||
printf Date OFS "SPEND" OFS Account OFS
|
||||
printf FeeCurrency OFS Fee OFS "USD"
|
||||
printf "\n";
|
||||
}
|
||||
|
||||
# - Drop USD-only spends (such as with Coinbase Card) because they are not needed.
|
||||
# - Do not print empty USD entries or empty symbol (Algorand) entries.
|
||||
# - Do not print testnet symbols.
|
||||
# TODO: regexp optimize
|
||||
if ((Symbol != "USD" && Symbol != Currency) \
|
||||
# TODO: HACK (isolating from RAW_TRADE): see #51 (and related lib_taxes work-around)
|
||||
if (tag != "RAW_TRADE" \
|
||||
&& (Symbol != "USD" && Symbol != Currency) \
|
||||
&& Volume != 0 && Volume != "" \
|
||||
&& Symbol != "BTCt" && Symbol != "DOGEt" && Symbol != "tLTC" && Symbol != "LTCTEST")
|
||||
{
|
||||
@@ -492,7 +567,24 @@ function lib_taxes::__taxes_print()
|
||||
printf Volume OFS
|
||||
printf Currency OFS
|
||||
printf Total OFS
|
||||
printf (has_fee ? FeeCurrency OFS Fee : Memo)
|
||||
|
||||
if (has_fee)
|
||||
{
|
||||
# TODO: HACK: see #51 (and related lib_taxes work-around)
|
||||
# NOTE: cost-basis *MUST* be calculated within preprocess
|
||||
if (is_trades && Fee && FeeCurrency != "USD")
|
||||
{
|
||||
printf "" OFS ""
|
||||
}
|
||||
else
|
||||
{
|
||||
printf FeeCurrency OFS Fee
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
printf Memo
|
||||
}
|
||||
|
||||
printf "\n"
|
||||
}
|
||||
@@ -632,17 +724,77 @@ function lib_taxes::__taxes_print()
|
||||
switch (Action)
|
||||
{
|
||||
case "SELL":
|
||||
# TODO: HACK: cost-basis calculated here (instead of preprocess) for #51
|
||||
if (FeeCurrency == Symbol)
|
||||
{
|
||||
if (Fee ~ /\./)
|
||||
{
|
||||
split(Fee, cost_basis, ".")
|
||||
rhs=length(cost_basis[2])
|
||||
CostBasis=sprintf("%." rhs "f", Volume - Fee)
|
||||
}
|
||||
else
|
||||
{
|
||||
CostBasis=Volume - Fee
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
CostBasis=Volume
|
||||
}
|
||||
|
||||
printf Date OFS Action OFS Account OFS
|
||||
printf Currency OFS Total OFS Symbol OFS Volume OFS
|
||||
printf FeeCurrency OFS Fee
|
||||
printf Currency OFS Total OFS Symbol OFS CostBasis OFS
|
||||
printf OFS # FeeCurrency/Fee handled below
|
||||
# Fee handled below
|
||||
printf "\n"
|
||||
|
||||
# TODO: HACK: print SPEND line for non-fiat fee (see #51)
|
||||
# NOTE: cost-basis *MUST* be calculated above or within preprocess
|
||||
if (FeeCurrency != "USD")
|
||||
{
|
||||
printf Date OFS "SPEND" OFS Account OFS
|
||||
printf FeeCurrency OFS Fee OFS "USD"
|
||||
printf "\n";
|
||||
}
|
||||
break
|
||||
|
||||
case "BUY":
|
||||
# TODO: HACK: cost-basis calculated here (instead of preprocess) for #51
|
||||
if (FeeCurrency == Currency)
|
||||
{
|
||||
if (Fee ~ /\./)
|
||||
{
|
||||
split(Fee, cost_basis, ".")
|
||||
rhs=length(cost_basis[2])
|
||||
CostBasis=sprintf("%." rhs "f", Total + Fee)
|
||||
}
|
||||
else
|
||||
{
|
||||
CostBasis=Total + Fee
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
CostBasis=Total
|
||||
}
|
||||
|
||||
printf Date OFS Action OFS Account OFS
|
||||
printf Symbol OFS Volume OFS Currency OFS Total OFS
|
||||
printf FeeCurrency OFS Fee
|
||||
printf Symbol OFS Volume OFS Currency OFS CostBasis OFS
|
||||
printf OFS # FeeCurrency handled below
|
||||
# Fee handled below
|
||||
printf "\n"
|
||||
|
||||
# TODO: HACK: print SPEND line for non-fiat fee (see #51)
|
||||
# NOTE: cost-basis *MUST* be calculated above or within preprocess
|
||||
if (FeeCurrency != "USD")
|
||||
{
|
||||
printf Date OFS "SPEND" OFS Account OFS
|
||||
printf FeeCurrency OFS Fee OFS "USD"
|
||||
printf "\n";
|
||||
}
|
||||
break
|
||||
|
||||
case "BORROW":
|
||||
# Reset tail end vars since this is an "INCOME" tag
|
||||
FeeCurrency = $14
|
||||
@@ -763,17 +915,36 @@ function lib_taxes::__taxes_print()
|
||||
if (Total ~ /\./) {sub("0*$", "", Total); sub("\\.$", "", Total)}
|
||||
if (Fee ~ /\./) {sub("0*$", "", Fee); sub("\\.$", "", Fee)}
|
||||
|
||||
# TODO: HACK: cost-basis calculated here (instead of preprocess) for #51
|
||||
if (FeeCurrency == Currency)
|
||||
{
|
||||
if (Action == "BUY") {CostBasis=Total + Fee}
|
||||
else {CostBasis=Total - Fee}
|
||||
}
|
||||
else
|
||||
{
|
||||
CostBasis=Total
|
||||
}
|
||||
|
||||
printf Date OFS
|
||||
printf Action OFS
|
||||
printf Account OFS
|
||||
printf Symbol OFS
|
||||
printf Volume OFS
|
||||
printf Currency OFS
|
||||
printf Total OFS
|
||||
printf FeeCurrency OFS
|
||||
printf Fee
|
||||
|
||||
printf CostBasis OFS
|
||||
printf OFS # FeeCurrency handled below
|
||||
# Fee handled below
|
||||
printf "\n";
|
||||
|
||||
# TODO: HACK: print SPEND line for non-fiat fee (see #51)
|
||||
# NOTE: cost-basis *MUST* be calculated above
|
||||
if (FeeCurrency != "USD")
|
||||
{
|
||||
printf Date OFS "SPEND" OFS Account OFS
|
||||
printf FeeCurrency OFS Fee OFS "USD"
|
||||
printf "\n";
|
||||
}
|
||||
}'
|
||||
fi
|
||||
|
||||
@@ -963,10 +1134,13 @@ function lib_taxes::__reports_patch()
|
||||
# Ensure appropriate tags in respective files
|
||||
#
|
||||
# NOTE:
|
||||
#
|
||||
# - Due to PARTIAL_TRADES, there may be a lone FEE SPEND straggler
|
||||
# - Due to MATCH, income/spend BORROW/REPAY may be in trades output
|
||||
# - Bitcoin.tax will allow SPENDS in trades file with error complaints
|
||||
# - Bitcoin.tax:
|
||||
# * will allow SPENDS in trades file (though, with error complaints)
|
||||
# * TODO: HACK: due to #51, trades with non-fiat fees will need a SPEND
|
||||
# line added for the disposal of said fee until upstream resolves
|
||||
# their importer.
|
||||
#
|
||||
# WARNING:
|
||||
# - Do *NOT* do a unique sort here!
|
||||
|
||||
Reference in New Issue
Block a user