Skip to main content

Command Palette

Search for a command to run...

Developing a Trading Strategy Platform: A Guide with gRPC, Buf, and Python

Creating a Trading Backtesting System Using gRPC, Python, and Multi-Language Support

Published
5 min read
Developing a Trading Strategy Platform: A Guide with gRPC, Buf, and Python

Introduction

Modern quantitative trading platforms rarely live in a single language or runtime. Performance-critical components may be written in Go, data science logic in Python, and APIs consumed by dashboards, notebooks, or web clients.

To support scalability, language-agnostic services, and clean contracts, this article walks through building a polyglot microservice-based strategy backtesting system using:

  • gRPC – high-performance service communication

  • gRPC-Gateway – REST access for dashboards & clients

  • Buf – protobuf linting, breaking-change detection & generation

  • Uber FX – dependency injection for Go services

  • Python – strategy logic & backtesting engine

  • Nx Workspace – monorepo orchestration for multi-language systems

By the end, you’ll have a cleanly designed system that:

  • Defines strategies once

  • Backtest them at scale

  • Exposes results via gRPC & REST

  • Is ready for extension into live trading or research tooling


System Architecture Overview

Core Services

ServiceLanguageResponsibility
Strategy ServicePythonStrategy definition & signal generation
Backtest ServicePythonHistorical simulation & PnL computation
Market Data ServiceGoOHLCV & order book access
Result ServiceGoAggregation & storage of backtest outputs
API GatewayGoREST exposure via gRPC-Gateway

High-Level Flow

  1. User submits a strategy definition

  2. Strategy service validates logic

  3. Backtest service runs simulations

  4. Results are stored & aggregated

  5. Clients query results via REST or gRPC


Why This Stack?

gRPC

  • Language-agnostic

  • Strongly typed contracts

  • Streaming support (ideal for market data)

Buf

  • Single source of truth for protobufs

  • Prevents accidental breaking changes

  • Clean code generation across Go & Python

Uber FX

  • Explicit dependency graph

  • Easy service composition

  • Production-ready lifecycle management

Nx Workspace

  • Monorepo with dependency graphs

  • One command to build/test everything

  • Language-agnostic orchestration


Hands-On: Step-by-Step Implementation


1. Nx Workspace Setup

Initialize Workspace

npx create-nx-workspace@latest backtesting-platform
cd backtesting-platform

Choose:

  • Template: Empty Starter Template

then create your services

mkdir apps
cd apps

mkdir api-gateway market-data-service result-service strategy-service backtest-service

Next, we create the packages.

cd packages

mkdir proto shared

Your Final Folder Structure

apps/
  api-gateway/
  market-data-service/
  result-service/
  strategy-service/
  backtest-service/

packages/
  proto/
  shared/

Nx now manages builds, caching, and dependency graphs across Go & Python.


2. Buf Initialization

Install Buf (https://buf.build/docs/cli/installation/)

npm install @bufbuild/buf

Initialize Buf Workspace

cd packages/proto
npx buf mod init

touch buf.gen.yaml

buf.yaml

version: v1
lint:
  use:
    - DEFAULT
breaking:
  use:
    - FILE

3. gRPC Contract Definition

Create the proto files in the proto folder, with the contents below

strategy.proto

syntax = "proto3";

package strategy;

service StrategyService {
  rpc RegisterStrategy(RegisterStrategyRequest)
    returns (RegisterStrategyResponse);
}

message RegisterStrategyRequest {
  string name = 1;
  string language = 2;
  string source_code = 3;
}

message RegisterStrategyResponse {
  string strategy_id = 1;
}

backtest.proto

syntax = "proto3";

package backtest;

service BacktestService {
  rpc RunBacktest(RunBacktestRequest)
    returns (RunBacktestResponse);
}

message RunBacktestRequest {
  string strategy_id = 1;
  string symbol = 2;
  string start_date = 3;
  string end_date = 4;
}

message RunBacktestResponse {
  string backtest_id = 1;
}

4. Code Generation with Buf

In the buf.gen.yaml file, add the content below

version: v2
managed:
  enabled: true
  override:
    - file_option: go_package_prefix
      value: github.com/bufbuild/buf-examples/gen
plugins:
  - remote: buf.build/protocolbuffers/go
    out: ../gen
    opt: paths=source_relative
  - remote: buf.build/connectrpc/gosimple
    out: ../gen
    opt:
      - paths=source_relative
  - remote: buf.build/protocolbuffers/python
    out: ../gen
  - remote: buf.build/connectrpc/python
    out: ../gen
  - remote: buf.build/grpc-ecosystem/gateway
    out: ../gen
    opt:
      - paths=source_relative

inputs:
  - directory: .

Generate code for python and Golang:

npx buf generate

This will create a gen sub-folder in the packages folder, with generated python and Golang code.


5. Python Strategy Service

FastAPI + gRPC

class StrategyService(strategy_pb2_grpc.StrategyServiceServicer):
    def RegisterStrategy(self, request, context):
        strategy_id = str(uuid.uuid4())
        save_strategy(strategy_id, request.source_code)
        return strategy_pb2.RegisterStrategyResponse(
            strategy_id=strategy_id
        )

This service:

  • Accepts user strategies

  • Stores code safely

  • Returns a versioned strategy ID


6. Python Backtesting Engine

def run_backtest(strategy_fn, data):
    positions = []
    for candle in data:
        signal = strategy_fn(candle)
        positions.append(signal)
    return compute_pnl(positions, data)

Key ideas:

  • Deterministic replay

  • Time-aligned execution

  • Reproducible results


7. Go Market Data Service (Uber FX)

func NewMarketDataService() *MarketDataService {
    return &MarketDataService{}
}

func main() {
    app := fx.New(
        fx.Provide(NewMarketDataService),
        fx.Invoke(RegisterGRPC),
    )
    app.Run()
}

FX ensures:

  • Explicit dependency wiring

  • Clean startup/shutdown

  • Testable services


8. gRPC-Gateway for REST Access

import "google/api/annotations.proto";

rpc RunBacktest(RunBacktestRequest)
returns (RunBacktestResponse) {
  option (google.api.http) = {
    post: "/v1/backtests/run"
    body: "*"
  };
}

Now clients can:

  • Use REST for dashboards

  • Use gRPC for internal services


9. Viewing Backtest Results

Expose endpoints like:

GET /v1/backtests/{id}/metrics

Returned metrics:

  • Total PnL

  • Sharpe Ratio

  • Max Drawdown

  • Win rate

Perfect for:

  • Streamlit dashboards

  • Research notebooks

  • Web UIs


10. Nx Task Orchestration

nx run-many --target=serve --all

Nx ensures:

  • Correct startup order

  • Cached builds

  • Parallel execution


Final Thoughts

This architecture gives you:

  • Strong contracts

  • Language freedom

  • Scalable experimentation

  • Production-grade structure

It’s suitable for:

  • Quant research platforms

  • Trading infrastructure

  • Large-scale simulation engines

From here, we can add:

  • Distributed backtesting

  • Strategy versioning

  • Live trading adapter

  • and much more feature

For the full code you can check the github repo linked below:

https://github.com/litmus-zhang/personal-playground/tree/main/quant/backtesting-platform