Multiple currencies
Keep an account in a foreign currency, buy that currency, spend it, and record the exchange rate, with each split's value in the transaction currency and its amount in the account's.
If you hold money in a foreign currency, give it an account in that currency. The book then keeps two numbers for every split, and they are not the same thing:
- the split's value is in the transaction's currency, the one the transaction as a whole is in;
- the split's amount is in the account's commodity, which can be another currency.
For a purchase of 100.00 EUR for 108.50 USD, the euro account's split has an amount of 100.00 (euros) and a value of 108.50 (dollars); the dollar account's split has both equal to 108.50. The values sum to zero, and the ratio of value to amount is the exchange rate.
Steps
- Create the account with account.create, with
commodityset to the currency's code (EUR). The currencies GnuCash knows are in currency.list; you do not create them. - Say which currency the transaction is in. transaction.post uses the first split's
account commodity unless you set
currency, so when the first split is in the foreign currency, passcurrencyexplicitly. A split whose account is in another commodity than the transaction needs itsamount. - Buy the currency: post the transaction in your home currency, with the euro split carrying both
valueandamount. For a simple move between your own accounts, transaction.transfer with aratedoes the same, and records the rate. - Record the rate for reports with price.add, so that balances can be shown in one currency.
transaction.postrecords a price from a priced split when you passrecordPrice: true. - Spend the currency: a transaction in USD whose euro split has
value: -54.25andamount: -50.00takes 50.00 EUR out of the euro account for a 54.25 USD expense. - Check with account.balance. A balance is in the account's own commodity; the price.list shows the rates the book has.
If your book uses trading accounts, see Use trading accounts.
Example
Example: with a new, empty book open as book.gnucash, at 2024-07-15T12:00:00Z.
JSON-RPC
Request:
{"jsonrpc":"2.0","id":1,"method":"account.create","params":{"name":"Checking","type":"BANK","commodity":"USD"}}
Response:
{
"jsonrpc": "2.0",
"id": 1,
"result": "…"
}
Request:
{"jsonrpc":"2.0","id":2,"method":"account.create","params":{"name":"Euro Bank","type":"BANK","commodity":"EUR"}}
Response:
{
"jsonrpc": "2.0",
"id": 2,
"result": {
"commodity": "CURRENCY::EUR",
"…": "…"
}
}
Request:
{"jsonrpc":"2.0","id":3,"method":"account.create","params":{"name":"Travel","type":"EXPENSE","commodity":"USD"}}
Response:
{
"jsonrpc": "2.0",
"id": 3,
"result": "…"
}
Request:
{"jsonrpc":"2.0","id":4,"method":"transaction.post","params":{"datePosted":"2024-07-02","description":"Buy euros","currency":"USD","splits":[{"account":"Euro Bank","value":"108.50","amount":"100.00"},{"account":"Checking","value":"-108.50"}]}}
Response:
{
"jsonrpc": "2.0",
"id": 4,
"result": {
"currency": "CURRENCY::USD",
"balanced": true,
"splits": [
{
"accountName": "Euro Bank",
"value": {
"num": "10850",
"denom": "100"
},
"amount": {
"num": "10000",
"denom": "100"
},
"…": "…"
},
{
"accountName": "Checking",
"…": "…"
}
],
"…": "…"
}
}
Request:
{"jsonrpc":"2.0","id":5,"method":"price.add","params":{"commodity":"EUR","currency":"USD","value":"1.0850","date":"2024-07-02"}}
Response:
{
"jsonrpc": "2.0",
"id": 5,
"result": {
"outcome": "added",
"…": "…"
}
}
Request:
{"jsonrpc":"2.0","id":6,"method":"transaction.post","params":{"datePosted":"2024-07-10","description":"Hotel in Lyon","currency":"USD","splits":[{"account":"Travel","value":"54.25"},{"account":"Euro Bank","value":"-54.25","amount":"-50.00"}]}}
Response:
{
"jsonrpc": "2.0",
"id": 6,
"result": {
"balanced": true,
"…": "…"
}
}
Request:
{"jsonrpc":"2.0","id":7,"method":"account.balance","params":{"account":"Euro Bank"}}
Response:
{
"jsonrpc": "2.0",
"id": 7,
"result": {
"balances": {
"commodity": "CURRENCY::EUR",
"balance": {
"num": "5000",
"denom": "100"
},
"…": "…"
},
"…": "…"
}
}
Command line
red-ale exec --book book.gnucash --script - <<'EOF'
account.create {"name":"Checking","type":"BANK","commodity":"USD"}
account.create {"name":"Euro Bank","type":"BANK","commodity":"EUR"}
account.create {"name":"Travel","type":"EXPENSE","commodity":"USD"}
transaction.post {"datePosted":"2024-07-02","description":"Buy euros","currency":"USD","splits":[{"account":"Euro Bank","value":"108.50","amount":"100.00"},{"account":"Checking","value":"-108.50"}]}
price.add {"commodity":"EUR","currency":"USD","value":"1.0850","date":"2024-07-02"}
transaction.post {"datePosted":"2024-07-10","description":"Hotel in Lyon","currency":"USD","splits":[{"account":"Travel","value":"54.25"},{"account":"Euro Bank","value":"-54.25","amount":"-50.00"}]}
account.balance {"account":"Euro Bank"}
EOF
It prints:
[
"…",
{
"commodity": "CURRENCY::EUR",
"…": "…"
},
"…",
{
"currency": "CURRENCY::USD",
"balanced": true,
"splits": [
{
"accountName": "Euro Bank",
"value": {
"num": "10850",
"denom": "100"
},
"amount": {
"num": "10000",
"denom": "100"
},
"…": "…"
},
{
"accountName": "Checking",
"…": "…"
}
],
"…": "…"
},
{
"outcome": "added",
"…": "…"
},
{
"balanced": true,
"…": "…"
},
{
"balances": {
"commodity": "CURRENCY::EUR",
"balance": {
"num": "5000",
"denom": "100"
},
"…": "…"
},
"…": "…"
}
]
MCP tool call
Tool call:
{"name":"account.create","arguments":{"name":"Checking","type":"BANK","commodity":"USD"}}
Result:
{
"content": [
{
"type": "text",
"text": "\"…\""
}
]
}
Tool call:
{"name":"account.create","arguments":{"name":"Euro Bank","type":"BANK","commodity":"EUR"}}
Result:
{
"structuredContent": {
"commodity": "CURRENCY::EUR",
"…": "…"
}
}
Tool call:
{"name":"account.create","arguments":{"name":"Travel","type":"EXPENSE","commodity":"USD"}}
Result:
{
"content": [
{
"type": "text",
"text": "\"…\""
}
]
}
Tool call:
{"name":"transaction.post","arguments":{"datePosted":"2024-07-02","description":"Buy euros","currency":"USD","splits":[{"account":"Euro Bank","value":"108.50","amount":"100.00"},{"account":"Checking","value":"-108.50"}]}}
Result:
{
"structuredContent": {
"currency": "CURRENCY::USD",
"balanced": true,
"splits": [
{
"accountName": "Euro Bank",
"value": {
"num": "10850",
"denom": "100"
},
"amount": {
"num": "10000",
"denom": "100"
},
"…": "…"
},
{
"accountName": "Checking",
"…": "…"
}
],
"…": "…"
}
}
Tool call:
{"name":"price.add","arguments":{"commodity":"EUR","currency":"USD","value":"1.0850","date":"2024-07-02"}}
Result:
{
"structuredContent": {
"outcome": "added",
"…": "…"
}
}
Tool call:
{"name":"transaction.post","arguments":{"datePosted":"2024-07-10","description":"Hotel in Lyon","currency":"USD","splits":[{"account":"Travel","value":"54.25"},{"account":"Euro Bank","value":"-54.25","amount":"-50.00"}]}}
Result:
{
"structuredContent": {
"balanced": true,
"…": "…"
}
}
Tool call:
{"name":"account.balance","arguments":{"account":"Euro Bank"}}
Result:
{
"structuredContent": {
"balances": {
"commodity": "CURRENCY::EUR",
"balance": {
"num": "5000",
"denom": "100"
},
"…": "…"
},
"…": "…"
}
}