跳到主要内容

报告

This 指南 explains the 投资组合 analysis and reporting capabilities provided by the ReportProvider class, and how these 报告 are used for PnL accounting and backtest post-run analysis.

概览

The ReportProvider class in NautilusTrader generates structured analytical 报告 from trading 数据, transforming raw 订单, fills, 头寸, and account states into pandas DataFrames for analysis and visualization. These 报告 are essential for understanding strategy 性能, analyzing 执行 quality, and ensuring accurate PnL accounting.

报告 can be generated using two approaches:

  • Trader helper methods (recommended): Convenient methods like trader.generate_orders_report().
  • ReportProvider directly: For more control over data selection and filtering.

报告 provide consistent analytics across both 回测 and 实时交易 environments, enabling reliable 性能 evaluation and strategy comparison.

Available 报告

The ReportProvider class offers several static methods to generate 报告 from trading 数据. Each report returns a pandas DataFrame with specific columns and indexing for easy analysis.

订单 report

Generates a comprehensive view of all 订单:

# Using Trader helper method (recommended)
orders_report = trader.generate_orders_report()

# Or using ReportProvider directly
from nautilus_trader.analysis.reporter import ReportProvider
orders = cache.orders()
orders_report = ReportProvider.generate_orders_report(orders)

Returns pd.DataFrame with:

ColumnDescription
client_order_idIndex - unique order identifier.
instrument_idTrading instrument.
strategy_idStrategy that created the order.
sideBUY or SELL.
typeMARKET, LIMIT, etc.
statusCurrent order status.
quantityOriginal order quantity (string).
filled_qtyAmount filled (string).
priceLimit price (string if set).
avg_pxAverage fill price (float if set).
ts_initOrder initialization timestamp (nanoseconds).
ts_lastLast 更新 timestamp (nanoseconds).

Order fills report

Provides a summary of filled 订单 (one row per order):

# Using Trader helper method (recommended)
fills_report = trader.generate_order_fills_report()

# Or using ReportProvider directly
orders = cache.orders()
fills_report = ReportProvider.generate_order_fills_report(orders)

This report includes only 订单 with filled_qty > 0 and contains the same columns as the 订单 report, but filtered to executed 订单 only. Note that ts_init and ts_last are converted to datetime objects in this report for easier analysis.

Fills report

Details individual fill events (one row per fill):

# Using Trader helper method (recommended)
fills_report = trader.generate_fills_report()

# Or using ReportProvider directly
orders = cache.orders()
fills_report = ReportProvider.generate_fills_report(orders)

Returns pd.DataFrame with:

ColumnDescription
client_order_idIndex - order identifier.
trade_idUnique trade/fill identifier.
venue_order_idVenue-assigned order ID.
last_pxFill 执行 price (string).
last_qtyFill 执行 quantity (string).
liquidity_sideMAKER or TAKER.
commissionCommission amount and currency.
ts_eventFill timestamp (datetime).
ts_initInitialization timestamp (datetime).

头寸 report

Comprehensive position analysis including snapshots:

# Using Trader helper method (recommended)
# Automatically includes snapshots for NETTING OMS
positions_report = trader.generate_positions_report()

# Or using ReportProvider directly
positions = cache.positions()
snapshots = cache.position_snapshots() # For NETTING OMS
positions_report = ReportProvider.generate_positions_report(
positions=positions,
snapshots=snapshots
)

Returns pd.DataFrame with:

ColumnDescription
position_idIndex - unique position identifier.
instrument_idTrading instrument.
strategy_idStrategy that managed the position.
entryEntry side (BUY or SELL).
sidePosition side (LONG, SHORT, or FLAT).
quantityPosition size.
peak_qtyMaximum size reached.
avg_px_openAverage entry price.
avg_px_closeAverage exit price (if closed).
realized_pnlRealized profit/loss.
realized_returnReturn percentage.
ts_openedOpening timestamp (datetime).
ts_closedClosing timestamp (datetime or NA).
duration_nsPosition duration in nanoseconds.
is_snapshotWhether this is a historical snapshot.

Account report

Tracks account balance and margin changes over time:

# Using Trader helper method (recommended)
# Requires venue parameter
from nautilus_trader.model.identifiers import Venue
venue = Venue("BINANCE")
account_report = trader.generate_account_report(venue)

# Or using ReportProvider directly
account = cache.account(account_id)
account_report = ReportProvider.generate_account_report(account)

Returns pd.DataFrame with:

ColumnDescription
ts_eventIndex - timestamp of account state change.
account_idAccount identifier.
account_typeType of account (e.g., SPOT, MARGIN).
base_currencyBase currency for the account.
totalTotal balance amount.
freeAvailable balance.
lockedBalance locked in 订单.
currencyCurrency of the balance.
reportedWhether balance was reported by venue.
marginsMargin information (if applicable).
infoAdditional venue-specific information.

PnL accounting considerations

Accurate PnL accounting requires careful consideration of several factors:

Position-based PnL

  • Realized PnL: Calculated when positions are partially or fully closed.
  • Unrealized PnL: Marked-to-market using current prices.
  • Commission impact: Only included when in settlement currency.
注意

PnL calculations depend on the OMS type. In NETTING mode, position snapshots preserve historical PnL when 头寸 reopen. Always include snapshots in 报告 for accurate total PnL calculation.

Multi-currency accounting

When dealing with multiple currencies:

  • Each position tracks PnL in its settlement currency.
  • 投资组合 aggregation requires currency conversion.
  • Commission currencies may differ from settlement currency.
# Accessing PnL across positions
for position in positions:
realized = position.realized_pnl # In settlement currency
unrealized = position.unrealized_pnl(last_price)

# Handle multi-currency aggregation (illustrative)
# Note: Currency conversion requires user-provided exchange rates
if position.settlement_currency != base_currency:
# Apply conversion rate from your data source
# rate = get_exchange_rate(position.settlement_currency, base_currency)
# realized_converted = realized.as_double() * rate
pass

Snapshot considerations

For NETTING OMS configurations:

from nautilus_trader.model.objects import Money

# Include snapshots for complete PnL (per currency)
pnl_by_currency = {}

# Add PnL from current positions
for position in cache.positions(instrument_id=instrument_id):
if position.realized_pnl:
currency = position.realized_pnl.currency
if currency not in pnl_by_currency:
pnl_by_currency[currency] = 0.0
pnl_by_currency[currency] += position.realized_pnl.as_double()

# Add PnL from historical snapshots
for snapshot in cache.position_snapshots(instrument_id=instrument_id):
if snapshot.realized_pnl:
currency = snapshot.realized_pnl.currency
if currency not in pnl_by_currency:
pnl_by_currency[currency] = 0.0
pnl_by_currency[currency] += snapshot.realized_pnl.as_double()

# Create Money objects for each currency
total_pnls = [Money(amount, currency) for currency, amount in pnl_by_currency.items()]

Backtest post-run analysis

After a backtest completes, comprehensive analysis is available through various 报告 and the 投资组合 analyzer.

Accessing backtest results

# After backtest run
engine.run(start=start_time, end=end_time)

# Generate reports using Trader helper methods
orders_report = engine.trader.generate_orders_report()
positions_report = engine.trader.generate_positions_report()
fills_report = engine.trader.generate_fills_report()

# Or access data directly for custom analysis
orders = engine.cache.orders()
positions = engine.cache.positions()
snapshots = engine.cache.position_snapshots()

投资组合 statistics

The 投资组合 analyzer provides comprehensive 性能 metrics:

# Access portfolio analyzer
portfolio = engine.portfolio

# Get different categories of statistics
stats_pnls = portfolio.analyzer.get_performance_stats_pnls()
stats_returns = portfolio.analyzer.get_performance_stats_returns()
stats_general = portfolio.analyzer.get_performance_stats_general()
信息

For detailed information about available statistics and creating custom metrics, see the Portfolio guide. The Portfolio guide covers:

  • Built-in statistics categories (PnLs, returns, 头寸, 订单 based).
  • Creating custom statistics with PortfolioStatistic.
  • Registering and using custom metrics.

Visualization

报告 integrate well with visualization tools:

import matplotlib.pyplot as plt

# Plot cumulative returns
returns = positions_report["realized_return"].cumsum()
returns.plot(title="Cumulative Returns")
plt.show()

# Analyze fill quality (commission is a Money string e.g. "0.50 USD")
# Extract numeric values and currency
fills_report["commission_value"] = fills_report["commission"].str.split().str[0].astype(float)
fills_report["commission_currency"] = fills_report["commission"].str.split().str[1]

# Group by liquidity side and currency
commission_by_side = fills_report.groupby(["liquidity_side", "commission_currency"])["commission_value"].sum()
commission_by_side.plot.bar()
plt.title("Commission by Liquidity Side and Currency")
plt.show()

Report generation patterns

实时交易

During 实时交易, generate 报告 periodically:

import pandas as pd

class ReportingStrategy(Strategy):
def on_start(self):
# Schedule periodic reporting
self.clock.set_timer(
name="generate_reports",
interval=pd.Timedelta(minutes=30),
callback=self.generate_reports
)

def generate_reports(self, event):
# Generate and log reports
positions_report = self.trader.generate_positions_report()

# Save or transmit report
positions_report.to_csv(f"positions_{event.ts_event}.csv")

性能 analysis

For backtest analysis:

import pandas as pd

# Run the backtest
engine.run(start=start_time, end=end_time)

# Collect comprehensive results
positions_closed = engine.cache.positions_closed()
stats_pnls = engine.portfolio.analyzer.get_performance_stats_pnls()
stats_returns = engine.portfolio.analyzer.get_performance_stats_returns()
stats_general = engine.portfolio.analyzer.get_performance_stats_general()

# Create summary dictionary
results = {
"total_positions": len(positions_closed),
"pnl_total": stats_pnls.get("PnL (total)"),
"sharpe_ratio": stats_returns.get("Sharpe Ratio (252 days)"),
"profit_factor": stats_general.get("Profit Factor"),
"win_rate": stats_general.get("Win Rate"),
}

# Display results
results_df = pd.DataFrame([results])
print(results_df.T) # Transpose for vertical display
信息

报告 are generated from in-内存 数据 structures. For large-scale analysis or long-running systems, consider persisting 报告 to a 数据库 for efficient querying. See the Cache guide for persistence options.

Integration with other components

The ReportProvider works with several system components:

  • Cache: Source of all trading data (orders, positions, accounts) for reports.
  • Portfolio: Uses reports for performance analysis and metrics calculation.
  • BacktestEngine: Leverages reports for post-run analysis and visualization.
  • Position snapshots: Critical for accurate PnL reporting in NETTING OMS mode.

Summary

The ReportProvider class offers a comprehensive suite of analytical 报告 for evaluating trading 性能. These 报告 transform raw trading 数据 into structured DataFrames, enabling detailed analysis of 订单, fills, 头寸, and account states. Understanding how to generate and interpret these 报告 is essential for 策略开发, 性能 evaluation, and accurate PnL accounting, particularly when dealing with position snapshots in NETTING OMS configurations.