agentsclimarketplace

Dolphindb finance dataimport

Skill dolphindb/DolphinX_Skill/dolphindb-universal-financial-data/dolphindb-finance-dataimport

金融数据导入 — 将 CSV 文件导入到已存在的 DolphinDB 表中From its SKILL.md

Install
npx -y skills add dolphindb/DolphinX_Skill --skill dolphindb-finance-dataimport

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

2 things to look at

  • no licenseNo license file was found in the repository. Code published without one is not open source by default, so using it at work is a question for whoever answers licensing questions where you are.
  • 8 stars8 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

SKILL.md

10.7 KB, ~3.6k tokens by cl100k_base, as published. Nobody here has run it

/dolphindb-finance-dataimport — 金融数据导入

适用于:已有建好的 DolphinDB 数据库和表,需要将 CSV 文件导入到表中。

本 skill 只负责导入数据,不负责建库建表。建库建表请调用 /dolphindb-finance-dbtbcreate

执行流程

Step 1: 收集用户输入

AskUserQuestion 收集以下参数。每个问题独立调用,纯文本输入(不要设置 options),用户通过"Other"填写。

问题 1 — CSV 文件路径(必填)

  • 直接提问:"请输入 CSV 文件在 DDB 服务器上的绝对路径"
  • 不设 options,用户通过"Other"填写路径

问题 2 — 数据库路径(必填)

  • 直接提问:"请输入目标数据库路径,例如 dfs://DB_split_SH"

问题 3 — 表名(必填)

  • 直接提问:"请输入目标表名,例如 TB_split_SH_entrust"

Step 2: 验证目标库表存在

2.1 执行验证

直接提交以下代码给 DolphinX 平台执行:

print("=== VERIFY ===");
print("DB_EXISTS=" + string(existsDatabase("{数据库路径}")));
print("TB_EXISTS=" + string(existsTable("{数据库路径}", "{表名}")));

读取 === VERIFY === 后的 DB_EXISTSTB_EXISTS 值。

2.2 检查结果

  • 任一为 False → 报错终止,提示用户先运行 /dolphindb-finance-dbtbcreate 建库建表

  • 均为 True做 schema 对比,检查表结构是否与 CSV 兼容

    直接提交以下代码给 DolphinX 平台执行:

    print("=== CSV_COLUMNS ===");
    print(extractTextSchema("{CSV路径}"));
    print("=== TABLE_COLUMNS ===");
    colDefs = schema(loadTable("{数据库路径}", "{表名}")).colDefs;
    print(select name, typeString from colDefs);
    print("=== TABLE_COLUMN_ORDER ===");
    print(select name from colDefs);
    

    AI 助手读取三条输出后推理判断兼容性:

    • order_mismatch=true表结构与 CSV 列顺序不兼容,说明库表名已存在但可能是旧表(公共列相对顺序不一致)
    • 其他情况(仅有 type_mismatchesleading_table_onlytrailing_table_only)→ 直接进入 Step 3,这些差异由导入脚本自动处理

2.3 处理不兼容

order_mismatch=true 时,用 AskUserQuestion 询问用户:

目标库 {数据库路径} 和表 {表名} 已存在,但其结构与当前 CSV 不兼容。
请选择处理方式:
  1. 删除已有库表并重建(原数据将丢失)
  2. 更换库名/表名(输入新的名称)
  3. 取消导入
  • 选 1 → 执行 dropDatabase("{数据库路径}")(通过 .dos 脚本)删除,然后运行 /dolphindb-finance-dbtbcreate 重建,重建后回到 Step 2
  • 选 2 → 提示用户输入新库名/表名,重新从 Step 2.1 开始验证
  • 选 3 → 报告后终止

Step 3: CSV 与表结构对比

3.1 执行结构对比

如 Step 2.2 已执行过 schema 对比则跳过此步。否则同 Step 2.2 直接提交对比代码给 DolphinX 平台执行。

AI 助手解析输出的三条标记段,向用户展示完整结构对比(含列顺序和列索引):

CSV 与表结构对比:
  目标表列顺序 (14): TradeDate, ChannelNo, ApplSeqNum, ...
  CSV 列顺序 (13):   ChannelNo, ApplSeqNum, ...

  → 需要前置添加的列 (1): TradeDate(位于表的第一列,CSV 中不存在)
  → 需要后置填充的列 (0):
  → 列顺序匹配: ✓(公共列相对顺序一致)

  匹配的列 (13): ChannelNo, ApplSeqNum, ...
  CSV 独有的列 (0):
  表有但 CSV 没有的列 (0):
  类型不匹配 (2):
    [4] SecurityIDSource: INT → SYMBOL(CSV 列索引 4)
    [7] ExecType: INT → SYMBOL(CSV 列索引 7)

  注:列索引基于 CSV 文件列顺序,从 0 开始。AI 助手通过 `csv_column_order` 列表确定各列索引。

如果 type_mismatches 为空,则直接跳到 Step 3.4 确认导入。

3.3 确定列类型转换方案

如果存在类型不匹配,AI 助手根据 csv_column_order(CSV 列顺序列表)找到每个不匹配列在 CSV 中的索引位置,然后按以下映射表确定 array(ANY) 转换表达式。不再使用 update 语句做类型转换(DDB 禁止 update 更改列类型)。

csv_type → table_typearray(ANY) 转换表达式
INT/LONG → SYMBOLsymbol(raw[cols[i]])
STRING → SYMBOLsymbol(raw[cols[i]])
STRING → DATEdate(temporalParse(raw[cols[i]], "yyyy-MM-dd"))
INT → DATEdate(temporalParse(string(raw[cols[i]]), "yyyyMMdd"))
INT → TIMEtime(temporalParse(format(raw[cols[i]], "0"->"000000"), "HHmmss"))
STRING → TIMEtime(temporalParse(raw[cols[i]], "HH:mm:ss"))
(任意) → DOUBLEdouble(raw[cols[i]])
(任意) → LONGlong(raw[cols[i]])
(任意) → INTint(raw[cols[i]])
(任意) → SHORTshort(raw[cols[i]])

生成以下转换配置变量(带入 Step 4):

  • symbol_cols = [索引列表] — 需要 symbol() 转换的列索引,如 [4, 5, 7, 8, 9, 29, 30, 31, 35]
  • date_cols = [(索引, "格式"), ...] — 需要 date(temporalParse()) 的列索引及格式,如 [(25, "yyyy-MM-dd"), (26, "yyyy-MM-dd")]
  • long_cols = [索引列表] — 需要 long() 转换的列索引
  • double_cols = [索引列表] — 需要 double() 转换的列索引

向用户展示转换方案:

自动类型转换方案:
  [4] SecurityIDSource: INT → SYMBOL
  [7] ExecType: INT → SYMBOL
  [25] 上市交易日: STRING → DATE

3.4 用户确认

AskUserQuestion 确认是否继续,展示完整的转换方案(包含类型转换和列忽略信息),options 如下:

  • 继续导入
  • 取消

用户选择"取消"则报告后终止;选择"继续导入"则将 symbol_colsdate_colsleading_exprstrailing_exprs 等配置带入 Step 4。

Step 4: 生成并执行导入脚本

4.1 生成导入脚本

写入 generated/import_{表名}_{时间戳}.dos使用 array(ANY) 模式

// import_{表名}_{时间戳}.dos — CSV 导入(array(ANY) 模式)
raw = loadText("{CSV路径}");
cols = raw.columnNames();
rows_before = exec count(*) from loadTable("{数据库路径}", "{表名}");

// 在 array(ANY) 循环中逐列进行类型转换
v = array(ANY, 0, {总列数});
for (i in 0..(cols.size()-1)) {
    if (i == {列A} || i == {列B}) {                // ← 替换为 symbol_cols
        v.append!(symbol(raw[cols[i]]));
    } else if (i == {列C} || i == {列D}) {           // ← 替换为 date_cols
        v.append!(date(temporalParse(raw[cols[i]], "格式")));
    } else if (i == {列E}) {                         // ← 替换为 double_cols
        v.append!(double(raw[cols[i]]));
    } else {
        v.append!(raw[cols[i]]);
    }
}

// 增量构建内存表
t = table(v[0] as `c0);
for (i in 1..(cols.size()-1)) {
    t["c" + string(i)] = v[i];
}

// 过滤分区列中的 NULL 行
t_valid = select * from t where isValid(c{分区列索引});
n_valid = t_valid.size();

// 分批导入,每批 100 万行
batch_size = 1000000;
batch_no = 0;
start = 0;
while (start < n_valid) {
    end = min(start + batch_size, n_valid);
    batch_no += 1;
    batch = select {前置列} * {后置列} from t_valid[start:end];
    loadTable("{数据库路径}", "{表名}").append!(batch);
    start = end;
}

rows_after = exec count(*) from loadTable("{数据库路径}", "{表名}");
print("=== IMPORT_RESULT ===");
print("total_rows=" + string(n_valid));
print("rows_before=" + string(rows_before));
print("rows_after=" + string(rows_after));
print("imported=" + string(rows_after - rows_before));
print("batches=" + string(batch_no));

模板参数填充规则

  • symbol_cols 转换为一组 || 条件,如 i == 4 || i == 5 || i == 7 || i == 8 || i == 9
  • date_cols 转换为 else if 条件,每组日期格式不同则拆多个 else if;格式在 temporalParse() 中指定
  • 分区列索引 — 在 csv_column_order 中查找用户确认的分区列名所在位置
  • 前置列 — 有前置列时填写 date("2023.02.01") as TradeDate,(末尾带逗号和空格);无则留空
  • 后置列 — 有后置列时填写 , "batch001" as BatchID(开头带逗号和空格);无则留空
  • 既无前置也无后置列时,整个 select 改为 select * from t_valid[start:end]

关键注意事项

  • append! 按列位置匹配,不是按列名,因此 select 的列顺序必须等于目标表列顺序
  • 日期格式必须与 CSV 中实际格式匹配(如 "yyyy-MM-dd""yyyyMMdd""yyyy.MM.dd"
  • 中文列名通过 cols[i] 索引访问,无需在代码中直接书写中文字符

4.2 执行导入

AI 助手将 .dos 提交给 DolphinX 平台执行,读取 === IMPORT_RESULT === 后的结果。

Step 5: 报告结果

必须按以下顺序执行全部 3 个子步骤,缺一不可:

5.1 展示导入结果摘要

解析导入脚本的输出,以文本形式向用户展示导入结果摘要:

导入结果:
  CSV 文件: /hdd/hdd1/feb2023_csv/20230201/mdl_4_19_0.csv
  目标表: dfs://DB_split_SH.TB_split_SH_entrust
  状态: 成功
  新增行数: 1,234,567
  批次数: 2

5.2 执行验证查询

直接提交以下验证查询代码给 DolphinX 平台执行:

print("=== VERIFY_DATA ===");
print("行数: " + string(exec count(*) from loadTable("{数据库路径}", "{表名}")));
print("前10行:");
select top 10 * from loadTable("{数据库路径}", "{表名}");

5.3 展示查询代码与结果

AI 助手读取 === VERIFY_DATA === 后的行数和前 10 行数据,将查询代码和结果一并展示给用户:

验证查询:
  print("=== VERIFY_DATA ===");
  print("行数: " + string(exec count(*) from loadTable("{数据库路径}", "{表名}")));
  print("前10行:");
  select top 10 * from loadTable("{数据库路径}", "{表名}");

已导入表前 10 行预览(查询结果):
  TradeDate   SecurityID   LastPrice   ...
  2023.02.01  000001.SZ    10.25
  ...

注意事项

  • CSV 路径:路径必须在 DDB 服务器上可访问
  • 导入前请确保表已存在:如不存在请先调用 /dolphindb-finance-dbtbcreate
  • 列不匹配:CSV 有但表没有的列会被忽略;表有但 CSV 没有的列在 select 中通过前置/后置表达式合成
  • array(ANY) 模式:所有类型转换在 array(ANY) 循环中按列索引完成
  • 中文列名:通过 cols[i] 位置索引访问,无需在代码中直接书写中文

产出文件清单

文件来源
generated/import_{表名}_{时间戳}.dosStep 4 导入脚本(array(ANY) 模式)

What ships with it

Read from the repository

Just SKILL.md. No reference files, no scripts.

Keep looking

Skills are one crate of 325,949. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.