Skip to main content

mts1b-treasury

Capital allocator, transfer planner, fund registry, NAV tracker, tax-lots.

Repo: github.com/MTS1B/mts1b-treasury Layer: 6 Wave: 3 (months 8-12) Depends on: foundation, platform, portfolio, oms, brokers, riskengine Audience: every operator with > 1 fund

What it is

Sits above the strategy layer. Manages capital across funds and sleeves: decides which fund gets how much NAV, plans transfers between brokers, tracks tax-lots, reports daily NAV.

treasury allocator (this repo)

├──▶ fund "paper-momentum" NAV $100k → portfolio + oms + brokers (paper)
├──▶ fund "live-crypto-revol" NAV $50k → portfolio + oms + brokers (coinbase)
├──▶ fund "live-equities-ls" NAV $250k → portfolio + oms + brokers (ibkr)
└──▶ fund "paper-sports" NAV $25k → sports + brokers (paper)

Module layout

mts1b_treasury/
├── allocator/
│ ├── core.py # decide NAV per fund based on goals + constraints
│ ├── rebalance.py # plan transfers
│ └── overrides.py # operator manual overrides
├── fund_registry/
│ ├── registry.py
│ └── api.py
├── nav/
│ ├── tracker.py # daily NAV snapshot per fund
│ └── attribution.py # decompose NAV moves
├── transfers/
│ ├── planner.py # broker A → bank → broker B route
│ └── executor.py # actually move money (manual co-sign required)
├── tax_lots/
│ ├── ledger.py # FIFO / HIFO / SpecID
│ └── annual_report.py # Form 1099-equivalent
└── api/
├── rest.py
└── grpc.py

Fund registry

class FundConfig(BaseModel):
fund_id: str
name: str
description: str
base_currency: str
target_nav_usd: Decimal
broker: str
broker_account_id: str
active: bool
asset_classes: list[str]
strategies: list[str]
created_at: datetime
notes: str

CRUD via REST or CLI:

mts mts1b-treasury fund create --fund-id paper-momentum --nav 100000 --broker paper
mts mts1b-treasury fund list
mts mts1b-treasury fund show --fund-id paper-momentum
mts mts1b-treasury fund edit --fund-id paper-momentum --target-nav 150000
mts mts1b-treasury fund close --fund-id paper-momentum --reason "demo done"

Allocator

The core question: given total firm NAV and a list of funds, how should capital be distributed?

from mts1b_treasury.allocator import allocate

decisions = await allocate(
funds=await fund_registry.active(),
total_nav=await get_firm_nav(),
constraints={
"min_per_fund": 25_000,
"max_per_fund_pct": 0.50, # no single fund > 50% of firm NAV
"max_sleeve_correlation": 0.7,
"preserve_capital_dnt": True, # don't trigger taxable events for rebalance
},
method="risk_parity", # or "kelly", "equal", "manual"
)
# [AllocationDecision(fund_id="paper-momentum", target_nav=Decimal('75000'),
# current_nav=Decimal('100000'), delta=Decimal('-25000'),
# reason="risk_parity rebalance + low Sharpe last 90d"),
# ...]

The decision is a plan, not an action — the operator co-signs before transfers execute.

Transfer planning

Moving money between brokers requires going through a bank, which takes 1-3 business days. The planner builds a route:

from mts1b_treasury.transfers import plan_transfer

route = await plan_transfer(
from_fund="paper-momentum-internal",
to_fund="live-crypto-revol",
amount_usd=10_000,
)
# TransferRoute(steps=[
# {step: 1, from: ibkr_internal, to: chase_checking, eta_business_days: 1,
# method: "ACH withdrawal", fee: $0},
# {step: 2, from: chase_checking, to: coinbase, eta_business_days: 1,
# method: "ACH deposit", fee: $0},
# ], total_eta_business_days: 2, total_fees: $0)

⚠️ The executor never moves money on its own. It produces operator-co-signable plans, which the operator approves via web UI (with 2FA) or signed CLI command.

Daily NAV snapshot per fund:

class NavSnapshot(BaseModel):
fund_id: str
asof: date
nav_usd: Decimal
cash_usd: Decimal
positions_market_value_usd: Decimal
pnl_today_usd: Decimal
pnl_today_pct: float
pnl_mtd_pct: float
pnl_ytd_pct: float
return_since_inception: float
drawdown_from_peak_pct: float
components: dict[str, Decimal] # per-strategy / per-symbol breakdown

Published to mts.v1.treasury.nav.<fund_id> at every market close + on demand.

Tax-lot ledger

Every fill creates a tax-lot. Closures match against lots via FIFO (default), HIFO (for capital-gains optimization), or SpecID (operator-specified).

class TaxLot(BaseModel):
lot_id: str
fund_id: str
symbol: Symbol
open_date: date
open_qty: Decimal
open_price: Decimal
close_date: date | None
close_qty: Decimal
close_price: Decimal | None
realized_pl_usd: Decimal | None
holding_period_days: int
short_term: bool # < 1 year

Used by mts1b-reportslibrary/settlement_report for tax filing.

Multi-currency

Each fund has a base_currency. Cross-currency P/L attribution separates:

  • Asset return (e.g., EURUSD +1% in EUR terms)
  • Currency return (e.g., EUR/USD -0.5%)
  • Combined (your USD P/L)

Used in mts1b-reportslibrary/nav_report for international funds.

Build + test

pip install -e ".[dev]"
pytest -m unit
docker compose up -d postgres
pytest -m integration

Roadmap

VersionItems
0.1 (Wave 3)Fund registry, allocator (equal + risk parity), NAV tracker, tax lots, transfer planner
0.2 (Wave 3)Manual transfer execution with 2FA co-sign
0.3 (Wave 3)Kelly-based allocation across funds
0.4Multi-currency hedging recommendations
1.0 (LTS)Stable fund spec

See also