Asset Allocation (AA) — Local CLI
All commands run from backend/, venv activated (hard rule 1 — never run modules from
inside their package folder). Target DB is whatever LOCAL_DB_* in backend/.env
points to — tedb on localhost by default.
cd backend
venv\Scripts\activate
1. Apply the migrations
alembic upgrade head
Applies every migration in the chain, including the AA-related ones. Safe to re-run —
Alembic tracks the applied revision and no-ops if already at head.
Check current revision:
alembic current
Full chain (oldest to newest), for orientation:
alembic history
2. Seed the data
python -m AA.seed_financial_data_2000_2026
Idempotent — inserts 3 assets (SAVINGS_RATE_SBI, FD_RATE_SBI_1Y,
CPI_INFLATION_INDIA) into te_asset and their price rows into te_price, all via
ON CONFLICT DO NOTHING. Re-running prints Inserted 0 new ... row(s) once seeded. To
revise an already-seeded value, edit the script's data table and issue an UPDATE
manually (or a migration) — it never overwrites an existing row.
Source data lives in AA/data/India_Financial_Data_2000-2026.xlsx (a user-supplied
workbook, copied into the repo) — see AA/CLAUDE.md rule 6a for how ambiguous rows
(ranges, multiple in-year revisions) were resolved into single values.
3. Run the tests
python -m pytest tests/test_aa_models.py tests/test_aa_allocation_engine.py -v
test_aa_models.py asserts te_asset's PK/unique/CHECK constraints (including the
economic_data category) and te_price's PK/FK constraints are enforced at the schema
level (SAVEPOINT-backed, tests/conftest.py — nothing written lingers in tedb).
test_aa_allocation_engine.py is pure unit tests of the CAGR/backtest math against the
older wide-table shape it was written for — kept passing (it's self-consistent with its
own fixtures) but not exercised by anything live; see AA/CLAUDE.md's Status section.
Quick sanity check — everything at once
cd backend
alembic upgrade head
python -m AA.seed_financial_data_2000_2026
python -m pytest tests/test_aa_models.py tests/test_aa_allocation_engine.py -v
Expect: migrations apply (or no-op if already applied), seed reports 3 assets + 68
price rows inserted the first time / 0 thereafter, all tests PASSED.
Poke the data manually
python -c "
from sqlalchemy import create_engine, text
from app.core.config import settings
engine = create_engine(settings.SYNC_DATABASE_URL)
with engine.connect() as conn:
for row in conn.execute(text('SELECT code, asset_class, value_kind FROM te_asset ORDER BY id')):
print(row)
"