| Crates.io | nt-portfolio |
| lib.rs | nt-portfolio |
| version | 1.0.0 |
| created_at | 2025-11-13 16:18:32.636702+00 |
| updated_at | 2025-11-13 16:18:32.636702+00 |
| description | Portfolio management and tracking for Neural Trader - positions, P&L, performance analytics |
| homepage | |
| repository | https://github.com/ruvnet/neural-trader |
| max_upload_size | |
| id | 1931467 |
| size | 98,036 |
Portfolio management, optimization, and real-time P&L tracking for algorithmic trading.
The nt-portfolio crate provides comprehensive portfolio management capabilities including position tracking, P&L calculation, rebalancing, and portfolio optimization using modern portfolio theory.
[dependencies]
nt-portfolio = "0.1"
use nt_portfolio::{Portfolio, Position};
use rust_decimal::Decimal;
use chrono::Utc;
#[tokio::main]
async fn main() -> anyhow::Result<()> {
let mut portfolio = Portfolio::new(
"main_portfolio",
Decimal::from(100_000), // Initial capital
);
// Add positions
portfolio.add_position(Position {
symbol: "AAPL".to_string(),
quantity: Decimal::from(100),
entry_price: Decimal::new(15000, 2), // $150.00
current_price: Decimal::new(15500, 2), // $155.00
entry_date: Utc::now(),
});
portfolio.add_position(Position {
symbol: "MSFT".to_string(),
quantity: Decimal::from(50),
entry_price: Decimal::new(30000, 2), // $300.00
current_price: Decimal::new(31000, 2), // $310.00
entry_date: Utc::now(),
});
// Calculate metrics
println!("Total Value: ${}", portfolio.total_value());
println!("Total P&L: ${}", portfolio.total_pnl());
println!("Total Return: {:.2}%", portfolio.total_return() * Decimal::from(100));
// Position-level metrics
for position in portfolio.positions() {
println!(
"{}: P&L ${} ({:.2}%)",
position.symbol,
position.unrealized_pnl(),
position.return_pct() * Decimal::from(100)
);
}
Ok(())
}
use nt_portfolio::{
optimizer::{PortfolioOptimizer, OptimizationMethod},
constraints::Constraints,
};
use rust_decimal::Decimal;
#[tokio::main]
async fn main() -> anyhow::Result<()> {
let symbols = vec!["AAPL", "MSFT", "GOOGL", "AMZN", "TSLA"];
let optimizer = PortfolioOptimizer::new(
symbols,
OptimizationMethod::MeanVariance {
target_return: Some(Decimal::new(12, 2)), // 12% annual
risk_free_rate: Decimal::new(4, 2), // 4% risk-free
},
);
// Set constraints
let constraints = Constraints {
min_weight: Decimal::new(5, 2), // 5% minimum
max_weight: Decimal::new(30, 2), // 30% maximum
max_sector_weight: Some(Decimal::new(40, 2)), // 40% per sector
max_volatility: Some(Decimal::new(20, 2)), // 20% max vol
};
// Optimize portfolio
let optimal_weights = optimizer
.optimize()
.with_constraints(constraints)
.await?;
println!("Optimal Portfolio Weights:");
for (symbol, weight) in optimal_weights {
println!(" {}: {:.2}%", symbol, weight * Decimal::from(100));
}
// Get expected metrics
let metrics = optimizer.expected_metrics(&optimal_weights)?;
println!("\nExpected Return: {:.2}%", metrics.expected_return * Decimal::from(100));
println!("Expected Volatility: {:.2}%", metrics.volatility * Decimal::from(100));
println!("Sharpe Ratio: {:.2}", metrics.sharpe_ratio);
Ok(())
}
use nt_portfolio::{
Portfolio,
rebalancer::{Rebalancer, RebalancingStrategy},
};
use rust_decimal::Decimal;
#[tokio::main]
async fn main() -> anyhow::Result<()> {
let mut portfolio = Portfolio::load("main_portfolio")?;
let rebalancer = Rebalancer::new(
RebalancingStrategy::TargetWeights {
weights: vec![
("AAPL".to_string(), Decimal::new(25, 2)),
("MSFT".to_string(), Decimal::new(25, 2)),
("GOOGL".to_string(), Decimal::new(25, 2)),
("AMZN".to_string(), Decimal::new(25, 2)),
].into_iter().collect(),
},
);
// Calculate rebalancing trades
let trades = rebalancer.calculate_trades(&portfolio)?;
println!("Rebalancing Trades:");
for trade in &trades {
println!(
" {} {} {} shares @ ${}",
trade.side,
trade.symbol,
trade.quantity,
trade.estimated_price
);
}
// Execute rebalancing
rebalancer.execute_trades(trades, &mut portfolio).await?;
println!("Portfolio rebalanced successfully");
Ok(())
}
use nt_portfolio::optimizer::{PortfolioOptimizer, OptimizationMethod};
#[tokio::main]
async fn main() -> anyhow::Result<()> {
let assets = vec![
"SPY", // Stocks
"TLT", // Bonds
"GLD", // Gold
"DBC", // Commodities
];
let optimizer = PortfolioOptimizer::new(
assets,
OptimizationMethod::RiskParity,
);
let weights = optimizer.optimize().await?;
println!("Risk Parity Portfolio:");
for (symbol, weight) in weights {
println!(" {}: {:.2}%", symbol, weight * Decimal::from(100));
}
Ok(())
}
use nt_portfolio::attribution::PerformanceAttributor;
#[tokio::main]
async fn main() -> anyhow::Result<()> {
let portfolio = Portfolio::load("main_portfolio")?;
let benchmark = "SPY"; // S&P 500
let attributor = PerformanceAttributor::new(
portfolio,
benchmark,
);
let attribution = attributor.calculate().await?;
println!("Performance Attribution:");
println!(" Total Return: {:.2}%", attribution.total_return * Decimal::from(100));
println!(" Benchmark Return: {:.2}%", attribution.benchmark_return * Decimal::from(100));
println!(" Alpha: {:.2}%", attribution.alpha * Decimal::from(100));
println!(" Beta: {:.2}", attribution.beta);
println!("\nReturn Decomposition:");
println!(" Asset Selection: {:.2}%", attribution.selection_effect * Decimal::from(100));
println!(" Sector Allocation: {:.2}%", attribution.allocation_effect * Decimal::from(100));
println!(" Interaction: {:.2}%", attribution.interaction_effect * Decimal::from(100));
Ok(())
}
use nt_portfolio::tax::{TaxLossHarvester, HarvestingStrategy};
#[tokio::main]
async fn main() -> anyhow::Result<()> {
let portfolio = Portfolio::load("taxable_portfolio")?;
let harvester = TaxLossHarvester::new(
HarvestingStrategy {
min_loss_threshold: Decimal::new(1000, 0), // $1,000 minimum loss
max_lots_per_symbol: 10,
avoid_wash_sales: true,
},
);
let opportunities = harvester.find_opportunities(&portfolio)?;
println!("Tax-Loss Harvesting Opportunities:");
for opp in opportunities {
println!(
" {} {} shares: Loss ${} (save ${})",
opp.symbol,
opp.quantity,
opp.loss_amount,
opp.tax_savings
);
}
// Execute harvesting
let trades = harvester.generate_trades(opportunities)?;
// ... execute trades
Ok(())
}
nt-portfolio/
├── portfolio.rs # Core portfolio management
├── position.rs # Position tracking
├── optimizer/
│ ├── mean_variance.rs # Mean-variance optimization
│ ├── risk_parity.rs # Risk parity
│ ├── black_litterman.rs # Black-Litterman model
│ └── constraints.rs # Portfolio constraints
├── rebalancer.rs # Rebalancing logic
├── attribution.rs # Performance attribution
├── tax.rs # Tax-loss harvesting
├── metrics.rs # Portfolio metrics
└── lib.rs
The crate calculates comprehensive portfolio metrics:
| Crate | Purpose |
|---|---|
nt-core |
Core types |
nt-risk |
Risk calculations |
polars |
DataFrame operations |
statrs |
Statistical functions |
nalgebra |
Linear algebra for optimization |
# Unit tests
cargo test -p nt-portfolio
# Integration tests
cargo test -p nt-portfolio --features integration
# Benchmarks
cargo bench -p nt-portfolio
See CONTRIBUTING.md.
Licensed under MIT OR Apache-2.0.