Skip to content

bradycheng1/MarketDataManager

Repository files navigation

MarketDataService

A production-grade C# market data provider exposing:

  • Spot prices — pulled live from KDB+/q
  • Implied volatility — EQBrain spline parameter cache + on-the-fly interpolation

Clients can connect via gRPC (C#, C++), REST/JSON (Excel HTTP), or the bundled Excel-DNA XLL add-in.


Architecture

┌──────────────────────────────────────────────────────────────────────┐
│                       MarketDataService.Server                       │
│                         (ASP.NET Core 8)                             │
│                                                                      │
│  ┌──────────────────────────┐   ┌──────────────────────────────────┐ │
│  │  gRPC SpotPriceService   │   │   gRPC VolatilityService         │ │
│  │  REST  /api/v1/spot/...  │   │   REST /api/v1/vol/...           │ │
│  └────────────┬─────────────┘   └──────────────┬───────────────────┘ │
│               │                                │                     │
│  ┌────────────▼──────────┐      ┌──────────────▼───────────────────┐ │
│  │  KdbSpotPriceProvider │      │       VolatilitySurface           │ │
│  │  (ISpotPriceProvider) │      │       (IVolatilitySurface)        │ │
│  └────────────┬──────────┘      │  ┌─────────────────────────────┐ │ │
│               │                 │  │ ConcurrentDictionary cache  │ │ │
│  ┌────────────▼──────────┐      │  │ (ticker, expiry) → SplineP  │ │ │
│  │   KdbConnection       │      │  └──────────────┬──────────────┘ │ │
│  │   (TCP IPC protocol)  │      │                 │                 │ │
│  └────────────┬──────────┘      │  ┌──────────────▼──────────────┐ │ │
│               │                 │  │   SplineInterpolator        │ │ │
│               │                 │  │   NaturalCubic / Akima / SVI│ │ │
│               │                 │  └─────────────────────────────┘ │ │
│               │                 └──────────────────────────────────┘ │
└───────────────┼──────────────────────────────────────────────────────┘
                │
         ┌──────▼──────┐        ┌─────────────────────┐
         │  KDB+/q     │        │  EQBrain             │
         │  (port 5000)│        │  → PushSplineParams  │
         └─────────────┘        └─────────────────────┘

Clients:
  ┌─────────────────┐  ┌──────────────────┐  ┌──────────────────────┐
  │  C# gRPC client │  │  C++ gRPC client  │  │  Excel-DNA XLL       │
  │  (Grpc.Net)     │  │  (grpc++ vcpkg)   │  │  =MDSpot("AAPL")     │
  └─────────────────┘  └──────────────────┘  │  =MDVol("AAPL",0.25,K)│
                                              └──────────────────────┘

Project Structure

MarketDataService/
├── proto/
│   └── market_data.proto            # Single source-of-truth IDL
├── src/
│   ├── MarketDataService.Core/      # Domain models + interfaces
│   │   ├── Models/
│   │   │   ├── MarketDataModels.cs  # SpotPriceData, VolatilityData
│   │   │   └── SplineParams.cs      # Vol surface parameters
│   │   └── Interfaces/
│   │       └── IMarketDataInterfaces.cs
│   ├── MarketDataService.KdbAdapter/
│   │   ├── KdbConnection.cs         # KDB IPC TCP client
│   │   ├── KdbDeserializer.cs       # Binary → .NET objects
│   │   └── KdbSpotPriceProvider.cs  # Implements ISpotPriceProvider
│   ├── MarketDataService.VolEngine/
│   │   ├── SplineInterpolator.cs    # NaturalCubic / Akima / SVI math
│   │   └── VolatilitySurface.cs     # Cache + interpolation orchestrator
│   └── MarketDataService.Server/
│       ├── GrpcServices/
│       │   ├── SpotPriceGrpcService.cs
│       │   └── VolatilityGrpcService.cs
│       ├── RestControllers/
│       │   └── MarketDataController.cs
│       ├── Program.cs
│       └── appsettings.json
└── clients/
    ├── excel/
    │   ├── MarketDataAddIn.cs       # Excel-DNA UDF functions
    │   └── MarketData.dna           # Excel-DNA manifest
    └── cpp/
        ├── CMakeLists.txt
        ├── market_data_client.h     # Public C++ API
        ├── market_data_client.cpp
        └── example_main.cpp

Quick Start

1. Run the server

cd src/MarketDataService.Server
# Edit appsettings.json → set KDB host/port/credentials
dotnet run
# gRPC on https://localhost:7001
# REST on https://localhost:7001/swagger

2. Push vol params from EQBrain (via gRPC)

var channel = GrpcChannel.ForAddress("https://localhost:7001");
var vol     = new VolatilityService.VolatilityServiceClient(channel);

await vol.UpdateSplineParamsAsync(new SplineParamsUpdate
{
    Ticker       = "AAPL",
    ExpiryYears  = 0.25,
    SplineType   = "natural_cubic",
    Knots        = { -0.3, -0.2, -0.1, 0.0, 0.1, 0.2, 0.3 },
    Coeffs       = { /* 4*(n-1) coefficients */ },
    CreatedUtcMs = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds()
});

3. Query from C#

var spot = await spotClient.GetSpotPriceAsync(new SpotPriceRequest { Ticker = "AAPL" });
Console.WriteLine($"AAPL = {spot.Price}");

var vol  = await volClient.GetVolAsync(new VolRequest
    { Ticker = "AAPL", ExpiryYears = 0.25, Strike = 150.0 });
Console.WriteLine($"AAPL 3M 150 vol = {vol.Vol:P1}");

4. Query from Excel (after installing XLL)

=MDSpot("AAPL")            → 182.35
=MDVol("AAPL", 0.25, 150)  → 0.2718

5. Query from C++

md::MarketDataClient client("localhost:7001");
auto spot = client.GetSpot("AAPL");
auto vol  = client.GetVol("AAPL", 0.25, 150.0);

6. REST (curl / Excel Power Query)

curl https://localhost:7001/api/v1/spot/AAPL
curl "https://localhost:7001/api/v1/vol/AAPL?expiry=0.25&strike=150"

Volatility Engine Details

Supported Spline Types

Type Description When to use
Quadratic (default) EQBrain primary format: S(x) = a + b·dx + c·dx² Production — EQBrain push
NaturalCubic Classic cubic spline with natural boundary conditions Backward compatibility
Akima Akima spline — less oscillatory at outliers Sparse or noisy input data

Quadratic Spline (EQBrain default)

Parameters per segment: [a, b, c]

S_i(x) = a_i + b_i*(x - knot_i) + c_i*(x - knot_i)²

Coefficient array layout (n knots → 3*(n-1) values):

[a₀,b₀,c₀, a₁,b₁,c₁, …, aₙ₋₂,bₙ₋₂,cₙ₋₂]

Expiry interpolation

Vol at intermediate expiries is obtained by linear interpolation in total variance:

w(T) = w(T₁) + (T-T₁)/(T₂-T₁) × (w(T₂)-w(T₁))
σ(T) = √(w(T)/T)

This ensures a non-negative forward variance and no calendar spread arbitrage.


Configuration (appsettings.json)

{
  "Kdb": {
    "Host":      "kdb-prod-01",
    "Port":      5000,
    "User":      "marketdata",
    "Password":  "***",
    "TimeoutMs": 5000
  },
  "KdbSpot": {
    "CacheTtlMs": 200
  }
}

KDB Schema Assumptions

The adapter calls getSpot[TICKER]which should return a mixed list(price;bid;ask;timestamp). Adjust KdbSpotPriceProvider.csandKdbDeserializer.cs` to match your actual KDB function/table names.


Building C++ Client

cd clients/cpp
cmake -B build -DCMAKE_TOOLCHAIN_FILE=$VCPKG_ROOT/scripts/buildsystems/vcpkg.cmake
cmake --build build
./build/md_example

Dependencies (via vcpkg): grpc, protobuf


Notes for Production

  • Replace the minimal KDB IPC parser with kx's official c.cs or a robust library.
  • Add mTLS between EQBrain → service (set use_tls=true).
  • Consider Redis or Apache Ignite for distributed spline param cache across service replicas.
  • Add Prometheus metrics via prometheus-net.AspNetCore for latency/error monitoring.

Offline Debug & Test (Air-gapped Machine)

Requirement

The target machine must have:

  • .NET Framework 4.8 (pre-installed on Windows 10 1903+)
  • Visual Studio 2019 (with .NET Framework 4.8 targeting pack)

No internet, no NuGet, no .NET SDK, no other tools needed.

What can run offline with ZERO NuGet dependencies

Project NuGet Dependencies
MarketDataService.Core NONE
MarketDataService.VolEngine NONE
MarketDataService.KdbAdapter NONE
ConsoleRunner (test app) NONE (references above 3 projects only)

These 4 projects compile and run with just the .NET Framework 4.8 DLLs.

What needs NuGet (Server + Excel only)

Project Needs NuGet?
MarketDataService.Server ❌ Yes — Grpc.AspNetCore, Swashbuckle, etc.
MarketDataExcelAddIn ❌ Yes — Grpc.Net.Client, ExcelDna

Step-by-step for the offline machine

Option A: Quick test (no NuGet, no Server)

  1. Copy the entire MarketDataService/ folder to the offline machine
  2. Open MarketDataService.sln in VS 2019
  3. In Solution Explorer, right-click ConsoleRunnerSet as StartUp Project
  4. Right-click ConsoleRunnerBuild
  5. Press F5 to run the test suite

The test output shows:

=== MarketDataService — Offline Test Runner ===

  QuadraticSpline_Eval ... PASS
  QuadraticSpline_Build ... PASS
  QuadraticSpline_BuildAndEval ... PASS
  CubicSpline_Eval ... PASS
  ExpiryInterpolation ... PASS
  VolSurface_SingleSlice ... PASS
  VolSurface_MultiSlice ... PASS
  VolSurface_NotFound ... PASS
  FindSegment_Edges ... PASS
  Horner_Formula ... PASS

Results: 10 passed, 0 failed, 10 total

Option B: Full Server (needs pre-downloaded NuGet packages)

  1. On a machine with internet, run pack-offline.bat:

    cd MarketDataService
    pack-offline.bat

    This creates deploy-offline/MarketDataService/ with source + packages/ folder.

  2. Copy deploy-offline/MarketDataService/ to the offline machine

  3. Open MarketDataService.sln in VS 2019

  4. If VS prompts for NuGet restore — point it to the packages/ folder:

    • Tools → NuGet Package Manager → Package Manager Settings
    • Under "Package Sources", add: packages/ folder path
    • Right-click Solution → Restore NuGet Packages
  5. Build and run Server as normal

Breakpoints to try (VS 2019)

File Where to set breakpoint What you're testing
SplineInterpolator.cs line 44 EvalQuadraticSpline return Verify Horner's formula output
VolatilitySurface.cs line 129 BracketIndex Verify expiry bracket lookup
VolatilitySurface.cs line 135 InterpolateExpiryLinearVariance call Verify total-variance interpolation
KdbDeserializer.cs line 30 ParseSpotResponse When you connect to real KDB

Test what matters most: Quadratic Spline accuracy

The ConsoleRunner includes 10 tests. Key ones:

  • QuadraticSpline_Eval: exact eval at knots and midpoints
  • QuadraticSpline_Build: fit from raw (x,y), verify reproduction
  • ExpiryInterpolation: linear total-variance formula correctness
  • VolSurface_MultiSlice: full pipeline — cache → bracket → interpolate

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors