资讯动态

Python股票数据爬虫与量化分析实战:从数据清洗到策略回测

发布时间:2026/10/21 2:44:59 来源:尧图企业网站定制
简介基于Python的股票大数据分析实战资料包定位于金融量化与股票数据分析的入门到进阶实操适合想用爬虫获取行情、以Pandas清洗数据、通过可视化探查规律再借助机器学习辅助判断走势的数据爱好者、金融从业者与在校学生。资源以7z压缩包提供约4.47MB内容覆盖爬虫抓取、数据预处理、统计分析、可视化及实时数据接口调用等完整链路体量紧凑便于快速下载学习。目前已有3654人学习下载。通过学习可理清从BeautifulSoup/Scrapy采集策略、缺失值与异常值处理、K线图与箱型图绘制到回归/决策树/随机森林等预测模型构建以及Tushare/Wind实时数据接入和Flask/Django部署的关键思路帮助读者把零散知识点串联成可落地的股票数据分析方案。1. 用Python爬股票数据别急着写爬虫先想清楚要爬什么做股票数据分析的Python项目绝大多数人第一步就翻车了——打开终端就开始写爬虫结果爬到一半发现数据源字段对不上或者被反爬策略挡在门外。这个「基于股票大数据分析Python实战」项目其实解决的正是这个问题它不是教你怎么写一段能跑的爬虫脚本而是给出一条从数据采集、清洗、存储到量化分析的完整链路。我拆完整个项目后最直观的感受是这更像是一份能直接上手的工程模板而不是教学示例。项目说白了做三件事第一用Python爬虫把股票历史行情、财务指标、资金流向这些数据捞下来第二把这堆脏数据清洗成能用的结构化数据存到本地数据库第三在干净数据上做技术指标计算、趋势分析和简单策略回测。适合的人群也很明确——已经会点Python基础、想往量化分析或数据工程方向走的开发者以及那些手里有数据源但不知道下一步该怎么处理的分析师。整份资源从需求拆解到代码实现都有不是那种只丢给你一堆脚本的压缩包。有意思的是项目里最核心的工作量不在爬虫本身而在数据清洗和特征对齐。比如同一个股票的复权因子、停牌记录、除权除息日这些数据源里给的字段名和单位都不一样怎么对齐、怎么补全才是真正考验功力的地方。下文我会把整个项目的目录结构、核心模块、运行方式和二次开发思路完整拆开讲确保你拿到手能跑跑完能改。2. 项目架构与数据流一张图看懂从行情源到策略回测的完整链路2.1 整体架构设计四层结构各司其职这个项目在架构上划分了四层每一层职责非常清晰基本遵循了标准的数仓分层思路。最上层是数据采集层负责对接行情源和财经数据接口原始数据落到这里第二层是数据清洗层做去重、补全、复权处理第三层是存储层用的是SQLite加CSV双轨制存储方便后续扩展最底层是分析层包括技术指标计算、可视化展示和策略回测三大块。我拆目录的时候发现这套分层不是刻意设计的更像是作者在实际爬数据过程中被坑过之后自然演化出来的。比如存储层用SQLite而不是MySQL就是为了让整个项目零配置直接跑起来拉下来就能用分析层单独拆出来则是为了让爬虫和策略解耦换数据源或者换策略不会牵一发动全身。2.2 核心数据流一次完整的数据生命周期从数据生命周期来看整个项目运作流程大致是这样爬虫程序从行情接口拉取日K线数据将JSON格式的原始数据解析后暂存成DataFrame随后执行清洗逻辑——过滤停牌日、处理缺失值、补充复权因子清洗完成后写入SQLite数据库。分析模块再从数据库读数据计算MA、MACD、RSI等技术指标最后把指标数据喂给回测引擎。这条链路里的关键设计是清洗层单独存在而不是爬虫跑完直接入库。为什么要这样设计因为实际爬虫拿到的数据质量参差不齐有的源对停牌日返回空值有的返回上一交易日的重复数据还有的复权因子只有除权当天才有。如果这些细节不做统一处理后面的技术指标算出来全是错的回测结果也就毫无意义。2.3 目录结构详解每个文件负责什么项目目录结构如下我按照实际运行顺序来标注说明stock_analysis/ ├── config/ │ ├── settings.py # 全局配置数据源URL、数据库路径、日志级别 │ └── user_agents.py # 爬虫请求头轮换列表 ├── crawler/ │ ├── stock_list.py # 获取股票基础列表代码、名称、行业 │ ├── daily_kline.py # 日K线数据爬虫 │ ├── finance_indicator.py # 财务指标爬虫 │ └── base_crawler.py # 爬虫基类封装请求、重试、限速逻辑 ├── cleaner/ │ ├── data_cleaner.py # 通用清洗去重、缺失值处理、类型转换 │ └── adjust_calculator.py # 复权因子计算与前复权处理 ├── storage/ │ ├── database.py # SQLite连接池与读写封装 │ └── csv_exporter.py # CSV导出模块 ├── analysis/ │ ├── indicators.py # MA/MACD/RSI/布林带等指标计算 │ ├── visualize.py # K线图、指标曲线绘制 │ └── backtest.py # 简单策略回测引擎 ├── scripts/ │ ├── run_pipeline.py # 一键运行爬取→清洗→入库→分析 │ ├── fetch_all.sh # Shell脚本定时调度 │ └── init_db.py # 初始化数据库表结构 ├── tests/ │ ├── test_cleaner.py # 清洗模块单元测试 │ └── test_indicators.py # 指标计算正确性测试 └── requirements.txt # 项目依赖清单单独的user_agents.py文件在爬虫类项目里很常见但多数人都是硬编码几个请求头就完事这个项目把它做成独立配置配合base_crawler.py里的轮换逻辑能在一定程度上降低被目标网站风控的概率。init_db.py单独隔离出来也很实用数据库表结构变更时不需要动主流程代码重新执行初始化脚本就行。2.4 数据库表设计字段级的数据规划数据库表的设计直接影响后续分析的灵活性项目里主要设计了四张表。股票列表表存储基础信息包含股票代码、名称、所属行业、上市日期日K线表存储行情数据包含日期、开高低收价格、成交量、成交额、换手率财务指标表按季度存储包含每股收益、净资产收益率、毛利率、负债率复权因子表记录除权除息事件包含除权日期、送股比例、配股比例、分红金额。-- 日K线表结构核心表 CREATE TABLE daily_kline ( stock_code TEXT NOT NULL, -- 股票代码如 600000 trade_date TEXT NOT NULL, -- 交易日期格式 YYYY-MM-DD open_price REAL NOT NULL, -- 开盘价不复权 high_price REAL NOT NULL, -- 最高价 low_price REAL NOT NULL, -- 最低价 close_price REAL NOT NULL, -- 收盘价 volume INTEGER NOT NULL, -- 成交量股 amount REAL NOT NULL, -- 成交额元 turnover REAL, -- 换手率% PRIMARY KEY (stock_code, trade_date) );这张表的主键设计成(stock_code, trade_date)联合主键天然防止了同一天重复数据的插入。open_price存的是不复权原始价格复权后的价格在分析时通过因子表现场计算好处是原始数据不丢失坏处是每次分析都要多一步联表计算这在项目里算是一个有意识的取舍。3. 核心模块拆解一个请求从进入到指标输出的完整链路3.1 爬虫基类请求重试与限速的黑匣子爬虫基类是整个采集层的骨架这个类的设计质量直接决定你能稳定爬到多少数据。项目里base_crawler.py的核心逻辑是封装请求发送、异常重试和限速控制子类只需要定义数据解析函数不用关心底层网络细节。import time import random import requests from config import settings from config.user_agents import USER_AGENTS class BaseCrawler: def __init__(self, max_retry3, timeout10): self.session requests.Session() self.max_retry max_retry self.timeout timeout def _get_headers(self): 轮换User-Agent降低被识别为爬虫的概率 return { User-Agent: random.choice(USER_AGENTS), Referer: https://finance.example.com/, Accept: application/json, text/plain, */*, } def fetch_json(self, url, paramsNone): 获取JSON数据带重试机制连续失败会抛出异常方便上层捕获 for attempt in range(1, self.max_retry 1): try: resp self.session.get( url, paramsparams, headersself._get_headers(), timeoutself.timeout, ) resp.raise_for_status() return resp.json() except (requests.Timeout, requests.ConnectionError) as exc: # 退避策略第n次失败后等待 (2^n 随机抖动) 秒 wait_time 2 ** attempt random.uniform(0, 1) time.sleep(wait_time) raise RuntimeError(f请求失败超过最大重试次数: {url}) def rate_limit(self, min_interval0.5): 限速保证两次请求间隔不低于指定值避免触发反爬 time.sleep(min_interval)这段代码里有几个细节值得注意。重试逻辑用的是指数退避加随机抖动而不是固定间隔重试这样做的好处是避免多个线程同时重试时再次撞上风控rate_limit方法把限速做成独立方法由子类在每次请求前主动调用比在基类内部写死更灵活。timeout参数设置成10秒是考虑到行情接口在交易时段偶尔会出现慢响应太短的超时会导致大量误判。3.2 日K线爬虫字段映射和分页拉取策略日K线爬虫是项目里最核心的采集模块它需要处理分页拉取、JSON字段映射和日期格式化三件事。以某行情接口为例接口返回的JSON结构里数据字段通常嵌套在data节点下列表每个元素代表一天的数据字段名可能缩写比如o代表开盘价、h代表最高价。from crawler.base_crawler import BaseCrawler from config import settings import pandas as pd class DailyKlineCrawler(BaseCrawler): def __init__(self): super().__init__() self.api_url settings.KLINE_API_URL def fetch_kline(self, stock_code, start_date, end_date): 拉取指定股票在时间区间内的日K线数据 all_rows [] page 1 page_size 1000 # 单页请求1000条减少请求次数 while True: params { code: stock_code, start: start_date, end: end_date, page: page, size: page_size, } data self.fetch_json(self.api_url, paramsparams) items data.get(data, {}).get(list, []) if not items: break for item in items: all_rows.append({ stock_code: stock_code, trade_date: item[date], # 源字段是 YYYY-MM-DD open_price: item[o], high_price: item[h], low_price: item[l], close_price: item[c], volume: item[v], amount: item[a], turnover: item.get(t, 0), # 有些接口没有换手率用0兜底 }) # 一页不满说明拉完了 if len(items) page_size: break page 1 df pd.DataFrame(all_rows) return df字段映射这一步很重要因为接口返回的缩写字段直接入库会让后续分析代码变得难读。项目选择在这里做一层翻译把o/h/l/c/v/a映射成语义清晰的中文字段名。分页策略上使用page_size1000是经过考量的一般行情接口限制单次最大请求条数在2000到5000之间1000是一个既能减少请求次数、又不容易触上限的折中值。换手率字段用item.get(t, 0)兜底是考虑到部分历史数据确实没有换手率如果直接取item[t]会在这个字段上抛异常一崩就是整批数据中断。3.3 复权因子计算很多人忽略但必须处理的一步复权处理是股票数据分析里最容易出错的环节也是这个项目里技术含量最高的模块。如果不做复权处理直接用原始价格计算均线或MACD遇到除权除息日会出现价格跳空技术指标产生假信号回测结果完全不可用。项目里adjust_calculator.py实现的是前复权算法。import pandas as pd def calc_adjust_factor(dividend_events, kline_df): 计算前复权因子。 前复权原理保持最新价格不变将历史价格按复权因子缩小。 复权因子 当日除权参考价 / 前一日收盘价未复权口径 df kline_df.sort_values(trade_date).copy() # 初始化因子为1.0按日期从后往前迭代 df[adjust_factor] 1.0 # 将除权事件映射到对应的交易日 event_map { pd.Timestamp(row[ex_date]): row for _, row in dividend_events.iterrows() } # 从倒数第二天往前遍历 for i in range(len(df) - 2, -1, -1): current_date df.iloc[i][trade_date] next_date df.iloc[i 1][trade_date] # 如果下一交易日前发生了除权事件需要修正因子 factor 1.0 if next_date in event_map: event event_map[next_date] # 前复权口径ratio (前收 - 每股分红) / 前收简化模型 prev_close df.iloc[i][close_price] factor (prev_close - event[cash_dividend]) / prev_close df.iloc[i 1, df.columns.get_loc(adjust_factor)] ( df.iloc[i 1][adjust_factor] * factor ) return df这段代码的核心思路是从最新交易日往前逐日推算复权因子。除权后的最新价格保持不变往前每遇到一次除权事件就把历史价格按比例缩小。代码里的cash_dividend是每股现金分红真实的复权模型还会考虑送股和配股这里用简化模型展示流程目的是让读者先理解原理。需要注意这个实现假设dividend_events里的ex_date已经对齐到交易日没有对齐的话因子会算错——这在实际工程里是一个常见的坑。3.4 技术指标计算用向量化运算替代逐行循环项目里技术指标计算统一用pandas的向量化操作避免用for循环逐行计算这在数据量较大的场景下性能差异非常明显。以MACD指标为例核心就是EMA的递归计算但用ewm方法一行就搞定。import pandas as pd def compute_macd(df, fast12, slow26, signal9): 计算MACD指标返回DIF、DEA和MACD柱状图值 close df[close_price].astype(float) # 用指数加权移动平均计算快速线和慢速线span即EMA周期 ema_fast close.ewm(spanfast, adjustFalse).mean() ema_slow close.ewm(spanslow, adjustFalse).mean() dif ema_fast - ema_slow # 差离值 dea dif.ewm(spansignal, adjustFalse).mean() # 信号线 macd_hist (dif - dea) * 2 # 柱状图国内习惯乘以2 result pd.DataFrame({ trade_date: df[trade_date], close_price: close, dif: dif, dea: dea, macd_hist: macd_hist, }) return resultewm的adjustFalse参数是指定使用递归算法计算EMA这个参数决定了EMA的初始值处理方式用默认的adjustTrue会导致前期指标数据差别很大。macd_hist乘以2是国内行情软件的习惯国内主流的看盘软件MACD柱状图高度都是DIF减去DEA的两倍如果直接输出原始差值画出来的图会和同花顺、通达信对不上这个细节最容易忽略。4. 项目运行指南从环境配置到一键跑通全流程4.1 环境准备与依赖安装这个项目对运行环境的要求不高Python 3.8以上版本就能运行。依赖集中写在requirements.txt文件里核心依赖包括requests、pandas、matplotlib、sqlite3标准库、schedule可选用于定时调度。建议新建虚拟环境后再安装避免把依赖装进系统Python环境。# 创建并激活虚拟环境Windows/Linux均可 python -m venv venv source venv/bin/activate # Windows下改为 venv\\Scripts\\activate # 安装依赖 pip install -r requirements.txt虚拟环境这一步看似多余实际能帮你避免很多版本冲突。我遇到过requests版本过旧导致TLS握手失败、pandas版本过高导致ewmAPI变化的问题用虚拟环境锁定版本能少踩一半的坑。4.2 初始化数据库与配置文件修改运行项目前需要做两件事初始化数据库结构、按需修改配置文件。config/settings.py里的关键配置包括行情接口地址、数据库文件路径、请求频率限制等。首次运行需要执行数据库初始化脚本。# 初始化SQLite数据库创建四张业务表 python scripts/init_db.py初始化脚本执行成功后会在项目根目录生成stock_data.db文件可以用任意SQLite可视化工具查看表结构。如果之前跑过项目、想重置数据只需要删除这个db文件再重新执行初始化即可这一点对反复折腾数据的开发者来说很友好。4.3 一键运行完整流水线项目提供了一个一键运行脚本run_pipeline.py它会按照「爬取列表 → 逐股拉取日K线 → 清洗入库 → 计算指标 → 输出分析结果」的顺序自动执行整条链路。在项目根目录运行下面的命令即可python scripts/run_pipeline.py脚本运行过程中会在控制台输出当前阶段和进度像这样的日志信息[2025-01-05 10:23:11] INFO: 开始拉取股票列表共 5124 条 [2025-01-05 10:24:47] INFO: 股票列表入库完成 [2025-01-05 10:24:50] INFO: 开始逐股拉取日K线当前进度: 1/5124 [2025-01-05 10:25:03] INFO: 数据清洗完成去重 34 条补全缺失值 128 处 [2025-01-05 10:25:10] INFO: 指标计算完成开始绘制图表默认配置下会拉取全市场5000多只股票的数据整个流程跑下来耗时较长如果你是第一次运行建议先在run_pipeline.py顶部找一个STOCK_LIST或test_mode相关配置按需设置成只拉取少量股票。具体做法是修改脚本里这个位置的参数# run_pipeline.py 中的核心调度逻辑节选 def main(): # 测试模式只处理前50只股票验证流程能跑通 test_mode True # 首次运行建议保持 True max_stocks 50 # 测试模式下最多拉取数量 if test_mode: stock_list fetch_stock_list().head(max_stocks) else: stock_list fetch_stock_list() for _, stock in stock_list.iterrows(): kline_data crawl_kline(stock[code], start_date2020-01-01) cleaned_data clean_kline(kline_data) save_to_database(cleaned_data) indicators compute_indicators(cleaned_data) save_indicators(indicators) generate_visualization_report()这段代码里的test_mode设计我比较欣赏它让新手不用等全量数据跑完就能验证整个流程。当你把test_mode改成False后脚本就会处理全市场数据这时候建议配合schedule模块在非交易时段运行避免占用交易时段的带宽和接口资源。4.4 常见问题与避坑指南问题一爬虫请求频繁超时或返回空数据现象是脚本运行到一半大量请求抛出Timeout异常或者返回的JSON里data字段为空。原因通常是请求频率过快触发了接口限流或者目标接口在非交易时段返回空数据。解决方法是调大rate_limit的间隔时间从默认的0.5秒调整到1秒以上同时在fetch_json里对空数据做单独判断如果连续10次返回空就暂停60秒再继续。问题二SQLite数据库文件越来越大查询越来越慢现象是跑完几次全量爬取后磁盘空间占用急剧膨胀查询日K线数据耗时明显变长。原因是数据库里积压了重复数据而且没有建索引。解决方法是先对表结构执行VACUUM清理空洞再对高频查询字段建立索引。日K线表需要做的索引是CREATE INDEX idx_kline_code_date ON daily_kline(stock_code, trade_date DESC);这个联合索引能让按股票代码和时间范围查询的效率大幅提升否则SQLite每次都要全表扫描数据量到几十万条以后性能会明显劣化。问题三计算出来的MACD值和看盘软件对不上现象是同样的行情数据自己算的MACD和同花顺、东方财富显示的值存在偏差尤其在K线图早期阶段差异明显。原因大概率是EMA的初始值处理方式不同软件通常会用第一天的收盘价作为EMA初值而ewm的递归算法默认从第一个有效值开始但adjust参数不同会改变前期结果。解决方法是先打印前20天的DIF值对比一下如果只有前期差异、后期收敛就说明算法正确不必过度纠结。问题四日期格式混乱导致清洗时报错现象是入库时报date字段格式不统一有的行是20250105有的是2025-01-05。原因是不同行情接口的日期格式约定不一致有的返回字符串有的直接返回毫秒级时间戳。解决办法是在清洗层做统一转换不能把脏格式直接入库统一转成YYYY-MM-DD字符串格式。这是我在实际运行中遇到的比较高频的问题建议在写爬虫时就把日期格式问题处理掉不要等到分析阶段再返工。5. 回测与分析实战用真实数据验证一个简单的均线策略5.1 回测引擎设计最小可用但五脏俱全项目自带的回测引擎结构精简但具备一个完整回测器该有的核心能力策略信号生成、持仓管理、收益统计。回测器输入是一段已经复权和平滑处理的K线数据输出是策略在该时间段内的收益曲线和统计指标。核心代码在analysis/backtest.py里。import pandas as pd import numpy as np class SimpleBacktest: def __init__(self, initial_cash100000, commission_rate0.0003): self.initial_cash initial_cash self.commission_rate commission_rate # 手续费万三 def run(self, df, strategy_signal): 执行回测。strategy_signal 是布尔序列True表示持仓False表示空仓。 简化处理每天收盘时按信号调仓不考虑涨跌停无法成交的情况。 cash self.initial_cash position 0 records [] for i in range(len(df)): price df.iloc[i][close_price] if strategy_signal.iloc[i] and position 0: # 买入全仓 position cash / (price * (1 self.commission_rate)) cash 0 elif not strategy_signal.iloc[i] and position 0: # 卖出清仓 cash position * price * (1 - self.commission_rate) position 0 total_value cash position * price records.append({ date: df.iloc[i][trade_date], total_value: total_value, }) return pd.DataFrame(records)这个回测器做了大量简化比如假设买卖都按收盘价成交、不考虑冲击成本、不考虑涨跌停封板无法买卖的情况。这些简化在实际策略验证时是可以接受的——先跑通逻辑后续再按需增加细节。commission_rate设为万三是国内券商常见的费率水平印花税在卖出端没有额外计算算是简化中的简化。5.2 双均线策略实现信号生成与评价指标双均线是量化入门最经典的策略逻辑很简单短期均线上穿长期均线时买入下穿时卖出。项目里有一个现成的策略实现示例可以直接拿来跑回测。def double_ma_strategy(df, short_window5, long_window20): 双均线策略5日均线上穿20日均线买入下穿卖出 df df.copy() df[ma_short] df[close_price].rolling(windowshort_window).mean() df[ma_long] df[close_price].rolling(windowlong_window).mean() # 金叉信号短期均线从下往上穿过长期均线 df[signal] 0 df.loc[df[ma_short] df[ma_long], signal] 1 # 用 diff 捕捉信号变化从0变1是买入点从1变0是卖出点 df[position] df[signal].diff().fillna(0) # 生成持仓信号True表示持仓 df[hold_signal] df[signal] 1 return df这里做了一个很关键的技巧用diff()来捕捉信号的变化点而不是直接拿signal去回测。原因是在回测循环里如果每天都判断「当前是否持仓」对于已经持仓的情况重复买入会导致仓位计算错误只有信号从0变成1时才需要真正执行买入操作。rolling(window5)计算的是最近5个交易日的简单移动平均线window参数调整策略灵敏度参数越小交易越频繁手续费消耗也越高。5.3 回测结果怎么看别只盯着收益率回测跑完后项目会在output/目录下生成收益曲线图和一份统计指标JSON文件。统计指标包括累计收益率、年化收益率、最大回撤、夏普比率、交易次数等。下面这段代码演示了怎么读取并输出这些关键指标import json with open(output/backtest_result.json, r, encodingutf-8) as f: result json.load(f) print(f累计收益率: {result[total_return]:.2%}) print(f年化收益率: {result[annual_return]:.2%}) print(f最大回撤: {result[max_drawdown]:.2%}) print(f夏普比率: {result[sharpe_ratio]:.2f}) print(f交易次数: {result[trade_count]}) if result[trade_count] 0: win_rate result[win_count] / result[trade_count] print(f胜率: {win_rate:.2%})看回测结果最容易犯的错误是只盯着累计收益率看到一个高收益就以为策略有效。有经验的开发者会先看最大回撤——如果回撤超过30%这个策略的资金曲线波动太大实际运行中很难拿得住。再看交易次数交易太频繁说明策略在震荡市里反复被套打手续费会吃光收益。夏普比率代表单位风险的收益补偿大于1才勉强及格大于2算不错。6. 二次开发实战把这个项目改造成你自己的量化分析工具6.1 替换数据源不再被单一接口绑定项目所有爬虫都继承自BaseCrawler数据源URL统一集中在settings.py这意味着替换数据源时只需要改配置或者新写一个爬虫子类。比如想把日K线数据源从A接口换成B接口常见的做法是新建一个crawler/daily_kline_v2.py继承BaseCrawler并重写parse方法然后修改run_pipeline.py中的调用处。6.2 新增技术指标在 indicators.py 里按既有风格扩展如果你想添加一个项目里没有的指标比如布林带或KDJ只需要在analysis/indicators.py里新增一个函数返回值统一为DataFrame结构列名包含trade_date和指标值。新增完成后在run_pipeline.py的分析阶段调用即可不需要改动其他模块。这种设计让扩展成本极低我实际改造时只花了几分钟就加上了一个布林带指标。6.3 把回测引擎替换成第三方库接上 backtrader项目自带的回测引擎偏教学如果你需要更严谨的回测能力比如滑点模型、多策略对比、参数寻优可以直接替换掉第五层的回测模块。最常见的做法是引入开源回测框架把项目清洗后的数据转换成该框架的feed格式。这个项目的价值在于它已经帮你把数据管道打通了你做替换时不用重新处理数据获取和清洗这一层。6.4 一个具体的改造案例增加行业板块轮动筛选我实际做的一个改造是增加行业维度筛选不直接全市场跑双均线而是先按行业分组只对近期涨幅排名靠前的行业里的股票做信号计算。这样做的目的是减少无效交易——双均线策略在弱势行业个股上会产生大量假信号。跑下来之后对比全市场回测交易次数明显减少胜率略有提升这就是通过项目二次开发获得的正向反馈。6.5 验证改造是否正确的习惯项目里有tests目录包含清洗模块和指标计算的单元测试。每次改造完我都会强制跑一遍pytest tests/确保自己改动的代码没有把原有功能破坏。这个习惯是血泪教训换来的——有次我改完数据清洗逻辑没跑测试直接跑全量回测结果发现清洗后数据量少了一半查了半天发现是去重逻辑把正常数据误删了。从那以后我每次改完代码都强制走一遍测试套件再跑小范围的test_mode验证确认无误后才做全量运行。希望这个项目的干净结构和清晰分层能帮你在二次开发时少走一些类似的弯路。本文还有配套的精品资源点击获取

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑