monte_carlo_simulation
Simulate financial asset price paths using Geometric Brownian Motion to forecast potential outcomes and assess investment risks. Configure simulation count, projection period, and visualization options.
Instructions
Runs a Monte Carlo simulation using Geometric Brownian Motion (Log Returns).
Args:
simulations: Number of paths to simulate.
days: Number of days to project forward.
visualize: If True, returns a histogram of final outcomes.
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| simulations | No | ||
| days | No | ||
| visualize | No |
Implementation Reference
- tools/risk_engine.py:77-148 (handler)The core handler function that performs Monte Carlo simulation on the portfolio using Geometric Brownian Motion with correlated log returns, Cholesky decomposition for covariance, and optional visualization.def monte_carlo_simulation(simulations: int = 1000, days: int = 252, visualize: bool = False) -> str: """ Runs a Monte Carlo simulation using Geometric Brownian Motion (Log Returns). Args: simulations: Number of paths to simulate. days: Number of days to project forward. visualize: If True, returns a histogram of final outcomes. """ data, weights = _get_portfolio_data() if data is None: return "Portfolio is empty." # Use Log Returns for additivity log_returns = np.log(data / data.shift(1)).dropna() mean_log_returns = log_returns.mean() cov_matrix = log_returns.cov() # Cholesky Decomposition try: L = np.linalg.cholesky(cov_matrix) except np.linalg.LinAlgError: # Fallback for non-positive definite matrix (e.g., too few data points) return "Covariance matrix is not positive definite. Insufficient data history." portfolio_sims = np.zeros((days, simulations)) initial_value = 1.0 for i in range(simulations): Z = np.random.normal(size=(days, len(weights))) # Correlated random shocks daily_shocks = np.dot(Z, L.T) # GBM: S_t = S_0 * exp( (mu - 0.5*sigma^2)*t + sigma*W_t ) # Here we simulate daily steps daily_log_ret = mean_log_returns.values + daily_shocks # Portfolio level log return port_log_ret = np.dot(daily_log_ret, weights) # Accumulate log returns cum_log_ret = np.cumsum(port_log_ret) portfolio_sims[:, i] = initial_value * np.exp(cum_log_ret) final_values = portfolio_sims[-1, :] returns = (final_values - 1) * 100 # Convert to percentage expected_return = np.mean(final_values) - 1 worst_case = np.percentile(final_values, 5) - 1 best_case = np.percentile(final_values, 95) - 1 result = (f"Monte Carlo Results ({simulations} sims, {days} days) [Log Normal]:\n" f"Expected Return: {expected_return:.2%}\n" f"5th Percentile (VaR 95%): {worst_case:.2%}\n" f"95th Percentile (Upside): {best_case:.2%}") if visualize: try: from tools.visualizer import plot_histogram chart = plot_histogram( returns, bins=50, title=f"Monte Carlo Simulation - {simulations} Paths ({days} days)", x_label="Return (%)", percentiles=[5, 50, 95] ) result += f"\n\n{chart}" except Exception as e: logger.error(f"Error generating visualization: {e}") result += f"\n(Visualization error: {str(e)})" return result
- server.py:380-383 (registration)Registers the monte_carlo_simulation tool (along with other risk tools) to the MCP server using the register_tools helper which applies @mcp.tool() decorator.register_tools( [portfolio_risk, var, max_drawdown, monte_carlo_simulation], "Risk Engine" )
- tools/risk_engine.py:10-30 (helper)Helper function to fetch portfolio data and compute value weights from positions, used by monte_carlo_simulation.def _get_portfolio_data(lookback: str = "1y"): portfolio = get_positions() positions = portfolio.get("positions", {}) if not positions: return None, None tickers = list(positions.keys()) weights = np.array(list(positions.values())) # This is qty, need value weights # Fetch data data = yf.download(tickers, period=lookback, progress=False)['Close'] if isinstance(data, pd.Series): data = data.to_frame(name=tickers[0]) # Calculate current value weights current_prices = data.iloc[-1] values = current_prices * pd.Series(positions) total_value = values.sum() weights = values / total_value return data, weights
- server.py:14-14 (registration)Import statement for the monte_carlo_simulation function in the MCP server.from tools.risk_engine import portfolio_risk, var, max_drawdown, monte_carlo_simulation