Beancount (інструмент для ведення бухгалтерії методом подвійного запису в текстовому форматі) та Fava (його вебінтерфейс) надзвичайно розширювані та придатні для написання скриптів. Їхній дизайн дозволяє автоматизувати фінансові завдання, генерувати власні звіти та налаштовувати сповіщення за допомогою Python-скриптів. Словами одного користувача: «Мені дуже подобається мати свої дані у такому зручному форматі, і мені подобається, що я можу автоматизувати все, що заманеться. Немає API кращого за файл на вашому диску; його легко інтегрувати.» Цей посібник проведе вас через створення скриптованих робочих процесів — від автоматизації для початківців до просунутих плагінів Fava.
Ознайомтеся з живим прикладом леджера:
Почніть з командного рядка bea
Перш ніж писати будь-який Python, перевірте, чи bea вже виконує це завдання. Він перевіряє леджер, виконує BQL-запити, формує чотири фінансові звіти та імпортує банківські виписки, а глобальний --json перетворює кожен з них на придатний для парсингу конверт, який ваша оболонка може спрямувати в jq. Його коди виходу — це контракт, на який орієнтується заплановане завдання, тому cron чи CI взагалі не потребує скрипта-завантажувача. Дивіться автоматизація бухгалтерії з bea щодо визначення цілі, конверта та розгалуження за кодами виходу, і повертайтеся сюди, коли вам знадобиться власний розрахунок, який CLI не надає.
Початок роботи: запуск Beancount як Python-скрипта
Для наведених нижче власних Python-скриптів встановіть бібліотеки для скриптингу (pip install beancount beanquery beangulp). Робочі процеси команди bea натомість використовують керований рушій; дотримуйтеся швидкого старту CLI, щоб його встановити. Оскільки Beancount написано на Python, ви можете використовувати його як бібліотеку у власних скриптах. Наведені нижче скрипти виконувалися з Beancount 3.2.3, beanquery 0.2.0 та beangulp 0.2.0. Загальний підхід такий:
-
Завантажте свій леджер Beancount: Використовуйте завантажувач Beancount, щоб розібрати файл
.beancountна Python-об'єкти. Наприклад:from beancount import loader entries, errors, options = loader.load_file("myledger.beancount") if errors: for error in errors: print(error) raise SystemExit(1)Завантажувач повертає записи та помилки разом. Невирівняний або недійсний файл усе одно повертає записи, тому перевірте
errorsі зупиніться, перш ніж довіряти даним. Усі ваші рахунки, транзакції та баланси тепер доступні в коді. -
Використовуйте Beancount Query Language (BQL): Замість ручного перебору ви можете виконувати SQL-подібні запити до даних. Запити містяться в окремому пакеті
beanquery. У Beancount 3.2.3 немає модуляbeancount.query. Наприклад, щоб отримати загальні витрати за місяцями, підключіть завантажені записи та виконайте запит безпосередньо:import beanquery conn = beanquery.connect("beancount:", entries=entries, errors=errors, options=options) cur = conn.execute( "SELECT year, month, sum(position) WHERE account ~ 'Expenses' GROUP BY year, month" ) for row in cur.fetchall(): print(row)Тут використовується beanquery для агрегування даних. Це той самий рушій, що стоїть за
bea query, але тут ви викликаєте його у скрипті. Це дозволяє уникнути виклику зовнішньої команди у циклі. -
Налаштуйте структуру проєкту: Організуйте свої скрипти поряд з леджером. Поширена структура — це каталоги для імпортерів (для отримання/парсингу зовнішніх даних), звітів або запитів (для скриптів аналізу) та документів (для зберігання завантажених виписок). Наприклад, один користувач тримає:
importers/– власні Python-скрипти імпорту (з тестами),queries/– скрипти для генерації звітів (запускаються черезpython3 queries/...),documents/– завантажені банківські CSV/PDF, організовані за рахунками.
З таким налаштуванням ви можете запускати скрипти вручну (наприклад, python3 queries/cash_flow.py) або планувати їх (через cron чи планувальник завдань), щоб автоматизувати робочий процес.
Автоматизація завдань звірки
Звіряння означає переконання, що ваш леджер відповідає зовнішнім записам (банківським випискам, звітам з кредитних карток тощо). Текстовий леджер Beancount та Python API дозволяють автоматизувати значну частину цього процесу.
Імпорт та зіставлення транзакцій (для початківців)
Для початківців рекомендований підхід — використовувати імпортери з окремого пакета beangulp. Beancount 3 видалив модуль ingest версії 2 та його команду extract. Ви пишете невеликий Python-клас, що успадковує beangulp.Importer, щоб розібрати заданий формат (CSV, OFX, PDF тощо) і створити транзакції. Зареєструйте його в короткому скрипті ingest, а потім запустіть його через bea ingest у керованому рушії:
- Напишіть імпортер (Python-клас з методами
identify(),account()таextract()) для CSV-формату вашого банку. - Додайте скрипт ingest, який реєструє ваші імпортери.
bea ingestзапускає командиidentify,extractтаarchiveцього скрипта. Наприклад, один робочий процес запускаєextractдля всіх файлів у~/Downloadsі виводить транзакції до тимчасового файлу. - Вручну перегляньте та скопіюйте транзакції з тимчасового файлу до свого основного леджера, а потім запустіть
bea check, щоб переконатися, що баланси звіряються.
Мінімальний приклад: statement.csv з колонками date,description,amount, який розбирає цей імпортер (checking_importer.py):
import csv
import datetime
from beancount.core import data
from beancount.core.amount import Amount
from beancount.core.number import D
import beangulp
class CheckingImporter(beangulp.Importer):
def identify(self, filepath: str) -> bool:
return filepath.endswith("statement.csv")
def account(self, filepath: str) -> str:
return "Assets:Bank:Checking"
def extract(self, filepath: str, existing):
entries = []
with open(filepath, newline="") as f:
for row in csv.DictReader(f):
date = datetime.date.fromisoformat(row["date"])
amount = Amount(D(row["amount"]), "USD")
meta = data.new_metadata(filepath, 0)
entries.append(
data.Transaction(
meta, date, "*", None, row["description"],
data.EMPTY_SET, data.EMPTY_SET, [
data.Posting("Expenses:Food:Groceries", amount,
None, None, None, None),
data.Posting("Assets:Bank:Checking",
Amount(-amount.number, "USD"),
None, None, None, None),
]))
return entriesСкрипт ingest (ingest.py) підключає його:
from checking_importer import CheckingImporter
from beangulp import Ingest
ingest = Ingest([CheckingImporter()])
if __name__ == "__main__":
ingest()Запустіть його для завантаженого файлу. Для локального CSV облікові дані не потрібні. Спочатку встановіть системну бібліотеку libmagic. Одноразова команда ввімкнення завантажує Beangulp до керованого рушія:
bea engine enable beangulp
bea ingest identify --config ingest.py statement.csv
bea ingest extract --config ingest.py statement.csv -o new.beancountidentify повідомляє checking_importer.CheckingImporter для цього файлу. extract записує транзакції у форматі Beancount:
2024-01-08 * "Grocery Store"
Expenses:Food:Groceries 120.00 USD
Assets:Bank:Checking -120.00 USDПерегляньте new.beancount, скопіюйте записи до свого основного леджера та запустіть bea check.
Вам не потрібно писати імпортер, щоб конвертувати одну виписку. Вставте файл у конвертер CSV у Beancount або скористайтеся OFX & QIF у Beancount для завантажень .ofx, .qfx та .qif. Обидва працюють повністю у вашому браузері, тож виписка ніколи не залишає вашу машину.
Хоча цей процес усе ще включає крок перегляду, значна частина рутинної роботи з парсингу та форматування записів автоматизована. Скрипти імпортерів також можуть автоматично призначати категорії та навіть встановлювати твердження щодо балансу (заяви про очікувані баланси), щоб виявляти розбіжності. Наприклад, після імпорту у вас може з'явитися рядок 2025-04-30 balance Assets:Bank:Checking 1234.56 USD, який стверджує кінцевий баланс. Коли ви запускаєте bea check, Beancount перевірить, що всі ці твердження щодо балансу є правильними, і позначить будь-які помилки, якщо транзакції відсутні або дублюються. Це найкраща практика: автоматично генеруйте твердження щодо балансу для кожного періоду виписки, щоб дозволити комп'ютеру виявляти незвірені розбіжності за вас.
Кастомні скрипти звірки (середній рівень)
Для більшого контролю ви можете написати власний Python-скрипт, щоб порівняти список транзакцій банку (CSV або через API) з записами вашого леджера:
- Зчитайте зовнішні дані: Розберіть CSV-файл банку за допомогою модуля
csvу Python (або Pandas). Нормалізуйте дані у список транзакцій, наприклад, кожна з датою, сумою та описом. - Завантажте транзакції леджера: Використайте
loader.load_file, як показано раніше, щоб отримати всі записи леджера. Відфільтруйте цей список до потрібного рахунку (наприклад, вашого поточного рахунку) і, можливо, до діапазону дат виписки. - Порівняйте та знайдіть розбіжності:
- Для кожної зовнішньої транзакції перевірте, чи існує ідентичний запис у леджері (зіставлення за датою та сумою, можливо, за описом). Якщо не знайдено, позначте її як «нову» і, можливо, виведіть її як транзакцію у форматі Beancount для вашого перегляду.
- І навпаки, виявіть будь-які записи леджера на цьому рахунку, яких немає у зовнішньому джерелі — це можуть бути помилки введення даних або транзакції, які ще не пройшли через банк.
- Виведіть результати: Надрукуйте звіт або створіть новий фрагмент
.beancountз відсутніми транзакціями.
Як приклад, скрипт спільноти під назвою reconcile.py робить саме це: отримуючи файл Beancount та вхідний CSV, він виводить список нових транзакцій, які слід імпортувати, а також будь-які наявні проводки в леджері, яких немає у вхідних даних (що потенційно може свідчити про неправильну класифікацію). З таким скриптом щомісячне звіряння може бути таким простим, як запуск скрипта та додавання запропонованих транзакцій до вашого леджера. Один користувач Beancount зазначає, що він «проводить процес звіряння для всіх рахунків щомісяця» і використовує зростаючу колекцію Python-коду, щоб усунути значну частину ручної роботи з імпорту та звіряння даних.
Порада: Під час звіряння використовуйте інструменти Beancount для точності:
- Використовуйте твердження щодо балансу, як згадано, для автоматичних перевірок балансів рахунків.
- За потреби використовуйте директиву
pad, яка може автоматично вставляти врівноважувальні записи для незначних розбіжностей округлення (використовуйте з обережністю). - Пишіть модульні тести для вашої логіки імпорту або звіряння (Beancount надає допоміжні засоби для тестування). Наприклад, один робочий процес включав взяття зразкового CSV, написання невдалих тестів з очікуваними транзакціями, а потім реалізацію імпортера, доки всі тести не пройшли. Це гарантує, що ваш скрипт імпорту коректно працює для різних випадків.
Створення власних звітів та підсумків
Хоча Fava надає багато стандартних звітів (звіт про прибутки та збитки, баланс тощо), ви можете створювати власні звіти за допомогою скриптів. Вони можуть варіюватися від простих консольних виводів до багато форматування файлів чи діаграм.
Запити даних для звітів (Початківець)
На базовому рівні ви можете використовувати Beancount Query Language (BQL), щоб отримати зведені дані та надрукувати або зберегти їх. Наприклад:
-
Зведення грошових потоків: Використайте запит, щоб обчислити чистий грошовий потік. «Грошовий потік» можна визначити як зміну балансу певних рахунків за період. За допомогою BQL ви можете зробити:
SELECT year, month, sum(position) WHERE account ~ 'Income' OR account ~ 'Expenses' GROUP BY year, monthЦе зводить усі проводки доходів і витрат за місяцями. Фільтруйте за допомогою
~та регулярного виразу:LIKEє синтаксичною помилкою в beanquery 0.2.0. Проводки містятьposition, а неamount. Кожен рядок містить один Inventory, тому кожна валюта вказується окремо, а не конвертується. Доходи надходять від'ємними, а витрати додатними. Ви можете запустити це черезbea queryабо через Python API beanquery, показаний раніше, а потім відформатувати результат. -
Звіт про витрати за категоріями: Запит загальних витрат за категоріями:
SELECT account, sum(position) WHERE account ~ 'Expenses' GROUP BY account ORDER BY sum(position) ASCЦе дає таблицю витрат за категоріями. Кожен підсумок — це Inventory у своїй початковій валюті. Не обгортайте агрегат у
round(): немає функціїround(inventory, int), тожround(sum(position), 2)не компілюється. Ви можете виконати кілька запитів у скрипті та вивести результати як текст, CSV або навіть JSON для подальшої обробки.
Один користувач вважав «тривіальним» аналіз фінансових даних за допомогою Fava або скриптів, зазначаючи, що він використовує один Python-скрипт, щоб витягти дані з Beancount через Query Language, а потім помістити їх у Pandas DataFrame для підготовки власного звіту. Наприклад, ви можете отримати місячні підсумки запитом, а потім за допомогою Pandas/Matplotlib побудувати діаграму грошових потоків у часі. Поєднання BQL та бібліотек для науки про дані дозволяє будувати звіти поза межами того, що Fava пропонує за замовчуванням.
Розширене звітування (діаграми, продуктивність тощо)
Для більш просунутих потреб ваші скрипти можуть обчислювати такі метрики, як продуктивність інвестицій, або створювати візуальні результати:
-
Продуктивність інвестицій (IRR/XIRR): Оскільки ваш леджер містить усі грошові потоки (купівлі, продажі, дивіденди), ви можете розрахувати ставки доходності портфеля. Наприклад, ви можете написати скрипт, який фільтрує транзакції ваших інвестиційних рахунків, а потім обчислює внутрішню норму доходності (IRR). Існують бібліотеки (або формули) для обчислення IRR за даними грошових потоків. Деякі розроблені спільнотою розширення Fava (як-от PortfolioSummary чи fava_investor) роблять саме це, обчислюючи IRR та інші метрики для інвестиційних портфелів. Як скрипт, ви можете використати функцію IRR (з NumPy чи власну) для серії внесків/вилучень плюс кінцевої вартості.
-
Багатоперіодні або власні метрики: Хочете звіт про вашу норму заощаджень (відношення заощаджень до доходу) щомісяця? Python-скрипт може завантажити леджер, підсумувати всі рахунки доходів і всі рахунки витрат, а потім обчислити заощадження = дохід − витрати та відсоток. Це може вивести гарну таблицю або навіть згенерувати HTML/Markdown-звіт для ваших записів.
-
Візуалізація: Ви можете генерувати діаграми поза Fava. Наприклад, використайте
matplotlibабоaltairу скрипті, щоб створити діаграму чистої вартості у часі, використовуючи дані леджера. Оскільки леджер містить усі історичні баланси (або ви можете накопичити їх, перебираючи записи), ви можете побудувати часові ряди. Зберігайте ці діаграми як зображення або інтерактивний HTML. (Якщо ви віддаєте перевагу візуалізаціям у застосунку, дивіться розділ про розширення Fava нижче, щоб додати діаграми всередині Fava.)
Варіанти виведення: Вирішіть, як доставити звіт:
- Для одноразового аналізу може бути достатньо виведення на екран або збереження у файл CSV/Excel.
- Для дашбордів розгляньте генерацію HTML-файлу з даними (можливо, з використанням бібліотеки шаблонів, як-от Jinja2, або навіть просто написання Markdown), який ви можете відкрити в браузері.
- Ви також можете інтегруватися з Jupyter Notebooks для інтерактивного середовища звітності, хоча це більше для дослідження, ніж для автоматизації.
Тригери сповіщень з вашого журналу
Ще одне потужне застосування скриптованих робочих процесів — це налаштування сповіщень на основі умов у ваших фінансових даних. Оскільки ваш леджер регулярно оновлюється (і може містити записи з майбутніми датами, як-от майбутні рахунки чи бюджети), ви можете сканувати його скриптом і отримувати повідомлення про важливі події.
Попередження про низький баланс рахунку
Щоб уникнути овердрафтів або підтримувати мінімальний баланс, вам може знадобитися сповіщення, якщо будь-який рахунок (наприклад, поточний чи ощадний) опускається нижче порогу. Ось як це реалізувати:
-
Визначте поточні баланси: Після завантаження
entriesчерез завантажувач обчисліть останній баланс потрібних рахунків. Ви можете зробити це, агрегуючи проводки або використовуючи запит. Наприклад, використайте BQL-запит для балансу конкретного рахунку:SELECT sum(position) WHERE account = 'Assets:Bank:Checking'Це повертає поточний баланс цього рахунку (суму всіх його проводок). Як альтернативу, використайте внутрішні функції Beancount, щоб побудувати баланс. Наприклад:
from beancount.core import realization tree = realization.realize(entries) acct = realization.get_or_create(tree, "Assets:Bank:Checking") balance = acct.balance # an Inventory of commoditiesПередавайте лише записи: другий параметр — це
min_accounts, а не мапа опцій. Потім витягніть числове значення (наприклад,balance.get_currency_units('USD')повертає суму в Decimal у доларах США). Як і агрегат запиту, баланс зберігає кожну валюту окремо. Однак використання запиту простіше для більшості випадків. -
Перевірте поріг: Порівняйте баланс з вашим заздалегідь визначеним лімітом. Якщо нижче — запустіть сповіщення.
-
Запустіть повідомлення: Це може бути так само просто, як виведення попередження в консоль, але для справжніх сповіщень ви можете надіслати електронного листа або push-повідомлення. Ви можете інтегруватися з електронною поштою (через
smtplib) або сервісом, як-от IFTTT чи webhook API Slack, щоб надіслати сповіщення. Наприклад:if balance < 1000: send_email("Low balance alert", f"Account XYZ balance is {balance}")(Реалізуйте
send_emailз деталями вашого поштового сервера.)
Запускаючи цей скрипт щодня (через завдання cron або Планувальник завдань Windows), ви отримаєте проактивні попередження. Оскільки він використовує леджер, він може враховувати всі транзакції, включаючи ті, які ви щойно додали.
Майбутні терміни платежів
Якщо ви використовуєте Beancount для відстеження рахунків або термінів, ви можете позначати майбутні платежі та мати скрипти, що нагадують вам. Два способи представлення майбутніх зобов'язань у Beancount:
-
Події (Events): Beancount підтримує директиву
eventдля довільних датованих нотаток. Наприклад:2025-05-10 event "BillDue" "Mortgage payment due"Це не впливає на баланси, але фіксує дату з міткою. Скрипт може сканувати
entriesна записиEvent, деEvent.type == "BillDue"(або будь-який власний тип, який ви оберете), і перевіряти, чи дата в межах, скажімо, наступних 7 днів від сьогодні. Якщо так — запустіть сповіщення (електронний лист, повідомлення або навіть спливне вікно). -
Майбутні транзакції: Деякі люди вводять транзакції з майбутніми датами (дата в майбутньому) для таких речей, як заплановані платежі. Вони не з'являться в балансах, доки дата не настане (якщо ви не запускаєте звіти станом на майбутні дати). Скрипт може шукати транзакції з датами в найближчому майбутньому та перелічувати їх.
Використовуючи це, ви можете створити скрипт-«нагадувач», який при запуску виводить список завдань або рахунків, термін сплати яких наближається. Інтегруйтеся з API, як-от Google Calendar чи менеджер завдань, якщо хочете автоматично створювати там нагадування.
Виявлення Аномалій
Окрім відомих порогів чи дат, ви можете написати скрипти для власних сповіщень про незвичайні закономірності. Наприклад, якщо зазвичай щомісячна витрата не відбулася (можливо, ви забули сплатити рахунок), або якщо витрати категорії цього місяця аномально високі, ваш скрипт може це позначити. Зазвичай це передбачає запит останніх даних і порівняння з історією (що може бути просунутою темою — можливо, із застосуванням статистики чи ML).
На практиці багато користувачів покладаються на звіряння, щоб виявляти аномалії (неочікувані транзакції). Якщо ви отримуєте банківські повідомлення (як-от електронні листи для кожної транзакції), ви можете розібрати їх скриптом і автоматично додати до Beancount, або принаймні перевірити, що вони зафіксовані. Один ентузіаст навіть налаштував свій банк надсилати електронні листи зі сповіщеннями про транзакції, з планом автоматично розбирати їх і додавати до леджера. Такий подієво-орієнтований підхід може гарантувати, що жодна транзакція не залишиться незафіксованою.
Розширення Fava за допомогою користувацьких плагінів і виглядів
Fava вже придатна для скриптингу через свою систему розширень. Якщо ви хочете, щоб ваша автоматизація чи звіти інтегрувалися безпосередньо у вебінтерфейс, ви можете написати розширення Fava (також зване плагіном) на Python.
Як працюють розширення Fava: Розширення — це Python-модуль, який визначає клас, що успадковує fava.ext.FavaExtensionBase. Ви реєструєте його у своєму файлі Beancount через власну опцію. Наприклад, якщо у вас є файл myextension.py з класом MyAlerts(FavaExtensionBase), ви можете ввімкнути його, додавши до свого леджера:
1970-01-01 custom "fava-extension" "myextension"Коли Fava завантажується, вона імпортує цей модуль і ініціалізує ваш клас MyAlerts.
Розширення можуть робити кілька речей:
- Хуки (Hooks): Вони можуть підключатися до подій у життєвому циклі Fava. Наприклад,
after_load_file()викликається після завантаження леджера. Ви можете використати це для запуску перевірок або попереднього обчислення даних. Якщо ви хотіли реалізувати перевірку низького балансу всередині Fava,after_load_fileміг би перебирати баланси рахунків і, можливо, зберігати попередження (хоча виведення їх в UI може вимагати трохи більше роботи, як-от виклик FavaAPIError або використання Javascript для показу повідомлення). - Власні звіти/сторінки: Якщо ваш клас розширення встановлює атрибут
report_title, Fava додасть нову сторінку для нього в бічній панелі. Потім ви надаєте шаблон (HTML/Jinja2) для вмісту цієї сторінки. Саме так ви створюєте цілком нові представлення, як-от дашборд чи зведення, яких Fava не має за замовчуванням. Розширення може зібрати будь-які потрібні йому дані (ви можете отримати доступ доself.ledger, який містить усі записи, баланси тощо), а потім відрендерити шаблон.
Наприклад, вбудоване розширення portfolio_list у Fava додає сторінку зі списком ваших позицій портфеля. Розширення спільноти йдуть далі:
- Дашборди: Плагін fava-dashboards дозволяє визначати власні діаграми та панелі (використовуючи бібліотеки, як-от Apache ECharts). Він читає YAML-конфігурацію запитів для виконання, виконує їх через Beancount і генерує динамічну сторінку дашборду у Fava. По суті, він поєднує дані Beancount та бібліотеку діаграм JavaScript для створення інтерактивних візуалізацій.
- Аналіз портфеля: Розширення PortfolioSummary (від користувача) обчислює інвестиційні зведення (групування рахунків, обчислення IRR тощо) і відображає їх в UI Fava.
- Перегляд транзакцій: Інше розширення, fava-review, допомагає переглядати транзакції у часі (наприклад, щоб переконатися, що ви не пропустили жодного чека).
Щоб створити просте розширення самостійно, почніть з успадкування FavaExtensionBase. Наприклад, мінімальне розширення, яке додає сторінку, може виглядати так:
from fava.ext import FavaExtensionBase
class HelloReport(FavaExtensionBase):
report_title = "Hello World"
def __init__(self, ledger, config):
super().__init__(ledger, config)
# any initialization, perhaps parse config if provided
def after_load_file(self):
# (optional) run after ledger is loaded
print("Ledger loaded with", len(self.ledger.entries), "entries")Якщо ви розмістите це у hello.py і додасте custom "fava-extension" "hello" до свого леджера, Fava покаже нову сторінку "Hello World" (вам також знадобиться файл шаблону HelloReport.html у підпапці templates, щоб визначити вміст сторінки, якщо розширення не використовує лише хуки). Шаблон може використовувати дані, які ви прикріпили до класу розширення. Fava використовує шаблони Jinja2, тож ви можете відрендерити свої дані в HTML-таблицю чи діаграму в цьому шаблоні.
Примітка: Система розширень Fava потужна, але вважається «нестабільною» (може змінюватися). Вона вимагає певної обізнаності з веброзробкою (HTML/JS), якщо ви робите власні сторінки. Якщо ваша мета — просто запускати скрипти чи аналізи, можливо, простіше залишити їх зовнішніми скриптами. Використовуйте розширення Fava, коли хочете налаштований досвід у застосунку для вашого робочого процесу.
Інтеграція сторонніх API та даних
Одна з переваг скриптованих робочих процесів — можливість залучати зовнішні дані. Ось поширені інтеграції:
Для цін оцінки на хостингу Live Prices пропонує керовані включення без запланованого скрипта для отримання цін. Виберіть підтримувані пари активів і валюту котирування у вибірнику. Наведені нижче локальні робочі процеси на основі файлів залишаються корисними для upstream Beancount, Fava та відтворюваних звітів. Кероване оновлення не створює Git-коміт у вашому леджері.
-
Курси обміну та товари: Upstream Beancount сам не отримує ціни, але надає директиву
price, щоб ви могли вказати курси. Ви можете автоматизувати отримання цих цін. Наприклад, скрипт може запитати API (Yahoo Finance, Alpha Vantage тощо) про останній курс обміну або ціну акції та додати запис ціни до вашого леджера:2025-04-30 price BTC 30000 USD 2025-04-30 price EUR 1.10 USDІснують інструменти, як-от
bea price, що базуються на Beanprice у керованому рушії, які отримують щоденні котирування та виводять їх у форматі Beancount. Ви можете ввімкнути його один раз за допомогоюbea engine enable beanprice, а потім заплануватиbea price main.beancountна кожну ніч, щоб оновлювати включений файлprices.beancount. Або використайте Python: наприклад, з бібліотекоюrequestsдля виклику API. Документація Beancount пропонує, що для публічно торгованих активів ви можете «викликати код, який завантажить ціни та запише директиви за вас». Іншими словами, дозвольте скрипту робити пошук і вставляти рядкиpriceзамість вас. -
Дані про фондовий портфель: Подібно до курсів обміну, ви можете інтегруватися з API, щоб отримати детальні дані про акції чи дивіденди. Наприклад, API Yahoo Finance (або бібліотеки спільноти, як-от
yfinance) може отримати історичні дані для тікера. Скрипт може оновлювати ваш леджер місячною історією цін для кожної акції, якою ви володієте, що дозволяє точні історичні звіти про ринкову вартість. Деякі власні розширення (як-от fava_investor) навіть отримують дані про ціни на льоту для відображення, але найпростіше — регулярно імпортувати ціни в леджер. -
Банківські API (Open Banking/Plaid): Замість завантаження CSV ви можете використовувати API для автоматичного отримання транзакцій. Сервіси, як-от Plaid, агрегують банківські рахунки та надають програмний доступ до транзакцій. У просунутому налаштуванні ви могли б мати Python-скрипт, який використовує API Plaid для щоденного отримання нових транзакцій і збереження їх у файл (або безпосереднього імпорту в леджер). Один досвідчений користувач побудував систему, де Plaid живить його конвеєр імпорту, роблячи його книги майже автоматичними. Він зазначає, що «ніщо не заважає вам зареєструватися в Plaid API і робити те саме локально» — тобто ви можете написати локальний скрипт для отримання банківських даних, а потім використати логіку імпортера Beancount, щоб розібрати їх на записи леджера. У деяких регіонах банки надають API відкритого банкінгу; їх можна використовувати подібним чином.
-
Інші API: Ви можете інтегрувати інструменти бюджетування (експорт запланованих бюджетів для порівняння з фактичними в Beancount) або використати API OCR для читання чеків і автоматичного зіставлення їх з транзакціями. Оскільки ваші скрипти мають повний доступ до екосистеми Python, ви можете інтегрувати все — від поштових сервісів (для надсилання сповіщень) до Google Sheets (наприклад, оновлення таблиці з місячними фінансовими метриками) до месенджерів (надіслати собі зведений звіт через бота Telegram).
Використовуючи сторонні API, пам'ятайте про захист своїх облікових даних (використовуйте змінні середовища або конфігураційні файли для ключів API) та коректно обробляйте помилки (проблеми з мережею, збої API) у ваших скриптах. Часто розумно кешувати дані (наприклад, зберігати отримані курси обміну, щоб не запитувати той самий історичний курс повторно).
Найкращі практики для модульних, підтримуваних скриптів
У міру розбудови скриптованих робочих процесів тримайте свій код організованим і надійним:
-
Модульність: Розділіть різні задачі на різні скрипти чи модулі. Наприклад, майте окремі скрипти для «імпорту даних/звіряння», «генерації звітів» і «сповіщень». Ви можете навіть створити невеликий Python-пакет для свого леджера з модулями, як-от
ledger_import.py,ledger_reports.pyтощо. Це робить кожну частину простішою для розуміння та тестування. -
Конфігурація: Уникайте жорсткого кодування значень. Використовуйте конфігураційний файл або змінні на початку скрипта для таких речей, як назви рахунків, пороги, ключі API, діапазони дат тощо. Це дозволяє легко змінювати без глибокого редагування коду. Наприклад, визначте
LOW_BALANCE_THRESHOLDS = {"Assets:Bank:Checking": 500, "Assets:Savings": 1000}на початку, і ваш скрипт сповіщень може перебирати цей словник. -
Тестування: Ставтеся до своєї фінансової автоматизації як до критично важливого коду — бо це так і є! Пишіть тести для складної логіки. Beancount надає деякі допоміжні засоби для тестування (використовуються внутрішньо для тестування імпортерів), які ви можете використати для імітації вхідних даних леджера. Навіть без складних фреймворків ви можете мати фіктивний CSV та очікувані вихідні транзакції і перевіряти, що ваш скрипт імпорту створює правильні записи. Якщо ви використовуєте
pytest, ви можете легко інтегрувати ці тести (як зробив Alex Watt через командуjust test, що обгортає pytest). -
Контроль версій: Тримайте свій леджер і скрипти під контролем версій (git). Це не лише дає резервні копії та історію, але й заохочує вносити зміни контрольованим чином. Ви можете позначати релізи своїх «фінансових скриптів» або переглядати відмінності під час налагодження проблеми. Деякі користувачі навіть відстежують свої фінансові записи в Git, щоб бачити зміни з часом. Просто подбайте про ігнорування чутливих даних (як-от необроблені файли виписок чи ключі API) у своєму репозиторії.
-
Документація: Задокументуйте свої власні робочі процеси для майбутнього себе. README у вашому репозиторії, який пояснює, як налаштувати середовище, як запускати кожен скрипт і що кожен робить, буде безцінним через місяці. Також коментуйте свій код, особливо будь-яку неочевидну бухгалтерську логіку чи взаємодію з API.
-
Підтримка плагінів Fava: Якщо ви пишете розширення Fava, тримайте його простим. Fava може змінюватися, тож менші розширення з цільовою функціональністю легше оновлювати. Уникайте дублювання надто великої кількості логіки — використовуйте рушій запитів Beancount чи наявні допоміжні функції, коли можливо, замість жорсткого кодування розрахунків, які можуть бути чутливими до змін у леджері.
-
Безпека: Оскільки ваші скрипти можуть обробляти чутливі дані та підключатися до зовнішніх сервісів, ставтеся до них з обережністю. Не розкривайте ключі API та розгляньте можливість запуску вашої автоматизації на захищеній машині. Якщо ви використовуєте хостингове рішення чи хмару (як-от планування GitHub Actions чи сервер для запуску Fava), переконайтеся, що дані вашого леджера зашифровані у стані спокою, і що ви комфортно почуваєтеся з наслідками для приватності.
Дотримуючись цих практик, ви забезпечуєте надійність свого робочого процесу навіть у міру того, як ваші фінанси (і самі інструменти) розвиваються. Ви хочете мати скрипти, які можна використовувати рік за роком з мінімальними правками.
Висновок
Beancount і Fava забезпечують потужну, гнучку платформу для технічно підкованих користувачів, щоб повністю налаштувати відстеження особистих фінансів. Пишучи Python-скрипти, ви можете автоматизувати нудні завдання, як-от звіряння виписок, створювати багаті звіти, пристосовані до ваших потреб, і тримати фінанси під контролем завдяки своєчасним сповіщенням. Ми розглянули низку прикладів від базових до просунутих — починаючи з простих запитів та імпорту CSV і переходячи до повноцінних плагінів Fava та інтеграцій зі сторонніми API. Впроваджуючи їх, починайте з простого та поступово нарощуйте. Навіть кілька невеликих скриптів автоматизації можуть зекономити години роботи та суттєво підвищити точність. І пам'ятайте: оскільки все є текстом і Python, ви маєте повний контроль — ваша фінансова система зростає разом з вами, підлаштовуючись під ваші конкретні потреби. Щасливого скриптингу!
Джерела: Наведені вище техніки взяті з документації Beancount і досвіду спільноти. Для подальшого читання дивіться офіційну документацію Beancount, посібники та блоги спільноти, а також репозиторій Awesome Beancount щодо посилань на корисні плагіни та інструменти.