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:
- Instantiates a
StateGraphwith the sharedAgentStateschema. - Adds a start node (
start) to initialize the state. - Dynamically injects analyst nodes (e.g., sentiment, fundamentals) retrieved from
get_analyst_nodesinsrc/utils/analysts.py. - 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
decisionsandanalyst_signalsfrom 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_buyapply_long_sellapply_short_openapply_short_cover
Back-test Mode
BacktestEngine.run_backtest in src/backtesting/engine.py drives a daily simulation loop:
- Prefetch market data for all tickers and SPY (benchmark).
- Iterate over business days using
pd.date_range. - Pull price data for the prior day; skip if missing.
- Call
AgentControllerto get normalized decisions. - Execute trades via
TradeExecutor. - Compute portfolio value (
calculate_portfolio_value) and exposures (compute_exposures). - Append a
PortfolioValuePointto the history. - Build a row of daily metrics (
OutputBuilder.build_day_rows) and print the full table. - 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:
- Input Gathering: CLI arguments parsed via
src/cli/input.pyand portfolio initialized insrc/main.py - Workflow Construction: LangGraph assembly via
create_workflowandget_analyst_nodesinsrc/main.pyandsrc/utils/analysts.py - Agent Invocation: Graph execution via
agent.invokewith state management across analyst, risk, and portfolio nodes - Decision Normalization: LLM output coercion to deterministic actions via
AgentControllerinsrc/backtesting/controller.py - Trade Execution: Live trades via
TradeExecutorinsrc/backtesting/trader.pyor historical simulation viaBacktestEngineinsrc/backtesting/engine.py - Metrics Calculation: Sharpe, Sortino, and drawdown computation in
src/backtesting/metrics.py - Output Rendering: Human-readable formatting via
print_trading_outputinsrc/utils/display.pyandOutputBuilderinsrc/backtesting/output.py
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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →