首页  >  All tags  >  beancount

使用 chatGPT 编写自动添加 beancount balance 断言语句

我使用 beancount 记账流程中的有一步是这样的,将每张信用卡的账单日添加到滴答清单中,每月重复。 每当到达账单日时,提醒我在 beancount 文件中添加一条对应帐目的 balance 断言语句,由于大部分信用卡 的出账是有滞后的,所以该balance断言通常需要同时加上!标记,便于后续账单出来后修改。

这个过程是比较机械的,所以我想到了使用 chatGPT 来自动化这个过程,这样我只需要在出账后手动更新自动添加 的断言语句,将金额修改为正确的还款金额,同时去除!标记。最终的脚本如下。

import datetime

def add_balance_statement(ledger_path, account, date, balance, currency):
    with open(ledger_path, 'a') as file:
        file.write(f"{date} balance {account} {balance} {currency}\n")

def auto_add_balance_statements(ledger_path, credit_cards):
    today = datetime.date.today()
    for card in credit_cards:
        bill_date = card['bill_date']
        accounts = card['accounts']
        balance = card['balance']
        currency = card['currency']
        if today.day == bill_date:
            for account in accounts:
                add_balance_statement(ledger_path, account, today, balance, currency)
                print(f"Balance statement added for {account} on {today}.")

# Specify the path to your Beancount ledger file
ledger_file_path = "<ledger_path>"

# Specify your credit card details (bill date, accounts, balance, and currency)
credit_cards = [
    {
        'bill_date': 1,  # Example: 1st of the month
        'accounts': [
            {'account': 'Assets:CreditCards:Card1:Account1', 'currency': 'USD'},  # Example: Account1 for Card1 with USD currency
            {'account': 'Assets:CreditCards:Card1:Account2', 'currency': 'EUR'},  # Example: Account2 for Card1 with EUR currency
        ],
        'balance': 1000.00,  # Example: Current balance for Card1
        'currency': 'USD'  # Example: Currency for Card1
    },
    {
        'bill_date': 15,  # Example: 15th of the month
        'accounts': [
            {'account': 'Assets:CreditCards:Card2:Account1', 'currency': 'USD'},  # Example: Account1 for Card2 with USD currency
            {'account': 'Assets:CreditCards:Card2:Account2', 'currency': 'GBP'},  # Example: Account2 for Card2 with GBP currency
        ],
        'balance': 2000.00,  # Example: Current balance for Card2
        'currency': 'USD'  # Example: Currency for Card2
    },
    # Add more credit card details as needed
]

# Call the function to automatically add balance statements
auto_add_balance_statements(ledger_file_path, credit_cards)

对于有兴趣的读者,可以看我和 chatgpt 的几轮对话。

Q: Write a python script, it check today’s date, if it match a specific day in a month, writing some content to a file, whois path is <path>.

A: Certainly! Here’s a Python script that checks if today’s date matches a specific day in a month and writes some content to a file:

import datetime

def write_content_to_file(path, content):
    with open(path, 'a') as file:
        file.write(content + '\n')

def check_and_write_content(path, day, month, content):
    today = datetime.date.today()
    if today.day == day and today.month == month:
        write_content_to_file(path, content)
        print("Content written to the file.")
    else:
        print("Today's date does not match the specified day.")

# Specify the path, day, month, and content
file_path = "<path>"
day = 15
month = 7
content = "This is the content to be written."

# Call the function to check and write content
check_and_write_content(file_path, day, month, content)

In the script above, you need to replace "<path>" with the actual path to the file where you want to write the content. Also, specify the daymonth, and content variables according to your requirements.

The script checks if today’s date matches the specified day and month. If it does, it calls the write_content_to_file function to append the content to the file. If the date doesn’t match, it prints a message indicating that today’s date doesn’t match the specified day.

Q:I have many credit cards, each card have different bill date. I want a python script can auto add a balance statement to my beancount ledger. please help me writing this script. A:Certainly! Here’s a Python script that can help you automatically add a balance statement to your Beancount ledger based on the bill dates of your credit cards:

import datetime

def add_balance_statement(ledger_path, account, date, balance):
    with open(ledger_path, 'a') as file:
        file.write(f"{date} balance {account} {balance}\n")

def auto_add_balance_statements(ledger_path, credit_cards):
    today = datetime.date.today()
    for card in credit_cards:
        bill_date = card['bill_date']
        account = card['account']
        balance = card['balance']
        if today.day == bill_date:
            add_balance_statement(ledger_path, account, today, balance)
            print(f"Balance statement added for {account} on {today}.")

# Specify the path to your Beancount ledger file
ledger_file_path = "<ledger_path>"

# Specify your credit card details (bill date, account, and balance)
credit_cards = [
    {
        'bill_date': 1,  # Example: 1st of the month
        'account': 'Assets:CreditCards:Card1',  # Example: Account for Card1
        'balance': 1000.00  # Example: Current balance for Card1
    },
    {
        'bill_date': 15,  # Example: 15th of the month
        'account': 'Assets:CreditCards:Card2',  # Example: Account for Card2
        'balance': 2000.00  # Example: Current balance for Card2
    },
    # Add more credit card details as needed
]

# Call the function to automatically add balance statements
auto_add_balance_statements(ledger_file_path, credit_cards)

In the script above, you need to replace "<ledger_path>" with the actual path to your Beancount ledger file. Also, specify the bill_dateaccount, and balance for each of your credit cards in the credit_cards list.

The script checks if today’s date matches the bill date for each credit card. If it does, it calls the add_balance_statement function to add a balance statement to the ledger file. The balance statement includes the account, date, and balance for the credit card. If the date doesn’t match the bill date for a particular credit card, it moves on to the next card.

Q:one bill_date can have multiple accounts, refine your code. A:Certainly! Here’s an updated version of the script that allows multiple accounts for a single bill date:

import datetime

def add_balance_statement(ledger_path, account, date, balance):
    with open(ledger_path, 'a') as file:
        file.write(f"{date} balance {account} {balance}\n")

def auto_add_balance_statements(ledger_path, credit_cards):
    today = datetime.date.today()
    for card in credit_cards:
        bill_date = card['bill_date']
        accounts = card['accounts']
        balance = card['balance']
        if today.day == bill_date:
            for account in accounts:
                add_balance_statement(ledger_path, account, today, balance)
                print(f"Balance statement added for {account} on {today}.")

# Specify the path to your Beancount ledger file
ledger_file_path = "<ledger_path>"

# Specify your credit card details (bill date, accounts, and balance)
credit_cards = [
    {
        'bill_date': 1,  # Example: 1st of the month
        'accounts': [
            'Assets:CreditCards:Card1:Account1',  # Example: Account1 for Card1
            'Assets:CreditCards:Card1:Account2',  # Example: Account2 for Card1
        ],
        'balance': 1000.00  # Example: Current balance for Card1
    },
    {
        'bill_date': 15,  # Example: 15th of the month
        'accounts': [
            'Assets:CreditCards:Card2:Account1',  # Example: Account1 for Card2
            'Assets:CreditCards:Card2:Account2',  # Example: Account2 for Card2
        ],
        'balance': 2000.00  # Example: Current balance for Card2
    },
    # Add more credit card details as needed
]

# Call the function to automatically add balance statements
auto_add_balance_statements(ledger_file_path, credit_cards)

In this updated version, each credit card in the credit_cards list has a bill_dateaccounts, and balance. The accounts field is a list of all the accounts associated with that credit card. The script iterates through each credit card and its associated accounts. If today’s date matches the bill date, it adds a balance statement for each account with the specified balance.

Please replace "<ledger_path>" with the actual path to your Beancount ledger file. Also, update the credit card details in the credit_cards list according to your specific accounts and balances.

Q:different accounts can have different currency, please add currency info to account. A:Certainly! Here’s an updated version of the script that includes currency information for each account:

import datetime

def add_balance_statement(ledger_path, account, date, balance, currency):
    with open(ledger_path, 'a') as file:
        file.write(f"{date} balance {account} {balance} {currency}\n")

def auto_add_balance_statements(ledger_path, credit_cards):
    today = datetime.date.today()
    for card in credit_cards:
        bill_date = card['bill_date']
        accounts = card['accounts']
        balance = card['balance']
        currency = card['currency']
        if today.day == bill_date:
            for account in accounts:
                add_balance_statement(ledger_path, account, today, balance, currency)
                print(f"Balance statement added for {account} on {today}.")

# Specify the path to your Beancount ledger file
ledger_file_path = "<ledger_path>"

# Specify your credit card details (bill date, accounts, balance, and currency)
credit_cards = [
    {
        'bill_date': 1,  # Example: 1st of the month
        'accounts': [
            {'account': 'Assets:CreditCards:Card1:Account1', 'currency': 'USD'},  # Example: Account1 for Card1 with USD currency
            {'account': 'Assets:CreditCards:Card1:Account2', 'currency': 'EUR'},  # Example: Account2 for Card1 with EUR currency
        ],
        'balance': 1000.00,  # Example: Current balance for Card1
        'currency': 'USD'  # Example: Currency for Card1
    },
    {
        'bill_date': 15,  # Example: 15th of the month
        'accounts': [
            {'account': 'Assets:CreditCards:Card2:Account1', 'currency': 'USD'},  # Example: Account1 for Card2 with USD currency
            {'account': 'Assets:CreditCards:Card2:Account2', 'currency': 'GBP'},  # Example: Account2 for Card2 with GBP currency
        ],
        'balance': 2000.00,  # Example: Current balance for Card2
        'currency': 'USD'  # Example: Currency for Card2
    },
    # Add more credit card details as needed
]

# Call the function to automatically add balance statements
auto_add_balance_statements(ledger_file_path, credit_cards)

In this updated version, each account in the accounts list of each credit card includes both the account name and the currency. The add_balance_statement function is modified to include the currency parameter when writing the balance statement to the ledger.

Please replace "<ledger_path>" with the actual path to your Beancount ledger file. Also, update the credit card details in the credit_cards list according to your specific accounts, balances, and currencies.

用于 beancount 快速记账的 Telegram Bot

当年从随手记迁移到桌面记账方式(Excel/GnuCash/Beancount)后,确实有一段时间的不适应。 后来实在没有找到好用的移动端记账 APP,同时也适应了桌面记账,遂被驯化认为不需要在移动场景 记账。Costflow 出来之后没有第一时间尝试的原因也在于此,使用一段时间基于 costflow 语法 的 Telegram 机器人之后,发现经常是想要的账户没有配置,导致使用频率并不高。

前段时间的某一天突然意识到,为什么要提前配置账户信息呢?账户信息全部都在账本文件中,直接 查询账本文件不就可以避免冷启动的问题么。遂自己开坑写了一个新的记账机器人 beancount-bot

使用一月有余,今天完善了一下相关功能,更新了文档和使用例子。下面是几点简要说明:

  1. 适合手动记账党 :D
  2. 适合有自己服务器的人(境内服务器需要配置代理),部署在本地 NAS 上也是可行的
  3. 不兼容 costflow 语法,不需要账户信息的配置,账户的匹配是读取账本文件,类似编辑器的账户补全

在这里分享给大家,希望可以节省一点记账/对账的时间,有兴趣的欢迎尝试。

Beancount 账户命名

命名是计算科学中最难的两件事,Beancount 的账户的命名尤其困难。对于从其他记账工具迁移过来的用户,直接将原先的账户结构迁移过来当然是可以的。但是 Beancount 这种文本记账工具,对于账户的处理几乎没有成本,可以任性地添加更多的账户。直接复制原来工具的账户结构可能无法完全发挥 Beancount 的能力。

我个人为 Beancount 的账户命名有提供以下几点指导:

  1. 账户命名在可接受的范围内尽量详细,有账户补全这样的功能在,多级账户名锁造成的额外负担是很小的。带来的好处是显而易见的,最终形成的报表详尽而清晰。此外,在后期使用正则替换合并账户是很容易的,但是拆分账户只能对每一条记录进行检查。
  2. 多使用多级账户,在 fava 中折叠次级账户后,可以清晰地看到上一级账户的总额。
  3. 尽量遵从你的直觉,想象你在以后遇到一笔账户,直觉告诉你应该放到哪个账户。这样可以最大地降低记账的认知负担。当然,这一点可以随着使用慢慢优化自己的账户命名,毕竟文本账本的一大优点就是可以方便地进行正则替换。

最后附上一些其他记账工具默认的账户命名,可供参考。

  • MoneyWiz 默认账户名

      Automobile
          Accessories
          Car Insurance
          Gas/Fuel
          Lease
          Maintenance
          Other
          Parking
      Bills
          Cable
          Electricity
          Gas
          Internet/Broadband
          Mobile Phone
          Other
          Phone
          Water
      Clothing
          Accessories
          Clothes
          Jewelry
          Other
          Shoes
      Digital
          Apps
          Books
          Movies
          Music
          Other
          Podcasts
          TV Shows
      Food & Dining
          Dining/Eating Out
          Groceries
          Other
      Health Care
          Dental
          Eye Care
          Health Insurance
          Medical
          Other
          Pharmacy
      Housing
          Furniture/Accessories
          Home Insurance
          Maintenance
          Mortgage
          Other
          Rent
      Leisure
          Entertainment
          Fitness/Sport
          Other
          Personal Care
      Loans
          Other
          Taxes
          Transportation
          Travel
    
  • mint-categories https://www.mint.com/mint-categories

      Expenses (all types)
          1. Rent/Mortgage
              a. Home Owners Association Dues
              b. Rental Insurance
              c. Home Owners Insurance
          2. Fixed Expenses
              a. Utilities
              b. Gas
              c. Electric
              d. Water/Trash/Sewer
              e. Cable/Internet/Phone
              f. Cell Phone
              g. Credit Cards
              h. Car Expenses
              i. Maintenance
              j. Gas
          3. Extra Expenses
              a. Grocery (Food)
              b. Clothes/Shoes/Hygiene
              c. Extra for Home Expenses
          4. Savings
              a. Savings Account. Speak with employer; some saving plans can pull from paycheck before taxes. That means less of your paycheck is taxable.
              b. Create an Emergency Fund; it should be at least 6 months of expenses. Emergencies can happen and drain a well-established savings account
          5. Taxes
              a. No explanation needed
          6. Fun Cash
              a. Out with friends
              b. Movies
              c. Vacations
    
  • GnuCash

      Adjustment
      Auto
          Fees
          Gas
          Parking
          Repair and Maintenance
      Bank Service Charge
      Books
      Cable
      Charity
      Clothes
      Computer
      Dining
      Education
      Entertainment
          Music/Movies
          Recreation
          Travel
      Gifts
      Groceries
      Hobbies
      Insurance
          Auto Insurance
          Health Insurance
          Life Insurance
      Laundry/Dry Cleaning
      Medical Expenses
      Miscellaneous
      Online Services
      Phone
      Public Transportation
      Subscriptions
      Supplies
      Taxes
          Federal
          Medicare
          Other Tax
          Social Security
          State/Province
      Utilities
          Electric
          Garbage collection
          Gas
          Water
    
  • beancount-boilerplate-cn 这个项目中的账户命名也可以参考。

Beancount 投资回报计算与可视化

TL;DR 使用 fava-portfolio-returns1 ,可在 fava 中直观展示投资回报率详细数据,该插件的数据来源是 beangrow2

几种方案概述🔗

fava-portfolio-returns + beangrow🔗

对于使用 Beancount 记录投资帐目的人来说,如何评估自己的投资回报一直是一个未解决的问题。前一段时间 Beancount 的开发者 Martin 写了一个计算回报率的小工具32,姑且可以算是 v3 版本功能的一个小前瞻,尝试使用之后,虽然目前还是比较粗糙的脚本,但是基本可以计算出来年化的投资回报率了。Beancount 用户 Redio 也写了详细的 Review4,可以作为第一个文档的补充,使用时参考。

2023-08-29 更新 近日在邮件列表看到了 fava-portfolio-returns1 项目,这是一个用于在 fava 中展示投资历史回报的插件,后端数据来自 beangrow,尝试了一下发现运行良好,当然运行良好的前提是解决一堆报错,这个插件对 beangrow 配置文件的错误容忍程度较低,遇到错误时可开启 debug 模式查看报错信息。这里放两张官方的截图,展示了该插件的功能。具体使用方法参见官方仓库 README。

![report_overview]({{ site.cdn_url }}/img/report_overview.png)

![report_vht]({{ site.cdn_url }}/img/report_vht.png)

fava_investor🔗

fava_investor 5 是另一个试图在 fava 中进行投资回报可视化的插件,目前处于开发中,由于我的投资帐目比较复杂,目前没有办法成功运行。对于简单的投资帐目(例如不包含数字货币),可以尝试使用。

beancount_portfolio_report🔗

另外还有一些比较小的工具,例如 beancount_portfolio_allocation6是一个根据当前市值计算持有资产比例的脚本,方便用来进行资产重新配置。我在此插件的基础上,进行了一些简单的修改,重新命名为 beancount_portfolio_report7,用于输出当前各类资产的市值、回报和总体回报率(非年化)。

beancount-boilerplate-cn🔗

beancount-boilerplate-cn 有部分净值计算的工具,但是同样不适合我这种比较复杂的投资记账。没有尝试。

beancount.io🔗

beancount.io 在网站上也提供了 Stock Analysis 工具,可惜没有看到开源,处于数据安全顾虑,目前没有体验。从 demo 来看完成度还是比较高的。侧重点在于比较不同风险资产的盈利情况。

读者可以根据自己的实际情况,选用上述工具,进行投资回报的计算。其实我理想中的功能,是类似且慢小账本,绘出净值变化曲线,自动计算回报率,以及和大盘指数进行对比。对于 Beancount 来说,前二者需要的数据都是存在的,大盘指数这个可以通过 beanprice 指定来源来进行对比。只能期待 v3 版本早日出来了。

注意🔗

关于资产价格。计算投资回报的前提是 Beancount 账本文件中有对应资产的价格数据,大部分用户可能没有这个数据或者数据不全,可以使用 bean-price 或者 beanprice8 (分离出来的新版本)进行资产价格获取。现在新版本的 beanprice 已经支持时间段的价格获取,可补全资产的历史价格。

参考链接🔗

3

Calculating Portfolio Returns 4: Martin’s Returns Computation Review 5: Asset allocation plugin for fava/beancount (personal finance software) https://github.com/redstreet/fava_investor 8: beanprice https://github.com/beancount/beanprice 6: Reports on portfolio asset allocations in beancount. Useful for risk analysis and for rebalancing purposes. https://github.com/ghislainbourgeois/beancount_portfolio_allocation 7: Reports on portfolio performance in beancount. Useful for risk analysis. https://github.com/wogong/beancount_portfolio_report 2: beangrow 1: fava-portfolio-returns

关于记账工具

本文记录个人关于记账以及记账工具选择的一些想法和经验。

你需要记账吗?🔗

记账利弊皆有,因人而异。最重要一点,记账可以帮助你清晰量化地认识个人收支情况。我是一个喜欢量化存档生活的人,以前会备份各种聊天记录、短信、通话记录等信息,日常也有写日记的习惯,账本相当于另一个维度的日记。

记账让我对自己的生活有更强大的掌控感(也许是错觉)。据说记账有以下缺点,可能会让人变小气,太麻烦等,读者根据自己的实际情况考虑。记不记账纯属个人选择,若您有兴趣开始记账的习惯,希望本文可以提供一点参考。

记账基本原则🔗

  1. 收付实现制与权责发生制 我采用收付实现制记账原则,与之对应的另一个词是权责发生制,举个简单的例子说明二者的含义。拿交房租来说,年初你交了未来半年的房租 12000 CNY,收付实现制会这么记账,年初支出 12000 CNY,只有这 1 笔。权责发生制会这么记,未来的 6 个月,每月支出 2000 CNY,共 6 笔。 个人采用的是前者,即收付实现制,主要优点是方便对账,毕竟银行的流水只有 1 笔 12000 CNY 的。他的缺点也很明显,会导致月度财务报表并不准确,不能清晰反应月度收支情况。所以采用收付实现制,在查看报表的时候,不应简单的去看数字的绝对值。

  2. 负支出 电商购物退款退货的场景很常见,月初买了一个东西,记了一笔支出,到货后发现不合适申请退货,中旬退款回到原支付渠道。我该怎么记这笔退款呢?省事的办法是把月初记的支出那笔删除,还有一个办法是退款导致时记一笔收入。但是聪明的你一定会发现这两种方法都不太理想,前者不能反应真实流水,后者会导致月度报表支出与收入都虚高。 比较合理的做法是退款时记录一笔负支出。当你意识到支出可以是负的时候,很多帐目记起来就简单多了。

记账工具🔗

1.移动设备

主要是 Android 和 iOS 两个平台。主流的记账工具基本都是全平台的了。其中功能丰富占据大部分用户的记账应用有二:

  • 随手记,我使用随手记时在论坛提出的关于多币种的问题1
  • 挖财
  • MoneyWiz, iOS

对于入门者,推荐使用这二者之一开始。基本满足大部分功能需求。

对于不需要如此复杂功能,例如多账户的用户来说,也可以选择很多主打简洁的应用,例如 iOS 下的 Expense。由于我不是 Android 用户,所以此平台下的轻量级应用请自行寻找。

2.桌面

桌面的记账方法相对来说比较严肃,简单的可以采用 Excel 记账,复杂的可以采用专业的财务软件。总结来说:

  • MoneyWiz, macOS
  • Excel, 网上寻找他人分享的记账模板,略加修改便可以使用
  • Gnucash, 开源软件,多平台支持。复式记账,多币种记账。Windows 下的桌面客户端虽然丑陋但是可用,功能强大
  • Ledger, 简单的命令行记账工具,复式记账
  • Beancount, Python编写,命令行工具,多币种记账功能强大,复式记账。可以认为是 Ledger 的升级版。可以参考推特上的讨论2

以上软件按照新手友好程度排列。

个人记账工具迁移路线🔗

最初,我使用 Excel 模板记账,2013 年 12 月以后尝试随手记,2015 年 12 月开始使用 Gnucash。对于轻松的记账,不太需要会计知识,在使用中多思考多搜索即可。进阶的话需要了解复式记账的概念,2016 年初开始使用命令行工具 Beancount。

Beancount🔗

  1. website
  2. Documents
  3. Google Group
  4. repository
  5. another web interface
  6. vim plugin
  7. Hacker News 讨论

一些参考链接🔗