summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorAlan Pearce2017-09-16 17:11:01 +0200
committerAlan Pearce2017-09-16 17:31:00 +0200
commit269e7b208e5d20bdc3f9cb2bdd178fbbecb046a6 (patch)
treef10e4670eb5335e35cbe99bc0b57ab821b59eb72
downloadbitcoincharts-beancount-269e7b208e5d20bdc3f9cb2bdd178fbbecb046a6.tar.lz
bitcoincharts-beancount-269e7b208e5d20bdc3f9cb2bdd178fbbecb046a6.tar.zst
bitcoincharts-beancount-269e7b208e5d20bdc3f9cb2bdd178fbbecb046a6.zip
Initial commit HEAD v1.0.0 master main
-rw-r--r--.gitignore1
-rw-r--r--LICENSE21
-rw-r--r--README.org40
-rw-r--r--index.js68
-rw-r--r--package-lock.json31
-rw-r--r--package.json25
6 files changed, 186 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..07e6e47
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1 @@
+/node_modules
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..a53abb1
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2017 Alan Pearce
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/README.org b/README.org
new file mode 100644
index 0000000..f0ff157
--- /dev/null
+++ b/README.org
@@ -0,0 +1,40 @@
+* Bitcoincharts Beancount converter
+
+This is a quick tool I hacked together to convert historic bitcoin
+prices from [[http://api.bitcoincharts.com/v1/csv/][bitcoincharts CSVs]] into beancount price directives.
+
+The files are gzipped CSVs of (unixtime, price, tradeamount)
+
+For each month with trades on the 1st, the tool calculates a weighted
+average of trades on that day and outputs a beancount price directive.
+
+** Running
+
+The tool does not download files on its own.  Download the files
+before running.
+
+#+BEGIN_SRC shell
+$ node index.js some.csv.gz
+# or
+$ node index.js some.csv.gz EUR
+# or
+$ node index.js some.csv.gz EUR BTC
+#+END_SRC 
+
+*** Parameters
+
+- filename (gzipped CSV)
+- currency [optional] (currency code used in beancount {USD,EUR, etc})
+- commodity [optional] (currency code of commodity) {BTC,BCH,LTC, etc}
+
+*** Status
+
+It works. I don't plan on working on it much further.
+
+It's not very efficent.  I suspect the main problem is the group
+function probably doesn't assume that the input is sorted and
+therefore buffers its entire input.  Patches welcome.
+
+** License
+
+MIT
diff --git a/index.js b/index.js
new file mode 100644
index 0000000..6152685
--- /dev/null
+++ b/index.js
@@ -0,0 +1,68 @@
+const r = require('ramda')
+const h = require('highland')
+const fs = require('fs')
+const path = require('path')
+const zlib = require('zlib')
+const BigNumber = require('bignumber.js')
+
+BigNumber.config({
+  DECIMAL_PLACES: 8
+})
+
+if (process.argv.length < 3) {
+  console.error(`${path.basename(process.argv[1])}
+
+bitcoincharts historic price conversion
+
+Input: gzipped csv of (unixtime, price, tradeamount)
+
+Outputs beancount price directives for the weighted average price
+of all trades executed on the first of each month in the provided file
+
+Download files from http://api.bitcoincharts.com/v1/csv/
+
+usage: ${path.basename(process.argv[1])} FILENAME [CURRENCY] [COMMODITY]`)
+  process.exit(1)
+}
+
+const [
+  ,,
+  filename,
+  currency = 'EUR',
+  commodity = 'BTC'
+] = process.argv
+
+h(
+  fs.createReadStream(filename)
+    .pipe(zlib.createGunzip())
+)
+  .split()
+  .filter(line => line.length > 1)
+  .map(line => line.split(',', 3))
+  .map(([time, price, amount]) => [
+    new Date(parseInt(time, 10) * 1000),
+    new BigNumber(price),
+    new BigNumber(amount)
+  ])
+  .filter(([date]) => date.getDate() === 1)
+  .group(([date]) => date.toDateString())
+  .map(group => Object.values(group))
+  .sequence()
+  .map(group => group
+       .map(
+         ([date, price, amount]) => [date, price.times(amount), amount]
+       )
+       .reduce(
+         ([date, sumPrice, sumAmount], [,weightPrice, amount]) => [
+           date,
+           sumPrice.plus(weightPrice),
+           sumAmount.plus(amount)
+         ]
+       ))
+  .map(([date, sumprice, sumamount]) => [date, sumprice.dividedBy(sumamount)])
+  .map(([date, avg]) =>
+       `${date.toISOString().substr(0, 10)} price ${commodity}  ${avg.toFixed(2)} ${currency}`
+      )
+  .intersperse("\n")
+  .pipe(process.stdout)
+
diff --git a/package-lock.json b/package-lock.json
new file mode 100644
index 0000000..7ee272f
--- /dev/null
+++ b/package-lock.json
@@ -0,0 +1,31 @@
+{
+  "name": "bitcoincharts-beancount",
+  "version": "1.0.0",
+  "lockfileVersion": 1,
+  "requires": true,
+  "dependencies": {
+    "bignumber.js": {
+      "version": "4.0.4",
+      "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-4.0.4.tgz",
+      "integrity": "sha512-LDXpJKVzEx2/OqNbG9mXBNvHuiRL4PzHCGfnANHMJ+fv68Ads3exDVJeGDJws+AoNEuca93bU3q+S0woeUaCdg=="
+    },
+    "highland": {
+      "version": "2.11.1",
+      "resolved": "https://registry.npmjs.org/highland/-/highland-2.11.1.tgz",
+      "integrity": "sha1-ObTZKZtuB9o9FeeveypvEnUirK8=",
+      "requires": {
+        "util-deprecate": "1.0.2"
+      }
+    },
+    "ramda": {
+      "version": "0.24.1",
+      "resolved": "https://registry.npmjs.org/ramda/-/ramda-0.24.1.tgz",
+      "integrity": "sha1-w7d1UZfzW43DUCIoJixMkd22uFc="
+    },
+    "util-deprecate": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
+      "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8="
+    }
+  }
+}
diff --git a/package.json b/package.json
new file mode 100644
index 0000000..20e849f
--- /dev/null
+++ b/package.json
@@ -0,0 +1,25 @@
+{
+  "name": "bitcoincharts-beancount",
+  "version": "1.0.0",
+  "description": "bitcoincharts historic price conversion",
+  "main": "index.js",
+  "scripts": {
+    "test": "echo \"Error: no test specified\" && exit 1"
+  },
+  "repository": {
+    "type": "git",
+    "url": "https://git.alanpearce.eu/bitcoincharts-beancount"
+  },
+  "keywords": [
+    "bitcoin",
+    "beancount",
+    "accounting"
+  ],
+  "author": "Alan Pearce <alan@alanpearce.eu>",
+  "license": "MIT",
+  "dependencies": {
+    "bignumber.js": "^4.0.4",
+    "highland": "^2.11.1",
+    "ramda": "^0.24.1"
+  }
+}