Costflow 语法

Costflow 语法规则

Costflow 是一个提升复式记账效率的工具,通过连接聊天工具与云存储的方式来解决现有复式记账记录麻烦和移动设备无法记录的问题。更多 Costflow 的介绍可以查看这篇文章。Costflow 语法则是其中解析文本到记账工具格式的规则。

例如发送下方内容给 Costflow 机器人:

Dinner #trip 200 bofa > trip

根据语法规则会被解析成下方内容:

2019-06-25 * "Dinner" #trip #costflow
Assets:US:BofA -200.00 USD
Expenses:Trip +200.00 USD

Costflow 语法和对应的解析器代码将会开源在 https://github.com/costflow/syntaxhttps://github.com/costflow/parser 。欢迎大家来贡献想法和代码,一起来让这个语法更好用。

Playground

https://playground.costflow.io

Costflow Syntax v0.1

以下内容基于 Costflow Syntax v0.1,并且输出格式仅支持 Beancount

语法特点

  • 可选输入日期,默认为今天;

  • 货币代码可省略;

  • 账户名替换,例如用 bofa 代替 Assets:US:BofA:Checking;

  • 自动获取当前货币汇率、加密货币和股票的价格;

  • 极简交易语法;

  • 自定义缩进长度以及每行对齐长度;

语法指令符

指令符是文本开头的第一个符号或者单词(除日期外),指令符兼容记账工具的部分 directive,并进行了扩展。以下为可用的指令符。

指令符

说明

*

已确认交易,可省略。

!

未确认交易。

;

注释。会同步存储到文件中。

//

注释。只记录在 Costflow 中,不会同步到文件中。

open

对应 Open Directive.

close

对应 Close Directive.

commodity

对应 Commodity Directive.

option

对应 Option Directive.

note

对应 Note Directive.

balance

对应 Balance Directive.

pad

对应 Pad Directive.

price

对应 Price Directive.

$

查询法定货币、加密货币的汇率,以及股票的最新价格。不会同步到文件中。

event

对应 Event Directive.

在未匹配到任何指令符的情况下: 如果语句中含有数字,则认为指令符为 *; 如果语句中没有数字,则认为指令符为 //。

通用规则

为了使语法更简单易用,在使用前会要求用户预先设置以下内容:

  • 解析格式,此版本只支持 Beancount;

  • 用户所在时区;

  • 默认货币代码;

  • 缩进长度、每行对齐长度;

  • 账户名称对应的缩写。

此版本语法有如下通用规则:

  • 日期采用 YYYY-MM-DD 格式,可省略,默认为当前你所在时区的今天(以下示例用 2019-07-01 代替);

  • 货币代码可省略,默认为你预设的货币(以下示例用 USD 代替);

  • 不支持 metadata;

  • 数字、货币代码、交易描述之间都需要有空格;

  • commodity 全部为大写英文字母;

  • 文字缩写不能全部是大写字母,以下为后面示例中可能用到的缩写:

    eob: Equity:Opening-Balances
    bofa: Assets:US:BofA:Checking
    rx: Assets:Receivables:X
    ry: Assets:Receivables:Y
    boc: Assets:CN:BOC
    cmb: Liabilities:CreditCard:CMB
    food: Expenses:Food
    phone: Expenses:Home:Phone
    rent: Expenses:Home:Rent

交易 Transaction

交易是最常见的记账类型。Costflow 支持以下两种交易格式。

第一种:>

第一种使用大于号来代表交易的流向,意思是交易从符号左侧的账户流向符号右侧的账户。语法规则如下:

[YYYY-MM-DD] [Flag] ["Payee"] ["Narration"] [#tag] [^link] AMOUNT [COMMODITY] FROM_ACCOUNT > [AMOUNT] [COMMODITY] TO_ACCOUNT

方括号中的内容代表可以被省略。具体规则如下:

  • 日期可以省略,默认为当前你所在时区的今天;

  • Flag 代码交易是否确认, ! 代表未确认, 代表已确认,如果是 可以省略;

  • Payee 和 Narration 使用起来会很简单,但语法规则稍微有些复杂:

    • 兼容 Beancount 现有的双引号规则(但不支持 | 来分割):只有一个双引号时代表 Narration,如果有两个则第一个代表 Payee,第二个代表 Narration;

    • 双引号在 Costflow 中可以省略:

      • 如果是 Narration 可以直接跳过双引号输入文字,但此规则 Narration 中不能有数字出现,例如 「去 711 买饮料」是不符合规则的。

      • 如果是 Payee 可以使用 @Payee 的格式,但 Payee 中间不可以有空格,可以使用 _ 或者 - 来连接。例如 @KFC 和 @Burger_King 都是符合规则的 Payee;

      • 如果只想记录 Payee,则直接 @Payee 即可,Narration 完全不用在意。

  • Tag:以 # 开始的字符会被认为是 tag,可为多个;

  • Link:以 ^ 开始的字符会被认为是 link,可为多个;

  • 第一种交易语法中,AMOUNT / COMMODITY / ACCOUNT 要按照这个顺序来书写;

    • AMOUNT 为交易金额,因为 > 代表流向,所以 > 左侧金额默认为负数,负号可以省略;

    • COMMODITY 可省略,默认为预先设置的货币代码;

    • ACCOUNT 为账户名称,可为账户全名,或者是预先设置缩写;

  • > 右侧的规则和左侧基本一致,除了金额默认为正数;

  • 如果需要记录 Costs 和 Prices,用法与 Beancount 一致,@ 和 @@ 两端都需要有空格;

  • 如果涉及多个账户,则使用 + 来代表,左右两侧均可出现。但请注意, > 只能出现一次;

  • > 右侧的金额可以省略,默认根据左侧对的金额来计算,如果右侧有多个账户,则平分左侧金额(AA)。

下面来看几个示例:

// 示例一:传统格式输入
2017-01-05 "RiverBank Properties" "Paying the rent" 2400 Assets:US:BofA:Checking > 2400 Expenses:Home:Rent
// 示例一输出
2017-01-05 * "RiverBank Properties" "Paying the rent"
Assets:US:BofA:Checking -2400.00 USD
Expenses:Home:Rent +2400.00 USD
// 示例二:省略日期、货币代码,并使用非双引号格式的 Payee
@Verizon 59.61 Assets:US:BofA:Checking > Expenses:Home:Phone
// 示例二输出
2019-07-01 * "Verizon" ""
Assets:US:BofA:Checking -59.61 USD
Expenses:Home:Phone +59.61 USD
// 示例三:在示例二的基础上,按照文字替换进行缩写
@Verizon 59.61 bofa > phone
// 示例三输出与示例二完全一致
// 示例四:从多个账户支出,一种用途
Rent 750 cmb + 750 boc > rent
// 示例四输出
2019-07-01 * "Rent"
Liabilities:CreditCard:CMB -750.00 USD
Assets:CN:BOC -750.00 USD
Expenses:Home:Rent +1500.00 USD
// 示例五:从一个账户支出,多种用途。场景为朋友 AA 聚餐,你使用信用卡来结帐(为 X 和 Y 垫付)。
Dinner 180 CNY bofa > rx + ry + food
// 示例五输出
2019-07-01 * "Dinner"
Assets:Receivables:X +60.00 CNY
Assets:Receivables:Y +60.00 CNY
Expenses:Food +60.00 CNY
Liabilities:CreditCard:CMB -180.00 CNY
// 示例六:记录 Cost/Price
Transfer to account in US 5000 CNY @@ 726.81 USD boc > 726.81 bofa
// 示例六输出
2019-07-01 * "Transfer to account in US"
Assets:CN:BOC -5000.00 CNY @@ 726.81 USD
Assets:US:BofA:Checking +726.81 USD

第二种:|

第二种方式与第一种语法大部分相同,除了账户部分不使用 > 表示流向,而是使用管道符号(U+007C)来代表换行,换行出现的时机与 Beancount 一致。第二种规则如下:

[YYYY-MM-DD] [Flag] ["Payee"] ["Narration"] [#tag] [^link] | ACCOUNT_A [COMMODITY] AMOUNT | ACCOUNT_B [COMMODITY] AMOUNT

可以看出,其中日期、Flag、Payee、Narration、Tag、Link 用法与第一种完全相同。两者不同点是:

  • 第二种需要在每个账户出现前输入一个 |;

  • 第二种语法中, ACCOUNT / COMMODITY / AMOUNT 的顺序与 Beancount 一致;

  • 第二种因为没有流向,所以无法对金额进行计算。所以 Amount 如果是负值,负号不能省略。每个区间内 AMOUNT 值也不能省略。

我们将上面的示例用第二种方式进行改写:

// 示例一:传统格式输入
2017-01-05 "RiverBank Properties" "Paying the rent" | Assets:US:BofA:Checking -2400 | Expenses:Home:Rent 2400
// 示例一输出
2017-01-05 * "RiverBank Properties" "Paying the rent"
Assets:US:BofA:Checking -2400.00 USD
Expenses:Home:Rent +2400.00 USD
// 示例二:省略日期、货币代码,并使用非双引号格式的 Payee
@Verizon | Assets:US:BofA:Checking -59.61 | Expenses:Home:Phone 59.61
// 示例二输出
2019-07-01 * "Verizon" ""
Assets:US:BofA:Checking -59.61 USD
Expenses:Home:Phone +59.61 USD
// 示例三:在示例二的基础上,按照文字替换进行缩写
@Verizon | bofa -59.61 | phone 59.61
// 示例三输出与示例二完全一致
// 示例四:从多个账户支出,一种用途
Rent | cmb -750 | boc -750 | rent 1500
// 示例四输出
2019-07-01 * "Rent"
Liabilities:CreditCard:CMB -750.00 USD
Assets:CN:BOC -750.00 USD
Expenses:Home:Rent +1500.00 USD
// 示例五:从一个账户支出,多种用途。场景为朋友 AA 聚餐,你使用信用卡来结帐(为 X 和 Y 垫付)。
Dinner | bofa 180 CNY | rx -60 | ry -60 | food -60
// 示例五输出
2019-07-01 * "Dinner"
Assets:Receivables:X +60.00 CNY
Assets:Receivables:Y +60.00 CNY
Expenses:Food +60.00 CNY
Liabilities:CreditCard:CMB -180.00 CNY
// 示例六:记录 Cost/Price
Transfer to account in US | boc -5000 CNY @@ 726.81 USD | bofa +726.81
// 示例六输出
2019-07-01 * "Transfer to account in US"
Assets:CN:BOC -5000.00 CNY @@ 726.81 USD
Assets:US:BofA:Checking +726.81 USD

注释 Comment

; 与 // 对的用法都非常简单,直接在符号后面输入任何内容即可。例如

; I paid and left the taxi, forgot to take change, it was cold.
// to do: cancel Netflix subscription

两者不同的是,使用 ; 的注释会先存储到 Costflow 服务器(其它类型同样,可以登录 Costflow 后台查看),然后同步注释到云存储文件中;而 // 注释只会存储到 Costflow 服务器。// 注释适用于提醒自己做一些账户操作。

Open

语法与 Beancount 一致。此版本暂不支持 Metadata 的设置。

[YYYY-MM-DD] open ACCOUNT

示例:

// 输入
open Assets:US:BofA
// 输出
2019-07-01 open Assets:US:BofA

Close

语法与 Beancount 一致。

[YYYY-MM-DD] close ACCOUNT

示例:

// 输入
close Assets:US:BofA
// 输出
2019-07-01 close Assets:US:BofA

Commodity

语法与 Beancount 一致。此版本暂不支持 Metadata 的设置。

[YYYY-MM-DD] commodity SYMBOL

示例:

// 输入
commodity BTC
// 输出
2019-07-01 commodity BTC

Option

语法:

option [NAME] VALUE

NAME 和 VALUE 一般需要放在双引号中,但在以下几种情况下除外:

  • 如果 Name 为 title,此时 Name 可以省略,直接使用 option Value 的格式,Value 也无需使用双引号;

  • 如果 Value 值为 ISO 4217 中的货币代码,此时 Name 可以省略(会自动解析成 operating_currency),Value 也无需使用双引号。

示例:

// 输入
option Example Costflow file
// 输出
option "title" "Example Costflow file"
// 输入
option CNY
// 输出
option "operating_currency" "CNY"
// 输入
option "conversion_currency" "NOTHING"
// 输出
option "conversion_currency" "NOTHING"

Note

语法:

[YYYY-MM-DD] note ACCOUNT DESCRIPTION

说明:

  • ACCOUNT 可以是账户全称也可以是预先设置的缩写;

  • DESCRIPTION 为任意文字,无需使用双引号。

示例:

// 输入
note bofa Called about fraudulent card.
// 输出
2019-07-01 note Assets:US:BofA:Checking "Called about fraudulent card."

Balance

语法:

[YYYY-MM-DD] balance ACCOUNT AMOUNT [COMMODITY]

说明:

  • ACCOUNT 可以是账户全称也可以是预先设置的缩写;

  • COMMODITY 可以省略,默认为预先设置的货币代码。

示例:

// 输入
balance bofa 360
// 输出
2019-07-01 balance Assets:US:BofA:Checking 360 USD

Pad

语法:

[YYYY-MM-DD] pad ACCOUNT ACCOUNT_PAD

说明:

  • ACCOUNT 和 ACCOUNT_PAD 可以是账户全称也可以是预先设置的缩写;

  • Pad 操作请谨慎使用,详情可参考 Beancount 文档

示例:

// 输入
pad bofa eob
// 输出
2019-07-01 pad Assets:US:BofA:Checking Equity:Opening-Balances

Price

语法:

[YYYY-MM-DD] price COMMODITY_A [PRICE] [COMMODITY_B]

说明:

  • 如果 COMMODITY_B 省略,则默认为 COMMODITY_B 是你预设的货币代码;

  • 可以手动输入 PRICE,即 PRICE 为阿拉伯数字,此时用法与 Beancount 一致;

  • 如果没有输入 PRICE,Costflow 将会自动在货币之间机型转换(数据源为 Alpha Vantage),转换优先级为:

    1. 首先判断 COMMODITY_A 是否是 ISO 4217 中的货币代码,如果是则进行汇率之间的转换;

    2. 其次判断 COMMODITY_A 是否是 Alpha Vantage 支持的加密货币代码(支持列表),如果是则进行转换;

    3. 最后将 COMMODITY_A 作为股票代码进行当前价格的查询,目前只支持美股(NASDAQ 和 NYSE)。注意此时不能指定 COMMODITY_B,而是以股票所在市场的货币为准。

示例:

// 输入
2017-01-17 price USD 1.08 CAD
// 输出
2017-01-17 price USD 1.08 CAD
// 输入,自动查询当前汇率。为了方便理解可以使用 to 链接两个货币代码,可以省略
price CAD to USD
// 输出
2019-07-01 price
// 输入,查询当前比特币价格
price BTC
// 输出
2019-07-01 price BTC 11946.64 USD
// 输入,查询苹果股票价格
price AAPL
// 输出
2019-07-01 price AAPL 199.8 USD

$

$ 作为指令符时用于查询法定货币、加密货币的汇率,以及股票的最新价格。查询结果将直接返回,不会同步到文件中。 $ 的语法与 price 有些类似:

$ [AMOUNT] COMMODITY_A [to] COMMODITY_B

说明:

  • 如果 COMMODITY_B 省略,则默认为 COMMODITY_B 是你预设的货币代码;

  • 如果不输入 AMOUNT,则默认 AMOUNT 为 1;

  • to 只是为了方便语义通顺,可以省略;

  • 转换优先级与 price 相同:

    1. 首先判断 COMMODITY_A 是否是 ISO 4217 中的货币代码,如果是则进行汇率之间的转换;

    2. 其次判断 COMMODITY_A 是否是 Alpha Vantage 支持的加密货币代码(支持列表),如果是则进行转换;

    3. 最后将 COMMODITY_A 作为股票代码进行当前价格的查询,目前只支持美股(NASDAQ 和 NYSE)。注意此时不能指定 COMMODITY_B,而是以股票所在市场的货币为准。

示例:

// 输入,自动查询当前汇率。为了方便理解可以使用 to 链接两个货币代码,可以省略
$ CAD to USD
// 输出
1 CAD = 0.7637 USD
// 输入,查询当前比特币价格,可以加入数量
$ 10 BTC
// 输出
10 BTC = 119466.4 USD
// 输入,查询苹果股票价格
$ AAPL
// 输出
AAPL 199.8 USD (-0.030%)

Event

语法:

[YYYY-MM-DD] event NAME VALUE

说明:

  • NAME 和 VALUE 可以使用双引号的形式;

  • 如果语句中没有双引号出现,则视语句中(除日期外)第一个单词为 NAME,剩余部分为 VALUE。

示例:

// 输入:传统方式
2017-01-02 event "location" "Paris, France"
// 输出
2017-01-02 event "location" "Paris, France"
// 输入:省略日期与双引号
event location Paris, Francce
// 输出
2017-01-02 event "location" "Paris, France"

相关链接