【AI量化交易实战】第05讲:小雅初试锋芒——Backtrader回测引擎入门实战
开篇导语上一讲小晴建好了数据管道本地数据库里已经躺着清洗干净的历史行情。现在最激动人心的环节来了——让小雅分析师把这些数据喂进回测引擎检验策略到底能不能赚钱。很多量化新手有一个共同的经历在炒股软件上看到一个金叉信号觉得这还不简单吗然后兴冲冲地写了几行代码假装自己在做量化。但专业的策略验证远不止金叉买入死叉卖出——你需要知道这个策略在什么市场环境下表现好、什么环境下会亏钱、最大回撤你扛得住吗、胜率和盈亏比分别是多少。这一讲小雅正式入驻分析师工位。我们将使用Backtrader——Python生态中最成熟的事件驱动型回测框架——跑通第一个完整的数据→信号→绩效闭环。学完本节后你将能够理解事件驱动回测的原理和Backtrader的核心架构独立编写并回测一个双均线交叉策略读懂年化收益、最大回撤、夏普比率风险调整后收益的衡量指标等核心指标对比多个经典策略在同一标的上的表现差异1 为什么需要回测——历史上赚不到钱实盘大概率也赚不到概念讲解回测Backtesting的本质是用历史数据模拟真实交易——假设你穿越回到2021年1月1日手里有100万全程按策略规则买卖到2024年12月31日账户还剩多少钱。这听起来简单但回测的坑远比想象的多常见陷阱表现后果未来函数策略在t日使用了t1日才公布的数据回测净值完美实盘一塌糊涂幸存者偏差回测股票池只包含现在还活着的股票忽略了已经退市的倒霉蛋过度拟合参数调得刚好贴合历史数据换一个时间段就失效摩擦成本忽略没考虑佣金、印花税、滑点回测盈利的策略实盘可能亏损一个专业策略的验证流程应该是策略想法 → 历史回测 → 样本外测试 → 模拟盘交易 → 小资金实盘 → 正式上线在本课程的体系中每一步都有对应的Agent在把关——小雅负责前两步小瑾在后面负责风险审核小彤负责策略上线后的执行监控。代码演示先安装并验证Backtrader环境 Backtrader环境验证与第一个Hello World Backtrader官网https://www.backtrader.com/ import backtrader as bt # 创建一个最小化的回测引擎 cerebro bt.Cerebro() # 打印Backtrader的基本信息 print(fBacktrader版本{bt.__version__}) print(核心概念速览) print( Cerebro → 回测引擎的大脑统筹整个回测流程) print( Strategy → 策略逻辑定义何时买卖) print( DataFeed → 数据输入为策略提供价格信息) print( Broker → 虚拟券商模拟账户和订单) print( Analyzer → 绩效分析输出收益、回撤等指标) # 验证数据加载能力 import pandas as pd print(f\nPandas版本{pd.__version__}) print(环境验证完成Backtrader就绪)关键要点Backtrader是事件驱动Event-Driven架构——每来一根新K线就触发一次策略逻辑模拟真实交易中的逐根K线判断回测结果好 ≠ 实盘能赚钱但回测结果很差一定说明策略有问题——先用回测做一票否决手续费必须建模——A股佣金万1.5 印花税0.05%卖出时单边征收两者合计对高频策略影响巨大样本外测试是把数据分成两段前段用来开发策略和调参数后段只能跑一次杜绝过度拟合2 双均线策略——小雅的第一个交易系统概念讲解双均线交叉策略是量化交易的Hello World——它足够简单但包含了完整策略的所有要素。策略逻辑只有两句话金叉买入短期均线如5日均线从下方上穿长期均线如20日均线视为上涨趋势确立买入死叉卖出短期均线从上方下穿长期均线视为上涨趋势结束卖出均线Moving Average的本质是对价格序列做平滑处理——计算过去N个交易日的收盘价平均值。短期均线MA5反应快但噪声多长期均线MA20反应慢但趋势稳定。两者的交叉点就是市场短期力量和长期力量的交汇处。双均线策略属于趋势跟踪类——它不会买在最低点也不会卖在最高点。它赚的是趋势形成后中间段的那部分利润并承受趋势反转时从高点回吐的一部分作为代价。代码演示下面用Backtrader完整实现一个双均线策略并加载真实A股数据回测import backtrader as bt import pandas as pd import akshare as ak from datetime import datetime class DualMAStrategy(bt.Strategy): 双均线交叉策略 —— 小雅的第一个交易系统 参数 short_period: 短期均线周期默认5日 long_period: 长期均线周期默认20日 params ( (short_period, 5), (long_period, 20), ) def __init__(self): 初始化计算两条均线 # 计算短期和长期简单移动平均线 self.short_ma bt.indicators.SimpleMovingAverage( self.data.close, periodself.params.short_period ) self.long_ma bt.indicators.SimpleMovingAverage( self.data.close, periodself.params.long_period ) # 记录交叉信号短期均线 - 长期均线正负号切换即为交叉 self.crossover bt.indicators.CrossOver(self.short_ma, self.long_ma) def next(self): 每根K线到来时触发——策略的核心逻辑 # 获取当前持仓状态 if not self.position: # 空仓状态 if self.crossover 0: # 金叉短期均线上穿长期均线 # 用全部资金买入 self.buy() self.log(f金叉信号触发买入价格: {self.data.close[0]:.2f}) else: # 已持仓 if self.crossover 0: # 死叉短期均线下穿长期均线 # 卖出全部持仓 self.sell() self.log(f死叉信号触发卖出价格: {self.data.close[0]:.2f}) def log(self, txt): 日志输出包含当前日期 dt self.datas[0].datetime.date(0) print(f{dt.isoformat()} - {txt}) # 回测主流程 def run_backtest(stock_code600519, start_cash100000.0): 运行双均线策略回测 参数 stock_code: 股票代码 start_cash: 初始资金默认10万元 # 第一步获取数据 df ak.stock_zh_a_hist(symbolstock_code, perioddaily, start_date20230101, end_date20250720, adjustqfq) df[日期] pd.to_datetime(df[日期]) df.set_index(日期, inplaceTrue) # 第二步将DataFrame转换为Backtrader的DataFeed data bt.feeds.PandasData( datanamedf, datetimeNone, # index已经是日期 open开盘, high最高, low最低, close收盘, volume成交量, openinterest-1 # A股无持仓量概念 ) # 第三步创建回测引擎 cerebro bt.Cerebro() cerebro.adddata(data) # 加载数据 cerebro.addstrategy(DualMAStrategy) # 加载策略 cerebro.broker.setcash(start_cash) # 设置初始资金 cerebro.broker.setcommission(commission0.00025) # 佣金万2.5 # 第四步添加分析器绩效指标 cerebro.addanalyzer(bt.analyzers.Returns, _namereturns) # 收益率 cerebro.addanalyzer(bt.analyzers.DrawDown, _namedrawdown) # 回撤 cerebro.addanalyzer(bt.analyzers.SharpeRatio, _namesharpe, riskfreerate0.03) # 夏普比率无风险利率3% cerebro.addanalyzer(bt.analyzers.TradeAnalyzer, _nametrades) # 交易统计 # 第五步执行回测 print(f\n{*50}) print(f回测标的{stock_code}) print(f策略双均线交叉MA{strategy_params[short]}/MA{strategy_params[long]}) print(f初始资金{start_cash:,.0f}元) print(f{*50}\n) start_value cerebro.broker.getvalue() results cerebro.run() end_value cerebro.broker.getvalue() # 第六步输出绩效报告 strat results[0] print(f\n{*50}) print(回测绩效报告) print(f{*50}) print(f初始资金: {start_value:,.2f} 元) print(f最终资金: {end_value:,.2f} 元) print(f总收益率: {(end_value/start_value - 1)*100:.2f}%) # 分析器结果 returns strat.analyzers.returns.get_analysis() drawdown strat.analyzers.drawdown.get_analysis() sharpe strat.analyzers.sharpe.get_analysis() trades strat.analyzers.trades.get_analysis() print(f年化收益率: {returns.get(rnorm100, 0):.2f}%) print(f最大回撤: {drawdown.get(max, {}).get(drawdown, 0):.2f}%) print(f夏普比率: {sharpe.get(sharperatio, 0):.2f}) total_trades trades.get(total, {}).get(total, 0) won_trades trades.get(won, {}).get(total, 0) print(f总交易次数: {total_trades}) print(f胜率: {(won_trades/total_trades*100) if total_trades 0 else 0:.2f}%) return cerebro # 执行回测 strategy_params {short: 5, long: 20} cerebro run_backtest(600519, start_cash100000.0) # 绘制回测结果图表 # cerebro.plot(stylecandlestick, volumeFalse) print(\n提示取消上面的一行注释可以显示K线图。)关键要点Crossover指标自动检测正负号切换——从负变正就是金叉返回值1从正变负就是死叉返回值-1Backtrader的next()方法是策略的核心——每根K线调用一次你在这里定义买卖逻辑佣金设置不能遗漏——万2.5的佣金看似不高但高频策略下20次交易就吃掉0.5%的利润参数5和20不是拍脑袋定的——应该用参数扫描Grid Search在不同参数组合上回测选样本外表现最好的3 解读绩效报告——什么才算好策略概念讲解回测跑完了屏幕上出现一串数字。但哪些数字是关键我们按重要性排序指标含义优秀标准警戒线夏普比率每承担一单位风险获得的超额回报1.0年化0.5还不如存银行最大回撤从最高点到最低点的最大亏损幅度20%35%大多数人在此之前会放弃年化收益率折算为每年平均的收益百分比10%5%跑不赢理财胜率盈利交易次数占总次数的比例40-60%正常范围30%策略逻辑可能有问题盈亏比平均单笔盈利 / 平均单笔亏损1.51.0一次亏损抵消多次盈利这里特别解释一下夏普比率Sharpe Ratio它把收益和风险放在同一个公式里比较。夏普比率 (策略年化收益率 - 无风险利率) / 年化波动率如果策略年化收益15%无风险利率3%约等于余额宝收益年化波动率12%夏普比率 (15%-3%)/12% 1.0。这意味着每承担1%的波动风险策略能带来1%的超额回报。一般认为夏普1是不错2是优秀3可能不可持续。代码演示下面写一个独立的绩效分析函数可以从任意回测结果中提取并格式化展示这些指标def analyze_performance(strat_result): 解析Backtrader回测结果输出格式化绩效报告 参数 strat_result: cerebro.run()返回的Strategy实例取第一个元素 # 提取各项分析器结果 returns strat_result.analyzers.returns.get_analysis() drawdown strat_result.analyzers.drawdown.get_analysis() sharpe strat_result.analyzers.sharpe.get_analysis() trades strat_result.analyzers.trades.get_analysis() # 构建报告 report { 年化收益率(%): round(returns.get(rnorm100, 0), 2), 最大回撤(%): round(drawdown.get(max, {}).get(drawdown, 0), 2), 夏普比率: round(sharpe.get(sharperatio, 0), 2), 总交易次数: trades.get(total, {}).get(total, 0), 盈利次数: trades.get(won, {}).get(total, 0), 亏损次数: trades.get(lost, {}).get(total, 0), } # 计算胜率 total report[总交易次数] won report[盈利次数] report[胜率(%)] round(won / total * 100, 2) if total 0 else 0 # 计算盈亏比 avg_win trades.get(won, {}).get(pnl, {}).get(average, 0) avg_loss abs(trades.get(lost, {}).get(pnl, {}).get(average, 0)) report[盈亏比] round(avg_win / avg_loss, 2) if avg_loss 0 else 0 # 格式化输出 print(\n * 50) print(策略绩效评估报告) print( * 50) for key, value in report.items(): print(f {key}: {value}) # 综合评级 if report[夏普比率] 1.5 and report[最大回撤(%)] 20: rating 优秀 - 收益风险比和回撤控制俱佳 elif report[夏普比率] 1.0: rating 良好 - 具备实盘潜力建议模拟盘验证 elif report[夏普比率] 0.5: rating 一般 - 收益风险比偏低可尝试优化参数 else: rating 较差 - 策略需要重新设计思路 print(f\n 综合评级: {rating}) return report # 快速对比同一策略在不同标的上的表现 print(\n提示可在不同股票上运行 run_backtest() 并调用 analyze_performance() 进行横向对比。) print(例如对比茅台(600519)、五粮液(000858)、招商银行(600036) 上的双均线策略表现差异。)关键要点夏普比率是最诚实的指标——它同时惩罚低收益和高波动不像单纯看收益率那么容易被美颜最大回撤决定了你能否坚持执行策略——回撤40%意味着100万变60万很少有人能不为所动胜率低的策略不一定差——趋势跟踪策略通常胜率只有35-40%但盈亏比3:1以上总体仍然盈利策略对比必须在同一时间段上进行——牛市中的任何策略都好看熊市才是真考验4 策略对比实验——为什么不同策略在不同市场表现各异概念讲解现在小雅已经掌握了回测技能接下来做一个重要的思维实验将双均线、买入持有、单均线三种策略放在同一时间段对比。这个对比实验想说明一个道理没有一种策略在任何市场环境下都表现最好。2023年茅台的走势可以分为三段1-3月单边上涨趋势策略和买入持有表现好4-7月横盘震荡双均线频繁假突破反复亏损8-12月单边下跌买入持有大幅亏损而趋势策略至少能在死叉时离场这就是第01讲说的策略与市场状态的匹配——理解这一点是后面学习多策略组合的理论基础。代码演示在同一张图表上对比三种策略的净值曲线import matplotlib.pyplot as plt import matplotlib matplotlib.rcParams[font.sans-serif] [SimHei] matplotlib.rcParams[axes.unicode_minus] False class BuyAndHold(bt.Strategy): 买入持有策略——第一天全仓买入最后一天卖出 def next(self): if len(self) 1: # 第一根K线 self.buy() class SingleMA(bt.Strategy): 单均线策略——价格上穿均线买入下穿卖出 params ((period, 20),) def __init__(self): self.ma bt.indicators.SimpleMovingAverage( self.data.close, periodself.params.period) self.crossover bt.indicators.CrossOver(self.data.close, self.ma) def next(self): if not self.position and self.crossover 0: self.buy() elif self.position and self.crossover 0: self.sell() def compare_strategies(stock_code, strategies_dict, start_cash100000.0): 对比多个策略在同一标的上的表现 参数 stock_code: 股票代码 strategies_dict: {策略名称: StrategyClass} 字典 start_cash: 初始资金 # 获取数据 df ak.stock_zh_a_hist(symbolstock_code, perioddaily, start_date20230101, end_date20250720, adjustqfq) results {} for name, strategy_cls in strategies_dict.items(): cerebro bt.Cerebro() df_copy df.copy() df_copy[日期] pd.to_datetime(df_copy[日期]) df_copy.set_index(日期, inplaceTrue) data bt.feeds.PandasData(datanamedf_copy, datetimeNone, open开盘, high最高, low最低, close收盘, volume成交量, openinterest-1) cerebro.adddata(data) cerebro.addstrategy(strategy_cls) cerebro.broker.setcash(start_cash) cerebro.broker.setcommission(commission0.00025) start_val cerebro.broker.getvalue() strat_results cerebro.run() end_val cerebro.broker.getvalue() total_return (end_val / start_val - 1) * 100 results[name] { 总收益率(%): round(total_return, 2), 最终资金: round(end_val, 2) } # 输出对比表格 print(f\n{*60}) print(f策略对比实验 - {stock_code}) print(f{*60}) print(f{策略名称:15} {总收益率(%):12} {最终资金(元):15}) print(- * 45) for name, result in results.items(): print(f{name:15} {result[总收益率(%)]:12.2f} {result[最终资金]:15,.2f}) return results # 三策略对比 strategies { 双均线(5/20): DualMAStrategy, 买入持有: BuyAndHold, 单均线(20): SingleMA, } compare_strategies(600519, strategies)关键要点策略之间的对比只能说明在这个历史时间段上谁表现好不能预测未来买入持有策略的回撤最大——因为没有止损机制跌多久就扛多久双均线策略在震荡市中表现最差——频繁的假交叉会反复割肉这是趋势策略的先天短板多策略组合趋势 震荡 套利能平滑收益曲线——这是第二阶段小雅进阶要学的核心内容实战总结本节小雅分析师完成了她的首次亮相核心成果如下回测引擎搭建Backtrader回测环境理解事件驱动的核心思想双均线策略实现完整的买卖逻辑体验数据→信号→绩效的闭环绩效解读掌握夏普比率、最大回撤、胜率、盈亏比四个核心指标策略对比用对比实验直观感受不同策略在不同市场状态下的表现差异常见误区提醒误区一把回测收益率直接当成预期收益。回测有各种隐性偏差幸存者偏差、未来函数实盘收益通常会打折扣误区二只优化收益率不理睬回撤。最大回撤50%的策略意味着你账户从100万跌到50万这个过程可能持续半年——你能拿住吗误区三回测一次就下结论。应该做鲁棒性检验换时间段、换股票、换参数组合分别回测看在多大范围内策略有效下一讲小雅将装备Talib技术指标库从手动写均线升级为调取数十种经典指标并学会识别K线形态、用成交量确认信号——让策略分析能力上一个台阶。下一篇预告第06讲小雅再升级——Talib指标库与K线形态量化均线只是冰山一角。TA-Lib提供了150种技术指标——MACD、RSI、布林带、ATR……小雅将把这些指标从看图经验变成可回测的策略组件。每周更新。关注专栏不错过后续内容。

相关新闻

口岸、海关、边检全域透明智慧管控汇报方案

口岸、海关、边检全域透明智慧管控汇报方案

核心技术底座:视频融合、视频孪生全域三维重构、透明全流程管理、身份指纹无感识别(纯视觉无源无感) 适用场景:航空口岸、陆路口岸、水运港口综合监管;海关旅检 / 货检、边检出入境核查、口岸安防联防联控 汇报定位&am…

2026/10/8 2:17:20 阅读更多 →
地面辐射防护原理与电子设备抗辐射技术

地面辐射防护原理与电子设备抗辐射技术

1. 地面辐射防护的基本原理 当高能粒子从太空进入地球大气层时,会与大气分子发生一系列相互作用。这些宇宙射线主要由质子(约85%)、α粒子(约12%)和重离子(约3%)组成,能量范围从几Me…

2026/10/6 11:15:33 阅读更多 →
低代码与零代码深度解析:核心差异、技术原理与选型指南

低代码与零代码深度解析:核心差异、技术原理与选型指南

1. 项目概述:从“造轮子”到“选轮子”的范式转移最近几年,无论是技术圈的朋友,还是业务部门的同事,嘴里都时不时会蹦出“低代码”和“零代码”这两个词。我身边就有产品经理在琢磨怎么用“微搭”快速搭个内部审批流,也…

2026/9/30 2:09:32 阅读更多 →

最新新闻

ManagedSpy实战:撬开.NET WinForms界面黑匣子的调试利器

ManagedSpy实战:撬开.NET WinForms界面黑匣子的调试利器

简介:ManagedSpy for .NET 4.5 是一款面向 .NET Framework 4.5 的托管代码调试与分析工具,旨在帮助开发者实时监控 .NET 应用运行时行为、内存分配与性能问题,无需重新编译或附加目标进程即可完成检查,适合需要深入理解运行时机制…

2026/10/14 7:02:34 阅读更多 →
Vue3 + VueFlow 企业级审批流程图设计器实战指南

Vue3 + VueFlow 企业级审批流程图设计器实战指南

做企业级审批流程设计器的时候,很多人第一反应就是“画节点连线条线”,但真上手之后才会发现,一个能落地到生产环境的流程图可视化,远不止画图这么简单。这篇文章我基于 Vue3 JavaScript 技术栈,用 VueFlow 这个开源库…

2026/10/14 7:02:34 阅读更多 →
OpenDriveVLA:统一视觉-语言-动作的自动驾驶认知模型

OpenDriveVLA:统一视觉-语言-动作的自动驾驶认知模型

1. 项目概述:当自动驾驶的“眼睛”开始“思考”与“规划”最近在刷论文预印平台时,看到一篇标题特别扎眼的 work:AAAI 2026 | 慕尼黑团队 OpenDriveVLA:多阶段训练范式,统一驾驶规划与 VQA 推理任务。光看标题里这几个…

2026/10/14 7:02:34 阅读更多 →
QT与QXlsx实现高效Excel操作的完整指南

QT与QXlsx实现高效Excel操作的完整指南

1. 项目概述:QT与QXlsx的Excel操作方案在数据处理领域,Excel文件的操作一直是刚需。传统方案依赖微软COM组件或Python库,但在C生态中一直缺乏优雅的解决方案。QT框架配合QXlsx库的出现,彻底改变了这一局面。这套组合不仅能实现基础…

2026/10/14 7:02:34 阅读更多 →
导师认可的AI论文写作软件综合榜(2026 优选)

导师认可的AI论文写作软件综合榜(2026 优选)

基于学术严谨性、写作辅助效率、界面友好度及用户反馈数据,以下是当前主流 AI 论文写作工具的权威测评榜单,按综合使用价值从高到低排序,并标注其核心功能与适用人群。🏆 第一梯队:全流程学术解决方案(★★…

2026/10/14 7:02:34 阅读更多 →
前端数学公式渲染实践:MathJax接入、配置与性能优化指南

前端数学公式渲染实践:MathJax接入、配置与性能优化指南

1. 从排版阵痛到第一行渲染:为什么前端数学公式绕不开MathJax大概每个做过在线教育、科研协作平台或者技术文档站点的前端开发者,都会有那么一段难熬的日子:需求方递过来一堆Word或者Markdown文档,里面全是排版好的数学公式&#…

2026/10/14 7:01:34 阅读更多 →

日新闻

AnyPS5通用适配层设计:兼容性与性能的工程取舍

AnyPS5通用适配层设计:兼容性与性能的工程取舍

1. 从"AnyPS5"这个名字说起:它到底想解决什么问题第一次看到"AnyPS5"这个标题,我脑子里冒出来的第一个念头是:这大概率是一个围绕"跨平台运行"或者"通用适配"做文章的项目。名字里的"Any"…

2026/10/14 0:00:41 阅读更多 →
Flutter跨平台开发实战:二手交易应用与HarmonyOS适配

Flutter跨平台开发实战:二手交易应用与HarmonyOS适配

1. 项目概述:Flutter跨平台二手交易应用开发作为一名长期从事移动应用开发的工程师,我最近完成了一个基于Flutter框架的二手物品交易平台项目。这个项目最吸引我的地方在于它完美结合了Flutter的跨平台优势与HarmonyOS的生态特性,实现了"…

2026/10/14 0:00:41 阅读更多 →
DFS算法解决飞机降落调度问题实战

DFS算法解决飞机降落调度问题实战

1. 项目背景与核心思路飞机降落问题是一个经典的调度优化场景,也是算法竞赛和面试中的高频题目。这个题目要求我们合理安排多架飞机的降落顺序和时间,确保所有飞机都能安全着陆而不发生冲突。在实际航空管制中,这类问题直接关系到飞行安全和机…

2026/10/14 0:00:41 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/14 3:30:28 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/13 16:22:04 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/14 3:29:58 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/13 22:01:27 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/13 14:57:39 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/12 18:11:17 阅读更多 →