ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

TuShare 行情写入 ACCESS 出差错?让 Codex 走 TaoToken 查 pyodbc 脚本

TuShare 行情写入 ACCESS 出差错?让 Codex 走 TaoToken 查 pyodbc 脚本 TuShare 行情写入 ACCESS 总是卡在 pyodbc 的 insert 上别急着改第四遍先用 Codex 排查更省事。Codex 的模型 API 我这次走了 TaoTokenKey 在 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_end 创建。下面从这次实际遇到的报错讲起列出列名映射、日期转换和 executemany 批量写入的完整修复。这段脚本会用 pro.daily 和 adj_factor 把个股行情拉下来然后通过 pyodbc 逐行 insert 进 ACCESS 的 stockprice 表问题往往恰好出在这三步上。拿到脚本时TuShare 那边数据已经能拉到但一进 ACCESS 就报找不到字段。后来把代码丢给 Codex 通读才发现原来vol和volume差一个字母adj_factor和dvd_factor完全对不上。这种错靠人眼盯一遍也能发现但脚本一旦长到几百行或者你要同时处理多只股票让模型按结构对照明显更快。下面先把这次遇到的问题按顺序拆开再给出 Codex 走 TaoToken 的具体配置和修正后的可运行版本。整篇不会去接生产库Codex 只负责生成和检查脚本实际执行都在你自己的 Python 环境里完成。1. 从报错现场看pyodbc 写 ACCESS 的四个典型问题1.1 列名映射vol 不是 volumeadj_factor 不是 dvd_factorTuShare 的pro.daily返回一个 DataFrame列名是ts_code, trade_date, open, high, low, close, pre_close, vol, amount, change, pct_chg。而 ACCESS 表stockprice里的字段按原脚本定义是stockcode, stockname, tradedate, open, high, low, close, pre_close, volume, amount, change, pct_chg, dvd_factor。对比一下就能看到vol要写成volumeadj_factor要写成dvd_factortrade_date要写成tradedate。如果 INSERT 语句里直接填了volACCESS 会返回“No value given for one or more required parameters”或“字段不存在”。另外原脚本里有一行m_stockcodem_stockcode[:6]把ts_code截成了 6 位。这个操作用在pro.adj_factor和pro.daily的参数上也许还能拉到数据但写进stockcode字段时000001.SZ和600000.SH会同时变成000001和600000还不至于重复但如果你按行业循环可能遇到同一市场不同板块代码前六位相同实际上不会深市和沪市前缀不同。但像688001和300001不同没问题。真正的问题是丢失了交易所后缀后面想和 TuShare 重新关联时还得补回来。所以如果stockcode字段长度够VARCHAR(10)建议保留完整ts_code。1.2 日期和 NaN字符串拼接 insert 的隐含炸弹原 INSERT 语句把trade_date直接用%s拼进 SQL。TuShare 给的trade_date是20210430这种字符串ACCESS 的tradedate如果是日期型驱动会尝试转换。在区域设置为中文的环境下20210430不一定能被正确理解为日期于是报“Invalid character value for cast specification”。更常见的坑是停牌日open/close等字段在 TuShare 里是NaN字符串拼接后变成nanACCESS 无法把它写入数值列。正确做法是参数化查询SQL 里写?占位符值用元组传入。pyodbc 会按参数类型走驱动转换同时我们需要在写入前把NaN替换成 Python 的None这样数据库会收到 SQLNULL。日期字段如果tradedate是日期型就用datetime.strptime(row[trade_date], %Y%m%d).date()转成datetime.date如果是文本型保持原字符串即可但要把字段长度设够 8 位。1.3 逐行 execute不是错但慢得让你想重写原代码里for jj in range(len(ts_code))一行一行crsr.execute。对单只股票几十行没什么但全市场几千只股票一次入库就是几十万行。每行都要走一遍 SQL 编译和驱动回调耗时差距非常明显。这也是 ACCESS 类场景最值得优先改的地方。把数据收集到一个rows列表里最后用crsr.executemany(sql, rows)一次提交能明显减少驱动交互次数。如果担心一次提交太多导致内存或锁问题可以按 5000 行分片提交。1.4 让 Codex 做第一轮审阅上面三类问题靠人眼也能慢慢查但把脚本和表结构丢给 Codex让它按“列名映射、类型转换、批量写入”三个方向去检查通常一次性就能列出所有可疑点。这也是整篇改造的起点先把 Codex 的模型通道配置好让它能正常对话再开始排查。Codex 本身不能直连你的.mdb文件也不需要连它看到的是你贴进去的代码和 DDL输出的是修订后的 Python 代码真正入库动作永远发生在你本地。2. 把 Codex 接到 TaoToken拿 Key 与 config.toml 配置2.1 创建 API Key并分清两个 Token这里要分清楚TuShare 的ts.set_token里填的是 TuShare 给你的 token用来访问行情数据Codex 这边需要一个 TaoToken 的 API Key用来访问模型接口。去 TaoToken 注册登录在控制台创建 API Key复制下来记为YOUR_API_KEY。然后打开模型广场挑选一个你打算给 Codex 用的模型把模型 ID 复制出来。模型 ID 以模型广场当时列表为准不要凭记忆输入。2.2 在 ~/.codex/config.toml 中写入 TaoToken 供应商Codex CLI 的配置文件在用户目录下的~/.codex/config.toml。没有这个文件就新建一个然后加入下面的内容# 替换成你在 TaoToken 模型广场复制的模型 ID model YOUR_MODEL_ID model_provider taotoken [model_providers.taotoken] name TaoToken base_url https://taotoken.net/api env_key TAOTOKEN_API_KEY注意base_url填的是 https://taotoken.net/api末尾不要加/v1也不要填成官网首页地址。官网首页地址只用于注册、看模型和查用量填进工具的是 API 地址两者用途不同。保存后设置环境变量export TAOTOKEN_API_KEYYOUR_API_KEYWindows PowerShell 用$env:TAOTOKEN_API_KEYYOUR_API_KEY然后在终端运行codex随便问一句“11 等于几”。能正常返回就说明供应商配置生效。如果提示缺少 API Key检查环境变量名是否拼成TAOTOKEN_KEY如果提示 401检查YOUR_API_KEY是否复制完整如果提示模型不存在回到模型广场重新复制模型 ID。2.3 关于 Coding Plan 和用量可以先不急着买大额套餐用默认按量计费跑完这次排障确认日常使用量后再考虑。稍后验证章节会给出具体的页面链接。3. 用 Codex 对照脚本列名、类型、批量写入3.1 贴代码时要带上表结构打开 Codex 后把原始 pyodbc 脚本贴进去再把stockprice的建表语句或 ACCESS 里的字段清单也贴过去。Codex 会自己识别vol和volume的差异。如果不确定字段清单可以让 Codex 先根据 INSERT 语句反推它认为的字段映射再和你实际表结构对比。给 Codex 的提示可以是这样“请检查下面这段 TuShare 转 ACCESS 的 pyodbc 代码。重点关注三点1. DataFrame 列名和 INSERT 字段是否一一对应2. trade_date 是否需要转成日期型NaN 是否会被拼进 SQL3. 逐行 insert 怎么改成 executemany。不要执行代码只输出分析和修改后的版本。”3.2 修改后的核心代码下面这段是让 Codex 按上述要求改写的完整版本。注意里面ts.set_token仍然填 TuShare 自己的 token不是 TaoToken 的 Keyimport pyodbc import pandas as pd import tushare as ts from datetime import datetime conn pyodbc.connect(rDRIVER{Microsoft Access Driver (*.mdb, *.accdb)};DBQD:\WindData\WindRawData.mdb) crsr conn.cursor() ts.set_token(YOUR_TUSHARE_TOKEN) pro ts.pro_api() dfx pro.stock_basic(exchange, list_statusL, fieldsts_code,symbol,name,exchange,list_status,delist_date,list_date,market) rows [] for _, stock in dfx.iterrows(): code stock[ts_code].strip() name stock[name].strip() df_a pro.adj_factor(ts_codecode, start_date20210430) df_b pro.daily(ts_codecode, start_date20210430) if df_a is None or df_b is None: print(f{code} data error!) continue df pd.merge(df_a, df_b, on[ts_code, trade_date], sortTrue) if df.empty: continue # 统一把 NaN 转成 None避免字符串拼接时出现 nan df df.astype(object).where(pd.notnull(df), None) for _, row in df.iterrows(): rows.append(( row[ts_code], name, datetime.strptime(row[trade_date], %Y%m%d).date(), row[open], row[high], row[low], row[close], row[pre_close], row[vol], row[amount], row[change], row[pct_chg], row[adj_factor] )) insert_sql INSERT INTO stockprice( stockcode, stockname, tradedate, open, high, low, close, pre_close, volume, amount, change, pct_chg, dvd_factor ) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?) if rows: crsr.executemany(insert_sql, rows) conn.commit() crsr.close() conn.close()如果你的stockcode字段只存 6 位数字就把第 7 行附近的code stock[ts_code].strip()改成code stock[ts_code].strip()[:6]但要注意这样可能丢失交易所后缀。另外如果 ACCESS 里的tradedate是文本型就不用datetime.strptime直接传row[trade_date]即可。3.3 为什么这样改不会让 Codex 连上数据库整个过程中 Codex 只接触你贴给它的文本和它返回的代码不会去打开你的.mdb更不会执行 INSERT。你拿到修改版之后要在自己的 Python 环境里运行把新的报错复制回 Codex继续下一轮排查。这样既安全也符合本地数据文件不被外部工具直接操作的原则。4. 修完还可能遇到的新报错把错误原文贴回去4.1 参数数量对不上改成executemany后最常见的报错是The SQL contains 13 parameter markers, but 12 parameters were supplied。原因是VALUES里的?数量和 rows 元组里的元素个数不一致。仔细数一下stockcode, stockname, tradedate, open, high, low, close, pre_close, volume, amount, change, pct_chg, dvd_factor一共 13 个字段所以VALUES后面要有 13 个?。如果漏掉dvd_factor或stockname就会触发这个提示。4.2 字段为 NULL 时的 ACCESS 兼容性TuShare 的vol、amount在某些情况下是 0 而不是 NULL但pre_close可能为 0。ACCESS 里如果字段设置为“必须非空”你传None会被拒绝报类似“不能在字段中保存 NULL 值”的错误。这时要么修改表结构允许 NULL要么在代码里把None填成 0。Codex 可以根据你的 DDL 继续调整你只需要把表结构一并贴给它。如果数据量特别大可以在rows的基础上每 5000 条分片提交避免单次写入过大BATCH 5000 for i in range(0, len(rows), BATCH): crsr.executemany(insert_sql, rows[i:iBATCH]) conn.commit()5. 跑通后去控制台对一下这次 Codex 调用5.1 检查消耗和 Key 的状态整个排障过程如果一切顺利你的 TuShare 行情已经批量写进 ACCESSCodex 这边也消耗了若干次模型调用。如果你突然发现模型 ID 或 Key 还没配对可以打开 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_end 回到模型广场重新确认再去 TaoToken 控制台 API Keys 页面看用量。如果想要更稳的套餐可以到 Coding Plan 按自己的月用量选一档在 模型对话 里也可以用同一把 Key 发一条消息确认模型 ID 和响应速度是否符合预期。5.2 这次排障留下的操作习惯TuShare 到 ACCESS 的脚本以后还会改可能换日线频率、增加复权因子字段或者把stockprice表加一列。每次改动后都按“Codex 先审 → 本地跑 → 贴报错”的顺序来能少花很多时间。关键不是记住所有列名而是让 Codex 在你的配置里熟悉这套 pyodbc 脚本的上下文下次维护时直接把新旧代码一起丢给它它会更快定位差异。
返回列表