How to Debug Strategy Logic and Inspect Internal State in Nautilus Trader

Enable DEBUG logging via strategy._log.setLevel("DEBUG") and inspect self.cache and self.portfolio attributes to trace real-time strategy state without modifying library code.

Nautilus Trader is a high-performance algorithmic trading platform that isolates strategy execution within a Strategy instance. When you need to debug strategy logic and inspect internal state, the framework provides built-in logging, cache access, and portfolio inspection capabilities that allow deep visibility without altering the core library.

Enable Detailed Logging for Strategy Debugging

Every Strategy instance creates its own logger accessible via self._log. This logger captures all framework interactions, including order submissions, position changes, and market data events.

Configure Logging via StrategyConfig

Set logging flags when defining your strategy configuration in nautilus_trader/trading/config.py:

from nautilus_trader.trading.config import StrategyConfig

class MyStrategyConfig(StrategyConfig, frozen=True):
    log_events: bool = True      # Log all events received by the strategy

    log_commands: bool = True    # Log all commands sent by the strategy

These flags ensure that the strategy's internal message processing is recorded in the logs.

Runtime Log Level Adjustment

For existing strategy instances, change the log level dynamically to capture DEBUG output:

strategy._log.setLevel("DEBUG")

This is useful when you need verbose output only during specific market conditions or debugging sessions.

File Output for Post-Mortem Analysis

Redirect logs to a file for offline analysis without modifying the core library:

import logging

strategy._log.addHandler(logging.FileHandler("strategy_debug.log"))

All subsequent log entries write to strategy_debug.log, preserving a record of strategy logic execution.

Inspect Core Components at Runtime

The Strategy class in nautilus_trader/trading/strategy.pyx maintains references to core components after registration with the Trader. These attributes provide read-only access to the platform's internal state.

Access the Cache for Market Data

The self.cache attribute (type Cache) stores market data, order-book snapshots, and instrument definitions:

def on_bar(self, bar: Bar) -> None:
    # Query the latest quote for the instrument

    quote = self.cache.quote_tick(bar.instrument_id)
    self._log.debug(f"Latest quote: {quote}")
    
    # Access historical bars if cached

    bars = self.cache.bars(bar.instrument_id)
    self._log.debug(f"Cached bars count: {len(bars)}")

Query Portfolio State and Positions

The self.portfolio attribute (type PortfolioFacade) exposes open positions, cash balances, and P&L calculations:

def on_trade(self, trade: TradeTick) -> None:
    # List all open positions

    positions = self.portfolio.positions()
    self._log.debug(f"Open positions: {list(positions)}")
    
    # Check exposure for specific instrument

    exposure = self.portfolio.exposure(trade.instrument_id)
    self._log.debug(f"Current exposure: {exposure}")
    
    # Access unrealized P&L

    pnl = self.portfolio.unrealized_pnl(trade.instrument_id)
    self._log.debug(f"Unrealized P&L: {pnl}")

Both components reflect the live state maintained by the Trader and update synchronously with market events.

Use Python Inspection Utilities

Nautilus Trader includes utilities in nautilus_trader/core/inspect.py to differentiate platform objects from user-defined types.

Verify Method Signatures

When debugging command submissions, verify expected parameters using Python's standard inspect module:

import inspect

# Check submit_order signature before calling

sig = inspect.signature(self.submit_order)
self._log.debug(f"submit_order signature: {sig}")

This prevents errors from incorrect argument passing when debugging complex order logic.

Identify Nautilus Object Types

Use is_nautilus_class to filter collections containing mixed object types:

from nautilus_trader.core.inspect import is_nautilus_class

def debug_cache_contents(self):
    for obj in self.cache.objects():
        if is_nautilus_class(type(obj)):
            self._log.debug(f"Nautilus object: {obj}")
        else:
            self._log.debug(f"User object: {obj}")

This distinction helps when serializing objects or diagnosing type-related bugs.

Interactive Debugging Techniques

Breakpoint Debugging with pdb

Since the strategy runs in the same Python process as the Trader, you can insert standard breakpoints:

def on_trade(self, trade: TradeTick) -> None:
    import pdb; pdb.set_trace()
    
    # When execution pauses, inspect:

    # (pdb) self.cache.quote_tick(trade.instrument_id)

    # (pdb) self.portfolio.positions()

    # (pdb) self._log.handlers

At the breakpoint, you have direct access to self, self.cache, self.portfolio, and all strategy attributes.

External Trader Inspection

When running interactive sessions (Jupyter or REPL) with a Trader reference, query loaded strategies externally:


# trader is an instance of nautilus_trader.trading.trader.Trader

for strat in trader.strategies():
    print(f"Strategy ID: {strat.id}")
    print(f"State: {strat.state}")
    print(f"Position count: {len(strat.portfolio.positions())}")

The Trader also exposes actor_ids(), strategy_ids(), and component clocks for system-wide diagnostics.

Running Tests with Diagnostic Logging

The repository contains unit tests that exercise the strategy API in tests/unit_tests/trading/test_strategy_pyo3.py. Run these with debug logging enabled to observe internal behavior:

export NAUTILUS_LOG_LEVEL=DEBUG
pytest -vv tests/unit_tests/trading/test_strategy_pyo3.py -k test_strategy

This outputs the same structured logs you will see in production, allowing you to verify strategy behavior before deployment.

Summary

  • Enable DEBUG logging via strategy._log.setLevel("DEBUG") or StrategyConfig flags to capture all events and commands.
  • Inspect internal state through self.cache (market data) and self.portfolio (positions, P&L) attributes available in every strategy.
  • Use Python inspection tools like inspect.signature() and is_nautilus_class() to verify API calls and filter object types.
  • Attach breakpoints using pdb.set_trace() for interactive debugging with full access to strategy components.
  • Query the Trader externally via trader.strategies() to monitor loaded strategies in Jupyter or REPL sessions.

Frequently Asked Questions

How do I enable DEBUG logging in Nautilus Trader?

Set the log level on the strategy instance after creation: strategy._log.setLevel("DEBUG"). Alternatively, configure log_events=True and log_commands=True in your StrategyConfig subclass. For file output, add a logging.FileHandler to strategy._log.

Can I modify strategy state during a pdb debugging session?

Yes. When execution pauses at a pdb.set_trace() breakpoint inside a strategy method, you have full read-write access to self and all its attributes including self.cache, self.portfolio, and private variables. You can call methods and modify state interactively.

What is the difference between self.cache and self.portfolio?

self.cache (type Cache) provides access to market data such as quote ticks, trade ticks, bars, and order-book snapshots. self.portfolio (type PortfolioFacade) exposes trading account state including open positions, cash balances, exposure, and unrealized P&L. Both are read-only from the strategy perspective.

How do I inspect all loaded strategies from the Trader instance?

Access the strategies() method on a Trader instance: for strat in trader.strategies(): print(strat.id, strat.state). The Trader class in nautilus_trader/trading/trader.py also provides strategy_ids() and actor_ids() methods for component enumeration.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →