Added taxes.org, and a table printer

This commit is contained in:
Peter Selby 2018-09-13 10:19:04 -07:00
parent b75d956c13
commit 90aefc0f29
4 changed files with 118 additions and 36 deletions

31
resources/taxes.org Normal file
View File

@ -0,0 +1,31 @@
* Taxes 2017
Basic idea:
- Make a list of all purchases and all sales in history.
- Take the sales from 2017. Calculate capital gains. That's the bulk of the
taxes.
- Trades count as sale of crypto #1, purchase of crypto #2.
- Already paid taxes for 2013...that should be accounted for in step 1.
- BCH and BTG count as income: all deposits should be multiplied by the day-1
value and counted as income--everything else counts as capital gains.
- BCH traded on the first day at $277, according to bitcoin.tax.
- Uhh, some Coinbase "sends" are really sales. Look for "Sent to Coinbase".
- Coinbase sent to Vault of Satoshi, where they were sold. Should be
considered sold...but I don't know how to calculate the tax. Anyway, I
paid it in 2014:
- 1AF6ZPez9NFc7nUfJtwBgod6aWcYaDTi3F
- 1LTrqFApTvfSn415Rjs1ukCVN149zADxxJ
- 1LTrqFApTvfSn415Rjs1ukCVN149zADxxJ
- 18as544Wxg3ZScCZo7fjWSV4JGUhsLv6AR
- 18as544Wxg3ZScCZo7fjWSV4JGUhsLv6AR
- 1GxxcLKjqHD1wZWoZ3KNgiqjQonGDpZS4
- 1G3GM7izNsegWnxTB3RbuXAkC9YZxfeYP1
- Definitely gifts:
- 1L4kschshGtKJPM3T5RXhBJYtEHhFa3xq (Omar)
- 18Co5639x3Dp1EExfbgEzBKXYn329cwYKt
- Vircurex:
- 1FripmTRgNFx6M2C7udeDWKYW8wfR5vuUU
- 1FripmTRgNFx6M2C7udeDWKYW8wfR5vuUU

View File

@ -22,32 +22,36 @@
(s/def ::recipient [:self :buyer :merchant]) (s/def ::recipient [:self :buyer :merchant])
(def txn-common [::id (s/def ::notes string?)
::amount
::currency (def txn-common-req [::id
::txn-type ::amount
::account ::currency
::currency]) ::txn-type
::account
::currency])
(defmulti txn-type ::txn-type) (defmulti txn-type ::txn-type)
(defmethod txn-type :buy [_] (defmethod txn-type :buy [_]
(s/keys :req (concat txn-common (s/keys :req (concat txn-common-req
[::from-currency]) [::from-currency])
:opt [::amount-consumed])) :opt [::notes]))
(defmethod txn-type :sell [_] (defmethod txn-type :sell [_]
(s/keys :req (concat txn-common (s/keys :req (concat txn-common-req
[]) [])
:opt [::consuming-txns])) :opt [::notes]))
(defmethod txn-type :trade [_] (defmethod txn-type :trade [_]
(s/keys :req (concat txn-common (s/keys :req (concat txn-common-req
[::to-currency]))) [::to-currency])
:opt [::notes]))
(defmethod txn-type :send [_] (defmethod txn-type :send [_]
(s/keys :req (concat txn-common []) (s/keys :req (concat txn-common-req [])
:opt [::recipient])) :opt [::notes]))
(defmethod txn-type :receive [_] (defmethod txn-type :receive [_]
(s/keys :req (concat txn-common []) (s/keys :req (concat txn-common-req [])
:opt [::sender])) :opt [::notes]))
(defmethod txn-type :fee [_] (defmethod txn-type :fee [_]
(s/keys :req (concat txn-common []))) (s/keys :req (concat txn-common-req [])
:opt [::notes]))
(s/def ::txn (s/multi-spec txn-type ::txn-type)) (s/def ::txn (s/multi-spec txn-type ::txn-type))
(s/def ::txns (s/coll-of ::txn)) (s/def ::txns (s/coll-of ::txn))
@ -59,4 +63,7 @@
::open ::high ::low ::close] ::open ::high ::low ::close]
:opt-un [::volume_from ::volume_to]))) :opt-un [::volume_from ::volume_to])))
(s/def ::pricemaps (s/map-of keyword? ::pricemap)) (s/def ::rate-fetcher (s/fspec :args (s/cat :date ::datetime)
:ret decimal?))
(s/def ::rate-fetchers (s/map-of keyword? ::rate-fetcher))

View File

@ -13,7 +13,8 @@
(import/load-coinbase-csv (io/resource "Coinbase-50f5ebcff0c2719719000033-TaxTransactionsReport-2018-05-18-21_36_35.csv")))) (import/load-coinbase-csv (io/resource "Coinbase-50f5ebcff0c2719719000033-TaxTransactionsReport-2018-05-18-21_36_35.csv"))))
(defn rates [] (defn rates []
(let [btcusd (import/load-bittrex-rates (io/resource "Bittrex_BTCUSD_1h.csv"))] (let [btcusd (import/load-bittrex-rates (io/resource "Bittrex_BTCUSD_1h.csv"))
ada->usd (partial import/bittrex-rate:ada->usd btcusd)]
(-> {} (-> {}
(assoc :btc->usd (-> btcusd (import/bittrex-rate:btc->usd))) (assoc :btc->usd (-> btcusd (import/bittrex-rate:btc->usd)))
(assoc :bcc->usd (-> (io/resource "Poloniex_BCHUSD_1h.csv") (assoc :bcc->usd (-> (io/resource "Poloniex_BCHUSD_1h.csv")
@ -21,7 +22,7 @@
(import/bittrex-rate:bcc->usd))) (import/bittrex-rate:bcc->usd)))
(assoc :ada->usd (-> (io/resource "Bittrex_ADABTC_1h.csv") (assoc :ada->usd (-> (io/resource "Bittrex_ADABTC_1h.csv")
(import/load-bittrex-rates) (import/load-bittrex-rates)
(partial import/bittrex-rate:ada->usd btcusd))) ada->usd))
(assoc :eth->usd (-> (io/resource "Bittrex_ETHUSD_1h.csv") (assoc :eth->usd (-> (io/resource "Bittrex_ETHUSD_1h.csv")
(import/load-bittrex-rates) (import/load-bittrex-rates)
(import/bittrex-rate:eth->usd))) (import/bittrex-rate:eth->usd)))
@ -30,8 +31,42 @@
(import/coinmarketcap-rate:btg->usd))) (import/coinmarketcap-rate:btg->usd)))
(assoc :usdt->usd (fn [date] 1))))) (assoc :usdt->usd (fn [date] 1)))))
(s/fdef rates (s/fdef rates
:ret ::tax/pricemaps) :ret ::tax/rate-fetchers)
(defn bittrex [] (defn bittrex []
(import/merge-bittrex-transactions (rates) (import/merge-bittrex-transactions (rates)
(import/load-bittrex-csv "resources/bittrex-fullOrders.csv"))) (import/load-bittrex-csv "resources/bittrex-fullOrders.csv")))
(defn all-txns []
(concat (gdax) (coinbase) (bittrex)))
(defn project [ks m]
(into {} (map (fn [k] [k (get m k)]) ks)))
(defn round-str [dec]
(format "%.2f" dec))
(let [format (java.text.SimpleDateFormat. "yyyy-MM-dd")]
(defn format-date [date]
(.format format date)))
(defn update-field [field f txns]
(map (fn [txn] (update txn field f)) txns))
(defn print-as-table [txns]
(let [restrict-fields (partial project [::tax/timestamp
::tax/txn-id
::tax/txn-type
::tax/amount
::tax/currency
::tax/usd-amount
::tax/id
;;::tax/notes
])]
(clojure.pprint/print-table
(->> txns
(sort-by ::tax/timestamp)
(update-field ::tax/amount round-str)
(update-field ::tax/usd-amount round-str)
(update-field ::tax/timestamp format-date)
(map restrict-fields)))))

View File

@ -8,7 +8,7 @@
[clojure.spec.alpha :as s] [clojure.spec.alpha :as s]
[orchestra.spec.test :as st])) [orchestra.spec.test :as st]))
(st/instrument) ;;(st/instrument)
(defn file? [obj] (defn file? [obj]
(instance? java.io.File obj)) (instance? java.io.File obj))
@ -114,7 +114,8 @@
::tax/usd-amount (:usd_amount_transacted txn) ::tax/usd-amount (:usd_amount_transacted txn)
::tax/account :coinbase ::tax/account :coinbase
::tax/amount (:quantity_transacted txn) ::tax/amount (:quantity_transacted txn)
::tax/currency (:asset txn)) ::tax/currency (:asset txn)
::tax/notes (str/replace (:notes txn) #"\n" " :: "))
(common->local))) (common->local)))
(defmulti coinbase->local :transaction_type) (defmulti coinbase->local :transaction_type)
@ -130,7 +131,7 @@
(defmethod coinbase->local :receive [txn] (defmethod coinbase->local :receive [txn]
(-> txn (-> txn
(assoc ::tax/txn-type :recieve) (assoc ::tax/txn-type :receive)
(common-coinbase->local))) (common-coinbase->local)))
(defmethod coinbase->local :send [txn] (defmethod coinbase->local :send [txn]
@ -144,8 +145,7 @@
(common-coinbase->local))) (common-coinbase->local)))
(defn merge-coinbase-transactions [txns] (defn merge-coinbase-transactions [txns]
(map coinbase->local txns (map coinbase->local txns))
))
(defn common-gdax->local [txn] (defn common-gdax->local [txn]
(-> txn (-> txn
@ -296,15 +296,18 @@
:args (s/cat :bccusd ::tax/pricemap) :args (s/cat :bccusd ::tax/pricemap)
:ret (s/fspec :args (s/cat :date ::tax/timestamp) :ret decimal?)) :ret (s/fspec :args (s/cat :date ::tax/timestamp) :ret decimal?))
(defn pp [obj]
(clojure.pprint/pprint obj)
obj)
(defn bittrex-rate:ada->usd [btcusd adabtc] (defn bittrex-rate:ada->usd [btcusd adabtc]
(let [->usd (bittrex-rate:btc->usd btcusd) (let [->usd (bittrex-rate:btc->usd btcusd)
timestamps (sort (keys adabtc))] timestamps (sort (keys adabtc))]
(fn [date] (fn [date]
(let [ada-in-btc (first (map get-avg-rate (let [ada-in-btc (first (map get-avg-rate
(get adabtc (bsearch-timestamps timestamps (get adabtc (bsearch-timestamps timestamps
(.getTime date))))) (.getTime date)))))]
btc-in-usd (->usd date)] (* ada-in-btc (->usd date))))))
(* ada-in-btc btc-in-usd)))))
(s/fdef bittrex-rate:ada->usd (s/fdef bittrex-rate:ada->usd
:args (s/cat :btcusd ::tax/pricemap :adabtc ::tax/pricemap) :args (s/cat :btcusd ::tax/pricemap :adabtc ::tax/pricemap)
:ret (s/fspec :args (s/cat :date ::tax/timestamp) :ret decimal?)) :ret (s/fspec :args (s/cat :date ::tax/timestamp) :ret decimal?))
@ -329,14 +332,14 @@
(s/fdef bittrex-rate:usdt->usd (s/fdef bittrex-rate:usdt->usd
:ret (s/fspec :args (s/cat :date ::tax/timestamp) :ret decimal?)) :ret (s/fspec :args (s/cat :date ::tax/timestamp) :ret decimal?))
(defn build-bittrex-rates [btcusd-csv bccusd-csv adabtc-csv ethusd-csv] #_(defn build-bittrex-rates [btcusd-csv bccusd-csv adabtc-csv ethusd-csv]
(let [btcusd (load-bittrex-rates btcusd-csv)] (let [btcusd (load-bittrex-rates btcusd-csv)]
{:btc->usd (-> btcusd bittrex-rate:btc->usd) {:btc->usd (-> btcusd bittrex-rate:btc->usd)
:bcc->usd (-> bccusd-csv load-bittrex-rates bittrex-rate:bcc->usd) :bcc->usd (-> bccusd-csv load-bittrex-rates bittrex-rate:bcc->usd)
:ada->usd (-> adabtc-csv load-bittrex-rates (partial bittrex-rate:ada->usd btcusd)) :ada->usd (-> adabtc-csv load-bittrex-rates (partial bittrex-rate:ada->usd btcusd))
:eth->usd (-> ethusd-csv load-bittrex-rates bittrex-rate:eth->usd) :eth->usd (-> ethusd-csv load-bittrex-rates bittrex-rate:eth->usd)
:usdt->usd (bittrex-rate:usdt->usd)})) :usdt->usd (bittrex-rate:usdt->usd)}))
(s/fdef build-bittrex-rates #_(s/fdef build-bittrex-rates
:args (s/cat :btcusd-csv file? :args (s/cat :btcusd-csv file?
:bccusd-csv file? :bccusd-csv file?
:adabtc-csv file? :adabtc-csv file?
@ -364,30 +367,36 @@
(assoc ::tax/txn-type :sell (assoc ::tax/txn-type :sell
::tax/amount (:quantity txn) ::tax/amount (:quantity txn)
::tax/currency (:from-currency txn) ::tax/currency (:from-currency txn)
::tax/usd-amount usd-amount) ::tax/usd-amount usd-amount
::tax/notes "split from sell")
(common-bittrex->local)) (common-bittrex->local))
(-> txn (-> txn
(assoc ::tax/txn-type :buy (assoc ::tax/txn-type :buy
::tax/amount (with-precision 10 (/ (:quantity txn) ::tax/amount (with-precision 10 (/ (:quantity txn)
(:price txn))) (:price txn)))
::tax/currency (:to-currency txn) ::tax/currency (:to-currency txn)
::tax/usd-amount usd-amount))])) ::tax/usd-amount usd-amount
::tax/notes "split from sell")
(common-bittrex->local))]))
(defn bittrex-buy->local-txns [rates txn] (defn bittrex-buy->local-txns [rates txn]
(let [usd-amount (* (:quantity txn) (let [usd-amount (* (:quantity txn)
(get-bittrex-rate rates (:to-currency txn) :usd (:closed txn)))] (get-bittrex-rate rates (:from-currency txn) :usd (:closed txn)))]
[(-> txn [(-> txn
(assoc ::tax/txn-type :buy (assoc ::tax/txn-type :buy
::tax/amount (:quantity txn) ::tax/amount (:quantity txn)
::tax/currency (:to-currency txn) ::tax/currency (:to-currency txn)
::tax/usd-amount usd-amount) ::tax/usd-amount usd-amount
::tax/notes "split from buy")
(common-bittrex->local)) (common-bittrex->local))
(-> txn (-> txn
(assoc ::tax/txn-type :sell (assoc ::tax/txn-type :sell
::tax/amount (with-precision 10 (/ (:quantity txn) ::tax/amount (with-precision 10 (/ (:quantity txn)
(:price txn))) (:price txn)))
::tax/currency (:from-currency txn) ::tax/currency (:from-currency txn)
::tax/usd-amount usd-amount))])) ::tax/usd-amount usd-amount
::tax/notes "split from buy")
(common-bittrex->local))]))
(defn bittrex-txn->local-txns [rates txn] (defn bittrex-txn->local-txns [rates txn]
(match (:type txn) (match (:type txn)