Skip to content

Repository files navigation

B3TradingPlatform

Status: bootstrap. See issue #1.

Open-source participant-side platform in the B3 ecosystem family — what a corretora's order-management backend looks like. Symmetric to B3MarketDataPlatform but for the order-entry plane: it owns end-client identity, holds positions, manages own working orders, and exposes a modern API (REST + WebSocket + frontend) on top of the raw FIXP/SBE protocol.

Where this fits

Repo Role Wire IN Wire OUT Frontend?
B3MatchingPlatform The "exchange" (matching engine + UMDF publisher) EntryPoint orders UMDF MD + EntryPoint ER Operator-only
B3MarketDataPlatform Market-data subscriber UMDF Yes
B3TradingPlatform (this repo) Participant / OMS-like backend EntryPoint ER EntryPoint orders Yes
B3EntryPointClient Wire-puro EntryPoint client lib + conformance suite EntryPoint ER EntryPoint orders

This repo consumes B3EntryPointClient (as a NuGet or project reference) for the wire layer, and adds everything above it: end-client management, subscriptions, position keeping, frontend.

Architecture sketch

Browser / Mobile                          External user bots
       │ WebSocket (subscribe: orders.me, executions.me, positions.me, …)
       │ REST     (submit/cancel/replace, login, account ops)
       │                                          │ FIXP/SBE TCP
       ▼                                          ▼
B3TradingPlatform backend
  ├── REST + WebSocket API     (browsers, REST clients)
  ├── FIXP Listener            (external user bots; opt-in via Trading:EntryPointListener:Enabled)
  ├── EndClientRegistry        end-client identity, login (JWT/session)
  ├── SubscriptionManager      per-end-client streams
  ├── PositionKeeper           cumulative position derived from ER stream
  ├── WorkingOrderBook         per-end-client open orders
  ├── PreTradeRisk             (v2) margin / position limits / fat-finger
  └── B3EntryPointClient       ← wire-puro lib (separate repo)
         │ TCP / SBE / SOFH / FIXP
         ▼
   B3MatchingPlatform   ← or B3 UAT (same lib, just swap endpoint + creds)

See docs/ARCHITECTURE.md for the longer-form notes, including ER routing, ClOrdID namespacing, and the open architecture questions flagged in issue #1.

FIXP Listener (inbound)

External user bots can connect via native B3 FIXP/SBE protocol using self-service credentials. See the FIXP listener operations guide and the RFC.

Layout

backend/
  src/
    B3.Trading.Domain/           end-client, position, order aggregate
    B3.Trading.Application/      use-cases, registry, position keeper
    B3.Trading.Api/              REST + WebSocket endpoints
    B3.Trading.Infrastructure/   B3EntryPointClient adapter (Stub/Mock/Real/Unavailable modes)
    B3.Trading.Host/             composition root (ASP.NET Core)
  tests/
    B3.Trading.Domain.Tests/
    B3.Trading.Application.Tests/
    B3.Trading.Api.Tests/        (uses WebApplicationFactory<Program>)
frontend/
  index.html  +  js/app.js       (vanilla, mirrors B3MarketDataPlatform stack)
docs/
  ARCHITECTURE.md
.github/workflows/ci.yml         (build + test + format, mirrors B3MatchingPlatform)

Build & test

Requires the .NET SDK pinned in global.json (10.0.201).

dotnet restore B3TradingPlatform.slnx
dotnet build   B3TradingPlatform.slnx -c Release
dotnet test    B3TradingPlatform.slnx -c Release

Run locally

dotnet run --project backend/src/B3.Trading.Host

The host listens on the default ASP.NET Core ports (typically http://localhost:5000). Smoke-test with:

curl http://localhost:5000/health
curl -XPOST http://localhost:5000/api/orders \
  -H 'content-type: application/json' \
  -d '{"login":"alice","symbol":"PETR4","side":"Buy","type":"Limit","quantity":100,"price":30.50}'
curl 'http://localhost:5000/api/orders?login=alice'

The IExchangeGateway wiring is selected at startup via Trading:Exchange:Mode (composition root in Program.cs; see ARCHITECTURE.md § Wire boundary for the full table):

Mode Behavior
Stub No-op gateway; CI smoke / API-only tests
Mock In-process MockEntryPointClient; dev loop, integration tests, demo overlay
Real Per-firm B3EntryPointClient over FIXP/SBE against B3MatchingPlatform (or B3 UAT)
Unavailable Fail-closed; submits return 502 (Docker bootstrap default before broker wiring)

Quick demo (laptop)

Want to see the trader UI move on its own — blotter filling up, executions ticking, positions evolving — without manually clicking through the order ticket? Use the demo overlay:

cp docker/.env.example docker/.env
# edit docker/.env and set TRADING_AUTH_SIGNING_KEY (>= 32 bytes)

docker compose \
    -f docker/docker-compose.yml \
    -f docker/docker-compose.demo.yml \
    up -d --build
# open http://localhost:8080 and log in as bot-clientA / demopass

This brings up the trading-host in Mode=Mock + AllowErInjection=true (synthetic ER injection enabled; #163 collapsed the legacy Mode=Simulator into this combination) and starts a companion demo-driver process (backend/tools/B3.Trading.DemoDriver) that:

  • logs in as bot-clientA and bot-clientB and submits random buy/sell limit orders around the configured reference prices, and
  • logs in as demo-admin and injects synthetic Fill / PartialFill ERs against the bots' working orders via /api/admin/simulator/er.

Log in as bot-clientA (password demopass) or bot-clientB to see that bot's blotter, executions and positions panels evolve in real time. Logging in as alice — the original seed — shows the empty view, since alice does not submit orders.

Tear down with docker compose -f docker/docker-compose.yml -f docker/docker-compose.demo.yml down -v.

The overlay is for laptop demos onlyAllowErInjection=true is gated to non-Production environments and the demo credentials are public in this repo. See docs/DOCKER.md § Demo overlay for tuning, safety notes, and what is intentionally out of scope (live MD ticks, real-stack cross-firm bots).

Sample bot (authenticated end-client smoke)

Want to see what an ordinary end-client integration looks like, not a demo/simulation shortcut? backend/tools/B3.Trading.SampleBot is a small one-shot .NET console that authenticates through the same POST /api/auth/login a browser uses, opens the same authenticated /ws, subscribes to B3MarketDataPlatform's public feed, submits one bounded REST order, and reconciles before exiting. It never receives a matching-platform endpoint or FIXP credential — that's enforced at the option-validation layer, not just documented.

cp docker/.env.example docker/.env
# edit docker/.env — TRADING_AUTH_SIGNING_KEY is mandatory (>= 32 bytes)

docker compose \
    -f docker/docker-compose.yml \
    -f docker/docker-compose.market-maker.yml \
    -f docker/docker-compose.sample-bot.yml \
    up -d --build --wait trading-host market-maker-bot
docker compose \
    -f docker/docker-compose.yml \
    -f docker/docker-compose.market-maker.yml \
    -f docker/docker-compose.sample-bot.yml \
    run --rm --no-deps --build sample-bot

LocalPassword auth is the required default; ExternalExchange and InternalToken cover the Hybrid/Entra and supplied-token cases. The default order is deliberately priced away from the reference price, so the expected outcome on a clean run is submit -> observe Working -> timeout -> best-effort cancel -> Cancelled, with GET /api/orders showing no working order left behind — not a guaranteed fill. See docs/DOCKER.md § Sample-bot overlay for auth-mode details, the optional sub-account flow, safety notes, and how this differs from DemoDriver, MarketMakerBot, and the external FIXP user-bot listener.

Documentation

Start at docs/README.md for the full index — it maps every architecture note, RFC, runbook, and operations guide in this repo. Highlights:

Bootstrap scope (issue #1)

In:

  • Backend skeleton (Clean-Architecture-ish: Domain / Application / Infrastructure / Api / Host)
  • Frontend skeleton matching B3MarketDataPlatform's vanilla-JS stack
  • This README + docs/ARCHITECTURE.md
  • CI: build + test + dotnet format (mirrors B3MatchingPlatform)

Out (deliberately deferred):

  • Pre-trade risk (v2)
  • Persistence (start ephemeral, derive from ER replay)
  • Algo / basket
  • Multi-region / HA
  • Smoke E2E against B3MatchingPlatform — blocked on the matching-side FIXP lifecycle (Phase 2 epic)

License

MIT

About

Participant-side platform for B3: end-client identity, positions, working orders, WebSocket+frontend on top of EntryPoint (companion to B3MatchingPlatform / B3MarketDataPlatform / B3EntryPointClient)

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages