The hardware and bandwidth for this mirror is donated by dogado GmbH, the Webhosting and Full Service-Cloud Provider. Check out our Wordpress Tutorial.
If you wish to report a bug, or if you are interested in having us mirror your free-software or open-source project, please feel free to contact us at mirror[@]dogado.de.

Example: Monte Carlo Portfolio Simulation

Overview

Monte Carlo simulations are a common use case for parallel computing. This example demonstrates running 10,000 portfolio simulations to estimate risk metrics.

Use Case: Portfolio risk analysis, Value at Risk (VaR) calculations, stress testing

Computational Pattern: Embarrassingly parallel - each simulation is independent

The Problem

You need to simulate 10,000 different portfolio scenarios to estimate: - Expected portfolio value - Value at Risk (VaR) at 95% confidence - Sharpe ratio distribution - Probability of loss scenarios

Each simulation involves 252 trading days (one year) with correlated asset returns.

Setup

library(starburst)
library(ggplot2)

Simulation Function

Define a function that simulates one portfolio trajectory:

simulate_portfolio <- function(seed) {
  set.seed(seed)

  # Portfolio parameters
  n_days <- 252
  initial_value <- 1000000  # $1M portfolio

  # Asset allocation (60/40 stocks/bonds)
  stock_weight <- 0.6
  bond_weight <- 0.4

  # Expected returns (annualized)
  stock_return <- 0.10 / 252  # 10% annual
  bond_return <- 0.04 / 252   # 4% annual

  # Volatility (annualized)
  stock_vol <- 0.20 / sqrt(252)  # 20% annual
  bond_vol <- 0.05 / sqrt(252)   # 5% annual

  # Correlation
  correlation <- 0.3

  # Generate correlated returns
  stock_returns <- rnorm(n_days, mean = stock_return, sd = stock_vol)
  bond_noise <- rnorm(n_days)
  bond_returns <- rnorm(n_days, mean = bond_return, sd = bond_vol)
  bond_returns <- correlation * stock_returns +
                  sqrt(1 - correlation^2) * bond_returns

  # Portfolio returns
  portfolio_returns <- stock_weight * stock_returns +
                      bond_weight * bond_returns

  # Cumulative value
  portfolio_values <- initial_value * cumprod(1 + portfolio_returns)

  # Calculate metrics
  final_value <- portfolio_values[n_days]
  max_drawdown <- max((cummax(portfolio_values) - portfolio_values) /
                      cummax(portfolio_values))
  sharpe_ratio <- mean(portfolio_returns) / sd(portfolio_returns) * sqrt(252)

  list(
    final_value = final_value,
    return_pct = (final_value - initial_value) / initial_value * 100,
    max_drawdown = max_drawdown,
    sharpe_ratio = sharpe_ratio,
    min_value = min(portfolio_values),
    max_value = max(portfolio_values)
  )
}

Local Execution

Run a smaller test locally:

# Test with 100 simulations
set.seed(123)
local_start <- Sys.time()
local_results <- lapply(1:100, simulate_portfolio)
local_time <- as.numeric(difftime(Sys.time(), local_start, units = "secs"))

cat(sprintf("100 simulations completed in %.1f seconds\n", local_time))
cat(sprintf("Estimated time for 10,000: %.1f minutes\n",
            local_time * 100 / 60))

Typical output:

100 simulations completed in 2.3 seconds
Estimated time for 10,000: 3.8 minutes

For 10,000 simulations locally: ~3.8 minutes

Cloud Execution with staRburst

Run all 10,000 simulations on AWS:

# Run 10,000 simulations on 50 workers
results <- starburst_map(
  1:10000,
  simulate_portfolio,
  workers = 50,
  cpu = 2,
  memory = "4GB"
)

Typical output:

🚀 Starting starburst cluster with 50 workers
💰 Estimated cost: ~$2.80/hour
📊 Processing 10000 items with 50 workers
📦 Created 50 chunks (avg 200 items per chunk)
🚀 Submitting tasks...
✓ Submitted 50 tasks
⏳ Progress: 50/50 tasks (1.2 minutes elapsed)

✓ Completed in 1.2 minutes
💰 Actual cost: $0.06

Results Analysis

Extract and analyze the results:

# Extract metrics
final_values <- sapply(results, function(x) x$final_value)
returns <- sapply(results, function(x) x$return_pct)
sharpe_ratios <- sapply(results, function(x) x$sharpe_ratio)
max_drawdowns <- sapply(results, function(x) x$max_drawdown)

# Summary statistics
cat("\n=== Portfolio Simulation Results (10,000 scenarios) ===\n")
cat(sprintf("Mean final value: $%.0f\n", mean(final_values)))
cat(sprintf("Median final value: $%.0f\n", median(final_values)))
cat(sprintf("\nMean return: %.2f%%\n", mean(returns)))
cat(sprintf("Std dev of returns: %.2f%%\n", sd(returns)))
cat(sprintf("\nValue at Risk (5%%): $%.0f\n",
            quantile(final_values, 0.05)))
cat(sprintf("Expected Shortfall (5%%): $%.0f\n",
            mean(final_values[final_values <= quantile(final_values, 0.05)])))
cat(sprintf("\nMean Sharpe Ratio: %.2f\n", mean(sharpe_ratios)))
cat(sprintf("Mean Max Drawdown: %.2f%%\n", mean(max_drawdowns) * 100))
cat(sprintf("\nProbability of loss: %.2f%%\n",
            mean(returns < 0) * 100))

# Distribution plot
hist(final_values / 1000,
     breaks = 50,
     main = "Distribution of Portfolio Final Values",
     xlab = "Final Value ($1000s)",
     col = "lightblue",
     border = "white")
abline(v = 1000, col = "red", lwd = 2, lty = 2)
abline(v = quantile(final_values / 1000, 0.05), col = "orange", lwd = 2, lty = 2)
legend("topright",
       c("Initial Value", "VaR (5%)"),
       col = c("red", "orange"),
       lwd = 2, lty = 2)

Typical output:

=== Portfolio Simulation Results (10,000 scenarios) ===
Mean final value: $1,102,450
Median final value: $1,097,230

Mean return: 10.24%
Std dev of returns: 12.83%

Value at Risk (5%): $892,340
Expected Shortfall (5%): $845,120

Mean Sharpe Ratio: 0.82
Mean Max Drawdown: 8.45%

Probability of loss: 18.34%

Performance Comparison

Method Workers Time Cost Speedup
Local 1 3.8 min $0 1x
staRburst 10 0.6 min $0.03 6.3x
staRburst 25 0.3 min $0.04 12.7x
staRburst 50 0.2 min $0.06 19x

Key Insights: - Near-linear scaling up to 50 workers - Cost remains minimal ($0.06) even with 50 workers - Sweet spot: 25-50 workers for this workload - Total iteration time: <2 minutes from start to results

When to Use This Pattern

Good fit: - Each iteration is independent - Computational time > 0.1 seconds per iteration - Total iterations > 1,000 - Results can be easily aggregated

Not ideal: - Very fast iterations (< 0.01 seconds) - High data transfer per iteration - Strong sequential dependencies

Running the Full Example

The complete runnable script is available at:

system.file("examples/monte-carlo.R", package = "starburst")

Run it with:

source(system.file("examples/monte-carlo.R", package = "starburst"))

Next Steps

Related examples: - Bootstrap Confidence Intervals - Another Monte Carlo application - Financial Risk Modeling - Advanced portfolio analysis

These binaries (installable software) and packages are in development.
They may not be fully stable and should be used with caution. We make no claims about them.
Health stats visible at Monitor.