> ## Documentation Index
> Fetch the complete documentation index at: https://docs.clypt.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Builder Guide

> Strategy development and marketplace listing guide for strategy creators

## Overview

This guide walks you through the full Builder workflow: develop a strategy in Jupyter, validate it through backtest → paper → live, and list it on the marketplace.

## Why Build on ClyptQ?

| Benefit                       | What You Get                                                              |
| ----------------------------- | ------------------------------------------------------------------------- |
| **Production Infrastructure** | Data, execution engine, monitoring — ready to use                         |
| **Code Parity**               | Same `StatefulGraph` runs in backtest, paper, and live. No rewrite needed |
| **Python Freedom**            | Use PyTorch, XGBoost, HuggingFace, scipy — any library inside operators   |
| **Monetization**              | List strategies on marketplace — traders pay a one-time purchase price    |
| **Independent Verification**  | Platform verifies your backtest + runs cross-exchange validation          |

## Template Format

When you submit a strategy to the marketplace, your `.py` file is executed inside ClyptQ's validation sandbox. Your code must follow a specific contract for the platform to validate, backtest, and deploy it correctly.

<Note>
  **ML/DL strategies**: Currently, only the `.py` strategy file is submitted — external model files (`.pkl`, `.pt`, `.onnx`) cannot be uploaded. ML/DL workflows that require pre-trained models are supported in the **research environment** (Jupyter notebooks) but cannot yet be deployed to paper/live or listed on the marketplace. A workspace file explorer for model artifact management is planned.
</Note>

### The `main()` function

Every strategy must define a `main()` function that returns a `TradingDriver`. The platform calls this function to run your strategy.

**New format (recommended)** — receives `mode` and `accounts` from the platform:

```python theme={null}
def main(mode, accounts):
    """
    Args:
        mode: "backtest", "paper", or "live" — injected by the platform
        accounts: Dict mapping venue -> {"initial_cash": float}
                  e.g., {"binance:futures": {"initial_cash": 10000.0}}
    Returns:
        TradingDriver instance
    """
    graph = StatefulGraph()
    # ... build graph ...

    spec = TradingSpec(
        data=TradingDataSpec(...),
        strategy=TradingStrategySpec(graph=graph, output_nodes=["equity", "signal"]),
        execution=TradingExecutionSpec(
            accounts=[AccountSpec(
                exchange="binance",
                market_type="futures",
                base_currency="USDT",
                initial_cash=accounts["binance:futures"]["initial_cash"],
            )],
        ),
        mode=mode,   # Injected by the platform: "backtest", "paper", or "live"
        debug=True,
    )

    driver = TradingDriver.from_spec(spec)
    driver.warmup()

    return driver  # MUST return the driver
```

**Old format** — no parameters, uses injected global variables:

```python theme={null}
def main():
    initial_cash = __SANDBOX_INITIAL_CASH__  # Injected by the platform

    # ... build graph and spec ...
    driver = TradingDriver.from_spec(spec)
    driver.warmup()

    return driver  # MUST return the driver
```

<Warning>
  `main()` must contain a `return driver` statement. The platform validates this at submission time — strategies without a return statement will be rejected.
</Warning>

### Required metric operators

For marketplace listing, your graph **must** include three metric operators with **exact node names**. These operators are computed by ClyptQ's internal code — the platform extracts final values from these nodes to display verified metrics to traders.

```python theme={null}
from clyptq.apps.trading.operators.metrics import (
    AccumSharpe,
    AccumMaxDrawdown,
    AccumTotalReturn,
)

# These three are REQUIRED — node names must match exactly
graph.add_node("sharpe", AccumSharpe(
    Input("equity", "1m", lookback=1), timeframe="1m",
))

graph.add_node("max_drawdown", AccumMaxDrawdown(
    Input("equity", "1m", lookback=1),
))

graph.add_node("total_return", AccumTotalReturn(
    Input("equity", "1m", lookback=1),
))
```

| Node Name        | Operator           | What It Computes                               |
| ---------------- | ------------------ | ---------------------------------------------- |
| `"sharpe"`       | `AccumSharpe`      | Incremental Sharpe ratio (Welford's algorithm) |
| `"max_drawdown"` | `AccumMaxDrawdown` | Running peak-to-trough max drawdown            |
| `"total_return"` | `AccumTotalReturn` | Cumulative total return                        |

<Info>
  These metric operators are computed by ClyptQ's internal code, not by user-supplied logic. This is how the platform guarantees that reported metrics are independently verified — builders cannot self-report or manipulate performance numbers.
</Info>

### Required output nodes

Your `TradingStrategySpec.output_nodes` must include `"equity"` at minimum:

```python theme={null}
TradingStrategySpec(
    graph=graph,
    output_nodes=["equity", "signal"],  # "equity" is REQUIRED
)
```

| Node          | Purpose                                            |
| ------------- | -------------------------------------------------- |
| `"equity"`    | Portfolio value over time **(required)**           |
| `"intention"` | Trading signals and target positions (recommended) |
| `"pnl"`       | Profit/loss tracking (recommended)                 |
| `"drawdown"`  | Drawdown curve visualization (recommended)         |

### Configuration parsed from your code

The platform automatically parses the following from your strategy code:

| What              | How It's Detected                                                     | Example                              |
| ----------------- | --------------------------------------------------------------------- | ------------------------------------ |
| **Venues**        | `SymbolSourceMap`, `AccountSpec`, or `"exchange:market_type"` strings | `"binance:futures"`                  |
| **Symbols**       | `SymbolSourceMap` dict values, or `SYMBOLS` variable                  | `["BTC/USDT:USDT", "ETH/USDT:USDT"]` |
| **Timeframe**     | `TIMEFRAME` variable, or `timeframe=` in `OHLCVSpec`/`Input`          | `"4h"`                               |
| **Initial cash**  | `initial_cash=` in `AccountSpec`, or `INITIAL_CASH` variable          | `50_000.0`                           |
| **Base currency** | `base_currency=` in `AccountSpec`                                     | `"USDT"`                             |

<Warning>
  All venues in your `SymbolSourceMap` must have a matching `AccountSpec` with `initial_cash`. Strategies with missing cash configuration will fail validation.
</Warning>

### Injected sandbox variables

During validation, the platform injects these variables into your execution environment:

| Variable                   | Type             | Description                                                            |
| -------------------------- | ---------------- | ---------------------------------------------------------------------- |
| `__SANDBOX_CONFIG__`       | `dict`           | Contains `symbols`, `start`, `end`, `timeframe`, `initial_cash`        |
| `__SANDBOX_INITIAL_CASH__` | `float`          | Target initial cash for validation                                     |
| `__SANDBOX_ACCOUNTS__`     | `dict` or `None` | Multi-venue accounts: `{"binance:futures": {"initial_cash": 10000.0}}` |

During validation, the platform injects the capital level used for testing. Your code should use these values instead of hardcoding initial cash.

### Ephemeral operators

Strategies using ephemeral (semantic) operators — `LLMScorer`, `WebSearchOperator`, `SentimentParser` — are handled differently:

* **Backtesting is skipped entirely** (these operators hit rate limits and produce non-reproducible results for historical data)
* **Paper trading validation only** is performed
* The strategy listing will display a badge indicating it uses AI/semantic operators

### Sandbox security

The platform enforces multiple layers of security during strategy validation to protect the infrastructure and other users. Submitted code is analyzed and executed in an isolated environment with restricted capabilities.

Strategies that attempt to access system resources, network endpoints, or execute arbitrary code outside of the ClyptQ operator framework will be automatically rejected. The platform's validation pipeline is designed to detect and block malicious or abusive patterns at multiple stages — from static analysis through runtime execution.

<Info>
  Focus on writing clean strategy logic using ClyptQ's operator framework. If your code only uses ClyptQ imports, standard data science libraries (numpy, pandas, scipy, sklearn), and standard Python utilities (datetime, math, json, re, collections), it will pass validation without issues.
</Info>

### Template checklist

| Requirement                       | Details                                                 |
| --------------------------------- | ------------------------------------------------------- |
| `main()` function exists          | Defined at top level, returns `TradingDriver`           |
| `main()` returns driver           | Must have explicit `return driver` statement            |
| `"sharpe"` node                   | `graph.add_node("sharpe", AccumSharpe(...))`            |
| `"max_drawdown"` node             | `graph.add_node("max_drawdown", AccumMaxDrawdown(...))` |
| `"total_return"` node             | `graph.add_node("total_return", AccumTotalReturn(...))` |
| `"equity"` in `output_nodes`      | Required for equity curve display                       |
| Symbols defined                   | `SymbolSourceMap` or `SYMBOLS` variable                 |
| `AccountSpec` with `initial_cash` | Required for each venue                                 |
| Timeframe specified               | `TIMEFRAME` variable or `timeframe=` parameter          |

## Development Workflow

```mermaid theme={null}
%%{init: {'theme': 'base', 'themeVariables': { 'primaryColor': '#1e293b', 'primaryTextColor': '#e2e8f0', 'primaryBorderColor': '#94F1E8', 'lineColor': '#5bb8b0', 'clusterBkg': '#0f172a', 'clusterBorder': '#1e3a3a', 'titleColor': '#94F1E8', 'edgeLabelBackground': 'transparent' }}}%%
flowchart LR
    classDef source fill:#0d3b3b,stroke:#94F1E8,stroke-width:1.5px,color:#e0faf7
    classDef action fill:#172554,stroke:#60a5fa,stroke-width:1.5px,color:#bfdbfe
    classDef highlight fill:#134e4a,stroke:#94F1E8,stroke-width:2.5px,color:#94F1E8
    S1["Explore<br><br>Helper.exchanges()<br>Helper.symbols()<br>Helper.data_catalog()"]
    S2["Build Graph<br><br>StatefulGraph<br>Operators<br>FIELD/STATE inputs"]
    S3["Backtest<br><br>mode=backtest<br>(notebook)"]
    S4["Submit<br><br>Dashboard submission<br>→ platform validates"]
    S5["Paper Trade<br><br>mode=paper<br>(dashboard)"]
    S6["Live<br><br>mode=live<br>(dashboard)"]
    S7["Marketplace<br><br>List for traders"]

    S1 --> S2 --> S3 --> S4 --> S5 --> S6 --> S7
    class S2 source
    class S6 action
    class S7 highlight
```

## Step 1: Explore

Use the `Helper` class to discover what's available:

```python theme={null}
from clyptq import Helper

# Available exchanges
Helper.exchanges()

# Futures symbols on Binance
symbols = Helper.symbols("binance", "futures", quote="USDT", limit=20)
# → ['BTC/USDT:USDT', 'ETH/USDT:USDT', 'SOL/USDT:USDT', ...]

# What data is cached locally?
Helper.data_catalog()

# Margin parameters (MMR, liquidation fee)
Helper.margin_info("binance")
# → default_mmr: 1.3%, liquidation_fee: 0.75%
```

## Step 2: Build the Strategy Graph

### Define symbol mapping

```python theme={null}
from clyptq.apps.trading.spec.symbol_source_map import SymbolSourceMap

symbol_source_map = SymbolSourceMap({
    "binance:futures": ["BTC/USDT:USDT", "ETH/USDT:USDT"],
})
```

### Build the graph

```python theme={null}
from clyptq.system.graph import StatefulGraph, Input
from clyptq.apps.trading.operators.indicator import SMA
from clyptq.apps.trading.operators.transform import EqualWeight
from clyptq.apps.trading.operators.balance import EquityCalculator, BookSize
from clyptq.apps.trading.operators.order import FuturesTargetPositionIntention

graph = StatefulGraph()

# FIELD input — raw close prices from Binance futures
close = Input("FIELD:binance:futures:ohlcv:close", "1m", lookback=50)

# Indicators
graph.add_node("sma_fast", SMA(close, period=10))
graph.add_node("sma_slow", SMA(close, period=50))

# Signal — custom operator (user-defined BaseOperator subclass)
# Example: returns +1 when fast > slow, -1 otherwise
graph.add_node("signal", MySignalOperator(
    fast=Input("sma_fast", "1m", lookback=2),
    slow=Input("sma_slow", "1m", lookback=2),
))

# Transform — equal weight allocation
graph.add_node("weights", EqualWeight(),
    inputs=[Input("signal", "1m", lookback=1)])

# Portfolio accounting — uses STATE inputs
graph.add_node("equity", EquityCalculator(
    cash=Input("STATE:binance:futures:cash", "1m", lookback=0),
    positions=Input("STATE:binance:futures:pos_quantity", "1m", lookback=0),
    prices=Input("FIELD:binance:futures:ohlcv:close", "1m", lookback=0),
    entry_prices=Input("STATE:binance:futures:pos_entry_price", "1m", lookback=0),
    axis_keys=symbol_source_map.axis_keys_for("binance:futures"),
))

graph.add_node("book", BookSize(
    Input("equity", "1m", lookback=1), min_book_size=100.0,
))

# Order generation — target position intention
graph.add_node("intention", FuturesTargetPositionIntention(
    weights=Input("weights", "1m", lookback=1),
    book_size=Input("book", "1m", lookback=1),
    positions=Input("STATE:binance:futures:pos_quantity", "1m", lookback=0),
    prices=Input("FIELD:binance:futures:ohlcv:close", "1m", lookback=0),
    axis_keys=symbol_source_map.axis_keys_for("binance:futures"),
    execution_routing=symbol_source_map.execution_routing,
    leverage=3.0,
))
```

**Key concepts:**

* `FIELD:` inputs pull market data from exchanges
* `STATE:` inputs pull portfolio state from the executor (cash, positions, entry prices)
* Each `Input` declares its `lookback` — the number of historical ticks it needs
* The graph handles warmup, buffering, and execution order automatically

See [Your First Strategy](/tutorials/first-strategy) for a step-by-step walkthrough.

## Step 3: Backtest

### Configure and run

```python theme={null}
from datetime import datetime
from clyptq.apps.trading.spec.unified import TradingSpec
from clyptq.apps.trading.spec.unified import TradingDataSpec, TradingStrategySpec
from clyptq.apps.trading.spec.execution import TradingExecutionSpec, AccountSpec
from clyptq.apps.trading.spec.observation.crypto import OHLCVSpec
from clyptq.apps.trading.driver import TradingDriver

spec = TradingSpec(
    data=TradingDataSpec(
        symbol_source_map=symbol_source_map,
        observations=[OHLCVSpec(exchange="binance", market_type="futures", timeframe="1m")],
        start=datetime(2024, 1, 1),
        end=datetime(2024, 12, 31),
    ),
    strategy=TradingStrategySpec(
        graph=graph,
        output_nodes=["equity", "signal"],
    ),
    execution=TradingExecutionSpec(
        accounts=[AccountSpec(
            exchange="binance",
            market_type="futures",
            base_currency="USDT",
            initial_cash=10_000.0,
            max_leverage=3.0,
        )],
        execution_price_source="ohlcv",
    ),
    mode="backtest",
    debug=True,
)

driver = TradingDriver.from_spec(spec)
driver.warmup()

for result in driver:
    pass

# Analyze
df_equity = driver.to_dataframe("equity")
df_signal = driver.to_dataframe("signal")
df_equity.plot(title="Equity Curve", figsize=(14, 5))
```

### Compare with zero-cost backtest

```python theme={null}
from clyptq.apps.trading.spec.execution import CostModelSpec

spec_zero = TradingSpec(
    ...  # same data and strategy
    execution=TradingExecutionSpec(
        accounts=[AccountSpec(
            exchange="binance", market_type="futures", base_currency="USDT", initial_cash=10_000,
            cost_model=CostModelSpec(maker_fee=0, taker_fee=0, slippage_bps=0),
        )],
    ),
    mode="backtest",
)
```

If the gap between zero-cost and real-cost returns is > 50% of gross return, your strategy may have excessive trading costs.

## Step 4: Submit & Paper Trade

After validating your backtest, **submit your strategy to the platform**. Paper and live trading cannot be run from notebook cells — they are managed through the **dashboard**.

1. Submit your strategy via the marketplace submission flow
2. From the dashboard, start a **Paper Trade** run

**What happens internally:**

1. Historical warmup loads past data to fill all RollingBuffers
2. Clock syncs to the next real-time bar boundary
3. Live data arrives via WebSocket
4. Orders are executed with simulated fills (same fill model as backtest)

## Step 5: Live Trading

From the dashboard, switch to **Live** mode and connect your exchange API credentials.

**Safety features built in:**

* **Emergency shutdown**: Stop from the dashboard to close all positions immediately
* **Balance sync**: Detects external changes (manual trades, liquidations, funding)
* **First tick skip**: Skips execution on the first real-time tick to avoid stale signals

## Step 6: Marketplace Listing

### What you submit

Builders submit a **TradingSpec** — not source code. The spec defines the complete strategy (graph, operators, connections, parameters) in a serializable format.

* **Included**: Graph structure, operator types, parameters, input connections, execution configuration
* **Not included**: Source code of custom operators (packaged as compiled modules)

### Verification process

The platform independently verifies your strategy through automated validation: code validation, backtesting, multi-scale backtesting, and venue sampling (cross-exchange validation).

<Card title="Marketplace Validation" icon="shield-check" href="/platform/marketplace">
  Full details on each verification stage, consistency scoring, and how validation works
</Card>

### Listing requirements

* Strategy code passes validation (syntax + security checks)
* Required metric operators present (`sharpe`, `max_drawdown`, `total_return`)
* `main()` function exists and returns `TradingDriver`
* `"equity"` included in `output_nodes`
* All venues have matching `AccountSpec` with `initial_cash`

### Pricing

Set your strategy's price. Traders pay a **one-time purchase fee**, and the platform takes a commission based on your seller tier:

| Seller Tier | Max Listing Price | Builder Revenue Share | Platform Commission |
| ----------- | ----------------- | --------------------- | ------------------- |
| **Free**    | \$99              | 20%                   | 80%                 |
| **Bronze**  | \$299             | 40%                   | 60%                 |
| **Silver**  | \$599             | 60%                   | 40%                 |
| **Gold**    | \$999             | 70%                   | 30%                 |

**Tier progression** (based on total revenue):

* **Bronze**: \$10,000+ total revenue
* **Silver**: \$40,000+ total revenue
* **Gold**: \$70,000+ total revenue

## Best Practices

### Strategy development

* **Keep it simple**: Fewer parameters reduce the risk of overfitting
* **Use universe filters**: Don't trade every symbol. Filter by volume and liquidity
* **Minimize lookback**: Smaller lookback = faster warmup + less memory
* **Test across periods**: Use out-of-sample testing. Don't curve-fit to a single year

### Backtesting

* **Compare zero-cost vs real-cost**: Check the fee impact on your returns
* **Verify with funding costs**: For futures, cumulative funding can erode profits significantly

### Common pitfalls

| Pitfall               | Why It's Dangerous                    | How ClyptQ Prevents It                                       |
| --------------------- | ------------------------------------- | ------------------------------------------------------------ |
| **Lookahead bias**    | Using future data in signals          | RollingBuffer only exposes declared lookback history         |
| **Survivorship bias** | Testing only current listings         | Use point-in-time symbol lists                               |
| **Overfitting**       | Too many parameters                   | Cross-exchange validation catches venue-specific overfitting |
| **Ignoring costs**    | Profitable in theory, not in practice | Auto-injected exchange fees and funding rates                |
| **Ignoring funding**  | Slow bleed on long-hold futures       | Auto-injected funding rate simulation                        |

## Related Pages

<CardGroup cols={2}>
  <Card title="Your First Strategy" icon="graduation-cap" href="/tutorials/first-strategy">
    Step-by-step SMA crossover tutorial with detailed explanations
  </Card>

  <Card title="Backtest to Live" icon="arrow-right" href="/tutorials/backtest-to-live">
    Full deployment lifecycle from backtest through paper to live
  </Card>

  <Card title="Marketplace" icon="store" href="/platform/marketplace">
    How the strategy marketplace verification works
  </Card>

  <Card title="Operator Reference" icon="book" href="/operators/overview">
    Browse all available operators
  </Card>
</CardGroup>
