Skip to content

enekoreto/risk-engine

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

RiskEngine (.NET 8 Web API)

RiskEngine is a production-style backend service that simulates a small market risk platform. It supports portfolio management, market data ingestion, VaR/Expected Shortfall calculations, scenario analysis, calculation history, audit logs, and scheduled background data updates.

Tech stack

  • .NET 8
  • ASP.NET Core Web API
  • Entity Framework Core + PostgreSQL
  • FluentValidation
  • xUnit + integration tests with WebApplicationFactory
  • Swagger/OpenAPI
  • Serilog structured logging
  • Docker + docker-compose

Key features

  • Portfolio CRUD with position management
  • Market data ingestion (JSON series + CSV import)
  • Risk metrics:
    • Historical simulation Value at Risk (VaR)
    • Expected Shortfall (ES)
    • Portfolio annualized volatility
    • Deterministic stress loss
    • Marginal contribution to portfolio risk per position
  • Scenario management + scenario run API
  • Calculation history + idempotent risk request handling
  • Audit log persistence for calculation requests/failures
  • Background hosted job for daily mock market data import
  • API key protection (X-Api-Key)
  • Health check endpoint (/health) and Prometheus metrics endpoint (/metrics)

Architecture

The solution uses a layered modular architecture:

  • src/RiskEngine.Domain
    • Core entities and enums (Portfolio, Position, MarketDataPoint, StressScenario, RiskCalculationRequest, RiskCalculationResult, AuditLog)
  • src/RiskEngine.Application
    • DTOs, validators, service interfaces, business services, and risk math logic
    • Keeps risk modelling separate from HTTP concerns
  • src/RiskEngine.Infrastructure
    • EF Core DbContext, repository implementations, seed logic, background hosted services
  • src/RiskEngine.Api
    • Controllers, middleware, API key security, startup composition, Swagger
  • tests/RiskEngine.UnitTests
    • Unit tests for risk math logic
  • tests/RiskEngine.IntegrationTests
    • End-to-end API integration tests

Risk modelling notes

  • VaR / ES use historical simulation over aligned historical return series.
  • Confidence levels are configurable in appsettings.json (95% and 99% by default).
  • Expected Shortfall is computed as the average loss in the tail beyond VaR.
  • Volatility is sample standard deviation annualized with sqrt(252).
  • Stress scenarios are deterministic shocks by asset class plus optional per-asset overrides.

Seed data

At startup, the API seeds:

  • Demo portfolio: AAPL, MSFT, BUND10Y, EURUSD
  • Multiple predefined stress scenarios
  • 300 business-day mock return series

Run locally

  1. Start PostgreSQL (or use docker-compose below).
  2. Update connection string and API key if needed:
    • src/RiskEngine.Api/appsettings.json
  3. Run API:
dotnet run --project src/RiskEngine.Api

Default local API key:

  • riskengine-local-key

Run with Docker

docker compose up --build

Services:

  • API: http://localhost:8080
  • PostgreSQL: localhost:5432

Swagger UI:

  • http://localhost:8080/swagger

Example curl requests

Create portfolio

curl -X POST http://localhost:8080/api/portfolios \
  -H "Content-Type: application/json" \
  -H "X-Api-Key: riskengine-local-key" \
  -d '{
    "name": "Graduate Risk Portfolio",
    "baseCurrency": "USD",
    "positions": [
      { "assetSymbol": "AAPL", "quantity": 50, "marketValue": 95000, "assetClass": 1, "currency": "USD" },
      { "assetSymbol": "MSFT", "quantity": 40, "marketValue": 80000, "assetClass": 1, "currency": "USD" }
    ]
  }'

Add position to portfolio

curl -X POST http://localhost:8080/api/portfolios/{portfolioId}/positions \
  -H "Content-Type: application/json" \
  -H "X-Api-Key: riskengine-local-key" \
  -d '{
    "assetSymbol": "EURUSD",
    "quantity": 100000,
    "marketValue": 110000,
    "assetClass": 3,
    "currency": "USD"
  }'

Upload return series (JSON)

curl -X POST http://localhost:8080/api/market-data \
  -H "Content-Type: application/json" \
  -H "X-Api-Key: riskengine-local-key" \
  -d '{
    "assetSymbol": "AAPL",
    "pointType": 1,
    "values": [
      { "observationDate": "2025-10-01", "value": 0.0123 },
      { "observationDate": "2025-10-02", "value": -0.0081 }
    ]
  }'

Import market data CSV

curl -X POST http://localhost:8080/api/market-data/import/csv \
  -H "Content-Type: application/json" \
  -H "X-Api-Key: riskengine-local-key" \
  -d "{\"pointType\":1,\"csvContent\":\"$(cat samples/market-data-returns.csv | sed ':a;N;$!ba;s/\n/\\n/g')\"}"

Calculate risk

curl -X POST http://localhost:8080/api/risk/calculate \
  -H "Content-Type: application/json" \
  -H "X-Api-Key: riskengine-local-key" \
  -H "Idempotency-Key: calc-portfolio-1-2026-04-12" \
  -d '{
    "portfolioId": "{portfolioId}",
    "confidenceLevel": 0.95
  }'

Get risk result by result id

curl -X GET http://localhost:8080/api/risk/results/{resultId} \
  -H "X-Api-Key: riskengine-local-key"

Run scenarios

curl -X POST http://localhost:8080/api/scenarios/run \
  -H "Content-Type: application/json" \
  -H "X-Api-Key: riskengine-local-key" \
  -d '{
    "portfolioId": "{portfolioId}"
  }'

Get audit logs

curl -X GET "http://localhost:8080/api/audit-logs?limit=100" \
  -H "X-Api-Key: riskengine-local-key"

Main endpoints

  • POST /api/portfolios
  • GET /api/portfolios/{id}
  • POST /api/portfolios/{id}/positions
  • POST /api/market-data
  • POST /api/market-data/import/csv
  • POST /api/risk/calculate
  • GET /api/risk/results/{id}
  • GET /api/risk/history
  • POST /api/scenarios
  • POST /api/scenarios/run
  • GET /api/audit-logs
  • GET /health
  • GET /metrics

Configuration

Key sections in src/RiskEngine.Api/appsettings.json:

  • ConnectionStrings:Postgres
  • Security:ApiKey
  • RiskCalculation
    • MinimumObservationCount
    • AllowedConfidenceLevels
  • BackgroundJobs
    • mock market data import interval/symbols

Testing

dotnet test RiskEngine.sln

Current coverage includes:

  • Risk calculation math unit tests
  • Integration tests for portfolio/risk endpoints
  • Edge cases: invalid inputs, empty portfolios, unknown assets

Why this project matters

Risk systems are core infrastructure in modern financial markets, especially for brokers, CCP/clearing workflows, and post-trade controls where capital, margin, and stress resilience must be computed reliably and repeatedly.

This project demonstrates the backend engineering concerns behind that reality: deterministic calculations, strict validation, traceability through audit logs, idempotent request handling, resilience through health/metrics, and reproducible containerized deployment. Those are the same reliability and correctness themes that matter in real financial infrastructure, where failures are operationally expensive and risk visibility must be timely and explainable.

About

Production-style .NET 8 Web API market risk engine portfolio project

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors