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

# Crypto Up/Down feed

> Build on Crypto Up/Down markets with historical windows, OHLC price charts, live ticks, and window resolutions.

Polymarket's Crypto Up/Down markets resolve over fixed-length windows: the window's open price is locked when it starts, the close price is locked when it ends, and the market resolves UP if close > open or DOWN otherwise. Struct exposes the resolution data behind these markets through three sources, all keyed off `(symbol, variant, start_time)`:

| Need                                       | Source                                                                                                    |
| ------------------------------------------ | --------------------------------------------------------------------------------------------------------- |
| Past window results (open, close, outcome) | `client.assets.getAssetHistory`                                                                           |
| Historical OHLC price chart for the asset  | `client.assets.getAssetCandlestick`                                                                       |
| Live in-window asset price                 | [`polymarket_asset_prices`](/websockets/rooms/asset-prices) (`asset_price_tick`)                          |
| Window open and close events               | [`polymarket_asset_window_updates`](/websockets/rooms/asset-window-updates) (`asset_price_window_update`) |

Each resolution window carries only two prices: the open locked at `start_time` and the close locked at `end_time`. When you want a full price chart of the underlying asset to render behind the live indicator, use the [asset candlestick endpoint](#charting-the-underlying-price) for OHLC bars at standard resolutions.

## When to use this

* Up/Down market dashboards: a row per (asset, variant) showing the current window's open price, the live spot price, and whether spot is currently above or below open.
* Resolution monitors: react when a window closes and a market resolves.
* Past-outcome leaderboards: "BTC 1h windows over the last 24h, which closed UP vs DOWN".

## How a window resolves

Every Up/Down market is keyed by `(symbol, variant, start_time)`:

* `start_time` and `end_time` are Unix milliseconds, `end_time - start_time` matches the `variant` length.
* At `start_time`, an `update_type: "open"` event fires with `open_price` locked in.
* While the window is live, `asset_price_tick` events for the same `symbol` give you spot.
* At `end_time`, an `update_type: "close"` event fires with `close_price` locked in. The market is now resolved: UP if `close_price > open_price`, DOWN otherwise.

Supported `variant` values across the price-history endpoint and the window-updates room: `5m`, `15m`, `1h`, `4h`, `1d`, `24h`.

## Step 1: backfill past windows

`client.assets.getAssetHistory` returns past resolution windows for a `(symbol, variant)` pair. Each row carries the locked `open_price` and `close_price` for that window, which is what determines the UP / DOWN outcome.

<CodeGroup>
  ```typescript SDK theme={null}
  import { StructClient } from "@structbuild/sdk";

  const client = new StructClient({ apiKey: "sk_live_xxx" });

  const { data: history } = await client.assets.getAssetHistory({
    asset_symbol: "BTC",
    variant: "1h",
  });

  const past = history.map((row) => ({
    start_time: row.start_time,
    end_time: row.end_time,
    open_price: row.open_price,
    close_price: row.close_price,
    outcome: row.close_price > row.open_price ? "UP" : "DOWN",
  }));
  ```

  ```bash cURL theme={null}
  curl "https://api.struct.to/v1/polymarket/asset-history?asset_symbol=BTC&variant=1h" \
    -H "X-API-Key: YOUR_API_KEY"
  ```

  ```python Python theme={null}
  import requests

  history = requests.get(
      "https://api.struct.to/v1/polymarket/asset-history",
      headers={"X-API-Key": "YOUR_API_KEY"},
      params={"asset_symbol": "BTC", "variant": "1h"},
  ).json()["data"]

  past = [
      {**row, "outcome": "UP" if row["close_price"] > row["open_price"] else "DOWN"}
      for row in history
  ]
  ```
</CodeGroup>

## Step 2: subscribe to the live spot price

The asset-prices room pushes sub-second ticks (rate: 0.005 credits per message). Use them to show where the asset is right now relative to the current window's locked `open_price`.

<CodeGroup>
  ```typescript SDK theme={null}
  import { StructWebSocket } from "@structbuild/sdk";

  const ws = new StructWebSocket({ apiKey: "sk_live_xxx" });
  await ws.connect();

  await ws.subscribe("polymarket_asset_prices", {
    asset_symbols: ["BTC", "ETH"],
  });

  ws.on("asset_price_tick", (event) => {
    const { symbol, price, timestamp_ms } = event.data;
    updateSpot(symbol, price, timestamp_ms);
  });
  ```

  ```bash cURL theme={null}
  > {"type":"join_room","payload":{"room_id":"polymarket_asset_prices"}}
  > {"type":"room_message","payload":{"room_id":"polymarket_asset_prices","message":{"action":"subscribe","asset_symbols":["BTC","ETH"]}}}
  ```

  ```python Python theme={null}
  await ws.send(json.dumps({"type": "join_room", "payload": {"room_id": "polymarket_asset_prices"}}))
  await ws.send(json.dumps({
      "type": "room_message",
      "payload": {
          "room_id": "polymarket_asset_prices",
          "message": {"action": "subscribe", "asset_symbols": ["BTC", "ETH"]},
      },
  }))
  ```
</CodeGroup>

Each tick carries `symbol`, `price`, `timestamp_ms`, and `published_at`. Compare `price` against the open of the current window for the asset you're watching to render the live UP / DOWN indicator.

## Step 3: subscribe to window open and close events

Window updates fire twice per resolution window per `(symbol, variant)`: an `open` event when the window starts, a `close` event when it ends. Rate: 0.025 credits per message. At least one of `asset_symbols` or `timeframes` is required.

<CodeGroup>
  ```typescript SDK theme={null}
  await ws.subscribe("polymarket_asset_window_updates", {
    asset_symbols: ["BTC"],
    timeframes: ["1h"],
  });

  ws.on("asset_price_window_update", (event) => {
    const { symbol, variant, start_time, end_time, open_price, close_price, update_type } = event.data;
    if (update_type === "open") {
      openWindow(symbol, variant, start_time, end_time, open_price);
    } else {
      const outcome = close_price > open_price ? "UP" : "DOWN";
      resolveWindow(symbol, variant, start_time, close_price, outcome);
    }
  });
  ```

  ```bash cURL theme={null}
  > {"type":"room_message","payload":{"room_id":"polymarket_asset_window_updates","message":{"action":"subscribe","asset_symbols":["BTC"],"timeframes":["1h"]}}}
  ```

  ```python Python theme={null}
  await ws.send(json.dumps({
      "type": "room_message",
      "payload": {
          "room_id": "polymarket_asset_window_updates",
          "message": {"action": "subscribe", "asset_symbols": ["BTC"], "timeframes": ["1h"]},
      },
  }))
  ```
</CodeGroup>

Merge into a per-window map keyed by `(symbol, variant, start_time)`. The `open` event tells you a new market just kicked off; the `close` event resolves it.

## Charting the underlying price

Window rows give you the open and close only. To draw a full price chart of the underlying asset (the candlestick chart that sits behind the live UP / DOWN indicator), use `client.assets.getAssetCandlestick`. It returns OHLC bars for the asset's spot price at a TradingView-style resolution.

<CodeGroup>
  ```typescript SDK theme={null}
  const { data: candles } = await client.assets.getAssetCandlestick({
    asset_symbol: "BTC",
    resolution: "60",
    count_back: 500,
  });

  const bars = candles.map((bar) => ({
    time: bar.t,
    open: bar.o,
    high: bar.h,
    low: bar.l,
    close: bar.c,
  }));
  ```

  ```bash cURL theme={null}
  curl "https://api.struct.to/v1/polymarket/asset-history/candlestick?asset_symbol=BTC&resolution=60&count_back=500" \
    -H "X-API-Key: YOUR_API_KEY"
  ```

  ```python Python theme={null}
  candles = requests.get(
      "https://api.struct.to/v1/polymarket/asset-history/candlestick",
      headers={"X-API-Key": "YOUR_API_KEY"},
      params={"asset_symbol": "BTC", "resolution": "60", "count_back": 500},
  ).json()["data"]
  ```
</CodeGroup>

Each bar is `{ o, h, l, c, t }`: open, high, low, close, and the bar's start time in Unix milliseconds.

| Parameter        | Description                                                                                                                  |
| ---------------- | ---------------------------------------------------------------------------------------------------------------------------- |
| `asset_symbol`   | One of `BTC`, `ETH`, `XRP`, `SOL`, `DOGE`, `BNB`, `HYPE`                                                                     |
| `resolution`     | Candle interval in TradingView naming: `1S` (1 second), `1`, `5`, `15`, `30`, `60` (minutes), `240` (4h), `D` / `1D` (daily) |
| `count_back`     | Number of candles to return, newest first (max 2500)                                                                         |
| `from` / `to`    | Optional Unix millisecond range to bound the window                                                                          |
| `pagination_key` | Cursor from a previous response to page further back                                                                         |

Pair the historical candles with the live [`asset_price_tick`](/websockets/rooms/asset-prices) stream: load the chart from this endpoint on mount, then extend the most recent bar as ticks arrive.

## Putting it together

```typescript theme={null}
type Window = {
  symbol: string;
  variant: string;
  start_time: number;
  end_time: number;
  open_price: number;
  close_price: number | null;
  outcome: "UP" | "DOWN" | null;
};

const windows = new Map<string, Window>();
const spot = new Map<string, number>();

const key = (s: string, v: string, t: number) => `${s}:${v}:${t}`;

const past = await client.assets.getAssetHistory({ asset_symbol: "BTC", variant: "1h" });
for (const row of past.data) {
  windows.set(key("BTC", "1h", row.start_time), {
    symbol: "BTC",
    variant: "1h",
    start_time: row.start_time,
    end_time: row.end_time,
    open_price: row.open_price,
    close_price: row.close_price,
    outcome: row.close_price > row.open_price ? "UP" : "DOWN",
  });
}

ws.on("asset_price_tick", (event) => {
  spot.set(event.data.symbol, event.data.price);
  renderLiveIndicator(event.data.symbol);
});

ws.on("asset_price_window_update", (event) => {
  const { symbol, variant, start_time, end_time, open_price, close_price, update_type } = event.data;
  const k = key(symbol, variant, start_time);
  if (update_type === "open") {
    windows.set(k, { symbol, variant, start_time, end_time, open_price, close_price: null, outcome: null });
  } else {
    const outcome = close_price > open_price ? "UP" : "DOWN";
    windows.set(k, { symbol, variant, start_time, end_time, open_price, close_price, outcome });
  }
  renderWindows();
});
```

The live indicator for the current window is `spot.get(symbol)` compared against `windows.get(currentKey).open_price`.

## Common combinations

| Goal                                        | Subscribe payload                                                                         |
| ------------------------------------------- | ----------------------------------------------------------------------------------------- |
| Multi-timeframe Up/Down board for one asset | `polymarket_asset_window_updates`, `asset_symbols=["BTC"]`, `timeframes=["5m","1h","1d"]` |
| All assets on one timeframe                 | `polymarket_asset_window_updates`, `timeframes=["1h"]` (no `asset_symbols`)               |
| Live spot for every tracked asset           | `polymarket_asset_prices` with no `asset_symbols`                                         |
| Backfill long-window outcomes               | `getAssetHistory({ asset_symbol: "ETH", variant: "1d" })`                                 |
| OHLC price chart for an asset               | `getAssetCandlestick({ asset_symbol: "BTC", resolution: "60", count_back: 500 })`         |

## Follow-on

For threshold-based alerts on these resolutions (price crosses, individual window outcomes), see [`asset-price-tick`](/websockets/alerts/asset-price-tick) and [`asset-price-window-update`](/websockets/alerts/asset-price-window-update) under the alerts websocket.
