Class: LedgerGetPrices::GetPrices

Inherits:
Object
  • Object
show all
Defined in:
lib/ledger_get_prices.rb

Overview

Synopsis

Tool that uses Yahoo finance to intelligently generate a ledger price database based on your current ledger commodities and time period.

Ensure that you have set the LEDGER and LEDGER_PRICE_DB environment variables before proceeding. Alternatively, you can make the same addition to your .ledgerrc, so long as running ledger vanilla knows where to get the journal and pricedb.

Options

LEDGER_BASE_CURRENCY: Defaults to USD, change this to your reporting currency. LEDGER_PRICE_DATE_FORMAT: The date format of the outputted pricedb. Defaults to %Y/%m/%d.

Constant Summary collapse

BASE_CURRENCY =

Yahoo finance works best in USD, if the base currency is different we will also store the USD price of that currency to allow for conversion.

ENV['LEDGER_BASE_CURRENCY'] || "USD"
PRICE_DB_PATH =

PRICE_HIST is <v3

ENV['LEDGER_PRICE_DB'] || ENV['PRICE_HIST']
DATE_FORMAT =
ENV['LEDGER_PRICE_DATE_FORMAT'] || "%Y/%m/%d"
PRICE_FORMAT =
"P %{date} %{time} %{symbol} %{price}"
COMMODITY_BLACKLIST =
(ENV['LEDGER_PRICE_COMMODITY_BLACKLIST'] || '').split(" ")

Class Method Summary collapse

Class Method Details

.existing_pricesArray

We work with the database as an array of price definitions



44
45
46
47
48
# File 'lib/ledger_get_prices.rb', line 44

def existing_prices
  @existing_prices ||= File.read(PRICE_DB_PATH)
                          .split("\n")
                          .reject { |x| (/^P.*$/ =~ x) != 0 }
end

.new_pricesArray

This method builds a new price database intelligently.



53
54
55
56
57
58
59
# File 'lib/ledger_get_prices.rb', line 53

def new_prices
  commodities.reduce(existing_prices) do |db, c|
    # `|` is a shortcut for merge
    db | prices_for_symbol(c, start_date: start_date, end_date: end_date)
        .map { |x| price_string_from_result(x, symbol: c) }
  end
end

.price_string_from_result(data, symbol: nil) ⇒ String



93
94
95
96
97
98
99
100
101
# File 'lib/ledger_get_prices.rb', line 93

def price_string_from_result(data, symbol: nil)
  raise "Must pass symbol" if symbol.nil?
  PRICE_FORMAT % {
    date: Date.strptime(data.trade_date, '%Y-%m-%d').strftime(DATE_FORMAT),
    time: '23:59:59',
    symbol: (BASE_CURRENCY == 'USD' ? '$' : 'USD'),
    price: (BASE_CURRENCY == symbol ? '$' : symbol)+ data.close
  }
end

.prices_for_symbol(symbol, start_date: start_date, end_date: end_date) ⇒ Array



62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
# File 'lib/ledger_get_prices.rb', line 62

def prices_for_symbol(symbol, start_date: start_date, end_date: end_date) # -> Array
  puts "Getting historical quotes for: #{symbol}"

  if COMMODITY_BLACKLIST.include?(symbol)
    puts "Skipping #{symbol}: blacklisted."
    puts "Use `LEDGER_PRICE_COMMODITY_BLACKLIST` to configure the blacklist."
    return []
  end

  result = nil
  quote_strings = possible_quote_strings(commodity: symbol)
  err = nil

  while quote_strings.length > 0 && result.nil?
    begin
      result = YahooFinance::Client.new.historical_quotes(
        quote_strings.shift, start_date: start_date, end_date: end_date, period: :daily)
    rescue OpenURI::HTTPError => e
      err = e
    end
  end

  if result.nil?
    puts "Could not get quotes from Yahoo for: #{symbol}"
    puts "It may be worthwhile getting prices for this manually."
    []
  else result
  end
end

.run!Object

With a bang because it does a file write.



38
39
40
# File 'lib/ledger_get_prices.rb', line 38

def run!
  File.write(PRICE_DB_PATH, new_prices.join("\n"))
end