Just hacked up my own price fetcher. Will attach it here in case anyone 
finds it useful.

Their API no longer gives historical prices for free, so this relies on 
scraping (credit to this 
post: 
https://medium.com/@danielcimring/downloading-historical-data-from-coinmarketcap-41a2b0111baf).

In order to use:
1.) Create folder "price_sources" in your beancount folder
2.) Create an empty __init__.py file in this folder
3.) Place my attached file price_sources/coinmarketcap.py
4.) Add this as the source for your crypto commodity. For example, for 
bitcoin, you'd add: "price: "USD:price_sources.coinmarketcap/bitcoin" as 
the attribute. Note "bitcoin" corresponds to the coinmarketcap url (in this 
case, the url 
is https://coinmarketcap.com/currencies/bitcoin/historical-data/)
5.) ???
6.) Profit?!

By the way, I am not a Python programmer, so this code probably sucks.

Also, fair warning that Coinmarketcap blocks you if you send too many 
requests; for this reason, I've cnofigured it to wait 1 second before 
sending a request. Be a good internet citizen and don't abuse their 
service, please!


On Monday, March 4, 2019 at 5:25:32 PM UTC+2, Aamer wrote:
>
> Somehow just saw this message. Thanks for sharing!
>
> On Friday, January 11, 2019 at 4:02:04 AM UTC+2, Vonpupp wrote:
>>
>> Sure @Aamer, it is on a github repo [1].
>>
>> I got it working when I was developing this but since then a lot of 
>> things happened and now I don't remember how to setup the paths for it to 
>> work, so you are on your own in this. If you manage to improve the README 
>> or anything else for that matter I would be glad to receive PRs =)
>>
>> I hope it helps a little.
>>
>> [1]: https://github.com/vonpupp/beancount_cryptocompare
>>
>> On Wednesday, January 2, 2019 at 10:37:03 AM UTC-2, Aamer wrote:
>>>
>>> Vonpupp
>>>
>>> I'm looking for a price fetcher for coinmarketcap. Would you by any 
>>> chance be willing to share your code? Would save me the hassle of having to 
>>> write one from scratch :-)
>>>
>>> On Monday, November 20, 2017 at 2:24:13 AM UTC+2, Vonpupp wrote:
>>>>
>>>> Hi,
>>>>
>>>> Congratulations on beancount. I am new to it but I think it is an 
>>>> amazing software, therefore I would like to take the most advantage of it. 
>>>> This is actually my first message on the forum.
>>>>
>>>> I would like to use beancount with cryptocurrencies. I have may doubts 
>>>> but I prefer to take one step at a time. What I would like to be able to 
>>>> do 
>>>> first is to be able to see the my portfolio value at the present time. For 
>>>> instance, let's assume the following file:
>>>>
>>>> ; -*- mode: org; mode: beancount; coding: utf-8; fill-column: 400; -*-
>>>> ;
>>>> ; Cheatsheet
>>>> ; 
>>>> https://docs.google.com/document/d/1M4GwF6BkcXyVVvj4yXBJMX7YFXpxlxo95W6CpU3uWVc/edit
>>>>
>>>> option "title" "Crypto"
>>>> option "operating_currency" "ETH"
>>>> option "operating_currency" "GAS"
>>>> option "operating_currency" "LTC"
>>>> option "operating_currency" "NEO"
>>>>
>>>> plugin "beancount.plugins.book_conversions" 
>>>> "Assets:Crypto:ETH,Income:Capital-gains"
>>>>
>>>> ;* Equity
>>>> ;2017-11-01 open Equity:Opening-Balances
>>>>
>>>> * Account declarations
>>>> ; Account1
>>>> 2017-08-18 open Assets:Crypto:ETH:Account1             ETH
>>>> 2017-08-18 open Assets:Crypto:LTC:Account1             LTC
>>>> ; Account2
>>>> 2017-08-18 open Assets:Crypto:ETH:Account2             ETH
>>>> ; Exchange
>>>> 2017-08-18 open Assets:Crypto:GAS:Exchange             GAS
>>>> 2017-08-18 open Assets:Crypto:NEO:Exchange             NEO
>>>>
>>>> 2017-08-18 open Expenses:Crypto:ETH:Balance            ETH
>>>> 2017-08-18 open Expenses:Crypto:GAS:Balance            GAS
>>>> 2017-08-18 open Expenses:Crypto:LTC:Balance            LTC
>>>> 2017-08-18 open Expenses:Crypto:NEO:Balance            NEO
>>>>
>>>> * Income
>>>> 2017-08-18 open Income:Capital-gains
>>>>
>>>> * Expenses
>>>> 2017-08-18 open Expenses:Financial:Commisions:USD
>>>>
>>>> * Transactions
>>>> 2017-11-19 * "Opening balance: Account1"
>>>>     Assets:Crypto:ETH:Account1                5.12561083 ETH
>>>>     Assets:Crypto:LTC:Account1                7.58990978 LTC
>>>>     Expenses:Crypto:ETH:Balance              -5.12561083 ETH
>>>>     Expenses:Crypto:LTC:Balance              -7.58990978 LTC
>>>>
>>>> 2017-11-19 * "Opening balance: Account2"
>>>>     Assets:Crypto:ETH:Account2                3.968560 ETH
>>>>     Expenses:Crypto:ETH:Balance              -3.968560 ETH
>>>>
>>>> 2017-11-19 * "Opening balance: Exchange"
>>>>     Assets:Crypto:NEO:Exchange                4 NEO
>>>>     Assets:Crypto:GAS:Exchange                0.18651499 GAS
>>>>     Expenses:Crypto:NEO:Balance              -4 NEO
>>>>     Expenses:Crypto:GAS:Balance              -0.18651499 GAS
>>>>
>>>> I am not experienced with accounting and english is not my primary 
>>>> language, but I guess the file is in "accounting good shape" and it makes 
>>>> sense somehow. If not please let me know.
>>>>
>>>> Now let's go to the point. Assuming that file I would like to be able 
>>>> to issue a command on the command line and be able to see the portfolio in 
>>>> USD or EUR at the present time value. I can query most of the coins using 
>>>> a 
>>>> pip package, the question is, how I do that? I have read the "Prices in 
>>>> Beancount" [1] google docs file, however there is no example and it would 
>>>> be very useful to grasp a bit better how everything ties up. Is there any 
>>>> example of fetcher module so I can build mine on top of it? Or if you are 
>>>> aware of any module for prices that works with crypto that I could use out 
>>>> of the box it would be even better.
>>>>
>>>> Please note that each coin might be on an exchange account or in a 
>>>> wallet (account1 or account2). I would like to get the overview of this 
>>>> sum, for instance when I refer to "ETH" I would like to see as it appears 
>>>> on the balance, but at the current USD or EUR price, and so for the other 
>>>> currencies.
>>>>
>>>> From what I understood about the prices document, the prices will be 
>>>> fetched and saved on the beancount file automatically. I would like to do 
>>>> this automatically on a weekly basis, so I guess cron is my friend here. I 
>>>> guess it is wise to use a separated file and link them together somehow.
>>>>
>>>> I would also like (if possible) to have this on a web interface like 
>>>> fava or similar if possible. I guess this might work automatically once 
>>>> the 
>>>> prices are correctly fetched.
>>>>
>>>> Could you please point me into the right directions to get all these 
>>>> things working properly?
>>>>
>>>> Thank you very much.
>>>>
>>>> [1]: 
>>>> https://docs.google.com/document/d/1thYRAMell_QT1Da1F_laprSs6BlROZjyK_h3V8qHW9c/edit
>>>>
>>>

-- 
You received this message because you are subscribed to the Google Groups 
"Beancount" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To post to this group, send email to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/beancount/752a8ea4-cfde-4e0b-a161-99696cda9f79%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
import requests
import time
from datetime import datetime, tzinfo, timedelta
from string import Template

from bs4 import BeautifulSoup

from beancount.core.number import D
from beancount.prices import source
from beancount.utils.date_utils import parse_date_liberally

ZERO = timedelta(0)
BASE_URL_TEMPLATE = Template("https://coinmarketcap.com/currencies/$ticker/historical-data/?start=$date&end=$date";)
CURRENCY = "USD"
TIME_DELAY = 1

class UTCtzinfo(tzinfo):
    def utcoffset(self, dt):
        return ZERO

    def tzname(self, dt):
        return "UTC"

    def dst(self, dt):
        return ZERO

utc = UTCtzinfo()

class CoinmarketcapError(ValueError):
    "An error from the Coinmarketcap API."

class Source(source.Source):
    def _get_price_for_date(self, ticker, date=None):
        time.sleep(TIME_DELAY)

        if date == None:
            date_string = ""
        else:
            date_string = date.strftime("%Y%m%d")

        url = BASE_URL_TEMPLATE.substitute(date=date_string, ticker=ticker)

        try:
            content = requests.get(url).content
            soup = BeautifulSoup(content,'html.parser')
            table = soup.find('table', {'class': 'table'})
            tr = table.findChildren('tr')[1]
            data = [td.text.strip() for td in tr.findChildren('td')]

            parsed_date = parse_date_liberally(data[0])
            date = datetime(parsed_date.year, parsed_date.month, parsed_date.day, tzinfo=utc)

            price = D(data[4])

            return source.SourcePrice(price, date, CURRENCY)

        except KeyError:
            raise CoinmarketcapError("Invalid response from Coinmarketcap: {}".format(repr(content)))
        except AttributeError:
            raise CoinmarketcapError("Invalid response from Coinmarketcap: {}".format(repr(content)))

    def get_latest_price(self, ticker):
        return self._get_price_for_date(ticker, None)

    def get_historical_price(self, ticker, time):
        return self._get_price_for_date(ticker, time)

Reply via email to