Ledger 是一个命令行会计工具,基于文本日记账提供复式记账功能。它没有任何花哨的功能,让用户回到了用户界面甚至还未在其父辈的 CRT 显示器上闪烁的时代。
Ledger 是一款有勇气存在的会计工具。它不提供花哨的功能,让用户回归到用户界面还在父辈 CRT 显示器上闪烁之前的时代。
它真正提供的是一个复式记账簿,具备现代同类产品的所有灵活性和强大功能,但没有任何冗余。可以把它看作是会计工具中的麦芬蛋糕。
要使用它,你需要开始记账。这是所有会计的基础,如果你还没有开始,现在是学习的时候了。你的支票簿附带的小册子就是一个账本,所以我们将以此为基础来描述复式记账法。
支票簿账本记录与单一账户(支票账户)相关的借方(减少或取款)和贷方(增加或存款)。资金的来源和去向在收款人字段中描述,你在那里写下个人或公司的名称。维护支票簿账本的最终目的是了解有多少可用资金。这确实是所有账本的目标。
计算机增加的是遍历这些记账项的能力,告诉你关于消费习惯的信息;让你制定预算并控制支出;将资金虚拟存入储蓄账户而无需实际转移资金等等。当你记账时,你正在记录关于生活和习惯的信息,有时这些信息可以开始告诉你一些你未意识到的事情。这就是所有优秀会计工具的目标。
从支票簿账本升级的下一个阶段是跟踪所有账户(不仅仅是支票账户)的账本。在这样的账本中,你不仅记录谁被支付(在借方情况下),还记录资金的来源。在支票簿账本中,假定所有资金都来自你的支票账户。但在通用账本中,你用两行记录记账项:源账户和目标账户。每笔对另一个账户的贷方必须始终有至少一个账户的借方。这就是“复式”记账的含义:账本必须始终平衡为零,借方和贷方数量相等。
例如,假设您有一个支票账户和一个经纪账户,并且可以从这两个账户开具支票。您决定使用一本通用日记账来记录这两个账户,而不是保留两本支票簿。在这本通用日记账中,您需要记录支付给太平洋贝尔公司的月电话费账单,以及从经纪账户到支票账户的转账(通过支票)。假设太平洋贝尔的账单是 23.00 美元,您想从支票账户支付。在通用日记账中,除了记录资金去向,还需要说明资金来源。这些交易可能如下所示:
9/29 太平洋贝尔 $23.00 $23.00 支票账户 $-23.00 0 9/30 支票账户 $100.00 $100.00 (123) 经纪账户 $-100.00 0
过账必须平衡至 0 美元:23 美元支付给太平洋贝尔,23 美元来自支票账户。下一笔条目显示从您的经纪账户开具的 123 号支票,将资金转账至您的支票账户。这两笔交易中资金只是从一个账户转移到另一个账户,没有剩余需要核算的资金。这是复式记账法的基础:资金不会凭空产生或消失;它总是从一个账户过账到另一个账户。
维护通用日记账与维护两本独立的日记账效果相同:一本用于太平洋贝尔,一本用于支票账户。在这种情况下,每次在一本日记账中记录付款时,您需要在另一本中记录相应的取款。这样更容易记录“滚动余额”,因为您不必回溯上次该账户被引用的时间——但如果您处理多个账户,这也意味着需要很多本日记账。
这里适合对“账户”一词的使用做个说明。大多数个人认为账户是机构为他们持有资金的某种东西。Ledger 使用这个词的更广义定义。账户是资金可以去的任何地方。其他财务程序使用“类别”,而 Ledger 使用账户。因此,例如,如果您在 Trader Joe's 购买一些杂货,然后在 Whole Food Market 购买更多杂货,您可能会这样分配交易:
2011/03/15 Trader Joe's 支出:杂货 $100.00 资产:支票账户 2011/03/15 Whole Food Market 支出:杂货 $75.00 资产:支票账户
在这两种情况下,资金都流向‘杂货’账户,尽管收款人不同。您可以按任何方式设置账户。
这就是计算机化记账的美妙之处。Ledger 程序的目的是通过为您跟踪余额,使通用日记账记账变得简单。您唯一的工作是输入过账。如果单个过账不平衡,Ledger 会显示错误并指出不正确的过账。1
总之,Ledger 的使用有两个方面:更新日记账数据文件,以及使用 Ledger 工具查看交易的汇总结果。
仅作为示例——为那些想一头扎进去的人提供一个起点——以下是上述日记账交易,格式化为 Ledger 程序希望看到的形式:
2004/09/29 太平洋贝尔 支出:太平洋贝尔 $23.00 资产:支票账户
此文件中的账户余额和登记簿,如果保存为ledger.dat,可以使用以下命令报告:
$ ledger -f ledger.dat balance
$-23.00 资产:支票账户 $23.00 支出:太平洋贝尔 -------------------- 0
或
$ ledger -f ledger.dat register checking
04-9 月-29 太平洋贝尔 资产:支票账户 $-23.00 $-23.00
甚至:
$ ledger -f ledger.dat register Bell
04-9 月-29 太平洋贝尔费用:太平洋贝尔 $23.00 $23.00
Ledger 与其他财务软件的一个重要区别在于,Ledger 永远不会修改您的输入文件。您可以用任何喜欢的方式创建和编辑该文件,但 Ledger 仅用于分析数据,而非修改数据。
Ledger 使用 ANSI C++ 编写,应能在任何 Unix 平台上编译。构建和安装 Ledger 最简单的方法是使用预制的 acprep 脚本,它能完成大量基础工作:
# 安装缺失的依赖项 ./acprep dependencies # 构建 Ledger ./acprep update # 运行实际安装 make install
请参阅 'acprep' 的 'help' 子命令,它解释了其众多选项中的一些。您可以运行 'make check' 来确认结果,并运行 'make install' 进行安装。如果这些说明对您无效,您可以查看源代码目录中的 'INSTALL.md' 以获取最新的构建说明。
Ledger 拥有基于 GNU Info 的完整在线帮助系统。本手册可以直接从命令行使用 info ledger 进行搜索,这将在您的 TTY 中显示整个手册。或者,可以通过 man ledger 或 ledger --help 从命令行访问较短的 man 页面。
如果您需要关于如何使用 Ledger 的帮助,或遇到问题,可以加入 Ledger 邮件列表:http://groups.google.com/group/ledger-cli。
您也可以在 IRC 服务器 irc.libera.chat 上的 #ledger 频道中找到帮助。
有许多人在会计应用中使用 Ledger。一些人记录了如何使用 Ledger 的功能来解决他们的会计问题。
其中一个教程专门为寻求使用 Ledger 的非营利慈善机构设计,可在 https://k.sfconservancy.org/NPO-Accounting/npo-ledger-cli 找到(GitHub 上也有副本:https://github.com/conservancy/npo-ledger-cli/)。如果您正在寻找有关如何使用 Ledger 的标记系统处理发票、按项目目标跟踪费用等概念的信息,可能会发现该教程很有用。(与上述 Ledger 设置相关的一些审计报告脚本可以在 Ledger 自己的源代码仓库中的 contrib/non-profit-audit-reports/ 找到。)
日记账是记录您财务交易的账本,也是使用 Ledger 的核心。现在我们只想初步了解 Ledger 的功能。源代码发行版中包含一个示例日记账文件,名为 drewr3.dat(参见 示例日记账文件)。将其复制到方便的位置,并在该目录下打开终端窗口。
如果您希望立即开始使用自己的日记账,请参阅 维护日记账。
请注意,作为一个命令行程序,Ledger 是通过您的 shell 来控制的。有多种不同的命令 shell,它们在某些特殊字符的处理上略有不同。特别是,“bash” shell 对‘$’符号的解释方式与 Ledger 不同,必须进行转义才能传递给实际程序。另一个例子是“zsh”,它对‘^’的解释方式也与 Ledger 的预期不同。在后续所有情况下,输入命令行参数时都应考虑到这一点。不同 shell 之间的差异太多,无法为每个 shell 提供具体示例。
要查找所有账户的余额,请运行以下命令:
$ ledger -f drewr3.dat balance
Ledger 将生成:
$ -3,804.00 资产 $ 1,396.00 支票账户 $ 30.00 业务 $ -5,200.00 储蓄账户 $ -1,000.00 权益:期初余额 $ 6,654.00 支出 $ 5,500.00 汽车 $ 20.00 书籍 $ 300.00 托管账户 $ 334.00 食品:杂货 $ 500.00 利息:抵押贷款 $ -2,030.00 收入 $ -2,000.00 工资 $ -30.00 销售 $ -63.60 负债 $ -20.00 万事达卡 $ 200.00 抵押贷款:本金 $ -243.60 什一税 -------------------- $ -243.60
显示所有账户的余额。选项和搜索条件可以缩小范围,仅显示您想要的账户。
一个更有用的报表是仅显示您的资产和负债:
$ ledger -f drewr3.dat balance Assets Liabilities
$ -3,804.00 资产 $ 1,396.00 支票账户 $ 30.00 业务 $ -5,200.00 储蓄账户 $ -63.60 负债 $ -20.00 万事达卡 $ 200.00 抵押贷款:本金 $ -243.60 什一税 -------------------- $ -3,867.60
要显示所有交易和运行总计:
$ ledger -f drewr3.dat register
Ledger 将生成:
10-12-01 检查余额 资产:支票账户 $ 1,000.00 $ 1,000.00 权益:期初余额 $ -1,000.00 0 10-12-20 有机合作社 支出:食品:杂货 $ 37.50 $ 37.50 支出:食品:杂货 $ 37.50 $ 75.00 支出:食品:杂货 $ 37.50 $ 112.50 支出:食品:杂货 $ 37.50 $ 150.00 支出:食品:杂货 $ 37.50 $ 187.50 支出:食品:杂货 $ 37.50 $ 225.00 资产:支票账户 $ -225.00 0 10-12-28 Acme 抵押 负债:抵押:本金 $ 200.00 $ 200.00 支出:利息:抵押 $ 500.00 $ 700.00 支出:托管账户 $ 300.00 $ 1,000.00 资产:支票账户 $ -1,000.00 0 11-01-02 杂货店 支出:食品:杂货 $ 65.00 $ 65.00 资产:支票账户 $ -65.00 0 11-01-05 雇主 资产:支票账户 $ 2,000.00 $ 2,000.00 收入:工资 $ -2,000.00 0 (负债:什一税) $ -240.00 $ -240.00 11-01-14 银行 资产:储蓄账户 $ 300.00 $ 60.00 资产:支票账户 $ -300.00 $ -240.00 11-01-19 杂货店 支出:食品:杂货 $ 44.00 $ -196.00 资产:支票账户 $ -44.00 $ -240.00 11-01-25 银行 资产:支票账户 $ 5,500.00 $ 5,260.00 资产:储蓄账户 $ -5,500.00 $ -240.00 11-01-25 Tom 二手车行 支出:汽车 $ 5,500.00 $ 5,260.00 资产:支票账户 $ -5,500.00 $ -240.00 11-01-27 书店 支出:书籍 $ 20.00 $ -220.00 负债:万事达卡 $ -20.00 $ -240.00 11-12-01 销售 资产:支票账户:业务 $ 30.00 $ -210.00 收入:销售额 $ -30.00 $ -240.00 (负债:什一税) $ -3.60 $ -243.60
要将其限制为更有用的子集,只需添加您希望查看交易记录的账户:
$ ledger -f drewr3.dat register Groceries
10-12-20 有机合作社 支出:食品:杂货 $ 37.50 $ 37.50 支出:食品:杂货 $ 37.50 $ 75.00 支出:食品:杂货 $ 37.50 $ 112.50 支出:食品:杂货 $ 37.50 $ 150.00 支出:食品:杂货 $ 37.50 $ 187.50 支出:食品:杂货 $ 37.50 $ 225.00 11-01-02 杂货店 支出:食品:杂货 $ 65.00 $ 290.00 11-01-19 杂货店 支出:食品:杂货 $ 44.00 $ 334.00
这与“Groceries”账户报告的余额相匹配:
$ ledger -f drewr3.dat balance Groceries
$ 334.00 支出:食品:杂货
如果您只想查找特定收款人的交易,请使用“payee”或“@”:
$ ledger -f drewr3.dat register payee "Organic"
10-12-20 有机合作社 支出:食品:杂货 $ 37.50 $ 37.50 支出:食品:杂货 $ 37.50 $ 75.00 支出:食品:杂货 $ 37.50 $ 112.50 支出:食品:杂货 $ 37.50 $ 150.00 支出:食品:杂货 $ 37.50 $ 187.50 支出:食品:杂货 $ 37.50 $ 225.00 资产:支票账户 $ -225.00 0
一个非常有用的报告是显示您的应付款项与实际记录的支出之间的对比。支票可能需要几天时间才能清算,但您应将其视为已支出的资金。cleared报告正是显示这一点(请注意,对于包含多种商品的账户,cleared报告的格式可能不正确):
$ ledger -f drewr3.dat cleared
$ -3,804.00 $ 775.00 资产 $ 1,396.00 $ 775.00 10-12 月-20 支票账户 $ 30.00 0 商业账户 $ -5,200.00 0 储蓄账户 $ -1,000.00 $ -1,000.00 10-12 月-01 权益:初始余额 $ 6,654.00 $ 225.00 支出 $ 5,500.00 0 汽车 $ 20.00 0 书籍 $ 300.00 0 托管账户 $ 334.00 $ 225.00 10-12 月-20 食品:杂货 $ 500.00 0 利息:抵押贷款 $ -2,030.00 0 收入 $ -2,000.00 0 工资 $ -30.00 0 销售 $ -63.60 0 负债 $ -20.00 0 万事达卡 $ 200.00 0 抵押贷款:本金 $ -243.60 0 什一税 ---------------- ---------------- --------- $ -243.60 0
第一列显示未结余额,第二列显示“已清算”余额。
在 Windows 命令提示符下使用 ledger 有一个显著限制。CMD.EXE 仅限于标准 ASCII 字符,因此无法显示除美元符号‘$’以外的任何货币符号。
会计核算只是简单地追踪您的资金。它可以是从什么都不做,只是等待自动透支保护启动(或不启动),到完整的复式记账系统。Ledger 实现了后者。使用 ledger,您可以处理个人财务或业务财务。复式记账具有可扩展性。
会计师会谈论“贷方”和“借方”,但其含义通常与普通人的理解不同。为避免混淆,Ledger 仅使用减法和加法,尽管其基本意图与标准会计原则相同。
请记住,每笔过账都会涉及两个或更多账户。资金从一个或多个账户转移到一个或多个其他账户。为了记录过账,金额从源账户减去,并加到目标账户。
为了正确编写 Ledger 交易,您必须确定资金来自哪里以及去向哪里。例如,当您收到工资时,您必须将资金添加到您的银行账户,同时从收入账户中减去它:
9/29 我的雇主 资产:支票账户 $500.00 收入:工资 $-500.00
为什么收入是负数?当您查看分类账的余额总计时,可能会惊讶地发现支出是正数,而收入是负数。这可能需要一些时间来适应,但要正确使用分类账,您必须从资金流动的角度来思考。与其让 Ledger「修正」负号,不如让我们理解它们存在的原因。
当您赚钱时,钱必须来自某个地方。我们称那个地方为「社会」。为了让社会给您收入,您必须从社会取走(提取)资金,才能将其存入(支付到)您的银行账户。当您随后花费这笔钱时,它会离开您的银行账户(一次取款)并返回社会(一次支付)。这就是为什么收入显示为负数——它反映了您从社会提取的资金——而支出为正数——它是您返还给社会的金额。这些增减最终总是会相互抵消,因为您没有创造新货币的能力:货币总是来自某个地方,最终也总是会离开。这是经济的起点,之后的解释会变得异常复杂。
基于这个解释,这里有另一种看待余额报告的方式:每个负数意味着该账户、个人或地方现在的资金比您开始记账时少;每个正数意味着该账户、个人或地方现在的资金比您开始记账时多。明白了吗?
资产是您拥有的资金,而负债是您欠他人的资金。「负债」只是对债务的一个更包容的称呼。
资产通常通过从收入账户转移资金来增加,例如当您获得报酬时。这是一个典型交易:
2004/09/29 我的雇主 资产:支票账户 $500.00 收入:薪水 $-500.00
这里的资金来自属于「我的雇主」的收入账户,并被转移到您的支票账户。这笔钱现在是您的,因此它成为资产。
负债追踪欠他人的资金。当您借钱购买物品或欠某人钱时,就会发生这种情况。这是一个通过使用信用卡消费来增加万事达卡负债的例子:
2004/09/30 餐厅 支出:餐饮 $25.00 负债:万事达卡 $-25.00
餐饮账户余额现在显示在餐饮上花费了 25 美元,而万事达卡上相应欠款 25 美元——因此显示为 $-25.00。万事达卡负债显示为负数,因为它抵消了您的资产价值。
您的资产和负债的合计总额就是您的净资产。因此,要查看您当前的净资产,请使用此命令:
$ ledger balance ^assets ^liabilities
$500.00 资产:支票账户 $-25.00 负债:万事达卡 -------------------- $475.00
类似地,您的收入账户显示为负数,因为它们从账户转移资金以增加您的资产。您的支出显示为正数,因为那是资金去向的地方。收入和支出的合计总额是您的现金流。正现金流意味着您的支出大于收入,因为收入始终是负数。要查看您当前的现金流,请使用此命令:
$ ledger balance ^income ^expenses
$25.00 支出:餐饮 $-500.00 收入:工资 -------------------- $-475.00
关于支出的另一个常见问题是:我每个月在 X 上花费多少钱?Ledger 提供了一种简单的方法来显示任何账户的月度总计。以下是一个总结您月度汽车支出的示例:
$ ledger -M register -f drewr3.dat expenses:auto
11-Jan-01 - 11-Jan-31 支出:汽车 $ 5,500.00 $ 5,500.00
这当然假设您使用诸如‘支出:汽车:加油’和‘支出:汽车:维修’这样的账户名称。
有时您会代表他人花钱,这笔钱最终会得到偿还。由于这笔钱仍然是您的,它实际上是一项资产。而且由于支出是为他人进行的,您不希望它污染您的支出报告。您需要设立一个账户来跟踪报销。
在 Ledger 中这相当容易实现。当花钱时,将其支出到您的资产:报销账户,为您花钱的每个人或企业使用不同的账户。例如:
2004/09/29 电路城 资产:报销:XYZ 公司 $100.00 负债:万事达卡
这表明在电路城使用万事达卡花费了$100.00,该支出是代表 XYZ 公司进行的2。后来,当 XYZ 公司偿还该金额时,资金将从该报销账户转移回常规资产账户:
2004/09/29 XYZ 公司 资产:支票账户 $100.00 资产:报销:XYZ 公司
这将 XYZ 公司欠款存入支票账户,大概是因为他们用支票偿还了该金额。
但如果您经营自己的企业,想要跟踪为自己进行的支出,同时仍在单个账本文件中跟踪所有内容,该怎么办?这更复杂,因为您需要跟踪两个独立的事项:1) 这笔钱应该偿还给您的事实,以及 2) 支出账户是什么,以便您以后可以确定公司在哪里花钱。
这种过账最好通过在两个不同文件中的镜像过账来处理,一个用于您的个人账户,一个用于您的公司账户。但将它们保存在一个文件中涉及相同类型的过账,因此这里展示的就是这些。首先是个人交易,显示需要报销:
2004/09/29 电路城 资产:报销:XYZ 公司 $100.00 负债:万事达卡
这与上面相同,只是您拥有 XYZ 公司,并在同一账本文件中跟踪其支出。此交易应立即后跟一个等效交易,显示支出类型,并注明$100.00 现在应付给您的事实:
2004/09/29 电路城 XYZ 公司:支出:计算机:软件 $100.00 XYZ 公司:应付账款:您的姓名
这第二笔交易显示 XYZ 公司刚刚在软件上花费了$100.00,而这$100.00 来自您的姓名,必须偿还。
这两笔交易也可以合并,以使事情更清晰。请注意,现在必须指定所有金额:
2004/09/29 电路城 资产:报销:XYZ 公司 $100.00 负债:万事达卡 $-100.00 XYZ 公司:费用:计算机:软件 $100.00 XYZ 公司:应付账款:您的姓名 $-100.00
要“偿还”这笔报销,只需将所有条目顺序反转,但这次是从公司资产中提取资金,支付给应付账款,然后再次从报销账户中提取,并支付到您的个人资产账户。实际操作比口头描述更简单:
2004/10/15 XYZ 公司 资产:支票账户 $100.00 资产:报销:XYZ 公司 $-100.00 XYZ 公司:应付账款:您的姓名 $100.00 XYZ 公司:资产:支票账户 $-100.00
现在报销账户已结清,应付账款已结清,$100.00 已有效地从公司支票账户转移到您的个人支票账户。这笔钱只是在 '资产:报销:XYZ 公司' 和 'XYZ 公司:应付账款:您的姓名' 中“等待”——直到能够结清为止。
这样从双方跟踪费用的价值在于,您不会让他人代付的费用污染您的个人费用报告,同时又能生成准确的公司支出报告。虽然比直接用个人资产支付更繁琐,但它提供了非常准确的信息追踪。
将这些双重交易保持在一起的优势是它们始终保持同步。将它们分开的优势是明确了转账的视角。要将过账保存在单独的文件中,只需将上面连接的两个交易分开。例如,对于上面显示的费用和偿还,将创建以下四个交易。两个在您的个人账本文件中:
2004/09/29 电路城 资产:报销:XYZ 公司 $100.00 负债:万事达卡 $-100.00 2004/10/15 XYZ 公司 资产:支票账户 $100.00 资产:报销:XYZ 公司 $-100.00
两个在您的公司账本文件中:
apply account XYZ 公司 2004/09/29 电路城 费用:计算机:软件 $100.00 应付账款:您的姓名 $-100.00 2004/10/15 XYZ 公司 应付账款:您的姓名 $100.00 资产:支票账户 $-100.00 end apply account
(注意:上面的 apply account 意味着文件中提到的所有账户都是该账户的子账户。在这种情况下,这意味着文件中的所有活动都与 XYZ 公司相关)。
创建这些交易后,您将始终知道 $100.00 是使用您的万事达卡为 XYZ 公司花费的,并且 XYZ 公司将这笔钱用于计算机软件并在大约两周后偿还。
$ ledger balance --no-total
$100.00 资产:支票账户 0 XYZ 公司 $-100.00 资产:支票账户 $100.00 费用:计算机:软件 $-100.00 负债:万事达卡
Ledger 不对您使用的商品类型做任何假设;它只要求您指定一种商品。商品可以是任何不包含句点、逗号、斜杠或@符号的非数字字符串。它可以出现在金额之前或之后,但通常认为出现在金额之前的符号代表货币,而出现在金额之后且未连接的符号代表商品。以下是一些有效的货币和商品标识符示例:
$20.00 ; 货币:二十美元 40 AAPL ; 商品:40 股苹果股票 60 DM ; 货币:60 德国马克 £50 ; 货币:50 英镑 50 EUR ; 货币:50 欧元(或使用相应符号)
Ledger 会检查任何商品的首次使用情况,以确定在报告中应如何显示该商品。它会关注商品名称是否与金额分离、出现在金额之前还是之后、金额指定的精度、是否使用了千位分隔符等。这样做的目的是使商品显示方式与您的使用习惯保持一致。
一个账户可能包含多种商品,在这种情况下,它将为每种商品分别计算总额。例如,如果您的经纪账户同时包含现金、黄金和多种股票数量,余额可能显示为:
$200.00 100.00 AU AAPL 40 BORL 100 FEQTX 50 资产:经纪账户
此余额报告显示了您的经纪账户中每种商品的数量。
有时,您可能希望了解余额的当前市场价值,而不是商品总量。为此,您必须指定每种商品的当前价格。价格可以是任何商品,此时余额将按该商品计算。指定价格的常用方法是使用价格历史文件,其内容可能如下:
P 2004/06/21 02:18:01 FEQTX $22.49 P 2004/06/21 02:18:01 BORL $6.20 P 2004/06/21 02:18:02 AAPL $32.91 P 2004/06/21 02:18:02 AU $400.00
使用 --price-db 文件 选项指定价格历史数据库,配合 --market (-V) 选项以当前市场价值报告:
$ ledger --price-db prices.db -V balance brokerage
由于价格数据库使用美元货币,您的经纪账户余额将以美元报告。
$40880.00 资产:经纪账户
您可以在任何商品之间进行转换。假设您的支票账户中有 5000 美元,出于某种原因,您想知道按当前金价这些钱能购买多少盎司黄金:
$ ledger -X AU balance checking
此命令的结果可能是:
12.50 AU 资产:支票账户
当使用一种商品购买另一种商品时(例如用美元购买普通股),就会确立该商品当日的价格。通过在账本文件中记录价格详情,还可以在任何给定时间为商品指定其他价格。此类价格交易可能如下所示:
P 2004/06/21 02:17:58 TWCUX $27.76 P 2004/06/21 02:17:59 AGTHX $25.41 P 2004/06/21 02:18:00 OPTFX $39.31 P 2004/06/21 02:18:01 FEQTX $22.49 P 2004/06/21 02:18:02 AAPL $32.91
默认情况下,Ledger 在生成各种报告时不会考虑商品价格。它总是以商品总量而非当前价值来报告余额。要启用定价报告,请使用商品报告选项之一。
有时,一种商品有多种等价形式。时间就是一个例子。无论是按分钟、小时还是天来跟踪,都应该能够在不同形式之间进行转换。这需要使用商品等价关系。
例如,您可能有以下两个记账项:一个将一小时时间转入“可计费”账户,另一个将同一账户减少十分钟。最终报告将显示剩余五十分钟:
2005/10/01 为公司完成的工作 可计费:客户 1h 项目:XYZ 2005/10/02 向项目返还十分钟 项目:XYZ 10m 可计费:客户
报告此账本文件的余额会产生:
$ ledger --no-total balance 可计费 项目
50.0m 可计费:客户 -50.0m 项目:XYZ
这个例子之所以有效,是因为 Ledger 已经知道如何处理秒、分钟和小时,这是其时间跟踪支持的一部分。定义其他等价关系很简单。以下是一个创建数据等价关系的示例,有助于跟踪字节、千字节、兆字节等:
C 1.00 Kb = 1024 b C 1.00 Mb = 1024 Kb C 1.00 Gb = 1024 Mb C 1.00 Tb = 1024 Gb
每个定义都将一个商品(如“Kb”)及其默认精度与一定数量的另一种商品相关联。在上面的例子中,千字节以两位小数精度报告,每个千字节等于 1024 字节。
等价链可以任意长。当商品以小数形式报告(小于“1.00”)时,会使用下一个更小的商品。如果可以用更大的商品单位报告而不产生分数,则会使用更大的商品单位。
由于 Ledger 的账户和商品系统非常灵活,您可以拥有实际上不存在的账户,并使用其他人不认识的商品。例如,假设您在 EverQuest 中买卖各种物品,并想用账本跟踪它们。只需将任意数量的物品添加到您的 EverQuest 账户中:
9/29 在旅馆获取一些物品 地点:黑酒馆 -3 苹果 地点:黑酒馆 -5 牛排 EverQuest:库存
现在您的 EverQuest:Inventory 中有 3 个苹果和 5 块牛排。金额为负数,因为您正在从黑鸦酒馆提取物品以添加到库存账户中。请注意,您不必使用‘地点:黑鸦酒馆’作为来源账户。您可以使用‘EverQuest:系统’来表示这些物品是通过在线方式获得的。选择不同来源账户的唯一目的是为了日后生成更具信息量的报告。您了解得越多,就能进行越好的分析。
如果您之后将这些物品中的一部分出售给其他玩家,交易记录将如下所示:
10/2 斯特姆·光明之刃 EverQuest:库存 -2 牛排 EverQuest:库存 15 金币
现在您已将 2 块牛排转化为 15 金币,这要感谢您的客户斯特姆·光明之刃。
$ ledger balance EverQuest
3 苹果 15 金币 3 牛排 EverQuest:库存
在任何账本中最令人困惑的交易将是您的权益账户——因为初始余额不可能凭空产生。
当您首次建立账本时,您的某些账户中可能已经有钱。假设您的支票账户中有 100 美元;然后在账本中添加一笔交易来反映这笔金额。这笔钱从哪里来?答案是:来自您的权益。
10/2 初始余额 资产:支票账户 $100.00 权益:初始余额
但什么是权益?您可能听说过人们在谈论房屋抵押贷款时提到权益,即“您拥有的房屋部分”。基本上,权益就像某物的价值。如果您拥有一辆价值 5000 美元的汽车,那么您在这辆车上拥有 5000 美元的权益。为了将这辆车(一种商品)转化为现金流,或记入您的银行账户,您需要通过出售它来借记权益。
当您开始建立账本时,您可能已经拥有净资产。您的净资产就是您当前的权益。通过将账本中的资金从您的权益转移到银行账户,您正在基于先前的权益为账本账户贷记。这就是为什么当您查看余额报告时,会看到一个永远不会变化的大额负数权益:因为那是您在资金开始流动之前所拥有的价值(您为了启动账本而从自己那里借记的金额)。如果您的资产总正值大于初始权益的绝对值,这意味着您正在赚钱。
还是一头雾水?继续思考。在您想明白之前,请在余额命令末尾加上not Equity,以从总额中移除这个令人困惑的数字。
让许多人完全放弃记账的原因之一是追踪小额现金支出的繁琐。这些支出很少产生收据,而且通常有很多小额记录,而不是像支票那样只有几笔大额记录。
一种解决方案是:不必费心。将您的支出转移到借记卡上,但总体上忽略现金。一旦您从 ATM 取出现金,就将其标记为已支出到‘支出:现金’类别:
2004/03/15 ATM 支出:现金 $100.00 资产:活期存款
如果您在某个时候有一笔想要追踪的大额现金支出,只需将支出金额从‘支出:现金’转移到目标账户:
2004/03/20 某人 支出:食品 $65.00 支出:现金
这样,您仍然可以追踪大额现金支出,同时忽略所有小额支出。
在某些情况下,您追踪的账户与存放资金的金融机构之间存在差异。例如,担任宗教机构的财务主管时。从世俗角度来看,您可能处理三个不同的账户:
从宗教角度来看,社区期望将其资源划分为多个“资金”,用于采购或为将来储备资源:
这种设置的问题在于,当您花钱时,资金同时来自两个或更多地方:账户和基金。然而,基金与账户之间的金额关联很少是一对一的。如果学校基金有‘$500.00’,但其中‘$400.00’来自活期存款,‘$100.00’来自储蓄账户,该怎么办?
传统财务软件要求资金只能存放在一个地方。但实际上数据有两种“视图”:从账户角度和从基金角度——但两组数据都应反映相同的总体支出和现金流。只是资金存放的位置不同。
这种情况可以通过两种方式之一处理。第一种是使用虚拟过账来表示资金同时进出两种账户:
2004/03/20 捐款 资产:活期存款 $500.00 收入:捐赠 2004/03/25 捐赠分配 [基金:学校] $300.00 [基金:建筑] $200.00 [资产:活期存款] $-500.00
第二笔交易中使用方括号确保虚拟过账余额为零。现在资金可以直接从基金支出,同时从实体账户提取:
2004/03/25 购书付款(从活期存款支付) 支出:书籍 $100.00 资产:活期存款 $-100.00 (基金:学校) $-100.00
使用圆括号创建虚拟过账,但不确保余额为零。生成报告时,默认会按基金显示。在这种情况下,您可能希望隐藏‘资产’账户,否则余额会显得不合理:
$ ledger --no-total bal not ^资产
$100.00 支出:书籍 $400.00 基金 $200.00 建筑 $200.00 学校 $-500.00 收入:捐赠
如果使用--real选项,报告将按实际账户显示:
$ ledger --real --no-total bal
$400.00 资产:支票账户 $100.00 支出:图书 $-500.00 收入:捐赠
如果需要更多资产账户作为记账条目的来源,只需按常规方式列出它们,例如:
2004/03/25 图书付款(从支票账户支付) 支出:图书 $100.00 资产:支票账户 $-50.00 负债:信用卡 $-50.00 (资金:学校) $-100.00
第二种追踪资金的方法是使用交易代码。在这方面,代码就像虚拟账户一样,包含整个记账条目集。基本上,我们通过设置交易代码来将交易与资金关联。以下是两笔向'资金:学校'资金存入和支出的交易:
2004/03/25 (资金:学校) 捐赠 资产:支票账户 $100.00 收入:捐赠 2004/03/25 (资金:建筑) 捐赠 资产:支票账户 $20.00 收入:捐赠 2004/04/25 (资金:学校) 图书付款 支出:图书 $50.00 资产:支票账户
请注意,现在账户仅与真实账户相关,任何余额或登记报告都会反映这一点。交易与特定资金的关联仅通过代码来维护。
这如何变成资金报告?通过使用--payee=code选项,您可以生成一个登记报告,其中每个记账条目的收款人显示代码。单独使用这个选项并不特别有趣;但当与--by-payee (-P)选项结合使用时,您将看到与特定资金相关的所有记账条目的账户小计。因此,要查看所有资金的当前货币余额,命令将是:
$ ledger --payee=code -P reg ^Assets
04-3 月-25 资金:建筑 资产:支票账户 $20.00 $20.00 04-3 月-25 资金:学校 资产:支票账户 $50.00 $70.00
或者要查看特定资金的支出,本例中的'学校'资金:
$ ledger --payee=code -P reg ^Expenses and code School
04-4 月-25 资金:学校 支出:图书 $50.00 $50.00
两种方法都提供了不同种类的灵活性,取决于您更喜欢将资金视为虚拟账户,还是与特定交易关联的标签。您自己的偏好将决定哪种方法最适合您的情况。
会计最重要的部分是保持良好的日记账。如果您有良好的日记账,就可以编写工具来执行所需的任何数学技巧,以更好地理解您的支出模式。没有良好的日记账,再聪明的工具也无法帮助您。
Ledger 程序旨在使日记账交易尽可能简单。由于它是一个命令行工具,它不提供用于维护日记账的用户界面。如果您需要用户界面来维护日记账交易,GnuCash 是一个很好的替代方案。
如果您不使用 GnuCash,而是使用文本编辑器维护日记账,请继续阅读。Ledger 的设计旨在使数据交易尽可能简单,既通过保持日记账格式简单,也通过根据交易性质自动确定尽可能多的信息。
例如,您无需告知 Ledger 您使用的账户。每当 Ledger 发现涉及未知账户的记录时,它会自动创建该账户3。若您使用 Ledger 未识别的新商品,它将创建该商品,并根据您在记录中的使用方式确定其显示特征(符号在金额前后的位置、显示精度等)。
以下是前述太平洋贝尔公司的示例,以 Ledger 记录形式呈现,并添加了支票号码:
9/29 (1023) 太平洋贝尔 费用:公用事业:电话 $23.00 资产:支票账户 $-23.00
如您所见,这与纸质记录非常相似,只是去除了计算后的余额总计,并添加了更符合 Ledger 体系结构的账户名称。实际上,由于 Ledger 具有智能处理能力,若金额与首行相同,您无需指定平衡金额:
9/29 (1023) 太平洋贝尔 费用:公用事业:电话 $23.00 资产:支票账户
对此交易,Ledger 将推断必须从‘资产:支票账户’支出 $-23.00 才能平衡该交易。
还需注意账户条目的结构。通过冒号分隔可建立隐含的层级关系(参见构建账户结构)。
该格式非常灵活,您无需完全按照示例进行缩进和间隔。唯一要求是:交易起始点(通常是日期)位于交易首行开头,账户需至少缩进一个空格。若省略账户行的前导空格,Ledger 将报错。金额与账户之间必须至少有两个空格或一个制表符。若金额与账户间分隔不足,Ledger 会报错并停止计算。
除非您刚来自外星球,否则您已具备财务状态。需要捕获该财务状态以便 Ledger 拥有起始点。
在某个时间点,您知晓所有财务账户的余额和未偿债务。这些金额构成了 Ledger 期初分录的基础。例如,若选择 2011 年初作为开始用 Ledger 追踪财务的日期,您的期初余额分录可能如下所示:
2011/01/01 * 期初余额 资产:联名支票账户 $800.14 资产:其他支票账户 $63.44 资产:储蓄账户 $2805.54 资产:投资:401K:递延 100.0000 VIFSX @ $80.5227 资产:投资:401K:匹配 50.0000 VIFSX @ $83.7015 资产:投资:IRA 250.0000 VTHRX @ $20.5324 负债:抵押贷款 $-175634.88 负债:汽车贷款 $-3494.26 负债:Visa 信用卡 -$1762.44 权益:期初余额
作为账户名称的收款人,“期初余额”这个名字并没有什么特别之处,任何您理解的方便名称都可以使用。
实际上对此没有硬性要求,但为了保持条理性,我们建议为您的会计系统建立一些非常基础的结构。
在最高层级,您有五类账户:
以此方式开始构建结构将使您更容易获得关于财务状况所需问题的答案。
在这些顶级账户之下,您可以设置任意所需的详细层级。例如,如果您想具体追踪在汉堡和薯条上的花费,可以设置如下:
支出:食品:汉堡和薯条
注释通常以‘;’开头。然而,为了提高与其他文本处理程序和方法的兼容性,如果在行首使用,还有四个额外的注释字符有效:‘#’、‘|’、‘*’和‘%’。
块注释可以通过使用comment ... end comment来创建。
; 这是单行注释,# 这也是,% 这也是,| 这也是,* 这也是。comment 这是多行块注释 end comment
在交易中有多种注释形式,例如:
; 这是全局注释,不应用于特定交易 ; 它可以以五种字符中的任意一种开头,但不包含在 ; 'print'或'output'的输出中 2011/12/11 甜蜜之物 ; 德国巧克力蛋糕 ; :打破节食: 支出:食品 $10.00 ; 朋友: 伙伴们 资产:信用合作社:支票账户
第一条注释是全局性的,Ledger 不会将其附加到任何特定交易。交易内的注释都必须以‘;’开头,并作为交易的一部分保留。‘:’表示元数据和标签(参见元数据)。
Ledger 在账户估值方面是无关性的。美元、欧元、英镑、法郎、股票等都被视为“商品”。股票、债券、共同基金和其他金融工具的持仓可以使用任何您方便的标签(建议对公开交易的资产使用股票代码)。4
在本手册的其余部分,我们将仅使用“商品”一词来指代交易价值的单位。
这与许多常见的会计软件有根本不同,后者假设所有账户使用同一种货币。这意味着如果您通常使用欧元,但前往美国并产生一些费用,您必须在将条目录入财务系统之前进行货币兑换。而使用 Ledger 则无需这样做。在同一日记账中,您可以有任意或所有您实际持有的商品的条目。您可以使用报告功能将所有商品转换为单一商品进行报告,而无需更改基础条目。
例如,以下条目反映了从美国到欧洲商务旅行的交易:
2011/09/23 慕尼黑现金 资产:现金 €50.00 资产:支票账户 $-66.00 2011/09/24 慕尼黑晚餐 支出:商务:旅行 €35.00 资产:现金
这表明 $66.00 从支票账户取出并兑换为 50 欧元。隐含汇率为 $1.32。然后在慕尼黑晚餐花费了 35.00 欧元。
运行 ledger 余额报告显示:
$ ledger -f example.dat bal
$-66.00 €15.00 资产 €15.00 现金 $-66.00 支票账户 €35.00 支出:商务:旅行 -------------------- $-66.00 €50.00
前两行显示我当前的资产为支票账户中的 $-66.00(在这个非常简短的示例中,我没有为支票账户建立初始余额)和 €15.00。晚餐消费后,我钱包里有 €15.00。最后一行平衡为零,但显示为两行,因为我们没有告诉 ledger 转换商品。
商品名称可以包含任何字符,包括空格。但是,如果包含空格或数字字符,商品名称必须用双引号‘"’括起来:
1999/06/09 ! 购买 资产:SG PEE STK 49.957 "Arcancia Équilibre 454" 资产:SG PEE STK $-234.90 2000/12/08 ! 购买 资产:SG PEE STK 215.796 "Arcancia Équilibre 455" 资产:SG PEE STK $-10742.54
请注意,对于查询带引号的商品,引号需要转义,如下所示:
$ ledger -f d reg -l 'commodity == "\"Arcancia Équilibre 454\""'
购买股票是一个典型例子,许多人会使用涉及同一交易中多种商品的场景。股票类型(如 AAPL 代表苹果公司)以及以您购买时使用的货币单位计价的股票购买价格(AAPL 以美元计价)。是的,典型惯例如下:
2004/05/01 股票购买 资产:经纪账户 50 AAPL @ $30.00 支出:经纪账户:佣金 $19.95 资产:经纪账户 $-1,519.95
这假设您拥有一个能够同时管理流动资产和商品资产的经纪账户。现在,在出售当天:
2005/08/01 股票出售 资产:经纪账户 -50 AAPL {$30.00} @ $50.00 支出:经纪账户:佣金 $19.95 收入:资本收益 $-1,000.00 资产:经纪账户 $2,480.05当然,您可以省略最后一条过账的金额。这里显示是为了清晰起见。
‘{$30.00}’ 是批次价格。您也可以使用批次日期 ‘[2004/05/01]’,或同时使用两者,以防您有多个相同价格/日期的批次且您的税务模型基于最长持有优先原则。
您为了日后出售而持有的商品具有随市场价格波动的可变价值。而您消费的商品价值不应波动,而应保持其购买时的批次价格。作为“批次定价”的扩展,您可以固定商品的单位价格。
例如,假设您以每加仑 1.20 美元的价格购买 10 加仑汽油。在未来的“价值”报告中,您不希望这些加仑按当前价格报告,而是按购买时的价格报告。同时,您还希望其他类型的商品(如股票)按当前价格报告。
这通过以下方式支持:
2009/01/01 壳牌加油站 支出:汽油 11 GAL {=$2.299} 资产:支票账户此交易实际上引入了一种新商品‘GAL {=$2.29}’,其市场价值忽略汽油价格的任何未来变化。
如果您不想固定价格,可以通过以下两种等效方式之一指定相同的交易(注意与上述交易相比缺少等号):
2009/01/01 壳牌加油站 支出:汽油 11 GAL {$2.299} 资产:支票账户 2009/01/01 壳牌加油站 支出:汽油 11 GAL @ $2.299 资产:支票账户这两种形式在含义上没有区别。您可能会问,为什么两者都存在?是为了支持这样的情况:
2009/01/01 壳牌加油站 支出:汽油 11 GAL {=$2.299} @ $2.30 资产:支票账户此交易表示您以每加仑 2.299 美元的价格购买了 11 加仑汽油,但您的成本为每加仑 2.30 美元。在这种情况下,Ledger 会自动生成一条平衡过账到权益:资本损失,以反映 1.1 美分的差异,然后由资产:支票账户平衡,因为其金额为空。
Ledger 允许您对商品计价方式进行非常精细的控制。您可以使用 --market 或 --exchange COMMODITY 选项来微调结果。现在有多个干预点可供指定计价方法:
market。固定定价(例如‘{=$20}’)在此方案中仍然起作用。就计价而言,它是书写‘((s,d,t -> market($20,d,t)))’的简写形式。
计价函数接收三个参数:
source(来源)标识正在查询价格的商品的字符串(例如:‘EUR’)。
date(日期)价格应相对的参考日期。
target(目标)标识“目标”商品的字符串,或返回价格应采用的商品。如果使用了 --market 而不是 --exchange COMMODITY,则此参数为 null。
计价函数应返回一个金额。如果您用 Python 编写函数,可以返回类似‘Amount("$100")’的内容。如果函数返回显式值,则无论商品、日期或所需目标商品如何,始终使用该值。例如,
define myfunc_seven(s, d, t) = 7 EUR
为了指定固定价格但仍将该价格计价为目标商品,请使用类似以下方式:
define myfunc_five(s, d, t) = market(5 EUR, d, t)
value 指令设置用于数据流其余部分中所有商品的计价方式。如果没有找到更具体的设置,这是回退方案。
value myfunc_seven
您可以按商品设置特定的计价函数。除了定义函数外,您还可以传递 lambda 表达式。
commodity $ value s, d, t -> 6 EUR
每个账户还可以为转入该账户的任何商品提供默认计价函数。
account Expenses:Food5 value myfunc_five
如果找到元数据字段‘Value’,它会在交易范围或按分录基础上覆盖计价函数。
= @XACT and Food ; Value:: 8 EUR (Equity) $1 = @POST and Dining (Expenses:Food9) $1 ; Value:: 9 EUR
最后,您可以使用‘(( ))’商品注释为任何特定金额指定计价函数/值。
2012-03-02 KFC Expenses:Food2 $1 ((2 EUR)) Assets:Cash2 2012-03-03 KFC Expenses:Food3 $1 ; Value:: 3 EUR Assets:Cash3 2012-03-04 KFC ; Value:: 4 EUR Expenses:Food4 $1 Assets:Cash4 2012-03-05 KFC Expenses:Food5 $1 Assets:Cash5 2012-03-06 KFC Expenses:Food6 $1 Assets:Cash6 2012-03-07 KFC Expenses:Food7 1 CAD Assets:Cash7 2012-03-08 XACT Expenses:Food8 $1 Assets:Cash8 2012-03-09 POST Expenses:Dining9 $1 Assets:Cash9
$ ledger reg -V food
12-Mar-02 KFC 支出:食品 2 2 EUR 2 EUR 12-Mar-03 KFC 支出:食品 3 3 EUR 5 EUR 12-Mar-04 KFC 支出:食品 4 4 EUR 9 EUR 12-Mar-05 KFC 支出:食品 5 $1 $1 9 EUR 12-Mar-06 KFC 支出:食品 6 $1 $2 9 EUR 12-Mar-07 KFC 支出:食品 7 1 CAD $2 1 CAD 9 EUR 12-Mar-08 XACT 支出:食品 8 $1 $3 1 CAD 9 EUR
有时 Ledger 的灵活性可能会导致困难。使用自由格式的文本编辑器输入交易虽然便于保存数据,但也容易导致账户或收款人名称不一致或出现拼写错误。
为了应对不一致性问题,您可以定义允许的账户和收款人。为简单起见,创建一个单独的文本文件并按如下方式定义账户和收款人:
account 支出 account 支出:公用事业
使用 --strict 选项将使 Ledger 在遇到任何未预先定义的账户时发出警告:
$ ledger bal --strict 警告: "FinanceData/Master.dat", 第 6 行: 未知账户 '负债:什一税欠款' 警告: "FinanceData/Master.dat", 第 8 行: 未知账户 '负债:什一税欠款' 警告: "FinanceData/Master.dat", 第 15 行: 未知账户 '分配:股票:国内'
如果您已经创建了一个大型的 Ledger 账簿,可以使用 accounts 命令开始操作:
$ ledger accounts >> Accounts.dat
您需要编辑此文件,在每行前面添加 account 指令。
Ledger 文件格式相当简单,但也非常灵活。它支持许多选项,不过通常用户可以忽略其中的大部分。下面将对这些选项进行总结。
每行的起始字符决定了该行的含义以及应如何解释。允许的起始字符包括:
数字以数字开头的行表示一笔交易。其后可以跟随任意数量的行,每行以空白字符开头,表示交易的账户过账。第一行的格式为:
日期[=生效日期] [*|!] [(代码)] 描述
如果在日期(带有可选的生效日期)后出现‘*’,表示该交易已“清算”,其具体含义可由用户自行定义。如果在日期后出现‘!’,表示该交易处于“待处理”状态;即从用户的角度看已暂定清算,但尚未实际清算。如果在括号中出现 代码,可用于表示支票号码或过账类型。在这些之后是收款人或过账的描述。
后续每笔条目的格式为:
账户 金额 [; 备注]
若为虚拟条目,账户可用圆括号包围;若为必须平衡的虚拟条目,则用方括号包围。金额后可跟单单位过账成本,通过指定@ 金额实现,或通过@@ 金额指定完整过账成本。备注可使用语法[实际日期]、[=生效日期]或[实际日期=生效日期]来指定条目的实际日期和/或生效日期(参见虚拟条目)。最后请注意,金额前必须至少有两个空白字符。
P¶指定商品的歷史價格。這些通常出現在價格歷史文件中(參見--download (-Q)選項)。語法為:
P 日期 代號 價格
=¶自動化交易。等號後必須出現數值表達式。
在此初始行之後應有一組或多組條目,就像普通交易一樣。如果條目的金額沒有商品單位,它們將作為乘數應用於數值表達式匹配的實際條目(參見自動化交易)。
~¶週期性交易。波浪號後必須出現週期表達式。
在此初始行之後應有一組或多組條目,就像普通交易一樣。
; # % | *¶以分號、井號、百分號、豎線或星號開頭的行表示註釋,將被忽略。註釋不會在「打印」響應中返回。
縮進 ;¶若分號被縮進且出現在交易內部,它將被解析為其前一類別的持久註釋。這些註釋或標籤可用於增強 Ledger 的報告和篩選功能。
行首命令指令必須出現在行首。使用‘!’和‘@’已被棄用。
賬戶¶預先聲明有效的賬戶名稱。這僅在使用了--strict或--pedantic時有效(見下文)。賬戶指令支持多個可選子指令,前提是它們緊跟在賬戶指令之後且以空白字符開頭:
賬戶 支出:食品 註釋 此賬戶全是關於雞肉的! 別名 食品 收款人 ^(KFC|Popeyes)$ 檢查 商品 == "$" 斷言 商品 == "$" 評估 打印("你好!") 默認註釋子指令將文本註釋與賬戶關聯。之後可在任何賬戶上下文中使用註釋數值表達式函數訪問此註釋。
alias(别名)子指令可以多次出现,允许在任何允许使用账户名称的地方使用别名替代完整账户名称。
payee(收款方)子指令可以多次出现,提供正则表达式来识别账户:当遇到该收款方且其交易中的某个账户以"Unknown"结尾时生效。示例:
2012-02-27 KFC 支出:未知 $10.00 ;现在读作"支出:食品" 资产:现金
check(检查)和assert(断言)指令会在给定值表达式在任何过账上下文中评估为 false 时分别发出警告或报错。
eval(求值)指令会在定义时的账户上下文中对值表达式进行求值。目前这个指令价值有限。
default(默认)指令指定该账户应作为未来任何仅包含单个过账条目的交易的"平衡账户"使用。
应用账户¶设置此指令后所有账户的根目录。Ledger 支持分层树状账户结构。维护两个"根账户"可能比较方便。例如,您可以同时跟踪个人财务和业务财务。为保持分离,您可以在所有个人账户前加'personal:'前缀,所有业务账户前加'business:'前缀。使用账户指令可以轻松分离大量交易组,无需手动编辑。例如:
应用账户 个人 2011/11/15 超市 支出:食品杂货 $50.00 资产:支票账户
这将导致所有过账都进入'Personal:Expenses:Groceries'和'Personal:Assets:Checking',直到遇到'end apply account'指令。
应用固定¶固定区块用于为一组交易设置固定价格(参见固定价格和成本)。这纯粹是为了节省输入时间,适用于需要输入大量含固定价格交易的情况。
因此,以下内容:
应用固定 CAD $0.90 2012-04-10 加拿大午餐 资产:钱包 -15.50 CAD 支出:食品 15.50 CAD 2012-04-11 加拿大第二天晚餐 资产:钱包 -25.75 CAD 支出:食品 25.75 CAD 结束应用固定
等同于:
2012-04-10 加拿大午餐 资产:钱包 -15.50 CAD {=$0.90} 支出:食品 15.50 CAD {=$0.90} 2012-04-11 加拿大第二天晚餐 资产:钱包 -25.75 CAD {=$0.90} 支出:食品 25.75 CAD {=$0.90}别名¶为账户名称定义别名。如果您有深度嵌套的账户树,定义别名可能很方便,例如:
别名 餐饮=支出:娱乐:餐饮 别名 支票账户=资产:信用合作社:联名支票账户 2011/11/28 美味宫殿 餐饮 $10.00 支票账户
别名仅在定义后读入的交易中生效,并受其前面的account指令影响。
$ ledger bal --no-total ^Exp
$10.00 支出:娱乐:餐饮
使用--recursive-aliases选项时,别名可以引用其他别名,以下示例产生与前述示例完全相同的交易和账户名称:
别名 娱乐=支出:娱乐 别名 餐饮=娱乐:餐饮 别名 支票账户=资产:信用合作社:联名支票账户 2011/11/30 ChopChop 餐饮 $10.00 支票账户
$ ledger balance --no-total --recursive-aliases ^Exp
$10.00 支出:娱乐:餐饮
选项 --no-aliases 完全禁用别名扩展。所有账户都按其在账本文件中的原样逐字读取。
断言¶如果在 Ledger 运行期间未满足条件,断言可以抛出错误。
assert <值表达式布尔结果>
桶账户定义用于平衡交易的默认账户。通常,每笔交易至少有两个过账项,必须平衡为零。Ledger 允许您保留一个没有金额的过账项,并自动平衡该过账项中的交易。bucket 允许您填写所有过账项,并自动生成一个额外的过账项到桶账户以平衡交易。如果任何交易不平衡,它将自动与 bucket 账户进行平衡。以下示例将‘资产:支票账户’设置为桶账户:
bucket 资产:支票账户 2011/01/25 Tom's Used Cars 支出:汽车 $ 5,500.00 2011/01/27 书店 支出:书籍 $20.00 2011/12/01 销售 资产:支票账户:业务 $ 30.00
捕获指示 Ledger 将任何匹配正则表达式的账户替换为给定账户。例如:
capture 支出:可抵扣:医疗 医疗
这将导致名称中包含‘医疗’的任何过账项被替换为‘支出:可抵扣:医疗’。
Ledger 将在 print 和 register 报告中显示映射后的收款人。
检查¶如果在 Ledger 运行期间未满足条件,检查会发出警告。
check <值表达式布尔结果>
注释¶开始一个块注释,由 end comment 关闭。
商品¶预声明商品名称。这仅在使用了 --strict 或 --pedantic 时有效(见下文)。
commodity $ commodity CAD
commodity 指令支持几个可选的子指令,如果它们紧跟在商品指令之后,并且——如果它们在连续行上——以空白开头:
commodity $ note 美元 format $1,000.00 nomarket alias USD default
note 子指令将文本注释与商品关联。目前这除了文档外没有其他价值。
format 子指令提供了一种告诉 Ledger 如何格式化此商品的方法。将来,使用此指令将禁用 Ledger 对该商品其他使用方式的观察,并提供“规范”表示。
nomarket 子指令声明该商品的价格永远不应自动下载。
alias 子指令声明任何匹配此符号的商品都应使用在此块中声明的商品。
default 子指令将此标记为“默认”商品。
定义¶允许您定义值表达式以供将来使用。例如:
define var_name=$100 2011/12/01 测试费用 (var_name*4) 资产
该记账条目将产生 400 美元的成本。
end¶关闭块命令,如apply或comment。
expr¶与eval相同。
include¶将指定文件包含进来,如同它是当前文件的一部分。文件名可以包含通配符('*')以引用多个文件(例如'bank/*.ledger')。
payee¶payee指令支持两个可选的子指令,如果它们紧跟在 payee 指令之后,并且(如果在后续行)以空白开头:
payee KFC alias KENTUCKY FRIED CHICKEN uuid 2a2e21d434356f886c84371eebac6e44f1337fda
alias子指令提供一个正则表达式,如果匹配到解析的收款人,则替换为声明的收款人名称:
2012-02-27 KENTUCKY FRIED CHICKEN ; 将被读取为'KFC'
uuid子指令指定具有完全匹配给定 uuid 的交易应替换为声明的收款人名称:
2014-05-13 UNHELPFUL PAYEE ; 将被读取为'KFC' ; UUID: 2a2e21d434356f886c84371eebac6e44f1337fda
Ledger 将在 print 和 register 报告中显示映射后的收款人。
apply tag¶允许您指定一个交易块并为所有交易分配相同的标签。标签可以有值并且可以嵌套。
apply tag hastag apply tag nestedtag: true 2011/01/25 Tom's Used Cars 费用:汽车 $ 5,500.00 ; :nobudget: 资产:支票 2011/01/27 书店 费用:书籍 $20.00 负债:万事达卡 end apply tag 2011/12/01 销售 资产:支票:业务 $ 30.00 收入:销售 end apply tag
等同于:
2011/01/25 Tom's Used Cars ; :hastag: ; nestedtag: true 费用:汽车 $ 5,500.00 ; :nobudget: 资产:支票 2011/01/27 书店 ; :hastag: ; nestedtag: true 费用:书籍 $20.00 负债:万事达卡 2011/12/01 销售 ; :hastag: 资产:支票:业务 $ 30.00 收入:销售
tag¶预声明标签名称。这仅在使用了--strict或--pedantic时有效(见下文)。
tag 收据 tag CSV
tag指令支持两个可选的子指令,如果它们紧跟在 tag 指令之后,并且(如果在后续行)以空白开头:
tag 收据 check value =~ /pattern/ assert value != "foobar"
check和assert子指令会在给定值表达式在相关标签的任何使用上下文中评估为 false 时发出警告或错误(分别)。在此类上下文中,“value”绑定到标签的值(如果使用类型化元数据,可能是字符串以外的其他内容!)。如果未给出值,则不会调用此类检查或断言。
test¶这是comment的同义词,必须由end标签关闭。
year¶表示用于所有后续未指定年份的交易的年份。年份应紧跟在指令之后出现,例如:year 2004。这在文件开头特别有用,用于指定该文件的年份。但如果所有交易都已指定年份,则此命令无效。
以下单字母命令可单独出现在行首,以保持与旧版 Ledger 的向后兼容性。
A¶参见bucket。
Y¶参见year。
N 符号¶指示忽略指定符号的定价信息,且不会为该符号下载报价。适用于本国货币,如美元‘$’。建议将这些定价选项设置在价格数据库文件中,默认为~/.pricedb。此命令的语法为:
N 符号
D 金额¶通过以预期格式指定金额来设置默认商品。xact命令在无法确定其他商品时将使用此商品作为默认值。此命令可多次使用,为不同商品设置默认标志;最后出现的将用作默认商品。例如,要将美元设为默认商品,同时设置该商品的千位分隔符和小数点标志,请使用:
D $1,000.00
C 金额 1 = 金额 2¶指定商品换算关系,其中第一个金额等于第二个金额。第一个金额应使用报告时所需的小数精度:
C 1.00 Kb = 1024 字节
I, i, O, o, b, h¶这四个与时间时钟支持相关,允许 Ledger 读取时间日志文件。有关其时间日志文件语法的更多信息,请参阅 timeclock 的文档。
有多种工具可帮助将各种格式转换为 Ledger 文件。大多数银行会生成逗号分隔值文件,可使用这些工具之一轻松解析为 Ledger 格式。一些最流行的工具包括:
ledger convert download.csv
hledger -f checking.csv print
icsv2ledger
csvToLedger
CSV2Ledger
直接从银行提取信息超出了 Ledger 的功能范围。
一段时间后,您的日志可能会变得相当庞大。虽然这不会减慢 Ledger 的速度——它设计用于快速处理日志——但事情可能会开始显得“混乱”;这是一个普遍现象:当财务感觉混乱时,人们往往会回避它们。
因此,将往年数据归档到独立文件中可以带来完成感和从过去解脱的自由感。但如何通过账本程序最好地实现这一点呢?有两个命令让这变得非常简单:print和equity。
我们以一个示例文件为例,其数据范围从 2000 年到 2004 年。我们希望将 2000 年和 2001 年的数据归档到独立文件中,而将 2002-2004 年的数据保留在当前文件中。因此,使用print命令将所有早期交易输出到一个名为ledger-old.dat的文件中:
$ ledger -f ledger.dat -b 2000 -e 2002 print > ledger-old.dat
请注意-e参数将输出限制在指定日期之前的交易。
要从当前账本文件中删除旧数据,再次使用print命令,这次指定 2002 年为起始日期:
$ ledger -f ledger.dat -b 2002 print > x $ mv x ledger.dat
然而,现在当前文件仅包含 2002 年及以后的记录,这将无法得出准确的当前余额,因为往年的净收入不再被计入。为了弥补这一点,我们必须在新的账本文件开头附加旧账本的权益报告:
$ ledger -f ledger-old.dat equity > equity.dat $ cat equity.dat ledger.dat > x $ mv x ledger.dat $ rm equity.dat
现在ledger.dat报告的余额与数据拆分前完全相同。
应该多久拆分一次账本?如果你不想,就永远不需要拆分。即使是八十年的数据也不会显著降低账本程序的运行速度,而这还只是使用当今的硬件!或者,你可以将前一年和当前年的数据保存在一个文件中,而将更早的每一年数据保存在各自的文件中。这完全取决于你以及你希望如何组织财务。对于那些还保留精确纸质记录的人来说,将较早年份的数据归档到独立文件中,然后将这些文件刻录到 CD 中与纸质记录一起保存——同时包括当年收到的任何电子对账单——可能会很有用。在组织管理方面,请记住这条格言:做任何能让你坚持下去的事情。
最基本的交易形式如下:
2012-03-10 肯德基 支出:食品 $20.00 资产:现金 $-20.00
该交易包含日期、收款方或描述、目标账户(第一个分录)和来源账户(第二个分录)。每个分录都指定了与该账户相关的操作。
一个交易可以包含任意数量的分录:
2012-03-10 肯德基 支出:食品 $20.00 资产:现金 $-10.00 负债:信用卡 $-10.00
简化操作的第一种方法是省略金额。也就是说,如果恰好有一个分录未指定金额,Ledger 将推断出其他分录金额的相反值:
2012-03-10 肯德基 支出:食品 $20.00 资产:现金 $-10.00 负债:信用卡 ; 等同于指定 $-10
如果其他分录使用多种货币,Ledger 会将空分录复制 N 次,并填入各种货币的负值:
2012-03-10 肯德基 支出:食品 $20.00 支出:小费 $2.00 资产:现金 EUR -10.00 资产:现金 GBP -10.00 负债:信用卡
该交易等同于写入:
2012-03-10 肯德基 支出:食品 $20.00 支出:小费 $2.00 资产:现金 EUR -10.00 资产:现金 GBP -10.00 负债:信用卡 $-22.00 负债:信用卡 EUR 10.00 负债:信用卡 GBP 10.00
您可以在主日期后跟一个等号来为交易关联第二个日期:
2012-03-10=2012-03-08 肯德基 支出:食品 $20.00 资产:现金 $-20.00
这个辅助日期的含义完全由您决定。Ledger 对它的唯一用途是,如果您指定了 --aux-date(或 --effective),那么所有报告和计算(包括定价)都将使用辅助日期,就好像它是主日期一样。
请注意,--aux-date 选项是 --effective 的别名;有关生效日期的更多详细信息,请参阅 生效日期。
交易可以有一个文本“代码”。这没有特定含义,仅由打印命令显示。支票账户通常使用诸如 DEP、XFER 等代码以及支票号码。这是为了让您有一个地方放置这些代码:
2012-03-10 (#100) 肯德基 支出:食品 $20.00 资产:支票账户
交易可以具有“状态”:已清算、待处理或未清算。默认状态为未清算。要将交易标记为已清算,请在日期后、代码或收款人前添加星号‘*’:
2012-03-10 * KFC 支出:食品 $20.00 资产:现金
要将其标记为待处理,请使用‘!’:
2012-03-10 ! KFC 支出:食品 $20.00 资产:现金
这些状态的含义完全由您决定。--cleared 选项将报告限制为仅显示已清算项目,而 --uncleared 显示未清算和待处理项目,--pending 仅显示待处理项目。
我使用已清算表示我已将交易与银行对账单核对,待处理表示我正在核对过程中。
当您清算交易时,这实际上只是清算其所有条目的简写。即:
2012-03-10 * KFC 支出:食品 $20.00 资产:现金
等同于写入:
2012-03-10 KFC * 支出:食品 $20.00 * 资产:现金
您可以将单个条目标记为已清算或待处理,以防交易的某一“方”已清算,而另一方尚未清算:
2012-03-10 KFC 负债:信用卡 $100.00 * 资产:支票账户
在收款人后,且至少有一个制表符或两个空格(或一个空格和一个制表符)之后(Ledger 称之为“硬分隔符”),您可以使用‘;’字符引入关于交易的备注:
2012-03-10 * KFC ; 美味,鸡肉... 支出:食品 $20.00 资产:现金
备注也可以出现在下一行,只要该行以空白开头:
2012-03-10 * KFC ; 美味,鸡肉... ; 以及更多备注... 支出:食品 $20.00 资产:现金 2012-03-10 * KFC ; 仅这些备注... 支出:食品 $20.00 资产:现金
交易的备注由其所有条目共享。这在查询元数据时变得重要(见下文)。要指定备注仅属于一个条目,请将其放在金额后的硬分隔符之后,或在其自己的行上并以空白开头:
2012-03-10 * KFC 支出:食品 $20.00 ; 条目 #1 备注 资产:现金 ; 条目 #2 备注,额外的缩进是可选的
Ledger 更强大的功能之一是为条目和交易(我指的是交易的所有条目)关联类型化元数据的能力。此元数据可被查询、显示并用于计算。
元数据有两种形式:纯标签和标签/值对。
要为项目添加标签,请在注释中的两个冒号之间放置任何不包含空格的单词:
2012-03-10 * KFC 支出:食品 $20.00 资产:现金 ; :标签:
您可以通过共享冒号来组合多个标签:
2012-03-10 * KFC 支出:食品 $20.00 资产:现金 ; :标签 1:标签 2:标签 3:
要将值与标签关联,请使用语法“键: 值”,其中值可以是任何字符串。冒号后需要空格,且空格不能出现在键中:
2012-03-10 * KFC 支出:食品 $20.00 资产:现金 ; 我的标签: 这只是一个用于我的标签的虚假值
如果元数据标签以 :: 结尾,其值将被解析为值表达式,并在内部存储为值而非字符串。例如,虽然我可以像这样以文本方式指定日期:
2012-03-10 * KFC 支出:食品 $20.00 资产:现金 ; 辅助日期: 2012/02/30
这个日期只是一个字符串,除非其值在日期上下文中使用(此时每次需要作为日期时,字符串都会自动解析为日期),否则不会被解析为日期。另一方面,如果我这样写:
2012-03-10 * KFC 支出:食品 $20.00 资产:现金 ; 辅助日期:: [2012/02/30]
那么它只会在解析日记账文件时被解析为日期一次,这会让我立即知道它是一个无效日期。
“收款人”是一个特殊的元数据字段。如果在过账中设置,它将用作该过账的收款人名称。这会影响 register 报告、payees 报告和 --by-payee 选项。
这在例如您一次向银行存入 4 张支票时非常有用。在银行对账单上,只有一个金额‘$400’,但您可以指定每张支票来自谁,如下例所示:
2010-06-17 示例 资产:银行 $400.00 收入:支票 1 $-100.00 ; 收款人: 人员一 收入:支票 2 $-100.00 ; 收款人: 人员二 收入:支票 3 $-100.00 ; 收款人: 人员三 收入:支票 4 $-100.00 ; 收款人: 人员四
当使用
$ ledger reg
报告时,显示为:
10-Jun-17 示例 资产:银行 $400.00 $400.00 人员一 收入:支票 1 $-100.00 $300.00 人员二 收入:支票 2 $-100.00 $200.00 人员三 收入:支票 3 $-100.00 $100.00 人员四 收入:支票 4 $-100.00 0
这表明它们都在同一交易中(这就是为什么日期没有重复),但现在它们有不同的收款人。
如果使用--strict或--pedantic选项,您必须声明此标签以避免警告和错误。
通常,交易中所有记账项的金额必须平衡至零。这是不可协商的。这正是复式记账法的核心!但 Ledger 还有一些技巧...
您可以使用虚拟账户偷偷地将金额转移到某个账户,绕过平衡要求。诀窍在于这些记账项不被视为“真实”的,并且可以使用--real选项从所有报告中移除。
要指定虚拟账户,请用括号将账户名称括起来:
2012-03-10 * KFC 支出:食品 $20.00 资产:现金 (预算:食品) $-20.00
如果您愿意,可以使用方括号(看起来更“硬”)而不是圆括号来表示虚拟记账项应该与一个或多个其他虚拟记账项平衡:
2012-03-10 * KFC 支出:食品 $20.00 资产:现金 [预算:食品] $-20.00 [权益:预算] $20.00
金额是带有商品的数字,但也可以是任何值表达式。要表示这一点,请用括号将金额表达式括起来:
2012-03-10 * KFC 支出:食品 ($10.00 + $20.00) ; Ledger 会为您计算总和 资产:现金
如果在记账项金额的末尾(如果有成本,也在成本之后)有一个等号,那么 Ledger 将验证该账户截至该记账项的总价值是否与指定的金额匹配。请参阅--permissive选项以放宽余额断言检查。
此功能有两种形式:余额断言和余额分配。请注意,这两种形式都是在解析给定账本文件时处理的。因此,它们的评估顺序是它们在账本文件中出现的顺序。包含余额断言或余额分配的交易和记账项的日期或生效日期因此与余额断言和余额分配的评估无关。这对于认为日期顺序更直观的人来说可能会令人困惑。
余额断言具有以下一般形式:
2012-03-10 KFC 支出:食品 $20.00 资产:现金 $-20.00 = $500.00
这仅断言从资产:现金中减去$20.00 后,最终总额应匹配$500.00。如果不匹配,则视为错误。
该断言仅对指定的商品生效。如果一个账户包含多种商品,则仅验证被断言的那种:
2012-03-10 纽约肯德基 支出:食品 $20.00 资产:现金 $-20.00 = $500.00 2012-03-11 蒙特利尔肯德基 支出:食品 15.00 加元 资产:现金 -15.00 加元 = $500.00
在这种情况下,将验证现金的美元金额(未发生变化)。对于‘资产:现金’中当前的加元金额未作任何断言。
唯一可以不带商品进行断言的值是‘0’。这会产生跨商品断言,使得可以断言某个账户完全为空。
2012-03-09 填充钱包 收入 $20.00 收入 15.00 加元 资产:现金 2012-03-10 纽约肯德基 支出:食品 $20.00 资产:现金 $-20.00 2012-03-11 蒙特利尔肯德基 支出:食品 15.00 加元 资产:现金 -15.00 加元 = 0
最后一笔交易将断言我们已没有任何形式的现金。
余额分配的形式如下:
2012-03-10 肯德基 支出:食品 $20.00 资产:现金 = $500.00
这将第二个条目的金额设置为使‘资产:现金’在记账后总额为$500.00 所需的任何值。如果在此情况下结果金额不是$-20.00,则视为错误。
假设您的簿记有些过时,且您的账本余额不再与银行余额匹配。您可以使用余额分配创建调整交易:
2012-03-10 调整 资产:现金 = $500.00 权益:调整
由于第二个条目也为空,其值将成为第一个条目生成金额的相反数。
这是在 Ledger 中唯一一次允许多个条目金额为空的情况——而且仅是因为它并非真正为空,而是由余额分配的值间接提供的。
基于以上所有内容,请考虑以下交易:
2012-03-10 我的经纪人 [资产:经纪账户] = 10 苹果股票
这表示:将条目的金额设置为使‘资产:经纪账户’包含 10 股苹果股票所需的任何值。然后,由于该条目必须平衡,确保其值为零。只有当资产:经纪账户在该输入文件的时间点确实包含 10 股苹果股票时,这才可能成立。
平衡虚拟交易仅用于向 Ledger 表明这不是一个“真实”交易。它不会出现在任何报告中(除非您使用带有--empty参数的登记报告)。
当您将商品从一个账户转移到另一个账户时,有时会在交易过程中发生转换。例如,当您花钱购买汽油时,会将美元转换为加仑汽油,或将美元转换为公司股票。
在这些情况下,Ledger 会为您记录该交易的“成本”,并可以在报告过程中以多种方式使用它。以下是一个股票购买的示例:
2012-03-10 我的经纪人 资产:经纪账户 10 AAPL 资产:经纪账户:现金 $-500.00
这与将 10 股 AAPL 从一个账户转移到另一个账户不同,在这种情况下,您是在交换一种商品为另一种商品。由此产生的过账成本为每股$50.00。
您可以使用金额或金额表达式后的‘@’符号来显式指定任何过账的成本:
2012-03-10 我的经纪人 资产:经纪账户 10 AAPL @ $50.00 资产:经纪账户:现金 $-500.00
当您这样做时,由于 Ledger 现在可以从第一个过账的成本计算出平衡金额,您可以省略另一个金额:
2012-03-10 我的经纪人 资产:经纪账户 10 AAPL @ $50.00 资产:经纪账户:现金
在 Ledger 中有一个通用约定:交易中的“顶部”过账包含目标账户,而最后的过账包含源账户。每当商品以这种方式交换时,转移到目标账户的商品被视为“次要”商品,而用于购买并在成本中跟踪的商品是“主要”商品。
换句话说,每当 Ledger 看到形式为"金额 @ 金额"的过账成本时,第二个金额中使用的商品被标记为“主要”商品。
主要商品的唯一意义是--market (-V)标志永远不会将主要商品转换为任何其他商品。然而,--exchange 商品 (-X)仍然会进行转换。
就像您可以有金额表达式一样,您也可以有过账表达式:
2012-03-10 我的经纪人 资产:经纪账户 10 AAPL @ ($500.00 / 10) 资产:经纪账户:现金
您甚至可以同时拥有两者:
2012-03-10 我的经纪人 资产:经纪账户 (5 AAPL * 2) @ ($500.00 / 10) 资产:经纪账户:现金
‘@’字符后的成本数值指定了所转移商品的单价。如果您想指定总成本,请使用‘@@’:
2012-03-10 我的经纪人 资产:经纪账户 10 AAPL @@ $500.00 资产:经纪账户:现金
Ledger 会将其解读为您写入了:
2012-03-10 我的经纪人 资产:经纪账户 10 AAPL @ ($500.00 / 10) 资产:经纪账户:现金
通常每当发生此类商品交换时,交换价格(例如上文中每股 AAPL 50 美元)会被记录在 Ledger 的内部价格历史数据库中。为防止在特殊交易中出现这种情况,请用括号将‘@’或‘@@’括起来:
2012-03-10 我的兄弟 资产:经纪账户 1000 AAPL (@) $1 收入:收到的礼物
当发生一种商品与另一种商品交换的交易时,Ledger 不仅在其内部价格数据库中记录该商品价格,还会将其附加到商品本身。通常这一事实对用户是不可见的,除非您启用--lot-prices来显示这些隐藏的价格数值。
例如,考虑上面给出的股票销售:
2012-03-10 我的经纪人 资产:经纪账户 10 AAPL @ $50.00 资产:经纪账户:现金
转移到‘资产:经纪账户’的商品实际上不是 10 AAPL,而是 10 AAPL {$50.00}。金额后面大括号中的数值被称为“批次价格”。这是 Ledger 记住该商品通过交换转移的方式,且$50.00 是该交换的价格。
如果您之后再次出售该商品,这一点就变得很重要。例如,您可能会这样写:
2012-04-10 我的经纪人 资产:经纪账户:现金 资产:经纪账户 -10 AAPL @ $75.00
这样完全没问题,但如何跟踪销售的资本收益呢?可以通过虚拟过账来完成:
2012-04-10 我的经纪人 资产:经纪账户:现金 资产:经纪账户 -10 AAPL @ $75.00 (收入:资本收益) $-250.00
但这会变得混乱,因为资本收益收入是非常真实的,不太适合虚拟过账。
相反,如果您引用相同的隐藏价格注释,Ledger 将计算出您正在出售的股票价格与您出售它们的成本不平衡:
2012-04-10 我的经纪人 资产:经纪账户:现金 $750.00 资产:经纪账户 -10 AAPL {$50.00} @ $75.00此交易将失败,因为您购买这些股票的价格与卖出价格之间存在 250.00 美元的价差不匹配。批次价格还标识了您在该先前日期购买的特定股票。
作为简写形式,您可以在双花括号中指定总价而非每股价格。这与总成本搭配使用效果很好,但不强制要求必须一起使用:
2012-04-10 我的经纪人 资产:经纪业务:现金 $750.00 资产:经纪业务 -10 AAPL {{$500.00}} @@ $750.00 收入:资本收益 $-250.00需要注意的是,这仅适用于买卖整批股票的便利情况。{{$500.00}} 并非商品的属性,而{$50.00}则是。实际上,当您写入{{$500.00}}时,Ledger 只是将该值除以 10 并视为{$50.00}。因此如果您使用 print 命令查看此交易,将在输出中看到单花括号形式。双花括号价格形式仅是一种简写方式。
此外,它还存在风险。以下操作正常:
2012-04-10 我的经纪人 资产:经纪业务 10 AAPL @ $50.00 资产:经纪业务:现金 $-500.00 2012-04-10 我的经纪人 资产:经纪业务:现金 $375.00 资产:经纪业务 -5 AAPL {$50.00} @@ $375.00 收入:资本收益 $-125.00 2012-04-10 我的经纪人 资产:经纪业务:现金 $375.00 资产:经纪业务 -5 AAPL {$50.00} @@ $375.00 收入:资本收益 $-125.00但以下操作不会达到预期效果:
2012-04-10 我的经纪人 资产:经纪业务 10 AAPL @ $50.00 资产:经纪业务:现金 $-500.00 2012-04-10 我的经纪人 资产:经纪业务:现金 $375.00 资产:经纪业务 -5 AAPL {{$500.00}} @@ $375.00 收入:资本收益 $-125.00 2012-04-10 我的经纪人 资产:经纪业务:现金 $375.00 资产:经纪业务 -5 AAPL {{$500.00}} @@ $375.00 收入:资本收益 $-125.00在金额无法整除而必须四舍五入的情况下,资本收益数字可能会有 1 美分的误差。请谨慎使用。
由于批次定价提供了足够的信息来推断成本,以下两个交易是等价的:
2012-04-10 我的经纪人 资产:经纪业务 10 AAPL @ $50.00 资产:经纪业务:现金 $-500.00 2012-04-10 我的经纪人 资产:经纪业务 10 AAPL {$50.00} 资产:经纪业务:现金 $-500.00但请注意,在某些报告(例如打印报告)中显示的内容可能有所不同。然而在功能上并无差异,登记簿和余额报告都不会受到这种差异的影响。
如果您去年购买了一支股票,现在想查询其当前价值,Ledger 会查询其价格数据库以获取该股票的最新价格。您可以通过在交易时“固定”价格来跳过这个查询过程。这可以通过使用‘{=金额}’来实现:
2012-04-10 我的经纪商 资产:经纪账户 10 AAPL {=$50.00} 资产:经纪账户:现金 $-500.00无论在此期间该股票发生什么变化,这 10 股 AAPL 现在将始终被报告为价值 50 美元。
固定价格是使用批次估值表达式(见下文)来固定商品批次价值的一种特殊情况。
由于价格注释和成本在很大程度上可以互换且取决于个人偏好,通过成本指定固定价格也有等效语法:
2012-04-10 我的经纪商 资产:经纪账户 10 AAPL @ =$50.00 资产:经纪账户:现金 $-500.00
这与之前的交易相同,具有与价格与成本中相同的注意事项。
当用一种商品交换另一种商品时,Ledger 允许通过共同基础货币跟踪盈亏。这在交易两种非基础货币商品且两者都有以第三种货币计价的已知价格时非常有用。
例如,如果您用比特币(BTC)交换以太坊(ETH),且两者都有已知的美元价值,Ledger 可以自动计算并以美元为单位跟踪盈亏。
要使用此功能,您需要同时为源商品和目标商品指定价格注释:
2025-04-12 Coinbase 资产:Coinbase -100 BTC {$100} 2 ETH {$40} [2025-04-12] 资产:Coinbase 200 ETH {$40} [2025-04-12] 支出:资本损失 $2,000.00在此示例中:
ETH 接收方的大括号中的价格注释{$40}表示 ETH 在共同基础货币中的单位价格。Ledger 将使用此信息自动计算盈亏。
您也可以稍后出售第二种商品并跟踪其盈亏:
2025-04-13 Coinbase 资产:Coinbase -200 ETH {$40} [2025-04-12] $50 资产:Coinbase $10,000 收入:资本收益 $-2,000.00这种方法提供了跨不同商品的完整端到端投资跟踪,同时在共同基础货币中保持准确的盈亏记录。
除了批次价格外,您还可以指定批次日期并通过--lot-dates显示它们。但除此之外,它们对 Ledger 没有特殊含义。它们在金额后的方括号中指定(与在价值表达式中解析日期的方式相同):
2012-04-10 我的经纪商 资产:经纪账户:现金 $375.00 资产:经纪账户 -5 AAPL {$50.00} [2012-04-10] @@ $375.00 收入:资本收益 $-125.00您还可以在括号内添加任意备注用于自己的记录保存,并通过 --lot-notes 显示它们。需要注意的是,备注不能以‘@’字符开头,因为那表示虚拟成本:
2012-04-10 我的经纪商 资产:经纪账户:现金 $375.00 资产:经纪账户 -5 AAPL {$50.00} [2012-04-10] (天哪!) @@ $375.00 收入:资本收益 $-125.00您可以以任意顺序指定批次价格、日期或备注的任意组合。这些都是可选的。
要在报告中显示所有批次信息,请使用 --lots。
通常当您要求 Ledger 显示持有的商品价值时,它会使用名为“市场”的价值表达式从其价格数据库中确定最新价值——如果指定了 --download (-Q) 并且在您的系统上找到了合适的 getquote 脚本,它甚至会从互联网下载价格。
但是,您可以通过在双括号中提供商品估值表达式来覆盖此估值逻辑。此表达式必须产生两个值之一:要么始终用作该商品每股价格的金额;要么是接受三个参数的函数,调用该函数来确定价格。
如果使用函数形式,您可以指定函数名称或 lambda 表达式。这是一个函数,无论请求什么商品,它都会产生 $10 的价格:
定义 ten_dollars(s, date, t) = market($10, date, t)
我现在可以在批次价值表达式中使用它,如下所示:
2012-04-10 我的经纪商 资产:经纪账户:现金 $375.00 资产:经纪账户 -5 AAPL {$50.00} ((ten_dollars)) @@ $375.00 收入:资本收益 $-125.00或者,我可以通过使用接受三个参数的 lambda 表达式来实现相同的功能,而无需预定义函数:
2012-04-10 我的经纪商 A:B:现金 $375.00 A:B -5 AAPL {$50.00} ((s, d, t -> market($10, date, t))) @@ $375.00 收入:资本收益 $-125.00传递给这些函数的参数具有以下含义:
在大多数情况下,最简单的方法是在估值表达式中使用明确金额,或者根据需求修改参数后将其传递给‘market’。
自动化交易是一种特殊类型的交易,当其他交易的任何记账项匹配其谓词时,它会将其记账项添加到这些交易中。谓词使用与 Ledger 命令行相同的查询语法。
考虑以下记账项:
2012-03-10 KFC 支出:食品 $20.00 资产:现金
如果我在文件中在此之前编写此自动化交易:
= expr true Foo $50.00 Bar $-50.00
那么在解析过程中,第一个交易将被修改,就像我写了这样:
2012-03-10 KFC 支出:食品 $20.00 Foo $50.00 Bar $-50.00 资产:现金 $-20.00 Foo $50.00 Bar $-50.00
尽管有这种复杂的逻辑,自动化交易本身遵循与常规交易大部分相同的规则:它们的记账项必须平衡(除非使用虚拟记账项),可以包含元数据等。
然而,有一件事不能做,就是在自动化交易中省略金额。
作为一种特殊情况,如果自动化交易的记账项金额(呼)没有商品单位,则将其视为匹配记账项成本的乘数。例如:
= expr true Foo 50.00 Bar -50.00 2012-03-10 KFC 支出:食品 $20.00 资产:现金
那么在解析过程中,后一个交易会变成这样:
2012-03-10 KFC 支出:食品 $20.00 Foo $1000.00 Bar $-1000.00 资产:现金 $-20.00 Foo $1000.00 Bar $-1000.00
如果在自动化交易的过账中使用金额表达式,该表达式可以访问匹配过账的所有详细信息。例如,您可以使用“amount”值表达式变量引用该过账的金额:
= expr true (Foo) (amount * 2) ; 在此情况下等同于 "2" 2012-03-10 KFC 支出:食品 $20.00 资产:现金
这将变为:
2012-03-10 KFC 支出:食品 $20.00 (Foo) $40.00 资产:现金 $-20.00 (Foo) $-40.00
有时您希望在自动化交易本身中以某种方式引用匹配的账户。这可以通过在自动化过账的账户部分任意位置使用字符串‘$account’来实现:
= food (预算:$account) 10 2012-03-10 KFC 支出:食品 $20.00 资产:现金
变为:
2012-03-10 KFC 支出:食品 $20.00 (预算:支出:食品) $200.00 资产:现金 $-20.00
可以使用VEXPR引用过账中的信息。请注意,使用VEXPR的语法是"%(VEXPR)"。
= ^收入 负债:税费:%(标签(/税费/)) (20/120) $账户 (-20/120) 2024-07-04 * 销售 ; 税费: 通用 资产 10 USD 收入:客户 A
变为:
2024/07/04 * 销售 ; 税费: 通用 资产 10 USD 收入:客户 A -10 USD 负债:税费:通用 -2 USD 收入:客户 A 2 USD
请注意,如果您使用--strict或--pedantic模式,必须明确定义账户以避免错误。当使用‘$account’时,可以这样定义:
账户 $账户
如果自动化交易有交易备注,该备注(以及任何元数据)将被复制到每个匹配谓词的过账中:
= food ; Foo: Bar (预算:$账户) 10 2012-03-10 KFC 支出:食品 $20.00 资产:现金
变为:
2012-03-10 KFC 支出:食品 $20.00 ; Foo: Bar (预算:支出:食品) $200.00 资产:现金 $-20.00
如果自动化交易的过账有备注,该备注将传递到匹配交易中生成的过账:
= food (预算:$账户) 10 ; Foo: Bar 2012-03-10 KFC 支出:食品 $20.00 资产:现金
变为:
2012-03-10 KFC 支出:食品 $20.00 (预算:支出:食品) $200.00 ; Foo: Bar 资产:现金 $-20.00
这与常规交易注释的规则略有不同,自动化交易的注释并不适用于其内部的每个过账,而是适用于它匹配的每个过账。
在现实世界中,交易并非瞬时完成。购物可能需要几天时间才能过账到银行账户。您可能会提前支付某项费用,并希望分摊成本。通过 Ledger,您可以控制交易时间安排的每个方面。
假设您正在经营业务。如果您向客户开具账单,可以输入类似这样的内容:
2008/01/01=2008/01/14 客户发票 ; 预计收款日期 资产:应收账款 $100.00 收入:客户名称
然后,当您收到付款时,将其更改为:
2008/01/01=2008/01/15 客户发票 ; 实际收款日期 资产:应收账款 $100.00 收入:客户名称
并添加类似这样的内容:
2008/01/15 客户付款 资产:支票账户 $100.00 资产:应收账款
现在
$ ledger --begin 2008/01/01 --end 2008/01/14 bal 收入
会显示您在该年前两周的应计收入,而
$ ledger --effective --begin 2008/01/01 --end 2008/01/14 bal 收入
会显示您在同一两周内的现金制收入。
另一个用途是随时间分摊成本。例如,假设您刚刚预付了当地蔬菜合作社的费用,这将支撑您度过整个冬天。加入该计划需要花费 225 美元,因此您开了一张支票。但您不希望十月份的食品预算因为提前购买食物而超支。您真正希望的是将这笔钱均匀分摊到接下来的六个月中,这样您的月度预算会逐渐为从合作社领取的蔬菜承担费用,即使您已经提前支付了款项。
2008/10/16 * (2090) 丰盛祝福农场 支出:食品:杂货 $ 37.50 ; [=2008/10/01] 支出:食品:杂货 $ 37.50 ; [=2008/11/01] 支出:食品:杂货 $ 37.50 ; [=2008/12/01] 支出:食品:杂货 $ 37.50 ; [=2009/01/01] 支出:食品:杂货 $ 37.50 ; [=2009/02/01] 支出:食品:杂货 $ 37.50 ; [=2009/03/01] 资产:支票账户
此条目实现了这一目标。每个月您都会看到应有的 37.50 美元自动赤字,而您的支票账户实际上知道本月借记了 225 美元。
使用 --effective(或 --aux-date)选项时,初始日期将被生效日期覆盖。
$ ledger --effective register 杂货
01-10 月-08 丰盛祝福.. 支出:食品:杂货 $ 37.50 $ 37.50 01-11 月-08 丰盛祝福.. 支出:食品:杂货 $ 37.50 $ 75.00 01-12 月-08 丰盛祝福.. 支出:食品:杂货 $ 37.50 $ 112.50 01-1 月-09 丰盛祝福.. 支出:食品:杂货 $ 37.50 $ 150.00 01-2 月-09 丰盛祝福.. 支出:食品:杂货 $ 37.50 $ 187.50 01-3 月-09 丰盛祝福.. 支出:食品:杂货 $ 37.50 $ 225.00
请注意 --aux-date 选项是 --effective 的别名;关于辅助日期的简要说明,请参阅 辅助日期。
周期性交易以波浪符‘~’开头,后跟一个周期表达式(参见 周期表达式)。周期性交易仅用于预算和预测,若未指定 --budget 选项,则不会产生任何效果。有关示例和详细信息,请参阅 预算与预测。
作为一名巴哈伊信徒,我需要在获取资产时计算胡库库拉(Huqúqu’lláh)。这类似于犹太教徒和基督徒的什一税,或穆斯林的天课(Zakát)。计算胡库库拉的具体细节较为复杂,但如果您有进一步兴趣,请查阅网络资料。
Ledger 使这项原本复杂的法律变得非常简单。只需在账本文件顶部设置一个自动化记账项:
; 此自动化交易将基于本日记账的记账项计算胡库库拉。任何匹配的账户将按该记账项价值的 19% 影响 ; 负债:胡库库拉账户。= /^(?:收入:|支出:(?:业务|租金$|家具|税费|保险))/ (负债:胡库库拉) 0.19
此自动化记账项通过检查账本文件中的每个记账项来工作。如果任何记账项匹配给定的值表达式,该记账项价值的 19% 将应用于‘负债:胡库库拉’账户。因此,如果从‘收入:工资’赚取 1000 美元,则向‘负债:胡库库拉’账户添加 190 美元;如果花费 1000 美元支付租金,则减去 190 美元。
2003/01/01 (99) 工资 收入:工资 -$1000 资产:支票 2003/01/01 (100) 租金 支出:租金 $500 资产:支票
胡库库拉的最终余额反映了为履行胡库库拉义务所需支付的金额。当准备支付时,只需开具一张支票来覆盖‘负债:胡库库拉’中显示的金额。该交易将如下所示:
2003/01/01 (101) 巴哈伊胡库库拉信托 负债:胡库库拉 $1,000.00 资产:支票
就是这样。要查看根据您的账本交易当前欠多少胡库库,请使用:
$ ledger balance 负债:胡库库
$-95 负债:胡库库拉
这种方法可行,但忽略了法律的一个方面:胡库克(Huqúq)仅在负债超过 19 米斯卡尔黄金价值(约 2.22 盎司)时才需缴纳。因此我们需要的是,只有当负债超过当前 2.22 盎司黄金价值时,才在余额报告中显示该负债。这可以通过以下命令实现:
$ ledger -Q -t "/Liab.*Huquq/?(a/P{2.22 AU}<={-1.0}&a):a" bal liab使用此命令时,系统会下载黄金的当前价格,并且只有当胡库库拉(Huqúqu’lláh)的价值超过 2.22 盎司黄金时才会报告。如果您希望无论如何都在父级小计中反映该负债,请改用以下命令:
$ ledger -Q -T "/Liab.*Huquq/?(O/P{2.22 AU}<={-1.0}&O):O" bal liab在某些情况下,您可能希望引用与自动化交易值表达式匹配的任何过账账户。为此,请使用特殊账户名称‘$account’:
= /^Some:Long:Account:Name/ [$account] -0.10 [Savings] 0.10
此示例将匹配账户总额的 10%延迟到‘Savings’(储蓄)账户——作为平衡的虚拟过账,可通过使用--real参数在报告中排除。
信用卡有时会提供消费金额的返现百分比。可通过以下方式设置:
; 此自动化交易将添加到"Assets:Credit Card Cashback"(资产:信用卡返现); 交易金额乘以"cashback"(返现)标签。= "Liabilities:Credit Card" and %cashback Assets:Credit Card Cashback (-amount * tag("cashback") * 0.01) Income:Credit Card Rewards (amount * tag("cashback") * 0.01)要添加提供 2%返现的交易:
2023/06/06 麦当劳 ; cashback:: 2% Expenses:Food:Restaurants $23.98 Liabilities:Credit Card
现在当生成报告时,例如:
$ ledger -f cashback.dat reg
返现过账会随交易一起显示。
23-6 月-06 麦当劳 支出:食品:餐厅 $23.98 $23.98 负债:信用卡 $-23.98 0 ..信用卡返现 $0.48 $0.48 收入:信用卡奖励 $-0.48 0
Ledger 的强大功能来自于其报告命令的惊人灵活性,结合格式化命令。某些选项控制计算中包含的内容,而格式化控制其显示方式。组合方式是无限的。本章将向您展示组合各种选项和命令的基础知识。在后续章节中,您将找到有关特定命令和选项的详细信息。
余额报告是最常用的报告。最简单的调用方式是:
$ ledger balance -f drewr3.dat
这将打印您日记账中每个账户的余额。
$ -3,804.00 资产 $ 1,396.00 支票账户 $ 30.00 业务 $ -5,200.00 储蓄账户 $ -1,000.00 权益:期初余额 $ 6,654.00 支出 $ 5,500.00 汽车 $ 20.00 书籍 $ 300.00 托管账户 $ 334.00 食品:杂货 $ 500.00 利息:抵押贷款 $ -2,030.00 收入 $ -2,000.00 工资 $ -30.00 销售 $ -63.60 负债 $ -20.00 万事达卡 $ 200.00 抵押贷款:本金 $ -243.60 什一税 -------------------- $ -243.60
大多数时候,这比您想要的要多。将结果限制到特定账户就像在命令后输入账户名称一样简单:
$ ledger balance -f drewr3.dat Auto MasterCard
$ 5,500.00 支出:汽车 $ -20.00 负债:万事达卡 -------------------- $ 5,480.00
注意‘Auto’和‘Mastercard’之间隐含的逻辑或关系。
如果您想要账户树分支的完整内容,请使用分支中的最高公共名称:
$ ledger balance -f drewr3.dat Income
$ -2,030.00 收入 $ -2,000.00 工资 $ -30.00 销售 -------------------- $ -2,030.00
您几乎可以在 Ledger 需要字符串的任何地方使用通用正则表达式(PCRE):
$ ledger balance -f drewr3.dat ^Bo
第一个示例查找任何以‘Bo’开头的账户,但没有找到。
$ ledger balance -f drewr3.dat Bo
$ 20.00 支出:书籍
第二个示例查找任何包含‘Bo’的账户,即‘Expenses:Books’。
如果您想确切知道在特定账户上向特定收款人花费了多少,以下两种方式是等效的:
$ ledger balance Expenses:Auto:Fuel and @Chevron
$ ledger balance --limit 'account=~/Expenses:Auto:Fuel/ and payee=~/Chevron/'
将显示您在 Chevron 加油站购买汽油的支出金额。第二个示例是可用于塑造报告的非常强大的表达式语言的第一个示例。第一个示例可能更容易记住,但学会使用第二个将打开更多可能性。
如果您想从报告中排除特定账户,可以使用括号排除多个账户:
$ ledger bal Expenses and not (Expenses:Drinks or Expenses:Candy or Expenses:Gifts)
以下查询显示自去年十月以来的所有支出,按总额排序:
$ ledger -b "last oct" -S T bal ^expenses
从左到右的选项分别表示:显示自去年十月以来的交易;按总额的绝对值排序;并报告所有以‘expenses’开头的账户余额。
以下查询可轻松查看月度支出,并按金额对每个月的支出进行排序:
$ ledger -M --period-sort "(amount)" reg ^expenses
现在,您可能想知道支付这些费用的资金来自何处。要查看该报告,请添加--related (-r)选项,它会显示“关联账户”的过账:
$ ledger -M --period-sort "(amount)" -r reg ^expenses
但这可能会打印过多信息。您可能只想查看使用万事达卡的消费金额。这类查询需要使用显示谓词,因为计算的过账必须匹配‘^expenses’,而显示的过账必须匹配‘mastercard’。命令如下:
$ ledger -M -r --display 'account=~/mastercard/' reg ^expenses
此查询表示:报告月度小计;报告“关联账户”的过账;仅显示账户匹配‘mastercard’的关联过账,并基于匹配‘^expenses’的过账进行计算。
这同样适用于报告总体总额:
$ ledger -s -r --display "account=~/mastercard/" reg ^expenses
--subtotal (-s)选项对所有过账进行小计,就像--monthly (-M)按月份进行小计一样。但由于使用了显示表达式,这两种情况下的运行总额都不准确。
管理投资组合的一个非常流行的方法是通过特定类别来控制资产的百分比分配。类别组合及其权重因投资理念而异,但大多数都遵循类似的模式。在 ledger 中跟踪资产配置并不困难,但确实需要一些额外的努力来描述您拥有的各种资产如何贡献到您想要跟踪的资产类别中。
在我们的简单示例中,我们假设您希望将资产分配到国内和国际股票(股票)以及债券和现金的组合类别中。为了说明目的,我们将使用 Vanguard 的几个公开可用的共同基金。我们将跟踪的三个基金是 Vanguard 500 指数基金信号(VIFSX)、Vanguard 目标退休 2030(VTHRX)和 Vanguard 短期联邦基金(VSGBX)。这些基金中的每一个都将资产分配到投资领域的不同类别,并以不同的比例进行分配。当您购买 VTHRX 的份额时,该份额部分投资于股票,部分投资于债券和现金。以下是上述列出的每种工具的资产分配:
| 国内 | 全球 | ||
| 代码 | 股票 | 股票 | 债券/现金 |
| VIFSX | 100% | ||
| VTHRX | 24.0% | 56.3% | 19.7% |
| VSGBX | 100% |
这些数字可以从任何公开可用的共同基金的招股说明书中获得。当然,单只股票是 100%的股权,单只债券是 100%的债券。
我们使用该投资的代码作为其商品来跟踪特定投资的购买。我们如何告诉 Ledger,VTHRX 的份额是 24%的国内股票?输入自动交易和虚拟账户。
在我们的账本顶部,我们输入自动交易,向 Ledger 描述这些比例。在相同的条目中,我们设置虚拟账户,让我们将这些抽象计算与我们的实际余额分开。
对于上面列出的三种工具,这些自动交易将如下所示:
= expr ( commodity == 'VIFSX' ) (Allocation:Equities:Domestic) 1.000 = expr ( commodity == 'VTHRX' ) (Allocation:Equities:Global) 0.240 (Allocation:Equities:Domestic) 0.563 (Allocation:Bonds/Cash) 0.197 = expr ( commodity == 'VBMFX') (Allocation:Bonds/Cash) 1.000 2015-01-01 Buy VIFSX Assets:Broker 100 VIFSX Assets:Cash $-10000 2015-01-01 Buy VTHRX Assets:Broker 10 VTHRX Assets:Cash $-10000 2015-01-01 Buy VBMFX Assets:Broker 1 VBMFX Assets:Cash $-10000
这些是如何工作的?首先,行首的‘=’符号告诉 Ledger,这是一个自动交易,当‘=’后面的条件为真时应用。在‘=’符号之后是一个值表达式(参见值表达式),当任何过账包含感兴趣的商品时,它返回真。
下一行给出了属于每个资产类别的每个商品单位的比例(不是百分比)。每当 Ledger 看到特定商品的买入或卖出时,它将根据移动的股份数量的该比例贷记或借记这些虚拟账户。
既然 Ledger 知道如何在各种资产类别之间分配商品,我们如何获得一个报告来告诉我们当前的分配?使用余额命令和一些巧妙的格式化!
ledger bal Allocation --current --format "\ %-17((depth_spacer)+(partial_account))\ %10(percent(market(display_total), market(parent.total)))\ %16(market(display_total))\n%/"
这产生:
Allocation 100.00% $30000 Bonds/Cash 39.90% $11970 Equities 60.10% $18030 Domestic 86.69% $15630 Global 13.31% $2400
让我们更仔细地看看 Ledger 的调用。上面的命令为了清晰起见被分成多行。第一行是非常普通的 Ledger,要求使用特殊格式化器获取“Allocation”树中账户的当前余额。
魔法在于格式化器。第二行简单地指示 Ledger 按账户在树状结构中的深度缩进打印部分账户名称。第三行是我们计算和显示百分比的地方。display_total命令给出此行中为该账户计算的总值。parent.total命令给出树状结构中上一层级的总值。percent将它们的比率格式化为百分比。第四行指示 ledger 显示该行的当前市场价值。最后两个字符‘%/’告诉 Ledger 在最后一行执行什么操作,在此情况下,什么都不做。
如果您安装了“Gnuplot”程序,可以绘制上述任何登记报告的图表。执行此操作的脚本包含在 ledger 发行版中,名为contrib/report。将report安装到PATH中的任意位置,然后在执行登记报告时使用report代替ledger。唯一需要注意的是,必须指定--amount-data (-j)或--total-data (-J)来指示“Gnuplot”应绘制金额还是运行总计。例如,此命令绘制您在 MasterCard 上产生的月度总支出。
$ report -j -M -r --display "account =~ /mastercard/" reg ^expenses
report脚本是一个非常简单的 Bourne shell 脚本,它将一组脚本化命令传递给“Gnuplot”。请随意根据您的喜好修改脚本,例如,您可能更喜欢直方图而不是折线图。
以下是一些有用的绘图:
report -j -M reg ^expenses # 月度支出 report -J reg checking # 支票账户余额 report -J reg ^income ^expenses # 现金流报告 # 净资产报告,忽略非美元记账 report -J -l "Ua>={\$0.01}" reg ^assets ^liab # 从去年二月开始的净资产报告。需要使用显示谓词(-d),否则余额将从零开始,因此 y 轴不会反映真实余额 report -J -l "Ua>={\$0.01}" -d "d>=[last feb]" reg ^assets ^liab最后一个报告同时使用了计算谓词--limit EXPR (-l)和显示谓词--display EXPR (-d)。计算谓词将报告限制为金额大于或等于$0.01 的记账(这只有在记账金额以美元为单位时才会发生)。显示谓词将显示的交易限制为自去年二月以来的交易,即使之前的那些交易仍将作为余额的一部分进行计算。
balance 命令 ¶balance 命令报告所有账户的当前余额。它接受一个可选正则表达式列表,这些正则表达式将余额报告限制为匹配的账户。如果一个账户包含多种类型的商品,每种商品的总数将分别报告。
register 命令 ¶register 命令逐行显示单个账户中发生的所有过账。账户正则表达式必须作为此命令的唯一参数指定。如果在必需的账户名称之后出现任何正则表达式,寄存器将仅包含匹配的过账,这对于查找特定过账非常有用。
register 的输出非常接近典型支票簿或单账户分类账的外观。它还显示运行余额。任何寄存器的最终运行余额应始终与该账户的当前余额相同。
如果您安装了“Gnuplot”,您可以使用 Ledger 发行版中包含的脚本 report 来绘制任何寄存器的金额或运行总额。唯一的要求是您向 register 命令添加 --amount-data (-j) 或 --total-data (-J),以便分别绘制金额列或总额列。
print 命令 ¶print 命令以 Ledger 可解析的文本格式输出账本交易记录。这些记录将被正确格式化,并以最经济的形式输出。print 命令还接受一系列可选的正则表达式,仅会打印与之匹配的过账条目。
print 命令是整理格式混乱的账本文件的便捷方法。
convert 命令 ¶convert 命令解析逗号分隔值(CSV)文件并输出 Ledger 交易记录。许多银行提供 CSV 文件下载。不幸的是,除了逗号分隔外,文件格式各不相同。Ledger 的 convert 命令会尽力提供帮助。
您银行的 CSV 文件字段顺序与其他银行不同,因此必须有一种方法告知 Ledger 预期的格式。在 CSV 文件开头插入一行,向 Ledger 描述字段信息。
例如,这是从美国一家信用合作社下载的 CSV 文件的一部分:
账户名称:VALUFIRST 支票账户 账户号码:71 日期范围:2011 年 11 月 13 日 - 2011 年 12 月 13 日 交易编号,日期,描述,备注,借方金额,贷方金额,余额,支票号码,费用 767406,2011/12/13,"存款","现金存款",,45.00,00001646.89,, 767718,2011/12/13,"取款","ACE HARDWARE 16335 S HOUGHTON RD",8.80,,00001640.04,, 767406,2011/12/13,"取款","ACE HARDWARE 16335 S HOUGHTON RD",1.03,,00001648.84,, 683342,2011/12/13,"Visa 支票","NetFlix 日期 2011/12/12 000326585896 5968",21.85,,00001649.87,, 639668,2011/12/13,"取款","ID: 1741472662 CO: XXAA.COM 付款",236.65,,00001671.72,, 1113648,2011/12/12,"取款","Tuscan IT #00037657",29.73,,00001908.37,,
遗憾的是,目前 Ledger 无法直接读取该文件,但您可以手动处理。Ledger 期望第一行包含文件中每行字段的描述。Ledger 能够识别的字段包含以下不区分大小写的字符串:date、posted、code、payee 或 desc 或 description、amount 或 credit、debit、cost、total 以及 note。
删除顶部的账户描述行,并将上述数据的第一行替换为:
,date,payee,note,debit,credit,,code,
然后像这样执行 ledger 命令:
$ ledger convert download.csv --input-date-format "%m/%d/%Y"
其中 --input-date-format DATE_FORMAT 选项告诉 Ledger 如何解析日期格式。
导入 CSV 文件需要较多工作,但非常适合通过脚本自动化处理。
如果您的 CSV 文件只有一个金额列,且使用正负号区分贷方和借方,这也是支持的。例如,上述账户的前几行也可以采用以下格式:
,date,payee,note,credit,,code, 767406,2011/12/13,"存款","现金存款",45.00,00001646.89,, 767718,2011/12/13,"取款","ACE HARDWARE 16335 S HOUGHTON RD",-8.80,00001640.04,,
如果银行数据中有除上述主要字段外您希望保留在账本数据中的列,您可以在字段描述符列表中命名它们,如果 Ledger 不识别该字段名称,它会将其作为元数据包含在交易中。例如,如果您想捕获银行交易编号且它出现在数据的第一列,请使用:
transid,date,payee,note,debit,credit,,code,
Ledger 将在来自上述文件的第一个交易中包含‘; transid: 767718’。
convert 命令接受四个选项。它们是:--invert(反转金额)、--auto-match(自动为每行 CSV 数据匹配 Ledger 日记账中的账户)、--account STR(可用于指定要平衡的账户)以及 --rich-data(存储额外的标签/值对)。
使用上述 CSV 文件的前两行,
,date,payee,note,debit,credit,balance,code, 767406,2011/12/13,"存款","现金存款",,45.00,00001646.89,, 767718,2011/12/13,"取款","ACE HARDWARE 16335 S HOUGHTON RD",8.80,,00001640.04,,
并运行以下命令,
$ ledger convert download.csv --input-date-format "%m/%d/%Y" \ --invert --account Assets:MyBank --rich-data \ --file sample.dat --now=2012/01/13
你将得到以下结果:
2011/12/13 * 存款 ;现金存款 ; 余额: 00001646.89 ; CSV: 767406,12/13/2011,"存款","现金存款",,45.00,00001646.89,, ; 导入日期: 2012/01/13 ; UUID: ce0b7d42b02ce5eaf0d828c3b1028041fd09494c 支出:未知 -45 资产:我的银行 2011/12/13 * 取款 ;ACE 五金店 16335 S HOUGHTON RD ; 余额: 00001640.04 ; CSV: 767718,12/13/2011,"取款","ACE 五金店 16335 S HOUGHTON RD",8.80,,00001640.04,, ; 导入日期: 2012/01/13 ; UUID: 0aaf85911adc447ea2d5377ff6a60d6b2940047f 支出:未知 8.8 资产:我的银行
添加的三个元数据分别是:'CSV'(来自 CSV 文件的原始行),'Imported'(CSV 文件导入 Ledger 的日期),以及'UUID'(原始 CSV 行的校验和)。
如果普通 Ledger 文件(通过--file FILE (-f)或环境变量LEDGER_FILE指定)中已包含具有相同'UUID'标签的条目,则该条目将不再重复输出。
在上述输出中,CSV 行的账户为'Expenses:Unknown'。你可以使用--auto-match选项来自动匹配 Ledger 日记中的账户。
你也可以将convert与payee和account指令结合使用。首先,可以使用payee和alias指令根据某些规则重写payee字段。然后可以使用账户及其payee指令来指定账户。例如,我这样使用:
payee Aldi alias ^ALDI SUED SAGT DANKE account 支出:购物:食品 payee ^(Aldi|Alnatura|Kaufland|REWE)$
请注意,如果你想要匹配新的 payee 字段,可能需要将'ledger convert'的输出再次传递给ledger print。在ledger convert运行期间,似乎只使用 CSV 数据中指定的原始 payee 名称。
lisp命令 ¶lisp命令以 Emacs Lisp 可直接读取的格式打印结果。sexp的格式为:
((起始位置 已清算 日期 代码 收款人 (账户 金额)...) ; 过账列表 ...) ; 交易列表
默认情况下,DATE字段使用 Emacs Lisp 时间格式(表示时间的整数列表)。你可以使用--lisp-date-format选项控制日期格式(参见报告选项)。
emacs也可以作为lisp的同义词使用。
org 模式 ¶Org 模式有一个名为 Babel 的子系统,支持文学编程。这允许您在同一文档中混合文本和代码,并自动执行可能生成结果的代码,这些结果随后会出现在文本中。
Babel 支持的语言之一是 Ledger,因此您可以在文本文件中嵌入 Ledger 命令,并使 Ledger 命令的输出也出现在文本文件中。每当添加新的 Ledger 条目时,输出都可以更新。
例如,以下 Org 模式文本文档片段展示了 Babel 系统的一个非常简单但仍有用的应用:
* 在 org 文件中测试 Ledger 的简单示例 以下是一些条目,我已请求运行 Ledger 以生成账户余额。我本可以要求生成寄存器,或者实际上 Ledger 通过命令行选项可以执行的任何操作。 #+begin_src ledger :cmdline bal :results value 2010/01/01 * 初始余额 assets:bank:savings £1300.00 income:starting balances 2010/07/22 * 收到工资 assets:bank:chequing £1000.00 income:salary 2010/07/23 租金 expenses:rent £500.00 assets:bank:chequing #+end_src #+results: : £1800.00 assets:bank : £500.00 chequing : £1300.00 savings : £500.00 expenses:rent : £-2300.00 income : £-1000.00 salary : £-1300.00 starting balances
在“Ledger 源代码块”中的任意位置键入 C-c C-c 将对该块的内容调用 Ledger 并生成一个“结果”块。结果块可以出现在文件中的任何位置,但默认情况下会紧接在源代码块下方。
您可以在执行 Ledger 之前组合多个源代码块,并使用 Babel(和 Org 模式)完成各种其他精彩的操作。
使用 Babel,可以方便地在 org 文件中记录财务交易,并随后生成所需的财务报告。
自 Org 模式 7.01 起,提供了 Ledger 支持。请查看 Worg 上的 Babel 文档 获取如何实现此功能的说明,但我目前直接按以下方式操作:
(org-babel-do-load-languages 'org-babel-load-languages '((ledger . t) ;这是本教程中重要的一项 ))
一旦在 Babel 中启用了 Ledger 支持,我们就可以在 org 文件中包含 Ledger 条目。至少有三种方式可以包含这些条目:
noweb 文学编程方法,在文件的其他位置将它们组合成一个块以供 Ledger 处理,tangle 生成一个 Ledger 文件,随后您可以直接使用 Ledger 处理该文件。前两种方法在这个简短教程中有更详细的描述。
在 org 文件中使用 Ledger 最简单(尽管可能最不实用)的方法是使用单个源块记录所有 Ledger 条目。以下是一个示例源块:
#+name: allinone #+begin_src ledger 2010/01/01 * 初始余额 assets:bank:savings £1300.00 income:starting balances 2010/07/22 * 获得工资 assets:bank:chequing £1000.00 income:salary 2010/07/23 租金 expenses:rent £500.00 assets:bank:chequing 2010/07/24 食物 expenses:food £150.00 assets:bank:chequing 2010/07/31 * 银行储蓄利息 assets:bank:savings £3.53 income:interest 2010/07/31 * 转账储蓄 assets:bank:savings £250.00 assets:bank:chequing 2010/08/01 再次获得工资 assets:bank:chequing £1000.00 income:salary #+end_src
在这个示例中,我们将支出和收入合并为一组 Ledger 条目。现在我们可以使用 Babel 调用 Ledger 并传递特定参数来生成登记簿和余额报告(以及许多其他类型的报告)。参数通过:cmdline头部参数传递给 Ledger。在上面的代码块中,没有这样的参数,因此系统采用默认值。对于 Ledger 代码块,默认的:cmdline参数是bal,评估此代码块(C-c C-c)的结果将是:
#+results: allinone() : £2653.53 assets:bank : £1100.00 chequing : £1553.53 savings : £650.00 expenses : £150.00 food : £500.00 rent : £-3303.53 income : £-3.53 interest : £-2000.00 salary : £-1300.00 starting balances
如果您希望生成所有交易的登记簿,可以更改代码块的#+begin_src行以包含所需的命令行选项:
#+begin_src ledger :cmdline reg
重新评估代码块将生成不同的报告。
必须更改代码块上的实际指令并重新评估,这使得难以拥有多个视图来查看您的交易和财务状况。最终,Babel 将支持向代码块的#+call评估传递参数,但目前缺少此支持。相反,我们可以使用文学编程的概念,如 Babel 的noweb功能所实现的,来帮助我们。
noweb的多个 Ledger 源块 ¶Babel 的 noweb 功能允许我们在代码块内扩展对其他代码块的引用。对于 Ledger,这可用于按类型(例如)对交易进行分组,然后将各种交易集组合在一起生成报告。
使用上面相同的交易,我们可以考虑将它们分为支出和收入,如下所示:
第一组条目涉及收入,无论是月薪还是利息,通常都会存入我的某个银行账户。这里我放置了几个条目,但我们可以将每个条目放在单独的 src 块中。请注意,所有您希望稍后引用的代码块都必须指定 :noweb yes 头部参数。
#+name: income #+begin_src ledger :noweb yes 2010/01/01 * 初始余额 assets:bank:savings £1300.00 income:starting balances 2010/07/22 * 收到工资 assets:bank:chequing £1000.00 income:salary 2010/07/31 * 银行储蓄利息 assets:bank:savings £3.53 income:interest 2010/07/31 * 转账储蓄 assets:bank:savings £250.00 assets:bank:chequing 2010/08/01 再次收到工资 assets:bank:chequing £1000.00 income:salary #+end_src
以下条目涉及个人支出,如房租和食品。同样,这些都已放在单个 src 块中,但也可以单独完成。
#+name: expenses #+begin_src ledger :noweb yes 2010/07/23 房租 expenses:rent £500.00 assets:bank:chequing 2010/07/24 食品 expenses:food £150.00 assets:bank:chequing #+end_src
给定上面在收入和支出代码块中定义的账目条目,我们现在可以使用 noweb 扩展指令 <<name>> 来引用这些条目。我们现在可以定义不同的代码块来为这些交易生成特定报告。以下是两个示例,一个用于生成余额报告,另一个用于生成所有交易的登记报告。
通过向 Ledger 传递 :cmdline bal 参数,可以指定您账户的总体余额和按类别细分的支出情况。现在可以评估此代码块(C-c C-c),并通过包含 <<income>> 和 <<expenses>> 行引用的交易来生成结果。
#+name: balance #+begin_src ledger :cmdline bal :noweb yes <<income>> <<expenses>> #+end_src #+results: balance : £2653.53 assets:bank : £1100.00 chequing : £1553.53 savings : £650.00 expenses : £150.00 food : £500.00 rent : £-3303.53 income : £-3.53 interest : £-2000.00 salary : £-1300.00 starting balances
如果您想要一个不那么详细的资金去向细分,可以指定 --collapse (-n) 标志(即‘:cmdline -n bal’)来告诉 Ledger 在报告中排除子账户。
#+begin_src ledger :cmdline -n bal :noweb yes <<income>> <<expenses>> #+end_src #+results: : £2653.53 assets : £650.00 expenses : £-3303.53 income
您也可以通过执行以下 src 代码块来生成月度登记表(reg 命令)。这会显示每个月度期间(--monthly (-M) 参数)的交易摘要,并在最后一列显示运行总计(如果所有条目都正确,最终应为 0)。
#+name: monthlyregister #+begin_src ledger :cmdline -M reg :noweb yes <<income>> <<expenses>> #+end_src #+results: monthlyregister :2010/01/01 - 2010/01/31 assets:bank:savings £1300.00 £1300.00 : in:starting balances £-1300.00 0 :2010/07/01 - 2010/07/31 assets:bank:chequing £100.00 £100.00 : assets:bank:savings £253.53 £353.53 : expenses:food £150.00 £503.53 : expenses:rent £500.00 £1003.53 : income:interest £-3.53 £1000.00 : income:salary £-1000.00 0 :2010/08/01 - 2010/08/01 assets:bank:chequing £1000.00 £1000.00 : income:salary £-1000.00 0
我们还可以生成关于我们资产的月度报告,显示这些资产是如何增加(或减少!)的。在这种情况下,最后一列将是我们账本中资产的运行总计。
#+name: monthlyassetsregister #+begin_src ledger :cmdline -M reg assets :noweb yes <<income>> <<expenses>> #+end_src #+results: monthlyassetsregister : 2010/01/01 - 2010/01/31 assets:bank:savings £1300.00 £1300.00 : 2010/07/01 - 2010/07/31 assets:bank:chequing £100.00 £1400.00 : assets:bank:savings £253.53 £1653.53 : 2010/08/01 - 2010/08/01 assets:bank:chequing £1000.00 £2653.53
本简短教程展示了如何将 Ledger 条目嵌入到 org 文件中,并使用 Babel 进行操作。然而,仅展示了简单的 Ledger 功能;有关账本上更复杂操作的示例,请参阅 Ledger 文档。
pricemap 命令 ¶如果您安装了 graphviz 图形可视化包,ledger 可以生成各种商品之间关系的图表。输出文件采用“dot”格式。
除非您拥有许多相互计价的不同商品,否则这可能不太有趣。例如,多种货币以及以这些货币计价的多种投资。
xml 命令 ¶默认情况下,Ledger 使用人类可读的数据格式,并以适合屏幕阅读的方式显示其报告。然而,为了编写使用 Ledger 的工具,可以使用 XML 读取和显示数据。本节记录了该格式。
Ledger 数据使用的通用格式为:
<?xml version="1.0"?> <ledger> <xact>...</xact> <xact>...</xact> <xact>...</xact>... </ledger>
数据流包含在 ledger 标签中,该标签包含一系列一个或多个交易。每个 xact 描述一个交易,并包含一系列一个或多个过账:
<xact> <en:date>2004/03/01</en:date> <en:cleared/> <en:code>100</en:code> <en:payee>John Wiegley</en:payee> <en:postings> <posting>...</posting> <posting>...</posting> <posting>...</posting>... </en:postings> </xact>
en:date 的日期格式始终为 YYYY/MM/DD。en:cleared 标签是可选的,表示过账是否已清算。还有一个 en:pending 标签,用于标记待处理的过账。en:code 和 en:payee 标签都包含用户希望的任何文本。
在初始交易数据之后,必须跟随一组用 en:postings 标记的过账。通常这些过账会相互平衡,但如果不平衡,它们将自动平衡到一个名为‘Unknown’的账户中。
在 en:postings 标签内是一系列一个或多个 posting,其形式如下:
<posting> <tr:account>Expenses:Computer:Hardware</tr:account> <tr:amount> <value type="amount"> <amount> <commodity flags="PT">$</commodity> <quantity>90.00</quantity> </amount> </value> </tr:amount> </posting>
这是一个基础记账条目。它可能以tr:virtual和/或tr:generated标签开头,分别表示虚拟和自动生成的记账条目。随后是tr:account标签,其中包含该记账条目关联账户的完整名称。在账户名称中,冒号用于分隔父账户和子账户。
最后是记账条目的金额,由tr:amount标签表示。该标签内包含一个value标签,共有四种不同类型,每种都有其特定的格式:
布尔值的格式为用boolean标签包裹的true或false,例如:
<boolean>true</boolean>
整数值的格式为用integer标签包裹的数值,例如:
<integer>12036</integer>
金额值的格式包含两个成员:商品和数量。商品可以有一组标志来指示其显示方式。这些标志的含义(均为可选)如下:
P商品前缀于数值。
S商品与数值之间用空格分隔。
T使用千位分隔符显示金额。
E金额采用欧洲格式,使用句点作为千位分隔符,逗号作为小数点。
金额的实际数量可以是任意大小的整数。Ledger 使用 GNU 多精度算术库来处理此类数值。XML 格式假定读取器具备同等处理能力。以下是一个金额示例:
<value type="amount"> <amount> <commodity flags="PT">$</commodity> <quantity>90.00</quantity> </amount> </value>
最后,余额值包含一系列金额,每种金额对应不同的商品。与名称不同,此类值不需要平衡。它被称为余额是因为它汇总了多个金额。例如:
<value type="balance"> <balance> <amount> <commodity flags="PT">$</commodity> <quantity>90.00</quantity> </amount> <amount> <commodity flags="TE">DM</commodity> <quantity>200.00</quantity> </amount> </balance> </value>
这就是 Ledger 使用的 XML 数据格式的全部内容。当使用xml命令时,它将输出此类数据,并且能够读取相同格式的数据。
prices和pricedb命令 ¶prices命令显示匹配商品的价历史记录。--average (-A)选项在此报告中很有用,用于显示运行平均价格,或使用--deviation (-D)选项显示每个价格与该平均值的偏差。
还有一个 pricedb 命令,它输出与 prices 相同的信息,但采用 Ledger 可解析的格式。这对于生成和整理 pricedb 数据库文件非常有用。
accounts ¶accounts 命令报告日记账中的所有账户。在命令后跟一个正则表达式将限制输出为匹配该正则表达式的账户。输出按名称排序。使用 --count 选项将告诉您每个账户有多少条目使用。
payees ¶payees 命令报告日记账中的所有唯一收款人。使用 --count 选项将告诉您每个收款人有多少条目使用。要筛选显示的收款人,必须使用前缀 @:
$ ledger payees @Nic
Nicolas Nicolas BOILABUS Oudtshoorn Municipality Vaca Veronica
xact ¶xact 命令简化了新交易的创建过程。它基于 80%的记账都是早期记账变体这一原理工作。其工作原理如下:
假设您当前在账本文件中有以下记账:
2004/03/15 * Viva Italiano 支出:食品 $12.45 支出:小费 $2.55 负债:万事达卡 $-15.00
现在是‘2004/4/9’,您刚刚又在‘Viva Italiano’用餐。具体金额不同,但整体形式相同。使用 xact 命令,您可以输入:
$ ledger xact 2004/4/9 viva food 11 tips 2.50
这将产生以下输出:
2004/04/09 Viva Italiano 支出:食品 $11.00 支出:小费 $2.50 负债:万事达卡
它通过查找与正则表达式‘viva’匹配的过往记账,并假设任何指定的账户或金额都将与该早期记账相似。如果 Ledger 未能成功生成新交易,则会打印错误并将退出代码设置为‘1’。
以下是 xact 命令的更多示例,假设有上述账本交易:
$ ledger xact 4/9 viva 11.50 $ ledger xact 4/9 viva 11.50 checking # (来自 `checking') $ ledger xact 4/9 viva food 11.50 tips 8 $ ledger xact 4/9 viva food 11.50 tips 8 cash $ ledger xact 4/9 viva food $11.50 tips $8 cash $ ledger xact 4/9 viva dining "DM 11.50"
draft 和 entry 都是 xact 的同义词。entry 是为了与 Ledger 2.X 向后兼容而提供的。
stats ¶stats query 提供与查询匹配的所有记账的摘要信息。
$ ledger stats
select ¶select query 命令 select query 允许生成类似 SQL 的查询,例如,
列出与查询匹配的所有记账。此命令允许生成类似 SQL 的查询,例如:
ledger select date,amount from posts where account=~/Income/
本章介绍 Ledger 的功能和选项。您可能希望先浏览本章以获得概览,然后再深入学习Ledger 教程及后续更详细的示例。
Ledger 拥有一个非常简单的命令行界面,其名称相当吸引人——ledger。它支持一些报告命令,并提供大量选项来优化这些命令的输出。任何 ledger 命令的基本语法都是:
$ ledger [选项...] 命令 [参数...]
命令词后可以出现任意数量的参数。对于大多数命令,这些参数是正则表达式,用于使输出仅与匹配这些正则表达式的记录相关。对于xact命令,参数具有特殊含义,如下所述。
正则表达式参数始终匹配记录所引用的账户名称。若要匹配交易的收款人,请在正则表达式前加上‘payee’或‘@’。例如,以下余额命令报告租金、食品和电影的账户总额,但仅限收款人匹配 Freddie 的记录:
$ ledger bal rent food movies payee freddie
或
$ ledger bal rent food movies @freddie
ledger程序提供了许多命令行选项,掌握它们需要一些时间。但是,使用基本报告命令时不需要任何选项。
balance¶bal¶显示账户余额。
register¶reg¶显示所有交易及其累计总额。
csv¶以 CSV 格式显示交易,便于导出到其他程序。
print¶以 ledger 可读的格式打印交易。
xml¶生成 register 命令的 XML 输出。
lisp¶emacs¶生成适合 Emacs 使用的 S 表达式输出。
equity¶以交易形式打印账户余额。
prices¶打印匹配商品的价历史。
pricedb¶以 ledger 可读的格式打印匹配商品的价历史。
xact¶基于之前的记账条目生成交易。
显示 ledger 的手册页。
打印版本信息并退出。
将 FILE 作为 ledger 文件读取。
将输出重定向到文件。
指定一个选项文件。
将文件作为 Python 模块导入。
为 QIF 文件记账指定默认账户字符串。
仅显示当前日期或之前的交易。
将处理限制在日期或之后的交易。
将处理限制在日期之前的交易。
将处理限制在期间表达式内的交易(参见期间表达式)。
根据值表达式对每个期间内的记账进行排序。
仅显示已清算的记账。
以借/贷格式显示寄存器或余额。
仅显示未清算的过账。
仅显示实际过账。
仅显示实际过账,不显示自动生成的过账。
显示相关过账。
显示您的过账与预算的接近程度。
显示未预算的过账。
仅显示未预算的过账。
将余额预测到未来。
通过EXPR限制计算中使用的过账。
更改register报告中报告的价值表达式。
更改用于register和balance报告中“总计”列的值表达式。
先前未声明的账户、标签或商品将导致警告。
先前未声明的账户、标签或商品将导致错误。
对付款人以及账户、商品和标签启用严格和挑剔的检查。这仅在与--strict或--pedantic结合使用时有效。
指示 ledger 立即计算而不是延迟计算。
折叠具有多个条目的交易。
将 register 报告为单个小计。
按付款人报告小计。
在报告中包含空账户。
按周报告条目总计。
按季度报告记账总额。
按年度报告记账总额。
按星期几报告记账总额。
使用VEXPR对报告进行排序。
假设使用 132 列而非 80 列。
报告前INT条记账记录。
报告后INT条记账记录。
将输出定向到FILE分页程序。
将输出定向到标准输出,避免使用分页程序。
报告记账记录的平均值。
报告每条记账记录与平均值的偏差。
在余额报告中以百分比形式显示小计。
生成指定TAG类型的透视表。
仅显示日期和数值列,以便为绘图格式化输出。
指定绘图输出的格式。
仅显示日期和总计列,以便为绘图格式化输出。
指定绘图输出的格式。
仅显示符合EXPR中条件的记录。
更改报告中使用的基本日期格式。
设置各种报告的报告格式。
使用匿名账户和收款人打印账本记录,适用于提交错误报告。
Ledger 报告的选项影响三个独立的操作范围:全局、会话和报告。实际上这些范围之间差异很小。Ledger 3.0 包含了对 GUI 的支持,这将通过让 Ledger 实例在后台运行并在每个会话中运行多个报告来利用不同的范围。
忽略所有环境和初始化文件设置,仅使用命令行参数来控制 Ledger。适用于调试或测试与主财务数据库无关的小型日记账文件。
未记录!请贡献此功能的文档以提供帮助。如果 ledger 已使用调试选项构建,这将在运行期间提供额外数据。
显示 ledger 的手册页。
指定初始化文件的位置。默认情况下,按顺序尝试 $XDG_CONFIG_HOME、~/.config/ledger/ledgerrc、~/.ledgerrc 和 ./.ledgerrc。
显示此 Ledger 调用中生效的选项及其值和来源,例如:
$ ledger --options bal --cleared
=============================================================================== [全局范围选项] --args-only --args-only [会话范围选项] --file = A9349E4.dat --file [报告范围选项] --cleared --cleared --columns = 80 --columns --limit = cleared --cleared =============================================================================== $15.00 支出 $12.45 食品 $2.55 小费 $-15.00 负债:万事达卡 -------------------- 0
对于来源列,以‘-’或‘--’开头的值表示来源是命令行参数。如果条目以‘$’开头,则来源是环境变量。如果来源是 ?normalize,则该值由 ledger 在名为 normalize_options 的函数内部设置。
执行 ledger 脚本。
启用跟踪。整数 指定所需的跟踪级别。
打印 Ledger 执行的详细信息。
在运行时启用额外的断言检查。这会导致显著的性能下降。当与--debug CODE结合使用时,ledger 将生成内存跟踪信息。
验证每个构造的对象是否被正确析构。这仅用于调试目的。
打印版本信息并退出。
Ledger 报告的选项影响三个独立的操作范围:全局、会话和报告。实际上这些范围之间差异很小。Ledger 3.0 包含了对 GUI 的支持,这将通过让 Ledger 实例在后台运行并在每个会话中运行多个报告来利用不同的范围。
对付款人以及账户、商品和标签启用严格和挑剔的检查。这仅在与--strict或--pedantic结合使用时有效。
按天拆分跨越多天的时间日志条目的register报告。
指示 Ledger 使用欧洲标准逗号作为小数分隔符来解析账本文件,而不是通常的句点。
指示 Ledger 下载价格数据。
为此调用指定输入文件。
为日记账条目指定输入日期格式。例如,
$ ledger convert Export.csv --input-date-format "%m/%d/%Y"
将转换Export.csv文件为 ledger 格式,假设 CSV 文件中的日期格式为 12/23/2009(参见日期和时间格式代码)。
在所有账户名称前添加参数作为前缀。
$ ledger -f drewr3.dat bal --no-total --master-account HUMBUG
0 HUMBUG $ -3,804.00 资产 $ 1,396.00 支票账户 $ 30.00 业务 $ -5,200.00 储蓄账户 $ -1,000.00 权益:期初余额 $ 6,654.00 支出 $ 5,500.00 汽车 $ 20.00 书籍 $ 300.00 托管账户 $ 334.00 食品:杂货 $ 500.00 利息:抵押贷款 $ -2,030.00 收入 $ -2,000.00 工资 $ -30.00 销售 $ 180.00 负债 $ -20.00 万事达卡 $ 200.00 抵押贷款:本金
如果指定此选项,Ledger 不会展开任何别名。
先前未声明的账户、标签或商品将导致错误。
静默处理余额断言。
指定价格条目数据文件的位置。
设置价格报价的预期新鲜度,单位为整数小时。也就是说,如果任何商品的最后已知报价比此值更旧,并且正在使用--download选项,则会再次查询互联网以获取更新的价格。否则,旧价格仍被认为足够新鲜。
Ledger 通常静默接受过账中的任何账户或商品,即使您拼错了常用账户或商品。选项--strict会改变此行为。在使用--strict运行时,Ledger 将所有已清算交易视为正确,如果遇到新账户或商品(等同于拼错的商品或账户),它将发出警告,提供问题所在的文件和行号。
通常,ledger 只展开别名一次。使用此选项,ledger 会尝试递归地展开别名展开的结果,直到不再适用任何展开。
--time-colon 选项将以秒为单位的商品值显示为实际的小时和分钟。
例如,默认情况下 8100 秒会显示为 2.25,而使用 --time-colon 选项则会显示为 2:15。
设置全局值表达式注解。
Ledger 报告的选项影响三个独立的操作范围:全局、会话和报告。实际上这些范围之间差异很小。Ledger 3.0 包含了对 GUI 的支持,这将通过让 Ledger 实例在后台运行并在每个会话中运行多个报告来利用不同的范围。
设置账户名称在无法适应 account-width 时的最小缩写长度。如果 INT 为零,则账户名称将从右侧截断。如果 INT 大于 account-width,则账户将从左侧截断,不会为了适应所需宽度而缩短账户名称。
在所有报告的账户前添加 STR。也就是说,选项 '--account Personal' 会在余额报告或登记报告中每个账户的开头添加 'Personal:'。
将 register 报告中账户列的宽度设置为 INT 个字符。
仅报告真实交易,忽略所有自动或虚拟交易。
仅显示未预算的过账。
如果指定了周期表达式,则使用其开始时间作为间隔的起点(参见 周期表达式)。例如,对于周期表达式 "weekly from 2009/01/10",将使用 "2009/01/10" 的开始时间作为每周间隔的起点。覆盖 '--start-of-week INT'。
将给定的值表达式应用于过账金额(参见 值表达式)。使用 --amount EXPR 可以对过账进行任意转换。
在登记报告中仅打印过账的日期和金额。适用于图表和电子表格应用。
设置 register 报告中金额列的字符宽度。
匿名化注册表输出,主要用于提交错误报告。
在使用 convert 命令从 CSV 文件生成账本交易时,自动匹配账本日记中的账户。
显示所有计算的辅助日期(参见 有效日期)。
打印交易数量的平均值而非运行总计。
在余额报告中报告每种商品的购买平均价格。
指定用于 balance 报告的格式(参见 格式字符串)。默认值为:
"%(justify(scrub(display_total), 20, -1, true, color))" " %(!options.flat ? depth_spacer : \"\")" "%-(ansify_if(partial_account(options.flat), blue if color))\n%/" "%$1\n%/" "--------------------\n"
将可转换商品归约到转换的底部,例如以秒为单位显示时间。这也适用于自定义商品转换(参见商品等价关系)。
在所有过账中报告成本基础。
指定所有计算的起始日期。该日期之前的交易将被忽略。
如果给定的值表达式为真,则以粗体打印整行(参见值表达式)。
$ ledger reg Expenses --begin Dec --bold-if "amount>100"
列出自 12 月初以来的所有交易,并以粗体显示金额大于 100 美元的任何过账。
仅显示预算项目。在登记报告中,这会显示预算中的交易;在余额报告中,这会显示预算中的账户(参见预算与预测)。
指定用于budget报告的格式(参见格式字符串)。默认值为:
"%(justify(scrub(get_at(display_total, 0)), 12, -1, true, color))" " %(justify(-scrub(get_at(display_total, 1)), 12, " " 12 + 1 + 12, true, color))" " %(justify(scrub(get_at(display_total, 1) + " " get_at(display_total, 0)), 12, " " 12 + 1 + 12 + 1 + 12, true, color))" " %(ansify_if(" " justify((get_at(display_total, 1) ? " " (100% * quantity(scrub(get_at(display_total, 0)))) / " " -quantity(scrub(get_at(display_total, 1))) : 0), " " 5, -1, true, false)," " magenta if (color and get_at(display_total, 1) and " " (abs(quantity(scrub(get_at(display_total, 0))) / " " quantity(scrub(get_at(display_total, 1)))) >= 1))))" " %(!options.flat ? depth_spacer : \"\")" "%-(ansify_if(partial_account(options.flat), blue if color))\n" "%/%$1 %$2 %$3 %$4\n%/" "%(prepend_width ? \" \" * int(prepend_width) : \"\")" "------------ ------------ ------------ -----\n"按收款人对登记报告进行分组。
仅考虑已清算的交易用于显示和计算。
指定用于cleared报告的格式(参见格式字符串)。默认值为:
"%(justify(scrub(get_at(total_expr, 0)), 16, 16 + prepend_width, " " true, color)) %(justify(scrub(get_at(total_expr, 1)), 18, " " 36 + prepend_width, true, color))" " %(latest_cleared ? format_date(latest_cleared) : \" \")" " %(!options.flat ? depth_spacer : \"\")" "%-(ansify_if(partial_account(options.flat), blue if color))\n%/" "%$1 %$2 %$3\n%/" "%(prepend_width ? \" \" * prepend_width : \"\")" "---------------- ---------------- ---------\n"
默认情况下,ledger 会打印账户树中的所有账户。使用--collapse时,仅打印指定的顶级账户。
仅在账户余额为零时折叠账户显示。
如果终端支持,则使用颜色。
以字符为单位指定register报告的宽度。
当附加到commodities、accounts或payees命令时,直接账本报告项目数量。
指定csv报告使用的格式(参见格式字符串)。默认值为:
"%(quoted(date))," "%(quoted(code))," "%(quoted(payee))," "%(quoted(display_account))," "%(quoted(commodity(scrub(display_amount))))," "%(quoted(quantity(scrub(display_amount))))," "%(quoted(cleared ? \"*\" : (pending ? \"!\" : \"\")))," "%(quoted(join(note | xact.note)))\n"
‘--limit "date <= today"’的简写形式。
‘--period "daily"’的简写形式。
使用EXPR转换交易的日期。
指定账本用于读取和打印日期的格式(参见日期和时间格式代码)。
指定register报告中日期列的宽度(以字符为单位)。
指定账本用于打印日期时间的格式。
以借/贷格式显示登记簿或余额。如果将--dc与register(reg)或balance(bal)命令一起使用,现在将获得额外的列。登记簿从这样:
12-Mar-10 雇主 资产:现金 $100 $100 收入:雇主 $-100 0 12-Mar-10 KFC 支出:食品 $20 $20 资产:现金 $-20 0 12-Mar-10 KFC - 返利 资产:现金 $5 $5 支出:食品 $-5 0 12-Mar-10 KFC - 食品 & 返利.. 支出:食品 $20 $20 支出:食品 $-5 $15 资产:现金 $-15 0
变为这样:
12-Mar-10 雇主 资产:现金 $100 0 $100 收入:雇主 0 $100 0 12-Mar-10 KFC 支出:食品 $20 0 $20 资产:现金 0 $20 0 12-Mar-10 KFC - 返利 资产:现金 $5 0 $5 支出:食品 0 $5 0 12-Mar-10 KFC - 食品 &.. 支出:食品 $20 0 $20 支出:食品 0 $5 $15 资产:现金 0 $15 0
其中第一列为借方,第二列为贷方,第三列为运行总计。只有运行总计可能包含负值。
对于没有--dc的余额报告:
$70 资产:现金 $30 支出:食品 $-100 收入:雇主 -------------------- 0
而使用--dc后变为:
$105 $35 $70 资产:现金 $40 $10 $30 支出:食品 0 $100 $-100 收入:雇主 -------------------------------------------- $145 $145 0
限制余额和登记簿报告中显示的账户深度。任何深度更大的账户都会在指定级别折叠到其父账户中。例如,使用‘--depth 2’时,账户‘Expenses:Entertainment’将被折叠到‘Expenses:Entertainment:Dining’中显示。重要的是,这是一个显示谓词,意味着它只影响显示,不影响总计计算。
报告每个过账与平均值的偏差。仅在登记簿和价格报告中有意义。
仅显示满足表达式EXPR的行。
对显示金额应用转换。此操作在计算完成后进行。
对显示总额应用转换。此操作在计算完成后进行。
按星期几对交易进行分组。
$ ledger reg Expenses --dow --collapse
将打印每周各天的所有支出总额。
在报告和平均值计算中包含空账户。
指定交易被纳入报告的截止日期。在此日期或之后的所有交易将被忽略。
与equity命令相关(参见equity命令)。以寄存器报告的形式给出当前账户余额。
按该期间内发生的第一笔和最后一笔过账日期报告期间的开始和结束。
以给定的商品显示数值。如果给出多个商品,列出的商品中的数值将保持不变,其他商品将显示为它们可以转换到的第一个列出的商品。
$ ledger balance assets
100 EUR 100 PHP 100 USD 资产 100 EUR EUR 银行 100 PHP PHP 银行 100 USD USD 银行 -------------------- 100 EUR 100 PHP 100 USD
$ ledger balance assets --exchange PHP
11382 PHP 资产 5801 PHP EUR 银行 100 PHP PHP 银行 5481 PHP USD 银行 -------------------- 11382 PHP
$ ledger balance assets --exchange "PHP, EUR"
100 EUR 5581 PHP 资产 100 EUR EUR 银行 100 PHP PHP 银行 5481 PHP USD 银行 -------------------- 100 EUR 5581 PHP
使用最新的可用价格。语法-X 商品 1:商品 2使用最新可用价格以商品 2为单位显示商品 1的值,但不会自动将任何其他商品转换为商品 2。可以在单个命令行上使用多个-X参数(如-X 商品 1:商品 2 -X 商品 3:商品 2),这对于需要以商品 2为单位报告许多价格但只有少数应以该方式显示的情况特别有用。
强制在余额报告中使用账户的全名。余额报告将不使用缩进树形结构。
即使 TTY 不支持,也输出 TTY 颜色代码。对于未正确通告其功能的 TTY 很有用。
强制 Ledger 对其输出进行分页。
当VEXPR为真时继续预测。
最多预测未来INT年。
使用给定的格式字符串打印输出。
使用最新可用价格报告收益。
在通常不希望包含自动生成条目的情况下,将自动生成的条目(如来自自动化交易的条目)包含在报告中。
在register报告中按组对交易进行分组。EXPR可以是任何表达式,但最常见的是payee(收款方)或commodity(商品)。tags()函数在此处也很有用。
设置分组报告各部分标题的格式。仅在使用--group-by EXPR的 register 报告时有效。
$ ledger reg Expenses --group-by "payee" --group-title-format "------------------------ %-20(value) ---------------------\n"
------------------------ 7-Eleven --------------------- 2011/08/13 7-Eleven 支出:汽车:杂项 $ 5.80 $ 5.80 ------------------------ AAA 会费 --------------------- 2011/06/02 AAA 会费 支出:汽车:杂项 $ 215.00 $ 215.00 ------------------------ ABC 拖车服务 --------------------- 2011/03/17 ABC 拖车服务.. 支出:汽车:爱好 $ 48.20 $ 48.20 ...
根据ALGO参数指定的哈希算法(目前仅支持sha512),在Hash元数据值中记录每个交易的链式哈希。要使用此功能,请在某些交易中显式记录Hash元数据;这些将与内部计算的哈希进行核对,如果不匹配,则会报告错误。您也可以只写入Hash的前缀,这样虽然不够详细,但仍能提供相当好的保证。
支持的算法有:
sha512使用 SHA512 哈希算法。
sha512_half与 SHA512 相同,但仅记录前 256 位。
类似于余额断言(确保先前过账金额正确),这些Hash标签确保所有先前的日记账条目(按解析顺序)未被更改(或至少它们的组合哈希与当前出现在日记账中的 Hash 标签匹配)。
这些哈希依赖于先前交易的哈希,因此最终交易的单个哈希值足以保证其之前整个历史记录的结构完整性。
哈希依赖的其他细节来自交易中每个过账的以下信息:
此外,以下交易本身的细节也会被哈希:
此列表还意味着,帖子或交易中的注释更改,或交易内帖子的排序更改,不会影响哈希值。然而,交易的排序确实重要,这与余额断言的情况相同。
打印前 INT 个条目。--tail INT 的相反操作。
按商品获取时的价值计价。
立即而非延迟地执行计算。
在计算中使用 Expected 金额。如果您知道交易应有的金额,但实际交易金额有误,可以使用元数据指定预期金额:
2012-03-12 工资收入 $-990 ; Expected:: $-1000.00 支票账户
然后使用命令 ledger reg --inject=Expected Income 会将交易视为“预期值”为实际值。
反转所有报告值的符号。
只有满足 EXPR 的交易才会被纳入计算和显示。
指定 lisp 输出中的日期格式。默认情况下,日期使用 Emacs Lisp 时间格式(整数列表)进行格式化。此选项允许您使用不同的格式:
示例:
$ ledger -f sample.dat --lisp-date-format seconds lisp
$ ledger -f sample.dat --lisp-date-format '%Y-%m-%d' lisp
在余额报告中报告每种商品的购买日期。
在余额报告中报告附加到每种商品的标签。
在余额报告中报告每种商品的购买价格。
在余额报告中报告每种商品的购买日期和价格。
保留商品的唯一性,使其在报告期间不会合并,同时不打印批次注释。
对所有商品使用最新的市场价值。
在登记报告中,使用给定的标签值作为交易的前缀。
指定用于--meta 标签选项的元数据列的宽度。
‘--period "monthly"’的同义词。
别名会被完全忽略。
抑制任何彩色 TTY 输出。
将输出定向到标准输出,避免使用分页程序。
阻止 Ledger 显示<重估值>过账。此选项与--exchange或--market选项结合使用很有用。
不输出‘<调整>’过账。请注意,这将导致运行总计经常无法相加!其主要用途是用于--amount-data (-j)和--total-data (-J)报告。
抑制组标题的输出。
在余额报告中抑制打印最终总计行。
定义当前日期,以防您想要使用--current在过去或未来进行计算。
这是一个过账谓词,在执行某些转换(如定期收集)后应用。
将 ledger 的输出重定向到文件中定义的文件。
将输出定向到FILE分页程序。
设置用于格式化收款人的值表达式。在register报告中,这可以防止第二个条目为每笔交易显示日期和收款人。
将登记报告中用于收款人的列数设置为整数。
仅使用标记为待定的过账。
计算余额报告中每个账户的百分比值。仅适用于具有单一商品的账户。
定义一个时间段表达式,设置要记账的交易时间范围。对于register报告,仅显示满足时间段表达式的交易。对于balance报告,仅这些交易会被计入最终余额。
围绕给定的TAG生成余额透视报告。例如,如果您拥有多辆汽车并在‘Expenses:Auto:Fuel’中跟踪每笔加油支出,并使用标签标识每笔加油是为哪辆车购买的‘; Car: Prius’,那么命令:
$ ledger bal Fuel --pivot "Car" --period "this year"
$ 3491.26 Car $ 1084.22 M3:Expenses:Auto:Fuel $ 149.65 MG V11:Expenses:Auto:Fuel $ 621.89 Prius:Expenses:Auto:Fuel $ 1635.50 Sienna:Expenses:Auto:Fuel $ 42.69 Expenses:Auto:Fuel -------------------- $ 3533.95
参见元数据值。
定义金额数据图的输出格式。参见使用 Gnuplot 可视化。
定义总计数据图的输出格式。参见使用 Gnuplot 可视化。
在输出的每一行前添加STR。
在输出的每一行开头保留INT个空格。
使用商品购买价格进行计算。
设置历史价格文件的预期格式。
设置prices报告的格式。
显示所有计算的主要日期(参见有效日期)。
报告商品总计(此为默认设置)。
‘--period "quarterly"’的同义词。
在print报告中,使用用户在其数据文件中指定的完全相同语法显示交易。不进行任何整理或解释。这对于小的清理工作很有用,比如仅对齐金额。
仅使用实际交易进行记账,忽略虚拟和自动交易。
定义register报告的输出格式。
在register报告中显示相关账户。这是交易的另一方。
显示交易中的所有过账,类似于--related,但显示每笔交易的两个方面。
通过在手动报告中插入<Revalued>过账来报告价值差异。在使用--exchange或--market选项时隐含此功能。
仅显示<Revalued>过账。
将重估过账的总和显示为运行总计,用于在损益报告中显示未实现资本。
在使用convert命令从 CSV 文件生成账本交易时,添加 CSV、Imported 和 UUID 元数据。
为generate命令设置随机种子为INT。作为开发测试的一部分使用。
根据给定的排序值表达式对register报告进行排序。
对所有账户和商品进行排序。
使用给定的值表达式对交易内的过账进行排序。
告诉 ledger 使用特定的星期几作为其“每周”摘要的开始。‘--start-of-week=1’指定星期一为一周的开始。可被‘--align-intervals’覆盖。
将register报告中的所有交易折叠为单个带小计的交易。
仅报告最后INT个条目。仅在register报告中有用。
在余额报告中添加两列,显示时间日志条目的最早签到和最晚签出时间。
定义一个用于计算报告中总计的值表达式。
仅显示日期和总计,以便为绘图格式化输出。
设置 register 报告中总计字段的宽度。
指示当列内容超过其宽度时应如何进行截断。有效参数为‘leading’(前导)、‘middle’(中间)和‘trailing’(尾随)。默认方式比这三种都更智能,因为它考虑了账户名称中的子名称(该样式称为“缩写”)。
仅显示未预算的过账。
在计算和报告中仅使用未清算交易。
在资产负债报告中显示生成的未实现损益账户。
允许用户指定用于未实现收益的账户名称。默认为‘"Equity:Unrealized Gains"’。通常在初始化文件中设置以更改默认值。
允许用户指定用于未实现损失的账户名称。默认为‘"Equity:Unrealized Losses"’。通常在初始化文件中设置以更改默认值。
执行所有计算时不进行舍入,并以全精度显示结果。
与tags命令结合使用时,显示每个标签使用的值。
‘--period "weekly"’的同义词。
让登记报告使用 132 列而不是 80 列(默认值)。等同于‘--columns "132"’。
‘--period "yearly"’的同义词。
这些是最基本的命令选项。用户很可能希望通过环境变量设置它们(参见环境变量),而不是使用实际的命令行选项:
显示 ledger 的手册页。
打印当前版本的 ledger 并退出。这对于发送错误报告很有用,可以让作者知道您正在使用哪个版本的 ledger。
将FILE作为账本文件读取。FILE可以是‘-’,这是‘/dev/stdin’的同义词。此命令可以多次使用。通常,会设置环境变量LEDGER_FILE,而不是使用此命令行选项。
将任何命令的输出重定向到FILE。默认情况下,所有输出都发送到标准输出。
使FILE在任何其他账本文件之前被 ledger 读取。此文件可能不包含任何过账,但可能包含选项设置。要在初始化文件中指定选项,请使用与命令行相同的语法,但将每个选项放在单独的行上。这是一个示例初始化文件:
--price-db ~/finance/.pricedb --wide ; ~/.ledgerrc 在此结束
命令行或环境中的选项设置始终优先于初始化文件中的设置。
指定 QIF 文件过账默认关联的账户。
这些选项以除使用正则表达式之外的方式更改哪些过账会影响报告的结果:
仅显示在当前日期或之前发生的交易。
将报告限制在DATE或之后的交易。只有该日期之后的交易才会被计算,这意味着余额报告中的运行总计将始终从第一个匹配交易开始为零。(注意:这与使用--display EXPR来限制显示内容不同)。
限制报告,使得DATE或之后的交易不被考虑。
将报告期间设置为STR。这将分别对每个期间内所有匹配的交易进行小计,便于查看每周、每月、每季度等的过账总计。期间字符串甚至可以使用简单术语如‘last June’(去年六月)或‘next month’(下个月)来指定报告范围的开始和结束。有关期间表达式的更多详情,请参见期间表达式。
使用值表达式EXPR对每个报告期间内的过账进行排序。这在报告月度支出时最为有用,以便在每个月的顶部查看最高的支出类别:
$ ledger -M --period-sort total reg ^Expenses
仅显示其交易已被标记为“已清算”的过账(通过在日期右侧放置星号)。
仅显示其交易未被标记为“已清算”的过账(即,如果日期右侧没有星号)。
仅显示实际过账,而非虚拟过账。(虚拟过账通过在账户名称周围加上括号或方括号来表示;更多信息请参见虚拟过账)。
仅显示实际过账,而非由自动化交易创建的过账。
显示与原本匹配筛选条件的过账相关的过账。在登记报告中,这显示资金去向或来源账户。在余额报告中,它显示受具有相关过账的交易影响的所有账户。例如,如果文件中有此交易:
2004/03/20 Safeway 支出:食品 $65.00 支出:现金 $20.00 资产:支票账户 $-85.00
而登记命令为:
$ ledger -f safeway.dat -r register food
将打印以下内容,显示与匹配过账相关的过账:
04-Mar-20 Safeway 支出:现金 $20.00 $20.00 资产:支票账户 $-85.00 $-65.00
用于显示您的过账与预算的接近程度。--add-budget还会显示未预算的过账,而--unbudgeted仅显示这些。--forecast VEXPR是一个相关选项,可将您的预算投射到未来,显示它将如何影响未来余额。请参见预算与预测。
限制哪些过账参与报告的计算。
更改用于计算register报告中“值”列的值表达式,balance报告中用于计算账户总计的金额,以及equity报告中打印的值。请参见值表达式。
设置用于register和balance报告中“总计”列的值表达式。
这些选项仅影响输出,但不影响用于创建输出的记账条目:
使register报告中包含多个记账条目的交易折叠为单个、小计的交易。
将register报告中的所有交易折叠为单个带小计的交易。
按付款人报告小计。
在balance报告中包含即使是空的账户。
按周报告记账条目总计。周开始于包含该记账条目的月份开始的任意一天。要设置特定的开始日期,请使用周期字符串,例如‘weekly from DATE’。
按月报告记账条目总计。
按年报告记账条目总计。对于更复杂的周期,请使用--period。
上述选项说明。
报告一周中每天的记账条目总计。这是查看周末支出是否多于工作日的简便方法。
通过比较使用值表达式VEXPR确定的值来对报告进行排序。例如,在balance报告中使用‘-S "-abs(total)"’将按总值的绝对值从大到小对账户余额进行排序。有关如何使用值表达式的更多信息,请参见值表达式。
围绕提供的TAG生成数据透视表。这需要使用带值的标签元数据。
使默认的register报告假设为 132 列而不是 80 列。
仅打印前INT笔交易。这与使用命令行工具head不同,后者会限制为前INT个记账条目。--tail INT仅输出最后INT笔交易。这两个选项可以同时使用。如果给出负数,它将反转标志的含义(例如,不是打印前五笔交易,而是打印除前五笔之外的所有交易)。
告诉 Ledger 将其输出传递给给定的FILE分页程序;当输出特别长时非常有用。可以通过设置LEDGER_PAGER环境变量将此行为设为默认。
告诉 Ledger不要将其输出传递给分页程序;当默认设置了分页程序时很有用。
报告记账记录的平均值。
报告每个记账条目与平均值的偏差。这仅在register和prices报告中有意义。
在balance报告中以父账户的百分比显示账户小计。
更改register报告,使其仅打印日期和价值列,且后者不带商品。这仅在报告使用单一商品时有意义。这些数据可以输入到其他程序中,用于绘制日期、分析等。
更改register报告,使其仅打印日期和总计列,不带商品。
限制哪些过账或账户实际在报告中显示。它们可能仍会被计算,并成为寄存器报告运行总额的一部分,但不会显示出来。这对于查看上个月的支票过账非常有用,同时运行余额包含所有过账值:
$ ledger -d "d>=[上个月]" reg checking
此命令的输出与以下命令的输出有很大不同,后者的运行总额仅包含从上个月开始的过账:
$ ledger -p "上个月" reg checking
哪种更有用取决于您想要了解什么:报告范围内的总金额(使用--period PERIOD_EXPRESSION (-p)),或者仅仅是限制在报告范围内的显示(使用--display EXPR (-d))。
更改报告使用的基本日期格式。默认使用类似‘2004/08/01’的日期,这代表默认日期格式%Y/%m/%d。要更改日期的通用显示方式,最简单的方法是在 Ledger 初始化文件(或LEDGER_INIT引用的文件)中添加--date-format DATE_FORMAT。
设置 Ledger 即将生成的任何报告的报表格式。请参阅格式字符串。每种报告类型还有特定的格式命令:
定义balance报告的输出格式。默认值(在report.h中定义)为:
"%(ansify_if( justify(scrub(display_total), 20, 20 + int(prepend_width), true, color), bold if should_bold)) %(!options.flat ? depth_spacer : \"\") %-(ansify_if( ansify_if(partial_account(options.flat), blue if color), bold if should_bold))\n%/ %$1\n%/ %(prepend_width ? \" \" * int(prepend_width) : \"\") --------------------\n"
定义已清算报告的格式。默认值为:
"%(justify(scrub(get_at(display_total, 0)), 16, 16 + int(prepend_width), true, color)) %(justify(scrub(get_at(display_total, 1)), 18, 36 + int(prepend_width), true, color)) %(latest_cleared ? format_date(latest_cleared) : \" \") %(!options.flat ? depth_spacer : \"\") %-(ansify_if(partial_account(options.flat), blue if color))\n%/ %$1 %$2 %$3\n%/ %(prepend_width ? \" \" * int(prepend_width) : \"\") ---------------- ---------------- ---------\n"
定义register报告的输出格式。默认值(在report.h中定义)为:
"%(ansify_if( ansify_if(justify(format_date(date), int(date_width)), green if color and date > today), bold if should_bold)) %(ansify_if( ansify_if(justify(truncated(payee, int(payee_width)), int(payee_width)), bold if color and !cleared and actual), bold if should_bold)) %(ansify_if( ansify_if(justify(truncated(display_account, int(account_width), int(abbrev_len)), int(account_width)), blue if color), bold if should_bold)) %(ansify_if( justify(scrub(display_amount), int(amount_width), 3 + int(meta_width) + int(date_width) + int(payee_width) + int(account_width) + int(amount_width) + int(prepend_width), true, color), bold if should_bold)) %(ansify_if( justify(scrub(display_total), int(total_width), 4 + int(meta_width) + int(date_width) + int(payee_width) + int(account_width) + int(amount_width) + int(total_width) + int(prepend_width), true, color), bold if should_bold))\n%/ %(justify(\" \", int(date_width))) %(ansify_if( justify(truncated(has_tag(\"Payee\") ? payee : \" \", int(payee_width)), int(payee_width)), bold if should_bold)) %$3 %$4 %$5\n"
设置 csv 报告的格式。默认值为:
"%(quoted(date)), %(quoted(code)), %(quoted(payee)), %(quoted(display_account)), %(quoted(commodity(scrub(display_amount)))), %(quoted(quantity(scrub(display_amount)))), %(quoted(cleared ? \"*\" : (pending ? \"!\" : \"\"))), %(quoted(join(note | xact.note)))\n"
设置金额图表的格式,使用 --amount-data (-j) 选项。默认值为:
"%(format_date(date, \"%Y-%m-%d\")) %(quantity(scrub(display_amount)))\n"
设置总额图表的格式,使用 --total-data (-J) 选项。默认值为:
"%(format_date(date, \"%Y-%m-%d\")) %(quantity(scrub(display_total)))\n"
设置历史价格文件的预期格式。默认值为:
"P %(datetime) %(display_account) %(scrub(display_amount))\n"
设置 prices 报告的格式。默认值为:
"%(date) %-8(display_account) %(justify(scrub(display_amount), 12, 2 + 9 + 8 + 12, true, color))\n"
这些选项会影响商品值的显示方式:
设置用于记录下载的商品价格的文件。该文件总是在启动时被读取,以确定历史价格。其他设置可以手动放置在此文件中,例如防止下载特定商品的报价。这是通过添加如下行来完成的:
; 不要下载美元报价,或时间日志值 N $ N h
注意:Ledger 从不将输出写入文件。您负责更新价格数据库文件。最好的方法是让您的价格下载脚本维护此文件。
可以通过告诉 Ledger 使用您定义的 --pricedb-format FORMAT_STRING 来更改文件的格式。
设置价格报价的预期新鲜度,单位为整数小时。也就是说,如果任何商品的最后已知报价比此值更旧,并且正在使用--download选项,则会再次查询互联网以获取更新的价格。否则,旧价格仍被认为足够新鲜。
通过运行名为getquote的脚本并期望该脚本返回 ledger 可理解的值,实现按需自动下载报价。发行版中提供了一个用 Perl 实现的getquote脚本示例实现。下载的报价价格随后会附加到价格数据库中,通常使用环境变量LEDGER_PRICE_DB指定。
Ledger 有多种不同的方式来报告其显示的总数。最灵活的调整方法是使用值表达式,以及--amount EXPR (-t)和--total VEXPR (-T)选项。不过,还有几种"默认"报告,可以满足大多数用户的基本报告需求:
报告商品总计(此为默认设置)。
报告所有过账的成本基础。
使用商品的最后已知值计算最终价值。
报告报告中所有具有价格历史的商品的净收益/损失。
通常您会更关注以您偏好的货币计算的整个持有资产的价值。知道您持有 10,000 股 PENNY 可能不错,但您更关心的是这价值是$1000.00 还是$10,000.00。然而,商品的当日价值对不同的人可能意味着不同的事情,这取决于涉及的账户、商品、交易性质等。
当您指定--market (-V)或--exchange COMMODITY (-X)时,您是在请求将部分或全部商品按今天(或无论--now DATE设置为什么日期)进行估值。但这种估值意味着什么?这个含义由VALUE元数据属性的存在决定,其内容是一个用于计算该值的表达式。
如果未指定VALUE属性,则假定每个过账都有一个默认值,就像您指定了如下的全局自动化交易:
= expr true ; VALUE:: market(amount, date, exchange)
此定义模拟了--market (-V)和--exchange COMMODITY (-X)的当前行为(对于'-X',请求的商品通过上面的字符串'exchange'传递)。
许多人想要做的一件事是在某个日期之后将旧欧洲货币的估值固定为欧元:
= expr commodity == "DM" ; VALUE:: date < [Jun 2008] ? market(amount, date, exchange) : 1.44 EUR
这表示:如果--now DATE是某个旧日期,则使用当时的市场价格;但如果--now DATE晚于 2008 年 6 月,则使用固定价格将德国马克转换为欧元。
或者,由于费用中的商品不能有不同的未来价值,从不重新估值这些商品:
= /^Expenses:/ ; VALUE:: market(amount, post.date, exchange)
这表示未来估值与过账时的估值相同。post.date等于过账的日期,而仅'date'是--now DATE的值(默认为今天)。
或者,也可以根据特定时间段内的报销费率来评估里程价值:
= expr commodity == "miles" and date >= [2007] and date < [2008] ; VALUE:: market($1.05, date, exchange)
在这种情况下,2007 年行驶的里程将始终按每英里 1.05 美元计价。如果您使用‘-X EUR’明确要求所有金额以欧元显示,Ledger 将通过适当的方式将 1.05 美元转换为欧元。
请注意,您可以通过使用特定的元数据覆盖这些通用默认值,为特定的过账或交易设置特定的估值表达式:
2010-12-26 示例 支出:食品 $20 ; 仅为示例,无论用户使用-V 或-X 要求何种货币,始终将这 20 美元估值为 30 德国马克 ; VALUE:: 30 DM 资产:现金
此示例表明,您的价值表达式应尽可能符号化,使用诸如'amount'和'date'之类的术语,而不是具体的金额和日期。此外,您应将金额传递给'market'函数,以便在用户要求特定货币时可以进一步重新估值。
或者,如果更适合您的会计需求,您可以减少符号化程度,这样在使用‘-X EUR’时,大多数内容都可以以欧元报告,但某些账户或过账应始终以另一种货币计价。例如:
= /^Assets:Brokerage:CAD$/
; Always report the value of commodities in this account in
; terms of present day dollars, despite what was asked for
; on the command-line VALUE:: market(amount, date, ‘$’)
Ledger 目前无法处理诸如先进先出(FIFO)和后进先出(LIFO)之类的方法。
如果您指定一个未修饰的商品名称,如 AAPL,它将与自身平衡。如果未显示--lots,那么它将看起来与任何 AAPL 批次平衡。
如果您指定一个修饰过的商品,如 AAPL {$10.00},它也将与自身平衡,并且在未指定--lots时与任何 AAPL 平衡。但如果您确实指定了--lot-prices,例如,那么它将与该特定价格的 AAPL 平衡。
通常,当您使用--exchange COMMODITY (-X)要求以特定商品报告金额时,Ledger 使用以下值:
register报告,使用该商品在被报告过账日期的价值,并在末尾添加一个‘<重新估值>’过账(如果今天的价值与最后一次过账的价值不同)。balance报告,使用该商品截至今天的价值。您现在可以指定--historical (-H),要求对所有金额的估值相对于遇到该金额的日期进行。
您现在还可以将--exchange COMMODITY (-X)(和--historical (-H))与--basis (-B)和--price (-I)结合使用,以查看仅基于您的成本基础或批次价格的估值报告。
最后,有时您可能希望仅以一种商品(或某个子集)来报告另一种商品。在这种情况下,您可以使用语法 --exchange 商品 1:商品 2 来请求 ledger 始终以 商品 2 为单位显示 商品 1,但您不希望其他商品在没有额外 --exchange 选项的情况下自动以 商品 2 为单位显示。例如,如果您希望以美元报告欧元和比特币,但其他所有商品不转换为美元报告,您可以使用:--exchange EUR:USD --exchange BTC:USD。
如果选项具有长名称,则每个 ledger 选项都可以使用环境变量进行设置。例如,设置环境变量 ‘LEDGER_DATE_FORMAT="%d.%m.%Y"’ 的效果与在命令行中指定 ‘--date-format '%d.%m.%Y'’ 相同。但是,命令行上的选项始终优先于环境变量设置。
请注意,您还可以通过将选项设置放入文件 ~/.ledgerrc 中来永久指定选项值,每行一个选项,例如:
--pager /bin/cat --date-format %d.%m.%Y
期间表达式表示一个时间跨度、报告间隔或两者兼有。Ledger 的结束日期始终是排他的,可以想象日期后面跟着 00:00:00 时间。它们是时间点,而不是完整的天数。完整语法为:
[间隔] [开始] [结束]
可选的 间隔 部分可以是以下任意一项:
每天 每周 每月 每季度 每年 每 N 天 # N 为任意整数 每 N 周 每 N 月 每 N 季度 每 N 年 每日 每周 双周 每月 双月 每季度 每年
在间隔之后,可以指定开始时间、结束时间、两者或都不指定。至于开始时间,可以是以下之一:
从 <规范> 起 自 <规范> 起
结束时间可以是以下之一:
至 <规范> 直到 <规范>
其中 规范 可以是以下任意一项:
2004 2004/10 2004/10/1 10/1 十月 本周 # 或天、月、季度、年 下周 上周
如果跨越单个期间,可以同时给出开始和结束。在这种情况下,只需单独使用 规范。例如,期间 ‘十月’ 将涵盖十月的所有天数。可能的形式有:
<规范> 在 <规范> 中
间隔从周的开始、月的第一天、季度或年的第一天开始。这可以通过指定 --align-intervals 来覆盖,该选项将改为使用指定的开始时间。
以下是一些期间表达式的示例:
2004 年每月 从十月起每周 从上月起每周 从九月到十月 从 10/1 到 10/5 直到 2005 年每月 从 2005/04/06 起每月 从四月到十一月 去年十月 每周 去年八月
日期表达式可用于多种场景,例如与--display(-d)选项一起使用以按日期筛选交易,或在方括号内指定相对日期。日期表达式支持丰富的关键词集,用于指定绝对日期和相对日期。
您可以使用各种时间单位指定相对于当前日期的日期:
N 天前今天之前的特定天数(例如,3 天前)。
N 天后今天之后的特定天数(例如,60 天后)。
N 周前/后今天之前或之后的特定周数。
N 月前/后今天之前或之后的特定月数。
N 季度前/后今天之前或之后的特定季度数。
N 年前/后相对于今天的特定年数之前或之后。
您可以使用 this(本)、last(上)和 next(下)来指代时间段:
this day/week/month/quarter/year当天、本周、本月、本季度或本年。
last day/week/month/quarter/year前一天、上一周、上一月、上一季度或上一年。
next day/week/month/quarter/year即将到来的一天、一周、一月、一季度或一年。
日期表达式通常用在过滤表达式的方括号 [...] 内。以下是一些示例:
# 显示本月的交易 $ ledger -d "d>[this month]" register checking # 显示过去 60 天的交易 $ ledger -d "d>[60 days ago]" register # 显示从现在起 30 天内的交易 $ ledger -d "d<[30 days hence]" register # 显示上一季度的交易 $ ledger -d "d>=[last quarter] and d<[this quarter]" register
日期表达式也可以与 --begin 和 --end 选项一起使用:
# 从 90 天前到今天的交易 $ ledger --begin "[90 days ago]" --end "[today]" register # 预测未来 6 个月 $ ledger --forecast "d<[6 months hence]" register
制定预算可以让您更密切地关注收入和支出,通过报告实际财务活动与预期的差距。
要开始制定预算,请将一些周期性交易(参见周期性交易)放在账本文件的顶部。周期性交易与常规交易几乎相同,不同之处在于它以波浪号开头,并用周期表达式代替收款人。例如:
~ Monthly Expenses:Rent $500.00 Expenses:Food $450.00 Expenses:Auto:Gas $120.00 Expenses:Insurance $150.00 Expenses:Phone $125.00 Expenses:Utilities $100.00 Expenses:Movies $50.00 Expenses $200.00 ; 所有其他支出 Assets ~ Yearly Expenses:Auto:Repair $500.00 Assets
这两个周期性交易给出了通常的月度支出,以及一个典型的年度支出。要了解任何类别的平均月度支出,请使用如下命令:
$ ledger -p "this year" --monthly --average register ^expenses
报告的总数是每个账户当年的平均值。
一旦定义了这些周期性交易,创建预算报告就像在命令行中添加 --budget 一样简单。例如,典型的月度支出报告将是:
$ ledger --monthly register ^expenses
要查看与预算平衡的相同报告,请使用:
$ ledger --budget --monthly register ^expenses
预算报告仅包含预算中出现的账户。要查看所有与预算平衡的支出,请使用--add-budget。您甚至可以使用--unbudgeted仅查看未预算的支出:
$ ledger --unbudgeted --monthly register ^expenses
您也可以将这些标志与balance命令一起使用。
有时了解未来的财务状况很有用,例如确定账户何时会归零。Ledger 使用与预算编制相同的周期性交易,使这一操作变得简单。可以通过以下方式生成示例预测报告:
$ ledger --file drewr3.dat --forecast "T>{\$-500.00}" register ^assets ^liabilities此报告会持续输出记账条目,直到运行总额超过$-500.00。始终会显示最后一个记账条目,以告知您之后的总金额。
预测也可以与balance报告一起使用,但仅按日期进行,而不是针对运行总额:
$ ledger --forecast "d<[2010]" bal ^assets ^liabilities
Ledger 直接支持“时间日志”条目,其格式如下:
i 2013/03/28 22:13:00 ACCOUNT[ PAYEE] o 2013/03/29 03:39:00
这记录了对给定账户的签到和签出。如果您愿意,可以同时签到多个账户,并且它们可以跨越多天(使用--day-break在报告中拆分它们)。签到和签出之间的秒数将累计为该账户的时间。如果签出使用大写字母'O',则该交易标记为“已清算”。您可以使用可选的 PAYEE 来表示您喜欢的任何含义。
现在,有几种生成此信息的方法。您可以使用 Emacs 的一部分timeclock.el包。或者您可以用您喜欢的任何语言编写一个简单的脚本来发出类似的信息。或者您可以使用 Org mode 的时间记录功能和 John Wiegley 开发的org2tc脚本。
这些时间日志条目可以出现在单独的文件中,也可以直接出现在您的主账本文件中。初始的'i'和'o'字符被视为 Ledger“指令”,在普通交易有效的任何地方都被接受。
Ledger 使用值表达式为多种不同目的进行计算:
值表达式支持大多数简单的数学和逻辑运算符,以及一组函数和变量。
显示谓词在寄存器报告中也非常方便,用于限制打印哪些交易。例如,以下命令仅显示从本月开始的交易,同时仍基于所有交易计算运行余额:
$ ledger -d "d>[this month]" register checking
此命令复杂性的优势在于,它根据寄存器中的所有交易打印运行总额。以下更简单的命令类似,但仅总计显示的记录项:
$ ledger -b "this month" register checking
以下是任何值表达式中可用的单字母变量。对于 register 和 print 命令,这些变量与单个记录项相关,有时与记录项影响的账户相关。对于 balance 命令,这些变量与账户相关,通常在含义上有细微差别。每个变量在两种情况下的使用都有说明。
t这映射到用户使用 --amount EXPR (-t) 指定的任何内容。在 register 报告中,--amount EXPR (-t) 更改值列;在 balance 报告中,默认情况下它没有意义。如果未指定 --amount EXPR (-t),则使用当前报告样式的值表达式。
T这映射到用户使用 --total VEXPR (-T) 指定的任何内容。在寄存器报告中,--total VEXPR (-T) 更改总计列;在余额报告中,这是为每个账户给出的值。如果未指定 --total VEXPR (-T),则使用当前报告样式的值表达式。
m这始终是当前时刻/日期。
ddate(日期)记录项的日期,以自纪元以来的秒数表示。对于账户,这始终是“今天”。
aux_date记录项的辅助日期
a金额条目的金额;不考虑子账户的账户余额。
b条目的成本;不考虑其子账户的账户成本。
v不考虑其子账户的条目或账户的市场价值。
g不考虑其子账户的条目或账户的净收益(市场价值减去成本基础)。等同于‘v-b’。
depth账户的深度(“层级”)。如果一个账户有一个父账户,其深度为一。
n条目的索引,或影响账户的条目数量。
Xcleared如果条目的交易已清算,则为‘1’,否则为‘0’。
uncleared如果条目的交易状态为未清算,则为‘1’,否则为‘0’。
pending如果条目的交易状态为待处理,则为‘1’,否则为‘0’。
R如果条目不是虚拟的,则为‘1’,否则为‘0’。
Z如果条目不是自动化的,则为‘1’,否则为‘0’。
可用的单字母函数有:
-对参数取负。
U参数的绝对值(无符号值)。
S从参数中去除商品信息。
P参数的当前市场价值。支持语法‘P(x,d)’,该语法返回时间‘d’的市场价值。如果未指定日期,则使用当前时刻。
可以使用以下方式构建更复杂的表达式:
expr "amount == COMMODITY AMOUNT"金额可以是 ledger 支持的任何类型的金额,可以带或不带商品标识。用于十进制数值。
/REGEX/expr account =~ /REGEX/匹配账户全名的正则表达式。如果是交易条目,将匹配受该条目影响的账户。
@/REGEX/expr payee =~ /REGEX/匹配交易收款人名称的正则表达式。
%/REGEX/expr has_tag(/REGEX/)expr has_tag('TAG')检查交易标签的正则表达式(REGEX)或字符串(TAG)。
expr has_meta(/REGEX/)expr has_meta('TAG')检查交易元数据键的正则表达式(REGEX)或字符串(TAG)。
expr tag(REGEX) =~ /REGEX/将交易标签与其值进行匹配的正则表达式。
expr date =~ /REGEX/用于以简单术语指定日期。例如,您可以说‘expr date =~ /2014/’。您还可以在方括号内使用日期表达式进行更复杂的日期筛选。例如,‘date > [上个月]’或‘date < [60 天后]’。有关可用日期关键字的完整列表,请参见期间表达式。
expr comment =~ /REGEX/匹配记账条目注释字段的正则表达式。这仅搜索记账条目的字段,而不搜索交易的备注或注释字段。例如,ledger reg "expr" "comment =~ /landline/"将匹配:
2014/1/29 电话账单 资产:支票账户 $50.00 支出:电话 $-50.00 ; 固话账单
但不会匹配:
2014/1/29 电话账单 ; 固话账单 ; 固话账单 资产:支票账户 $50.00 支出:电话 $-50.00
要匹配后者,请改用‘ledger reg "expr" "note =~ /landline/"’。
expr note =~ /REGEX/匹配交易备注字段的正则表达式。这将搜索交易中的所有注释,包括单个记账条目的注释。因此,‘ledger reg "expr" "note =~ /landline/"’将匹配以下所有三个示例:
2014/1/29 电话账单 资产:支票账户 $50.00 支出:电话 $-50.00 ; 固话账单
2014/1/29 电话账单 ; 固话账单 资产:支票账户 $50.00 支出:电话 $-50.00
2014/1/29 电话账单 ; 固话账单 资产:支票账户 $50.00 支出:电话 $-50.00
(EXPR)子表达式嵌套在括号中。这对于向函数传递更复杂的参数或覆盖运算符的自然优先级顺序非常有用。
expr base =~ /REGEX/匹配账户基础名称的正则表达式。如果是记账条目,这将匹配受该条目影响的账户。
expr code =~ /REGEX/匹配交易代码(收款人前括号内的文本)的正则表达式。
expr any(KEYWORD =~ /REGEX/)any关键字用于指定交易的至少一个记账条目必须匹配括号内的表达式。例如,‘ledger -f d reg expr "any(account =~ /Assets:/)"’可用于显示涉及至少一个‘资产:’账户的所有交易。
expr all(KEYWORD =~ /REGEX/)all关键字用于指定交易的所有记账条目必须匹配括号内的表达式。例如,‘ledger -f d reg expr "all(account =~ /Assets:/)"’可用于显示所有账户均为‘资产:’的交易。
query命令可用于查看 Ledger 如何解释您的查询。如果您没有得到预期的结果,这可能很有用(参见预命令)。
以下 Ledger 日记账数据(保存为expr.dat)用于解释下面函数和变量的行为:
2015/01/16 * (C0D3) 收款人 资产:现金 ¤ -123,45 ; 收款人: 储蓄罐 支出:办公用品
返回给定值的绝对值,例如金额。
$ ledger -f expr.dat --format "%(account) %(abs(amount))\n" reg assets
Assets:Cash ¤ 123,45
返回账户层级的最后部分。
根据--amount选项返回过账的计算金额。
将给定的表达式渲染为字符串,如果布尔值为真,则应用适当的 ANSI 转义码以指定的颜色显示。它通常检查--color选项的值。由于 ANSI 转义码包含不可打印字符序列,例如转义符^[,以下示例在命令行中可能不会显示为最终结果。
$ ledger -f expr.dat --format "%(ansify_if(account, blue, options.color))\n" reg
[34mAssets:Cash[0m [34mExpenses:Office Supplies[0m
返回具有平均价格的批次。
返回值向+无穷大的下一个整数。
$ ledger -f expr.dat --format "%(account) %(ceiling(amount))\n" reg
Assets:Cash ¤ -123,00 Expenses:Office Supplies ¤ 124,00
清除商品定价信息。
返回给定商品的价格。
返回交易代码,即日期后括号内的字符串。
$ ledger -f expr.dat --format "%(account) %(code)\n" reg assets
Assets:Cash C0D3
返回过账金额的商品类型。
$ ledger -f expr.dat --format "%(account) %(commodity)\n" reg
Assets:Cash ¤ Expenses:Office Supplies ¤
$ ledger -f expr.dat --format "%(date) %(account)\n" reg assets
2015/01/16 Assets:Cash
返回相关账户,虚拟过账用[]或()包围。
可以附加.note或.depth来获取账户的备注或深度信息
格式化金额以供显示。
格式化总计以供显示。
返回向负无穷方向最接近的值的整数。
$ ledger -f expr.dat --format "%(account) %(floor(amount))\n" reg
Assets:Cash ¤ -124,00 Expenses:Office Supplies ¤ 123,00
将字符串作为格式求值,类似于--format选项。
使用格式将日期作为字符串返回。有关格式字符串详情,请参阅strftime (3)。
$ ledger -f expr.dat --format "%(format_date(date, '%A, %B %d. %Y'))\n" reg assets
Friday, January 16. 2015
使用格式将日期时间作为字符串返回。有关格式字符串的详细信息,请参考strftime (3)。
返回序列中位于索引处的值。第一个元素的索引为 0。仅供内部使用。
如果值是序列,则返回 true。仅供内部使用。
将值中的所有换行符替换为\n。
对表示值的字符串进行右对齐或左对齐。首行的字段宽度由first_width指定。后续行的宽度由latter_width指定。如果latter_width=-1,则所有行都使用first_width。如果right_justify=true,则字段在字段宽度内右对齐。如果为false,则字段左对齐并填充至字段的完整宽度。如果colorize为 true,则 ledger 将遵循颜色设置。
$ ledger -f expr.dat --format "»%(justify(account, 30, 30, true))«\n" reg
» 资产:现金« » 支出:办公用品«
返回 posting 的批次日期。
返回 posting 的批次价格。
返回 posting 的批次标签。
固定金额的精度。
一个变量,允许使用长选项名称访问给定命令行选项的值,例如,要查看是否给出了--daily或-D,请使用option.daily。
$ ledger -f expr.dat -X $ -D --format "%(options.daily) %(options.exchange)\n" reg assets
真 $
返回 值_a 相对于 值_b(作为 100%)的百分比
$ ledger -f expr.dat --format "%(percent(amount, 200))\n" reg
-61.73% 61.73%
将 值 打印到标准输出。仅供内部使用。
对于具有单位成本的值,返回 值 的数量。
用双引号包围 表达式。如果表达式包含双引号,将使用反斜杠进行转义。
$ ledger -f expr.dat --format "%(quoted(account)) %(quoted(amount))\n" reg
"Assets:Cash" "¤ -123,45" "Expenses:Office Supplies" "¤ 123,45"
类似,但根据 RFC 4180 规定,嵌入的双引号将通过在其前面添加另一个双引号进行转义。
将金额四舍五入到标准精度。
返回金额的四舍五入版本。
返回 值 四舍五入到 n 位数字。不影响格式化。
$ ledger -f expr.dat --format "%(account) %(roundto(amount, 1))\n" reg
Assets:Cash ¤ -123,40 Expenses:Office Supplies ¤ 123,40
使用各种转换(如 四舍五入、去除值注释等)清理 值。
设置商品的价格。
如果传递给 --bold-if 的表达式计算结果为真,则返回 true。仅限内部使用。
将 value 转换为金额。仅限内部使用。
将 value 转换为余额。仅限内部使用。
将 value 转换为布尔值。仅限内部使用。
将 value 转换为日期。仅限内部使用。
将 value 转换为日期时间。仅限内部使用。
返回 value 的整数值。
$ ledger -f expr.dat --format "%(1 + to_int('1'))\n%(2,5 + int(2,5))\n" reg assets2 4.5
将 value 转换为掩码。仅限内部使用。
将 value 转换为序列。仅限内部使用。
返回今天的日期。
$ ledger -f expr.dat --now 2015/01/01 --format "%(today)\n" reg assets
2015/01/01
返回顶级金额。
根据--total选项返回过账的计算总额。
去除value的首尾空白字符。
$ ledger -f expr.dat --format "»%(trim(' Trimmed '))«\n" reg assets»Trimmed«
将string截断至total_len长度,确保每个账户至少为account_len长度。
移除金额的舍入。
返回金额的未舍入版本。
未文档化!请贡献文档以支持此功能。
格式字符串可用于更改报告的输出格式。通过将格式化字符串传递给--format FORMAT_STRING (-F)选项来指定。在该字符串中,允许使用构造,以便能够以自定义方式显示账户或过账的各个部分。
有几个附加标志允许您为特定报告定义格式。这些在配置文件中定义很有用,并且允许您从命令行运行账本报告,而无需为每个命令输入新格式。
在格式字符串中,使用百分号‘%’字符指定替换。所有替换的基本格式为:
%[-][最小宽度][.最大宽度](VALEXPR)
如果可选的减号‘-’跟随在百分号‘%’之后,那么替换的内容将左对齐。默认为右对齐。如果接下来指定了最小宽度,替换文本将至少达到该宽度,可能更宽。如果指定了句点和最大宽度,替换文本将永远不会超过该宽度,并且会被截断以适应。以下是一些示例:
%-20P交易的收款人,左对齐并填充至 20 字符宽。
%20P相同内容,右对齐,至少 20 字符宽。
%.20P相同内容,不超过 20 字符宽。
格式约束后面的表达式可以是单个字母,或者是用括号或方括号括起来的表达式。
为演示目的,使用了来自expr.dat的日记数据。允许的表达式有:
%插入一个百分号。
$ ledger -f expr.dat --format "%%\n" reg assets
%
t插入由--amount EXPR (-t)指定的值表达式的结果。如果未指定--amount EXPR (-t),则使用当前报告样式的值表达式。
T插入由--total VEXPR (-T)指定的值表达式的结果。如果未指定--total VEXPR (-T),则使用当前报告样式的值表达式。
(EXPR)插入括号中给出的值表达式产生的金额。例如,要插入账户总值的五倍,可以说‘%12(5*O)’。注意:在该表达式中将 5 放在前面很重要,这样商品就不会从总额中被剥离。
$ ledger -f expr.dat --format "%12(5*O)\n" reg assets
¤ -617,25
[DATEFMT]使用日期格式字符串格式化过账日期并插入结果,完全类似于strftime (3)支持的那些。例如:‘%[%Y/%m/%d %H:%M:%S]’。
S插入从中读取交易数据的文件的路径名。仅在register报告中才有意义。
$ ledger -f ~/journal.dat --format "%S\n" reg assets
/home/jwiegley/journal.dat
B插入该交易在文件中的起始字符位置。
$ ledger -f expr.dat --format "%B\n" reg assets
26
b插入该交易在文件中的起始行号。
$ ledger -f expr.dat --format "%b\n" reg assets
2
E插入该交易在文件中的结束字符位置。
$ ledger -f expr.dat --format "%E\n" reg assets
90
e插入该交易在文件中的结束行号。
$ ledger -f expr.dat --format "%e\n" reg assets
3
D按照默认格式返回日期。
d按照默认格式返回日期。如果交易有生效日期,则打印实际日期=生效日期。
X如果过账已被清算,则返回 1,否则返回 0。
Y这与‘%X’相同,不同之处在于它仅在所有成员过账具有相同状态时才显示状态字符。
C插入交易代码。这是在交易第一行括号内指定的值。
$ ledger -f expr.dat --format "%C\n" reg assets
(C0D3)
P插入与过账相关的收款人信息。
$ ledger -f expr.dat --format "%P\n" reg assets
PiggyBank
A插入账户的完整名称。
$ ledger -f expr.dat --format "%A\n" reg
资产:现金 支出:办公用品
N插入与过账关联的备注(如果存在)。
$ ledger -f expr.dat --format "%N\n" reg assets
收款人: PiggyBank
/‘%/’结构是特殊的。它将格式字符串分隔为交易第一个过账的打印内容和所有后续过账的打印内容。如果不使用,则所有过账使用相同的格式字符串。
$ ledger -f expr.dat --format "%P\n%/%A\n" reg
PiggyBank 支出:办公用品
为了展示 --format FORMAT_STRING 字符串的灵活性,默认余额格式如下所示(各种函数将在后面描述):
"%(justify(scrub(display_total), 20, -1, true, color))" " %(!options.flat ? depth_spacer : \"\")" "%-(ansify_if(partial_account(options.flat), blue if color))\n%/" "%$1\n%/" "--------------------\n"
以下代码返回为特定字段分配的宽度。可以使用相应的命令行选项更改默认值:
date_width
payee_width
account_width
amount_width
total_width
基于字符的格式化账本功能仅限于普通 TTY 会话中的 ANSI 终端字符颜色和字体高亮。
red | magenta | bold |
green | cyan | underline |
yellow | white | 闪烁 |
蓝色 | 黑色 |
amount_exprabs商品display_amountdisplay_totalfloorget_atis_seqmarket百分比价格数量已四舍五入truncatedtotal_exprtop_amountto_booleanto_intto_amountto_balanceunrounded以下函数允许您操作和格式化日期。
date(日期)返回当前交易的日期。
format_date(日期, "格式字符串")使用给定的格式字符串格式化日期。
now返回当前日期和时间。如果定义了 --now DATE 选项,将返回该值。
今天返回当前日期。如果定义了 --now DATE 选项,将返回该值。
to_datetime将字符串转换为日期时间值。
to_date将字符串转换为日期值。
value_date日期和时间格式被指定为以百分号开头的单字母代码字符串。可以指定任何分隔符,或不指定分隔符。
日期由日、月和年代码组合而成,可按您偏好的任意顺序排列:
%Y四位数字年份。
%y两位数字年份。
%m两位数的月份。
%d两位数的日期。
因此 "%Y%m%d" 生成‘20111214’,提供了一个易于排序的日期格式。
您可以使用‘%A’在日期中添加额外的星期信息,例如
%m-%d-%Y %A生成‘02-10-2010 星期三’。
%A %m-%d-%Y生成‘星期三 02-10-2010’。
这些是您可以选择用于星期几的选项
%a星期几,缩写形式(如周三)。
%A星期几,完整形式(如星期三)。
%d月份中的天数(dd),补零至两位数。
%e月份中的天数(dd),不补零至两位数。
%j一年中的天数,补零至三位数(000–366)。
%u星期几,从周一开始(1),即 mtwtfss 3。
%w星期几,从周日开始(0),即 smtwtfs 3。
您可以使用‘%B’在日期中添加额外的月份信息,例如
%m-%d-%Y %B生成‘02-10-2010 二月’。
%B %m-%d-%Y生成‘二月 02-10-2010’。
这些是您可以为月份选择的选项
%m‘mm’ 月份以两位数表示。
%b区域设置的缩写月份,例如‘02’可能缩写为‘Feb’。
%B区域设置的全称月份,长度可变,例如二月。
可使用的其他日期格式参数:
%U周数,以周日为一周的第一天,范围 01–53。
%W周数,以周一为一周的第一天,范围 01–53。
%V一年中的周数,范围 01–53。
%C世纪,范围 00–99。
%D生成%m/%d/%y,如‘02/10/10’。
%x区域设置的日期表示,如美国的‘02/10/2010’。
%F生成%Y-%m-%d,如‘2010-02-10’。
以下格式化函数允许您对文本进行有限的格式化:
ansify_if(值, 颜色)使用 ANSI 代码包装表示值的字符串,以便在 TTY 显示器上显示颜色。如果输出到文件则无效。
justify(value, first_width, latter_width, right_justify, colorize)对表示值的字符串进行右对齐或左对齐。首行的字段宽度由first_width指定。后续行的宽度由latter_width指定。如果latter_width=-1,则所有行都使用first_width。如果right_justify=true,则字段在字段宽度内右对齐。如果为false,则字段左对齐并填充至字段的完整宽度。如果colorize为 true,则 ledger 将遵循颜色设置。
join(STR)将STR中的换行符替换为‘\n’。
quoted(STR)返回用双引号包围的STR,‘"STR"’。
strip(value)值可以有多个注释,例如生效日期和批次价格。strip会移除这些注释。
以下格式字符串提供关于生成该条目的源数据文件中条目坐标的位置元数据。
filename条目来源的 ledger 数据文件名,缩写为‘S’。
beg_posfilename中条目开始的字符位置,缩写为‘B’。
end_posfilename中条目结束的字符位置,缩写为‘E’。
beg_linefilename中条目开始的行号,缩写为‘b’。
end_linefilename中条目结束的行号,缩写为‘e’。
可以使用 Python 来扩展您的 Ledger 体验。但首先,必须说明一下 Ledger 的数据模型,以便后续内容更容易理解。
与 Ledger 的每次交互都在会话(Session)的上下文中进行。即使您没有手动创建会话,顶层接口函数也会为您创建一个。会话是对象存在的地方,比如金额(Amounts)所引用的商品(Commodities)。
要使会话有用,您必须使用函数‘read_journal’将日志(Journal)读入其中。这会从给定文件中读取 Ledger 数据,在当前会话中填充一个日志对象,并返回对该日志对象的引用。
日志中包含所有与您的数据相关的事务(Transactions)、过账(Postings)和其他对象。还有自动事务(AutomatedTransactions)和周期事务(PeriodicTransactions)等。
以下是如何遍历数据文件中的所有过账:
import ledger for xact in ledger.read_journal("sample.dat").xacts(): for post in xact.posts(): print "Transferring %s to/from %s" % (post.amount, post.account)Ledger 数据以两种形式之一存在:原始(raw)和加工(cooked)。原始对象是您通过如上遍历得到的,并精确表示数据文件中看到的内容。考虑这个日志:
= true (Assets:Cash) $100 2012-03-01 KFC Expenses:Food $100 Assets:Credit
在这种情况下,文件中的原始常规事务是:
2012-03-01 KFC Expenses:Food $100 Assets:Credit
而加工形式是:
2012-03-01 KFC Expenses:Food $100 Assets:Credit $-100 (Assets:Cash) $100
因此,理解原始与加工的简单方式是:原始是未处理的数据,而加工则应用了所有考虑因素。
当您通过迭代事务来遍历日志时,通常查看的是原始数据。要查看加工数据,您必须通过查询日志生成某种报告:
for post in ledger.read_journal("sample.dat").query("food"): print "Transferring %s to/from %s" % (post.amount, post.account)查询迭代过账而不是事务的原因是,查询通常只返回它们所应用事务的一个“切片”。您总是可以通过查看匹配过账的xact成员来获取其事务:
last_xact = None for post in ledger.read_journal("sample.dat").query(""): if post.xact != last_xact: for post in post.xact.posts(): print "Transferring %s to/from %s" % (post.amount, post.account) last_xact = post.xact此查询最终报告日志中的每个加工过账,但按事务方式进行。它依赖于未排序报告按从日志文件解析的确切顺序返回过账这一事实。
Journal.query() 方法接受所有可在命令行中指定的参数,包括 --options。
由于查询会对其应用的 journal 进行“烹饪”处理,因此在任何给定时间,每个 journal 只能有一个活跃查询。当查询对象消失后(for 循环结束后),数据将恢复至原始状态。
您可以使用 'python' 指令将 Python 嵌入到数据文件中:
python import os def check_path(path_value): print "%s => %s" % (str(path_value), os.path.isfile(str(path_value))) return os.path.isfile(str(path_value)) tag PATH assert check_path(value) 2012-02-29 KFC ; PATH: somebogusfile.dat 支出:食品 $20 资产:现金
通过这种方式定义的任何 Python 函数都会立即作为 valexpr 函数可用。
当数字来自 Ledger 时(如 post.amount),其值的类型为 Amount。它可以像普通数字一样使用,但加法和减法仅限于具有相同商品(commodity)的金额。如需创建多种商品的总和,请使用 Balance。例如:
total = Balance() for post in ledger.read_journal("sample.dat").query(""): total += post.amount print totalLedger 采用分层功能集进行开发,下层对上层一无所知。实际上,在开发过程中会构建多个库,并将单元测试链接到这些库,因此若下层违反此模块化原则将产生链接错误。
这些层级包括:
Ledger 包含大量通用实用功能,用于时间解析、使用 Boost.Regex、错误处理等。所有这些都以可在其他项目中按需重用的方式实现。
一种数值抽象,将多精度有理数(通过 GMP)与商品相结合。这些结构可以在 C++ 或 Python(作为 Amount 对象)中像常规数字一样操作。
所有商品均由一个商品池管理,以便后续对金额的解析可以链接到同一商品,并建立一致的价格历史记录和格式详细信息。
引入了多种商品不同金额的概念。支持简单算术运算,以及与非商品化数值的乘除运算。
金额具有价格信息,这些数据保存在一个数据图中,金额代码本身对此仅有模糊感知(提供三个访问点,使得金额可以查询其在特定日期的重估价格)。
通常 Ledger 的高层模块并不关心对象是金额还是余额,它们只需要进行加法运算或打印输出。为此我创建了类型擦除类 value_t/Value,可以容纳多种数据类型并进行操作。它们可以包含金额、余额、日期、字符串等。如果尝试在两个数值之间执行无意义的操作(例如用金额除以余额),会在运行时而非编译时报错(如果直接尝试用amount_t除以balance_t就会在编译时报错)。
这是数值表达式语言的核心数据类型。
上一层围绕 Value 概念添加了函数和运算符。这使得您可以在运行时对数值进行转换和测试,而无需将其硬编码到 C++中。可用函数集由 Ledger 中的每个对象类型(如过账、账户、交易等)定义,但核心引擎对这些一无所知。其基础层仅知道如何对数值应用运算符,以及如何在函数间传递和接收数值。
在命令行输入表达式可能很繁琐,因此提供了称为“查询表达式”的简写形式。这些表达式本身不添加功能,纯粹是将输入字符串转换为对应的数值表达式,例如输入字符串'cash'会被转换为'(account =~ /cash/)'。这是一个便利层。
格式字符串允许您将数值表达式插入到字符串中,要求任何插入的数值都必须具有字符串表示形式。实际上这只是计算当前报告上下文中的数值表达式,调用结果值的to_string()方法,并将结果填入输出字符串。它还提供类似 printf 的行为,例如最小/最大宽度、右/左对齐等。
接下来是日志中任何可出现对象共享的基础类型:item_t。它包含所有此类解析实体的通用细节,例如所在文件和行号等信息。
作为日志中最常见的对象,过账是一种包含账户、金额、成本和元数据的项类型。还存在其他一些复杂情况,例如账户可标记为虚拟账户,金额可能是表达式等。
过账始终由交易拥有。这个item_t的子类了解日期、收款人等信息。如果从过账请求日期或元数据标签但过账没有该信息,则会查询交易是否能够提供。
过账也由账户共享,不过实际内存由交易管理。每个账户知道其包含的所有过账,但自身包含的信息相对较少。
最后,所有交易及其过账,以及所有账户,都由一个journal_t对象拥有。这是查询和报告数据的核心对象。
有一个文本解析器,完全包含在 textual.cc 中,它知道如何将文本解析为日志对象,然后这些对象会被“最终化”并添加到日志中。最终化是强制执行复式记账保证的步骤。
每个日志对象都是“可迭代的”,这些迭代器定义在 iterators.h 和 iterators.cc 中。为了模块化,迭代逻辑被保留在基本日志对象本身之外。
另一个抽象被隔离到自己的层中,这个类封装了日志对象的比较,基于用户传递给 --sort VEXPR 的任何值表达式。
许多报告会创建伪日志对象,比如在‘Total’账户中报告总额的过账。这些对象由 temporaries_t 对象创建和管理,报告过滤器在许多地方使用它。
有一个选项处理子系统,被许多下层使用。它使我相对容易地添加新选项,并让这些选项设置立即对值表达式可访问。
每个日志对象都由一个会话拥有,会话为该对象提供支持。用 GUI 术语来说,这是日志数据对象的控制器对象,每个文档窗口都是一个单独的会话。它们都由全局作用域拥有。
每次创建任何报告输出时,都会创建一个报告对象来确定您想看到的内容。在 Ledger REPL 中,每次执行命令时都会创建一个新的报告对象。在 CLI 模式下,只会创建一个报告对象,因为 Ledger 在显示结果后立即退出。
Ledger 生成数据的方式是:它向会话请求当前日志,然后创建一个应用于该日志的迭代器。迭代器的类型取决于报告的类型。
然后遍历这个迭代器,迭代器产生的每个对象都传递给一个“项处理器”,其类型与迭代器的类型直接相关。
有许多许多项处理器,它们可以链接在一起。每个处理器接收一个项(过账、账户、交易等),对其执行某些操作,然后将其传递给链中的下一个处理器。有计算运行总额的过滤器;在按新顺序回放之前对所有输入项进行排队和排序的过滤器;过滤掉不符合谓词的项的过滤器等。Ledger 中几乎每个报告功能都与一个或多个过滤器相关。查看 filters.h,目前定义了超过 25 个过滤器。
过滤器如何连接以及以什么顺序连接,是一个基于用户指定的各种选项的复杂过程。这是链逻辑的工作,完全在 chain.cc 中。花了很长时间才使这个逻辑完全正确,这就是为什么我还没有将这个层暴露给 Python 桥接。
尽管过滤器很棒,但最终您希望看到内容。这是称为输出模块的特殊“叶子”过滤器的工作。它们的实现就像常规过滤器一样,但它们没有“下一个”过滤器来传递数据。相反,它们是终点,必须对项执行某些操作,使用户在屏幕或文件中看到某些内容。
选择查询虽然通过实现用户查询逻辑来利用所有其他呈现的功能,但它们对各种信息了如指掌。选择查询本身没有独立功能,它们只是一种简写方式,通过更简洁、更一致的语法提供对 Ledger 大部分功能的访问。
存在一个主对象,它拥有所有其他对象,这就是 Ledger 的全局作用域。它创建其他对象,为命令行工具提供 REPL 行为等。在 GUI 术语中,这就是应用程序对象。
它创建全局作用域对象,执行错误报告,并处理必须在创建全局作用域之前处理的命令行选项,例如 --debug CODE。
以上就是 Ledger 的概要介绍。其余都是细节问题,例如每个日记账条目公开哪些值表达式、当前存在多少过滤器、报告和会话作用域定义了哪些选项等。
本章完整描述了日记账数据格式,适合其他语言的实现者参考。对于用户而言,关于记账的章节内容较少,但更符合常见用法(参见 记账)。
数据以交易的形式收集,这些交易发生在一个或多个日记账文件中。每个交易又由一个或多个过账条目组成,这些条目描述了金额如何从一个账户流向另一个账户。以下是一个最简单的日记账文件示例:
2010/05/31 仅作示例 支出:某:账户 $100.00 收入:另一:账户
在此示例中,包含一个交易日期、一个收款方(或交易描述)和两个过账条目。这些过账条目显示了一百美元从收入层级中的某个账户流向指定支出账户的流动情况。这些账户的名称和含义是任意的,没有隐含偏好,但您会发现遵循标准会计实践很有用(参见 Ledger 会计原则)。
由于第二个过账条目缺少金额,因此假定其为第一个金额的相反数。这保证了复式记账法的基本规则:每笔交易的总和必须平衡为零,否则就是错误的。每当 Ledger 遇到交易中的空过账条目时,它会用它来平衡其余部分。
通常(虽非强制)将第一个过账条目视为目的地,最后一个视为来源。因此,第一个过账条目的金额通常为正数。请考虑:
2010/05/31 收入交易 资产:支票账户 $1,000.00 收入:薪水 2010/05/31 支出交易 支出:餐饮 $100.00 资产:支票账户
日记的核心在于其记录的金额,这一事实体现在所允许的金额表达式的多样性上。虽然必须说明有时存在多种实现预期结果的方式,但此处将涵盖所有表达式。
注意:必须注意账户末尾与金额开头(包括商品标识符)之间至少需要两个空格。
最简单的形式是接受纯十进制数字:
2010/05/31 一笔收入交易 资产:活期存款 1000.00 收入:工资
此类金额只能使用可选的小数点。这些被称为整数金额或非商品化金额。在大多数方面它们与商品化金额相似,但有一个重要区别:它们在报告中始终以全精度显示。稍后将详细说明。现在必须谈谈 Ledger 存储数字的方式。
Ledger 解析的每个数字在内部都存储为无限精度有理数值。从不使用浮点运算,因为它无法保持值的精度。因此,对于上述‘1000.00’,内部值为‘100000/100’。
虽然有理数能很好地保持精度,但问题出现了:应如何显示它们?像‘100000/100’这样的数字没问题,因为它表示一个整洁的十进制分数。但当数字‘1/1’除以三时呢?应如何打印无限循环小数‘1/3’?
Ledger 通过在最后可能时刻将有理数转换为十进制来解决此问题,且仅用于显示。因此,有时必须进行一些舍入。如果这种舍入会影响运行总额的计算,则会生成特殊的调整过账以提醒您发生了这种情况。实际上,这种情况很少发生,但即使发生,它也不反映内部金额的调整,仅影响显示金额。
尚未解答的问题是 Ledger 如何对数值进行舍入。‘1/3’应该显示为‘0.33’还是‘0.33333’?对于商品化金额,小数位数是通过观察每种商品的使用方式决定的;但在整数金额的情况下,必须选择一个任意因子。初始时,这个因子是六。因此,‘1/3’会显示为‘0.333333’。此外,这个舍入因子会与每个特定值关联,并在数学运算中保持。例如,如果该特定数字自乘,结果的小数精度将为十二位。加法和减法不会影响精度。
由于每个整数金额都保留其自身的显示精度,这被称为全精度,与商品化金额相对,后者总是参照其商品来确定应舍入到的精度,因此使用商品精度。
商品化金额是一个具有关联商品的整数金额。该商品可以出现在金额之前或之后,并且可能与金额之间用空格分隔,也可能不用。商品名称中允许使用大多数字符,除了以下字符:
.,;:?!-+*/^&|=<>[](){}@然而,如果这些字符被双引号包围,它们仍可以出现在商品名称中,例如:
100 "EUN+133"
如果发现一个带引号的商品,它也会在引号中显示,以避免混淆哪部分是金额,哪部分是商品。
商品化金额的另一个特点是它们会以与解析时相同的形式报告。如果您使用‘$100’指定美元金额,它们将以相同方式显示;同样适用于‘100 $’或‘$100.000’。您甚至可以使用十进制逗号,如‘$100,00’,或千位分隔符,如‘$10,000.00’。
这些显示特性会与商品关联,结果是同一商品的所有金额都会一致地报告。最明显的是显示精度,在大多数情况下,它由给定商品所见的最精确值决定。
Ledger 区分观察到的金额和未观察到的金额。观察到的金额由 Ledger 评估,以确定使用该商品的金额应如何显示;未观察到的金额仅在其数值上有意义——无论它们如何指定,都不会改变该商品中其他金额的显示方式。
下一节将介绍成本表达式中的一个例子。
您已经了解了如何为过账指定商品化金额或整数金额。但如果您支付的金额是一种商品,而收到的金额是另一种商品呢?主要有两种表达方式:
2010/05/31 农贸市场 资产:我的食品柜 100 个苹果 资产:支票账户 -$20.00
在这个例子中,您支付了 20 美元购买 100 个苹果。您的成本是每个苹果 20 美分,Ledger 会为您计算这个隐含成本。您也可以使用成本金额来明确表示成本:
2010/05/31 农贸市场 资产:我的食品柜 100 个苹果 @ $0.200000 资产:支票账户
这里单位成本以成本金额的形式明确给出;由于成本金额是未观察到的,使用六位小数对最终报告中美元金额的显示方式没有影响。您也可以指定总成本:
2010/05/31 农贸市场 资产:我的食品柜 100 个苹果 @@ $20 资产:支票账户
这三种形式具有相同的含义。在大多数情况下,首选第一种形式,但当涉及两个以上的过账时,后两种形式是必要的:
2010/05/31 农贸市场 资产:我的食品柜 100 个苹果 @ $0.200000 资产:我的食品柜 100 个菠萝 @ $0.33 资产:我的食品柜 100 个"海棠果" @ $0.04 资产:支票账户
这里的隐含成本是‘$57.00’,它会自动输入到空过账中,以使交易平衡。
在涉及多种商品的每笔交易中,总有一种是主要商品。这种商品应被视为交换商品,或用于买卖其他商品单位的商品。在上面的水果示例中,美元是主要商品。这是由 Ledger 根据商品在交易中的位置决定的:
2010/05/31 示例交易 支出 100 次要商品 资产 -50 主要商品 2010/05/31 示例交易 支出 100 次要商品 @ 0.5 主要商品 资产 2010/05/31 示例交易 支出 100 次要商品 @@ 50 主要商品 资产
唯一需要区分主要和次要商品的情况是在使用--market (-V)或--basis (-B)选项的报告中。使用这些选项时,只显示主要商品。
如果一笔交易只使用一种商品,这种商品也被视为主要商品。实际上,当 Ledger 确保所有交易余额为零时,它只对主要商品进行此操作。
这些选项主要供 Ledger 开发者使用,但对于尝试新功能的用户也可能有一定用处。
忽略 ledger 运行的初始化文件和环境变量。
如果 Ledger 已使用调试选项构建,这将在运行期间提供额外数据。下面列出了可用的调试 代码。您可以使用正则表达式(如 "(account.display|expr.calc)")提供多个代码。
account.display | draft.xact | option.names |
account.sorted | expr.calc | org.next_amount |
amount.commodities | expr.compile | org.next_total |
amount.convert | expr.merged.compile | parser.error |
amount.is_zero | filters.changed_value | pool.commodities |
amount.parse | filters.changed_value.rounding | post.assign |
amount.price | filters.collapse | python.init |
amount.refs | filters.forecast | python.interp |
amount.roundto | filters.interval | query.mask |
amount.truncate | filters.revalued | report.predicate |
amount.unround | format.abbrev | scope.search |
annotate.less | format.expr | scope.symbols |
archive.journal | generate.post | select.parse |
auto.columns | generate.post.string | textual.include |
budget.generate | history.find | textual.parse |
commodity.annotated.strip | history.map | timelog |
commodity.annotations | item.meta | times.epoch |
commodity.compare | ledger.read | times.interval |
commodity.download | ledger.validate | times.parse |
commodity.exchange | lookup | value.sort |
commodity.price.find | lookup.account | value.storage.refcount |
commodity.prices.add | mask.match | xact.extend |
commodity.prices.find | memory.debug | xact.extend.cleared |
csv.mappings | op.memory | xact.extend.fail |
csv.parse | option.args | xact.finalize |
启用追踪功能。INT 参数指定所需的追踪级别:
LOG_OFF | 0 |
LOG_CRIT | 1 |
LOG_FATAL | 2 |
LOG_ASSERT | 3 |
LOG_ERROR | 4 |
LOG_VERIFY | 5 |
LOG_WARN | 6 |
LOG_INFO | 7 |
LOG_EXCEPT | 8 |
LOG_DEBUG | 9 |
LOG_TRACE | 10 |
LOG_ALL | 11 |
打印 Ledger 执行的详细信息。
在运行时启用额外的断言检查。这会导致显著的性能下降。当与--debug CODE结合使用时,ledger 将生成内存跟踪信息。
验证每个构造的对象是否被正确析构。这仅用于调试目的。
打印版本信息并退出。
当您不确定某个命令或选项将如何工作时,预执行命令非常有用。预执行命令与常规命令的区别在于,预执行命令完全忽略日志数据文件,也不会读取用户的初始化文件。
eval VEXPR¶针对模型交易评估给定的值表达式。
format FORMAT_STRING¶打印 ledger 如何使用给定格式描述的详细信息,并将其应用于模型交易。
generate¶从种子随机生成语法有效的 Ledger 数据。由 'GenerateTests' 测试框架用于开发测试。
parse VEXPR¶expr VEXPR¶打印 Ledger 如何使用给定的值表达式描述并将其应用于模型交易的详细信息。
period PERIOD_EXPRESSION¶评估给定期间并报告 Ledger 如何解释它:
$ ledger period "this year" --now 2011-01-01
--- 期间表达式标记 --- TOK_THIS: this TOK_YEAR: year END_REACHED: <EOF> --- 稳定前 --- 范围: 2011 年 --- 稳定后 --- 范围: 2011 年 开始: 11-Jan-01 结束: 12-Jan-01 --- 范围内的示例日期 (最多 20 个) --- 1: 11-Jan-01
query¶args¶评估给定参数并报告 Ledger 如何针对以下模型交易解释它:
$ ledger query "/Book/"
--- 输入参数 --- ("/Book/") --- 上下文是以下交易的首次记账 --- 2004/05/27 书店 ; 此注释适用于所有记账。 :SecondTag: 费用:书籍 20 BOOK @ $10 ; 元数据: 某值 ; Typed:: $100 + $200 ; :ExampleTag: ; 以下是描述记账的注释。 负债:万事达卡 $-200.00 --- 输入表达式 --- (account =~ /Book/) --- 解析后的文本 --- (account =~ /Book/) --- 表达式树 --- 0x7fd639c0da40 O_MATCH (1) 0x7fd639c10170 IDENT: account (1) 0x7fd639c10780 VALUE: /Book/ (1) --- 编译后的树 --- 0x7fd639c10520 O_MATCH (1) 0x7fd639c0d6c0 IDENT: account (1) 0x7fd639c0d680 FUNCTION (1) 0x7fd639c10780 VALUE: /Book/ (1) --- 计算值 --- truescript¶未文档化!请贡献文档以支持此功能。
template¶显示 xact 子命令生成的插入模板。这是一个调试命令。
Ledger 源代码附带了一套相当完整的测试,用于验证一切正常,且没有旧错误重新出现。测试使用 ctest 单独运行。所有测试可以使用 make check 或 ninja check 运行,具体取决于您偏好的构建工具。
构建完成后,账本可执行文件位于源码树的build子目录下。测试文件会被构建并存储在构建目录的test子目录中。例如:~/ledger/build/ledger/opt/test。
完整的测试套件可以使用构建工具的检查选项从构建目录运行。例如:make check。整个测试套件在优化构建版本下大约需要一分钟,而在调试版本下则需要数倍时间。在开发和调试过程中,运行单个测试可以节省大量时间。
单个测试可以从构建位置的test子目录运行。要执行单个测试,请使用ctest -V -R regex,其中正则表达式匹配您想要构建的测试名称。
在主源码分发版的test子目录下存储了近 300 个测试。它们分为两大类:基准测试和回归测试。例如,要运行5FBF2ED8测试,请执行ctest -V -R "5FB"。
编写新测试时,首先确定测试属于哪个大类:基准测试或回归测试。根据类别不同,测试命名方式也不同:基准测试以其类型为前缀,例如‘cmd’(有效类型请参见基准测试类型),而回归测试则以错误 ID 命名,例如‘1234.test’或 UUID‘91416D62.test’。如果多个测试文件属于同一个错误编号,则通过在文件名后附加_X来区分,其中‘X’是测试编号,例如‘1234_1.test’、‘1234_2.test’。
cmd账本命令,如register或balance
dir账本指令,如account或alias
feat账本功能,如日记文件中的余额断言
opt账本选项,如--period或--format
账本测试文件包含三个部分:
Ledger 有一个特殊的测试命令指令,位于 test 和 end test 之间的所有内容都被视为注释,因此每个 Ledger 测试自动成为一个有效的 Ledger 文件。测试脚本会获取 test 行的剩余部分并将其用作 ledger 的命令行参数,而位于 test 和 end test 之间的文本是预期输出,例如:
; 这是 2014 年的日记账数据 12/24 (C0d3) 圣诞老人 资产:银行 ¤ -150,00 支出:礼物 ; 下一行指定此测试的 ledger 命令行选项,; 下一行到 `end test` 之间的所有内容指定预期输出 test reg --payee=code 14-Dec-24 C0d3 资产:银行 ¤ -150,00 ¤ -150,00 14-Dec-24 C0d3 支出:礼物 ¤ 150,00 0 end test
当需要测试输出到 stderr 的错误时,通过在 test 行添加 -> 来重定向测试输出,并在 __ERROR__ 部分匹配预期的错误文本:
2014/01/01 * Acme 公司 资产:银行:支票 ¤ 1.000,00 [基金:假期] ¤ 300,00 [基金:学习] ¤ 600,00 收入:工资 ¤ -2.000,00 test reg -> __ERROR__ 解析文件 "$FILE" 第 5 行时:平衡来自 "$FILE" 第 1-5 行的交易时:> 2014/01/01 * Acme 公司 > 资产:银行:支票 ¤ 1.000,00 > [基金:假期] ¤ 300,00 > [基金:学习] ¤ 600,00 > 收入:工资 ¤ -2.000,00 不平衡余数为:¤ -100,00 需要平衡的金额:¤ 1.900,00 错误:交易不平衡 end test
可以使用特殊的 $FILE 变量来匹配测试期间使用的日记账文件名。
要向测试套件添加新测试,请使用您所用构建工具的 rebuild_cache 选项,例如 make rebuild_cache,现在可以按照 运行测试 中的文档运行新测试。
以下功能已从 Ledger 3.0 中移除:
bal 执行的是 2.x 中 ‘-s bal’ 的功能。要查看 2.6 的行为,请在 3.0 中使用 --collapse (-n) 选项,如 ‘bal -n’。选项 --subtotal (-s) 不再对余额报告产生任何影响。以下功能在 Ledger 3.0 中已弃用:
LEDGER现为 LEDGER_FILE,
LEDGER_INIT现为 LEDGER_INIT_FILE,
PRICE_HIST现为 LEDGER_PRICE_DB,
PRICE_EXP现为 LEDGER_PRICE_EXP。
以下日记账文件包含在 ledger 的源代码发行版中。它名为 drewr3.dat,展示了 ledger 的许多功能,包括自动和虚拟交易,
; -*- ledger -*- = /^Income/ (Liabilities:Tithe) 0.12 ;~ Monthly ; Assets:Checking $500.00 ; Income:Salary ;~ Monthly ; Expenses:Food $100 ; Assets 2010/12/01 * Checking balance Assets:Checking $1,000.00 Equity:Opening Balances 2010/12/20 * Organic Co-op Expenses:Food:Groceries $ 37.50 ; [=2011/01/01] Expenses:Food:Groceries $ 37.50 ; [=2011/02/01] Expenses:Food:Groceries $ 37.50 ; [=2011/03/01] Expenses:Food:Groceries $ 37.50 ; [=2011/04/01] Expenses:Food:Groceries $ 37.50 ; [=2011/05/01] Expenses:Food:Groceries $ 37.50 ; [=2011/06/01] Assets:Checking $ -225.00 2010/12/28=2011/01/01 Acme Mortgage Liabilities:Mortgage:Principal $ 200.00 Expenses:Interest:Mortgage $ 500.00 Expenses:Escrow $ 300.00 Assets:Checking $ -1000.00 2011/01/02 Grocery Store Expenses:Food:Groceries $ 65.00 Assets:Checking 201 极/01/05 Employer Assets:Checking $ 2000.00 Income:Salary 2011/01/14 Bank ; Regular monthly savings transfer Assets:Savings $ 300.00 Assets:Checking 2011/01/19 Grocery Store Expenses:Food:Groceries $ 44.00 ; hastag: not block Assets:Checking 2011/01/25 Bank ; Transfer to cover car purchase Assets:Checking $ 5,500.00 Assets:Savings ; :nobudget: apply tag hastag: true apply tag nestedtag: true 2011/01/25 Tom's Used Cars Expenses:Auto $ 5,500.00 ; :nobudget: Assets:Checking 2011/01/27 Book Store Expenses:Books $20.00 Liabilities:MasterCard end tag 2011/12/01 Sale Assets:Checking:Business $ 30.00 Income:Sales end tag
来自讨论列表的各种说明,我尚未将其纳入文档主体。
$ ledger --group-by "tag('trip')" bal$ ledger cleared VWCU NFCU Tithe Misentry
$ ledger register Joint --uncleared
$ ledger register Checking --sort d -d 'd>[2011/04/01]' until 2011/05/25
= /^Income:Taxable/ (Liabilities:Tithe Owed) -0.1 = /Noah/ (Liabilities:Tithe Owed) -0.1 = /Jonah/ (Liabilities:Tithe Owed) -0.1 = /Tithe/ (Liabilities:Tithe Owed) -1.0
| 跳转到: | A B C D E F G H I J L M N O P R S T U W |
|---|
| 跳转到: | A B C D E F G H I J L M N O P R S T U W |
|---|
| 跳转到: | -
=
~
A B C D E F G H I J L M N O P Q R S T U V X Y |
|---|
| 跳转到: | -
=
~
A B C D E F G H I J L M N O P Q R S T U V X Y |
|---|