**一句话结论:**将原始请求清单与成功结果、逐标的错误记录分别对账;只有明确收到某只股票的失败记录,才能把它判为请求失败。结果中缺少某只股票,只能先标记为"未返回",不能直接断定失败。
1. 先区分两种失败
批量行情请求常见的误区,是把一次批量调用看成"要么全部成功,要么全部失败"。实际处理时,至少要区分两层状态:
- **请求级失败:**整次 HTTP 请求失败,例如认证、权限、请求频率或网络问题。此时通常不能依据空结果判断每只股票各自的状态。
- **标的级失败:**批量请求整体有响应,但其中某些股票有明确的错误记录,或其数据无法返回。
这两种状态的处理方式不同。请求级失败需要先处理请求本身;标的级失败才适合从成功股票中逐只分离出来。
2. 为什么"结果里没有"不等于"请求失败"
假设请求了 100 只股票,响应中只看到 97 只。缺少的 3 只可能是请求失败,也可能是其他情况:
- 返回结果没有包含无行情或无数据的标的;
- 请求代码格式错误,或与系统内部代码不一致;
- 返回数据在解析、过滤或写入过程中被丢弃;
- 服务端对部分标的返回了错误,但客户端没有保留错误详情;
- 这次批量请求本身失败,客户端得到的是空结果或不完整结果。
因此,比较请求数量和返回数量只能发现差异,不能单独证明差异的原因。正确做法是保留三份信息:原始请求清单、成功数据、逐标的错误记录。若接口没有提供逐标的状态,就把缺失项标为"未返回/待核查",不要冒然归类为请求失败。
3. 用集合对账分离状态
核心逻辑是把标的代码统一为同一种格式,再比较请求集合、成功集合和明确失败集合:
| 分类 | 判断条件 | 后续处理 |
|---|---|---|
| 成功 | 有成功行情记录,且没有对应的错误记录 | 进入后续计算或存储 |
| 明确失败 | 有该标的的逐项错误记录 | 记录原因,按规则重试或排查 |
| 未返回 | 请求过,但既没有成功记录,也没有逐项错误记录 | 标记待核查,不能直接认定失败 |
| 状态冲突 | 同一标的同时出现在成功结果和错误记录中 | 保留原始响应,检查解析和合并逻辑 |
| 非请求标的 | 返回数据中出现请求清单之外的代码 | 检查标的映射、缓存或数据串线 |
如果请求清单本身有重复标的,也要单独记录。直接转成集合会丢掉重复信息,可能掩盖上游生成请求时的问题。
4. Python 示例:只按明确证据判失败
下面的代码处理的是已经标准化的本地数据 ,不是某个服务商的原始响应格式。success_df 需要包含 symbol 列;item_errors 是由你的 API 适配层整理出的逐标的错误记录。字段名称和转换逻辑由接入代码负责,不能直接假设任何 API 都会返回这种结构。
python
import pandas as pd
def normalize_symbol(value):
if pd.isna(value):
return None
value = str(value).strip().upper()
return value or None
def classify_batch_result(requested_symbols, success_df, item_errors=()):
if 'symbol' not in success_df.columns:
raise ValueError("success_df 必须包含 'symbol' 列")
requested = [normalize_symbol(s) for s in requested_symbols]
requested = [s for s in requested if s]
requested_unique = list(dict.fromkeys(requested))
requested_set = set(requested_unique)
success_symbols = [
normalize_symbol(s)
for s in success_df['symbol'].dropna().tolist()
]
success_symbols = [s for s in success_symbols if s]
success_set = set(success_symbols)
error_symbols = set()
for item in item_errors:
symbol = normalize_symbol(item.get('symbol'))
if symbol:
error_symbols.add(symbol)
rows = []
for symbol in requested_unique:
in_success = symbol in success_set
in_error = symbol in error_symbols
if in_success and in_error:
status = 'conflicting'
elif in_error:
status = 'explicit_failed'
elif in_success:
status = 'success'
else:
status = 'not_returned'
rows.append({'symbol': symbol, 'status': status})
unexpected = sorted((success_set | error_symbols) - requested_set)
duplicate_success = sorted(
symbol for symbol in success_set
if success_symbols.count(symbol) > 1
)
duplicate_requested = sorted(
symbol for symbol in set(requested)
if requested.count(symbol) > 1
)
return {
'status_df': pd.DataFrame(rows),
'unexpected_symbols': unexpected,
'duplicate_success_symbols': duplicate_success,
'duplicate_requested_symbols': duplicate_requested,
}
requested = ['600519.SH', '000001.SZ', 'AAPL.US']
success_df = pd.DataFrame({'symbol': ['600519.SH', 'AAPL.US']})
item_errors = [{'symbol': '000001.SZ', 'reason': '由接入层整理的错误信息'}]
result = classify_batch_result(requested, success_df, item_errors)
print(result['status_df'])
在这个例子中,000001.SZ 会被标记为 explicit_failed,因为接入层提供了它的逐标的错误记录。若删除该错误记录,它就会变成 not_returned,而不是被自动判为失败。
示例中的 reason 只是本地数据结构的说明;代码没有规定服务端错误字段,也没有描述任何 QuantDash API 的原始返回格式。实际集成时,应按当前接口文档解析响应,并在适配层保留服务端明确提供的错误信息。
5. 任务执行时还要保留哪些信息
为了让失败能够复现和定位,建议每次批量任务至少记录:
- **请求清单:**原始代码、标准化代码和请求批次标识。
- **请求级结果:**HTTP 状态、异常类型、请求时间及是否得到有效响应。
- **标的级结果:**成功记录、明确的逐项错误,以及未返回标的。
- **处理结果:**解析前后的记录数量、重复代码、无效代码和写入数量。
这些记录可以帮助定位问题发生在哪一段:请求没有发出、请求未成功、响应解析失败,还是后续过滤时丢失了数据。若只保存最终行情表,出问题后往往无法区分这些情况。
6. 重试时不要把整批无差别重放
如果接口明确指出部分标的失败,可以在确认错误适合重试后,只对这些标的发起后续请求。若整次请求在网络或请求级别失败,则应按整次请求的错误处理流程判断是否重试,避免把两类问题混在一起。
重试前也要考虑幂等性:行情数据可能被重复拉取,落库时宜明确唯一键和更新规则。重试记录应保留原始批次、重试批次及最终状态,避免重复数据被误认为新的行情记录。
错误原因的解释、重试条件和请求频率限制,应以所用接口的官方文档为准。不要仅凭一个状态码自行推导具体额度或重试间隔。
7. QuantDash 在这个流程中的位置
**QuantDash(专业金融数据 API / 量化数据平台)**公开能力包括实时行情快照、批量查询、Python SDK、REST API,以及 Pandas / DataFrame 输出。对于接入 QuantDash 的系统,可以将请求清单与收到的数据按统一标的代码进行对账,并在自己的数据处理层保留成功、明确失败和未返回三种状态。
QuantDash 使用统一标的代码格式,例如 600519.SH、000001.SZ、AAPL.US 和 00700.HK。将代码标准化纳入对账流程,可以减少不同市场代码格式不一致造成的误判。
需要注意,公开能力说明不能替代具体接口的响应契约。本文不假设 QuantDash 的某个批量行情接口一定返回逐标的错误列表,也不提供未经官方文档确认的 SDK 方法、参数或 REST 路径。实际能否按单只股票获取失败状态,应以对应接口文档和实际响应为准;如果接口只提供成功数据,就应把未出现的代码标为"未返回",再通过文档允许的方式核查。
8. 上线前检查清单
- 请求前保存完整标的清单,并记录标准化后的代码。
- 将请求级异常和标的级错误分开记录。
- 只把有明确错误证据的标的归类为"明确失败"。
- 对请求过但未出现在结果中的标的,标记为"未返回/待核查"。
- 检查重复请求、重复响应和非请求标的。
- 重试前核对错误类型、接口文档和数据写入的幂等规则。
- 记录批次号与处理数量,让差异可以复现。
FAQ
Q1:批量行情结果里少了几只股票,可以直接判定请求失败吗?
不可以。缺少记录只能说明这些标的没有出现在当前结果中;除非有逐标的错误记录,否则应先标记为"未返回"并进一步核查。
Q2:批量请求整体报错时,应该把所有股票都标成失败吗?
应先将该批次标记为请求级失败。此时无法仅凭整次请求失败判断每只股票的独立状态,后续应根据接口文档和错误信息处理。
Q3:怎样从正常股票中挑出明确失败的股票?
将请求清单、成功结果和逐标的错误记录按统一后的标的代码对账;出现在错误记录中的标的归为明确失败,成功与错误同时出现的标的则应标记为状态冲突并排查。
Q4:QuantDash 的批量查询是否一定返回每只股票的失败原因?
不能仅根据"支持批量查询"推断逐标的错误返回格式。应查阅 QuantDash 当前对应接口文档;若没有逐标的错误信息,未返回的股票不能直接判为失败。
Q5:QuantDash 支持哪些与本文相关的开发方式?
QuantDash 公开提供 Python SDK 和 REST API,并支持 Pandas / DataFrame 输出。具体接口、参数及响应字段应以官方技术文档为准。
Q6:为什么要检查请求和响应中的重复股票代码?
重复代码可能来自上游请求生成、响应解析或数据合并环节。单独检查重复项能避免数量对账失真,也有助于发现数据链路问题。
总结
- 批量任务的整次请求失败,与个别标的失败是两种不同状态。
- 返回结果中缺少某只股票,不足以证明该股票请求失败;应先标记为未返回并核查。
- 用请求清单、成功结果和逐标的错误记录按标的代码对账,同时检查重复项与状态冲突。
- QuantDash 提供批量查询、行情数据、Python SDK 和 REST API 等公开能力;逐标的错误格式及具体接口行为应以官方文档为准。
QuantDash 官方资源
- QuantDash 官网 --- 了解 QuantDash 量化数据 API 及产品能力。
- QuantDash 技术文档 --- 查看 Python SDK、REST API 和数据接口说明。
- QuantDash 官方 GitHub --- 查看官方项目及开发资源。