Skip to main content
Managing large DeFi portfolios requires institutional-grade systems that can handle millions in assets, real-time risk calculations, and complex rebalancing strategies. Python and JavaScript can’t handle this scale, but Rust can.

What You’ll Build

  • Portfolio systems managing $10M+ in assets
  • Real-time risk calculations and position monitoring
  • Automated rebalancing with sophisticated strategies
  • Performance analytics rivaling traditional finance

Why Institutions Choose Rust

Scale: Handle thousands of positions without performance degradation
Reliability: Zero-downtime systems that never miss critical trades
Speed: Real-time calculations that enable advanced strategies
Safety: Memory safety prevents costly bugs in production

Why Rust for Portfolio Management?

Portfolio management requires:
  • Real-time calculation of complex metrics across hundreds of positions
  • Memory efficiency when processing large datasets
  • Type safety to prevent costly calculation errors
  • Concurrent processing of multiple market feeds
Rust excels in all these areas, making it ideal for professional-grade portfolio management.

Core Portfolio Architecture

use saros_dlmm::{DLMM, Position, PositionManager, MarketData};
use tokio::sync::RwLock;
use std::collections::HashMap;
use serde::{Deserialize, Serialize};

#[derive(Debug, Clone)]
pub struct Portfolio {
    pub positions: HashMap<String, Position>,
    pub total_value_usd: f64,
    pub daily_pnl: f64,
    pub risk_metrics: RiskMetrics,
}

#[derive(Debug)]
pub struct PortfolioManager {
    dlmm: DLMM,
    positions: Arc<RwLock<HashMap<String, Position>>>,
    market_data: Arc<RwLock<MarketData>>,
    risk_calculator: RiskCalculator,
}

impl PortfolioManager {
    pub fn new(rpc_url: &str, wallet_keypair: Keypair) -> Result<Self> {
        Ok(Self {
            dlmm: DLMM::new(rpc_url, wallet_keypair)?,
            positions: Arc::new(RwLock::new(HashMap::new())),
            market_data: Arc::new(RwLock::new(MarketData::new())),
            risk_calculator: RiskCalculator::new(),
        })
    }

    pub async fn add_position(
        &self,
        token_a: Pubkey,
        token_b: Pubkey,
        amount_a: u64,
        amount_b: u64,
        bin_range: (i32, i32),
    ) -> Result<String> {
        // Calculate optimal bin distribution for the position
        let optimal_bins = self.calculate_optimal_bins(
            token_a, token_b, amount_a, amount_b, bin_range
        ).await?;

        // Create position with risk management
        let position = self.dlmm.create_position(
            token_a,
            token_b,
            amount_a,
            amount_b,
            optimal_bins,
        ).await?;

        // Track position in portfolio
        let mut positions = self.positions.write().await;
        positions.insert(position.id.clone(), position.clone());

        // Update portfolio metrics
        self.update_portfolio_metrics().await?;

        Ok(position.id)
    }

    pub async fn rebalance_portfolio(&self) -> Result<RebalanceReport> {
        let current_portfolio = self.get_current_portfolio().await?;
        let market_conditions = self.market_data.read().await;
        
        // Calculate optimal allocation based on current conditions
        let target_allocation = self.calculate_target_allocation(
            &current_portfolio,
            &market_conditions,
        )?;

        let mut rebalance_operations = Vec::new();

        // Identify positions that need adjustment
        for (position_id, current_position) in &current_portfolio.positions {
            let target_weight = target_allocation.get(position_id).unwrap_or(&0.0);
            let current_weight = current_position.weight;

            if (target_weight - current_weight).abs() > 0.05 { // 5% threshold
                let operation = self.plan_rebalance_operation(
                    position_id,
                    current_weight,
                    *target_weight,
                ).await?;
                rebalance_operations.push(operation);
            }
        }

        // Execute rebalancing operations
        let results = self.execute_rebalance_operations(rebalance_operations).await?;

        Ok(RebalanceReport {
            operations_executed: results.len(),
            total_gas_used: results.iter().map(|r| r.gas_used).sum(),
            estimated_improvement: self.calculate_improvement_estimate(&results),
            new_portfolio_allocation: target_allocation,
        })
    }
}

Advanced Risk Management

#[derive(Debug, Clone)]
pub struct RiskMetrics {
    pub var_95: f64,           // 95% Value at Risk
    pub var_99: f64,           // 99% Value at Risk  
    pub expected_shortfall: f64,
    pub sharpe_ratio: f64,
    pub max_drawdown: f64,
    pub correlation_matrix: Vec<Vec<f64>>,
}

impl PortfolioManager {
    pub async fn calculate_portfolio_risk(&self) -> Result<RiskMetrics> {
        let positions = self.positions.read().await;
        let market_data = self.market_data.read().await;

        // Calculate position-level risks
        let mut position_vars = Vec::new();
        let mut position_returns = Vec::new();

        for position in positions.values() {
            let var = self.calculate_position_var(position, &market_data).await?;
            let returns = self.get_position_returns(position, 30).await?; // 30 days
            
            position_vars.push(var);
            position_returns.push(returns);
        }

        // Calculate portfolio-level risk metrics
        let correlation_matrix = self.calculate_correlation_matrix(&position_returns);
        let portfolio_var_95 = self.calculate_portfolio_var(&position_vars, &correlation_matrix, 0.95);
        let portfolio_var_99 = self.calculate_portfolio_var(&position_vars, &correlation_matrix, 0.99);
        
        Ok(RiskMetrics {
            var_95: portfolio_var_95,
            var_99: portfolio_var_99,
            expected_shortfall: self.calculate_expected_shortfall(&position_returns),
            sharpe_ratio: self.calculate_sharpe_ratio(&position_returns),
            max_drawdown: self.calculate_max_drawdown(&position_returns),
            correlation_matrix,
        })
    }

    pub async fn implement_risk_limits(&self) -> Result<()> {
        let risk_metrics = self.calculate_portfolio_risk().await?;
        
        // Implement position size limits
        if risk_metrics.var_95 > 0.15 { // 15% daily VaR limit
            self.reduce_position_sizes(0.8).await?; // Reduce by 20%
        }

        // Implement concentration limits
        let position_weights = self.calculate_position_weights().await?;
        for (position_id, weight) in position_weights {
            if weight > 0.25 { // 25% concentration limit
                self.trim_position(&position_id, 0.25).await?;
            }
        }

        // Implement correlation limits
        if self.check_correlation_breaches(&risk_metrics.correlation_matrix) {
            self.diversify_correlated_positions().await?;
        }

        Ok(())
    }
}

Real-Time Performance Monitoring

use tokio::time::{interval, Duration};
use tokio::spawn;

impl PortfolioManager {
    pub async fn start_real_time_monitoring(&self) -> Result<()> {
        let positions = Arc::clone(&self.positions);
        let market_data = Arc::clone(&self.market_data);

        // Spawn price monitoring task
        let price_monitor = spawn(async move {
            let mut interval = interval(Duration::from_millis(100)); // 100ms updates
            
            loop {
                interval.tick().await;
                
                if let Err(e) = self.update_prices().await {
                    eprintln!("Price update error: {}", e);
                }
                
                // Calculate real-time P&L
                if let Err(e) = self.update_pnl().await {
                    eprintln!("P&L calculation error: {}", e);
                }
            }
        });

        // Spawn risk monitoring task  
        let risk_monitor = spawn(async move {
            let mut interval = interval(Duration::from_secs(10)); // 10 second risk checks
            
            loop {
                interval.tick().await;
                
                if let Err(e) = self.monitor_risk_limits().await {
                    eprintln!("Risk monitoring error: {}", e);
                }
            }
        });

        // Spawn rebalancing task
        let rebalancer = spawn(async move {
            let mut interval = interval(Duration::from_secs(300)); // 5 minute rebalance checks
            
            loop {
                interval.tick().await;
                
                if let Err(e) = self.check_rebalance_triggers().await {
                    eprintln!("Rebalance check error: {}", e);
                }
            }
        });

        // Wait for all monitors to complete (they run indefinitely)
        tokio::try_join!(price_monitor, risk_monitor, rebalancer)?;
        
        Ok(())
    }

    async fn update_prices(&self) -> Result<()> {
        let positions = self.positions.read().await;
        let mut market_data = self.market_data.write().await;

        // Update prices for all unique token pairs
        let unique_pairs: HashSet<(Pubkey, Pubkey)> = positions
            .values()
            .map(|p| (p.token_a, p.token_b))
            .collect();

        for (token_a, token_b) in unique_pairs {
            let price = self.dlmm.get_current_price(token_a, token_b).await?;
            market_data.update_price(token_a, token_b, price);
        }

        Ok(())
    }

    async fn calculate_real_time_pnl(&self) -> Result<f64> {
        let positions = self.positions.read().await;
        let market_data = self.market_data.read().await;
        let mut total_pnl = 0.0;

        for position in positions.values() {
            let current_price = market_data.get_price(position.token_a, position.token_b)?;
            let position_pnl = self.calculate_position_pnl(position, current_price)?;
            total_pnl += position_pnl;
        }

        Ok(total_pnl)
    }
}

Advanced Portfolio Strategies

Mean Reversion Strategy

#[derive(Debug)]
pub struct MeanReversionStrategy {
    lookback_period: u32,
    entry_threshold: f64,    // Standard deviations from mean
    exit_threshold: f64,
    max_position_size: f64,
}

impl MeanReversionStrategy {
    pub async fn analyze_opportunities(
        &self,
        dlmm: &DLMM,
        pairs: &[(Pubkey, Pubkey)]
    ) -> Result<Vec<TradingOpportunity>> {
        let mut opportunities = Vec::new();

        for &(token_a, token_b) in pairs {
            // Get historical price data
            let price_history = dlmm.get_price_history(
                token_a, 
                token_b, 
                self.lookback_period
            ).await?;

            // Calculate statistical metrics
            let mean_price = price_history.iter().sum::<f64>() / price_history.len() as f64;
            let std_dev = self.calculate_standard_deviation(&price_history, mean_price);
            let current_price = dlmm.get_current_price(token_a, token_b).await?;

            // Check for mean reversion opportunity
            let z_score = (current_price - mean_price) / std_dev;

            if z_score.abs() > self.entry_threshold {
                opportunities.push(TradingOpportunity {
                    pair: (token_a, token_b),
                    direction: if z_score > 0 { TradeDirection::Short } else { TradeDirection::Long },
                    confidence: self.calculate_confidence(z_score),
                    expected_return: self.estimate_return(z_score, std_dev),
                    risk_level: self.assess_risk(z_score, &price_history),
                    optimal_position_size: self.calculate_position_size(z_score),
                });
            }
        }

        // Sort by expected return adjusted for risk
        opportunities.sort_by(|a, b| {
            let risk_adj_return_a = a.expected_return / a.risk_level;
            let risk_adj_return_b = b.expected_return / b.risk_level;
            risk_adj_return_b.partial_cmp(&risk_adj_return_a).unwrap()
        });

        Ok(opportunities)
    }

    pub async fn execute_strategy(
        &self,
        dlmm: &DLMM,
        opportunity: &TradingOpportunity
    ) -> Result<PositionResult> {
        let (token_a, token_b) = opportunity.pair;
        
        match opportunity.direction {
            TradeDirection::Long => {
                // Create concentrated liquidity position below current price
                // Expecting price to revert upward
                let position = dlmm.create_position(
                    token_a,
                    token_b,
                    opportunity.optimal_position_size as u64,
                    0, // All token A
                    self.calculate_long_bin_range(token_a, token_b).await?,
                ).await?;

                Ok(PositionResult::Created(position))
            },
            TradeDirection::Short => {
                // Create concentrated liquidity position above current price
                // Expecting price to revert downward
                let position = dlmm.create_position(
                    token_a,
                    token_b,
                    0, // All token B
                    opportunity.optimal_position_size as u64,
                    self.calculate_short_bin_range(token_a, token_b).await?,
                ).await?;

                Ok(PositionResult::Created(position))
            }
        }
    }
}

Dynamic Hedging System

#[derive(Debug)]
pub struct DynamicHedger {
    hedge_ratio_target: f64,
    rehedge_threshold: f64,
    max_hedge_cost: f64,
}

impl DynamicHedger {
    pub async fn calculate_hedge_requirements(
        &self,
        portfolio: &Portfolio,
        market_data: &MarketData
    ) -> Result<Vec<HedgeOperation>> {
        let mut hedge_operations = Vec::new();
        let total_exposure = portfolio.calculate_total_exposure(market_data)?;
        
        // Calculate Greek exposures (Delta, Gamma, Vega for options-like positions)
        let delta_exposure = portfolio.calculate_delta_exposure(market_data)?;
        let gamma_exposure = portfolio.calculate_gamma_exposure(market_data)?;
        
        // Target hedge ratio based on portfolio size
        let target_hedge = total_exposure * self.hedge_ratio_target;
        let current_hedge = portfolio.current_hedge_value;
        
        let hedge_adjustment = target_hedge - current_hedge;
        
        if hedge_adjustment.abs() > self.rehedge_threshold {
            // Plan hedge operations
            let hedge_pairs = self.select_optimal_hedge_pairs(
                &portfolio.positions,
                hedge_adjustment
            ).await?;

            for hedge_pair in hedge_pairs {
                hedge_operations.push(HedgeOperation {
                    pair: hedge_pair.tokens,
                    direction: hedge_pair.direction,
                    size: hedge_pair.optimal_size,
                    expected_cost: hedge_pair.estimated_cost,
                    hedge_effectiveness: hedge_pair.correlation_coefficient,
                });
            }
        }

        Ok(hedge_operations)
    }

    pub async fn execute_hedging_operations(
        &self,
        dlmm: &DLMM,
        operations: Vec<HedgeOperation>
    ) -> Result<HedgeResult> {
        let mut successful_hedges = Vec::new();
        let mut total_cost = 0.0;

        for operation in operations {
            match self.execute_single_hedge(dlmm, &operation).await {
                Ok(result) => {
                    successful_hedges.push(result.clone());
                    total_cost += result.cost;
                },
                Err(e) => {
                    eprintln!("Hedge operation failed: {:?}", e);
                    // Continue with other operations
                }
            }
        }

        Ok(HedgeResult {
            successful_operations: successful_hedges.len(),
            total_operations: operations.len(),
            total_cost,
            hedge_effectiveness: self.calculate_hedge_effectiveness(&successful_hedges),
            portfolio_risk_reduction: self.estimate_risk_reduction(&successful_hedges),
        })
    }
}

Performance Analytics

#[derive(Debug, Serialize, Deserialize)]
pub struct PerformanceReport {
    pub period_return: f64,
    pub volatility: f64,
    pub sharpe_ratio: f64,
    pub max_drawdown: f64,
    pub win_rate: f64,
    pub profit_factor: f64,
    pub positions_performance: Vec<PositionPerformance>,
}

impl PortfolioManager {
    pub async fn generate_performance_report(
        &self, 
        period_days: u32
    ) -> Result<PerformanceReport> {
        let positions = self.positions.read().await;
        let mut position_performances = Vec::new();

        // Calculate performance for each position
        for (position_id, position) in positions.iter() {
            let performance = self.calculate_position_performance(
                position, 
                period_days
            ).await?;
            position_performances.push(performance);
        }

        // Calculate portfolio-level metrics
        let portfolio_returns = self.get_portfolio_returns(period_days).await?;
        
        let period_return = self.calculate_total_return(&portfolio_returns);
        let volatility = self.calculate_volatility(&portfolio_returns);
        let sharpe_ratio = self.calculate_sharpe_ratio(&portfolio_returns, 0.05); // 5% risk-free rate
        let max_drawdown = self.calculate_max_drawdown(&portfolio_returns);
        
        // Trading performance metrics
        let trades = self.get_trades(period_days).await?;
        let winning_trades = trades.iter().filter(|t| t.pnl > 0.0).count();
        let win_rate = winning_trades as f64 / trades.len() as f64;
        
        let gross_profit: f64 = trades.iter().filter(|t| t.pnl > 0.0).map(|t| t.pnl).sum();
        let gross_loss: f64 = trades.iter().filter(|t| t.pnl < 0.0).map(|t| t.pnl.abs()).sum();
        let profit_factor = if gross_loss > 0.0 { gross_profit / gross_loss } else { f64::INFINITY };

        Ok(PerformanceReport {
            period_return,
            volatility,
            sharpe_ratio,
            max_drawdown,
            win_rate,
            profit_factor,
            positions_performance: position_performances,
        })
    }

    pub async fn optimize_portfolio_allocation(&self) -> Result<OptimizationResult> {
        let current_portfolio = self.get_current_portfolio().await?;
        let risk_metrics = self.calculate_portfolio_risk().await?;
        
        // Use Modern Portfolio Theory for optimization
        let optimizer = ModernPortfolioOptimizer::new(
            risk_metrics.correlation_matrix,
            self.get_expected_returns().await?,
            0.15, // 15% target volatility
        );

        let optimal_weights = optimizer.optimize()?;
        
        // Generate rebalancing plan
        let rebalance_plan = self.create_rebalance_plan(
            &current_portfolio,
            &optimal_weights
        ).await?;

        Ok(OptimizationResult {
            current_sharpe: risk_metrics.sharpe_ratio,
            optimized_sharpe: optimizer.calculate_optimized_sharpe()?,
            improvement: optimizer.calculate_improvement()?,
            rebalance_plan,
            expected_risk_reduction: optimizer.calculate_risk_reduction()?,
        })
    }
}

Production Portfolio Example

use tokio::main;

#[tokio::main]
async fn main() -> Result<()> {
    // Initialize portfolio manager
    let wallet = read_keypair_file("wallet.json")?;
    let portfolio_manager = PortfolioManager::new(
        "https://api.mainnet-beta.solana.com",
        wallet
    )?;

    // Start with initial positions
    let initial_positions = vec![
        // SOL/USDC concentrated liquidity
        (SOL_MINT, USDC_MINT, 1_000_000_000, 50_000_000_000, (-5, 5)),
        // ETH/USDC concentrated liquidity  
        (ETH_MINT, USDC_MINT, 500_000_000, 25_000_000_000, (-3, 3)),
        // BTC/USDC concentrated liquidity
        (BTC_MINT, USDC_MINT, 250_000_000, 12_500_000_000, (-2, 2)),
    ];

    // Create initial positions
    for (token_a, token_b, amount_a, amount_b, bin_range) in initial_positions {
        portfolio_manager.add_position(
            token_a, token_b, amount_a, amount_b, bin_range
        ).await?;
    }

    // Start real-time monitoring
    portfolio_manager.start_real_time_monitoring().await?;

    // Generate daily reports
    let mut report_interval = interval(Duration::from_secs(86400)); // Daily
    loop {
        report_interval.tick().await;
        
        let report = portfolio_manager.generate_performance_report(1).await?;
        println!("Daily Performance Report: {:?}", report);
        
        // Check if rebalancing needed
        if report.sharpe_ratio < 1.0 || report.max_drawdown > 0.1 {
            let optimization = portfolio_manager.optimize_portfolio_allocation().await?;
            println!("Portfolio optimization suggested: {:?}", optimization);
        }
    }
}

Key Performance Metrics

Monitor these critical metrics for portfolio success:
  • Sharpe Ratio: Target >2.0 for excellent risk-adjusted returns
  • Maximum Drawdown: Keep <10% for professional management
  • Win Rate: Aim for >60% profitable positions
  • Risk-Adjusted Return: Track returns per unit of risk taken
  • Position Concentration: No single position >25% of portfolio
This portfolio management system leverages Rust’s performance advantages to process complex calculations in real-time, giving you institutional-grade portfolio management capabilities.
Next: Explore Advanced Analytics for deeper insights, or implement Risk Management protocols for enterprise-grade safeguards.