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