PnL Controller - Portfolio Profit & Loss Calculation
Demo

Overview
The PnlController is a C++ REST API controller that calculates Profit and Loss (PnL) for investment portfolios. It integrates with MongoDB for portfolio data and QuotesService for real-time market prices, providing accurate PnL calculations across multiple assets.
Features
- Real-time PnL Calculation: Calculates profit/loss using current market prices
- Portfolio Analytics: Tracks individual asset performance within portfolios
- Batch Processing: Updates PnL for all portfolios in one operation
- MongoDB Integration: Stores and retrieves portfolio data
- Quotes Service Integration: Gets current market prices with caching
Architecture
Data Models
AssetQuote
struct AssetQuote {
std::string sravz_id;
double last_price;
std::string price_capture_time;
};
PortfolioAsset
struct PortfolioAsset {
std::string id;
std::string sravz_id;
double quantity;
double weight;
double purchase_price;
double current_price;
double purchase_value;
double current_value;
double pnl;
double pnl_percent;
std::string pnl_calculation_dt;
};
Portfolio
struct Portfolio {
std::string id;
std::string name;
std::vector<std::string> portfolio_assets;
double value;
double pnl;
double pnl_percent;
std::string pnl_calculation_dt;
};
API Endpoints
Calculate Portfolio PnL
Endpoint: POST /api/pnl/calculate/{portfolio_id}
Calculates PnL for a specific portfolio.
Response:
{
"portfolio_id": "60a1b2c3d4e5f6g7h8i9j0k1",
"name": "Tech Portfolio",
"total_value": 125000.50,
"total_pnl": 15000.50,
"pnl_percent": 13.64,
"calculation_time": "2024-11-24T10:30:00Z",
"assets": [
{
"sravz_id": "AAPL",
"quantity": 100,
"purchase_price": 150.00,
"current_price": 175.50,
"pnl": 2550.00,
"pnl_percent": 17.00
}
]
}
Update All Portfolios
Endpoint: POST /api/pnl/update-all
Updates PnL calculations for all portfolios in the system.
Response:
{
"status": "success",
"portfolios_updated": 25,
"total_value": 5250000.00,
"total_pnl": 450000.00,
"update_time": "2024-11-24T10:30:00Z"
}
Implementation Details
PnL Calculation Logic
The controller calculates PnL using the following formulas:
- Purchase Value =
quantity × purchase_price - Current Value =
quantity × current_price - PnL (Dollar) =
current_value - purchase_value - PnL (Percentage) =
(pnl / purchase_value) × 100
Workflow
- Load Portfolio Data: Retrieve portfolio and asset information from MongoDB
- Fetch Current Prices: Get latest prices from QuotesService (with caching)
- Calculate Asset PnL: Compute PnL for each asset in the portfolio
- Aggregate Portfolio PnL: Sum up all asset PnL values
- Update Database: Store calculated PnL values in MongoDB
- Return Results: Send PnL report as JSON response
Usage Example
Calculate Single Portfolio
#include <pnl_controller.hpp>
auto mongoClient = std::make_shared<MongoClient>();
auto quotesService = std::make_shared<QuotesService>(mongoClient);
auto pnlController = std::make_shared<PnlController>(mongoClient, quotesService);
// Calculate PnL for specific portfolio
std::string result = pnlController->calculatePortfolioPnl("portfolio_id_123");
Update All Portfolios
// Update PnL for all portfolios
std::string result = pnlController->updateAllPortfoliosPnl();
Integration with Router
The PnlController is integrated with the Boost Beast REST API router:
// In router.cpp
void router::handle_post_pnl_calculate(http::request<http::string_body> &req,
http::response<http::string_body> &res) {
std::string portfolio_id = extract_path_param(req.target(), "portfolio_id");
std::string result = pnlController_->calculatePortfolioPnl(portfolio_id);
res.body() = result;
res.set(http::field::content_type, "application/json");
}
Dependencies
- MongoClient: For portfolio and asset data storage
- QuotesService: For real-time market price data
- Boost.JSON: For JSON serialization/deserialization
- DependencyContainer: For dependency injection
See Also
- Quotes Analytics API - Market analytics
- Fundamentals Controller - S3 presigned URL caching
- MongoDB Service - Database integration
- REST API Router - Routing architecture
