"""分析 2022年4月底~5月初 CL=F 入选原因""" import os, sys, math from pathlib import Path import numpy as np import pandas as pd PROJECT_ROOT = Path(__file__).parent.parent.parent sys.path.insert(0, str(PROJECT_ROOT)) from rotation.simple_rotation import SimpleRotationStrategy, slope_r2_score if 'FLASK_API_URL' not in os.environ: os.environ['FLASK_API_URL'] = 'https://k3s.tokenpluse.xyz' strategy = SimpleRotationStrategy() strategy._preload_data() # 分析日期范围 start = pd.Timestamp('2022-04-15') end = pd.Timestamp('2022-05-10') n_days = strategy.config.factor.n_days # 25 print("=" * 80) print(f" 分析 CL=F 动量信号 ({start.date()} ~ {end.date()})") print(f" 窗口长度: {n_days} 天") print("=" * 80) # 获取所有 signal_codes 的 score signal_codes = strategy.signal_codes date_range = pd.bdate_range(start, end) for date in date_range: scores = {} for code in signal_codes: if code not in strategy.index_data: continue df = strategy.index_data[code] mask = df.index <= date recent = df.loc[mask] if len(recent) < n_days: continue prices = recent['close'].values[-n_days:] score = slope_r2_score(prices) scores[code] = (score, prices[-1]) if not scores: continue # 排序 ranked = sorted(scores.items(), key=lambda x: x[1][0], reverse=True) cl_rank = None for i, (code, (score, price)) in enumerate(ranked): if code == 'CL=F': cl_rank = i + 1 break cl_score = scores.get('CL=F', (None, None))[0] cl_price = scores.get('CL=F', (None, None))[1] print(f"\n{date.strftime('%Y-%m-%d')} | CL=F score={cl_score:.4f}, price={cl_price:.2f}, rank={cl_rank}/{len(ranked)}") print(f" Top 5:") for i, (code, (score, price)) in enumerate(ranked[:5]): marker = " <<<" if code == 'CL=F' else "" print(f" #{i+1} {code:<15} score={score:>10.4f} price={price:.2f}{marker}") # 详细分析 CL=F 价格走势 print(f"\n{'='*80}") print(f" CL=F 价格走势 (2022年3月~5月)") print(f"{'='*80}") df_cl = strategy.index_data['CL=F'] mask = (df_cl.index >= '2022-03-01') & (df_cl.index <= '2022-05-15') cl_prices = df_cl.loc[mask, 'close'] for date, price in cl_prices.items(): # 计算25天窗口的score mask2 = df_cl.index <= date recent = df_cl.loc[mask2] if len(recent) < n_days: continue prices = recent['close'].values[-n_days:] score = slope_r2_score(prices) normalized = prices / prices[0] slope, intercept = np.polyfit(np.arange(len(normalized)), normalized, 1) y_pred = slope * np.arange(len(normalized)) + intercept ss_res = np.sum((normalized - y_pred) ** 2) ss_tot = np.sum((normalized - np.mean(normalized)) ** 2) r2 = 1 - ss_res / ss_tot if ss_tot > 0 else 0 flag = "" if date.strftime('%Y-%m-%d') in ('2022-04-29', '2022-05-05'): flag = " <<< 入选日" print(f" {date.strftime('%Y-%m-%d')} price={price:>8.2f} score={score:>10.4f} " f"slope={slope:>8.5f} R²={r2:.4f}{flag}") # 分析 CL=F 的组内竞争 print(f"\n{'='*80}") print(f" CL=F 所在组: 查看组内竞争") print(f"{'='*80}") groups = strategy.config.asset_pools.by_group for group_name, assets in groups.items(): group_codes = [a.signal_source for a in assets.values()] if 'CL=F' in group_codes: print(f" 组名: {group_name}") print(f" 组成员: {group_codes}") # 4/29 和 5/5 的组内得分 for target_date_str in ['2022-04-29', '2022-05-05']: target_date = pd.Timestamp(target_date_str) print(f"\n {target_date_str} 组内得分:") for code in group_codes: if code not in strategy.index_data: continue df = strategy.index_data[code] mask = df.index <= target_date recent = df.loc[mask] if len(recent) < n_days: print(f" {code:<15} 数据不足") continue prices = recent['close'].values[-n_days:] score = slope_r2_score(prices) marker = " <<< TOP1" if score == max( slope_r2_score(strategy.index_data[c].loc[strategy.index_data[c].index <= target_date]['close'].values[-n_days:]) for c in group_codes if c in strategy.index_data and len(strategy.index_data[c].loc[strategy.index_data[c].index <= target_date]) >= n_days ) else "" print(f" {code:<15} score={score:>10.4f}{marker}")