数据源插件开发

AxData 数据源插件开发教程

数据源插件负责把一个上游数据源接入 AxData 的接口目录。它回答的问题是:“用户临时查一次这个源的数据时,参数是什么、返回什么字段、由哪个 Adapter 请求上游。”

它不等于采集器。接口临时调用默认不写入 data/rawdata/stagingdata/coredata/factor,也不会自动创建采集任务。需要长期落盘时,再写独立采集器插件。

本教程的术语和边界以 axdata-development-standards.md 为准:Provider / Adapter 负责 source_request,采集任务、写入、进度、日志和质量结果属于 Collector。

1. 什么时候写数据源插件

适合写数据源插件的场景:

不适合放在数据源插件里的内容:

2. 最小目录

推荐目录:

axdata-source-demo/
  pyproject.toml
  README.md
  LICENSE
  src/
    axdata_source_demo/
      __init__.py
      provider.py
      adapter.py
      catalog.py
      axdata-provider.json
      samples/
        stock_snapshot.json
  tests/
    test_manifest.py
    test_adapter.py
    test_catalog.py

最小 pyproject.toml

[project]
name = "axdata-source-demo"
version = "0.1.0"
requires-python = ">=3.11"
dependencies = ["axdata-core>=0.1.0"]

[project.entry-points."axdata.providers"]
demo = "axdata_source_demo.provider:provider"

[tool.setuptools.package-data]
axdata_source_demo = ["axdata-provider.json", "samples/*.json"]

关键点:

3. 命名规则

Provider 身份:

provider_id = axdata.source.demo
source_code = demo
source_name_zh = 示例数据源

接口名建议:

{数据口径}_{来源}

例子:

stock_snapshot_demo
announcements_demo
financial_statement_demo

规则:

4. 写接口目录

接口目录至少要写清:

字段说明
name全局唯一接口名
display_name_zh中文名
source_code数据源命名空间
asset_classstock、index、fund 等资产分类
menu_pathWeb 接口目录完整路径,例如 ["通达信", "股票数据", "基础数据"]
summary_zh接口页顶部中文短摘要
description_zh接口页中文正文说明
params_note_zh参数区中文补充说明
params_example_zh参数区静态 SDK 调用示例
parameters参数名、类型、是否必填、默认值、说明
fields返回字段、类型、含义、单位
example已真实请求过的静态小样例
reference_sections可选静态参考表,例如类别码、枚举映射、字段口径说明

接口页应能回答三个问题:

参数和字段必须带中文说明。日期格式、代码格式、价格/成交量/成交额/百分比单位、是否源端原始口径都要写清楚。instrument_id 这类 AxData 统一字段不能被源端原始代码替代。

接口页静态样例必须来自已经真实请求过的小样本快照,不能编假数据,也不能在页面打开时为了展示样例实时请求源端。样例参数应尽量使用稳定历史日期;返回字段必须和接口字段声明一致。

menu_path 是接口左侧目录的事实源,必须由插件 catalog / manifest 提供完整路径。Web 只根据 Registry 返回的 menu_path 渲染目录,不为具体数据源写死接口树。小源可以使用两层路径,例如 ["巨潮", "公告数据"];通达信这类大源应使用三层或更多路径,例如 ["通达信", "股票数据", "行情数据"]

接口页中文文案也必须跟插件 / Provider 走。不要把接口的短摘要、正文说明、参数提示或参数调用示例只写在 Web 静态文件里;应写入 summary_zhdescription_zhparams_note_zhparams_example_zh。Web request 接口页只按 Registry 返回的字段通用渲染,不为具体接口维护静态页面副本。

当前运行时接口目录使用单个 example,对应 SourceRequestInterface.example。插件 manifest 里如果按协议写了 examples 数组,也要选出一个主样例同步到运行时 example,给接口页和 API 返回使用。

接口页参考表必须跟插件 manifest 走。不要把类别码、参数槽含义、枚举映射这类内容只写到 Web 静态页面里;应写入 reference_sections,让插件分享、安装、禁用和 Web 展示保持同一份事实源。

5. 写 Provider

Provider 对象负责把接口目录和 Adapter 交给 AxData:

from axdata_core.plugins import SourceProvider

from .adapter import DemoAdapter
from .catalog import INTERFACES


class DemoProvider(SourceProvider):
    provider_id = "axdata.source.demo"
    source_code = "demo"
    source_name_zh = "示例数据源"
    version = "0.1.0"
    plugin_api_version = "1.0"

    def interfaces(self):
        return tuple(INTERFACES)

    def create_adapter(self, options=None):
        return DemoAdapter(options=options)


provider = DemoProvider()

新插件不要把采集器挂在 Provider 下面。Provider 的 collectors() 是旧兼容路径,不是新插件推荐方式。

6. 写 Adapter

Adapter 只负责源端请求和字段归一:

class DemoAdapter:
    def __init__(self, options=None):
        self.options = dict(options or {})

    def call(self, interface_name, params=None, fields=None, options=None):
        params = dict(params or {})
        if interface_name == "stock_snapshot_demo":
            return self._stock_snapshot(params, fields)
        raise KeyError(interface_name)

Adapter 应该做:

Adapter 不应该做:

本地 SDK 模式下,AxDataClient() 直接使用本机数据目录和本机 Adapter,不需要 AxData HTTP token。只有 AxDataClient(api_base="http://host:8666")AXDATA_API_BASE 或跨机器 HTTP/API 调用,且服务端开启鉴权时,才需要 AxData token。第三方源 token 由插件自行读取和保护,不能写入样例、日志或 manifest。

7. Manifest

axdata-provider.json 是 AxData 发现插件的主文件。最小骨架:

{
  "manifest_version": "1.0",
  "plugin_api_version": "1.0",
  "provider": {
    "provider_id": "axdata.source.demo",
    "source_code": "demo",
    "source_name_zh": "示例数据源",
    "version": "0.1.0",
    "declared_trust_level": "community",
    "description": "示例数据源 Provider"
  },
  "interfaces": [],
  "downloaders": [],
  "collectors": [],
  "dependencies": [],
  "config_schema": {"required_config": []}
}

推荐做法是由插件代码生成 manifest,再把它打进 wheel,避免 README、Python 代码和 manifest 三份内容漂移。

8. 本地开发验证

开发期安装:

.\.venv\Scripts\python -m pip install -e C:\path\to\axdata-source-demo
.\.venv\Scripts\axdata plugin list --json
.\.venv\Scripts\axdata plugin info axdata.source.demo --json

启用插件:

.\.venv\Scripts\axdata plugin enable axdata.source.demo

检查接口是否进入目录:

curl http://127.0.0.1:8666/v1/request/interfaces

调用接口:

curl -X POST http://127.0.0.1:8666/v1/request/stock_snapshot_demo ^
  -H "Content-Type: application/json" ^
  -d "{\"params\":{\"code\":\"000001.SZ\"},\"persist\":false}"

HTTP 请求体必须把接口参数放进 params。CLI 的 --param code=000001.SZ 和本地 SDK 的 client.call("stock_snapshot_demo", code="000001.SZ") 只是更顺手的写法,底层进入 HTTP API 时会转换成 params

9. 常见错误

现象常见原因修复
插件不出现在普通列表wheel 没带 manifest检查 package data
诊断里出现 ignored candidate有 entry point 但缺 manifestaxdata-provider.json
接口冲突interface_name 被其他插件占用改名或禁用冲突插件
启用失败plugin_api_version 不兼容调整 manifest 版本
调用时报错Adapter 参数或上游响应变化加参数校验和错误处理

10. 和采集器的边界

数据源插件只提供“查一次”的能力。采集器插件提供“长期落盘”的能力。

如果 Provider 或 Adapter 开始承担以下职责,应拆成采集器:

采集器应该进入 CollectorRegistry,通过 runner_entry 由 AxData Collector Runner 执行。