> ## 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.

# Your First Strategy

> Build a SMA crossover strategy from scratch with full explanations

## What We're Building

A dual SMA (Simple Moving Average) crossover strategy on Binance futures:

* **Buy** when the fast SMA crosses above the slow SMA (bullish momentum)
* **Sell** when the fast SMA crosses below the slow SMA (bearish momentum)
* Trade BTC and ETH with 3× leverage

This tutorial explains every step in detail. If you want just the code, see the [Quickstart](/quickstart).

## Step 1: Discovery

First, explore what's available:

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

# Check available exchanges
Helper.exchanges()

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

# Check data availability
Helper.data_catalog()
# Shows locally cached data with date ranges

# Check Binance margin parameters
Helper.margin_info("binance")
# → default_mmr: 1.3%, liquidation_fee: 0.75%
```

## Step 2: Symbol-Source Mapping

Define which symbols trade on which exchange. This mapping determines data routing and execution venues:

```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"],
})

# Helper methods for building the graph:
print(symbol_source_map.axis_keys_for("binance:futures"))
# → ['binance:futures:BTC/USDT:USDT', 'binance:futures:ETH/USDT:USDT']

print(symbol_source_map.execution_routing)
# → {'binance:futures:BTC/USDT:USDT': 'binance:futures', ...}
```

**Why `SymbolSourceMap`?** In multi-exchange strategies, you need to know which symbols belong to which exchange — for both data loading and order routing. Even for single-exchange strategies, this explicit mapping prevents configuration errors.

## Step 3: Build the Graph

The graph is a DAG (Directed Acyclic Graph) of operators. Data flows from FIELD inputs (market data) through computation nodes to intentions (trading orders).

### 3a: Imports

```python theme={null}
from clyptq.system.graph import StatefulGraph, Input
from clyptq.apps.trading.operators.indicator import SMA
from clyptq.apps.trading.operators.signal import MomentumAlpha
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
```

### 3b: FIELD Input

Every graph starts with a FIELD input — raw market data from an exchange:

```python theme={null}
graph = StatefulGraph()

# "FIELD:binance:futures:ohlcv:close" means:
#   FIELD: → market data (not portfolio state)
#   binance:futures: → from Binance futures
#   ohlcv: → OHLCV candle data
#   close: → close price field
#
# "1m" → 1-minute timeframe
# lookback=50 → this input needs 50 ticks of history
close = Input("FIELD:binance:futures:ohlcv:close", "1m", lookback=50)
```

### 3c: Indicators

SMA operators compute moving averages from the close price input:

```python theme={null}
# Fast SMA (10-period) — responds quickly to price changes
graph.add_node("sma_fast", SMA(input=close, period=10))

# Slow SMA (50-period) — smooth, captures longer-term trend
graph.add_node("sma_slow", SMA(input=close, period=50))
```

Each operator receives a `TaggedArray` of shape `(lookback, n_symbols)` — in this case, `(50, 2)` for 50 ticks of BTC and ETH close prices. The SMA operator computes the average over the `span` most recent values.

### 3d: Signal

The crossover alpha generates a trading signal when fast SMA crosses slow SMA:

```python theme={null}
graph.add_node("signal", MomentumAlpha(
    input=Input("sma_fast", "1m", lookback=2),
))
```

**Output**: A `TaggedArray` where positive values indicate bullish (fast > slow) and negative values indicate bearish (fast \< slow). The magnitude reflects the strength of the crossover.

### 3e: Transform

Convert the signal into portfolio weights:

```python theme={null}
graph.add_node("weights", EqualWeight(
    input=Input("signal", "1m", lookback=1),
))
```

`EqualWeight` normalizes signals to sum to 1.0 (long-only) or handles long/short allocations. Each symbol gets an equal share of the capital.

### 3f: Portfolio Accounting

Calculate equity (total account value) from STATE data:

```python theme={null}
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"),
))

# Book size: how much capital to allocate for trading
graph.add_node("book", BookSize(
    input=Input("equity", "1m", lookback=1),
    min_book_size=100.0,
))
```

**STATE inputs** (e.g., `STATE:binance:futures:cash`) pull portfolio data from the executor — cash balance, position quantities, entry prices. These are updated after every fill.

### 3g: Intention (Order Generation)

Convert weights into actual trading intentions:

```python theme={null}
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,
))
```

`FuturesTargetPositionIntention` computes the **delta** between current positions and target positions, then generates orders to close the gap. This is target-position trading: you declare where you want to be, not what to buy/sell.

## Step 4: Configure the Spec

```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

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, 6, 30),
    ),
    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,
)
```

**Key parameters explained:**

* `output_nodes=["equity", "signal"]` — Track these nodes for post-analysis with `to_dataframe()`
* `execution_price_source="ohlcv"` — Use OHLCV close price for fill simulation
* `debug=True` — Store all tick results (required for `to_dataframe()`)
* Funding rates are **auto-injected** for futures accounts — no manual configuration needed

## Step 5: Run and Analyze

```python theme={null}
from clyptq.apps.trading.driver import TradingDriver

driver = TradingDriver.from_spec(spec)

# Run all ticks
for result in driver:
    pass

# Analyze
df_equity = driver.to_dataframe("equity")
df_signal = driver.to_dataframe("signal")

# Plot equity curve
df_equity.plot(title="SMA Crossover Equity Curve", figsize=(14, 5))

# Check final state
results = driver.export_results()
print(results["state"])
```

## The Complete Graph

Here's how data flows through the graph we built:

```mermaid theme={null}
%%{init: {'theme': 'base', 'themeVariables': { 'primaryColor': '#1e293b', 'primaryTextColor': '#e2e8f0', 'primaryBorderColor': '#94F1E8', 'lineColor': '#5bb8b0', 'clusterBkg': '#0f172a', 'clusterBorder': '#1e3a3a', 'titleColor': '#94F1E8', 'edgeLabelBackground': 'transparent' }}}%%
flowchart TB
    classDef source fill:#0d3b3b,stroke:#94F1E8,stroke-width:1.5px,color:#e0faf7
    classDef action fill:#172554,stroke:#60a5fa,stroke-width:1.5px,color:#bfdbfe

    FIELD["FIELD:binance:futures<br>:ohlcv:close"]
    FIELD --> sma_fast["sma_fast<br>(SMA, span=10)"]
    FIELD --> sma_slow["sma_slow<br>(SMA, span=50)"]
    sma_fast --> signal["signal<br>(MomentumAlpha)"]
    sma_slow --> signal
    signal --> weights["weights<br>(EqualWeight)"]

    STATE_CASH["STATE:cash"] --> equity["equity<br>(EquityCalculator)"]
    STATE_POS["STATE:pos"] --> equity
    FIELD --> equity
    equity --> book["book<br>(BookSize)"]

    weights --> intention["intention<br>(FuturesTargetPosition<br>Intention)"]
    book --> intention
    FIELD --> intention
    intention --> executor["Executor"]
    executor --> fill["Fill"]
    fill --> state_update["STATE update"]

    class FIELD,STATE_CASH,STATE_POS,state_update source
    class executor,fill action
```

## Next Steps

<CardGroup cols={2}>
  <Card title="Backtest to Live" icon="arrow-right" href="/tutorials/backtest-to-live">
    Submit this strategy and run it in paper or live mode on the platform
  </Card>

  <Card title="Multi-Factor Strategy" icon="layer-group" href="/tutorials/multi-factor">
    Combine multiple alpha signals with risk management
  </Card>

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

  <Card title="Backtesting Accuracy" icon="shield" href="/backtesting/overview">
    Understand cost models, funding, and liquidation
  </Card>
</CardGroup>
