Dev#14
Merged
Merged
Conversation
- All Phase headers (0-4) marked ✅ - All milestones M1-M6 marked completed - All 16 task tickets (T01-T10, R1-R6) marked completed with evidence - Appendix A audit findings updated with fix status per item - Test coverage section updated: 730 → 753 tests (+23 new) - Fixed outdated LiveStoreBase.start() description - Added completion date header
- cerebro.py/strategy.py: 异常可见性改进(try/finally, 静默except改为日志) - 8个核心模块: 清理23处commented-out print/debug残留 - feed.py: 修正错误FIXME注释(sessionstart/sessionend实际被使用) - 代码质量改进优化.md: 新增Step5提交流程,明确已有测试不可修改 pytest tests -n 8: 760 passed, 1 skipped, 0 failed
- order.py: 删除7行commented-out旧代码块, 修正todo注释为正式文档注释 - brokers/bbroker.py: 清理11处(commented-out函数/变量/print/stale TODO) - functions.py: 删除1处stale todo注释 - indicators/sma.py: 删除2处DEBUG commented-out print块 - indicators/basicops.py: 清理1处commented-out print + 无用注释 pytest tests -n 8: 760 passed, 1 skipped, 0 failed
analyzers: annualreturn.py(2处dead code+todo), sharpe.py(3处TODO+Hack), vwr.py(1处print), logreturnsrolling.py(3处print) feeds: pandafeed.py(1处print), yahoo.py(2处todo), rollover.py(1处todo) plot: plot.py(26处print/Hack注释), locator.py(1处print) core: analyzer.py(1处Hack→正式注释), dataseries.py(2处todo), position.py(1处todo) 剩余10处均为三引号注释块内/合法FIXME/正常代码注释,不属于清理范围 pytest tests -n 8: 760 passed, 1 skipped, 0 failed
…eption as e with debug logging Systematically replaced all silent exception swallowing patterns across 20 files: - Core: feed.py(3), parameters.py(4), functions.py(5), lineroot.py(2), linebuffer.py(13) - Core: lineiterator.py(14), metabase.py(5), lineseries.py(4) - Indicators: sma.py(1), ema.py(1) - Observers: trade_logger.py(4) - Reports: performance.py(7) - Plot: plot.py(2), plot_plotly.py(1) - Live: btapistore.py(3), btapifeed.py(2), btapibroker.py(1) - Bokeh: app.py(4), tabs/performance.py(2), tabs/metadata.py(2), tabs/config.py(1), analyzers/recorder.py(1), utils/helpers.py(1) Each file now has import logging and logger = logging.getLogger(__name__). All blocks use logger.debug() with descriptive messages including the exception. No behavior changes - all catch blocks retain their original control flow. Test baseline maintained: 760 passed, 1 skipped.
P0 fixes: - performance.py: truthy checks (if value) → is not None, fixes zero-value (0.0) silent skips - performance.py: _get_analyzer_result exact match first, substring fallback second - performance.py: _get_backtest_days bare except → except Exception as e with logging - charts.py: plot_return_bars/get_periodicity bare except → debug logging P1 fixes: - performance.py: get_risk_metrics accepts pre-computed pnl_metrics to avoid double computation - charts.py: close_all guarded with MATPLOTLIB_AVAILABLE check - charts.py: removed dead hasattr(start_date, 'days') branch in _get_periodicity - charts.py: added module-level logger 760 passed, 1 skipped
P0 fixes: - reporter.py: HTML模板truthy检查 → is not none,修复0.0值显示为N/A - reporter.py: print_summary truthy检查修复,提取_fmt_metric helper消除重复 P1 fixes: - reporter.py: 移除_user/_memo实例状态,user/memo作为参数传递给_build_context - reporter.py: Jinja2 Environment添加autoescape=True防止XSS - reporter.py: base64图片数据标记|safe避免autoescape破坏 可测试性补强: - 新增32个edge case单元测试 (tests/unit/reports/test_performance_edge_cases.py) 792 passed, 1 skipped
P0 fixes: - _infer_tick_direction: truthy检查 → is not None,修复ask_price/bid_price=0.0被跳过 P1 fixes: - _order_to_payload: price or fallback → 显式None检查,修复price=0.0被忽略 - _coerce_text/_safe_text_attr/_ctp_field_to_dict: bare except添加logger.debug 可测试性补强: - 新增33个edge case单元测试 (tests/unit/stores/test_btapistore_edge_cases.py) - _infer_tick_direction零值价格测试 - _coerce_text边界值测试 (None, bytes, GBK, numeric) - _split_ctp_symbol格式测试 (dot, underscore, plain, empty, None) - _normalize_ctp_instrument CZCE规范化测试 - _ctp_field_to_dict过滤测试 (private, callable, SWIG attrs) 825 passed, 1 skipped
P0 fixes: - _validate_order/_reject_order/_order_runtime_details: price truthy-or → 显式is not None 修复price=0.0被静默替换为created.price的问题 P1 fixes: - _refresh_account: bare except → 添加logger.debug错误可见性 - _sync_positions: bare except → 添加logger.debug错误可见性 可测试性补强: - 新增20个edge case单元测试 (tests/unit/brokers/test_btapibroker_edge_cases.py) - 零值价格处理 (price=0.0不被替换) - _refresh_account/_sync_positions错误日志验证 - _execution_datetime格式解析 (datetime/time/compact/None/empty/invalid) - _position_key数据对象提取 (_name/_dataname/p.dataname/repr) - _should_refresh节流逻辑 (zero/negative/recent/old) 845 passed, 1 skipped
P0 fixes: - get_equity_curve: start_cash truthy-or → 显式is not None检查 修复start_cash=0.0被静默替换为100000的问题 (2处) P1 fixes: - get_kpi_metrics: sqn_score=None时sqn_human应为'N/A'而非None 移除冗余guard,sqn_to_rating已正确处理None 可测试性补强: - 新增40个edge case单元测试 (test_performance_calculator_edge_cases.py) - 零值start_cash处理 (start_cash=0.0不被替换为100000) - risk_metrics零回撤/缺失analyzer - trade_metrics零交易/全胜场景 - kpi_metrics缺失/NaN/None SQN - sqn_to_rating 16个边界值+inf/-inf - analyzer精确匹配优先于子串匹配 - strategy_info/data_info无数据场景 - profit_factor零亏损/正常计算 884 passed, 1 skipped (1 pre-existing flaky in parallel)
P1 fixes (8处bare except添加logger.debug): - _collect_indicators内层循环: 属性访问失败现可见 - _extract_indicator_values内层循环: 指标线读取失败现可见 - _save_position_snapshot: 快照文件写入失败现可见 - _insert_order_mysql: MySQL订单插入失败现可见 - _insert_trade_mysql: MySQL成交插入失败现可见 - _insert_position_mysql: MySQL持仓插入失败现可见 - _insert_indicator_mysql: MySQL指标插入失败现可见 - _insert_signal_mysql: MySQL信号插入失败现可见 可测试性补强: - 新增14个edge case单元测试 (test_trade_logger_edge_cases.py) - _collect_indicators属性访问异常日志验证 - _extract_indicator_values指标线读取异常日志验证 - 防御性访问器 (_store_provider/_session_id/_get_datetime_str/_get_strategy_name) - _safe_order_inf P1 fixes (8处bare except添加logger.debug): - _collect_indicators内层循环: 属性访问失败现可见 - _extrassed, 1 skipped
P1 fixes (pandafeed.py, 4处bare except添加logger.debug): - PandasData.start(): to_numpy()失败现可见 - PandasData.start(): datetime转换三级降级链现可见 (ts.to_pydatetime → ts.dt.to_pydatetime → element-wise) - PandasData.start(): datetime预计算整体失败现可见 charts.py审查通过: 所有exception handler已有logger.debug,无P0/P1问题 可测试性补强: - 新增10个edge case单元测试 (test_pandafeed_edge_cases.py) - PandasData基本加载 (简单/单行/datetime列) - 列名自动检测 (nocase=True/False, 缺失列) - numpy转换失败日志验证 - PandasDirectData itertuples加载 - 零值OHLCV正确加载 (close=0.0, volume=0) 909 passed, 1 skipped
清理内容: - indicators/mabase.py: 删除263行注释掉的手动MovingAverage注册系统(已被__init_subclass__自动注册取代) - plot/plot.py: 删除380行注释掉的legacy run_cerebro_plot函数 + 1个debug print语句 - brokers/bbroker.py: 删除26行注释掉的__getattribute__重写(已被get_cash/set_cash取代) - comminfo.py: 删除9行注释掉的__getattribute__重写(已被_StockLikeDescriptor取代) 验证: pytest tests -n 8 → 909 passed, 1 skipped
- commissions/dc_commission.py: ComminfoDC的旧版重复实现,含bug(self.self._creditrate) - 该文件未被任何模块引用,comminfo.py中已有正确的ComminfoDC实现 - 同时确认utils/flushfile.py被tests/testcommon.py引用(保留) - P2: comminfo.py子类中get_margin重复逻辑已记录但不改(避免破坏外部继承) 验证: pytest tests -n 8 → 909 passed, 1 skipped
- order.py L563: 'not self.price' → 'self.price is None' 避免price=0.0被当作未设置 - bbroker.py L1407: 'order.pannotated' → 'order.pannotated is not None' 避免收盘价0.0被忽略 - 新增8个边界测试覆盖零价格保留、None回退、pannotated语义 验证: pytest tests -n 8 → 917 passed, 1 skipped
- comminfo.py getsize(): price=0时直接返回0,避免cash//0 ZeroDivisionError - comminfo.py getsize(): margin=0时直接返回0,避免cash//0 - percents_sizer.py _getsizing(): close_price=0时返回0,避免除零 - 新增9个边界测试覆盖零价格、零保证金、正常计算场景 验证: pytest tests -n 8 → 926 passed, 1 skipped
- leverage.py: portfolio value=0时返回leverage=0,避免ZeroDivisionError - logreturnsrolling.py: 添加logger.debug到bare except块,log计算失败可追踪 - annualreturn.py: 添加logger.debug到日期转换bare except块 - 新增7个边界测试覆盖零值杠杆、负值、log失败日志 验证: pytest tests -n 8 → 933 passed, 1 skipped
- leverage.py: portfolio value=0时返回leverage=0,避免ZeroDivisionError - drawdown.py: peak=0时返回dd=0,避免ZeroDivisionError - timereturn.py: _value_start=0时返回return=0,避免ZeroDivisionError - calmar.py: 捕获ZeroDivisionError和ValueError(负值log),返回rann=0 - logreturnsrolling.py: bare except块添加logger.debug - annualreturn.py: bare except块添加logger.debug - 新增17个边界测试覆盖零值杠杆、零峰值回撤、零起始收益、Calmar边界 验证: pytest tests -n 8 → 943 passed, 1 skipped
- vwr.py: pi=0时VWR期间收益计算返回0,避免ZeroDivisionError - vwr.py: sdev_max=0时返回vwr=0,避免ZeroDivisionError - 捕获TypeError防御pn=None残留 验证: pytest tests -n 8 → 943 passed, 1 skipped
- observers/drawdown.py: peak=0时返回dd=0,避免ZeroDivisionError - analyzers/vwr.py: pi=0时期间收益返回0,sdev_max=0时返回vwr=0 验证: pytest tests -n 8 → 943 passed, 1 skipped
P0 修复:
- basicops.py ExponentialSmoothing.once(): 移除错误的 prev<=0.0 判断,零/负值是合法的金融数据
- basicops.py Average.once(): 预填充数组改用 NaN 替代 0.0,防止 warmup 期间产生错误信号
P1 修复:
- sma.py: import math 从 once() 方法体内移至模块顶部
- sma.py next(): 移除无效的 NaN 比较死代码 (sma_value == float('nan') 永远为 False)
- sma.py/basicops.py: 4 处 bare except Exception 增加 logger.debug 日志,提升异常可见性
统一修复 MA 相关指标的 once() 方法中数组预填充值:
- ema.py: larray.append(0.0) → larray.append(float('nan'))
- dema.py: DEMA + TEMA 两处 larray.append(0.0) → float('nan')
- wma.py: larray.append(0.0) → float('nan')
- smma.py: larray.append(0.0) → float('nan')
- basicops.py ExponentialSmoothing.once(): larray.append(0.0) → float('nan')
原因: 预填充 0.0 在 warmup 期间可能被策略误当作有效指标值,
触发错误的交易信号。NaN 比较永远返回 False,安全地阻止提前交易。
将 SMA 从 ~360 行简化至 ~130 行,移除不必要的复杂度: - 移除 numpy 依赖(sum()/period 足够准确) - 移除结果缓存机制(_result_cache, _cache_size_limit, _vectorized_enabled) - 移除 _calculate_sma_optimized 和 _calculate_sma_manual 多层 fallback - 移除 3 种获取价格的冗余方法和过度 hasattr 防御检查 - 移除 deque 滚动窗口(改用每 bar 重新计算,避免浮点漂移) - 简化 __init__: 仅调用 super().__init__() - 简化 nextstart: 委托给 next() - 简化 next: 直接 sum(last_period_prices) / period - once() 保持不变(已经简洁) - 保留 logger.debug 异常可见性(第一轮成果)
将 ExponentialSmoothingDynamic.__init__() 内定义的 Alpha1Line 类 提取为模块级 _Alpha1Line 类: - 避免每次实例化 ExponentialSmoothingDynamic 时创建新类对象 - 移除内部 'from . import Indicator' 延迟导入(模块顶部已有) - 提高可读性和可测试性 - 行为完全不变
…cator files
Changed array pre-fill pattern from 0.0 to float('nan') in once() methods
across 28 indicator files. This prevents warmup-period zeros from being
mistaken for valid indicator values, which could trigger incorrect signals.
Files changed: momentum.py, bollinger.py, deviation.py, dpo.py, hma.py,
kama.py, hurst.py, tsi.py, trix.py, aroon.py, macd.py, priceoscillator.py,
pivotpoint.py, williams.py, envelope.py, kst.py, rsi.py (RSI line only),
atr.py, directionalmove.py, hadelta.py, heikinashi.py, myind.py, ols.py,
percentchange.py, prettygoodoscillator.py, accdecoscillator.py,
awesomeoscillator.py, dma.py, zlema.py, ultimateoscillator.py
Intentionally kept 0.0 pre-fill for:
- stochastic.py: %K/%D warmup 0.0 used by downstream strategies
- crossover.py: 0.0 = 'no crossover' is a valid signal value
- rsi.py UpDay/DownDay/Bool: 0.0 = 'no movement' is semantically correct
All 943 tests pass.
Collapse ExponentialSmoothingDynamic alpha-source branching into a single _alpha_is_line flag computed in __init__. Changes: - compute _alpha_is_line once from alpha array capability - reuse one formula path in next() - reuse one formula path in once() - preserve existing behavior for both line-based and scalar alpha This removes duplicated hasattr-based dispatch logic and keeps the runtime behavior easier to reason about. Verification: pytest tests -n 8 => 943 passed, 1 skipped.
… edge-case hardening - P0: ComminfoDC.get_credit_interest: .seconds → .total_seconds() — was losing the days component for multi-day durations - P1: BarPointPerc: guard against parts ≤ 0 (degenerate OHLC data) - P1: ComminfoFundingRate.get_credit_interest: robust try/except fallback chain instead of fragile getattr(..., [price])[0] - Added 9 regression tests in test_comminfo_fillers_edge_cases.py - pytest tests -n 8: 1003 passed, 1 skipped
Move the entire Closed-trade statistics body (streak / pnl / won-lost / long-short / length / length-won-lost / length-long-short updates) out of notify_trade into _on_trade_closed(trade). notify_trade is now a trivial dispatcher on justopened/Closed. Logic moved verbatim (de-indented one level); no behavior change. notify_trade CC E(32) -> A(3); _on_trade_closed D(30). Verified: import clean, ruff/black green, analyzer + trade functional tests (238) pass.
Pull the execution-mode flag resolution (runonce/preload/exactbars/replay/ live) plus writer instantiation out of run() into _resolve_run_flags(). run() keeps its channel/empty bail-out, signal-strategy setup and single-run-vs- optimization dispatch. Logic moved verbatim; no behavior change. run CC F(41) -> E(32); _resolve_run_flags B(10). Verified: import clean, ruff green, cerebro/run/optimization/writer/replay tests (224) pass.
Update the S5 table and metrics: 7 high-complexity functions now reduced (runstrategies 57->37, _next_signal 84->28, run 41->32, SharpeRatio.stop 40->2, inherit_from 33->5, _derive_params 30->14, notify_trade 32->3). Remaining F-rated functions (process_orderbook / _runnext / _periodset / line-system __init__/donew/_once/__setitem__/__setattr__/_register_line_ assignment_child / plot) stay deferred with documented rationale.
Extract the dual-side and net portfolio-value accumulation loops into _get_value_dual_side / _get_value_net. Each returns (direct, pos_value, unrealized, pos_value_unlever): `direct` is non-None only for the single-data raw-value early-return path (caller returns it immediately), preserving the original early-return semantics exactly. _get_value keeps the cash-addition prologue, the fundhist vs normal value calculation, and _valuemkt update. Logic moved verbatim; no behavior change. _get_value CC E(36) -> C(11); helpers C(15)/C(13). Verified: import clean, ruff/black green, 202 broker tests + fund/multidata/ commission functional tests pass.
_get_value E(36)->C(11) via _get_value_dual_side/_get_value_net. Update S5 table, acceptance summary and metrics; note _execute/_execute_dual_side (order accounting) and _initialize_indicator_aliases (import-time init) added to the documented-deferred set.
… -> 12) Move the TradeAnalyzer-derived metrics (rpl / won-lost totals / profit_factor / rpl_per_trade) out of PerformanceCalculator.get_pnl_metrics into _apply_trade_metrics(metrics, trade_analysis). get_pnl_metrics keeps the basic cash-return and annual-return calculations. Logic moved verbatim; no behavior change. get_pnl_metrics CC D(26) -> C(12); _apply_trade_metrics C(15). Verified: import clean, ruff green, 132 report/performance tests pass.
The (value_end/value_start - 1) computation with zero/NaN/inf/complex guards appeared twice in AnnualReturn.stop (year-boundary and final-pending paths). Extract it into a shared static helper _safe_annual_return(value_start, value_end). Logic identical; removes the duplication. stop CC D(21) -> B(7); _safe_annual_return B(8). Verified: import clean, ruff green, 17 annual-return tests pass.
Pull the column-name -> integer-index resolution loop out of PandasData.start into _resolve_colmapping(). start() keeps the index reset, loaditems build and numpy/datetime pre-computation. Logic moved verbatim (honors nocase, same ValueError fallback semantics); no behavior change. start CC D(22) -> C(12); _resolve_colmapping C(11). Verified: import clean, ruff green, 25 pandas-feed tests pass.
Behavior-preserving extractions (verbatim moves), all in non-hot-path modules: - analyzers/sharpe_ratio_stats.estimated_sharpe_ratio_stdev: extract input validation/normalization into _validate_srstdev_params. CC D(25)->C(15). - bokeh/analyzers/recorder.RecorderAnalyzer.next: extract _record_datas + shared _record_lineiterators(store, ltype) (dedups the identical indicator and observer recording loops). CC D(21)->A(5). - bokeh/app.BacktraderBokeh._add_equity_data: split into _equity_from_broker_observer / _equity_from_timereturn / _compute_drawdown. CC D(24)->A(3). - feeds/btapifeed.BtApiFeed.islive: extract _api_indicates_live (flattens the three repeated supports_live_* probes; returns None when the API has no opinion so the caller falls through unchanged). CC D(22)->C(11). Verified per file: import clean, ruff/black green, radon CC down.
Add get_pnl_metrics, AnnualReturn.stop, PandasData.start, estimated_sharpe_ratio_stdev, RecorderAnalyzer.next, _add_equity_data and BtApiFeed.islive to the S5 table; update acceptance summary (15 functions reduced: 8 core/analysis + 7 non-hot-path) and metrics.
… CLI Behavior-preserving extractions (verbatim moves): - bokeh/tabs/config.ConfigTab._get_panel: split into _build_params_widgets / _build_data_widgets. CC D(21)->A(4). - bokeh/tabs/metadata.MetadataTab._get_panel: extract _collect_metadata (time/strategy/data/indicator/analyzer/broker info dict). CC D(23)->C(11). - btrun/btrun.btrun: extract _add_datas (resample/replay data-feed wiring) and _print_analyzers (pranalyzer/ppranalyzer output). CC D(28)->C(15). Verified: ruff/black green, radon CC down; backtrader imports clean; btrun.py parses (its pre-existing `from .. import strategies` quirk is unchanged).
The getobjects() helper appends tuples of arity 2 (class, kwargs) and arity 3 (class, kwargs, sigtype) to the same list. mypy inferred the element type from the first append, flagging the signal branch. Annotate retobjects as a bare `list` to accept the heterogeneous tuples, matching the existing `kwargs: dict` style in the same function. Restores the established 139-error mypy baseline.
…eserving) All extractions are verbatim phase splits with unchanged computation order, signatures, side-effects and error semantics. Each verified with import + black + ruff + radon + targeted tests. - profiles.LiveProfile.__post_init__: split into _normalize_mode_frequency / _validate_store_config / _normalize_symbols / _validate_data_source (CC 23 -> 1). test_live_profile.py 33 passed. - analyzers.tradeanalyzer.TradeAnalyzer._on_trade_closed: split into per-category helpers (_update_streak / _update_gross_net_pnl / _update_won_lost / _update_long_short / _update_length / _update_length_won_lost / _update_length_long_short) (CC 30 -> 1). - brokers.btapibroker.BtApiBroker._sync_positions: extract per-item parse into _sync_one_position (CC 24 -> 12). 81 broker tests passed. - cerebro.Cerebro._run_channel: extract _instantiate_channel_strategies + _wire_channel_strategies setup phases (CC 33 -> 21; event loop left intact as hot path). channel-mode integration tests passed.
Behavior-preserving verbatim extractions; verified with import + black + ruff + radon + targeted tests. - analyzers.sharpe.SharpeRatio._timeframe_ratio: extract the rate/returns timeframe-factor conversion into _convert_rate_returns (CC 26 -> 15). 103 sharpe analyzer tests passed. - plot.plot_plotly.PlotlyPlot: extract the duplicated leading-pre-warmup- zero trimming logic shared by _plot_indicator (CC 31 -> 20) and _plot_indicator_on_ax (CC 25 -> 14) into a single _trim_prewarmup_zeros static helper, removing the duplication. 13 plotly integration tests passed.
… collection Behavior-preserving verbatim extractions; verified with import + black + ruff + radon + targeted tests. - parameters.ParameterizedBase._compute_parameter_descriptors: extract STEP 1 inheritance collection into _collect_inherited_descriptors and STEP 2/3 current-class merge into _collect_own_descriptors (CC 22 -> 2). Lazy/cached, not a hot path. 57 parameter-system tests passed. - plot.plot_plotly.PlotlyPlot._collect_buysell_signals: split the four fallback sources into _buysell_from_transactions / _broker_orders / _strategy_attr / _observer, preserving the first-source-wins short-circuit (CC 21 -> 4). plotly integration tests passed.
Document profiles/tradeanalyzer/btapibroker/cerebro-channel-startup/ sharpe/plotly(×2)/parameters decompositions, add Replayer.__call__ to the deliberately-deferred hot-path/state-machine list, and bump the metrics dashboard from 18 to 26 functions reduced.
…> 139) Moving the per-item/per-strategy population loops into helper methods removed the local usages mypy relied on to infer container element types. Re-annotate the affected locals/params to keep the established 139-error baseline: - btapibroker._sync_positions: annotate synced/long_synced/short_synced as defaultdict[str, Position] and add matching params to _sync_one_position. - cerebro._run_channel: split the chained assignment and annotate runstrats: list. Annotations only; no runtime behavior change. 83 broker/channel tests pass.
Iteration 10: complete module headers (Data Used / Strategy Principle / Strategy Logic) and class/method/function docstrings across tests/functional/strategies. Comments/docstrings only; executable code unchanged. Also restored two concurrency-corrupted values (analyzer compression and source_ea path) to match HEAD.
…pdate - backtrader: ruff R2 cleanups (PIE/C4/RET/SIM/B) and minor refactors - pyproject: expand ruff lint families with documented ignores - CI: add dev branch triggers + nightly full-suite schedule - README: update strategy-suite benchmark (master 438.96s vs dev 236.36s, -46.2% / 1.86x; 1271 passed) and runtime hints - docs/scripts/tests: iteration tracking, analyze_docstrings, new unit/bench tests
… credential masking 迭代12 代码质量与安全加固,M1–M3/M5 落地(安全主线): S-1 异常可见性分类治理: - trade_logger._safe_order_info: 静默 except 改为 logger.debug 记录上下文 - bokeh/app.py: 跳过坏 executed dt 时补 debug 日志 - strategy/log_message: 热路径补理由注释 - line 系统热路径 23 处 except 追加带理由的 # nosec B110/B112(仅注释,零逻辑改动) S-2 网络鲁棒性: - utils/py3.urlopen 增加默认 30s 超时(setdefault,兼容显式覆盖), 避免 quandl 等数据源在远端无响应时无限挂起 S-3 实盘凭证暴露面收敛: - BtApiStore 新增安全 __repr__/__str__,屏蔽 password/auth_code - 新增 _SENSITIVE_KEYS + _mask_sensitive() 供日志脱敏复用 S-4/S-5 低危 triage 闭环: - btrun 弱随机加 # nosec B311(内部模块名,非安全用途) - 复核 SQL 全参数化、influxfeed 字段名可信(已有 # nosec B608) T-1/T-2 CI 防回流: - lint 作业新增 pip-audit 依赖漏洞扫描 + Bandit Low 未 triage 看板(基线 0) 新增测试: - tests/unit/stores/test_credential_safety.py(6) - tests/unit/utils/test_urlopen_timeout.py(3) 验收:bandit HIGH/MED/LOW=0;ruff/black/isort pass;mypy 139 未回流; pytest tests -n 8 → 3044 passed, 1 skipped, 0 failures。 公共 API、数值结果、订单逻辑、事件顺序均未变。
验收复查发现两处 nosec 噪声并修正: - bokeh/app.py: 该 except 已补 logger.debug,不再触发 B112,移除多余 `# nosec B112` 并修正自相矛盾的注释(原写"logging would be noisy"但实际已记日志) - btrun/btrun.py: 多行 `# nosec B311:` 注释被 bandit 误当成 test id 解析并告警, 改为说明注释置于上方、行尾仅保留干净的 `# nosec B311` bandit -r backtrader -c pyproject.toml 仍为 HIGH/MED/LOW=0; functions.py 嵌套 except 的 4 处 # nosec B110 经实测确属必要(移除会暴露真实 B110),其 line 676/698 告警为 bandit 对嵌套 except 的行归属怪癖,无害。 验收:ruff pass;mypy 139 未回流;pip-audit 无 CVE; pytest tests -n 8 → 3044 passed, 1 skipped。
台账补充验收复查记录与完成度小结:M1–M3(安全主线)+ M5(CI 防回流) 已完成并通过验收;M4(mypy/复杂度)、M6(结构评估/TODO)、T-3(pre-commit) 按计划属后续协同批次,尚未开始。
CI run 26727816157 (dev) failed with 8 collection errors + 3 test failures. 诊断(gh run view + 本地隔离 venv 复现): 1) 缺失可选依赖导致 collection error(8 个):sklearn/hmmlearn/bt_api_py 在 CI 镜像未安装,但 7 个 ML 测试 + btapistore CTP 测试在模块顶层硬导入。 修复:按项目既有约定(seaborn/pandas 已用 pytest.importorskip)为这些 模块/用例加 `pytest.importorskip(...)`,缺失即跳过而非 collection error。 2) numpy 2.x 计数漂移(buy_count 442vs440、rebalance_count 124vs123 等): 实证——numpy 1.26.4 下整套策略回归(单测+并行)全绿;numpy 2.4.6 下少数 exact-count 断言漂移 ±1-2(源于 reduction/sort/dtype 数值变化使浮点边界翻转, 含 score.rank/sort_values 的 tie-break)。回归基线按 numpy 1.x 标定。 修复:setup.py / requirements.txt 将 numpy 收紧为 `>=1.20.0,<2.0.0`。 不修改任何断言/期望值/策略逻辑;numpy 2.x 支持需另立批次重标定基线。 验收: - 隔离 venv(py3.12 + numpy2.4.6,无 sklearn/hmmlearn/bt_api_py)下,原 8 个 报错文件现可正常收集(20 collected)并干净 skip; - ruff pass;bandit -ll pass;mypy 137(未回流); - pytest tests -n 8 → 3044 passed, 1 skipped。
…re-commit 收口迭代12 剩余里程碑(质量辅线 + 评估 + 工具链): M4 Q-1 安全模块 mypy 清零: - influxfeed.py: InfluxDBClientError fallback 加 type: ignore[no-redef]; biter 注解为 Optional[Iterator[Any]] 并在 _load 加 None 守卫(修 arg-type) - 实测 stores/* 与 trade_logger 已无 mypy 错误;全仓 139→137 M4 Q-2 复杂度:实测 btapistore 最高仅 C 级(CC13),无 F/E 级,无需重构 M6 Q-3 结构评估:新增 M6-结构评估与TODO复核.md,结论为本迭代不拆 btapistore(无高复杂度热点 + 与 bt_api_py 动态导入强耦合),给出 常量→纯函数→客户端工厂 的分批拆分路线图供后续参考 M6 Q-4 源码 TODO:bbroker int2pnl 翻译遗留注释改写为正式文档; vchartfile FIXME 作为已知限制保留 T-3 pre-commit:新增 bandit 安全钩子(-ll,镜像 CI Medium/High 门禁), 把安全扫描左移到本地提交前 台账:M4/M5/M6/T-3 全部置「验收通过」,并记录 M7 CI 修复。 验收:ruff pass;bandit -ll pass;mypy 137;pytest tests -n 8 → 3044 passed。
…py3.13 第二轮 CI 修复(push 后 run 26732118071 暴露的剩余问题): CI-C test_0061 SVD 符号不确定性(根因): - `_latent_scores` 用 np.linalg.svd,LAPACK 不固定奇异向量符号,vt 行符号随 平台/Python 构建/BLAS 后端翻转 → 潜在因子分数翻转 → 边界交易信号漂移 (py3.11→209,py3.12/3.13→210,即使同为 numpy 1.26.4)。 - 修复:加确定性符号约定(每个奇异向量最大幅值分量取正)。实测 py3.11/3.12/3.13 × numpy1/2 全部复现同一结果,测试从"平台相关"变为"完全可移植"。 - 按确定性结果重标定 11 处断言(非弱化:计算先变确定性,再以确定值精确断言)。 CI-B numpy pin 改为条件式(修复 py3.13/Windows 段错误): - 上一轮 `numpy<2.0` 导致 py3.13 无 1.x wheel → 1.26.4 源码构建在 win/py3.13 段错误(exit 139,import backtrader 即崩)。 - 改为:py<3.13 用 `numpy>=1.20,<2.0`(验证基线);py>=3.13 用 `numpy>=2.1` (有 3.13 wheel)。实测 py3.13+numpy2 下三个敏感测试 + 策略功能子集全绿。 验收: - test_0061 在 py3.11/3.12/3.13(numpy1 与 numpy2)均通过且数值一致; - py3.13+numpy2 策略功能子集 385+1243 passed 无漂移; - 主环境 pytest tests -n 8 → 3044 passed, 1 skipped。 CI-A(上一轮 commit af929b0 的 importorskip 守卫)已使 8 个 collection error 转为 skip,本轮不再涉及。
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Backtrader 去元编程项目 - Pull Request
📋 PR 概述
基本信息
变更摘要
修改范围
backtrader/[模块名].py: [变更描述]tests/[测试文件].py: [变更描述]🎯 元编程移除验证 ⭐⭐⭐⭐⭐
移除的元编程模式
移除的元类:
移除的动态类创建:
替代方案实现
使用的替代技术:
__init_subclass__方法实现完整性验证:
工具验证
🔄 API兼容性验证 ⭐⭐⭐⭐
公共接口检查
方法签名保持不变:
属性访问保持一致:
行为兼容性
核心功能验证:
异常处理验证:
兼容性测试结果
⚡ 性能影响评估 ⭐⭐⭐
性能基准测试
执行性能对比:
内存使用分析:
性能测试命令
关键路径优化
🧪 测试覆盖验证 ⭐⭐⭐
测试覆盖率
新增测试用例
功能测试:
边界条件测试:
异常情况测试:
📊 代码质量检查 ⭐⭐⭐
静态分析结果
代码质量评估
可读性和维护性:
架构设计:
📚 文档更新 ⭐⭐
文档变更
API文档:
用户文档:
开发文档:
文档质量
🔍 回归测试验证
完整测试套件
核心功能测试:
集成测试:
已知问题
📝 变更详情
主要变更
[变更类别]: [详细描述]
[文件路径][变更类别]: [详细描述]
[文件路径]技术实现细节
设计决策
🚨 风险评估
潜在风险
高风险:
中等风险:
回滚计划
✅ 审查检查清单
自检完成项
待审查项
📞 联系信息
PR提交者: [姓名]
联系方式: [邮箱/Slack]
提交时间: [日期时间]
预计审查时间: [时间估算]
🔧 审查者使用指南
审查步骤
git checkout [branch-name]审查标准
审查反馈模板
请使用代码审查规范中的反馈模板进行审查反馈。
模板版本: 1.0
最后更新: 2025年05月30日