Skip to content
Back to skills

absbox

BSecurity

Model, project, and analyze structured finance deals (ABS, MBS, CLO, SRT) with the absbox Python library and Hastructure engine. Use for securitization modeling, deal maps, pool cashflow projection, bond waterfalls, tranche pricing, IRR/WAL, sensitivity analysis, root finding, and debugging projections. Python 3.10+.

  • 0 votes
  • 0 copies
  • 2 views
  • Added October 3, 2026
devopspythonrustgobashdockerdebuggingapiperformance

Works with

  • cli
  • api

Security analysis

B88/100
  • mediumInstalls packages at runtime which could introduce malicious dependencies
  • mediumInstalls packages at runtime which could introduce malicious dependenciesin scripts/smoke.py

Pro scans all 18 files and shows the line behind each finding

Scanned October 3, 2026

npx -y skills add absbox/absbox-skill --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of absbox?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for absbox
[![Security: B — Skills Directory](https://www.skillsdirectory.com/api/skills/absbox-absbox/badge)](https://www.skillsdirectory.com/skills/absbox-absbox)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: absbox
description: >-
  Model, project, and analyze structured finance deals (ABS, MBS, CLO, SRT)
  with the absbox Python library and Hastructure engine. Use for securitization
  modeling, deal maps, pool cashflow projection, bond waterfalls, tranche
  pricing, IRR/WAL, sensitivity analysis, root finding, and debugging
  projections. Python 3.10+.
metadata:
  author: absbox
  version: "4.0.1"
license: Apache-2.0
---

# absbox — Structured Finance Modeling Toolkit

absbox builds deal dictionaries ("deal maps"), sends them to a Hastructure
engine over HTTP, and returns pandas DataFrames. This file is the router; keep
it loaded. Pull detail from the files it points to.

- `REFERENCE.md` — exhaustive lookup tables (formulas, actions, constants, API).
- `golden-paths/` — verified end-to-end recipes. **Read the matching one before
  improvising a multi-step script.**
- `README.md` — human quick start.
- `doc/CHANGELOG.md` — release history tied to engine versions.

## When to use

- Model/project cashflows for ABS, MBS, CLO, SRT, or any securitization.
- Build waterfalls with tranches, triggers, accounts, fees, swaps, reserves.
- Pool/asset assumptions (CDR, CPR, recovery), sensitivity, scenario comparison.
- Bond pricing, IRR, WAL, duration, root finding / deal structuring.
- Debug or visualize a projection.

Not for: plain bond pricing with no waterfall, equity valuation, or generic
fixed-income analytics.

## Step 0 — how to approach

1. **Pick the asset type(s).** `Mortgage`, `Loan`, `Lease`, `Installment`,
   `FixedAsset`, `Invoice`, `ProjectedCashflow`, `ProjectedByFactor`.
2. **Build the pool** — `{"assets": [ [type, originDict, currentDict], ... ]}`.
3. **Choose assumptions** — pool performance (`CDR`/`CPR`/recovery) plus any
   interest-rate curves.
4. **Define the deal** — dates, accounts, bonds, waterfall, collect, status.
5. **Run** — `api.run(...)`, then read `r['bonds']`, `r['pool']`, `r['result']`.
6. **Check** `r['result']['logs']` before trusting anything.

If a golden path matches the task, follow it instead of re-deriving from these
tables.

## Setup & connection

```bash
pip install absbox      # Python 3.10+
```

```python
from absbox import API, EnginePath

api = API(EnginePath.PROD)                       # default: version check on
api = API(EnginePath.DEV, lang='english', check=False)
api = API(EnginePath.LOCAL)                      # localhost:8081 (Docker)
api = API("https://absbox.org/api/latest", 'english')
```

`EnginePath` shortcuts: `DEV`, `PROD`, `LOCAL`, `NY_DEV`, `NY_PROD`,
`USE_ENV` (reads env var `ABSBOX_SERVER`). `PROD` =
`https://absbox.org/api/latest`. There is **no** `LDN_DEV`/`LDN_PROD` in
absbox 0.52.3.

**Version rule:** the client and engine must share the same **MAJOR.MINOR**
version; the patch may differ. `check=True` (the default) enforces this at
connect and prints `local lib:x.y.z, server:x.y.z`. `check=False` disables the
check — fine for experiments, not for reproducible work. Inspect at runtime
with `api.server_info` and `api.version`.

Local engine:

```bash
docker pull yellowbean/hastructure
docker run -p 8081:8081 yellowbean/hastructure
```

Pick the first reachable endpoint yourself. (`PickApiFrom` exists but is
**broken in absbox 0.52.3** — it passes `API` an internal `{"url": ...}` dict —
so do not use it until fixed.)

```python
from absbox import API, EnginePath

api = None
for ep in [EnginePath.PROD, EnginePath.DEV, EnginePath.LOCAL]:
    try:
        api = API(ep, lang='english')
        break
    except Exception:
        continue
```

## Minimal complete deal (verified against the DEV engine)

```python
from absbox import API, EnginePath, mkDeal

deal = mkDeal({
    "name": "SimpleDeal",
    "dates": {
        "cutoff": "2021-03-01", "closing": "2021-06-15",
        "firstPay": "2021-07-26", "payFreq": ["DayOfMonth", 20],
        "poolFreq": "MonthEnd", "stated": "2030-01-01"
    },
    "pool": {"assets": [
        ["Mortgage",
         {"originBalance": 12000, "originRate": ["fix", 0.045], "originTerm": 120,
          "freq": "Monthly", "type": "Level", "originDate": "2021-02-01"},
         {"currentBalance": 10000, "currentRate": 0.075,
          "remainTerm": 80, "status": "Current"}]
    ]},
    "accounts": {"acc01": {"balance": 0}},
    "bonds": {
        "A": {"balance": 8000, "rate": 0.05, "originBalance": 8000,
              "originRate": 0.05, "startDate": "2021-06-15",
              "rateType": {"Fixed": 0.05}, "bondType": {"Sequential": None}},
        "EQ": {"balance": 2000, "rate": 0.0, "originBalance": 2000,
               "originRate": 0.0, "startDate": "2021-06-15",
               "rateType": {"Fixed": 0.0}, "bondType": {"Equity": None}}
    },
    "waterfall": {"Amortizing": [
        ["accrueAndPayInt", "acc01", ["A"]],
        ["payPrin", "acc01", ["A"]],
        ["payPrinResidual", "acc01", ["EQ"]]
    ]},
    "collect": [
        ["CollectedInterest", "acc01"],
        ["CollectedPrincipal", "acc01"],
        ["CollectedPrepayment", "acc01"]
    ],
    "status": ("PreClosing", "Amortizing")
})

api = API(EnginePath.DEV, lang='english')
poolAssump = ("Pool",
    ("Mortgage", {"CDR": 0.01}, {"CPR": 0.05}, {"Rate": 0.7, "Lag": 18}, None),
    None, None)
r = api.run(deal, poolAssump=poolAssump, read=True)

print(r['result']['logs'])   # check warnings first
print(r['bonds']['A'].tail())
print(r['pool']['flow'].tail())
```

`stated` must extend past the assets' remaining life, or the engine ends the
deal immediately with no cashflow.

## Deal map keys

| Key | Required | Description |
|-----|----------|-------------|
| `name` | yes | Deal identifier |
| `dates` | yes | cutoff/closing/firstPay/payFreq/poolFreq/stated |
| `pool` | yes | `{"assets": [...]}`; multi-pool = `{"PoolA": {...}, "PoolB": {...}}` |
| `accounts` | yes | Cash accounts, optional reserve targets and rates |
| `bonds` | yes | Tranches; nested map = bond group |
| `waterfall` | yes | Actions keyed by deal status |
| `collect` | yes | Maps pool sources to accounts |
| `status` | yes | `(initial, next)` e.g. `("PreClosing", "Amortizing")` |
| `fees` | no | Service/trustee fees |
| `triggers` | no | Performance triggers by point |
| `liqFacility` | no | Liquidity facilities |
| `rateSwap` | no | Swaps and caps |
| `ledgers` | no | Booking ledgers |

## Where to look next

| Topic | File |
|-------|------|
| Formula / condition / date-pattern syntax | `REFERENCE.md` §2–4 |
| Asset type fields | `REFERENCE.md` §5 |
| Waterfall action signatures | `REFERENCE.md` §9 |
| Fee types, bond/rate types | `REFERENCE.md` §6–8 |
| Pool & run assumptions, root finder | `REFERENCE.md` §12–14 |
| API methods & result structure | `REFERENCE.md` §15–16 |
| Minimal deal | `golden-paths/01-minimal-abs.md` |
| Assumptions & scenario sensitivity | `golden-paths/02-assumptions-and-scenarios.md` |
| Triggers / status switches | `golden-paths/03-triggers.md` |
| CLO-style tranche waterfall | `golden-paths/04-clo-waterfall.md` |
| Root finder / target IRR | `golden-paths/05-root-finder.md` |
| Revolving pool | `golden-paths/06-revolving.md` |
| Real loan tape | `golden-paths/07-loan-tape.md` |
| Fees, reserves, ledgers | `golden-paths/08-fees-reserves.md` |

## Running & reading

```python
r = api.run(deal, poolAssump=..., runAssump=[...], read=True)   # read defaults True
rs = api.runByScenarios(deal, poolAssump={"base": pa1, "stress": pa2})
rs = api.runByDealScenarios(deal, runAssump={"low": ra1, "high": ra2})
rs = api.runStructs({"DealA": d1, "DealB": d2}, poolAssump=pa)
rs = api.runByCombo({"DealA": d1}, poolAssump={...}, runAssump={...})
cf = api.runPool(pool, poolAssump)          # {poolName: {"flow": DataFrame, ...}}
cf = api.runAsset("2024-01-01", [asset], poolAssump)
fl = api.runFirstLoss(deal, "B", poolAssump)   # first-loss stress factor
roots = api.runRootFinder(deal, poolAssump, runAssump, (tweak, stop))
dates = api.runDates("2021-01-01", "MonthEnd", "2022-01-01")
```

Result keys: `r['pool']['flow']`, `r['bonds'][name]`, `r['accounts'][name]`,
`r['fees']`, `r['result']['logs' | 'status' | 'waterfall' | 'inspect' | 'report']`,
`r['pricing']`. Helpers: `readBondsCf`, `readFeesCf`, `readAccsCf`,
`readInspect`, `readLedgers`, `unifyTs`, `readFlowsByScenarios`,
`readMultiFlowsByScenarios`, `readFieldsByScenarios`, `toHtml`, `toExcel`,
`compResult`. See `REFERENCE.md` §15–16.

Pass `debug=True` to `api.run`/`runRootFinder` to get the request JSON without
sending it — the cheapest way to validate a deal map offline.

## Pitfalls

1. **Version skew** — client and engine must share MAJOR.MINOR. `check=False`
   skips the check; don't ship results built with it.
2. **`read` defaults to `True`** — pass `read=False` only when you want raw
   JSON. The common mistake is expecting DataFrames after `read=False`.
3. **`stated` too short ends the deal at closing** — extend stated maturity
   past the assets' remaining term.
4. **Tuple positions are positional** — pool assumptions are
   `(assetType, default, prepay, recovery, extra)`; use `None` for gaps.
5. **Single-element formulas need a trailing comma** — `("poolBalance",)`, not
   `("poolBalance")`.
6. **Enums are dict-wrapped** — `{"Sequential": None}`, `{"Equity": None}`,
   `{"Fixed": 0.05}`; a bare string fails.
7. **Action names and group order are exact, lowercase-sensitive** —
   `payPrin`, `accrueAndPayInt`; group order is `"byName"`/`"byMaturity"`/
   `"byCurRate"`/`"byProrata"` (not `"ByName"`).
8. **Bond groups are structural, not a field** — nest the bonds:
   `"bonds": {"Senior": {"A1": {...}, "A2": {...}}}`, then reference
   `"Senior"` in group actions. A `"bondGroup"` key inside a bond is ignored.
9. **Date strings are ISO `YYYY-MM-DD`** — other formats fail or raise.
10. **Unmapped pool sources vanish silently** — every source you care about
    must appear in `"collect"`.
11. **Reserve accounts need `type`** — otherwise the account is a plain
    passthrough with no target.
12. **Group/`writeOff`/`fundWith`/`liqRepay` arg counts** — `writeOff` and
    `fundWith` need an explicit limit (`None` is fine); use the 4-arg
    `liqRepay`. See `REFERENCE.md` §9.
13. **Large responses can truncate behind proxies** — pool projections grow with
    assets × periods; keep test deals small or use a local engine.

## Verification

1. Construct the deal, run with basic assumptions, and read
   `r['result']['logs']` before anything else.
2. Pool principal + losses should approximate the original balance.
3. Amortizing tranches should reach zero by stated maturity.
4. Scenario results must differ; identical output means the varied input had
   no effect.
5. `viz(deal)` (from `absbox.local.chart`) renders a Graphviz diagram.
6. Compare pricing (WAL/duration/yield) against a benchmark.

Files in this skill

  • REFERENCE.md27.5 KB
  • SKILL.md10.6 KB
  • doc/CHANGELOG.md2.8 KB
  • evals/bond-group-structural.eval.md964 B
  • evals/no-unverified-syntax.eval.md1.2 KB
  • evals/read-golden-path-first.eval.md1 KB
  • evals/trigger-not-in-preclosing.eval.md1.1 KB
  • evals/version-check-on-connect.eval.md1020 B
  • golden-paths/01-minimal-abs.md2.7 KB
  • golden-paths/02-assumptions-and-scenarios.md3.3 KB
  • golden-paths/03-triggers.md3.4 KB
  • golden-paths/04-clo-waterfall.md3.9 KB
  • golden-paths/05-root-finder.md3.5 KB
  • golden-paths/06-revolving.md3.4 KB
  • golden-paths/07-loan-tape.md2.8 KB
  • golden-paths/08-fees-reserves.md4.1 KB
  • golden-paths/README.md1.1 KB
  • scripts/smoke.py2.9 KB

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…