## 限售解禁（Lockup Expiry / Restricted-Share Unlock）

工具：`get_lockup_expiry`（`src.tools.lockup_expiry_tool.LockupExpiryTool`）
描述：A 股限售股在排定日期解禁；大额临近解禁会因新增可流通供给压制股价。工具返回个股的全历史解禁表，或全市场未来窗口（默认 90 日）的解禁日历。
市场：A 股。
限速：经共享 `eastmoney` per-host 节流层；东财按源 IP 限流。

<br>

**端点**

`https://datacenter-web.eastmoney.com/api/data/v1/get`，reportName = `RPT_LIFT_STOCK`。

<br>

**输入参数（工具入参）**

名称 | 类型 | 必选 | 描述
---- | ---- | ---- | ----
code | str | N | A 股 6 位代码，可带后缀（`600519` / `600519.SH` / `000001.SZ`）。给定 → 该股全历史解禁表；省略 → 全市场未来 N 日解禁日历。
horizon_days | int | N | 全市场日历的未来窗口天数，clamp 至 [1, 365]，默认 90。给定 code 时忽略（返回全历史）。

注：该工具 `repeatable = True`。

<br>

**端点查询参数**

名称 | 取值 | 描述
---- | ---- | ----
reportName | `RPT_LIFT_STOCK` | 报表名
columns | `SECURITY_CODE,SECURITY_NAME_ABBR,FREE_DATE,FREE_SHARES_TYPE,FREE_SHARES,CURRENT_FREE_SHARES,ABLE_FREE_SHARES,LIFT_MARKET_CAP,FREE_RATIO,TOTAL_RATIO` | 请求列
filter | 个股=`(SECURITY_CODE="<code>")`；全市场=`(FREE_DATE>='start')(FREE_DATE<='end')` | 过滤谓词
sortColumns / sortTypes | `FREE_DATE` / 个股 `-1`（最新在前）、全市场 `1`（最近解禁在前） | 排序
pageNumber / pageSize | `1` / `200` | 分页
source / client | `WEB` / `WEB` | 来源标识

<br>

**返回字段**（源字段 → 输出键）

源字段 | 输出键 | 类型 | 描述
---- | ---- | ---- | ----
SECURITY_CODE | code | str | 代码
SECURITY_NAME_ABBR | name | str | 简称
FREE_DATE | free_date | str | 解禁日（取 `YYYY-MM-DD`）
FREE_SHARES_TYPE | share_type | str | 解禁股份类型
FREE_SHARES | free_shares | float | 解禁股数
ABLE_FREE_SHARES | able_free_shares | float | 实际可流通股数
LIFT_MARKET_CAP | lift_market_cap | float | 解禁市值
FREE_RATIO | free_ratio | float | 占流通股比
TOTAL_RATIO | total_ratio | float | 占总股本比

无 code 或 free_date 的行被丢弃；记录上限 200。信封：`{"ok": true, "market": "a_share", "source": "eastmoney", "data": {"scope": "single_code"|"market_calendar", "count", "records":[...], ("code") | ("horizon_days","as_of"), ("truncated")}}`。

<br>

**调用范例**

```python
from src.tools.lockup_expiry_tool import LockupExpiryTool

# 个股全历史解禁
print(LockupExpiryTool().execute(code="600519.SH"))
# 全市场未来 30 日解禁日历
print(LockupExpiryTool().execute(horizon_days=30))
```
