# Candles

Read and stream public spot OHLCV candles via market_data.

`client.market_data` reads and streams public spot OHLCV data. No authentication is required. There is no `client.candles` alias; use `market_data`.

The service calls this value `interval` in convenience methods and `timeframe` in `GetCandlesOpts`; they represent the same candle duration. Supported aliases are `1s`, `1m`, `5m`, `15m`, `30m`, `1h`, `4h`, `12h`, `1d`, `1w`, and `1mo`. Forms such as `min1` and `MIN_1` are also accepted.

The current Rust `GetCandlesOpts` does not expose the wire-level `include_reference` field. Do not rely on requesting reference candles through this SDK version.

OHLCV fields are decimal strings. Candle times are epoch **seconds** (`ts_sec`). Row results are ordered **newest-first**. When requested, the open/incomplete candle is prepended at index `0`; never use `.last()` as the latest candle. Reverse or sort row results by `ts_sec` before feeding them to chronological indicators. The columns API is **oldest-first**.

## Methods

| Method                | Summary                                                        |
| --------------------- | -------------------------------------------------------------- |
| `get_candles`         | Fetch candles (`symbol`, `interval`, `limit`).                 |
| `get_candles_with`    | Full options (`GetCandlesOpts`).                               |
| `get_candles_columns` | Columnar wire form decoded to rows.                            |
| `get_current_candle`  | Latest candle as `Option<Candle>` (`None` when no rows exist). |
| `subscribe_candles`   | Stream live row candles (`recv_result()`).                     |

### Get candles

```rust
use polyester::models::GetCandlesOpts;

let result = client
    .market_data
    .get_candles("BTC-USDT", "1h", Some(200))
    .await?;
if let Some(latest) = result.candles.first() {
    println!("{} {} {}", latest.ts_sec, latest.close, latest.volume);
}

let mut chronological = result.candles.clone();
chronological.reverse();
// Feed chronological (oldest-first) to rolling indicators.

let ranged = client
    .market_data
    .get_candles_with(GetCandlesOpts {
        symbol: Some("BTC-USDT".into()),
        timeframe: "1h".into(),
        limit: Some(200),
        include_incomplete: false,
        ..Default::default()
    })
    .await?;
```

### Get candle columns

Same `GetCandlesOpts`; columnar response decoded into `CandlesResult` rows. The SDK verifies that every OHLCV column has exactly one value per timestamp and returns `Error::Transport` if the response is misaligned.

### Get current candle

```rust
let candle: Option<_> = client.market_data.get_current_candle("BTC-USDT", "1m").await?;
```

### Subscribe candles

Requires hydrated catalogs so `symbol` resolves to an id.

```rust
client.wait_for_catalogs().await?;
let mut sub = client.market_data.subscribe_candles("BTC-USDT", "1m").await?;
while let Some(candle) = sub.recv_result().await? {
    println!("{} {} {}", candle.ts_sec, candle.timeframe, candle.close);
    break;
}
```

`Candle` does not expose an `is_closed` field. Treat streamed candles as updates for their `ts_sec` and `timeframe` bucket; a later update for the same bucket supersedes the earlier value.

## Related

- [Market data guide](https://testnet.polyester.com/docs/sdk/rust/guides/market-data)
- [Streaming](https://testnet.polyester.com/docs/sdk/rust/guides/streaming)
- [Order book](https://testnet.polyester.com/docs/sdk/rust/reference/order-book)
- [Public trades](https://testnet.polyester.com/docs/sdk/rust/reference/public-trades)
