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 (для отримання/парсингу зовнішніх даних), reports або queries (для аналітичних скриптів) і documents (для зберігання завантажених виписок). Наприклад, один користувач зберігає:
importers/– власні Python-скрипти для імпорту (з тестами),queries/– скрипти для генерації звітів (запускаються черезpython3 queries/...),documents/– завантажені банківські CSV/PDF, організовані за рахунками.
З такою налаштуванням ви можете запускати скрипти вручну (наприклад, python3 queries/cash_flow.py) або планувати їх виконання (через cron чи task runner) для автоматизації робочого процесу.
Автоматизація завдань звірки
Звірка означає переконатися, що ваша бухгалтерська книга відповідає зовнішнім даним (банківським випискам, звітам по кредитних картках тощо). Текстова бухгалтерська книга Beancount і Python API дозволяють автоматизувати більшість цього процесу.
Імпорт та зіставлення транзакцій (для початківців)
Для початківців рекомендовано використовувати importers із окремого пакету beangulp. У Beancount 3 було видалено модуль v2 ingest та його команду extract. Ви пишете невеликий клас Python, який успадковує beangulp.Importer для парсингу певного формату (CSV, OFX, PDF тощо) і створення транзакцій. Реєструєте його у короткому ingset-скрипті, а тоді запускаєте через bea ingest у керованому двигуні:
- Напишіть імпортер (клас Python з методами
identify(),account()іextract()) для формату CSV вашого банку. - Додайте скрипт завантаження, який реєструє ваші імпортери.
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.py) підключає це:
from checking_importer import CheckingImporter
from beangulp import Ingest
ingest = Ingest([CheckingImporter()])
if __name__ == "__main__":
ingest()Запустіть його для завантаженого файлу. Для локального CSV не потрібні облікові дані. Спершу встановіть системну бібліотеку libmagic. Одноразова команда enable завантажує 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 to Beancount converter або використайте OFX & QIF to Beancount для завантажень .ofx, .qfx та .qif. Обидва працюють повністю у вашому браузері, тож звіт ніколи не залишає вашу машину.
Хоч цей процес і містить крок перегляду, більшість громіздкої роботи з парсингу й форматування записів автоматизована. Скрипти імпортера також можуть автоматично призначати категорії та навіть встановлювати балансні підтвердження (заяви про очікувані баланси) для виявлення розбіжностей. Наприклад, після імпорту ви можете мати рядок типу 2025-04-30 balance Assets:Bank:Checking 1234.56 USD, який підтверджує кінцевий баланс. Коли ви запускаєте bea check, Beancount перевіряє, чи всі ці балансні підтвердження правильні, і позначає помилки, якщо транзакції відсутні або дубльовані. Це краща практика: автоматично генерувати підтвердження балансу за кожен період звіту, щоб комп’ютер міг виявляти незвірені різниці для вас.
Кастомні скрипти звірки (середній рівень)
Для більшого контролю ви можете написати кастомний Python-скрипт для порівняння списку транзакцій банку (CSV або через API) з вашими записами в книзі:
- Прочитайте зовнішні дані: Розберіть CSV-файл банку, використовуючи модуль Python
csv(або 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або за допомогою API beanquery для Python, наведене раніше, а потім відформатувати результат. -
Звіт по категоріях витрат: Зробіть запит загальних витрат по категоріях:
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 за даними грошових потоків. Деякі розширення 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 у USD). Як і в агрегаті запиту, баланс зберігає кожну валюту окремо. Проте використання запиту простіше для більшості випадків. -
Перевірте поріг: Порівняйте баланс з вашим попередньо заданим лімітом. Якщо він нижчий, ініціюйте попередження.
-
Запустіть повідомлення: Це може бути просто виведення попередження в консоль, але для реальних оповіщень ви можете надіслати електронного листа або push-повідомлення. Ви можете інтегруватися з електронною поштою (через
smtplib) або зі службою на кшталт IFTTT чи Slack webhook API, щоб відправити оповіщення. Наприклад:if balance < 1000: send_email("Low balance alert", f"Account XYZ balance is {balance}")(Реалізуйте
send_emailза допомогою деталей вашого поштового сервера.)
Запускаючи цей скрипт щодня (через cron job або Планувальник завдань Windows), ви отримуватимете проактивні попередження. Оскільки він використовує ledger, він може враховувати всі транзакції, включно з тими, що ви щойно додали.
Майбутні терміни платежів
Якщо ви використовуєте Beancount для відстеження рахунків або термінів, ви можете позначати майбутні платежі та мати скрипти, які нагадують вам про них. Існує два способи подання майбутніх зобов’язань у Beancount:
-
Події: Beancount підтримує директиву
eventдля довільних нотаток із датами. Наприклад:2025-05-10 event "BillDue" "Mortgage payment due"Це не впливає на баланси, але фіксує дату з міткою. Скрипт може сканувати
entriesна предмет записівEvent, деEvent.type == "BillDue"(або будь-який обраний вами власний тип) і перевіряти, чи дата припадає, скажімо, на найближчі 7 днів від сьогодні. Якщо так, ініціювати попередження (e-mail, повідомлення або навіть спливаюче вікно). -
Майбутні транзакції: Деякі користувачі вводять транзакції з майбутньою датою (з відстроченою датою) для таких речей, як заплановані платежі. Вони не з’являються в балансах, доки дата не настане (якщо ви не запускаєте звіти по майбутніх датах). Скрипт може шукати транзакції з датою найближчого майбутнього і виводити їх.
Використовуючи ці методи, ви можете створити "скрипт-нагадувач", який під час запуску виводить список завдань або рахунків, що скоро мають бути оплачені. Інтегруйтеся з 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.
Розширення можуть виконувати кілька завдань:
- Хуки: Вони можуть підключатися до подій у життєвому циклі 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 тощо) і відображає їх у інтерфейсі 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 та даних
Однією з переваг сценарійованих робочих процесів є можливість підключати зовнішні дані. Ось поширені інтеграції:
-
Обмінні курси та товари: 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) або використати OCR API для зчитування чеків та автоматичного зіставлення їх з транзакціями. Оскільки ваші скрипти мають повний доступ до екосистеми 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, ви можете легко інтегрувати ці тести (як це зробив Алекс Ватт через команду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 з посиланнями на корисні плагіни та інструменти.