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 или планировщик задач) для автоматизации рабочего процесса.
Автоматизация задач сверки
Сверка означает удостовериться, что ваша бухгалтерская книга совпадает с внешними записями (выписки из банка, отчеты по кредитным картам и т. п.). Текстовая бухгалтерская книга 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-файл банка с помощью модуля 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или с помощью 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 по данным о денежных потоках. Некоторые расширения Fava, разработанные сообществом (например, PortfolioSummary или fava_investor), делают именно это — вычисляют IRR и другие метрики для инвестиционных портфелей. В качестве скрипта вы можете использовать функцию IRR (из NumPy или вашу собственную) для серии взносов/выводов и итогового значения.
-
Мультипериодные или пользовательские метрики: Хотите отчет о вашем уровне сбережений (отношение сбережений к доходу) за каждый месяц? Скрипт на Python может загрузить бухгалтерскую книгу, суммировать все счета доходов и все счета расходов, затем вычислить сбережения = доходы - расходы и процент. Это может вывести красивую таблицу или даже сгенерировать отчет в формате HTML/Markdown для ваших записей.
-
Визуализация: Вы можете создавать диаграммы вне Fava. Например, используйте
matplotlibилиaltairв скрипте для создания графика чистой стоимости с течением времени, используя данные бухгалтерской книги. Поскольку бухгалтерская книга содержит все исторические балансы (или вы можете накапливать их, перебирая записи), вы можете создавать временные графики. Сохраняйте эти графики как изображения или интерактивные HTML. (Если предпочитаете визуализацию прямо в приложении, смотрите раздел о расширениях Fava ниже для добавления графиков внутри Fava.)
Варианты вывода: Решите, как доставлять отчет:
- Для одноразового анализа может быть достаточно вывода на экран или сохранения в файл CSV/Excel.
- Для дашбордов рассмотрите возможность генерации HTML-файла с данными (возможно, с использованием шаблонизатора, такого как Jinja2, или даже просто написания Markdown), который можно открыть в браузере.
- Вы также можете интегрироваться с Jupyter Notebook для интерактивной среды отчетности, хотя это больше подходит для исследования, а не автоматизации.
Триггеры оповещений из вашей бухгалтерской книги
Еще одно мощное применение скриптовых рабочих процессов — настройка оповещений на основе условий в ваших финансовых данных. Поскольку ваша бухгалтерская книга регулярно обновляется (и может включать элементы с будущими датами, такие как предстоящие счета или бюджеты), вы можете сканировать ее с помощью скрипта и получать уведомления о важных событиях.
Предупреждения о низком балансе счета
Чтобы избежать перерасхода или поддерживать минимальный баланс, вы можете захотеть получать оповещение, если любой счет (например, расчетный или сберегательный) упадет ниже порога. Вот как это можно реализовать:
-
Определите текущие балансы: После загрузки
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')возвращает сумму в десятичном формате в USD). Как и в агрегате запроса, баланс хранит каждую валюту отдельно. Однако использование запроса проще в большинстве случаев. -
Проверьте порог: Сравните баланс с вашим предопределённым лимитом. Если он ниже, сработает оповещение.
-
Отправка уведомления: Это может быть простым выводом предупреждения в консоль, но для реальных оповещений вы можете отправить электронное письмо или push-уведомление. Можно интегрироваться с электронной почтой (через
smtplib) или сервисом, например IFTTT либо Slack webhook API, чтобы отправить оповещение. Например:if balance < 1000: send_email("Low balance alert", f"Account XYZ balance is {balance}")(Реализуйте
send_emailс параметрами вашего почтового сервера.)
Запуская этот скрипт ежедневно (через cron или Планировщик заданий Windows), вы получите предупреждения заранее. Поскольку он использует ledger, он сможет учитывать все транзакции, включая только что добавленные.
Ближайшие сроки платежей
Если вы используете Beancount для отслеживания счетов или сроков, можно отмечать будущие платежи и скрипты будут напоминать вам. Два способа представления предстоящих обязательств в Beancount:
-
События: В Beancount поддерживается директива
eventдля произвольных помеченных дат. Например:2025-05-10 event "BillDue" "Mortgage payment due"Это не влияет на балансы, но записывает дату с меткой. Скрипт может просканировать
entriesна предмет записейEventсEvent.type == "BillDue"(или любым вашим произвольным типом) и проверить, попадает ли дата, например, в ближайшие 7 дней от сегодня. Если да, сработает оповещение (почта, уведомление или даже всплывающее окно). -
Будущие транзакции: Некоторые пользователи вводят транзакции с будущей датой (постдатированные) для таких вещей, как запланированные платежи. Они не появятся в балансах, пока не наступит дата (если только вы не запускаете отчёты на указанную будущую дату). Скрипт может искать транзакции с датой в ближайшем будущем и выводить их список.
Используя это, вы можете создать скрипт «напоминалку», который при запуске выводит список задач или счетов с предстоящими сроками. Интегрируйтесь с API, например Google Calendar или менеджером задач, если хотите создавать напоминания автоматически.
Обнаружение аномалий
За известными порогами или датами вы можете создавать пользовательские оповещения для необычных паттернов. Например, если регулярные ежемесячные расходы не произошли (возможно, вы забыли оплатить счет), или если расходы по категории аномально высоки в этом месяце, ваш скрипт может это зафиксировать. Обычно это включает запрос недавних данных и сравнение с историей (что может быть продвинутой темой – возможно, с использованием статистики или машинного обучения).
На практике многие пользователи полагаются на сверку для обнаружения аномалий (неожиданных транзакций). Если вы получаете уведомления из банка (например, письма на каждую транзакцию), вы можете парсить их с помощью скрипта и автоматически добавлять в 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мог бы проходить по балансам счетов и, возможно, сохранять предупреждения (хотя отображение их в интерфейсе может потребовать дополнительной работы, например, вызова 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 с ссылками на полезные плагины и инструменты.