# K 线与指标

## 创建固定长度窗口

```python
bars = api.watch_kline(symbol, "1m", data_length=200)
```

仅支持期货。周期只能是 `"1m"`、`"5m"`、`"10m"`、`"15m"`、`"30m"`、`"1h"`、`"4h"`、`"1d"`。长度为 1–10000 的整数，默认 200；`True` 不算有效长度。

创建时同步初始化历史窗口，初始化可能等待网络；初始化整体上限为 180 秒。相同合约、周期、长度复用同一句柄，不同长度返回不同句柄。期权没有 K 线能力，误传期权可能得到空数据。

## DataFrame 结构

固定列为 `timestamp`、`trading_day`、`open`、`high`、`low`、`close`、`volume`、`turnover`、`open_interest`。

`timestamp` 表示周期结束的 Unix 毫秒，日线使用交易日北京时间零点。最后一行可能仍在形成。不要将日线时间戳解释为交易所收盘瞬间。

```python
frame = bars.data()
print(frame.attrs["symbol"], frame.attrs["period"])
if not frame.empty:
    print(frame.iloc[-1].to_dict())
```

## 计算移动平均

```python
import math

bars = api.watch_kline(symbol, "1m", data_length=200)
while api.wait_update():
    if bars.is_changing(["timestamp", "close"]):
        frame = bars.data()
        if len(frame) >= 20:
            frame["ma20"] = frame["close"].rolling(20).mean()
            latest = frame["ma20"].iloc[-1]
            if math.isfinite(latest):
                print("当前末行 MA20", latest)
```

指标添加在当前快照，不会进入 SDK 的下一份快照。需要每次重新计算或由业务层维护指标状态。`rolling(20)` 数据不足时产生 NaN，程序需要检查。

## 监测窗口推进

`bars.is_changing("timestamp")` 可检测时间列变化；`bars.is_changing("close")` 可检测价格变化。同一周期的末行可多次变化。面向已完成 K 线的策略必须额外建立完成判定和去重规则，不能把每次收盘价变化都当成新周期。
