Practical Examples & Recipes¶
This page provides practical, copy-pasteable recipes for common workflows using folioman-client.
1. Complete End-to-End Ingestion & Portfolio Valuation¶
This script initializes the local database, ingests a CAMS/KFintech CAS statement, updates market prices, and prints portfolio metrics:
import asyncio
from folioman_client import FoliomanClient
async def main() -> None:
async with FoliomanClient() as client:
# Step 1: Ingest statement PDF
print("Parsing CAS statement...")
job = await client.imports.cas_pdf(
file_path="CAMS_CAS_Jan2026.pdf",
password="ABCDE1234F",
)
print(f"Transactions created: {job.result.get('transactions_created')}")
# Step 2: Fetch latest NAVs and prices
print("Updating market prices...")
await client.navs.refresh()
# Step 3: Print portfolio valuation
summary = await client.portfolio.get(investor_id=1)
print(f"\n=== Portfolio Summary as of {summary.as_of} ===")
print(f"Market Value: INR {summary.total_inr:,.2f}")
print(f"Cost Basis: INR {summary.invested_inr:,.2f}")
print(f"Absolute P&L: INR {summary.unrealized_pnl_inr:,.2f} ({summary.return_pct:.2f}%)")
if summary.xirr is not None:
print(f"Annual XIRR: {summary.xirr * 100:.2f}%")
# Step 4: Asset allocation breakdown
print("\n--- Asset Allocation ---")
for mix in summary.asset_mix:
print(f"{mix.security_type.title():<12}: INR {mix.value_inr:>12,.2f}")
if __name__ == "__main__":
asyncio.run(main())
2. Generating Schedule 112A Realized Capital Gains (Tax Filing)¶
Generate a detailed lot-level report for the Indian Income Tax Return (ITR):
import asyncio
from folioman_client import FoliomanClient
async def main() -> None:
async with FoliomanClient() as client:
# Generate capital gains report for Financial Year 2024-25 (Apr 2024 - Mar 2025)
report = await client.capital_gains.get(investor_id=1, fy="2024-25")
print(f"=== Capital Gains Report for FY {report.fy} ===")
print(f"Total Disposals: {len(report.rows)}")
print(f"Realized STCG: INR {report.summary.stcg_inr:,.2f}")
print(f"Realized LTCG: INR {report.summary.ltcg_inr:,.2f}")
print(f"Total Gain: INR {report.summary.total_gain_inr:,.2f}")
# Display Schedule 112A eligible lots
print("\n--- Disposal Lot Details ---")
for row in report.rows[:5]:
print(
f"{row.security_name[:25]:<26} | Sold: {row.date} | "
f"Units: {row.units:>8.3f} | Gain: INR {row.gain_inr:>10,.2f} ({row.term})"
)
if __name__ == "__main__":
asyncio.run(main())
3. Extracting Historical Net-Worth Time Series¶
Reconstruct the daily, weekly, or monthly net-worth progression of an investor:
import asyncio
from folioman_client import FoliomanClient
async def main() -> None:
async with FoliomanClient() as client:
# Fetch monthly progression over the last year
series = await client.valuations.list(
investor_id=1,
from_date="2025-01-01",
to_date="2026-01-01",
granularity="monthly",
)
print(f"Historical Net-Worth Points ({len(series.points)} entries):")
for point in series.points:
print(f"Date: {point.date} | Net Worth: INR {point.value_inr:,.2f}")
if __name__ == "__main__":
asyncio.run(main())
4. Multi-Tenant Setup with PostgreSQL¶
In a wealth advisory or multi-tenant system, use user_id to enforce logical multi-tenancy:
import asyncio
from folioman_client import FoliomanClient
DATABASE_URL = "postgresql+psycopg://advisor:secret@localhost:5432/wealth_db"
async def main() -> None:
# Client for Advisor A
async with FoliomanClient(database_url=DATABASE_URL, user_id="advisor_alpha") as client_a:
inv_a = await client_a.investors.create("Ramesh Sharma")
print(f"Created Investor in Alpha: {inv_a.name} (ID: {inv_a.id})")
# Client for Advisor B
async with FoliomanClient(database_url=DATABASE_URL, user_id="advisor_beta") as client_b:
inv_b = await client_b.investors.create("Priya Verma")
print(f"Created Investor in Beta: {inv_b.name} (ID: {inv_b.id})")
# Advisor B cannot see Advisor A's investors
investors = await client_b.investors.list()
print(f"Advisor B sees {len(investors)} investor(s).")
if __name__ == "__main__":
asyncio.run(main())
5. Automated Weekly NAV Sync with Embedded Scheduler¶
For persistent processes (e.g. desktop apps or long-running worker services), enable the embedded scheduler:
import asyncio
from folioman_client import FoliomanClient
async def main() -> None:
# Launch with background scheduler enabled (runs daemon thread)
async with FoliomanClient(start_scheduler=True) as client:
print("Folioman engine running with 6-hourly background NAV sync...")
# Keep process alive
while True:
await asyncio.sleep(3600)
if __name__ == "__main__":
asyncio.run(main())