TaifoonTAIFOON
Taifoon · Docs
Customer integration

AlgoTrada Cubicle Trader

AlgoTrada Cubicle is a quantitative algo client built on top of the Taifoon CLOB venue. It runs a proprietary signal generation pipeline in Rust, reads market candles via the venue's public tape, and dispatches orders through POST /book/v1/orders like any other API client. This page documents the integration shape — useful as a reference for other algorithmic clients wiring into the venue.
Note
AlgoTrada is a third-party customer of the venue. Its internal decision model is proprietary and is described here abstractly — the integration surface is the public CLOB API and nothing else. Treat this page like a wiring diagram for any quant client connecting to Taifoon.

Wire shape

Two processes, one direction of traffic. The client owns its decision model and its own infrastructure; the venue owns the matcher, the tape, and the receipt log.

  AlgoTrada Cubicle (private)         Taifoon CLOB (public venue)
  ┌──────────────────────┐            ┌──────────────────────┐
  │  Rust decision model │  reads     │  /tape/v1/candles    │
  │  (internal)          │ ─────────► │  /tape/v1/sessions   │
  │                      │            │                      │
  │  Decision: BUY/SELL  │  posts     │  /book/v1/orders     │
  │                      │ ─────────► │  /book/v1/fills      │
  │                      │  monitors  │  /tape/v1/sessions   │
  │                      │ ─────────► │  ../replay/receipt   │
  └──────────────────────┘            └──────────────────────┘

1. Reading the tape

The client polls GET /tape/v1/candles for the markets it follows. The response shape is identical in live and warp modes — the mode, speed_x, and t_logicaltriple on each row is how the consumer disambiguates them.

// Pull 1m candles for a given window
#[derive(serde::Deserialize)]
struct Candle { t: i64, o: f64, h: f64, l: f64, c: f64, v: f64 }

#[derive(serde::Deserialize)]
struct CandlesResponse { candles: Vec<Candle> }

let resp: CandlesResponse = reqwest::Client::new()
    .get(format!("https://api.taifoon.dev/tape/v1/candles/{market}/1m"))
    .query(&[("from", from_unix), ("to", to_unix)])
    .send().await?
    .json().await?;

No authentication is required on Phase A. The client uses a stable attribution string when it later posts orders; reads are open.

2. Decision step (abstract)

The client runs its internal strategy on each new candle. The strategy is proprietary and produces aDecision { side, qty, attribution }. From the venue's point of view this is a black box — the matcher only sees the orders it emits.

/// Trait implemented by the client's proprietary strategy.
/// Returns Some(Decision) when the strategy wants to act on this candle,
/// None otherwise.
pub trait Strategy {
    fn decide(&self, candle: &Candle, market: &str) -> Option<Decision>;
}

pub struct Decision {
    pub side: Side,        // Buy | Sell
    pub qty: f64,          // contract qty in base units
    pub attribution: String,
}
The public docs deliberately stop at the trait boundary. The interesting part — how the client decides — lives behind that decide() call and is not part of the venue contract. Any third-party algo client can substitute its own Strategy impl and use the same wire shape below.

3. Posting orders

When decide() returns Some(...), the client POSTs to/book/v1/orders. The attribution string is the only identity the matcher sees — AlgoTrada stamps each order with trader-cubicle-<run_id> so operators can filter the venue log.

#[derive(serde::Serialize)]
struct OrderRequest<'a> {
    market: &'a str,
    side: &'a str,           // "buy" | "sell"
    qty: String,             // decimal string
    price: String,           // decimal string (close of latest candle, for limit IOC)
    tif: &'a str,            // "ioc" | "gtc" | "fok"
    attribution: String,
    #[serde(skip_serializing_if = "Option::is_none")]
    session: Option<String>, // None = live; Some(sid) = warp replay
}

#[derive(serde::Deserialize)]
struct OrderResponse { order_id: String, t_placed: i64, speed_x: f64 }

let body = OrderRequest {
    market,
    side: match decision.side { Side::Buy => "buy", Side::Sell => "sell" },
    qty: format!("{:.8}", decision.qty),
    price: format!("{:.2}", candle.c),
    tif: "ioc",
    attribution: format!("trader-cubicle-{}", run_id),
    session: warp_session_id.clone(), // None for live, Some(sid) for replay
};

let res: OrderResponse = client
    .post("https://api.taifoon.dev/book/v1/orders")
    .json(&body)
    .send().await?
    .json().await?;

4. Warp-replay backtest

Before promoting a build to live, the client backtests it inside a warp session. This is the standard backtest flow for any client — there is no special replay path for AlgoTrada. The samesession_id is then threaded into every order so the matcher routes into the partitioned book.

Mint the session over a historical window:

curl -s -X POST https://api.taifoon.dev/tape/v1/sessions \
  -H 'Content-Type: application/json' \
  -d '{
    "from": "2026-05-01T00:00:00Z",
    "to":   "2026-05-08T00:00:00Z",
    "markets": ["BTC-PERP","ETH-PERP","SOL-PERP"],
    "speed_x": 100.0
  }' | jq

Drive the cursor forward and step the matcher. AlgoTrada points the venue at its own brain endpoint viacubicle_url on the replay-start call; for any other client the same field accepts any HTTP-reachable decision service.

# Begin driving the session; the venue calls back into the client's
# decision service once per logical tick.
curl -s -X POST https://api.taifoon.dev/tape/v1/sessions/<sid>/replay/start \
  -H 'Content-Type: application/json' \
  -d '{
    "cubicle_url": "https://brain.algotrada.ai/decide",
    "attribution": "trader-cubicle-r4271"
  }' | jq

# Poll the causality receipt at any time during or after the run.
curl -s https://api.taifoon.dev/tape/v1/sessions/<sid>/replay/receipt | jq

The receipt is the 3-actor schema documented at /clob/docs/concepts/receipt:decider (the client's prompt + response per tick), matcher (the order / fill stream), trader (the attribution string). The top-level causality_ok bit must be true for the run to be considered usable.

5. Fills and outcomes

After (or during) a session, the client retrieves its fills via GET /book/v1/fills. Thesession query param scopes results to a single warp run; omit it for live fills.

# All fills attributable to this run, in t_placed order.
curl -s 'https://api.taifoon.dev/book/v1/fills?session=<sid>&attribution=trader-cubicle-r4271' | jq

# Live fills (no session) for the same client identity.
curl -s 'https://api.taifoon.dev/book/v1/fills?attribution=trader-cubicle-r4271&limit=200' | jq

Each fill row carries order_id, price, qty,t_filled, the counterparty attribution, and (during a warp) the same(mode, speed_x, t_logical) triple as the candles. The client computes its own outcomes from this stream; the venue does not score strategies.

Operator notes

  • Infrastructure. AlgoTrada runs the Cubicle client on its own infrastructure. The venue does not host the strategy process — it only sees the HTTP traffic.
  • Attribution prefix. Orders show up in venue logs underattribution=trader-cubicle-<run_id>. The trader- prefix buckets the identity into the Directional Trader bracket on the public leaderboard.
  • Counterparty.Public market makers provide liquidity in live mode. In warp replay, the venue's synthetic warp-MM quotes both sides of the seeded book — see/clob/docs/operators/market-maker for the contract.
  • Balance.The client carries its own balance on-chain when on-chain settlement ships; until then, all paper P&L is tracked off-venue by the client and reconciled against the receipt.
  • Promotion gate. Same gate as any other client: 24h paper WR ≥ 85% onn_resolved ≥ 30 before live attribution is unlocked.

Code repo

AlgoTrada team: algotrada.ai. Implementation source is private and available to authorized partners only. The integration shape on this page is the contract any third-party algo client can implement against the same public endpoints.

Note
For a fully public, copy-pasteable reference client, see /clob/docs/quickstart/bot and/clob/docs/concepts/cubicle. The endpoints and attribution mechanics are identical.