Към основното съдържание

Как Python скриптовете автоматизират Beancount и Fava

Beancount и Fava остават скриптируеми: използвайте Python за автоматизиране на отчети, баланси и персонализирани работни процеси спрямо вашия ledger.

Beancount (инструмент за двустранно счетоводство в обикновен текст) и Fava (неговият уеб интерфейс) са силно разширяеми и скриптируеми. Техният дизайн ви позволява да автоматизирате финансови задачи, да генерирате персонализирани отчети и да настройвате сигнали, като пишете Python скриптове. По думите на един потребител: „Наистина ми харесва, че данните ми са в толкова удобен формат, и ми харесва, че мога да автоматизирам нещата колкото си искам. Няма API като файл на диска ви; лесно се интегрира.“ Това ръководство ще ви преведе през създаването на скриптируеми работни потоци – от автоматизация за начинаещи до разширени Fava плъгини.

Разгледайте примерен ledger на живо:

Отворете Example Ledger в нов раздел

Започнете с командата bea

Преди да пишете какъвто и да е Python, проверете дали bea вече върши работата. Той валидира ledger-а, изпълнява 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 ledger: Използвайте loader-а на 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)

    Loader-ът връща записите и грешките заедно. Небалансиран или невалиден файл все пак връща записи, така че проверете 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, но тук го извиквате в скрипт. Това избягва извикването на външна команда в цикъл.

  • Създайте структура на проекта: Организирайте скриптовете си заедно с ledger-а. Често срещано оформление е да имате директории за импортери (за извличане/анализиране на външни данни), отчети или заявки (за аналитични скриптове) и документи (за съхраняване на изтеглени извлечения). Например, един потребител поддържа:

    • importers/ – персонализирани Python скриптове за импортиране (с тестове),
    • queries/ – скриптове за генериране на отчети (изпълними чрез python3 queries/...),
    • documents/ – изтеглени банкови CSV/PDF файлове, организирани по сметка.

С тази настройка можете да изпълнявате скриптове ръчно (напр. python3 queries/cash_flow.py) или да ги планирате (чрез cron или програма за задачи), за да автоматизирате работния си процес.

Автоматизиране на задачи по съгласуване

Съгласуването означава да се уверите, че ledger-ът ви съвпада с външни записи (банкови извлечения, отчети за кредитни карти и т.н.). Обикновеният текстов формат и Python API на Beancount правят възможно автоматизирането на голяма част от този процес.

Импортиране и съпоставяне на транзакции (за начинаещи)

За начинаещи препоръчителният подход е да използвате импортери от отделния пакет 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 и извежда транзакциите във временен файл.
  • Ръчно прегледайте и копирайте транзакциите от временния файл в основния ledger, след което изпълнете 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.beancount

identify отчита checking_importer.CheckingImporter за файла. extract записва транзакциите във формат Beancount:

2024-01-08 * "Grocery Store"
  Expenses:Food:Groceries   120.00 USD
  Assets:Bank:Checking     -120.00 USD

Прегледайте new.beancount, копирайте записите в основния ledger и изпълнете 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) с вашите ledger записи:

  1. Прочетете външните данни: Анализирайте CSV файла на банката с помощта на Python модула csv (или Pandas). Нормализирайте данните в списък от транзакции, например всяка с дата, сума и описание.
  2. Заредете ledger транзакциите: Използвайте loader.load_file, както е показано по-рано, за да получите всички ledger записи. Филтрирайте този списък до сметката от интерес (напр. разплащателната ви сметка) и може би периода на извлечението.
  3. Сравнете и открийте несъответствия:
  • За всяка външна транзакция проверете дали съществува идентичен запис в ledger-а (съпоставете по дата и сума, може би описание). Ако не бъде намерен, маркирайте го като „нов“ и евентуално го изведете като транзакция във формат Beancount за преглед.
  • Обратно, идентифицирайте всички ledger записи в тази сметка, които не се появяват във външния източник – това може да са грешки при въвеждане на данни или транзакции, които все още не са осчетоводени от банката.
  1. Изведете резултатите: Отпечатайте отчет или създайте нов .beancount фрагмент с липсващите транзакции.

Като пример, общностен скрипт, наречен reconcile.py, прави точно това: при даден Beancount файл и входен CSV, той отпечатва списък с нови транзакции, които трябва да бъдат импортирани, както и всички съществуващи ledger записи, които не са във входа (евентуален знак за погрешна класификация). С такъв скрипт месечното съгласуване може да бъде толкова просто, колкото да го изпълните и след това да добавите предложените транзакции към ledger-а. Един потребител на 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 или чрез beanquery Python API, показан по-рано, и след това да форматирате резултата.

  • Отчет за разходите по категории: Заявете общите разходи по категория:

    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): Тъй като ledger-ът ви съдържа всички парични потоци (покупки, продажби, дивиденти), можете да изчислите нормата на възвръщаемост на портфейла. Например, можете да напишете скрипт, който филтрира транзакциите на инвестиционните ви сметки и след това изчислява вътрешната норма на възвръщаемост. Съществуват библиотеки (или формули) за изчисляване на IRR при дадени данни за паричен поток. Някои разширения на Fava, разработени от общността (като PortfolioSummary или fava_investor), правят точно това, изчислявайки IRR и други показатели за инвестиционни портфейли. Като скрипт, можете да използвате IRR функция (от NumPy или ваша собствена) върху поредицата от вноски/тегления плюс крайната стойност.

  • Многопериодни или персонализирани показатели: Искате ли отчет за нормата на спестяване (съотношение на спестяванията към дохода) всеки месец? Python скрипт може да зареди ledger-а, да сумира всички сметки за приходи и всички сметки за разходи и след това да изчисли спестявания = приходи - разходи и процента. Това може да изведе хубава таблица или дори да генерира HTML/Markdown отчет за вашите записи.

  • Визуализация: Можете да генерирате графики извън Fava. Например, използвайте matplotlib или altair в скрипт, за да създадете графика на нетната стойност във времето, използвайки данните от ledger-а. Тъй като ledger-ът има всички исторически баланси (или можете да ги натрупате, като обхождате записите), можете да създавате времеви серии. Запазете тези графики като изображения или интерактивен HTML. (Ако предпочитате визуализации в приложението, вижте раздела за разширения на Fava по-долу за добавяне на графики във Fava.)

Опции за изход: Решете как да доставите отчета:

  • За еднократен анализ отпечатването на екрана или запазването в CSV/Excel файл може да е достатъчно.
  • За табла обмислете генерирането на HTML файл с данните (евентуално с библиотека за шаблони като Jinja2 или просто писане на Markdown), който можете да отворите в браузър.
  • Можете също така да се интегрирате с Jupyter Notebooks за интерактивна среда за отчитане, въпреки че това е повече за изследване, отколкото за автоматизация.

Задействане на сигнали от вашия ledger

Друга мощна употреба на скриптируеми работни потоци е настройването на сигнали въз основа на условия във вашите финансови данни. Тъй като ledger-ът ви се актуализира редовно (и може да включва позиции с бъдеща дата като предстоящи сметки или бюджети), можете да го сканирате със скрипт и да получавате известия за важни събития.

Предупреждения за нисък баланс на сметка

За да избегнете овърдрафт или да поддържате минимален баланс, може да искате сигнал, ако някоя сметка (напр. разплащателна или спестовна) падне под праг. Ето как можете да реализирате това:

  1. Определете текущите баланси: След като заредите entries чрез loader-а, изчислете последния баланс на сметките от интерес. Можете да направите това, като агрегирате записите или използвате заявка. Например, използвайте 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). Подобно на агрегат от заявка, балансът запазва всяка валута отделно. Въпреки това, използването на заявката е по-просто в повечето случаи.

  2. Проверете прага: Сравнете баланса с предварително зададения лимит. Ако е под него, задействайте сигнал.

  3. Задействайте известие: Това може да бъде толкова просто, колкото отпечатване на предупреждение на конзолата, но за реални сигнали може да изпратите имейл или push известие. Можете да се интегрирате с имейл (чрез smtplib) или услуга като IFTTT или Slack webhook API, за да изпратите сигнала. Например:

    if balance < 1000:
        send_email("Low balance alert", f"Account XYZ balance is {balance}")

    (Реализирайте send_email с данните на вашия имейл сървър.)

Като изпълнявате този скрипт ежедневно (чрез cron или Windows Task Scheduler), ще получавате проактивни предупреждения. Тъй като използва ledger-а, той може да вземе предвид всички транзакции, включително тези, които току-що сте добавили.

Предстоящи крайни срокове за плащания

Ако използвате Beancount за проследяване на сметки или крайни срокове, можете да маркирате бъдещи плащания и да накарате скриптове да ви напомнят. Два начина за представяне на предстоящи задължения в Beancount:

  • Събития: Beancount поддържа директива event за произволни бележки с дата. Например:

    2025-05-10 event "BillDue" "Mortgage payment due"

    Това не засяга балансите, но записва дата с етикет. Скрипт може да сканира entries за записи Event, където Event.type == "BillDue" (или всеки персонализиран тип, който изберете) и да провери дали датата е в рамките на, да речем, следващите 7 дни от днес. Ако да, задействайте сигнал (имейл, известие или дори изскачащ прозорец).

  • Бъдещи транзакции: Някои хора въвеждат транзакции с бъдеща дата (пост-датирани) за неща като планирани плащания. Те няма да се появят в балансите, докато датата не мине (освен ако не изпълнявате отчети към бъдещи дати). Скрипт може да търси транзакции, датирани в близкото бъдеще, и да ги изброи.

Използвайки тези, можете да създадете „напомнящ“ скрипт, който при изпълнение извежда списък със задачи или сметки, дължими скоро. Интегрирайте се с API като Google Calendar или мениджър на задачи, ако искате автоматично да създавате напомняния там.

Откриване на аномалии

Отвъд известни прагове или дати, можете да скриптирате персонализирани сигнали за необичайни модели. Например, ако обикновено месечен разход не е настъпил (може би сте забравили да платите сметка) или ако разходите в дадена категория са необичайно високи този месец, вашият скрипт може да го отбележи. Това обикновено включва запитване на скорошни данни и сравняване с историята (което може да е разширена тема – евентуално използване на статистика или ML).

На практика много потребители разчитат на съгласуването, за да откриват аномалии (неочаквани транзакции). Ако получавате банкови известия (като имейли за всяка транзакция), можете да ги анализирате със скрипт и автоматично да ги добавяте към Beancount или поне да проверите дали са записани. Един ентусиаст дори конфигурира банката си да изпраща имейли за сигнали за транзакции, с плана да ги анализира и добавя към ledger-а автоматично. Този вид сигнал, управляван от събития, може да гарантира, че никоя транзакция не остава незаписана.

Разширяване на Fava с персонализирани плъгини и изгледи

Fava вече е скриптируем чрез своята система за разширения. Ако искате вашата автоматизация или отчети да се интегрират директно в уеб интерфейса, можете да напишете разширение за Fava (наричано още плъгин) на Python.

Как работят разширенията на Fava: Разширението е Python модул, който дефинира клас, наследяващ fava.ext.FavaExtensionBase. Регистрирате го във вашия Beancount файл чрез персонализирана опция. Например, ако имате файл myextension.py с клас MyAlerts(FavaExtensionBase), можете да го активирате, като добавите към ledger-а:

1970-01-01 custom "fava-extension" "myextension"

Когато Fava се зареди, той ще импортира този модул и ще инициализира вашия клас MyAlerts.

Разширенията могат да правят няколко неща:

  • Куки: Те могат да се включат в събития от жизнения цикъл на Fava. Например after_load_file() се извиква след зареждане на ledger-а. Можете да използвате това, за да изпълнявате проверки или да предварително изчислите данни. Ако искате да реализирате проверката за нисък баланс във 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" към ledger-а, Fava ще покаже нова страница „Здравей, свят“ (също така ще ви е необходим шаблонен файл HelloReport.html в подпапка templates, за да дефинирате съдържанието на страницата, освен ако разширението не използва само куки). Шаблонът може да използва данни, които прикачите към класа на разширението. Fava използва шаблони Jinja2, така че можете да рендерирате данните си в HTML таблица или графика в този шаблон.

Забележка: Системата за разширения на Fava е мощна, но се счита за „нестабилна“ (подлежи на промяна). Тя изисква известна запознатост с уеб разработката (HTML/JS), ако създавате персонализирани страници. Ако целта ви е просто да изпълнявате скриптове или анализи, може да е по-лесно да ги запазите като външни скриптове. Използвайте разширения на Fava, когато искате персонализирано изживяване в приложението за вашия работен процес.

Интегриране на API и данни на трети страни

Едно от предимствата на скриптируемите работни потоци е възможността да привличате външни данни. Ето често срещани интеграции:

  • Обменни курсове и стоки: Beancount не извлича автоматично цени по дизайн (за да запази отчетите детерминистични), но предоставя директива Price, за да предоставите курсове. Можете да автоматизирате извличането на тези цени. Например, скрипт може да запита API (Yahoo Finance, Alpha Vantage и т.н.) за най-новия обменен курс или цена на акция и да добави ценови запис към ledger-а:

    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) може да извлече исторически данни за даден тикер. Скрипт може да актуализира ledger-а с месечна ценова история за всяка акция, която притежавате, което позволява точни исторически отчети за пазарната стойност. Някои персонализирани разширения (като fava_investor) дори извличат ценови данни в движение за показване, но най-простото е редовно да импортирате цени в ledger-а.

  • Банкови API (Open Banking/Plaid): Вместо да изтегляте CSV файлове, можете да използвате API, за да извличате транзакции автоматично. Услуги като Plaid агрегират банкови сметки и позволяват програмен достъп до транзакции. В разширена настройка можете да имате Python скрипт, който използва API-то на Plaid, за да извлича нови транзакции ежедневно и да ги записва във файл (или директно да ги импортира в ledger-а). Един напреднал потребител изгради система, при която Plaid захранва неговия тръбопровод за импортиране, правейки книгите му почти автоматични. Той отбелязва, че „нищо не ви пречи да се регистрирате за Plaid API и да правите същото локално“ – т.е. можете да напишете локален скрипт, за да получите банкови данни, и след това да използвате логиката на вашия Beancount импортер, за да ги анализирате в ledger записи. Някои региони имат open banking API, предоставени от банки; те могат да се използват по подобен начин.

  • Други API: Можете да интегрирате инструменти за бюджетиране (експортиране на планирани бюджети за сравнение с действителните в Beancount) или да използвате OCR API за четене на разписки и автоматичното им съпоставяне с транзакции. Тъй като вашите скриптове имат пълен достъп до екосистемата на Python, можете да интегрирате всичко – от услуги за имейл (за изпращане на сигнали) до Google Sheets (напр. актуализиране на електронна таблица с месечни финансови показатели) до приложения за съобщения (изпращане на обобщен отчет чрез Telegram бот).

Когато използвате API на трети страни, не забравяйте да защитите идентификационните си данни (използвайте променливи на средата или конфигурационни файлове за API ключове) и да обработвате грешките (мрежови проблеми, престой на API) елегантно в скриптовете си. Често е разумно да кеширате данни (например да съхранявате извлечени обменни курсове, за да не заявявате един и същ исторически курс многократно).

Добри практики за модулни и поддържаеми скриптове

Докато изграждате скриптируеми работни потоци, поддържайте кода си организиран и стабилен:

  • Модулност: Разделете различните грижи в различни скриптове или модули. Например, имайте отделни скриптове за „импортиране/съгласуване на данни“ срещу „генериране на отчети“ срещу „сигнали“. Можете дори да създадете малък Python пакет за вашия ledger с модули като ledger_import.py, ledger_reports.py и т.н. Това прави всяка част по-лесна за разбиране и тестване.

  • Конфигурация: Избягвайте твърдо кодирани стойности. Използвайте конфигурационен файл или променливи в началото на скрипта за неща като имена на сметки, прагове, API ключове, дати и т.н. Това улеснява настройката без дълбоко редактиране на кода. Например, дефинирайте LOW_BALANCE_THRESHOLDS = {"Assets:Bank:Checking": 500, "Assets:Savings": 1000} в началото и вашият скрипт за сигнали може да обхожда този речник.

  • Тестване: Отнасяйте се към финансовата си автоматизация като към критичен код – защото тя е такава! Пишете тестове за сложна логика. Beancount предоставя някои тестови помощници (използвани вътрешно за тестване на импортери), които можете да използвате, за да симулирате ledger входове. Дори без сложни рамки, можете да имате фалшив CSV и очаквани изходни транзакции и да потвърдите, че вашият скрипт за импортиране създава правилните записи. Ако използвате pytest, можете лесно да интегрирате тези тестове (както направи Alex Watt чрез команда just test, обвиваща pytest).

  • Контрол на версиите: Дръжте ledger-а и скриптовете си под контрол на версиите (git). Това не само ви дава резервни копия и история, но и ви насърчава да правите промени по контролиран начин. Можете да маркирате версии на вашите „финансови скриптове“ или да преглеждате разликите при отстраняване на проблем. Някои потребители дори проследяват финансовите си записи в Git, за да виждат промените във времето. Просто внимавайте да игнорирате чувствителни данни (като сурови файлове с извлечения или API ключове) във вашето хранилище.

  • Документация: Документирайте персонализираните си работни потоци за бъдещето. README във вашето хранилище, обясняващ как да настроите средата, как да изпълнявате всеки скрипт и какво прави всеки от тях, ще бъде безценен след месеци. Също така коментирайте кода си, особено всяка неочевидна счетоводна логика или API взаимодействие.

  • Поддръжка на Fava плъгини: Ако пишете разширение за Fava, го поддържайте просто. Fava може да се промени, така че по-малки разширения с целева функционалност са по-лесни за актуализиране. Избягвайте дублирането на твърде много логика – използвайте заявковия механизъм на Beancount или съществуващи помощни функции, когато е възможно, вместо твърдо кодирани изчисления, които може да са чувствителни към промени в ledger-а.

  • Сигурност: Тъй като вашите скриптове може да обработват чувствителни данни и да се свързват с външни услуги, отнасяйте се към тях внимателно. Не разкривайте API ключове и обмислете изпълнението на автоматизацията на сигурна машина. Ако използвате хостнато решение или облак (като планиране на GitHub Actions или сървър за изпълнение на Fava), уверете се, че данните в ledger-а са криптирани в покой и че сте съгласни с последиците за поверителността.

Следвайки тези практики, ще гарантирате, че работният ви процес остава надежден дори когато финансите ви (и самите инструменти) се развиват. Искате скриптове, които можете да преизползвате година след година, с минимални корекции.

Заключение

Beancount и Fava предоставят мощна, гъвкава платформа за технически напреднали потребители, за да персонализират напълно проследяването на личните си финанси. Като пишете Python скриптове, можете да автоматизирате досадни задачи като съгласуване на извлечения, да създавате богати отчети, пригодени към вашите нужди, и да сте в крак с финансите си чрез навременни сигнали. Обхванахме диапазон от примери от основни до разширени – започвайки с прости заявки и CSV импортиране и преминавайки към пълноценни Fava плъгини и интеграции с външни API. Докато ги прилагате, започнете просто и постепенно надграждайте. Дори няколко малки скрипта за автоматизация могат да спестят часове работа и значително да подобрят точността. И не забравяйте, тъй като всичко е в обикновен текст и Python, вие имате пълен контрол – вашата финансова система расте заедно с вас, приспособявайки се към вашите специфични нужди. Приятно скриптиране!

Източници: Техниките по-горе са извлечени от документацията на Beancount и опита на общността. За допълнително четене вижте официалната документация на Beancount, ръководства и блогове на общността, както и хранилището Awesome Beancount за връзки към полезни плъгини и инструменти.

Източник: https://beancount.io/bg/docs/Solutions/scriptable-workflows