diff --git a/rotation/backtest_viewer.html b/rotation/backtest_viewer.html new file mode 100644 index 0000000..38b106d --- /dev/null +++ b/rotation/backtest_viewer.html @@ -0,0 +1,715 @@ + + + + + +ETF轮动策略回测回放器 + + + + +
+
ETF 轮动策略回测回放器
+
加载 backtest_detail.json 开始回放
+ + +
+
+ +
+
+ + + + +
+ +
+ + + + + + + 速度: + + +
+ +
+ +
+ +
+ +
+
+

当日持仓

+
+
+
+

全部标的排名 (按动量排序)

+
+ + + + + + + + + + + + + + + + + + +
#代码名称大类动量阈值指数价ETF价指数收益ETF收益溢价率持仓
+
+
+
+ +
+
+ + + + diff --git a/rotation/simple_rotation.py b/rotation/simple_rotation.py index b3115c7..6743f72 100644 --- a/rotation/simple_rotation.py +++ b/rotation/simple_rotation.py @@ -774,6 +774,7 @@ class SimpleRotationStrategy: 'removed': sorted(removed), 'factors': {k: round(v, 6) for k, v in factors.items()}, 'threshold': threshold_val, + 'position_weights': {k: round(v, 6) for k, v in self._position_weights.items()}, }) current_holdings = new_holdings @@ -939,6 +940,7 @@ class SimpleRotationStrategy: factors = record.get('factors', {}) holdings = set(record['holdings']) threshold = record.get('threshold', 0.0) + position_weights = record.get('position_weights', {}) # Rank: sort all codes by momentum descending, rank 1 = highest sorted_codes = sorted(factors.keys(), key=lambda c: factors[c], reverse=True) @@ -995,6 +997,7 @@ class SimpleRotationStrategy: 'holding_days': holding_days, 'cum_return_etf': float(cum_ret_etf) if cum_ret_etf is not None else None, 'cum_return_idx': float(cum_ret_idx) if cum_ret_idx is not None else None, + 'weight': float(position_weights.get(code, 0.0)) if is_held else None, } return assets