ledger_get_prices 0.0.4

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: faf17809292e7310521c27fd452006a12c4e585d
4
+ data.tar.gz: a89bdaa59b678bf5148f2b70fbc869c4df30c88d
5
+ SHA512:
6
+ metadata.gz: 4ef4c4c623b7b9bbd5bf7cd72629301c67ddf76c0f623445ef3b8f4ec84e90e227f648f99dcf1246b4e24440d5ca6b9143d4b9dec8969930b0b0db3ad2bdb502
7
+ data.tar.gz: c3eb9534015dff5466e9196bd92b36570c65d4dab13d24321538dfeacec37639b44dc0cf82124880acba969e43718e20925d1dd7356299b25da07493c0df6b4f
data/.gitignore ADDED
@@ -0,0 +1,22 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
18
+ *.bundle
19
+ *.so
20
+ *.o
21
+ *.a
22
+ mkmf.log
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in ledger_get_prices.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2015 Nathan Kot
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,28 @@
1
+ ## ledger-get-prices
2
+
3
+ It's the end of financial year, and now that I'm accounting with NZD,USD,JPY,BTC I've spent some time to automate the
4
+ pricedb process. Enjoy :) PR's welcome.
5
+
6
+ # Synopsis
7
+
8
+ _Tool that uses Yahoo finance to intelligently generate
9
+ a ledger price database based on your current ledger
10
+ commodities and time period._
11
+
12
+ Ensure that you have set the `LEDGER` and `LEDGER_PRICE_DB`
13
+ environment variables before proceeding. Alternatively, you
14
+ can make the same addition to your `.ledgerrc`, so long as
15
+ running `ledger` vanilla knows where to get the journal and
16
+ pricedb.
17
+
18
+ # Environment Variables
19
+
20
+ * __LEDGER_BASE_CURRENCY__: Defaults to USD, change this to your reporting currency.
21
+ * __LEDGER_PRICE_DATE_FORMAT__: The date format of the outputted pricedb. Defaults to +%Y/%m/%d+.
22
+
23
+ # Usage
24
+
25
+ ```sh
26
+ gem install ledger-get-prices
27
+ getprices # This will WRITE to your LEDGER_PRICE_DB file.
28
+ ```
data/Rakefile ADDED
@@ -0,0 +1,2 @@
1
+ require "bundler/gem_tasks"
2
+
data/bin/getprices ADDED
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env ruby
2
+ require 'ledger_get_prices'
3
+ LedgerGetPrices::GetPrices.run!
@@ -0,0 +1,23 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'ledger_get_prices/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "ledger_get_prices"
8
+ spec.version = LedgerGetPrices::VERSION
9
+ spec.authors = ["Nathan Kot"]
10
+ spec.email = ["nk@nathankot.com"]
11
+ spec.summary = 'Intelligently update your ledger pricedb'
12
+ spec.homepage = 'https://github.com/nathankot/ledger-get-prices'
13
+ spec.license = "MIT"
14
+
15
+ spec.files = `git ls-files -z`.split("\x0")
16
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
17
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
18
+ spec.require_paths = ["lib"]
19
+
20
+ spec.add_development_dependency "bundler", "~> 1.6"
21
+ spec.add_development_dependency "rake"
22
+ spec.add_runtime_dependency "yahoo-finance"
23
+ end
@@ -0,0 +1,3 @@
1
+ module LedgerGetPrices
2
+ VERSION = "0.0.4"
3
+ end
@@ -0,0 +1,141 @@
1
+ require "ledger_get_prices/version"
2
+ require 'date'
3
+ require 'open-uri'
4
+ require 'yahoo-finance'
5
+
6
+ module LedgerGetPrices
7
+
8
+ # = Synopsis
9
+ #
10
+ # Tool that uses Yahoo finance to intelligently generate
11
+ # a ledger price database based on your current ledger
12
+ # commodities and time period.
13
+ #
14
+ # Ensure that you have set the +LEDGER+ and +LEDGER_PRICE_DB+
15
+ # environment variables before proceeding. Alternatively, you
16
+ # can make the same addition to your +.ledgerrc+, so long as
17
+ # running +ledger+ vanilla knows where to get the journal and
18
+ # pricedb.
19
+ #
20
+ # = Options
21
+ #
22
+ # +LEDGER_BASE_CURRENCY+: Defaults to USD, change this to your reporting currency.
23
+ # +LEDGER_PRICE_DATE_FORMAT+: The date format of the outputted pricedb. Defaults to +%Y/%m/%d+.
24
+ class GetPrices
25
+ class << self
26
+
27
+ # Yahoo finance works best in USD, if the base currency is
28
+ # different we will also store the USD price of that currency
29
+ # to allow for conversion.
30
+ BASE_CURRENCY = ENV['LEDGER_BASE_CURRENCY'] || "USD"
31
+
32
+ PRICE_DB_PATH = ENV['LEDGER_PRICE_DB'] || ENV['PRICE_HIST'] # PRICE_HIST is <v3
33
+ DATE_FORMAT = ENV['LEDGER_PRICE_DATE_FORMAT'] || "%Y/%m/%d"
34
+ PRICE_FORMAT = "P %{date} %{time} %{symbol} %{price}"
35
+ COMMODITY_BLACKLIST = (ENV['LEDGER_PRICE_COMMODITY_BLACKLIST'] || 'BTC').split(" ")
36
+
37
+ # With a bang because it does a file write.
38
+ def run!
39
+ File.write(PRICE_DB_PATH, new_prices.join("\n"))
40
+ end
41
+
42
+ # We work with the database as an array of price definitions
43
+ # @return [Array] an array of formatted prices
44
+ def existing_prices
45
+ @existing_prices ||= File.read(PRICE_DB_PATH)
46
+ .split("\n")
47
+ .reject { |x| (/^P.*$/ =~ x) != 0 }
48
+ end
49
+
50
+ # This method builds a new price database intelligently.
51
+ #
52
+ # @return [Array] an array of formatted prices
53
+ def new_prices
54
+ commodities.reduce(existing_prices) do |db, c|
55
+ # `|` is a shortcut for merge
56
+ db | prices_for_symbol(c, start_date: start_date, end_date: end_date)
57
+ .map { |x| price_string_from_result(x, symbol: c) }
58
+ end
59
+ end
60
+
61
+ # @return [Array] of YahooFinance results (OpenStruct)
62
+ def prices_for_symbol(symbol, start_date: start_date, end_date: end_date) # -> Array
63
+ puts "Getting historical quotes for: #{symbol}"
64
+
65
+ if COMMODITY_BLACKLIST.include?(symbol)
66
+ puts "Skipping #{symbol}: blacklisted."
67
+ puts "Use `LEDGER_PRICE_COMMODITY_BLACKLIST` to configure the blacklist."
68
+ puts "BTC is included by default because yahoo doesn't provide a way to " +
69
+ "get historical data for it."
70
+ return []
71
+ end
72
+
73
+ result = nil
74
+ quote_strings = possible_quote_strings(commodity: symbol)
75
+ err = nil
76
+
77
+ while quote_strings.length > 0 && result.nil?
78
+ begin
79
+ result = YahooFinance.historical_quotes(
80
+ quote_strings.shift, start_date: start_date, end_date: end_date, period: :daily)
81
+ rescue OpenURI::HTTPError => e
82
+ err = e
83
+ end
84
+ end
85
+
86
+ if result.nil?
87
+ puts "Could not get quotes from Yahoo for: #{symbol}"
88
+ puts "It may be worthwhile getting prices for this manually."
89
+ []
90
+ else result
91
+ end
92
+ end
93
+
94
+ # @return [String]
95
+ def price_string_from_result(data, symbol: nil)
96
+ raise "Must pass symbol" if symbol.nil?
97
+ PRICE_FORMAT % {
98
+ date: Date.strptime(data.trade_date, '%Y-%m-%d').strftime(DATE_FORMAT),
99
+ time: '23:59:59',
100
+ symbol: (BASE_CURRENCY == 'USD' ? '$' : 'USD'),
101
+ price: (BASE_CURRENCY == symbol ? '$' : symbol)+ data.close
102
+ }
103
+ end
104
+
105
+ protected
106
+
107
+ # Start date is either the latest price record or the earliest
108
+ # ever transaction.
109
+ # @return [Date]
110
+ def start_date
111
+ @start_date ||= existing_prices.map { |x| Date.strptime(x.split(" ")[1], DATE_FORMAT) }.max || begin
112
+ stats = `ledger stats` # Most compact way to retrieve this data
113
+ date_str = /Time\speriod:\s*([\d\w\-]*)\s*to/.match(stats)[1]
114
+ return Date.strptime(date_str, "%y-%b-%d")
115
+ end
116
+ end
117
+
118
+ # End date is today, wish I can see the future but unfortunately..
119
+ # @return [Date]
120
+ def end_date
121
+ @end_date ||= Date.new()
122
+ end
123
+
124
+ # Try the commodity as a currency first, before trying it as a stock
125
+ # @return [Array<String>] Possible Yahoo finance compatible quote strings
126
+ def possible_quote_strings(commodity: nil)
127
+ raise "No commodity given" if commodity.nil?
128
+ ["#{commodity}=X", "USD#{commodity}=X", "#{commodity}"]
129
+ end
130
+
131
+ def commodities
132
+ # All the commodities we care about.
133
+ @commodities ||= `ledger commodities`.split("\n").reject { |x| x == "$" }.tap do |c|
134
+ c << BASE_CURRENCY if BASE_CURRENCY != 'USD'
135
+ end
136
+ end
137
+
138
+ end
139
+ end
140
+
141
+ end
metadata ADDED
@@ -0,0 +1,96 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: ledger_get_prices
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.4
5
+ platform: ruby
6
+ authors:
7
+ - Nathan Kot
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-05-03 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.6'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.6'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: yahoo-finance
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ description:
56
+ email:
57
+ - nk@nathankot.com
58
+ executables:
59
+ - getprices
60
+ extensions: []
61
+ extra_rdoc_files: []
62
+ files:
63
+ - ".gitignore"
64
+ - Gemfile
65
+ - LICENSE.txt
66
+ - README.md
67
+ - Rakefile
68
+ - bin/getprices
69
+ - ledger_get_prices.gemspec
70
+ - lib/ledger_get_prices.rb
71
+ - lib/ledger_get_prices/version.rb
72
+ homepage: https://github.com/nathankot/ledger-get-prices
73
+ licenses:
74
+ - MIT
75
+ metadata: {}
76
+ post_install_message:
77
+ rdoc_options: []
78
+ require_paths:
79
+ - lib
80
+ required_ruby_version: !ruby/object:Gem::Requirement
81
+ requirements:
82
+ - - ">="
83
+ - !ruby/object:Gem::Version
84
+ version: '0'
85
+ required_rubygems_version: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ requirements: []
91
+ rubyforge_project:
92
+ rubygems_version: 2.2.2
93
+ signing_key:
94
+ specification_version: 4
95
+ summary: Intelligently update your ledger pricedb
96
+ test_files: []