Skip to main content

Nubra-native analytics, plots, and reports for trading workflows.

Project description

nubrastats

nubrastats is a Nubra-native helper library for:

  • strategy analytics
  • performance plots
  • HTML tearsheet reports
  • Nubra API historical data parsing
  • Nubra order/trade payload normalization

It is designed so users can fetch market data from Nubra and generate metrics/reports with minimal code.

What This Library Does

Standard workflow:

  1. Fetch close prices from Nubra Historical API (nubrastats.nubra)
  2. Convert prices to returns (nubrastats.utils.to_returns)
  3. Compute performance metrics (nubrastats.stats)
  4. Generate charts (nubrastats.plots)
  5. Export terminal/HTML reports (nubrastats.reports)

Alternative workflow:

  1. Convert filled order payloads to trade rows (nubrastats.adapters.orders_to_trades)
  2. Compute realized FIFO PnL (nubrastats.adapters.realized_pnl_fifo)
  3. Build equity and returns from trades
  4. Run the same stats/plots/reports pipeline

Installation

Local editable install:

cd nubra-stats
pip install -e .[dev]

If you use Nubra API fetch helpers, install Nubra SDK:

python -m pip install nubra-sdk

Packaging Notes

  • The published package is Nubra-only (nubrastats).
  • Example scripts in examples/ are for local development and are excluded from release artifacts.
  • Release artifacts include:
    • library source under src/nubrastats
    • HTML templates under src/nubrastats/templates
    • project metadata (pyproject.toml, README.md, LICENSE)

Quick Start (Minimal)

import pandas as pd
import nubrastats as ns

returns = pd.Series([0.01, -0.005, 0.007, 0.002])
ns.reports.metrics(returns=returns, display=True)
ns.reports.html(returns=returns, title="Demo", output="demo-report.html")
# detailed tearsheet mode (extended metrics + multi-section charts)
ns.reports.html(
    returns=returns,
    title="Demo Detailed",
    output="demo-detailed-report.html",
    mode="detailed",
)

Quick Start (Nubra API -> Report)

from nubra_python_sdk.marketdata.market_data import MarketData
from nubra_python_sdk.start_sdk import InitNubraSdk, NubraEnv
import pandas as pd
import nubrastats as ns

nubra = InitNubraSdk(env=NubraEnv.UAT, env_creds=True, totp_login=False)
md = MarketData(nubra)

prices = ns.nubra.fetch_close_series(
    md_client=md,
    symbol="RELIANCE",
    exchange="NSE",
    instrument_type="STOCK",
    start="2025-01-01",
    end="2025-12-31",
    interval="1d",
)

returns = ns.utils.to_series(ns.utils.to_returns(prices)).dropna()
ns.reports.metrics(returns=returns, display=True)
ns.reports.html(returns=returns, title="RELIANCE Report", output="reliance_report.html")
ns.reports.html(
    returns=returns,
    benchmark=returns * 0.8,  # replace with actual benchmark returns
    title="RELIANCE Detailed Report",
    output="reliance_detailed_report.html",
    mode="detailed",
)

Quick Start (One Call, Minimal User Code)

from nubra_python_sdk.marketdata.market_data import MarketData
from nubra_python_sdk.start_sdk import InitNubraSdk, NubraEnv
import nubrastats as ns

nubra = InitNubraSdk(env=NubraEnv.UAT, env_creds=True)
md = MarketData(nubra)

result = ns.nubra.analyze_symbol(
    md_client=md,
    symbol="RELIANCE",
    exchange="NSE",
    instrument_type="STOCK",
    start="2025-01-01",
    end="2025-12-31",
    interval="1d",
    benchmark_symbol="NIFTY",          # optional
    show_plots=True,                    # pop up plots
    save_plots=False,                   # optional PNG save
    generate_html=True,                 # optional HTML report
    open_html=True,                     # optional browser auto-open
    html_output="reliance_report.html",
    html_mode="detailed",               # "basic" | "detailed"
)

In generated metrics/HTML, the strategy and benchmark are labeled using the actual symbols (for example RELIANCE and NIFTY) instead of generic names. The equity curve represents compounded notional capital (base 100000) from periodic returns, not raw stock price.

Quick Start (Popup UI)

If you want users to only call one function and fill details in a popup:

import nubrastats as ns

ns.ui.launch_analyzer_ui()

This opens a small UI form for:

  • symbol/exchange/type
  • date range (calendar picker) and interval
  • benchmark options
  • plot popup options
  • optional PNG/HTML output options

After clicking Generate Report, the library handles authentication, analysis, and report generation internally.

.env credential note for popup/auth flows:

  • keep a .env file in project root or examples/.env
  • use keys exactly: PHONE_NO and MPIN
  • recommended format:
    • PHONE_NO="9999999999"
    • MPIN="1234"

When popup plot display is enabled, charts open in one viewer with Previous/Next navigation and keyboard arrow support.

Input Conventions

  • returns are decimal returns per period, not percentage.
    • Example: 0.01 means +1%.
  • prices and equity should be pandas.Series with datetime index.
  • Nubra historical close values are treated as paise and converted to rupees (price_scale="paise" default in nubrastats.nubra.fetch_close_series).
  • Trade prices/fees from broker payloads may be paise-based.
    • adapters.orders_to_trades(..., price_scale="paise") converts to rupees.

Public API Reference

Top-Level Package (nubrastats)

  • nubrastats.__version__
  • nubrastats.extend_pandas()
  • modules:
    • nubrastats.nubra
    • nubrastats.adapters
    • nubrastats.utils
    • nubrastats.stats
    • nubrastats.plots
    • nubrastats.reports
    • nubrastats.ui

extend_pandas() adds methods to pandas objects:

  • ns_to_returns
  • ns_to_equity
  • ns_sharpe
  • ns_sortino
  • ns_cagr
  • ns_max_drawdown
  • ns_drawdown_series

Module: nubrastats.nubra

Purpose: build Nubra historical request payloads and extract close price series.

Constants

  • NUBRA_INTERVALS = {"1s","1m","2m","3m","5m","15m","30m","1h","1d","1w","1mt"}
  • NUBRA_TYPES = {"STOCK","INDEX","OPT","FUT"}

Dataclass: Instrument

Field Type Default
symbol str required
exchange str "NSE"
instrument_type str "STOCK"

Functions

to_utc_iso(value: str | pd.Timestamp) -> str

Converts input datetime to UTC ISO string ending with Z.

Parameters:

  • value: date/time string or pd.Timestamp

build_historical_payload(...) -> dict[str, Any]

Signature:

build_historical_payload(
    *,
    symbol: str,
    exchange: str,
    instrument_type: str,
    start: str | pd.Timestamp,
    end: str | pd.Timestamp,
    interval: str = "1d",
    fields: list[str] | None = None,
) -> dict[str, Any]

Parameters:

  • symbol: instrument symbol
  • exchange: exchange name, e.g. "NSE"
  • instrument_type: one of STOCK/INDEX/OPT/FUT
  • start: start date/time
  • end: end date/time
  • interval: one of Nubra supported intervals above
  • fields: API fields list; defaults to ["close"]

Returns:

  • request payload dict for MarketData.historical_data

close_series_from_historical_response(response, symbol) -> pd.Series

Extracts close prices from Nubra historical response object for one symbol.

Parameters:

  • response: object returned by md_client.historical_data(...)
  • symbol: symbol to extract

Returns:

  • close-price pd.Series indexed by timestamp

fetch_close_series(...) -> pd.Series

Signature:

fetch_close_series(
    md_client: Any,
    *,
    symbol: str,
    exchange: str = "NSE",
    instrument_type: str = "STOCK",
    start: str | pd.Timestamp,
    end: str | pd.Timestamp,
    interval: str = "1d",
) -> pd.Series

Parameters:

  • md_client: Nubra MarketData instance
  • symbol, exchange, instrument_type: instrument identity
  • start, end: date bounds
  • interval: candle interval

Returns:

  • filtered close-price pd.Series for the selected range

Raises:

  • ValueError when no data is available or invalid date interval

analyze_symbol(...) -> dict[str, Any]

One-call convenience pipeline for minimal user code:

  1. fetch primary symbol historical close
  2. optional benchmark fetch and alignment
  3. compute returns/equity
  4. compute metrics
  5. show plots immediately (show_plots=True)
  6. optionally save PNGs (save_plots=True)
  7. optionally generate HTML report (generate_html=True)
  8. optionally auto-open HTML (open_html=True)

Signature:

analyze_symbol(
    md_client: Any,
    *,
    symbol: str,
    exchange: str = "NSE",
    instrument_type: str = "STOCK",
    start: str | pd.Timestamp,
    end: str | pd.Timestamp,
    interval: str = "1d",
    benchmark_symbol: str | None = None,
    benchmark_exchange: str = "NSE",
    benchmark_instrument_type: str = "INDEX",
    rf: float = 0.0,
    periods_per_year: int = 252,
    show_plots: bool = True,
    save_plots: bool = False,
    plots_dir: str | None = None,
    generate_html: bool = False,
    open_html: bool = False,
    html_output: str | None = None,
    html_mode: str = "basic",
    title: str | None = None,
    display_metrics: bool = True,
) -> dict[str, Any]

Returns dictionary keys:

  • prices, returns, equity
  • benchmark_prices, benchmark_returns, benchmark_equity
  • metrics (DataFrame)
  • plot_paths (empty unless save_plots=True)
  • html_path (None unless generate_html=True)
  • html_opened (True if browser auto-open succeeded)
  • html_mode ("basic" or "detailed")

Module: nubrastats.ui

Purpose: popup-based minimal UX for end users (no manual plumbing code).

Dataclass: AnalyzerUIConfig

Holds all UI/run configuration fields such as:

  • environment + login flags
  • primary symbol settings
  • benchmark settings
  • plot/report options

run_from_config(config, *, md_client=None) -> dict[str, Any]

Runs analysis directly from a config object.

Parameters:

  • config: AnalyzerUIConfig
  • md_client: optional pre-created Nubra MarketData client

Returns:

  • same output dictionary as nubrastats.nubra.analyze_symbol

launch_analyzer_ui(initial=None) -> None

Opens the popup UI and executes analysis when user clicks Generate Report.

Parameters:

  • initial: optional AnalyzerUIConfig to prefill defaults

Module: nubrastats.adapters

Purpose: convert broker/order payloads into consistent trade tables and PnL.

orders_to_trades(orders, *, price_scale="paise") -> pd.DataFrame

Parameters:

  • orders: iterable of order dicts
  • price_scale: "paise" or raw-unscaled mode

Reads these possible keys from each order:

  • quantity keys: filled_qty, order_qty, trade_qty, quantity
  • price keys: avg_filled_price, trade_price, order_price, price, last_traded_price
  • side keys: order_side, side
  • timestamp keys: filled_time, order_time, last_modified, timestamp
  • fee keys: brokerage, fee, charges

Output columns:

  • timestamp, symbol, side, quantity, price, fee, order_id, tag, strategy_id, status

realized_pnl_fifo(trades: pd.DataFrame) -> pd.DataFrame

Computes realized PnL using per-symbol FIFO lot matching. Supports long and short inventory transitions.

Required columns:

  • timestamp, symbol, side, quantity, price

Optional:

  • fee (defaults to 0.0)

Adds columns:

  • realized_pnl
  • cum_realized_pnl

equity_curve_from_trades(trades, *, starting_capital=100000.0) -> pd.Series

If realized_pnl is missing, it computes it first via FIFO. Then cumulative sum over realized PnL on top of starting capital.

returns_from_trades(trades, *, starting_capital=100000.0) -> pd.Series

Builds equity curve from trades and converts it to period returns.

Module: nubrastats.utils

Purpose: reusable conversion/index/time helpers.

to_series(data) -> pd.Series

Parameters:

  • data: pd.Series, pd.DataFrame, or iterable

Returns:

  • one pd.Series (for DataFrame takes first column)

ensure_datetime_index(data, *, fallback_start=None, freq="D")

Ensures datetime index. If conversion fails, generates date range index.

to_returns(equity) -> pd.Series | pd.DataFrame

Converts equity/price series to returns via pct_change.

to_equity(returns, *, start_balance=100000.0)

Compounds returns into equity series.

annualization_factor(periods_per_year=252) -> int

Returns a safe annualization factor (min 1).

safe_div(numerator, denominator) -> float

Returns NaN if denominator is zero or NaN.

monthly_returns_matrix(returns: pd.Series) -> pd.DataFrame

Pivoted matrix: index year, columns Jan..Dec, values monthly compounded returns.

normalize_side(value: str) -> str

Maps side aliases to standard:

  • BUY aliases: BUY, ORDER_SIDE_BUY, B
  • SELL aliases: SELL, ORDER_SIDE_SELL, S

to_timestamp(value) -> pd.Timestamp

Converts int/float/string timestamps. For numeric values, tries:

  • nanoseconds if very large
  • milliseconds
  • seconds

Module: nubrastats.stats

Purpose: performance metrics from returns/equity/trades.

comp(returns) -> float | pd.Series

Compounded return: prod(1 + r) - 1.

cagr(returns, periods_per_year=252) -> float

Annualized compounded growth rate.

volatility(returns, periods_per_year=252, annualize=True) -> float

Sample standard deviation; annualized if requested.

sharpe(returns, rf=0.0, periods_per_year=252) -> float

Sharpe ratio using per-period risk-free conversion.

sortino(returns, rf=0.0, periods_per_year=252) -> float

Sortino ratio using downside deviation only.

drawdown_series(returns=None, equity=None) -> pd.Series

Drawdown over time: equity / cummax(equity) - 1. Either returns or equity must be provided.

max_drawdown(returns=None, equity=None) -> float

Minimum value of drawdown series.

win_rate_returns(returns) -> float

Fraction of positive non-zero return periods.

win_rate_trades(trades) -> float

Fraction of positive non-zero trade PnL rows. Uses realized_pnl column when available, otherwise pnl.

profit_factor(trades) -> float

sum(winning pnl) / abs(sum(losing pnl)).

expectancy(trades) -> float

Mean trade PnL.

summary(...) -> pd.Series

Signature:

summary(
    *,
    returns: pd.Series | None = None,
    equity: pd.Series | None = None,
    trades: pd.DataFrame | None = None,
    rf: float = 0.0,
    periods_per_year: int = 252,
) -> pd.Series

Returns these keys:

  • Total Return
  • CAGR
  • Volatility
  • Sharpe
  • Sortino
  • Max Drawdown
  • Win Rate (Periods)
  • Avg Return
  • Best Period
  • Worst Period

If trades provided, also:

  • Win Rate (Trades)
  • Profit Factor
  • Expectancy
  • Trade Count

Module: nubrastats.plots

Purpose: plotting helpers using matplotlib/seaborn.

All plotting functions return matplotlib.figure.Figure. Most functions support:

  • show=True/False
  • savefig={...} passed to fig.savefig

By default, plots are displayed when show=True. Saving PNG files is optional via savefig or higher-level helpers.

equity_curve(equity, benchmark=None, *, title="Equity Curve", show=True, savefig=None)

Plots strategy equity and optional benchmark equity.

drawdown(returns=None, equity=None, *, title="Drawdown", show=True, savefig=None)

Filled drawdown chart from returns or equity.

monthly_heatmap(returns, *, title="Monthly Returns Heatmap", show=True, savefig=None)

Year-month heatmap in percentage terms.

pnl_distribution(trades, *, title="Trade PnL Distribution", show=True, savefig=None)

Histogram/KDE of trade PnL (realized_pnl or pnl).

rolling_sharpe(returns, *, window=63, rf=0.0, periods_per_year=252, title="Rolling Sharpe", show=True, savefig=None)

Rolling Sharpe time series plot.

figure_to_png_bytes(fig) -> bytes

Encodes a figure as PNG bytes (used by HTML report embedding).

Module: nubrastats.reports

Purpose: ready-to-use metrics tables and report generation.

metrics(...) -> pd.DataFrame

Signature:

metrics(
    *,
    returns: pd.Series | None = None,
    equity: pd.Series | None = None,
    trades: pd.DataFrame | None = None,
    benchmark: pd.Series | None = None,
    rf: float = 0.0,
    periods_per_year: int = 252,
    display: bool = True,
    precision: int = 4,
) -> pd.DataFrame

Behavior:

  • computes summary metrics for strategy
  • optional benchmark summary in second column
  • prints table if display=True

basic(...) -> pd.DataFrame

Same metric inputs as metrics plus:

  • show_plots: bool = True

Behavior:

  • prints metrics
  • optional standard plot set (equity/drawdown/monthly heatmap)

full(...) -> pd.DataFrame

Same parameters as basic.

Behavior:

  • includes basic metrics
  • adds rolling Sharpe and PnL distribution (if trades provided)

html(...) -> str

Signature:

html(
    *,
    returns: pd.Series | None = None,
    equity: pd.Series | None = None,
    trades: pd.DataFrame | None = None,
    benchmark: pd.Series | None = None,
    rf: float = 0.0,
    periods_per_year: int = 252,
    title: str = "Nubra Strategy Tearsheet",
    output: str | None = None,
    template_path: str | None = None,
    mode: str = "basic",
) -> str

Behavior:

  • mode="basic": compact report (metrics + core charts)
  • mode="detailed": extended tearsheet (multi-section charts + advanced tables)
  • writes file to output:
    • basic default: nubrastats-report.html
    • detailed default: nubrastats-detailed-report.html

Returns:

  • output file path string

Module: nubrastats.models

Simple typed dataclasses:

Trade

Field Type Required Default
timestamp datetime yes -
symbol str yes -
side str yes -
quantity float yes -
price float yes -
fee float no 0.0
strategy_id `str None` no
tag `str None` no

OrderEvent

Field Type Required Default
timestamp datetime yes -
order_id `str int` yes
symbol str yes -
side str yes -
quantity float yes -
price float yes -
status str yes -
tag `str None` no

Example Scripts Included

Script Purpose
examples/import_smoke.py import/version smoke test
examples/generate_report.py sample report generation from sample trades
examples/terminal_menu_tester.py interactive Nubra terminal flow
examples/nubra_api_static_test.py non-interactive QA/checklist runner
examples/nubra_api_quick_test.py short placeholder-based run script
examples/detailed_report_mode_demo.py generate extended HTML tearsheet (mode="detailed")
examples/nubra_ui_popup_demo.py one-function popup UI launcher

Testing and Quality

Run checks:

python -m ruff check src tests examples
python -m pytest

Build package:

python -m build
python -m twine check dist/*

Notes

  • The quick script is for minimal user lines.
  • The static script is intentionally larger for diagnostics and validation checks.
  • This project is Nubra-native and does not depend on external market-data providers.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

nubrastats-0.1.2.tar.gz (46.1 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

nubrastats-0.1.2-py3-none-any.whl (41.8 kB view details)

Uploaded Python 3

File details

Details for the file nubrastats-0.1.2.tar.gz.

File metadata

  • Download URL: nubrastats-0.1.2.tar.gz
  • Upload date:
  • Size: 46.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.7

File hashes

Hashes for nubrastats-0.1.2.tar.gz
Algorithm Hash digest
SHA256 e774ae65954c358b9cd269c136a21ba858725908dae4e4198aa9a196ec4569ea
MD5 29e50d0b7c36507ffb93f322255eb12e
BLAKE2b-256 b170401ffa3c93abe2c70badbcd54ee0acdb1c1d426cd71a86cabeb4521ebf55

See more details on using hashes here.

File details

Details for the file nubrastats-0.1.2-py3-none-any.whl.

File metadata

  • Download URL: nubrastats-0.1.2-py3-none-any.whl
  • Upload date:
  • Size: 41.8 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.7

File hashes

Hashes for nubrastats-0.1.2-py3-none-any.whl
Algorithm Hash digest
SHA256 06b35f1cce6888b0c5dcefe003f0bc1a03c6b5a193ffce462583c5be9c7e2a18
MD5 9b002224b8ecba6b6493c22f15c3b397
BLAKE2b-256 0c21ce5bd0ffe4cb4efe657c7a741daefb4c8ba98da8f9748472f950ee778c31

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page