Position Sizing Logic in the AI Hedge Fund: Volatility and Correlation-Based Risk Management

The ai-hedge-fund repository implements position sizing logic through a dedicated Risk Management Agent that calculates volatility-adjusted, correlation-aware dollar limits, constraining individual ticker exposure to between 10% and 25% of total portfolio value.

The position sizing logic in virattt/ai-hedge-fund dynamically adjusts portfolio exposure based on real-time market risk metrics. Located in the Risk Management Agent (src/agents/risk_manager.py), this system computes specific dollar limits for every ticker by analyzing price volatility and measuring correlation against existing positions.

The Four-Stage Position Sizing Pipeline

The risk management process executes four distinct computational stages to determine final position limits.

Step 1: Gathering Market Data

For all tickers present in the dataset or currently held in the portfolio, the agent retrieves daily price history using the get_prices tool. The latest close price for each ticker is cached for subsequent calculations.

This iteration occurs at lines 27-36 in src/agents/risk_manager.py, where the code loops through all_tickers and extracts current market data necessary for volatility and correlation analysis.

Step 2: Computing Volatility Metrics

Using the retrieved price series, the agent calculates daily returns and derives volatility statistics through calculate_volatility_metrics(prices_df) (lines 54-55). This function produces both daily and annualized volatility figures, along with a percentile rank indicating how current volatility compares to historical levels for that ticker.

Step 3: Adjusting for Correlation

The system builds a correlation matrix from the return series of all tickers with at least two days of history. For each candidate ticker, the agent computes the average correlation with active positions (those with non-zero exposure).

The calculate_correlation_multiplier(avg_corr) function (lines 41-62) translates this average correlation into a scaling factor between 0.70 and 1.10. High correlation with existing holdings reduces the position size, while low correlation permits expansion.

Step 4: Calculating Final Dollar Limits

The final position limit emerges from combining volatility and correlation adjustments:

  1. Volatility-adjusted base limit: calculate_volatility_adjusted_limit(annualized_vol) returns a base percentage of the total portfolio (lines 70-98).
  2. Correlation application: The system multiplies the base limit by the correlation multiplier: combined_limit_pct = vol_adjusted_limit_pct * corr_multiplier (lines 64-66).
  3. Cash constraint: The final usable dollar amount is the minimum of the calculated limit and available cash: max_position_size = min(remaining_position_limit, portfolio.get("cash", 0)) (lines 71-73).

Portfolio Value Calculation

The total portfolio value used for sizing calculations represents net liquidation value, computed as cash plus the market value of longs minus the market value of shorts. The implementation iterates through existing positions and applies the latest fetched prices:

total_portfolio_value = portfolio.get("cash", 0.0)
for ticker, position in portfolio.get("positions", {}).items():
    if ticker in current_prices:
        total_portfolio_value += position.get("long", 0) * current_prices[ticker]
        total_portfolio_value -= position.get("short", 0) * current_prices[ticker]

This calculation appears at lines 94-102 in src/agents/risk_manager.py.

Volatility-Adjusted Position Limits

The calculate_volatility_adjusted_limit function maps annualized volatility to base allocation percentages using a tiered multiplier system:

  • Low volatility (< 15%): Multiplier of 1.25, allowing up to 25% of portfolio value
  • Medium volatility (15-30%): Linear decay from 1.0 to 0.75, resulting in 15-20% allocation
  • High volatility (30-50%): Linear decay from 0.75 to 0.5, producing 10-15% allocation
  • Very high volatility (> 50%): Fixed multiplier of 0.5, capping exposure at 10%

The base allocation starts at 20% and scales according to these volatility bands (lines 70-98).

Correlation Multiplier Logic

The correlation adjustment function implements the following discrete thresholds (lines 101-108):

if avg_correlation >= 0.80:   return 0.70   # high correlation → shrink

elif avg_correlation >= 0.60: return 0.85
elif avg_correlation >= 0.40: return 1.00
elif avg_correlation >= 0.20: return 1.05
else:                         return 1.10   # very low correlation → expand

This 0.70-1.10 range ensures that positions highly correlated with existing holdings receive reduced allocation, while uncorrelated assets may receive modestly increased limits.

Practical Implementation Examples

Invoking the Risk Management Agent

To run the position sizing logic in isolation:

from src.graph.state import AgentState, create_initial_state
from src.agents.risk_manager import risk_management_agent

state: AgentState = create_initial_state(
    tickers=["AAPL", "MSFT", "TSLA"],
    start_date="2023-01-01",
    end_date="2023-12-31",
    initial_cash=100_000,
)

updated_state = risk_management_agent(state)
print(updated_state["data"]["analyst_signals"]["risk_management_agent"]["AAPL"])

Integrating Sizing into Trading Loops

When executing trades, convert the dollar limit to share quantities:

risk_limits = state["data"]["analyst_signals"]["risk_management_agent"]

for ticker, limit_info in risk_limits.items():
    max_dollar = limit_info["remaining_position_limit"]
    price = limit_info["current_price"]
    max_shares = int(max_dollar // price)
    
    execution_order = {
        "ticker": ticker,
        "quantity": max_shares,
        "side": "buy",
    }

Debugging Risk Calculations

Inspect intermediate values through the reasoning block stored in the agent state:

import json
risk_report = state["data"]["analyst_signals"]["risk_management_agent"]
print(json.dumps(risk_report["TSLA"]["reasoning"], indent=2))

Sample output:

{
  "portfolio_value": 128450.23,
  "current_position_value": 0.0,
  "base_position_limit_pct": 0.12,
  "correlation_multiplier": 1.05,
  "combined_position_limit_pct": 0.126,
  "position_limit": 16199.44,
  "remaining_limit": 16199.44,
  "available_cash": 100000.0
}

Final Output Structure

The agent returns a JSON-serializable dictionary per ticker (lines 174-180) containing:

  • remaining_position_limit: The final usable dollar size (rounded)
  • current_price: Latest market price
  • Detailed volatility and correlation metrics
  • A reasoning object documenting every intermediate calculation for audit trails

This data structure is stored in state["data"]["analyst_signals"]["risk_management_agent"] for downstream consumption by execution agents.

Summary

  • Position sizing logic resides in src/agents/risk_manager.py, specifically within the risk_management_agent function and its helper methods.
  • Volatility bands determine base allocation percentages ranging from 10% to 25% of total portfolio value.
  • Correlation multipliers between 0.70 and 1.10 adjust base limits based on diversification benefits relative to existing positions.
  • Portfolio value is calculated as net liquidation value (cash + longs - shorts) using real-time price data.
  • Final limits are constrained by both the calculated risk percentage and available cash balances.

Frequently Asked Questions

How is position sizing logic implemented in the ai-hedge-fund?

The implementation centers on the Risk Management Agent in src/agents/risk_manager.py. This agent computes dollar limits by first gathering price data, then calculating annualized volatility and correlation metrics, and finally combining these into a position limit capped by available cash.

What is the maximum position size percentage allowed?

The maximum allocation is 25% of total portfolio value, assigned to tickers with annualized volatility below 15%. The minimum allocation is 10%, assigned to tickers with volatility exceeding 50%. Intermediate volatility bands receive linearly scaled percentages between these extremes.

How does correlation affect position sizing?

High correlation with existing positions reduces the position size through a multiplier as low as 0.70 (for correlations ≥ 0.80), while low correlation increases it up to 1.10 (for correlations < 0.20). This mechanism prevents concentration risk while rewarding diversification.

Where is portfolio value calculated for sizing decisions?

The total_portfolio_value calculation occurs at lines 94-102 of src/agents/risk_manager.py. The function aggregates cash balances with the market value of long positions and subtracts the market value of short positions, using the latest prices fetched during the data gathering phase.

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 →