## 笔（BI）
----

笔是缠论的基本走势单元，连接相邻的顶分型和底分型。

### 构成条件

1. **方向**：上升笔（底→顶），下降笔（顶→底）
2. **顶底交替**：相邻两笔的端点分型必须交替（顶-底-顶-底...）
3. **无包含**：两个分型之间不能存在价格区间包含
4. **最小长度**：去包含后的K线数不少于阈值（默认7根）

### 上升笔

```
        ●顶分型
       /
      /
     /
    /
●底分型
```

`fx_a.mark = Mark.D`，`fx_b.mark = Mark.G`，且 `fx_b.fx > fx_a.fx`

### 下降笔

```
●顶分型
    \
     \
      \
       \
        ●底分型
```

`fx_a.mark = Mark.G`，`fx_b.mark = Mark.D`，且 `fx_b.fx < fx_a.fx`

### 关键属性

| 属性 | 说明 |
| --- | --- |
| `direction` | Direction.Up（上升）/ Direction.Down（下降） |
| `high` | 笔的最高价 |
| `low` | 笔的最低价 |
| `length` | 笔包含的去包含K线数 |
| `power_price` | 笔的价格力度（高低差） |
| `slope` | 笔的斜率 |
| `angle` | 笔的角度 |

### czsc 数据结构

```python
@dataclass
class BI:
    symbol: str
    fx_a: FX              # 起点分型
    fx_b: FX              # 终点分型
    fxs: List[FX]         # 经过的所有分型
    direction: Direction   # Up / Down
    bars: List[NewBar]     # 笔内的去包含K线
```

### 使用示例

```python
from czsc import CZSC

c = CZSC(bars)
for bi in c.bi_list[-5:]:
    d = "↑" if bi.direction.value == "Up" else "↓"
    print(f"{d} {bi.fx_a.dt:%m-%d} -> {bi.fx_b.dt:%m-%d}  "
          f"H={bi.high:.0f} L={bi.low:.0f} len={bi.length}")
```
