AI Hedge Fund Flow Execution Lifecycle: From CLI Input to Trading Decisions

The flow execution lifecycle in the virattt/ai-hedge-fund repository consists of seven distinct stages: input gathering, LangGraph workflow construction, agent invocation, decision normalization, trade execution, performance metrics calculation, and final output rendering.

The virattt/ai-hedge-fund project orchestrates a complete end-to-end trading pipeline using LangGraph and LLM-driven agents. Understanding the flow execution lifecycle is essential for developers extending the system or debugging agent behavior. The lifecycle spans from command-line argument parsing through graph-based agent execution to final portfolio valuation and reporting.

Stage 1: Input Gathering and CLI Parsing

The flow execution lifecycle begins in src/main.py at the script entry point.

if __name__ == "__main__":
    inputs = parse_cli_inputs(...)
    # Build the portfolio dict expected by the agents

    portfolio = {
        "cash": inputs.initial_cash,
        "margin_requirement": inputs.margin_requirement,
        ...
    }
    result = run_hedge_fund(...)
    print_trading_output(result)

The parse_cli_inputs function in src/cli/input.py reads command-line flags, validates date ranges, tickers, and optional graph visualization or reasoning flags. It returns a structured object that src/main.py uses to construct a plain dictionary representing the initial portfolio, containing keys such as cash and margin_requirement required by downstream LangGraph agents.

Stage 2: Workflow Construction with LangGraph

Once inputs are validated, run_hedge_fund calls create_workflow to assemble the agent graph.

workflow = create_workflow(selected_analysts if selected_analysts else None)
agent = workflow.compile()

The create_workflow function in src/main.py performs the following steps:

  1. Instantiates a StateGraph with the shared AgentState schema.
  2. Adds a start node (start) to initialize the state.
  3. Dynamically injects analyst nodes (e.g., sentiment, fundamentals) retrieved from get_analyst_nodes in src/utils/analysts.py.
  4. Connects each analyst to the risk-management node, then to the portfolio-management node, and finally routes to the graph END.

This construction phase defines the flow execution topology before any LLM inference occurs.

Stage 3: Agent Invocation and Graph Execution

With a compiled graph (agent), the system invokes the flow execution lifecycle core.

final_state = agent.invoke({
    "messages": [HumanMessage(content="Make trading decisions...")],
    "data": {
        "tickers": tickers,
        "portfolio": portfolio,
        "start_date": start_date,
        "end_date": end_date,
        "analyst_signals": {},
    },
    "metadata": {
        "show_reasoning": show_reasoning,
        "model_name": model_name,
        "model_provider": model_provider,
    },
})

During invocation:

  • Each analyst node enriches data["analyst_signals"] with ticker-specific insights.
  • The risk_management_agent can veto or adjust signals based on portfolio constraints.
  • The portfolio_management_agent produces a JSON-encoded decision string placed in final_state["messages"][-1].content.

This stage represents the primary LLM-driven computation phase of the flow execution lifecycle.

Stage 4: Decision Normalization

When operating in back-test mode, raw LLM output undergoes normalization via AgentController.run_agent in src/backtesting/controller.py.

The controller:

  • Guarantees a snapshot of the portfolio is sent to the agent for legacy compatibility.
  • Extracts decisions and analyst_signals from the LLM response.
  • Normalizes each ticker's decision to a concrete action (buy, sell, short, cover, hold) and a numeric quantity, coercing types and defaulting safely to prevent runtime errors during simulation.

Stage 5: Trade Execution and Portfolio Valuation

The flow execution lifecycle branches based on execution mode.

Live Mode

TradeExecutor.execute_trade in src/backtesting/trader.py receives a ticker, action, quantity, price, and the current Portfolio. It maps actions to the appropriate portfolio method:

  • apply_long_buy
  • apply_long_sell
  • apply_short_open
  • apply_short_cover

Back-test Mode

BacktestEngine.run_backtest in src/backtesting/engine.py drives a daily simulation loop:

  1. Prefetch market data for all tickers and SPY (benchmark).
  2. Iterate over business days using pd.date_range.
  3. Pull price data for the prior day; skip if missing.
  4. Call AgentController to get normalized decisions.
  5. Execute trades via TradeExecutor.
  6. Compute portfolio value (calculate_portfolio_value) and exposures (compute_exposures).
  7. Append a PortfolioValuePoint to the history.
  8. Build a row of daily metrics (OutputBuilder.build_day_rows) and print the full table.
  9. Compute final performance metrics (PerformanceMetricsCalculator.compute_metrics).

Stage 6: Performance Metrics and Reporting

Following execution, the system calculates quantitative performance indicators. PerformanceMetricsCalculator in src/backtesting/metrics.py derives:

  • Sharpe ratio
  • Sortino ratio
  • Maximum drawdown
  • Long/short exposure ratios
  • Gross and net exposures

OutputBuilder in src/backtesting/output.py formats these into markdown-style tables. For live executions, print_trading_output in src/utils/display.py renders decisions and analyst signals in a readable console format.

Stage 7: Output Display and Final Rendering

The flow execution lifecycle concludes with structured output generation. run_hedge_fund returns a JSON-compatible dictionary:

{
  "decisions": { ... },
  "analyst_signals": { ... }
}

print_trading_output in src/utils/display.py consumes this payload to print a human-readable summary, completing the end-to-end pipeline.

Complete Code Examples

Running the Hedge Fund CLI

Trigger the full flow execution lifecycle via command line:

python -m src.main \
  --tickers AAPL MSFT TSLA \
  --start-date 2024-01-01 \
  --end-date   2024-06-30 \
  --initial-cash 100000 \
  --margin-requirement 0.5 \
  --model-name gpt-4.1 \
  --model-provider OpenAI \
  --selected-analysts fundamentals sentiment

This command executes all seven stages, culminating in a printed table of daily trades and performance metrics.

Back-Testing a Strategy Programmatically

Execute the flow execution lifecycle in historical simulation mode:

from src.backtesting.engine import BacktestEngine
from src.agents.risk_manager import risk_management_agent

engine = BacktestEngine(
    agent=risk_management_agent,
    tickers=["AAPL", "MSFT", "TSLA"],
    start_date="2024-01-01",
    end_date="2024-06-30",
    initial_capital=100_000,
    model_name="gpt-4.1",
    model_provider="OpenAI",
    selected_analysts=["fundamentals", "sentiment"],
    initial_margin_requirement=0.5,
)

metrics = engine.run_backtest()
print("Final performance:", metrics)

The engine runs stages 1 through 6 in simulation, computing final performance metrics without live market exposure.

Summary

The flow execution lifecycle in virattt/ai-hedge-fund follows a rigorous seven-stage pipeline:

Frequently Asked Questions

How does the flow execution lifecycle handle errors during agent invocation?

The system relies on LangGraph's built-in error handling during the agent.invoke call in src/main.py. If an analyst node fails, the error propagates through the graph state. For back-testing, the BacktestEngine in src/backtesting/engine.py wraps daily iterations in logic that skips dates with missing market data, ensuring the flow execution lifecycle continues uninterrupted across valid trading days.

What is the difference between live mode and back-test mode in the execution stage?

In live mode, the TradeExecutor.execute_trade method in src/backtesting/trader.py applies decisions immediately to an in-memory Portfolio object using methods like apply_long_buy and apply_short_open. In back-test mode, the BacktestEngine.run_backtest method drives a historical simulation loop, prefetching market data, iterating over business days, and computing portfolio valuations retroactively without live market interaction.

How are analyst signals aggregated during the workflow construction stage?

The create_workflow function in src/main.py dynamically injects analyst nodes retrieved from get_analyst_nodes in src/utils/analysts.py. Each analyst node writes its signals into the shared AgentState under data["analyst_signals"]. The graph topology ensures all analyst nodes route to the risk-management node, which reads the aggregated signals before passing them to the portfolio-management node for final decision synthesis.

Where are performance metrics calculated in the flow execution lifecycle?

Performance metrics are calculated during Stage 6 by the PerformanceMetricsCalculator class in src/backtesting/metrics.py. This component computes the Sharpe ratio, Sortino ratio, maximum drawdown, and long/short exposure ratios from the portfolio value history accumulated during the execution stage. For back-tests, these metrics are finalized after the BacktestEngine completes its daily loop, while live mode displays immediate decision outputs without full historical metric calculation.

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 →