Skip to content

Building a CCM Adapter

A CCM (Capital & Connectivity Manager) plugin connects Meridian to a broker or trading venue. This guide walks through building one from scratch.

When to Build a CCM

Build a CCM when you need to connect to a broker or venue that doesn't already have a Meridian adapter. Each CCM handles one venue — if you trade through three brokers, you deploy three CCM instances.

Project Setup

meridian new ccm --lang python --name my-broker-ccm
cd my-broker-ccm

Or start from the SDK directly:

from meridian import CCMPlugin

plugin = CCMPlugin("my-broker", instance_id="ccm-my-broker")

Required Methods

Handle Incoming Orders

@plugin.on_order
async def handle_order(**data):
    """Called when EMS routes a child order to this venue."""
    symbol = data["security_id"]
    side = data["side"]
    quantity = data["quantity"]
    price = data.get("price")

    # Send to your broker's API
    venue_order_id = await broker_api.submit(symbol, side, quantity, price)

    # When the broker fills, publish back
    await plugin.submit_fill(symbol, side, quantity, fill_price)

Report Session Status

@plugin.on_ready
async def on_ready():
    await plugin.report_session_status("CONNECTED", "Session established")

@plugin.on_shutdown
async def on_shutdown():
    await plugin.report_session_status("DISCONNECTED", "Shutting down")

Fill Requirements

Every fill you publish must include:

Field Required Description
security_id Yes Instrument identifier
side Yes BUY or SELL
quantity Yes Filled quantity
price Yes Fill price

The sidecar automatically adds: - ts_init — when the sidecar received the fill - Deduplication key — composite of (trade_id, side, price, quantity, venue)

Session Management

Report status changes so the EMS knows whether to route orders to you:

Status When
CONNECTED Session established, ready for orders
DISCONNECTED Session lost, cannot accept orders
DEGRADED Partial connectivity (e.g., can receive but not send)
RECONNECTING Attempting to reconnect (exponential backoff)

Testing

Use FakeSidecar to test without a broker connection:

from meridian import CCMPlugin
from meridian.testing import FakeSidecar

sidecar = FakeSidecar()
plugin = CCMPlugin("test", instance_id="test-ccm", sidecar=sidecar)

await plugin.submit_fill("AAPL", "BUY", 100, 150.0)
assert sidecar.messages[0].topic == "platform.ccm.test-ccm.fill.AAPL"

Common Mistakes

  • Not handling reconnection (broker connections drop — implement exponential backoff)
  • Not publishing session status changes (EMS doesn't know to stop routing)
  • Duplicate fills (ensure your broker API deduplicates, or track locally)

Next Steps