Skip to content

Reports

Use NubraReports to discover and generate back-office, tax, trade, portfolio, and mutual fund reports for the logged-in client.

Reports can return either JSON view data, downloadable PDF/XLSX files, or an email acknowledgement depending on the report and action_type.

Confidential data

Reports can contain client name, PAN, bank details, balances, holdings, trades, and tax data. Do not print or store full report payloads in shared logs.

Basic Setup

from nubra_python_sdk.start_sdk import InitNubraSdk, NubraEnv
from nubra_python_sdk.reports.reports_data import NubraReports
from nubra_python_sdk.reports.reports_enum import (
    ReportActionType,
    ReportExportFormat,
)

nubra = InitNubraSdk(NubraEnv.PROD, env_creds=True)
reports = NubraReports(nubra)

Action Types

Action Meaning
ReportActionType.VIEW Returns JSON parsed into an SDK response model
ReportActionType.DOWNLOAD Returns a ReportFile containing PDF/XLSX bytes
ReportActionType.EMAIL Sends the report to the client's registered email and returns an acknowledgement

Email action

EMAIL sends a real email to the logged-in client's registered email address. Use it only when the client expects the report by email.

Export Formats

Format Usage
ReportExportFormat.PDF Back-office report downloads where PDF is supported
ReportExportFormat.EXCEL Back-office report downloads where Excel is supported
ReportExportFormat.JSON Used internally for VIEW; do not pass it manually

Back-office reports can support PDF, EXCEL, VIEW, and EMAIL depending on the report. Tax, trade, portfolio snapshot, and mutual fund reports are XLSX-only for downloads.

Dates

Date arguments accept YYYY-MM-DD strings, ISO datetimes, datetime.date, and datetime.datetime.

reports.financial_ledger("2025-04-01", "2025-06-30")
reports.holding_statement("2025-07-28")

Naive dates are treated as IST midnight and sent to the API in RFC3339 format, such as 2025-04-01T00:00:00+05:30.

Discover Available Reports

Use report_options() to fetch the reports, actions, formats, password flag, and date range available for the logged-in client.

options = reports.report_options()
catalogue = options.res

if catalogue:
    for item in catalogue.reports:
        print(
            item.type,
            item.title,
            item.downloadFileTypes,
            item.actionTypes,
            item.minDate,
            item.maxDate,
            item.passwordProtected,
            item.password,
        )

Example response shape:

ReportOptionsResponse(
    message="report-options",
    res=ReportOptionsResult(
        categories=["ACCOUNT_STATEMENT", "HOLDING", "MUTUAL_FUND_REPORT", "PROFIT_LOSS"],
        reports=[
            ReportOption(
                category="ACCOUNT_STATEMENT",
                title="Financial ledger",
                type="summary",
                downloadFileTypes=["PDF", "EXCEL"],
                actionTypes=["DOWNLOAD"],
                dateRangeOptions=["DATE_RANGE"],
                passwordProtected=True,
                password="PAN",
                minDate="2025-04-01",
                maxDate="2026-07-28",
            )
        ],
    ),
)

Note

If passwordProtected=True and password="PAN", open the downloaded PDF with the client's PAN in upper case.

Report Method Map

Report type from report_options() SDK method Date input Actions
summary financial_ledger() from_date, to_date VIEW, DOWNLOAD, EMAIL
profit_loss profit_loss() from_date, to_date VIEW, DOWNLOAD, EMAIL
demat demat() from_date, to_date VIEW, DOWNLOAD, EMAIL
contract_note contract_note() from_date, to_date VIEW, DOWNLOAD, EMAIL
daily_margin daily_margin() date VIEW, DOWNLOAD, EMAIL
holding holding_statement() date VIEW, DOWNLOAD, EMAIL
open_positions open_positions() date VIEW, DOWNLOAD, EMAIL
dividend dividend() from_date, to_date VIEW, DOWNLOAD
tradebook-report tradebook() from_date, to_date VIEW, DOWNLOAD
trader-diary trader_diary() from_date, to_date DOWNLOAD
transaction mf_transactions() from_date, to_date VIEW, DOWNLOAD
orderbook mf_orderbook() from_date, to_date VIEW, DOWNLOAD
holdings mf_holdings() date VIEW, DOWNLOAD
capital_gains mf_capital_gains() from_date, to_date VIEW, DOWNLOAD
no catalogue entry portfolio_snapshot() none DOWNLOAD

Back-Office Reports

These reports support VIEW, DOWNLOAD, and EMAIL.

# View financial ledger as JSON
ledger = reports.financial_ledger(
    "2025-04-01",
    "2025-06-30",
    action_type=ReportActionType.VIEW,
)

payload = ledger.model_dump(by_alias=True, exclude_none=True)
print(payload.keys())
print(len(payload.get("Financial", [])))
# Download demat statement as PDF
pdf = reports.demat(
    "2025-04-01",
    "2025-06-30",
    action_type=ReportActionType.DOWNLOAD,
    export_format=ReportExportFormat.PDF,
    save_to="./reports",
)

print(pdf.filename, len(pdf), pdf.saved_path)
# Single-date holding statement
holding = reports.holding_statement(
    "2025-07-28",
    action_type=ReportActionType.VIEW,
)

print(holding.model_dump(by_alias=True, exclude_none=True).keys())
# Email profit and loss report
ack = reports.profit_loss(
    "2025-04-01",
    "2025-06-30",
    action_type=ReportActionType.EMAIL,
)

print(ack.message)

Tax And Trade Reports

These reports are XLSX-only for downloads. dividend() and tradebook() support VIEW; trader_diary() is download-only.

dividend = reports.dividend(
    "2025-04-01",
    "2026-03-31",
    action_type=ReportActionType.VIEW,
)

print(dividend.total_dividend_fy)
print(len(dividend.dividends))
tradebook = reports.tradebook(
    "2025-04-01",
    "2025-06-30",
    action_type=ReportActionType.VIEW,
)

print(len(tradebook.data))
diary = reports.trader_diary(
    "2025-04-01",
    "2025-06-30",
    save_to="./reports",
)

print(diary.filename, diary.saved_path)

Portfolio Snapshot

portfolio_snapshot() generates an XLSX workbook from live trading data. It has no date input and no report_options() entry.

snapshot = reports.portfolio_snapshot(save_to="./reports")
print(snapshot.filename, snapshot.saved_path)

Mutual Fund Reports

Mutual fund reports are XLSX-only for downloads and support VIEW and DOWNLOAD.

transactions = reports.mf_transactions(
    "2025-04-01",
    "2025-06-30",
    action_type=ReportActionType.VIEW,
)

rows = [row for group in transactions.transactions for row in group]
print(len(rows))
mf_orders = reports.mf_orderbook(
    "2025-04-01",
    "2025-06-30",
    action_type=ReportActionType.VIEW,
)

print(len(mf_orders.transactions))
mf_holdings = reports.mf_holdings(
    "2025-07-28",
    action_type=ReportActionType.VIEW,
)

print(mf_holdings.current_value, mf_holdings.pnl)
capital_gains = reports.mf_capital_gains(
    "2025-04-01",
    "2026-03-31",
    action_type=ReportActionType.VIEW,
)

print(len(capital_gains.capital_gains))

Downloaded Files

Every download returns a ReportFile.

report = reports.financial_ledger("2025-04-01", "2025-06-30")

print(report.filename)
print(report.content_type)
print(len(report))

path = report.save("./reports")
print(path)

save_to can be a directory or a full file path. Parent directories are created automatically.

Response Types

Action or method SDK return type
Back-office VIEW BackOfficeReportView
dividend(..., VIEW) DividendReportResponse
tradebook(..., VIEW) TradebookResponse
mf_transactions(..., VIEW) MFTransactionReportView
mf_orderbook(..., VIEW) MFOrderbookReportView
mf_holdings(..., VIEW) MFHoldingsReportView
mf_capital_gains(..., VIEW) MFCapitalGainsReportView
Any DOWNLOAD ReportFile
Back-office EMAIL EmailAck

Error Handling

from nubra_python_sdk.interceptor.errors import (
    NubraValidationError,
    BadRequestError,
    ServerError,
    UnauthorizedError,
    RetryLimitExceeded,
)

try:
    report = reports.demat("2025-04-01", "2025-06-30", save_to="./reports")
except NubraValidationError as e:
    print("Bad input:", e.validation_error)
except BadRequestError as e:
    print("Request rejected:", e)
except ServerError as e:
    print("Report generation failed or no data:", e)
except UnauthorizedError:
    print("Session refresh failed")
except RetryLimitExceeded:
    print("Network failure")

No-data windows

A report window with no rows can return a server error such as failed to generate report. please try again after some time. Treat this as a possible no-data window and retry with a report date range confirmed by report_options().

Important Rules

Important Rules

  • Call report_options() first when you need the available report list, date limits, supported formats, and password flag.
  • Clamp report dates to the report's minDate and maxDate.
  • For VIEW, the SDK sends export_format=JSON internally.
  • EMAIL is supported only for back-office reports and sends a real email.
  • Tax, trade, portfolio snapshot, and mutual fund report downloads are XLSX-only.
  • Downloaded files and JSON payloads can contain sensitive client information.
  1. Authentication
  2. Holdings
  3. Positions
NEO Assistant