Skip to content

Docs

Getting started

MultiEdge Signal Relay is auditable signal-distribution infrastructure — not execution. The fastest way in is the Python SDK (multiedge-relay, Apache 2.0); everything it does is plain HTTP you can also call directly — see the API reference.

1 · Install

shell
$ uv add multiedge-relay

2 · Publish a signal

client_signal_id is your idempotency key: retries return the original ack (200, duplicate: true) instead of publishing twice. The ack carries the gapless per-strategy sequence.

publish.py
from multiedge_relay import Signal, SignalPublisher

relay = SignalPublisher(api_key="mesk_...")
ack = relay.publish(Signal(strategy_id="str_dm_rotation",
                           client_signal_id="2026-08-14-close",  # safe to retry
                           payload=rebalance))                   # 201, or 200 duplicate

3 · Subscribe with catch-up

The SDK keeps a durable cursor. On start it gap-fills over REST from that cursor, dedupes the overlap with the live stream by sequence, and only then goes live — every signal, in order, no matter how long you were offline. Delivery is at-least-once end to end: after a crash the uncommitted tail is redelivered, which is exactly what the state store in the next step is for.

subscribe.py
from multiedge_relay import SignalSubscriber

def handle(signal, meta):
    store(signal)  # live AND caught-up signals, in sequence order

sub = SignalSubscriber(api_key="mesk_...",
                       strategy_id="str_dm_rotation",
                       on_signal=handle)
sub.run()  # resumes from the persisted cursor, gap-fills, then goes live

4 · Process exactly once

SqliteStateStore records which signal_ids your handler has completed in one local SQLite file, and commits that marker atomically with your handler's success — so crash redelivery, reconnect overlap, webhook retries, and operator replays never run it twice. State you write through the store's transaction is exactly-once; external side effects keep only a microscopic redelivery window. The file prunes and vacuums itself, staying tiny.

subscribe_exactly_once.py
from multiedge_relay import SignalSubscriber, SqliteStateStore

store = SqliteStateStore()  # ~/.multiedge/state.db — stdlib sqlite3, no extra deps

sub = SignalSubscriber(api_key="mesk_...",
                       strategy_id="str_dm_rotation",
                       on_signal=store.exactly_once(handle),  # once per signal_id
                       cursor_store=store)                    # cursor + dedup, one file
sub.run()  # crash, restart, replay — your handler never runs twice for one signal

5 · Verify webhook signatures

Every webhook delivery is signed HMAC-SHA256 over "{unix_ts}." + raw body bytes with your per-endpoint secret. Verify over the raw received bytes — never re-serialize. The relay retries non-2xx deliveries up the ladder, so dedupe on signal_id — the same state store from step 4 does it in one line.

webhook.py
from multiedge_relay import verify_signature

@app.post("/webhooks/multiedge")
async def receive(request: Request):
    body = await request.body()  # RAW bytes — never re-parse before verifying
    signal = verify_signature(body, dict(request.headers), WEBHOOK_SECRET)
    # HMAC-SHA256 over "{ts}." + body; constant-time compare; 5-min freshness
    with store.process(signal) as fresh:  # same SqliteStateStore dedups retries
        if fresh:
            handle(signal)
    return {"ok": True}  # ACK duplicates too, so the retry ladder stops

The full walkthrough — producer and consumer, line by line

Complete portfolios, HOLD for unchanged tickers, heartbeats, corrections with the :r2 convention, failure handling, and a safe apply loop — every sample validated against the relay's own schema.

Python walkthrough

From signal to broker — live execution at IBKR

The relay hands you the target book; your code owns execution. Build your own execution layer at Interactive Brokers with ib_async — exactly-once processing, idempotent rebalance-to-target, paper-first, hard guardrails — in about eighty lines of Python.

IBKR execution walkthrough

Sealed mode — end-to-end encryption

Per-strategy E2E encryption with post-quantum hybrid cryptography: the relay stores and forwards ciphertext it cannot read. Threat model, wire format, and full setup.

Sealed mode guide

API reference

The full REST surface — publish, catch-up, deliveries, replay, endpoints, entitlements — as interactive OpenAPI 3.1.

Open the reference