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.queryв Beancount 3.2.3. Например, за да получите общите разходи по месеци, свържете заредените записи и изпълнете заявката директно: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 или task runner), за да автоматизирате работния си процес.
Автоматизиране на задачи по съгласуване
Осчетоводяването означава да се уверите, че регистърът ви съвпада с външни записи (банкови извлечения, отчети за кредитни карти и т.н.). Регистърът в обикновен текст на Beancount и Python API правят възможно автоматизирането на голяма част от този процес.
Импортиране и съпоставяне на транзакции (за начинаещи)
За начинаещи препоръчителният подход е да използвате импортери от отделния пакет beangulp. Beancount 3 премахна модула за поглъщане от v2 и неговата команда extract. Пишете малък Python клас, който наследява beangulp.Importer, за да парсира даден формат (CSV, OFX, PDF и т.н.) и да създава транзакции. Регистрирайте го в кратък скрипт за поглъщане, след което го стартирайте чрез 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. Еднократната команда за активиране изтегля 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, ако желаете, която може автоматично да вмъква балансиращи записи за малки разлики от закръгляне (използвайте внимателно). - Пишете unit тестове за логиката на вашия импортер или осчетоводяване (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 Notebooks за интерактивна среда за отчитане, въпреки че това е по-скоро за проучване, отколкото за автоматизация.
Задействане на сигнали от вашия ledger
Друго мощно приложение на скриптуемите работни процеси е настройването на известия въз основа на условия във вашите финансови данни. Тъй като регистърът ви се актуализира редовно (и може да включва елементи с бъдеща дата като предстоящи сметки или бюджети), можете да го сканирате със скрипт и да получите известия за важни събития.
Предупреждения за нисък баланс на сметка
За да избегнете овърдрафт или да поддържате минимален баланс, може да искате известие, ако някоя сметка (напр. разплащателна или спестовна) падне под праг. Ето как можете да го приложите:
-
Определете текущите баланси: След като заредите
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 или webhook API на Slack, за да изпратите известието. Например:if balance < 1000: send_email("Low balance alert", f"Account XYZ balance is {balance}")(Внедрете
send_emailс данните на вашия имейл сървър.)
Като стартирате този скрипт ежедневно (чрез cron задача или Windows Task Scheduler), ще получавате проактивни предупреждения. Тъй като използва регистъра, той може да вземе предвид всички транзакции, включително тези, които току-що сте добавили.
Предстоящи крайни срокове за плащания
Ако използвате Beancount, за да следите сметки или срокове, можете да маркирате бъдещи плащания и скриптовете да ви напомнят. Два начина за представяне на предстоящи задължения в Beancount:
-
Събития: 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.
Разширенията могат да правят няколко неща:
- Куки: Те могат да се свързват към събития в жизнения цикъл на 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 commit във вашия регистър.
-
Валутни курсове и стоки: 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, за да извлечете подробни данни за акции или дивиденти. Например, Yahoo Finance API (или библиотеки от общността като
yfinance) може да извлече исторически данни за тикер. Скрипт може да актуализира регистъра ви с месечна ценова история за всяка акция, която притежавате, което позволява точни исторически отчети за пазарната стойност. Някои персонализирани разширения (като fava_investor) дори извличат ценови данни в движение за показване, но най-простото е редовно да импортирате цени в регистъра. -
Банкови API (Open Banking/Plaid): Вместо да изтегляте CSV файлове, можете да използвате API, за да извличате транзакции автоматично. Услуги като Plaid агрегират банкови сметки и позволяват програмен достъп до транзакции. При напреднала настройка можете да имате Python скрипт, който използва API на Plaid, за да извлича нови транзакции ежедневно и да ги запазва във файл (или директно да ги импортира в регистъра). Един напреднал потребител изгради система, в която Plaid се влива в техния pipeline за импортиране, правейки книгите им почти автоматични. Те отбелязват, че "нищо не ви спира да се регистрирате в Plaid API и да направите същото локално" – т.е. можете да напишете локален скрипт, за да получите банкови данни, след което да използвате логиката на Beancount импортера си, за да ги парсирате в записи в регистъра. Някои региони имат open banking 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}в началото, и вашият скрипт за известия може да итерира през този dict. -
Тестване: Отнасяйте се към финансовата си автоматизация като към критичен код – защото е такава! Пишете тестове за сложната логика. 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 за връзки към полезни плъгини и инструменти.