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

# 量化分析

> 技术指标、因子计算、行情数据和回测功能

# Quant Module

`quant` 模块提供量化分析工具，包括技术指标计算、因子分析、OHLCV 行情数据和策略回测。

公式语法基于 Mai-language，兼容通达信/同花顺。

## 快速开始

```python theme={null}
from reportify_sdk import Reportify

client = Reportify(api_key="your-api-key")

# 计算 RSI 指标
df = client.quant.factors_compute(["000001"], "RSI(14)")

# 因子选股
stocks = client.quant.factors_screen(formula="RSI(14) < 30")

# 获取 OHLCV 数据
ohlcv = client.quant.ohlcv("000001")

# 策略回测
result = client.quant.backtest(
    start_date="2023-01-01",
    end_date="2024-01-01",
    symbols=["000001"],
    entry_formula="CROSS(MA(CLOSE, 5), MA(CLOSE, 20))",
)
```

***

## 因子 (Factors)

### factors()

获取可用因子列表（变量和函数）。

```python theme={null}
factors = client.quant.factors()

for f in factors:
    print(f"{f['name']} ({f['type']}, level {f['level']}): {f['description']}")
```

**因子分级：**

* **Level 0 变量**: CLOSE, OPEN, HIGH, LOW, VOLUME, AMOUNT 及别名
* **Level 0 函数**: MA, EMA, REF, HHV, LLV, STD 等核心函数
* **Level 1 函数**: CROSS, COUNT, EVERY 等应用函数
* **Level 2 函数**: MACD, KDJ, RSI, BOLL 等技术指标

***

### factors\_compute()

计算因子值，使用 Mai-language 语法。

```python theme={null}
df = client.quant.factors_compute(
    symbols=["000001"],
    formula="RSI(14)",
    market="cn",
    start_date="2024-01-01",
    end_date="2024-06-01"
)
```

**公式示例：**

```python theme={null}
# 简单指标
df = client.quant.factors_compute(["000001"], "RSI(14)")

# 获取 MACD 的 DIF 线
df = client.quant.factors_compute(["000001"], "MACD().dif")

# 收盘价是否高于 20 日均线（布尔值）
df = client.quant.factors_compute(["000001"], "CLOSE > MA(CLOSE, 20)")

# MA20 偏离度（百分比）
df = client.quant.factors_compute(["000001"], "(CLOSE - MA(CLOSE, 20)) / MA(CLOSE, 20) * 100")

# 复合条件
df = client.quant.factors_compute(["000001"], "(CLOSE > MA(CLOSE, 20)) & (MA(CLOSE, 20) > MA(CLOSE, 60))")
```

**支持的运算符：**

| 类型  | 运算符                              | 说明     |
| --- | -------------------------------- | ------ |
| 比较  | `>`, `<`, `>=`, `<=`, `==`, `!=` | 比较运算   |
| 逻辑与 | `&` 或 `AND`                      | 大小写不敏感 |
| 逻辑或 | `\|` 或 `OR`                      | 大小写不敏感 |
| 逻辑非 | `~` 或 `NOT`                      | 大小写不敏感 |
| 算术  | `+`, `-`, `*`, `/`               | 四则运算   |

**支持的变量：**

| 变量             | 别名         | 说明                                 |
| -------------- | ---------- | ---------------------------------- |
| `CLOSE`        | `C`        | 收盘价                                |
| `OPEN`         | `O`        | 开盘价                                |
| `HIGH`         | `H`        | 最高价                                |
| `LOW`          | `L`        | 最低价                                |
| `VOLUME`       | `V`, `VOL` | 成交量                                |
| `AMOUNT`       | -          | 成交额                                |
| `LISTING_DATE` | -          | 上市日期（`YYYY-MM-DD` 字符串，可直接与日期字符串比较） |
| `ISSUE_PRICE`  | -          | IPO 发行价                            |

**市场状态函数：**

| 函数                   | 说明                  |
| -------------------- | ------------------- |
| `IS_LIMIT_UP()`      | 是否一字涨停（一字板封涨停）      |
| `IS_LIMIT_DOWN()`    | 是否一字跌停（一字板封跌停）      |
| `IS_ST()`            | 是否为 ST 股票           |
| `IS_CHAIN_MAIN()`    | 是否为中国主板股票（60/000开头） |
| `IS_CHAIN_STAR()`    | 是否为科创板股票（68开头）      |
| `IS_CHAIN_CHINEXT()` | 是否为创业板股票（30开头）      |

***

### factors\_screen()

因子选股，筛选满足条件的股票。

```python theme={null}
stocks = client.quant.factors_screen(
    formula="RSI(14) < 30",
    market="cn",              # 可选
    check_date="2024-06-01",  # 可选，默认最新交易日
    symbols=None              # 可选，None 表示当前市场
)
```

**参数：**

| 参数           | 类型          | 必填 | 说明              |
| ------------ | ----------- | -- | --------------- |
| `formula`    | `str`       | 是  | 选股公式            |
| `market`     | `str`       | 否  | 市场，默认 cn        |
| `check_date` | `str`       | 否  | 检查日期，默认最新交易日    |
| `symbols`    | `list[str]` | 否  | 股票池，None 表示当前市场 |

**选股示例：**

```python theme={null}
# RSI 超卖
stocks = client.quant.factors_screen(formula="RSI(14) < 30")

# 金叉
stocks = client.quant.factors_screen(formula="CROSS(MA(CLOSE, 5), MA(CLOSE, 10))")

# 上升趋势
stocks = client.quant.factors_screen(formula="(CLOSE > MA(CLOSE, 20)) & (MA(CLOSE, 20) > MA(CLOSE, 60))")

# 突破布林带上轨
stocks = client.quant.factors_screen(formula="CLOSE > BOLL(20, 2).upper")

# 行业筛选（申万行业）
stocks = client.quant.factors_screen(formula='INDUSTRY("银行") & (PE_TTM() < 10)')

# 在指定股票池中筛选
stocks = client.quant.factors_screen(
    formula="RSI(14) < 30",
    symbols=["000001", "600519", "000002"]
)
```

***

## 行情 (Quotes)

### ohlcv()

获取单个股票的 OHLCV 日线数据。

```python theme={null}
df = client.quant.ohlcv(
    symbol="000001",
    market="cn",
    start_date="2024-01-01",
    end_date="2024-06-01"
)

print(df[["date", "open", "high", "low", "close", "volume"]])
```

**参数：**

| 参数           | 类型    | 必填 | 说明                                                                                                                  |
| ------------ | ----- | -- | ------------------------------------------------------------------------------------------------------------------- |
| `symbol`     | `str` | 是  | 股票代码                                                                                                                |
| `market`     | `str` | 否  | 市场，默认 cn，可选 `cn`/`hk`/`us`/`global`。获取指数行情（`stock_type=index`）时，除 A 股（`cn`）、港股（`hk`）、美股（`us`）外，其余指数统一通过 `global` 查询 |
| `start_date` | `str` | 否  | 开始日期，默认 1 个月前                                                                                                       |
| `end_date`   | `str` | 否  | 结束日期，默认今天                                                                                                           |

***

### ohlcv\_batch()

批量获取多个股票的 OHLCV 数据。

```python theme={null}
df = client.quant.ohlcv_batch(
    symbols=["000001", "600519", "000002"],
    market="cn",
    start_date="2024-01-01",
    end_date="2024-06-01"
)

print(df[["symbol", "date", "close", "volume"]])
```

数据按日期（降序）、股票代码排序。

***

### kline()

获取单个股票的 K 线数据，支持多种周期。

```python theme={null}
df = client.quant.kline(
    symbol="000001",
    kline_type="5M",
    start_datetime="2024-01-01 09:30:00",
    end_datetime="2024-01-01 15:00:00",
    market="cn"
)

print(df[["datetime", "open", "high", "low", "close", "volume"]])
```

**参数：**

| 参数               | 类型    | 必填 | 说明                                                           |
| ---------------- | ----- | -- | ------------------------------------------------------------ |
| `symbol`         | `str` | 是  | 股票代码                                                         |
| `kline_type`     | `str` | 否  | K 线类型，默认 `1D`，支持 `1M`/`5M`/`15M`/`30M`/`60M`/`1D`/`1W`/`1MO` |
| `market`         | `str` | 否  | 市场，默认 `cn`                                                   |
| `stock_type`     | `str` | 否  | 品种类型，默认 `stock`，支持 `stock`/`etf`/`index`/`sw`                |
| `start_datetime` | `str` | 否  | 开始时间（YYYY-MM-DD HH:MM:SS），未指定时自动推算                           |
| `end_datetime`   | `str` | 否  | 结束时间（YYYY-MM-DD HH:MM:SS）                                    |

***

### kline\_batch()

批量获取多个股票的 K 线数据。

```python theme={null}
df = client.quant.kline_batch(
    symbols=["000001", "600519", "000002"],
    kline_type="1D",
    market="cn"
)

print(df[["symbol", "datetime", "close", "volume"]])
```

数据按日期（升序）、股票代码排序。

***

### minute()

获取单个股票的分钟数据。

```python theme={null}
df = client.quant.minute(
    symbol="000001",
    start_datetime="2024-01-01 09:30:00",
    end_datetime="2024-01-01 15:00:00",
    market="cn"
)

print(df[["datetime", "open", "high", "low", "close", "volume"]])
```

**参数：**

| 参数               | 类型    | 必填 | 说明                        |
| ---------------- | ----- | -- | ------------------------- |
| `symbol`         | `str` | 是  | 股票代码                      |
| `start_datetime` | `str` | 是  | 开始时间（YYYY-MM-DD HH:MM:SS） |
| `end_datetime`   | `str` | 是  | 结束时间（YYYY-MM-DD HH:MM:SS） |
| `market`         | `str` | 否  | 市场，默认 cn                  |

***

### minute\_batch()

批量获取多个股票的分钟数据。

```python theme={null}
df = client.quant.minute_batch(
    symbols=["000001", "600519", "000002"],
    start_datetime="2024-01-01 09:30:00",
    end_datetime="2024-01-01 15:00:00",
    market="cn"
)

print(df[["symbol", "datetime", "close", "volume"]])
```

数据按日期（升序）、股票代码排序。

***

## 交易日历 (Trading Calendar)

<Note>
  支持的市场：`cn`（A 股，含 `sh`/`sz`/`bj`）、`hk`（港股）、`us`（美股）。`global` 无日历源，传入会抛出错误。
</Note>

### calendar()

获取指定区间内的 A 股交易日列表，返回带 `date` 列的 DataFrame（按日期升序）。

```python theme={null}
df = client.quant.calendar(
    start_date="2026-01-01",
    end_date="2026-01-31"
)

print(df["date"].tolist())
# ['2026-01-05', '2026-01-06', ...]
```

| 参数           | 类型    | 必填 | 描述                                                                     |
| ------------ | ----- | -- | ---------------------------------------------------------------------- |
| `start_date` | `str` | 否  | 开始日期 `YYYY-MM-DD`，默认当年 1 月 1 日                                         |
| `end_date`   | `str` | 否  | 结束日期 `YYYY-MM-DD`，默认当年 12 月 31 日                                       |
| `market`     | `str` | 否  | 市场，默认 `cn`，可选 `cn`/`hk`/`us`                                           |
| `exchange`   | `str` | 否  | 交易所（`cn`: `sh`/`sz`/`bj`，`hk`: `hk`，`us`: `us`），默认市场对应交易所（`cn` 为 `sh`） |

***

### calendar\_check()

判断某一天是否为交易日，并返回上一/下一交易日。

```python theme={null}
info = client.quant.calendar_check("2026-01-01")

print(info["is_trading_day"])        # False
print(info["previous_trading_day"])  # '2025-12-31'
print(info["next_trading_day"])      # '2026-01-05'
```

| 参数         | 类型    | 必填 | 描述                                                                     |
| ---------- | ----- | -- | ---------------------------------------------------------------------- |
| `target`   | `str` | 否  | 待判断日期 `YYYY-MM-DD`，默认今天                                                |
| `market`   | `str` | 否  | 市场，默认 `cn`，可选 `cn`/`hk`/`us`                                           |
| `exchange` | `str` | 否  | 交易所（`cn`: `sh`/`sz`/`bj`，`hk`: `hk`，`us`: `us`），默认市场对应交易所（`cn` 为 `sh`） |

返回字段：`date`、`is_trading_day`、`previous_trading_day`、`next_trading_day`。

***

## 回测 (Backtest)

### backtest()

执行策略回测。

```python theme={null}
result = client.quant.backtest(
    start_date="2023-01-01",
    end_date="2024-01-01",
    symbols=["000001"],
    market="cn",
    entry_formula="CROSS(MA(CLOSE, 5), MA(CLOSE, 20))",  # 买入信号：MA5 上穿 MA20
    exit_formula="CROSSDOWN(MA(CLOSE, 5), MA(CLOSE, 20))",  # 卖出信号（可选）
    initial_cash=100000,  # 初始资金
    commission=0.0003,    # 佣金费率
    position_size=0.2,    # 单个股票最大仓位 20%
    max_positions=5,      # 最大持仓股票数量
    cheat_on_open=False,  # 是否启用 T 日信号当日开盘成交
    auto_close=True,      # 自动平仓
    signal_factors={"rsi": "RSI(14)", "ma20": "MA(CLOSE, 20)"}  # 额外指标（可选）
)
```

**参数：**

| 参数                      | 类型               | 必填 | 默认值    | 说明                                                            |
| ----------------------- | ---------------- | -- | ------ | ------------------------------------------------------------- |
| `start_date`            | `str`            | 是  | -      | 回测开始日期（YYYY-MM-DD）                                            |
| `end_date`              | `str`            | 是  | -      | 回测结束日期（YYYY-MM-DD）                                            |
| `symbols`               | `list[str]`      | 否  | None   | 股票代码列表（不传则需传 filter\_formula）                                 |
| `filter_formula`        | `str`            | 否  | None   | 前置过滤公式                                                        |
| `market`                | `str`            | 否  | cn     | 市场（cn/hk/us）                                                  |
| `entry_formula`         | `str`            | 否  | None   | 买入/开仓公式（不传则需传 strategy\_code）                                 |
| `strategy_code`         | `str`            | 否  | None   | 自定义回测策略 Python 源码代码。代码中必须定义 `handle_data(context, datas)` 函数。 |
| `exit_formula`          | `str`            | 否  | None   | 卖出/平仓公式（结果 > 0 触发卖出）                                          |
| `initial_cash`          | `float`          | 否  | 100000 | 初始资金（元）                                                       |
| `commission`            | `float`          | 否  | 0      | 佣金费率（如 0.0003 表示万三）                                           |
| `buy_commission`        | `float`          | 否  | 0      | 买入手续费率（优先于 commission）                                        |
| `sell_commission`       | `float`          | 否  | 0      | 卖出手续费率（优先于 commission）                                        |
| `min_commission_amount` | `float`          | 否  | 0      | 单笔最低手续费金额（元）                                                  |
| `slippage`              | `float`          | 否  | 0      | 滑点比例（买入价上浮、卖出价下浮）                                             |
| `position_size`         | `float \| None`  | 否  | None   | 单只股票最大仓位比例（None = 不限制）                                        |
| `max_positions`         | `int \| None`    | 否  | None   | 最大持仓股票数量（None = 不限制）                                          |
| `min_volume`            | `int`            | 否  | 100    | 最小买入股数                                                        |
| `auto_close`            | `bool`           | 否  | True   | 是否在回测结束时自动平仓                                                  |
| `cheat_on_open`         | `bool`           | 否  | False  | 是否在 T 日信号生成后的 T 日开盘执行（False = T+1 开盘执行）                       |
| `signal_factors`        | `dict[str, str]` | 否  | None   | 预计算因子字典，用于 `strategy_code` 模式                                 |

**返回结果：**

```python theme={null}
{
    "success": True,
    "initial_cash": 100000,
    "final_cash": 115000,
    "total_return": 15000,
    "total_return_pct": 0.15,
    "max_drawdown": 0.08,
    "profit_factor": 1.5,
    "win_rate": 0.6,
    "total_trades": 10,
    "winning_trades": 6,
    "losing_trades": 4,
    "trades": [...],
    "portfolio_value": {...},
    "benchmark_value": {...},
    "benchmark_return_pct": 0.12,
    "sharpe_ratio": 1.18,
    "alpha": 0.04,
    "beta": 0.92,
    "max_drawdown_start": "2023-08-15",
    "max_drawdown_end": "2023-10-23",
    "daily_returns": {...},
    "drawdown_series": {...},
    "error_msg": None
}
```

**使用示例：**

```python theme={null}
# 1. 简单金叉策略（只有买入信号）
result = client.quant.backtest(
    start_date="2023-01-01",
    end_date="2024-01-01",
    symbols=["000001"],
    entry_formula="CROSS(MA(CLOSE, 5), MA(CLOSE, 20))"
)

print(f"总收益: {result['total_return']:.2f}")
print(f"收益率: {result['total_return_pct']:.2%}")
print(f"最大回撤: {result['max_drawdown']:.2%}")
print(f"胜率: {result['win_rate']:.2%}")
print(f"盈亏比: {result['profit_factor']:.2f}")
print(f"交易次数: {result['total_trades']}")

# 2. 买入和卖出信号都指定
result = client.quant.backtest(
    start_date="2023-01-01",
    end_date="2024-01-01",
    symbols=["000001"],
    entry_formula="CROSS(MA(CLOSE, 5), MA(CLOSE, 20))",      # 金叉买入
    exit_formula="CROSSDOWN(MA(CLOSE, 5), MA(CLOSE, 20))"    # 死叉卖出
)

# 3. RSI 超卖超买策略
result = client.quant.backtest(
    start_date="2023-01-01",
    end_date="2024-01-01",
    symbols=["000001"],
    entry_formula="RSI(14) < 30",   # RSI 低于 30 买入
    exit_formula="RSI(14) > 70"     # RSI 高于 70 卖出
)

# 4. 使用 signal_factors 记录额外指标
result_indicator = client.quant.backtest(
    start_date="2023-01-01",
    end_date="2024-01-01",
    symbols=["000001"],
    entry_formula="CROSS(MA(CLOSE, 5), MA(CLOSE, 10))",
    exit_formula="CROSS(MA(CLOSE, 10), MA(CLOSE, 5))",
    signal_factors={
        "ma5": "MA(CLOSE, 5)",
        "ma10": "MA(CLOSE, 10)"
    }
)

# 5. 自定义策略
custom_code = """
def handle_data(context, datas):
    for data in datas:
        symbol = data.name
        position = context.portfolio.get_position(symbol)

        if position is None:
            if data.close > data.open:  # 阳线买入
                context.order_target_percent(symbol, 0.2)
        else:
            if data.close < data.open:  # 阴线卖出
                context.order_target_percent(symbol, 0)
"""

result_custom = client.quant.backtest(
    start_date="2023-01-01",
    end_date="2024-01-01",
    symbols=["000001"],
    strategy_code=custom_code
)
```

### backtest\_upload()

上传 Excel 文件进行回测。使用自己的行情数据（而非系统内置数据源）。

```python theme={null}
result = client.quant.backtest_upload(
    file_path="my_stock_data.xlsx",
    start_date="2023-06-01",
    end_date="2024-01-01",
    entry_formula="CROSS(MA(CLOSE, 5), MA(CLOSE, 10))",
    exit_formula="CROSS(MA(CLOSE, 10), MA(CLOSE, 5))",
    initial_cash=100000,
    commission=0.0003
)
```

**参数：**

| 参数                      | 类型               | 必填  | 默认值    | 说明                                          |
| ----------------------- | ---------------- | --- | ------ | ------------------------------------------- |
| `file_path`             | `str`            | 否\* | None   | Excel 文件路径（与 `file_content` 二选一）            |
| `file_content`          | `bytes`          | 否\* | None   | Excel 文件字节内容（与 `file_path` 二选一）             |
| `file_name`             | `str`            | 否   | None   | 文件名（使用 `file_content` 时可指定）                 |
| `start_date`            | `str`            | 否   | None   | 回测开始日期(YYYY-MM-DD)，指标计算后按此过滤                |
| `end_date`              | `str`            | 否   | None   | 回测结束日期(YYYY-MM-DD)，指标计算后按此过滤                |
| `entry_formula`         | `str`            | 否   | None   | 买入/开仓公式（不传则需传 `strategy_code`）              |
| `strategy_code`         | `str`            | 否   | None   | 自定义回测策略 Python 源码                           |
| `exit_formula`          | `str`            | 否   | None   | 卖出/平仓公式                                     |
| `initial_cash`          | `float`          | 否   | 100000 | 初始资金（元）                                     |
| `commission`            | `float`          | 否   | 0      | 佣金费率                                        |
| `buy_commission`        | `float`          | 否   | 0      | 买入手续费率（优先于 commission）                      |
| `sell_commission`       | `float`          | 否   | 0      | 卖出手续费率（优先于 commission）                      |
| `min_commission_amount` | `float`          | 否   | 0      | 单笔最低手续费金额（元）                                |
| `slippage`              | `float`          | 否   | 0      | 滑点比例（买入价上浮、卖出价下浮）                           |
| `position_size`         | `float \| None`  | 否   | None   | 单只股票最大仓位比例。传 `None` 表示不限制                   |
| `max_positions`         | `int \| None`    | 否   | None   | 最大持仓股票数量。传 `None` 表示不限制                     |
| `min_volume`            | `int`            | 否   | 1      | 最小买入股数                                      |
| `auto_close`            | `bool`           | 否   | True   | 是否自动平仓                                      |
| `cheat_on_open`         | `bool`           | 否   | False  | `True` 时 T 日信号在 T 日开盘成交，`False` 时在 T+1 开盘成交 |
| `signal_factors`        | `dict[str, str]` | 否   | None   | 指标与因子字典                                     |

**Excel 文件格式：**

| 列名       | 是否必须   | 说明   |
| -------- | ------ | ---- |
| `date`   | 必须     | 交易日期 |
| `open`   | 必须     | 开盘价  |
| `high`   | 必须     | 最高价  |
| `low`    | 必须     | 最低价  |
| `close`  | 必须     | 收盘价  |
| `symbol` | 多标的时必须 | 股票代码 |
| `volume` | 可选     | 成交量  |
| `amount` | 可选     | 成交额  |

支持中文列名自动映射：

| 中文列名                 | 映射到      |
| -------------------- | -------- |
| 日期 / 时间 / 交易日期 / 交易日 | `date`   |
| 开盘 / 开盘价             | `open`   |
| 最高 / 最高价             | `high`   |
| 最低 / 最低价             | `low`    |
| 收盘 / 收盘价             | `close`  |
| 成交量 / 交易量            | `volume` |
| 成交额 / 交易额            | `amount` |
| 代码 / 股票代码 / 证券代码     | `symbol` |

> 自定义字段列名仍须为 ASCII 字符（英文字母、数字、下划线）。

**使用示例：**

```python theme={null}
# 从文件字节上传
with open("my_data.xlsx", "rb") as f:
    content = f.read()
result = client.quant.backtest_upload(
    file_content=content,
    file_name="my_data.xlsx",
    entry_formula="CROSS(MA(CLOSE, 5), MA(CLOSE, 20))"
)
```

***

## 完整示例

### 技术分析工作流

```python theme={null}
from reportify_sdk import Reportify

client = Reportify(api_key="your-api-key")

# 1. 获取股票数据
df = client.quant.ohlcv("000001", start_date="2024-01-01")

# 2. 计算多个指标
rsi = client.quant.factors_compute(["000001"], "RSI(14)")
macd = client.quant.factors_compute(["000001"], "MACD()")
boll = client.quant.factors_compute(["000001"], "BOLL(20, 2)")

# 3. 合并数据
import pandas as pd
data = df.merge(rsi[["date", "rsi"]], on="date")
data = data.merge(macd[["date", "dif", "dea", "macd"]], on="date")
data = data.merge(boll[["date", "upper", "mid", "lower"]], on="date")

print(data.tail())
```

### 选股并回测

```python theme={null}
# 1. 选股：RSI 超卖
oversold_stocks = client.quant.factors_screen(formula="RSI(14) < 30")
print(f"发现 {len(oversold_stocks)} 只超卖股票")

# 2. 对每只股票进行回测
for stock in oversold_stocks[:5]:  # 取前 5 只
    result = client.quant.backtest(
        start_date="2023-01-01",
        end_date="2024-01-01",
        symbols=[stock["symbol"]],
        entry_formula="CROSS(RSI(14), 30)"  # RSI 上穿 30 买入
    )
    print(f"{stock['symbol']}: 收益率 {result['total_return_pct']:.2%}")
```
