简介:面向YOLO系列目标检测算法实践者的股票行情形态识别数据集,聚焦熊市与牛市走势图中的关键特征标注,可用于金融图表自动化分析、技术指标可视化检测等场景的算法训练与效果验证。包内共465个文件,包括232张jpg图像、232个配套txt标注文件及1个yaml配置文件,压缩包约8.56MB,解压即可直接使用。标注内容采用标准YOLO格式,记录类别索引、归一化后的目标框中心点坐标与宽高比例;数据集已按训练集与验证集划分妥当,免去自行整理样本的环节。整体兼容yolov5、yolov7、yolov8、yolov9、yolov10及yolo11,可直接将yaml路径指向本地目录进行模型训练与验证测试。目前已有56人浏览学习,适合需要快速获取带标签金融图表数据以跑通完整检测流程的入门及进阶开发者,是一份轻量、直接可用的数据集资源。
1. 把YOLO算法用在股票K线图上:232张熊市/牛市图像到底能训练出什么
如果你手头正好压着一个“yolo算法-股票数据数据集-232张图像带标签-熊市_牛市-stock-data-78an1.zip”,多半第一反应是丢进YOLOv8里跑一版,看它能不能从K线图里区分熊市和牛市。这个数据集非常小,只有232张图像和对应的标签,类别就两个:熊市(bear)、牛市(bull)。但恰恰是这种小样本金融图像,最容易让不了解数据结构的选手翻车:训练loss压得很低,验证mAP却像随机猜测;或者模型记住的是股票软件的背景色,根本不是K线形态。这篇文章会把从解压、核查标签、写data.yaml,到训练、增强、验证和踩坑的完整路径走一遍,适合想用真实小数据集落地YOLO检测的算法工程师,也适合搞量化的工程师快速判断这个方向值不值得投入。
先说结论:YOLO能跑,也能收敛,但232张图像决定它只能做有限趋势识别,不能当稳定交易信号。真正的功夫在标签核查和数据切分上,这两个环节不做好,后面全是玄学。
2. 拆解stock-data-78an1.zip:先弄清232张图像里的熊市牛市标签是检测还是分类
拿到带“带标签”三个字的压缩包,我建议先花3分钟把文件结构看清楚,而不是急着建环境。很多训练中途报错,都源于图像和标签目录对不上、标签文件是空的、类别顺序写反这类基础问题。
2.1 先解压并判断它是检测格式还是分类格式
解压命令如下,注意压缩包名是中文,建议用双引号包住。
unzip "yolo算法-股票数据数据集-232张图像带标签-熊市_牛市-stock-data-78an1.zip" -d stock_data cd stock_data find . -maxdepth 3 -type f | sort | head -20-d stock_data是指定解压目标目录,避免文件散落到当前目录;find只显示前20个文件,用来快速观察目录层级。常见结果有两种:
- 情况A:
images/train/xxxx.jpg和labels/train/xxxx.txt同名文件一一对应,这是标准的YOLO检测格式。 - 情况B:
train/熊市/xxxx.jpg、val/牛市/xxxx.jpg这种按类别建子目录的结构,是图像分类格式,对应的是YOLOv8-cls任务,不是检测任务。
如果解压后看到data.yaml或classes.txt,那基本可以确定数据集为YOLO训练准备过。classes.txt里通常写着两个类别名,顺序决定了标签文件里数字0和1分别代表谁。
2.2 用cat看一个标签文件,读懂YOLO坐标含义
先看类别定义文件:
cat classes.txt按常见命名习惯,输出可能是bear和bull两行。紧接着看一个具体标签:
cat labels/train/00001.txt如果输出只有一行,比如:
0 0.51 0.49 0.82 0.53这一行就是YOLO的标准标注格式:第一列是类别id,0对应classes.txt第一行的bear,1对应bull;后面四个数字分别是归一化之后的中心点x、中心点y、边界框宽度、边界框高度。归一化是指这些值全部除以图片自身的宽或高,取值范围在0到1之间。所以0.51 0.49表示边界框中心大概在图片正中间,0.82 0.53表示框的宽度占整张图宽度的82%,高度占整张图的53%。
如果这个框刚好覆盖整张K线图主体,说明数据集做的是“整图趋势分类”,用检测模型也能练,但边界框并没有提供额外位置信息。如果一行有多个对象,比如一张图里标注了多个K线形态,那才是真正的目标检测任务。
2.3 批量核对:图像和标签是否一一对应
训练前必须跑一遍对应关系检查,尤其要警惕空标签文件。用一个简短脚本处理:
from pathlib import Path img_dir = Path("stock_data/images/train") label_dir = Path("stock_data/labels/train") missing = [] for img in img_dir.glob("*.jpg"): label = label_dir / (img.stem + ".txt") if not label.exists(): missing.append(img.name) elif label.stat().st_size == 0: missing.append(img.name + " (empty)") print(f"missing or empty: {len(missing)}") for name in missing[:10]: print(" " + name)img.stem拿到的是去掉后缀的文件名,比如00001.jpg变成00001;再用它拼出00001.txt去检查。空标签文件会让YOLO在训练时跳过这张图,偶尔一两个没影响,如果跳过太多,实际训练样本会缩水。缺失标签则通常会在数据加载阶段直接报错。
2.4 检查图片尺寸和完整度,排除破图干扰
股票图表图片来源很杂,有截图、有程序生成图,宽度高度可能差别很大,甚至存在损坏文件。用以下代码快速扫一遍:
from PIL import Image from pathlib import Path for p in list(Path("stock_data/images/train").glob("*.jpg"))[:10]: with Image.open(p) as img: print(p.name, img.size, img.mode)img.size返回的是(宽, 高),img.mode通常是RGB或RGBA。如果大小严重不统一,建议在data.yaml里统一imgsz=640,让YOLO训练时自动缩放。如果某张图打不开,把该图和对应txt一起删掉,别让一张坏图把整个训练流程带崩。
2.5 把标注框画回原图,一眼看出标注质量
只看文本坐标很难发现问题,我的习惯是把边界框画回原图检查一遍。
import cv2 img = cv2.imread("stock_data/images/train/00001.jpg") h, w = img.shape[:2] with open("stock_data/labels/train/00001.txt") as f: for line in f: cls, xc, yc, bw, bh = map(float, line.split()) x1 = int((xc - bw / 2) * w) y1 = int((yc - bh / 2) * h) x2 = int((xc + bw / 2) * w) y2 = int((yc + bh / 2) * h) cv2.rectangle(img, (x1, y1), (x2, y2), (0, 0, 255), 2) cv2.imwrite("check_00001.jpg", img)这里把归一化坐标还原成像素坐标:(xc - bw/2) * w是框左上角的x像素位置,(xc + bw/2) * w是右下角的x像素位置。cv2.rectangle最后一个参数2是线条粗细。如果框的位置偏到图片外、框住的是坐标轴而不是K线主体,后面训练出来的模型就会学到错误位置信息,这类问题越早发现越好。
3. 用YOLOv8跑通熊市/牛市检测:最小可复现训练流程
确认数据格式没问题之后,下一步是把它跑起来。我推荐直接用ultralytics封装好的YOLOv8,训练命令短、日志清晰、验证工具也齐全。以下流程用232张图从零跑通一次完整训练。
3.1 创建独立Python环境并安装ultralytics
不建议直接往系统Python里装深度学习包,依赖冲突会浪费大量时间。我一般用conda建独立环境:
conda create -n stock-yolo python=3.10 -y conda activate stock-yolo pip install ultralyticspython=3.10是目前比较稳妥的版本选择;pip install ultralytics会连同PyTorch、OpenCV等必要依赖一起装好。装完后可以用python -c "import ultralytics; print(ultralytics.__version__)"验证是否成功。
3.2 编写data.yaml,确定类别顺序和数据集路径
YOLO训练的数据集描述文件是data.yaml,它不负责图像增强,只告诉训练器三件事:数据在哪、有几个类别、类别叫什么。
# data.yaml path: /absolute/path/to/stock_data train: images/train val: images/val nc: 2 names: 0: bear 1: bullpath最好写成绝对路径,避免相对路径在不同机器上解析不一致;train和val是相对于path的目录路径。nc必须和标签文件里实际出现的类别数一致,多余或缺少都会在训练前报错。names的索引顺序必须和标签文件第一列的数字对应,如果标注文件里写的是0表示熊市,那names[0]就必须是bear,否则验证阶段无法看懂混淆矩阵。
3.3 用预训练权重启动第一次训练
最小可复现命令如下:
yolo detect train \ data=data.yaml \ model=yolov8n.pt \ epochs=100 \ imgsz=640 \ batch=16 \ patience=20 \ project=stock_runs \ name=exp1 \ seed=0 \ cache=True逐项说明参数:
model=yolov8n.pt是加载YOLOv8n的COCO预训练权重。首次运行会自动下载权重文件,网络慢时也可以先把yolov8n.pt放到当前目录。小数据集迁移学习比从零训练稳定得多。imgsz=640是训练输入尺寸。232张股票图通常不是正方形的,YOLO会先按比例缩放再填充到640x640。batch=16看显存决定。如果手里是V100、RTX3090这类卡,16没问题;如果只有8GB显存,改成4更稳妥。patience=20表示连续20个epoch验证指标没有改善就提前停止,避免空跑时间。seed=0固定随机种子,保证同一条数据能复现结果。cache=True是将图像缓存进内存,232张图很小,加载速度提升明显。
一个epoch大约只有232/16≈15个batch,100个epoch很快就会跑完。训练过程中会看到类似下面的输出:
Epoch 10/100 GPU_mem: 6.2G box_loss: 1.12 cls_loss: 0.87 dfl_loss: 1.01 mAP50: 0.62 mAP50-95: 0.393.4 训练期间该看哪些数字
很多人一看到loss下降就开心,但小数据集上loss下降不一定是好事。需要同时看box_loss、cls_loss、dfl_loss这三个YOLO损失函数分量,以及验证集的mAP50和mAP50-95。
box_loss衡量边界框回归误差,cls_loss衡量分类错误,dfl_loss是分布焦点损失,主要影响边界框边缘精度。如果三个loss都在降,但mAP50不涨,说明模型在训练集上记忆增强后的图像,没有学到可泛化的规律。对熊市/牛市二分类任务,mAP50比mAP50-95更直观,因为类别少且边界框本身可能很粗糙,mAP50-95偏低属于正常现象,不必焦虑。
4. 数据切分与增强:让232张图真正用出效率
小数据集最怕的不是模型不够大,而是数据划分不科学和增强策略乱用。这一章直接解决这两个问题。
4.1 如果压缩包未划分train/val,先做分层切分
很多下载来的数据打包时只有一份图像和标签目录,没有train/val区分。这种情况下不能直接训练,需要先切分。下面脚本把232张图按7:3切分到train和val目录:
import random import shutil from pathlib import Path root = Path("stock_data") all_images = list(root.glob("*.jpg")) if (root / "images").exists() is False else list(root.glob("images/*.jpg")) labels = {img.with_suffix(".txt") for img in all_images} random.Random(42).shuffle(all_images) train_imgs = all_images[: int(len(all_images) * 0.7)] val_imgs = all_images[int(len(all_images) * 0.7):] for phase, imgs in [("train", train_imgs), ("val", val_imgs)]: img_dst = root / "images" / phase lbl_dst = root / "labels" / phase img_dst.mkdir(parents=True, exist_ok=True) lbl_dst.mkdir(parents=True, exist_ok=True) for img in imgs: txt = img.with_suffix(".txt") if not txt.exists(): continue shutil.move(str(img), str(img_dst / img.name)) shutil.move(str(txt), str(lbl_dst / txt.name))这个脚本的关键点是标签和图像一起移动,避免移动了图像漏掉标签。random.Random(42).shuffle固定伪随机种子,保证每次切分结果一致。
但如果文件名带有日期或者原本就是连续K线窗口,我更建议按时间顺序切分,而不是随机打乱。比如文件名是20240101_0001.jpg这种,可以把前70%的时间区间作为train,后30%作为val,避免训练集和验证集来自同一段行情的相邻窗口。
4.2 YOLO默认增强对股票图是危险的,要显式关掉
YOLOv8自带一整套数据增强,默认值针对自然图像设计,用在K线图上会把关键语义破坏掉。常见的增强坑如下:
fliplr水平翻转:等于把时间轴倒过来,K线图的时间顺序全乱,牛市变镜像,模型学到的是错误的时间关系。flipud垂直翻转:等于把价格坐标倒置,涨跌方向直接反转,后果更严重。degrees旋转:K线图的横轴是时间、纵轴是价格,旋转几度就破坏了坐标语义。hsv_h、hsv_s、hsv_v颜色增强:会改变K线的红绿颜色。股市里红绿就是涨跌信号,把红K线变成绿K线等于把看涨样本变成看跌样本。mosaic马赛克拼接:把四张图拼在一起,K线的时间连续性彻底断裂,模型会用碎片化的价格序列做判断,增加过拟合风险。
所以,我训练股票类数据时会显式把这些增强关掉,只保留轻微缩放:
yolo detect train \ data=data.yaml \ model=yolov8n.pt \ epochs=100 \ imgsz=640 \ batch=16 \ fliplr=0.0 \ flipud=0.0 \ degrees=0.0 \ hsv_h=0.0 \ hsv_s=0.0 \ hsv_v=0.0 \ scale=0.1 \ mosaic=0.0 \ seed=0scale=0.1允许图片做10%以内的缩放,用来提高模型对图表缩放比例的鲁棒性。其他增强参数全部归零,宁可少一点增强,也不能让模型学错方向。
4.3 232张图选什么模型:优先YOLOv8n或YOLOv8s
模型越大不代表效果越好,尤其在只有232张图的数据集上。模型容量越大,过拟合风险越高。各版本对比如下:
| 模型版本 | 参数量量级 | 232张图上的训练成本 | 我的建议 |
|---|---|---|---|
| YOLOv8n | 约3M | 几分钟级别,低显存友好 | 首选 |
| YOLOv8s | 约11M | 速度稍慢,精度可能略高 | 可以对比 |
| YOLOv8m | 约25M以上 | 显存和耗时明显上涨 | 不建议 |
| YOLOv8x | 约60M以上 | 极容易过拟合 | 不要用 |
这是模型复杂度的参数量级参考,不同发布版本可能有差异。在232张图、两个类别的小任务上,YOLOv8n是性价比最高的起点。先把n跑通拿到基准mAP,再决定要不要用更大的模型去试,而不是一上来就开大模型追求精度的玄学。
5. 避坑指南:232张股票数据集训练YOLO时最常见的5个问题
这里记下我自己在这个数据集上反复踩过的坑,每条按现象、原因、解决的顺序展开,遇到类似情况可以直接对照排查。
5.1 现象:训练loss降到0.02,验证mAP却只有0.5左右
原因:最典型的是数据切分泄了未来信息。如果原始图像是按K线窗口连续截取的,随机打乱后,相邻窗口可能训练验证各占一部分,模型在训练时“见过”验证集同一段行情的延续部分,验证分数虚高;但loss极低而mAP不涨,则是另一种情况,说明模型记住了图表的背景布局,而不是K线形态。
解决:先确认文件名是否有时间编号。如果文件名是000001.jpg、000002.jpg这类顺序号,按连续块切分,例如前160张作训练、后72张作验证,不随机打乱。如果怀疑模型学到背景,回到第2.5节,把预测框画回原图,看边界框落在K线区域还是落在空白区域。
5.2 现象:熊市类别召回率接近0,预测结果几乎全是牛市
原因:类别不均衡。232张图里如果牛市180张、熊市52张,模型对熊市的先验概率很低;加上默认置信阈值是0.25,低置信度的熊市预测会被直接过滤掉。
解决:先降低置信阈值看召回能否恢复:
yolo detect val \ model=stock_runs/exp1/weights/best.pt \ data=data.yaml \ conf=0.1conf=0.1让模型把更多低置信度的框保留下来,如果熊市召回明显上升,说明模型并不是完全学不会,只是置信度偏低。再从训练集里对熊市类样本做重复采样,或给熊市类别更高的损失权重,都能缓解不均衡。
5.3 现象:同样的命令训练两次,mAP相差十个百分点
原因:232张图的训练集太小,模型初始化、数据增强的随机性、GPU浮点累加差异都会被放大。即使设置了seed=0,在多进程训练时仍可能出现微小的不一致。
解决:用同一个best.pt做多次验证,不要多次训练后挑最高的结果当算法真实水平。我一般会在同一份数据上跑5个不同seed,取mAP的中位数作为最终基准。取最大值是自欺欺人,取中位数才能判断方案是否稳定。
5.4 现象:模型把整张图框成牛市,实际K线早就走熊
原因:如果标签里的边界框覆盖整张K线图,包括坐标轴、股票软件logo、空白区域,模型很容易学到“这张图的整体配色更像牛市”这类表面特征,而不是K线本身的形态变化。
解决:把标注范围裁到K线主体区域,去掉坐标轴和图例。如果压缩包本身提供的就是整图级框,最简单的做法是裁剪图片后再重新生成标签,或者干脆把任务从检测改成分类,见第6章的YOLOv8-cls方案。对股票趋势识别来说,分类建模往往比检测建模更贴近问题本质。
5.5 现象:训练中途报FileNotFoundError或AssertionError: label not found
原因:数据集目录是中文名,某些YOLO版本在Windows或旧版Linux下对中文路径处理不友好;也可能图片是.png而标签脚本找的是.jpg,大小写不一致导致匹配失败。
解决:把数据目录改成纯英文路径,比如/data/stock_data/;用第2.3节的脚本重新核对一次标签完整度。另一个常见问题是解压时部分文件损坏,重新解压并覆盖全部文件即可。处理完再执行一次训练,基本能消除这类环境性报错。
6. 验证与进阶:用滑窗预测跑通真实K线,再决定要不要用分类模式
训练结束后,best.pt的mAP只是一个数字,真正要看的是在连续K线上能不能给出合理判断。先用自带的验证命令导出关键图表:
yolo detect val \ model=stock_runs/exp1/weights/best.pt \ data=data.yaml \ imgsz=640验证完成后,到输出目录里打开confusion_matrix.png和PR_curve.png。混淆矩阵里各列之和不需要完全一致,毕竟熊市和牛市样本数不同,重点看熊市那一行的召回是否过低。PR曲线则能帮你判断置信阈值应该设在多少,而不是默认的0.25。
对一整根长K线图做预测,建议用滑窗方式切成YOLO能接受的尺寸,避免直接resize把K线压扁。
import cv2 from ultralytics import YOLO model = YOLO("stock_runs/exp1/weights/best.pt") img = cv2.imread("long_chart.png") win_w = 640 step = 320 results = [] for x in range(0, img.shape[1] - win_w, step): crop = img[:, x:x + win_w] res = model.predict(crop, conf=0.25, imgsz=640) if len(res[0].boxes) > 0: cls_id = int(res[0].boxes.cls[0].item()) results.append((x, "bull" if cls_id == 1 else "bear")) print(results)step=320让相邻窗口有50%重叠,避免某个趋势被窗口边界切断。相邻窗口如果出现不同类别,以置信度更高的一次为准。这个滑窗结果已经可以作为最原始的看多/看空信号来源,但要注意它只适合作为技术分析辅助,不能直接当交易决策。
如果你发现数据集里的边界框本来就是整图框,没有具体检测目标,那我更建议换成YOLOv8-cls分类模式。只需要把图片按类别放进目录:
stock_data/classify/train/bear/*.jpg stock_data/classify/train/bull/*.jpg stock_data/classify/val/bear/*.jpg stock_data/classify/val/bull/*.jpg然后执行:
yolo classify train \ model=yolov8n-cls.pt \ data=stock_data/classify \ epochs=50 \ imgsz=224 \ batch=16分类模式不依赖边界框,完全按整图语义做判断,对熊市/牛市这种整体趋势问题往往更稳。232张图做二分类,几十个epoch就能看到明确结果。
我现在的习惯是,拿到任何股票类YOLO数据集,先问自己一句:这到底是一个检测问题,还是一个分类问题?想清楚这个问题,比换什么预训练模型、调什么学习率都重要。花十分钟确认标签结构和问题边界,能省下后面一整天的调参时间。希望帮到你。
本文还有配套的精品资源,点击获取