losalamos.budget#

Budget generation and analysis utilities.

Provides Budget for building collections of transfer notes from a structured batch seed, with a recurrence engine that expands periodic transfers into individual dated instances.

The typical workflow is:

  1. Instantiate and configure the budget:

    from losalamos.budget import Budget
    from pathlib import Path
    
    budget = Budget()
    budget.year = 2027
    budget.duration = 1
    budget.output_folder = Path("vault/budget")
    
  2. Build the in-memory collection from a batch seed:

    budget.build(batches=[
        {
            "defaults": {
                "currency": "BRL",
                "direction": "outflow",
                "payer": "My Company",
            },
            "transfers": [
                {"value": 1000.00, "receiver": "Rent Corp", "recurrence": "1 month"},
                {"value": 5000.00, "receiver": "Insurance Co", "recurrence": "1 year"},
            ],
        }
    ])
    
  3. Inspect before writing:

    print(budget.catalog)
    print(budget.monthly_equivalent(group_by="commitment"))
    
  4. Materialise notes to disk:

    budget.save()
    

Classes

Budget(name[, alias])

A collection of transfer notes built from a batch seed.

class losalamos.budget.Budget(name, alias='Bgt')[source]#

Bases: NoteCollTransfer

A collection of transfer notes built from a batch seed.

Extends NoteCollTransfer with a recurrence engine and budget-level statistics. Notes are held in memory until save() materializes them as Markdown files.

The collection can also be populated from existing files via the inherited load_folder() and related methods.

Parameters:
  • name (str) – Budget name, used as the prefix for every generated note filename (e.g. "HouseBudget"HouseBudget_2027_001.md). Required — no default.

  • alias (str) – Object alias. Default value = "Bgt"

Attributes

  • NOTE_PREFIX (str): Prefix for generated note filenames, uppercased at use. Default value = "transfer"

  • year (int): Budget start year. Defaults to the current year.

  • duration (int): Number of years covered. Default value = 1

  • output_folder (Path or None): Destination for save().

  • split (bool): When True, save() writes inflows to output_folder/inflows/ and outflows to output_folder/outflows/. Default value = False

NOTE_PREFIX = 'transfer'#
build(batches)[source]#

Populate the in-memory collection from a list of transfer batches.

Each batch is a dict with a defaults block and a transfers list. Every entry in transfers is merged with defaults (entry-level keys win), then expanded by the recurrence engine into one NoteTransfer per occurrence.

Two optional per-transfer anchor keys are consumed before the note is created and do not appear in the note metadata:

  • day (int): Day-of-month anchor. Default value = 1

  • month (int): Month anchor, only used for year-level recurrence. Default value = 1

Calling build() replaces any previously built content. No files are written to disk.

Parameters:

batches (list[dict]) –

List of batch dicts, each with:

  • defaults (dict) — fields applied to every transfer in the batch.

  • transfers (list[dict]) — per-transfer overrides.

Returns:

No value is returned.

Return type:

None

save()[source]#

Write all in-memory transfer notes to output_folder.

When split is False (default), all notes are written flat into output_folder. When True, inflow notes go to output_folder/inflows/ and outflow notes to output_folder/outflows/. All required folders are created if absent.

Raises:

ValueError – If output_folder is None.

Returns:

No value is returned.

Return type:

None

monthly_equivalent(group_by=None, account=None)[source]#

Return the monthly equivalent value across all transfers.

Sums every note’s value and divides by the total budget duration in months, normalising transfers with different recurrences to a common monthly baseline.

The result is a wide table where direction becomes columns so inflows and outflows can be compared side by side:

equivalence | account  | inflow  | outflow  | net
monthly     | BB-001   | 10500   | 4780     | 5720
monthly     | NB-002   | 1200    | 1455     | -255

Pass group_by to add row-level breakdown after account.

Parameters:
  • group_by (str, list, or None) – Extra column name or list of column names used as additional row keys after account, e.g. "commitment" or ["commitment", "category"]. When None, rows are by account only.

  • account (str, list, or None) – Account code or list of account codes to include. When None, all accounts are included.

Returns:

DataFrame with columns equivalence, account, optional extras, inflow, outflow, net. Also stored as catalog_monthly.

Return type:

pandas.DataFrame

annual_equivalent(group_by=None, account=None)[source]#

Return the annual equivalent value across all transfers.

Same wide layout as monthly_equivalent() with equivalence = "annual".

Parameters:
  • group_by (str, list, or None) – Extra column name or list of column names used as additional row keys after account. When None, rows are by account only.

  • account (str, list, or None) – Account code or list of account codes to include. When None, all accounts are included.

Returns:

DataFrame with columns equivalence, account, optional extras, inflow, outflow, net. Also stored as catalog_annual.

Return type:

pandas.DataFrame