summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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 @@
1MIT License
2
3Copyright (c) 2017 Alan Pearce
4
5Permission is hereby granted, free of charge, to any person obtaining a copy
6of this software and associated documentation files (the "Software"), to deal
7in the Software without restriction, including without limitation the rights
8to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9copies of the Software, and to permit persons to whom the Software is
10furnished to do so, subject to the following conditions:
11
12The above copyright notice and this permission notice shall be included in all
13copies or substantial portions of the Software.
14
15THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21SOFTWARE.
diff --git a/README.org b/README.org
new file mode 100644
index 0000000..f0ff157
--- /dev/null
+++ b/README.org
@@ -0,0 +1,40 @@
1* Bitcoincharts Beancount converter
2
3This is a quick tool I hacked together to convert historic bitcoin
4prices from [[http://api.bitcoincharts.com/v1/csv/][bitcoincharts CSVs]] into beancount price directives.
5
6The files are gzipped CSVs of (unixtime, price, tradeamount)
7
8For each month with trades on the 1st, the tool calculates a weighted
9average of trades on that day and outputs a beancount price directive.
10
11** Running
12
13The tool does not download files on its own. Download the files
14before running.
15
16#+BEGIN_SRC shell
17$ node index.js some.csv.gz
18# or
19$ node index.js some.csv.gz EUR
20# or
21$ node index.js some.csv.gz EUR BTC
22#+END_SRC
23
24*** Parameters
25
26- filename (gzipped CSV)
27- currency [optional] (currency code used in beancount {USD,EUR, etc})
28- commodity [optional] (currency code of commodity) {BTC,BCH,LTC, etc}
29
30*** Status
31
32It works. I don't plan on working on it much further.
33
34It's not very efficent. I suspect the main problem is the group
35function probably doesn't assume that the input is sorted and
36therefore buffers its entire input. Patches welcome.
37
38** License
39
40MIT
diff --git a/index.js b/index.js
new file mode 100644
index 0000000..6152685
--- /dev/null
+++ b/index.js
@@ -0,0 +1,68 @@
1const r = require('ramda')
2const h = require('highland')
3const fs = require('fs')
4const path = require('path')
5const zlib = require('zlib')
6const BigNumber = require('bignumber.js')
7
8BigNumber.config({
9 DECIMAL_PLACES: 8
10})
11
12if (process.argv.length < 3) {
13 console.error(`${path.basename(process.argv[1])}
14
15bitcoincharts historic price conversion
16
17Input: gzipped csv of (unixtime, price, tradeamount)
18
19Outputs beancount price directives for the weighted average price
20of all trades executed on the first of each month in the provided file
21
22Download files from http://api.bitcoincharts.com/v1/csv/
23
24usage: ${path.basename(process.argv[1])} FILENAME [CURRENCY] [COMMODITY]`)
25 process.exit(1)
26}
27
28const [
29 ,,
30 filename,
31 currency = 'EUR',
32 commodity = 'BTC'
33] = process.argv
34
35h(
36 fs.createReadStream(filename)
37 .pipe(zlib.createGunzip())
38)
39 .split()
40 .filter(line => line.length > 1)
41 .map(line => line.split(',', 3))
42 .map(([time, price, amount]) => [
43 new Date(parseInt(time, 10) * 1000),
44 new BigNumber(price),
45 new BigNumber(amount)
46 ])
47 .filter(([date]) => date.getDate() === 1)
48 .group(([date]) => date.toDateString())
49 .map(group => Object.values(group))
50 .sequence()
51 .map(group => group
52 .map(
53 ([date, price, amount]) => [date, price.times(amount), amount]
54 )
55 .reduce(
56 ([date, sumPrice, sumAmount], [,weightPrice, amount]) => [
57 date,
58 sumPrice.plus(weightPrice),
59 sumAmount.plus(amount)
60 ]
61 ))
62 .map(([date, sumprice, sumamount]) => [date, sumprice.dividedBy(sumamount)])
63 .map(([date, avg]) =>
64 `${date.toISOString().substr(0, 10)} price ${commodity} ${avg.toFixed(2)} ${currency}`
65 )
66 .intersperse("\n")
67 .pipe(process.stdout)
68
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 @@
1{
2 "name": "bitcoincharts-beancount",
3 "version": "1.0.0",
4 "lockfileVersion": 1,
5 "requires": true,
6 "dependencies": {
7 "bignumber.js": {
8 "version": "4.0.4",
9 "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-4.0.4.tgz",
10 "integrity": "sha512-LDXpJKVzEx2/OqNbG9mXBNvHuiRL4PzHCGfnANHMJ+fv68Ads3exDVJeGDJws+AoNEuca93bU3q+S0woeUaCdg=="
11 },
12 "highland": {
13 "version": "2.11.1",
14 "resolved": "https://registry.npmjs.org/highland/-/highland-2.11.1.tgz",
15 "integrity": "sha1-ObTZKZtuB9o9FeeveypvEnUirK8=",
16 "requires": {
17 "util-deprecate": "1.0.2"
18 }
19 },
20 "ramda": {
21 "version": "0.24.1",
22 "resolved": "https://registry.npmjs.org/ramda/-/ramda-0.24.1.tgz",
23 "integrity": "sha1-w7d1UZfzW43DUCIoJixMkd22uFc="
24 },
25 "util-deprecate": {
26 "version": "1.0.2",
27 "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
28 "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8="
29 }
30 }
31}
diff --git a/package.json b/package.json
new file mode 100644
index 0000000..20e849f
--- /dev/null
+++ b/package.json
@@ -0,0 +1,25 @@
1{
2 "name": "bitcoincharts-beancount",
3 "version": "1.0.0",
4 "description": "bitcoincharts historic price conversion",
5 "main": "index.js",
6 "scripts": {
7 "test": "echo \"Error: no test specified\" && exit 1"
8 },
9 "repository": {
10 "type": "git",
11 "url": "https://git.alanpearce.eu/bitcoincharts-beancount"
12 },
13 "keywords": [
14 "bitcoin",
15 "beancount",
16 "accounting"
17 ],
18 "author": "Alan Pearce <alan@alanpearce.eu>",
19 "license": "MIT",
20 "dependencies": {
21 "bignumber.js": "^4.0.4",
22 "highland": "^2.11.1",
23 "ramda": "^0.24.1"
24 }
25}