Value and amount
A Split has a value, in the Transaction currency, and an amount, in its Account's Commodity. Both are exact rationals; values sum to zero per Transaction. GnuCash's quantity is red-ale's amount.
A Split has two sizes, and mixing them up is the commonest mistake with multiple currencies or securities.
- Its value is in the Transaction currency: the one currency every Split of the Transaction shares. The values of a Transaction's Splits sum to exactly zero.
- Its amount is in the Commodity of the Split's Account: euros in a euro account, shares in a stock account.
⚠ GnuCash's word amount means exactly this quantity, not a generic number, and its files call it quantity.
Elsewhere in this Manual a value is always in the Transaction currency.
When an Account holds the Transaction currency, value and amount are equal, and red-ale fills in the amount from the value if you leave it out. When the Account's Commodity differs, you give both, and their ratio is the price the Split implies:
price = value / amount
Buying 10 shares of AAPL for 1,500.00 USD from a USD bank Account is a USD Transaction with two Splits:
| Account | Value (USD) | Amount |
|---|---|---|
| Broker (AAPL) | 1500.00 | 10 shares |
| Bank (USD) | -1500.00 | -1500.00 USD |
Transferring 100.00 USD to a euro Account at 0.92 is a USD Transaction too: the euro Account's Split has value 100.00
and amount 92.00. transaction.transfer works that out from a rate;
transaction.post takes the amounts as you give them.
Example: with a new, empty book open as book.gnucash.
JSON-RPC
Request:
{"jsonrpc":"2.0","id":1,"method":"account.create","params":{"name":"Bank","type":"BANK","commodity":"USD"}}
Response:
{
"jsonrpc": "2.0",
"id": 1,
"result": "…"
}
Request:
{"jsonrpc":"2.0","id":2,"method":"account.create","params":{"name":"Euro account","type":"BANK","commodity":"EUR"}}
Response:
{
"jsonrpc": "2.0",
"id": 2,
"result": "…"
}
Request:
{"jsonrpc":"2.0","id":3,"method":"transaction.post","params":{"datePosted":"2024-07-01","description":"To euros","currency":"USD","splits":[{"account":"Bank","value":"-100.00"},{"account":"Euro account","value":"100.00","amount":"92.00"}]}}
Response:
{
"jsonrpc": "2.0",
"id": 3,
"result": "…"
}
Request:
{"jsonrpc":"2.0","id":4,"method":"account.balance","params":{"account":"Euro account"}}
Response:
{
"jsonrpc": "2.0",
"id": 4,
"result": {
"balances": {
"commodity": "CURRENCY::EUR",
"balance": {
"num": "9200",
"denom": "100"
},
"…": "…"
},
"…": "…"
}
}
Command line
red-ale exec --book book.gnucash --script - <<'EOF'
account.create {"name":"Bank","type":"BANK","commodity":"USD"}
account.create {"name":"Euro account","type":"BANK","commodity":"EUR"}
transaction.post {"datePosted":"2024-07-01","description":"To euros","currency":"USD","splits":[{"account":"Bank","value":"-100.00"},{"account":"Euro account","value":"100.00","amount":"92.00"}]}
account.balance {"account":"Euro account"}
EOF
It prints:
[
"…",
"…",
"…",
{
"balances": {
"commodity": "CURRENCY::EUR",
"balance": {
"num": "9200",
"denom": "100"
},
"…": "…"
},
"…": "…"
}
]
MCP tool call
Tool call:
{"name":"account.create","arguments":{"name":"Bank","type":"BANK","commodity":"USD"}}
Result:
{
"content": [
{
"type": "text",
"text": "\"…\""
}
]
}
Tool call:
{"name":"account.create","arguments":{"name":"Euro account","type":"BANK","commodity":"EUR"}}
Result:
{
"content": [
{
"type": "text",
"text": "\"…\""
}
]
}
Tool call:
{"name":"transaction.post","arguments":{"datePosted":"2024-07-01","description":"To euros","currency":"USD","splits":[{"account":"Bank","value":"-100.00"},{"account":"Euro account","value":"100.00","amount":"92.00"}]}}
Result:
{
"content": [
{
"type": "text",
"text": "\"…\""
}
]
}
Tool call:
{"name":"account.balance","arguments":{"account":"Euro account"}}
Result:
{
"structuredContent": {
"balances": {
"commodity": "CURRENCY::EUR",
"balance": {
"num": "9200",
"denom": "100"
},
"…": "…"
},
"…": "…"
}
}
Both are kept; neither is derived from the other when a book is saved, so a change of rate later does not silently rewrite what you recorded.
Exact numbers
Amounts, values, prices and rates are exact rationals, a numerator over a denominator, never floating point. On the
wire send one as a decimal string ("12.34"), a rational string ("1234/100") or an object
({"num": "1234", "denom": "100"}); red-ale answers with the object. A JSON number is refused. This holds in every
door: JSON-RPC, MCP and the CLI.
An amount is held to its Commodity's smallest commodity unit (SCU): 100 for USD (cents), 1 for JPY, 10000 for a
typical share. When red-ale records a figure it rounds half up to the currency's fraction (values) or the Account's
SCU (amounts), and refuses a non-zero figure that would round to zero. GnuCash reduces fractions when it reads them
back (-617/50) but stores what was written (-1234/100), and red-ale does the same; compare figures by value, not by
their text.
Signs
Both value and amount use the raw sign: positive is a debit, negative a credit (Double entry). Selling shares gives the stock Account a negative value and a negative amount, and the bank Account that receives the proceeds a positive value and a positive amount.