完成模型更新
This commit is contained in:
@@ -50,5 +50,5 @@ RANK_MODEL = 'rank'
|
|||||||
TOP_MODEL = 'top'
|
TOP_MODEL = 'top'
|
||||||
STACKING_MODEL = 'stacking'
|
STACKING_MODEL = 'stacking'
|
||||||
|
|
||||||
# Stacking 选股阈值
|
# Stacking 选股阈值 (v6.7r3 最优阈值 0.331)
|
||||||
STACKING_THRESHOLD = 0.35
|
STACKING_THRESHOLD = 0.33
|
||||||
@@ -1,9 +1,10 @@
|
|||||||
"""
|
"""
|
||||||
扩展特征 v3.4 (16维)
|
扩展特征 v3.4 + v6.7新增 (20维: 16维 v3.4 + 4维 v6.7新增)
|
||||||
"""
|
"""
|
||||||
import numpy as np
|
import numpy as np
|
||||||
import pandas as pd
|
import pandas as pd
|
||||||
from core.scoring.features.v3_2_features import _ols_slope
|
from core.scoring.features.v3_2_features import _ols_slope
|
||||||
|
from core.scoring.features.v3_3_features import _grid_touch_count
|
||||||
from core.scoring.config import GRID_LOW, GRID_HIGH
|
from core.scoring.config import GRID_LOW, GRID_HIGH
|
||||||
|
|
||||||
|
|
||||||
@@ -104,6 +105,29 @@ def calculate_features_v3_4(ctx) -> pd.DataFrame:
|
|||||||
feat['wick_ratio_20d'] = np.mean(
|
feat['wick_ratio_20d'] = np.mean(
|
||||||
wick_len / np.where(total_len > 0, total_len, 1)) * 100
|
wick_len / np.where(total_len > 0, total_len, 1)) * 100
|
||||||
|
|
||||||
|
# ── v6.7 新增 4 维特征 ──────────────────────────────
|
||||||
|
# 53. vol_decay_5d: 近5日波动率 / 近20日波动率 (波动率用对数收益std)
|
||||||
|
log_ret = np.diff(np.log(np.maximum(closes, 1e-10)))
|
||||||
|
vol_5d = np.std(log_ret[-5:], ddof=1) if len(log_ret) >= 5 else 0
|
||||||
|
vol_20d = np.std(log_ret[-20:], ddof=1) if len(log_ret) >= 20 else vol_5d
|
||||||
|
feat['vol_decay_5d'] = float(vol_5d / vol_20d) if vol_20d > 0 else 0.0
|
||||||
|
|
||||||
|
# 54. grid_touch_relative_10d: 10日振幅比 / 60日振幅比
|
||||||
|
range_10d = float(np.max(highs[-10:]) - np.min(lows[-10:]))
|
||||||
|
range_60d = float(np.max(highs[-60:]) - np.min(lows[-60:])) if len(highs) >= 60 else range_10d
|
||||||
|
close_now = float(closes[-1])
|
||||||
|
close_60d_mean = float(np.mean(closes[-60:])) if len(closes) >= 60 else close_now
|
||||||
|
if close_now > 0 and close_60d_mean > 0 and range_60d > 0:
|
||||||
|
feat['grid_touch_relative_10d'] = (range_10d / close_now) / (range_60d / close_60d_mean)
|
||||||
|
else:
|
||||||
|
feat['grid_touch_relative_10d'] = 0.0
|
||||||
|
|
||||||
|
# 55. vol_decay_x_grid_balance: vol_decay × 网格均衡度
|
||||||
|
feat['vol_decay_x_grid_balance'] = feat['vol_decay_5d'] * feat.get('grid_room_balance', 0.0)
|
||||||
|
|
||||||
|
# 56. vol_decay_x_dist_lower: vol_decay × 下轨距离
|
||||||
|
feat['vol_decay_x_dist_lower'] = feat['vol_decay_5d'] * feat.get('dist_to_grid_lower', 0.0)
|
||||||
|
|
||||||
features[code] = feat
|
features[code] = feat
|
||||||
|
|
||||||
return pd.DataFrame.from_dict(features, orient='index')
|
return pd.DataFrame.from_dict(features, orient='index')
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
"""
|
"""
|
||||||
grid_seeker v6.6 三级模型推理管道
|
grid_seeker v6.7r3 三级模型推理管道
|
||||||
Rank → Top → Stacking → stacking_probability (最终排序)
|
Rank → Top → Stacking → stacking_probability (最终排序)
|
||||||
"""
|
"""
|
||||||
import pickle
|
import pickle
|
||||||
@@ -18,7 +18,7 @@ from core.logger import LogLevel, PrintLog
|
|||||||
|
|
||||||
|
|
||||||
# ============================================================
|
# ============================================================
|
||||||
# Rank 模型输入特征 (52维, v3.4, 直接从模型文件的 selected_features 读取)
|
# Rank 模型输入特征 (56维 v6.7/v3.4, 同时支持 feat_names 和 selected_features)
|
||||||
# ============================================================
|
# ============================================================
|
||||||
def _get_rank_features() -> list:
|
def _get_rank_features() -> list:
|
||||||
import pickle
|
import pickle
|
||||||
@@ -27,17 +27,26 @@ def _get_rank_features() -> list:
|
|||||||
with open(path, 'rb') as f:
|
with open(path, 'rb') as f:
|
||||||
obj = pickle.load(f)
|
obj = pickle.load(f)
|
||||||
if isinstance(obj, dict):
|
if isinstance(obj, dict):
|
||||||
sf = obj.get('selected_features', [])
|
# v6.7r3 使用 feat_names, v6.6 使用 selected_features
|
||||||
|
sf = obj.get('feat_names', []) or obj.get('selected_features', [])
|
||||||
if sf:
|
if sf:
|
||||||
return sf
|
return sf
|
||||||
raise RuntimeError("无法从 rank.pkl 读取 selected_features")
|
raise RuntimeError("无法从 rank.pkl 读取 feat_names 或 selected_features")
|
||||||
|
|
||||||
RANK_FEATURE_COLS = _get_rank_features()
|
RANK_FEATURE_COLS = _get_rank_features()
|
||||||
|
|
||||||
|
# Top/Stacking 模型只用 52 维基础特征(不含 v6.7 新增的4维)
|
||||||
|
# v6.7 新增: vol_decay_5d, grid_touch_relative_10d, vol_decay_x_grid_balance, vol_decay_x_dist_lower
|
||||||
|
_V67_NEW_FEATS = {
|
||||||
|
'vol_decay_5d', 'grid_touch_relative_10d',
|
||||||
|
'vol_decay_x_grid_balance', 'vol_decay_x_dist_lower'
|
||||||
|
}
|
||||||
|
BASE_52_COLS = [f for f in RANK_FEATURE_COLS if f not in _V67_NEW_FEATS]
|
||||||
|
|
||||||
|
|
||||||
class GridSeekerPipeline:
|
class GridSeekerPipeline:
|
||||||
"""
|
"""
|
||||||
grid_seeker v6.6 三级模型评分管道。
|
grid_seeker v6.7r3 三级模型评分管道。
|
||||||
|
|
||||||
Usage:
|
Usage:
|
||||||
engine = GridSeekerPipeline()
|
engine = GridSeekerPipeline()
|
||||||
@@ -120,7 +129,7 @@ class GridSeekerPipeline:
|
|||||||
DataFrame indexed by stock_code, 含 stacking_probability / rank 等列,
|
DataFrame indexed by stock_code, 含 stacking_probability / rank 等列,
|
||||||
按 stacking_probability 降序排列
|
按 stacking_probability 降序排列
|
||||||
"""
|
"""
|
||||||
PrintLog(LogLevel.INFO, f'[scorer] ===== grid_seeker v6.6 评分开始 ({trade_date}) =====')
|
PrintLog(LogLevel.INFO, f'[scorer] ===== grid_seeker v6.7r3 评分开始 ({trade_date}) =====')
|
||||||
|
|
||||||
# 1. 特征工程
|
# 1. 特征工程
|
||||||
pipeline = FeaturePipeline(trade_date)
|
pipeline = FeaturePipeline(trade_date)
|
||||||
@@ -140,16 +149,16 @@ class GridSeekerPipeline:
|
|||||||
self.rank_model, feature_df, RANK_FEATURE_COLS
|
self.rank_model, feature_df, RANK_FEATURE_COLS
|
||||||
)
|
)
|
||||||
|
|
||||||
# 3. Stage 2: Top 模型 → top_elite_prob (53维 = 52 + rank_predicted_rounds)
|
# 3. Stage 2: Top 模型 → top_elite_prob (53维 = 52基础 + rank)
|
||||||
PrintLog(LogLevel.INFO, '[scorer] Stage 2/3: Top 模型...')
|
PrintLog(LogLevel.INFO, '[scorer] Stage 2/3: Top 模型...')
|
||||||
top_cols = RANK_FEATURE_COLS + ['rank_predicted_rounds']
|
top_cols = BASE_52_COLS + ['rank_predicted_rounds']
|
||||||
feature_df['top_elite_prob'] = self._predict_with_model(
|
feature_df['top_elite_prob'] = self._predict_with_model(
|
||||||
self.top_model, feature_df, top_cols
|
self.top_model, feature_df, top_cols
|
||||||
)
|
)
|
||||||
|
|
||||||
# 4. Stage 3: Stacking 模型 → stacking_probability (54维 = 52 + rank + top)
|
# 4. Stage 3: Stacking 模型 → stacking_probability (55维 = 52基础 + rank + top)
|
||||||
PrintLog(LogLevel.INFO, '[scorer] Stage 3/3: Stacking 模型...')
|
PrintLog(LogLevel.INFO, '[scorer] Stage 3/3: Stacking 模型...')
|
||||||
stk_cols = RANK_FEATURE_COLS + ['rank_predicted_rounds', 'top_elite_prob']
|
stk_cols = BASE_52_COLS + ['rank_predicted_rounds', 'top_elite_prob']
|
||||||
feature_df['stacking_probability'] = self._predict_with_model(
|
feature_df['stacking_probability'] = self._predict_with_model(
|
||||||
self.stacking_model, feature_df, stk_cols
|
self.stacking_model, feature_df, stk_cols
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ K线数据同步 — 个股日K + 指数日K
|
|||||||
线程锁: KlineStockSync / KlineIndexSync 各自内部锁
|
线程锁: KlineStockSync / KlineIndexSync 各自内部锁
|
||||||
"""
|
"""
|
||||||
import pandas as pd
|
import pandas as pd
|
||||||
from datetime import date, timedelta
|
from datetime import date, datetime, timedelta
|
||||||
from core.scoring.sync.base import BaseSync
|
from core.scoring.sync.base import BaseSync
|
||||||
from core.scoring.models import KlineStock, KlineIndex
|
from core.scoring.models import KlineStock, KlineIndex
|
||||||
from core.scoring.config import TRACKED_INDICES
|
from core.scoring.config import TRACKED_INDICES
|
||||||
@@ -111,6 +111,10 @@ class KlineStockSync(BaseSync):
|
|||||||
stock_code = full_code.split('.')[0]
|
stock_code = full_code.split('.')[0]
|
||||||
records = []
|
records = []
|
||||||
for td in close_df.columns:
|
for td in close_df.columns:
|
||||||
|
# xtdata 返回的列名可能是字符串 'YYYYMMDD' 或 datetime,需统一转成 date
|
||||||
|
if isinstance(td, str):
|
||||||
|
td_date = datetime.strptime(td, '%Y%m%d').date()
|
||||||
|
else:
|
||||||
td_date = td.date() if hasattr(td, 'date') else td
|
td_date = td.date() if hasattr(td, 'date') else td
|
||||||
if start_date is not None and td_date <= start_date:
|
if start_date is not None and td_date <= start_date:
|
||||||
self.stats['skipped'] = self.stats.get('skipped', 0) + 1
|
self.stats['skipped'] = self.stats.get('skipped', 0) + 1
|
||||||
@@ -193,6 +197,9 @@ class KlineIndexSync(BaseSync):
|
|||||||
for full_code in close_df.index:
|
for full_code in close_df.index:
|
||||||
index_code = full_code.split('.')[0]
|
index_code = full_code.split('.')[0]
|
||||||
for td in close_df.columns:
|
for td in close_df.columns:
|
||||||
|
if isinstance(td, str):
|
||||||
|
td_date = datetime.strptime(td, '%Y%m%d').date()
|
||||||
|
else:
|
||||||
td_date = td.date() if hasattr(td, 'date') else td
|
td_date = td.date() if hasattr(td, 'date') else td
|
||||||
if latest is not None and td_date <= latest:
|
if latest is not None and td_date <= latest:
|
||||||
self.stats['skipped'] = self.stats.get('skipped', 0) + 1
|
self.stats['skipped'] = self.stats.get('skipped', 0) + 1
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ class SectorFeaturesSync(BaseSync):
|
|||||||
"""行业聚合指数同步 — kline_stock + industry → sector_features_daily"""
|
"""行业聚合指数同步 — kline_stock + industry → sector_features_daily"""
|
||||||
|
|
||||||
def _fetch(self, **kwargs):
|
def _fetch(self, **kwargs):
|
||||||
"""从数据库加载原始数据, 计算行业指数特征"""
|
"""从数据库加载原始数据, 计算行业指数特征(分块处理避免内存溢出)"""
|
||||||
PrintLog(LogLevel.INFO, '[sync] SectorFeatures: 加载原始数据...')
|
PrintLog(LogLevel.INFO, '[sync] SectorFeatures: 加载原始数据...')
|
||||||
|
|
||||||
# 1. 加载行业映射: code → industry_name
|
# 1. 加载行业映射: code → industry_name
|
||||||
@@ -24,8 +24,17 @@ class SectorFeaturesSync(BaseSync):
|
|||||||
code_to_industry = {row['code']: row['industry_name'] for row in industries}
|
code_to_industry = {row['code']: row['industry_name'] for row in industries}
|
||||||
PrintLog(LogLevel.INFO, f'[sync] SectorFeatures: {len(code_to_industry)} 条行业映射')
|
PrintLog(LogLevel.INFO, f'[sync] SectorFeatures: {len(code_to_industry)} 条行业映射')
|
||||||
|
|
||||||
# 2. 加载 K 线数据
|
# 2. 分块加载 K 线数据,避免内存溢出
|
||||||
kline_rows = (KlineStock
|
# 聚合结果: {(trade_date, sector_name): [sum_pct_chg, sum_amp, count]}
|
||||||
|
sector_daily_agg = {} # key: (date, sector) -> {'ret_sum': float, 'amp_sum': float, 'count': int}
|
||||||
|
CHUNK_SIZE = 50000
|
||||||
|
last_date_per_stock = {} # stock_code -> prev_close
|
||||||
|
|
||||||
|
PrintLog(LogLevel.INFO, '[sync] SectorFeatures: 分块处理K线数据...')
|
||||||
|
chunk_num = 0
|
||||||
|
while True:
|
||||||
|
chunk_num += 1
|
||||||
|
rows = list(KlineStock
|
||||||
.select(
|
.select(
|
||||||
KlineStock.stock_code,
|
KlineStock.stock_code,
|
||||||
KlineStock.trade_date,
|
KlineStock.trade_date,
|
||||||
@@ -35,38 +44,61 @@ class SectorFeaturesSync(BaseSync):
|
|||||||
KlineStock.close,
|
KlineStock.close,
|
||||||
)
|
)
|
||||||
.order_by(KlineStock.stock_code, KlineStock.trade_date)
|
.order_by(KlineStock.stock_code, KlineStock.trade_date)
|
||||||
|
.offset((chunk_num - 1) * CHUNK_SIZE)
|
||||||
|
.limit(CHUNK_SIZE)
|
||||||
.dicts())
|
.dicts())
|
||||||
|
if not rows:
|
||||||
|
break
|
||||||
|
|
||||||
if not kline_rows:
|
PrintLog(LogLevel.INFO, f'[sync] SectorFeatures: 处理块 {chunk_num} ({len(rows)} 行)...')
|
||||||
PrintLog(LogLevel.WARNING, '[sync] SectorFeatures: KlineStock 表为空')
|
|
||||||
|
for row in rows:
|
||||||
|
code = str(row['stock_code'])
|
||||||
|
td = row['trade_date']
|
||||||
|
open_p = float(row['open'])
|
||||||
|
high = float(row['high'])
|
||||||
|
low = float(row['low'])
|
||||||
|
close = float(row['close'])
|
||||||
|
|
||||||
|
sector = code_to_industry.get(code)
|
||||||
|
if sector is None:
|
||||||
|
continue
|
||||||
|
|
||||||
|
# 计算日收益率和振幅
|
||||||
|
prev_close = last_date_per_stock.get(code)
|
||||||
|
if prev_close is not None and prev_close > 0 and open_p > 0 and close > 0:
|
||||||
|
pct_chg = (close - prev_close) / prev_close * 100
|
||||||
|
amp = (high - low) / open_p * 100
|
||||||
|
key = (td, sector)
|
||||||
|
if key not in sector_daily_agg:
|
||||||
|
sector_daily_agg[key] = {'ret_sum': 0.0, 'amp_sum': 0.0, 'count': 0}
|
||||||
|
sector_daily_agg[key]['ret_sum'] += pct_chg
|
||||||
|
sector_daily_agg[key]['amp_sum'] += amp
|
||||||
|
sector_daily_agg[key]['count'] += 1
|
||||||
|
|
||||||
|
last_date_per_stock[code] = close
|
||||||
|
|
||||||
|
if not sector_daily_agg:
|
||||||
|
PrintLog(LogLevel.WARNING, '[sync] SectorFeatures: 无有效K线数据')
|
||||||
return None
|
return None
|
||||||
|
|
||||||
df = pd.DataFrame(kline_rows)
|
PrintLog(LogLevel.INFO, f'[sync] SectorFeatures: 聚合完成, {len(sector_daily_agg)} 个行业-日组合')
|
||||||
df['trade_date'] = pd.to_datetime(df['trade_date'])
|
|
||||||
PrintLog(LogLevel.INFO, f'[sync] SectorFeatures: {len(df)} 条K线数据')
|
|
||||||
|
|
||||||
# 3. 映射行业
|
# 3. 构建聚合 DataFrame
|
||||||
df['sector_name'] = df['stock_code'].map(code_to_industry)
|
agg_data = []
|
||||||
df = df.dropna(subset=['sector_name'])
|
for (td, sector), vals in sector_daily_agg.items():
|
||||||
|
agg_data.append({
|
||||||
|
'trade_date': td,
|
||||||
|
'sector_name': sector,
|
||||||
|
'sector_ret': vals['ret_sum'] / vals['count'],
|
||||||
|
'sector_amplitude': vals['amp_sum'] / vals['count'],
|
||||||
|
})
|
||||||
|
agg = pd.DataFrame(agg_data)
|
||||||
|
agg = agg.sort_values(['sector_name', 'trade_date'])
|
||||||
|
agg['trade_date'] = pd.to_datetime(agg['trade_date'])
|
||||||
|
PrintLog(LogLevel.INFO, f'[sync] SectorFeatures: {len(agg)} 行, {agg["sector_name"].nunique()} 个行业')
|
||||||
|
|
||||||
# 4. 逐股计算日收益率和振幅
|
# 4. 构建行业指数 (基值=100)
|
||||||
df = df.sort_values(['stock_code', 'trade_date'])
|
|
||||||
df['prev_close'] = df.groupby('stock_code')['close'].shift(1)
|
|
||||||
df['pct_chg'] = (df['close'] - df['prev_close']) / df['prev_close'] * 100
|
|
||||||
df['amplitude'] = (df['high'] - df['low']) / df['open'] * 100
|
|
||||||
|
|
||||||
# 清理无效值
|
|
||||||
df = df.dropna(subset=['pct_chg', 'amplitude'])
|
|
||||||
|
|
||||||
# 5. 按行业+日期聚合
|
|
||||||
agg = (df.groupby(['trade_date', 'sector_name'])
|
|
||||||
.agg(
|
|
||||||
sector_ret=('pct_chg', 'mean'),
|
|
||||||
sector_amplitude=('amplitude', 'mean'),
|
|
||||||
)
|
|
||||||
.reset_index())
|
|
||||||
|
|
||||||
# 6. 构建行业指数 (基值=100)
|
|
||||||
agg = agg.sort_values(['sector_name', 'trade_date'])
|
agg = agg.sort_values(['sector_name', 'trade_date'])
|
||||||
agg['sector_index'] = agg.groupby('sector_name')['sector_ret'].transform(
|
agg['sector_index'] = agg.groupby('sector_name')['sector_ret'].transform(
|
||||||
lambda x: (1 + x / 100).cumprod() * 100
|
lambda x: (1 + x / 100).cumprod() * 100
|
||||||
@@ -77,7 +109,7 @@ class SectorFeaturesSync(BaseSync):
|
|||||||
first_val = group['sector_index'].iloc[0]
|
first_val = group['sector_index'].iloc[0]
|
||||||
agg.loc[idx, 'sector_index'] = group['sector_index'] / first_val * 100
|
agg.loc[idx, 'sector_index'] = group['sector_index'] / first_val * 100
|
||||||
|
|
||||||
# 7. 计算 EMA 均线
|
# 5. 计算 EMA 均线
|
||||||
agg['ema10'] = (agg.groupby('sector_name')['sector_index']
|
agg['ema10'] = (agg.groupby('sector_name')['sector_index']
|
||||||
.transform(lambda x: x.ewm(span=10, min_periods=1).mean()))
|
.transform(lambda x: x.ewm(span=10, min_periods=1).mean()))
|
||||||
agg['ema20'] = (agg.groupby('sector_name')['sector_index']
|
agg['ema20'] = (agg.groupby('sector_name')['sector_index']
|
||||||
@@ -85,7 +117,7 @@ class SectorFeaturesSync(BaseSync):
|
|||||||
agg['ema200'] = (agg.groupby('sector_name')['sector_index']
|
agg['ema200'] = (agg.groupby('sector_name')['sector_index']
|
||||||
.transform(lambda x: x.ewm(span=200, min_periods=1).mean()))
|
.transform(lambda x: x.ewm(span=200, min_periods=1).mean()))
|
||||||
|
|
||||||
# 8. 趋势评分: close>ema200 得1分 + ema10>ema20 得1分
|
# 6. 趋势评分: close>ema200 得1分 + ema10>ema20 得1分
|
||||||
agg['score'] = (
|
agg['score'] = (
|
||||||
(agg['sector_index'] > agg['ema200']).astype(int) +
|
(agg['sector_index'] > agg['ema200']).astype(int) +
|
||||||
(agg['ema10'] > agg['ema20']).astype(int)
|
(agg['ema10'] > agg['ema20']).astype(int)
|
||||||
|
|||||||
@@ -173,6 +173,9 @@ class SFGridStrategy:
|
|||||||
# 检查是否已存在同 remark 的卖单(避免重复挂单)
|
# 检查是否已存在同 remark 的卖单(避免重复挂单)
|
||||||
if not any(o.order_remark == sell_remark for o in orders):
|
if not any(o.order_remark == sell_remark for o in orders):
|
||||||
# 卖单价格超过涨停价 → 今日无法成交,跳过下单
|
# 卖单价格超过涨停价 → 今日无法成交,跳过下单
|
||||||
|
# 防御性检查:若属性未初始化(初始化顺序导致),先获取
|
||||||
|
if not hasattr(self, 'todayUpStopPrice') or self.todayUpStopPrice is None:
|
||||||
|
self.todayUpStopPrice = qmtv.dailyUpStop(self.tradeTarget.stock_code) # type: ignore
|
||||||
if sellPrice > self.todayUpStopPrice:
|
if sellPrice > self.todayUpStopPrice:
|
||||||
PrintLog(LogLevel.INFO,
|
PrintLog(LogLevel.INFO,
|
||||||
f'|- 标的[{self.tradeTarget.targetName()}] '
|
f'|- 标的[{self.tradeTarget.targetName()}] '
|
||||||
@@ -207,6 +210,9 @@ class SFGridStrategy:
|
|||||||
# 检查是否已存在同 remark 的买单(避免重复挂单)
|
# 检查是否已存在同 remark 的买单(避免重复挂单)
|
||||||
if not any(o.order_remark == buy_remark for o in orders):
|
if not any(o.order_remark == buy_remark for o in orders):
|
||||||
# 买单价格低于跌停价 → 今日无法成交,跳过下单
|
# 买单价格低于跌停价 → 今日无法成交,跳过下单
|
||||||
|
# 防御性检查:若属性未初始化(初始化顺序导致),先获取
|
||||||
|
if not hasattr(self, 'todayDownStopPrice') or self.todayDownStopPrice is None:
|
||||||
|
self.todayDownStopPrice = qmtv.dailyDownStop(self.tradeTarget.stock_code) # type: ignore
|
||||||
if buyPrice < self.todayDownStopPrice:
|
if buyPrice < self.todayDownStopPrice:
|
||||||
PrintLog(LogLevel.INFO,
|
PrintLog(LogLevel.INFO,
|
||||||
f'|- 标的[{self.tradeTarget.targetName()}] '
|
f'|- 标的[{self.tradeTarget.targetName()}] '
|
||||||
|
|||||||
+69
-6
@@ -324,9 +324,9 @@ class _GridPanel:
|
|||||||
return self._col
|
return self._col
|
||||||
|
|
||||||
def _rebuild(self):
|
def _rebuild(self):
|
||||||
# (width, expand): 0=固定宽, >0=弹性比重
|
# (width, expand): 0=固定宽, >0=弹性比重; 新增排名列(50px)
|
||||||
_C = [(35, 0), (0, 2), (70, 1), (0, 2), (50, 1), (55, 1), (60, 1), (0, 1)]
|
_C = [(35, 0), (0, 2), (70, 1), (0, 2), (50, 1), (55, 1), (50, 0), (60, 1), (0, 1)]
|
||||||
H = ["ID", "股票", "市场价", "网格基准", "持仓", "成本", "状态", "操作"]
|
H = ["ID", "股票", "市场价", "网格基准", "持仓", "成本", "排名", "状态", "操作"]
|
||||||
header = []
|
header = []
|
||||||
for h, (w, e) in zip(H, _C):
|
for h, (w, e) in zip(H, _C):
|
||||||
if e > 0:
|
if e > 0:
|
||||||
@@ -335,6 +335,22 @@ class _GridPanel:
|
|||||||
header.append(ft.Container(_text(h, bold=True), width=w, padding=4))
|
header.append(ft.Container(_text(h, bold=True), width=w, padding=4))
|
||||||
rows = [ft.Row(header, spacing=0), ft.Divider(height=1, color='#e0e0e0')]
|
rows = [ft.Row(header, spacing=0), ft.Divider(height=1, color='#e0e0e0')]
|
||||||
|
|
||||||
|
# 获取最新评分排名
|
||||||
|
rank_map = {} # stock_code -> score_rank
|
||||||
|
try:
|
||||||
|
from core.scoring.models import ScoringResult
|
||||||
|
from peewee import fn
|
||||||
|
latest_date = ScoringResult.select(fn.MAX(ScoringResult.trade_date)).scalar()
|
||||||
|
if latest_date:
|
||||||
|
scored = (ScoringResult
|
||||||
|
.select(ScoringResult.stock_code, ScoringResult.score_rank)
|
||||||
|
.where(ScoringResult.trade_date == latest_date)
|
||||||
|
.dicts())
|
||||||
|
for r in scored:
|
||||||
|
rank_map[r['stock_code']] = r['score_rank']
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|
||||||
for tid, t in self._data.tradeTargets.items():
|
for tid, t in self._data.tradeTargets.items():
|
||||||
if t.strategy_type != STRATEGY_TYPE_GRID: continue
|
if t.strategy_type != STRATEGY_TYPE_GRID: continue
|
||||||
pg = t.getPriceGrid()
|
pg = t.getPriceGrid()
|
||||||
@@ -358,6 +374,22 @@ class _GridPanel:
|
|||||||
))
|
))
|
||||||
gcell = ft.Row(gcells, spacing=3) if len(gcells) > 1 else gcells[0]
|
gcell = ft.Row(gcells, spacing=3) if len(gcells) > 1 else gcells[0]
|
||||||
|
|
||||||
|
# 排名列
|
||||||
|
plain = t.stock_code.split('.')[0] if '.' in t.stock_code else t.stock_code
|
||||||
|
rank = rank_map.get(plain, None)
|
||||||
|
if rank is not None and rank <= 50:
|
||||||
|
rank_str = f'#{rank}'
|
||||||
|
rank_color = '#4CAF50'
|
||||||
|
elif rank is not None and rank <= 100:
|
||||||
|
rank_str = f'#{rank}'
|
||||||
|
rank_color = '#2196F3'
|
||||||
|
elif rank is not None:
|
||||||
|
rank_str = f'#{rank}'
|
||||||
|
rank_color = '#888888'
|
||||||
|
else:
|
||||||
|
rank_str = '—'
|
||||||
|
rank_color = '#888888'
|
||||||
|
|
||||||
# 操作按钮
|
# 操作按钮
|
||||||
_ICON = 22 # 图标大小,比默认 18 好按
|
_ICON = 22 # 图标大小,比默认 18 好按
|
||||||
if t.enabled:
|
if t.enabled:
|
||||||
@@ -385,6 +417,7 @@ class _GridPanel:
|
|||||||
f'{mp:.3f}', gcell,
|
f'{mp:.3f}', gcell,
|
||||||
str(t.current_position),
|
str(t.current_position),
|
||||||
f'{self._data.avgPrices.get(tid, 0):.3f}',
|
f'{self._data.avgPrices.get(tid, 0):.3f}',
|
||||||
|
rank_str,
|
||||||
'▶运行中' if t.enabled else '⏸已暂停',
|
'▶运行中' if t.enabled else '⏸已暂停',
|
||||||
btns]
|
btns]
|
||||||
row_cells = []
|
row_cells = []
|
||||||
@@ -392,6 +425,8 @@ class _GridPanel:
|
|||||||
content = cells_text[i]
|
content = cells_text[i]
|
||||||
if i == 2: # 市场价用颜色
|
if i == 2: # 市场价用颜色
|
||||||
content = _text(cells_text[i], color=pcolor, bold=True)
|
content = _text(cells_text[i], color=pcolor, bold=True)
|
||||||
|
elif i == 6: # 排名用颜色
|
||||||
|
content = _text(cells_text[i], color=rank_color, bold=True)
|
||||||
elif isinstance(content, str):
|
elif isinstance(content, str):
|
||||||
content = _text(content)
|
content = _text(content)
|
||||||
elif isinstance(content, list):
|
elif isinstance(content, list):
|
||||||
@@ -495,8 +530,25 @@ class _DrawerPanel:
|
|||||||
|
|
||||||
def _refresh_grid(self):
|
def _refresh_grid(self):
|
||||||
# (width, expand): 0=固定宽, >0=弹性比重; 股票列 expand 自动填充剩余空间
|
# (width, expand): 0=固定宽, >0=弹性比重; 股票列 expand 自动填充剩余空间
|
||||||
_C = [(35, 0), (0, 1), (80, 0), (60, 0), (70, 0), (65, 0)]
|
# 新增: 排名列 (50px)
|
||||||
H = ["ID", "股票", "市场价", "持仓", "成本", "操作"]
|
_C = [(35, 0), (0, 1), (80, 0), (60, 0), (70, 0), (50, 0), (65, 0)]
|
||||||
|
H = ["ID", "股票", "市场价", "持仓", "成本", "排名", "操作"]
|
||||||
|
|
||||||
|
# 获取最新评分排名
|
||||||
|
rank_map = {} # stock_code -> score_rank
|
||||||
|
try:
|
||||||
|
from core.scoring.models import ScoringResult
|
||||||
|
from peewee import fn
|
||||||
|
latest_date = ScoringResult.select(fn.MAX(ScoringResult.trade_date)).scalar()
|
||||||
|
if latest_date:
|
||||||
|
rows = (ScoringResult
|
||||||
|
.select(ScoringResult.stock_code, ScoringResult.score_rank)
|
||||||
|
.where(ScoringResult.trade_date == latest_date)
|
||||||
|
.dicts())
|
||||||
|
for r in rows:
|
||||||
|
rank_map[r['stock_code']] = r['score_rank']
|
||||||
|
except Exception:
|
||||||
|
pass # 数据库未就绪时忽略
|
||||||
|
|
||||||
def _cell(text, w, e, color=None):
|
def _cell(text, w, e, color=None):
|
||||||
if e > 0:
|
if e > 0:
|
||||||
@@ -509,15 +561,26 @@ class _DrawerPanel:
|
|||||||
for tid, t in self._data.tradeTargets.items():
|
for tid, t in self._data.tradeTargets.items():
|
||||||
if t.strategy_type == STRATEGY_TYPE_GRID: continue
|
if t.strategy_type == STRATEGY_TYPE_GRID: continue
|
||||||
mp = self._data.marketPrices.get(tid, 0) or 0
|
mp = self._data.marketPrices.get(tid, 0) or 0
|
||||||
|
plain = t.stock_code.split('.')[0] if '.' in t.stock_code else t.stock_code
|
||||||
|
rank = rank_map.get(plain, None)
|
||||||
|
rank_str = f"#{rank}" if rank is not None else "—"
|
||||||
|
# 排名颜色: top50 绿色, top100 蓝色, 其他灰色
|
||||||
|
if rank is not None and rank <= 50:
|
||||||
|
rank_color = '#4CAF50'
|
||||||
|
elif rank is not None and rank <= 100:
|
||||||
|
rank_color = '#2196F3'
|
||||||
|
else:
|
||||||
|
rank_color = '#888888'
|
||||||
cells = [
|
cells = [
|
||||||
_cell(str(tid), *_C[0]),
|
_cell(str(tid), *_C[0]),
|
||||||
_cell(f'{t.stock_code} {t.stock_name}', *_C[1]),
|
_cell(f'{t.stock_code} {t.stock_name}', *_C[1]),
|
||||||
_cell(f'{mp:.3f}', *_C[2]),
|
_cell(f'{mp:.3f}', *_C[2]),
|
||||||
_cell(str(t.current_position), *_C[3]),
|
_cell(str(t.current_position), *_C[3]),
|
||||||
_cell(f'{self._data.avgPrices.get(tid, 0):.3f}', *_C[4]),
|
_cell(f'{self._data.avgPrices.get(tid, 0):.3f}', *_C[4]),
|
||||||
|
_cell(rank_str, *_C[5], color=rank_color),
|
||||||
ft.Container(ft.IconButton(ft.Icons.SETTINGS, icon_size=20, tooltip="网格配置",
|
ft.Container(ft.IconButton(ft.Icons.SETTINGS, icon_size=20, tooltip="网格配置",
|
||||||
on_click=lambda e, tt=t: self._dialogs.open_config(tt)),
|
on_click=lambda e, tt=t: self._dialogs.open_config(tt)),
|
||||||
width=_C[5][0], padding=0),
|
width=_C[6][0], padding=0),
|
||||||
]
|
]
|
||||||
row = ft.Row(cells, spacing=0)
|
row = ft.Row(cells, spacing=0)
|
||||||
rows.append(ft.Container(row, padding=ft.Padding(0, 2, 0, 2)))
|
rows.append(ft.Container(row, padding=ft.Padding(0, 2, 0, 2)))
|
||||||
|
|||||||
@@ -1,197 +0,0 @@
|
|||||||
# v6.6 模型发布说明
|
|
||||||
|
|
||||||
**版本**: v6.6
|
|
||||||
**发布日期**: 2026-06-16
|
|
||||||
**状态**: 生产就绪
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 一、模型架构
|
|
||||||
|
|
||||||
v6.6 采用 **Stacking Calibrated** 三层融合架构:
|
|
||||||
|
|
||||||
```
|
|
||||||
输入特征 (52维 v3.4)
|
|
||||||
│
|
|
||||||
▼
|
|
||||||
┌─────────────────┐ ┌─────────────────┐
|
|
||||||
│ Rank 模型 │ │ Top 模型 │
|
|
||||||
│ LGBMRegressor │ │ LGBMClassifier │
|
|
||||||
│ 预测网格轮回次数 │ │ 分类精英股票 │
|
|
||||||
│ CV MAE: 0.2053 │ │ CV PR-AUC: 0.53│
|
|
||||||
│ CV R²: 0.2258 │ │ │
|
|
||||||
└────────┬────────┘ └────────┬────────┘
|
|
||||||
│ │
|
|
||||||
└──────────┬───────────┘
|
|
||||||
▼
|
|
||||||
┌─────────────────────┐
|
|
||||||
│ Stacking 模型 │
|
|
||||||
│ LGBMClassifier │
|
|
||||||
│ CV PR-AUC: 0.8207 │
|
|
||||||
│ 最优阈值: 0.35 │
|
|
||||||
└──────────┬──────────┘
|
|
||||||
▼
|
|
||||||
最终 top 概率
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 二、训练数据
|
|
||||||
|
|
||||||
| 指标 | 数值 |
|
|
||||||
|------|------|
|
|
||||||
| 特征版本 | v3.4 (52维) |
|
|
||||||
| 原始股票数 | 4,358 |
|
|
||||||
| 过滤后股票数 | 1,533 |
|
|
||||||
| 训练样本数 | 205,491 |
|
|
||||||
| 观察窗口 | 120天 |
|
|
||||||
| 预测窗口 | 60天 |
|
|
||||||
| 零触碰率 | 71.1% |
|
|
||||||
| Elite率 | 20.5% |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 三、模型性能
|
|
||||||
|
|
||||||
### Rank模型 (回归)
|
|
||||||
| 指标 | 数值 |
|
|
||||||
|------|------|
|
|
||||||
| CV MAE | 0.2053 |
|
|
||||||
| CV R² | 0.2258 |
|
|
||||||
| 最优参数 | num_leaves=63, min_child_samples=30, max_depth=7 |
|
|
||||||
|
|
||||||
### Top模型 (分类)
|
|
||||||
| 指标 | 数值 |
|
|
||||||
|------|------|
|
|
||||||
| CV PR-AUC | 0.5333 |
|
|
||||||
| 最优参数 | num_leaves=63, min_child_samples=30, max_depth=-1 |
|
|
||||||
|
|
||||||
### Stacking融合模型
|
|
||||||
| 指标 | 数值 |
|
|
||||||
|------|------|
|
|
||||||
| CV PR-AUC | **0.8207** |
|
|
||||||
| 最优阈值 | 0.35 |
|
|
||||||
| 最优参数 | num_leaves=31, min_child_samples=20, max_depth=-1 |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 四、Top 10 重要特征
|
|
||||||
|
|
||||||
### Rank模型
|
|
||||||
| 排名 | 特征 | 重要性% |
|
|
||||||
|------|------|---------|
|
|
||||||
| 1 | dist_to_grid_upper | 4.38% |
|
|
||||||
| 2 | dist_to_grid_lower | 4.26% |
|
|
||||||
| 3 | price_cv | 4.09% |
|
|
||||||
| 4 | amount_mean_20d | 3.98% |
|
|
||||||
| 5 | range_compression_20d | 3.48% |
|
|
||||||
|
|
||||||
### Stacking融合
|
|
||||||
| 排名 | 特征 | 重要性% |
|
|
||||||
|------|------|---------|
|
|
||||||
| 1 | rank_predicted_rounds | 20.87% |
|
|
||||||
| 2 | top_elite_prob | 19.38% |
|
|
||||||
| 3 | ma20_deviation_pct | 5.35% |
|
|
||||||
| 4 | atr_pct | 4.93% |
|
|
||||||
| 5 | dist_to_grid_lower | 3.75% |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 五、周评分回测结果 (2023-04 ~ 2026-04)
|
|
||||||
|
|
||||||
| 指标 | v6.6 数值 |
|
|
||||||
|------|-----------|
|
|
||||||
| **总收益率** | **+36.79%** |
|
|
||||||
| 年化夏普 | 0.8494 |
|
|
||||||
| 最大回撤 | -12.70% |
|
|
||||||
| 胜率(周) | 48.7% |
|
|
||||||
| 交易次数 | 277 (147买, 130卖) |
|
|
||||||
| 最大持仓 | 10只 |
|
|
||||||
|
|
||||||
### 年度收益
|
|
||||||
| 年度 | 收益 |
|
|
||||||
|------|------|
|
|
||||||
| 2023 | +2.09% |
|
|
||||||
| 2024 | +28.34% |
|
|
||||||
| 2025 | +7.32% |
|
|
||||||
| 2026 | +0.52% |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 六、与v6.5对比
|
|
||||||
|
|
||||||
| 指标 | v6.5 | v6.6 | 变化 |
|
|
||||||
|------|------|------|------|
|
|
||||||
| Stacking PR-AUC | 0.5234 | **0.8207** | +57% |
|
|
||||||
| 特征数 | 37维 | **52维** | +15维 |
|
|
||||||
| Top PR-AUC | 0.3923 | 0.5333 | +36% |
|
|
||||||
| 回测收益率 | 59.82% | 36.79%* | - |
|
|
||||||
| 回测最大回撤 | -33.47% | **-12.70%** | -62% |
|
|
||||||
|
|
||||||
\* v6.6使用周评分回测(157周),v6.5使用日评分回测(723天),粒度不同
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 七、模型文件
|
|
||||||
|
|
||||||
| 文件 | 说明 |
|
|
||||||
|------|------|
|
|
||||||
| `rank.pkl` | Rank模型 (预测网格轮回次数) |
|
|
||||||
| `top.pkl` | Top模型 (分类精英股票) |
|
|
||||||
| `stacking.pkl` | Stacking融合模型 |
|
|
||||||
| `rank_feature_importance.csv` | Rank特征重要性 |
|
|
||||||
| `top_feature_importance.csv` | Top特征重要性 |
|
|
||||||
| `stacking_feature_importance.csv` | Stacking特征重要性 |
|
|
||||||
| `training_summary.json` | 训练摘要 |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 八、使用方式
|
|
||||||
|
|
||||||
```python
|
|
||||||
import pickle
|
|
||||||
import numpy as np
|
|
||||||
|
|
||||||
# 加载模型
|
|
||||||
with open("rank.pkl", "rb") as f:
|
|
||||||
rank_md = pickle.load(f)
|
|
||||||
with open("top.pkl", "rb") as f:
|
|
||||||
top_md = pickle.load(f)
|
|
||||||
with open("stacking.pkl", "rb") as f:
|
|
||||||
stacking_md = pickle.load(f)
|
|
||||||
|
|
||||||
# 预测
|
|
||||||
rank_pred = rank_md["model"].predict(features)
|
|
||||||
top_prob = top_md["model"].predict_proba(features)[:, 1]
|
|
||||||
stacking_prob = stacking_md["model"].predict_proba(features)[:, 1]
|
|
||||||
|
|
||||||
# 选股
|
|
||||||
threshold = 0.35 # stacking最优阈值
|
|
||||||
top_picks = scores[scores["stacking_prob"] >= threshold]
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 九、Registry配置
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
# grid_seeker/registry.yaml
|
|
||||||
production:
|
|
||||||
version: v6.6
|
|
||||||
architecture: stacking_calibrated
|
|
||||||
models:
|
|
||||||
stacking: versions/6.6/output/stacking.pkl
|
|
||||||
rank: versions/6.6/output/rank.pkl
|
|
||||||
top: versions/6.6/output/top.pkl
|
|
||||||
feature_version: v3.4
|
|
||||||
training_samples: 205491
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 十、注意事项
|
|
||||||
|
|
||||||
1. **特征版本**: 必须使用 v3.4 特征(52维),与v6.5/v6.4不兼容
|
|
||||||
2. **Stacking阈值**: 推荐使用 0.35 作为选股阈值
|
|
||||||
3. **持股上限**: 建议不超过10只
|
|
||||||
4. **价格区间**: 适合7-10元区间股票
|
|
||||||
@@ -0,0 +1,727 @@
|
|||||||
|
date,cash,holding_market_value,total_asset
|
||||||
|
2023-05-04,28289.86,33283.08,61572.94
|
||||||
|
2023-05-05,29353.86,32311.96,61665.82
|
||||||
|
2023-05-08,29553.86,32215.16,61769.020000000004
|
||||||
|
2023-05-09,27953.86,32879.84,60833.7
|
||||||
|
2023-05-10,26153.86,35374.479999999996,61528.34
|
||||||
|
2023-05-11,29753.86,33225.380000000005,62979.240000000005
|
||||||
|
2023-05-12,24353.86,37200.04,61553.9
|
||||||
|
2023-05-15,25667.86,35345.6,61013.46
|
||||||
|
2023-05-16,20867.86,38643.44,59511.3
|
||||||
|
2023-05-17,17667.86,42281.4,59949.26
|
||||||
|
2023-05-18,17667.86,43420.1,61087.96
|
||||||
|
2023-05-19,19999.86,40128.84,60128.7
|
||||||
|
2023-05-22,19136.34,40407.96,59544.3
|
||||||
|
2023-05-23,19136.34,39661.66,58798.0
|
||||||
|
2023-05-24,19136.34,39738.92,58875.259999999995
|
||||||
|
2023-05-25,17736.34,40531.479999999996,58267.81999999999
|
||||||
|
2023-05-26,17736.34,41098.4,58834.740000000005
|
||||||
|
2023-05-29,14136.34,44736.28,58872.619999999995
|
||||||
|
2023-05-30,14336.34,45939.42,60275.759999999995
|
||||||
|
2023-05-31,14336.34,45642.6,59978.94
|
||||||
|
2023-06-01,20433.92,41484.86,61918.78
|
||||||
|
2023-06-02,22233.92,40253.44,62487.36
|
||||||
|
2023-06-05,20683.899999999998,42477.36,63161.259999999995
|
||||||
|
2023-06-06,24283.899999999998,37810.38,62094.28
|
||||||
|
2023-06-07,22683.899999999998,40119.560000000005,62803.46000000001
|
||||||
|
2023-06-08,21083.899999999998,40887.58,61971.479999999996
|
||||||
|
2023-06-09,23083.899999999998,39432.4,62516.3
|
||||||
|
2023-06-12,23083.899999999998,39468.780000000006,62552.68000000001
|
||||||
|
2023-06-13,23083.899999999998,40270.58,63354.479999999996
|
||||||
|
2023-06-14,24883.899999999998,38792.08,63675.979999999996
|
||||||
|
2023-06-15,26883.899999999998,36531.32000000001,63415.22
|
||||||
|
2023-06-16,27171.899999999998,36662.04,63833.94
|
||||||
|
2023-06-19,30577.359999999997,33518.72,64096.08
|
||||||
|
2023-06-20,28977.359999999997,35500.700000000004,64478.06
|
||||||
|
2023-06-21,27177.359999999997,35306.82,62484.17999999999
|
||||||
|
2023-06-26,25315.46,35218.7,60534.159999999996
|
||||||
|
2023-06-27,20515.46,40464.58,60980.04
|
||||||
|
2023-06-28,20515.46,39961.2,60476.659999999996
|
||||||
|
2023-06-29,20515.46,40167.38,60682.84
|
||||||
|
2023-06-30,20515.46,40323.66,60839.12
|
||||||
|
2023-07-03,28555.76,32259.06,60814.82
|
||||||
|
2023-07-04,28555.76,32140.9,60696.66
|
||||||
|
2023-07-05,28555.76,31760.359999999997,60316.119999999995
|
||||||
|
2023-07-06,28555.76,32029.4,60585.16
|
||||||
|
2023-07-07,27155.76,33151.0,60306.759999999995
|
||||||
|
2023-07-10,30335.76,30607.5,60943.259999999995
|
||||||
|
2023-07-11,30335.76,29987.239999999998,60323.0
|
||||||
|
2023-07-12,27135.76,32715.800000000003,59851.56
|
||||||
|
2023-07-13,28735.76,32062.980000000003,60798.740000000005
|
||||||
|
2023-07-14,29091.76,31705.800000000003,60797.56
|
||||||
|
2023-07-17,27259.08,33179.8,60438.880000000005
|
||||||
|
2023-07-18,27259.08,33110.299999999996,60369.38
|
||||||
|
2023-07-19,27259.08,33071.82,60330.9
|
||||||
|
2023-07-20,27259.08,32716.16,59975.240000000005
|
||||||
|
2023-07-21,27608.82,32509.1,60117.92
|
||||||
|
2023-07-24,29909.840000000004,30081.24,59991.08
|
||||||
|
2023-07-25,29909.840000000004,30276.039999999997,60185.880000000005
|
||||||
|
2023-07-26,31797.840000000004,27988.0,59785.840000000004
|
||||||
|
2023-07-27,31797.840000000004,27916.859999999997,59714.7
|
||||||
|
2023-07-28,30397.840000000004,29960.780000000002,60358.62000000001
|
||||||
|
2023-07-31,31034.120000000003,29691.679999999997,60725.8
|
||||||
|
2023-08-01,31326.78,29226.62,60553.399999999994
|
||||||
|
2023-08-02,33126.78,27590.860000000004,60717.64
|
||||||
|
2023-08-03,31326.78,29124.66,60451.44
|
||||||
|
2023-08-04,31326.78,29340.219999999998,60667.0
|
||||||
|
2023-08-07,28402.46,32404.219999999998,60806.67999999999
|
||||||
|
2023-08-08,28402.46,32277.72,60680.18
|
||||||
|
2023-08-09,28602.46,31887.659999999996,60490.119999999995
|
||||||
|
2023-08-10,28602.46,32160.539999999997,60763.0
|
||||||
|
2023-08-11,28602.46,31713.8,60316.259999999995
|
||||||
|
2023-08-14,30216.02,30586.119999999995,60802.14
|
||||||
|
2023-08-15,30216.02,30597.48,60813.5
|
||||||
|
2023-08-16,32216.02,28753.199999999997,60969.22
|
||||||
|
2023-08-17,30416.02,31062.44,61478.46
|
||||||
|
2023-08-18,33136.700000000004,28257.34,61394.04000000001
|
||||||
|
2023-08-21,31336.700000000004,30055.36,61392.060000000005
|
||||||
|
2023-08-22,29536.700000000004,32326.899999999998,61863.600000000006
|
||||||
|
2023-08-23,29536.700000000004,31548.5,61085.200000000004
|
||||||
|
2023-08-24,29536.700000000004,31743.98,61280.68000000001
|
||||||
|
2023-08-25,26136.700000000004,34300.62,60437.32000000001
|
||||||
|
2023-08-28,29708.780000000006,31279.519999999997,60988.3
|
||||||
|
2023-08-29,30196.780000000006,32665.699999999997,62862.48
|
||||||
|
2023-08-30,32196.780000000006,31247.879999999997,63444.66
|
||||||
|
2023-08-31,34196.780000000006,29057.66,63254.44
|
||||||
|
2023-09-01,33946.780000000006,29311.820000000003,63258.600000000006
|
||||||
|
2023-09-04,34135.520000000004,29560.14,63695.66
|
||||||
|
2023-09-05,34509.780000000006,29185.22,63695.00000000001
|
||||||
|
2023-09-06,32709.780000000006,30561.239999999998,63271.020000000004
|
||||||
|
2023-09-07,33082.920000000006,30092.64,63175.560000000005
|
||||||
|
2023-09-08,29682.920000000006,33243.98,62926.90000000001
|
||||||
|
2023-09-11,28129.100000000006,35377.44,63506.54000000001
|
||||||
|
2023-09-12,30129.100000000006,33934.32,64063.420000000006
|
||||||
|
2023-09-13,31929.100000000006,32089.72,64018.82000000001
|
||||||
|
2023-09-14,31929.100000000006,31721.36,63650.46000000001
|
||||||
|
2023-09-15,33929.100000000006,29926.239999999998,63855.340000000004
|
||||||
|
2023-09-18,35984.3,28165.4,64149.700000000004
|
||||||
|
2023-09-19,36370.3,27593.84,63964.14
|
||||||
|
2023-09-20,36917.340000000004,27446.239999999998,64363.58
|
||||||
|
2023-09-21,35117.340000000004,29112.16,64229.5
|
||||||
|
2023-09-22,35117.340000000004,29932.44,65049.78
|
||||||
|
2023-09-25,35673.340000000004,30188.22,65861.56
|
||||||
|
2023-09-26,33873.340000000004,31843.26,65716.6
|
||||||
|
2023-09-27,33873.340000000004,32595.0,66468.34
|
||||||
|
2023-09-28,39873.340000000004,27709.4,67582.74
|
||||||
|
2023-10-09,41247.340000000004,26008.479999999996,67255.82
|
||||||
|
2023-10-10,43605.08,24212.319999999996,67817.4
|
||||||
|
2023-10-11,43805.08,23993.4,67798.48000000001
|
||||||
|
2023-10-12,44083.08,23915.480000000003,67998.56
|
||||||
|
2023-10-13,44083.08,23683.52,67766.6
|
||||||
|
2023-10-16,43689.08,23793.599999999995,67482.68
|
||||||
|
2023-10-17,42089.08,25216.94,67306.02
|
||||||
|
2023-10-18,38489.08,28344.4,66833.48000000001
|
||||||
|
2023-10-19,36689.08,29789.940000000002,66479.02
|
||||||
|
2023-10-20,33289.08,32655.699999999997,65944.78
|
||||||
|
2023-10-23,31442.520000000004,33523.66,64966.18000000001
|
||||||
|
2023-10-24,29642.520000000004,36040.58,65683.1
|
||||||
|
2023-10-25,33642.520000000004,33017.58,66660.1
|
||||||
|
2023-10-26,34288.520000000004,33149.32,67437.84
|
||||||
|
2023-10-27,36088.520000000004,31940.920000000002,68029.44
|
||||||
|
2023-10-30,37285.62,32011.34,69296.96
|
||||||
|
2023-10-31,39938.9,29558.3,69497.2
|
||||||
|
2023-11-01,38429.700000000004,30972.719999999994,69402.42
|
||||||
|
2023-11-02,40429.700000000004,28891.5,69321.20000000001
|
||||||
|
2023-11-03,40429.700000000004,29377.8,69807.5
|
||||||
|
2023-11-06,41176.26,29848.48,71024.74
|
||||||
|
2023-11-07,45432.26,26553.34,71985.6
|
||||||
|
2023-11-08,45782.26,26698.7,72480.96
|
||||||
|
2023-11-09,48079.740000000005,24910.94,72990.68000000001
|
||||||
|
2023-11-10,46479.740000000005,25900.26,72380.0
|
||||||
|
2023-11-13,48501.3,24292.92,72794.22
|
||||||
|
2023-11-14,46701.3,26683.64,73384.94
|
||||||
|
2023-11-15,46957.340000000004,26097.679999999997,73055.02
|
||||||
|
2023-11-16,47157.340000000004,26279.88,73437.22
|
||||||
|
2023-11-17,49341.340000000004,24523.559999999998,73864.9
|
||||||
|
2023-11-20,51584.740000000005,23124.5,74709.24
|
||||||
|
2023-11-21,51940.740000000005,22778.399999999998,74719.14
|
||||||
|
2023-11-22,49054.740000000005,26431.32,75486.06
|
||||||
|
2023-11-23,50182.740000000005,25830.2,76012.94
|
||||||
|
2023-11-24,49700.740000000005,27047.760000000002,76748.5
|
||||||
|
2023-11-27,52958.340000000004,24999.68,77958.02
|
||||||
|
2023-11-28,46244.340000000004,30826.699999999997,77071.04000000001
|
||||||
|
2023-11-29,41844.340000000004,33468.94,75313.28
|
||||||
|
2023-11-30,37244.340000000004,37343.26,74587.6
|
||||||
|
2023-12-01,33892.340000000004,39456.38,73348.72
|
||||||
|
2023-12-04,29451.340000000004,43211.36,72662.70000000001
|
||||||
|
2023-12-05,36811.340000000004,40589.1,77400.44
|
||||||
|
2023-12-06,43811.340000000004,34448.659999999996,78260.0
|
||||||
|
2023-12-07,49721.340000000004,30807.46,80528.8
|
||||||
|
2023-12-08,50831.340000000004,30194.3,81025.64
|
||||||
|
2023-12-11,41721.94,37976.44,79698.38
|
||||||
|
2023-12-12,41967.94,38844.28,80812.22
|
||||||
|
2023-12-13,41967.94,40205.56,82173.5
|
||||||
|
2023-12-14,48057.94,35801.66,83859.6
|
||||||
|
2023-12-15,52387.94,31884.0,84271.94
|
||||||
|
2023-12-18,54779.94,31022.0,85801.94
|
||||||
|
2023-12-19,56379.94,28964.0,85343.94
|
||||||
|
2023-12-20,58379.94,28260.0,86639.94
|
||||||
|
2023-12-21,60909.94,24672.0,85581.94
|
||||||
|
2023-12-22,52909.94,32946.0,85855.94
|
||||||
|
2023-12-25,54909.94,32782.0,87691.94
|
||||||
|
2023-12-26,54909.94,33254.0,88163.94
|
||||||
|
2023-12-27,57197.94,31222.0,88419.94
|
||||||
|
2023-12-28,55761.94,33084.0,88845.94
|
||||||
|
2023-12-29,56387.94,33956.0,90343.94
|
||||||
|
2024-01-02,62813.94,29938.0,92751.94
|
||||||
|
2024-01-03,65205.94,27608.0,92813.94
|
||||||
|
2024-01-04,63405.94,29272.0,92677.94
|
||||||
|
2024-01-05,56405.94,34602.0,91007.94
|
||||||
|
2024-01-08,58405.94,31830.0,90235.94
|
||||||
|
2024-01-09,48405.94,40204.0,88609.94
|
||||||
|
2024-01-10,43605.94,45832.0,89437.94
|
||||||
|
2024-01-11,45405.94,44096.0,89501.94
|
||||||
|
2024-01-12,42405.94,42438.0,84843.94
|
||||||
|
2024-01-15,35605.94,46922.0,82527.94
|
||||||
|
2024-01-16,34005.94,52684.0,86689.94
|
||||||
|
2024-01-17,37205.94,49538.0,86743.94
|
||||||
|
2024-01-18,39005.94,49904.0,88909.94
|
||||||
|
2024-01-19,44405.94,46458.0,90863.94
|
||||||
|
2024-01-22,45355.94,42936.0,88291.94
|
||||||
|
2024-01-23,45355.94,44114.0,89469.94
|
||||||
|
2024-01-24,47895.94,42334.0,90229.94
|
||||||
|
2024-01-25,46695.94,42518.0,89213.94
|
||||||
|
2024-01-26,43543.94,44782.0,88325.94
|
||||||
|
2024-01-29,39113.94,44472.0,83585.94
|
||||||
|
2024-01-30,33513.94,50754.0,84267.94
|
||||||
|
2024-01-31,40113.94,46114.0,86227.94
|
||||||
|
2024-02-01,38705.94,44274.0,82979.94
|
||||||
|
2024-02-02,27305.940000000002,52690.0,79995.94
|
||||||
|
2024-02-05,22445.940000000002,55230.0,77675.94
|
||||||
|
2024-02-06,27245.940000000002,56198.0,83443.94
|
||||||
|
2024-02-07,36845.94,46666.0,83511.94
|
||||||
|
2024-02-08,31419.940000000002,51926.0,83345.94
|
||||||
|
2024-02-19,36311.94,48834.0,85145.94
|
||||||
|
2024-02-20,39861.28,47910.66,87771.94
|
||||||
|
2024-02-21,39861.28,48018.96,87880.23999999999
|
||||||
|
2024-02-22,41861.28,45818.24,87679.51999999999
|
||||||
|
2024-02-23,41861.28,44551.96,86413.23999999999
|
||||||
|
2024-02-26,45030.24,41690.74,86720.98
|
||||||
|
2024-02-27,48777.32,41789.439999999995,90566.76
|
||||||
|
2024-02-28,49161.3,39334.85999999999,88496.16
|
||||||
|
2024-02-29,45761.3,44599.96,90361.26000000001
|
||||||
|
2024-03-01,49575.3,40919.28,90494.58
|
||||||
|
2024-03-04,52677.94,37579.03999999999,90256.98
|
||||||
|
2024-03-05,51277.94,38087.04,89364.98000000001
|
||||||
|
2024-03-06,53277.94,36919.08,90197.02
|
||||||
|
2024-03-07,53677.94,35949.98,89627.92000000001
|
||||||
|
2024-03-08,53677.94,35737.8,89415.74
|
||||||
|
2024-03-11,57519.94,32557.06,90077.0
|
||||||
|
2024-03-12,59847.920000000006,30947.68,90795.6
|
||||||
|
2024-03-13,59847.920000000006,30429.56,90277.48000000001
|
||||||
|
2024-03-14,60047.920000000006,30268.980000000003,90316.90000000001
|
||||||
|
2024-03-15,60047.920000000006,31026.780000000002,91074.70000000001
|
||||||
|
2024-03-18,62559.920000000006,29269.68,91829.6
|
||||||
|
2024-03-19,62905.560000000005,29223.520000000004,92129.08000000002
|
||||||
|
2024-03-20,65165.560000000005,27477.68,92643.24
|
||||||
|
2024-03-21,65873.84,26703.800000000003,92577.64
|
||||||
|
2024-03-22,65873.84,26076.62,91950.45999999999
|
||||||
|
2024-03-25,61065.36,29863.06,90928.42
|
||||||
|
2024-03-26,59265.36,31568.499999999996,90833.86
|
||||||
|
2024-03-27,55865.36,34504.659999999996,90370.01999999999
|
||||||
|
2024-03-28,60401.36,30693.719999999998,91095.08
|
||||||
|
2024-03-29,60401.36,30781.6,91182.95999999999
|
||||||
|
2024-04-01,66053.02,26153.920000000002,92206.94
|
||||||
|
2024-04-02,66617.02,25795.5,92412.52
|
||||||
|
2024-04-03,65179.58,26641.44,91821.02
|
||||||
|
2024-04-08,63035.58,27350.300000000003,90385.88
|
||||||
|
2024-04-09,61435.58,29304.18,90739.76000000001
|
||||||
|
2024-04-10,56635.58,33710.5,90346.08
|
||||||
|
2024-04-11,56903.58,32962.08,89865.66
|
||||||
|
2024-04-12,56903.58,32507.18,89410.76000000001
|
||||||
|
2024-04-15,45899.58,40168.12,86067.70000000001
|
||||||
|
2024-04-16,36699.58,44627.16,81326.74
|
||||||
|
2024-04-17,33499.58,52978.979999999996,86478.56
|
||||||
|
2024-04-18,33499.58,53139.6,86639.18
|
||||||
|
2024-04-19,33499.58,52126.22,85625.8
|
||||||
|
2024-04-22,35961.58,49286.22,85247.8
|
||||||
|
2024-04-23,39761.58,47887.979999999996,87649.56
|
||||||
|
2024-04-24,41361.58,47785.3,89146.88
|
||||||
|
2024-04-25,41161.58,47469.36,88630.94
|
||||||
|
2024-04-26,42761.58,46693.66,89455.24
|
||||||
|
2024-04-29,46142.72,44846.68,90989.4
|
||||||
|
2024-04-30,51342.72,39697.380000000005,91040.1
|
||||||
|
2024-05-06,59221.060000000005,32499.46,91720.52
|
||||||
|
2024-05-07,59421.060000000005,32774.7,92195.76000000001
|
||||||
|
2024-05-08,59805.060000000005,31778.78,91583.84
|
||||||
|
2024-05-09,58005.060000000005,33495.740000000005,91500.80000000002
|
||||||
|
2024-05-10,56205.060000000005,34632.66,90837.72
|
||||||
|
2024-05-13,54405.060000000005,35785.520000000004,90190.58000000002
|
||||||
|
2024-05-14,56405.060000000005,34677.5,91082.56
|
||||||
|
2024-05-15,56791.060000000005,34668.46,91459.52
|
||||||
|
2024-05-16,58591.060000000005,33183.68,91774.74
|
||||||
|
2024-05-17,60869.060000000005,31647.16,92516.22
|
||||||
|
2024-05-20,60891.060000000005,31465.64,92356.70000000001
|
||||||
|
2024-05-21,61091.060000000005,31509.34,92600.40000000001
|
||||||
|
2024-05-22,61405.060000000005,31812.32,93217.38
|
||||||
|
2024-05-23,61405.060000000005,32031.88,93436.94
|
||||||
|
2024-05-24,59605.060000000005,32880.44,92485.5
|
||||||
|
2024-05-27,59387.50000000001,33578.0,92965.5
|
||||||
|
2024-05-28,63387.50000000001,29672.0,93059.5
|
||||||
|
2024-05-29,61787.50000000001,31334.0,93121.5
|
||||||
|
2024-05-30,64141.5,28916.0,93057.5
|
||||||
|
2024-05-31,64141.5,29130.0,93271.5
|
||||||
|
2024-06-03,59560.399999999994,32518.96,92079.35999999999
|
||||||
|
2024-06-04,57760.399999999994,33912.6,91673.0
|
||||||
|
2024-06-05,56160.399999999994,34984.96,91145.35999999999
|
||||||
|
2024-06-06,47960.399999999994,40566.12,88526.51999999999
|
||||||
|
2024-06-07,47960.399999999994,42130.56,90090.95999999999
|
||||||
|
2024-06-11,50552.399999999994,40529.64,91082.04
|
||||||
|
2024-06-12,54152.399999999994,37975.64,92128.04
|
||||||
|
2024-06-13,56152.399999999994,36528.12,92680.51999999999
|
||||||
|
2024-06-14,56152.399999999994,36035.36,92187.76
|
||||||
|
2024-06-17,58145.759999999995,33718.0,91863.76
|
||||||
|
2024-06-18,60345.759999999995,32524.0,92869.76
|
||||||
|
2024-06-19,64277.759999999995,29616.0,93893.76
|
||||||
|
2024-06-20,59921.759999999995,33686.0,93607.76
|
||||||
|
2024-06-21,62239.759999999995,31984.0,94223.76
|
||||||
|
2024-06-24,56927.759999999995,35350.0,92277.76
|
||||||
|
2024-06-25,53927.759999999995,37340.0,91267.76
|
||||||
|
2024-06-26,52527.759999999995,40366.0,92893.76
|
||||||
|
2024-06-27,52527.759999999995,39326.0,91853.76
|
||||||
|
2024-06-28,52527.759999999995,40070.0,92597.76
|
||||||
|
2024-07-01,57551.759999999995,35500.0,93051.76
|
||||||
|
2024-07-02,57551.759999999995,36244.0,93795.76
|
||||||
|
2024-07-03,57551.759999999995,36146.0,93697.76
|
||||||
|
2024-07-04,55751.759999999995,36268.0,92019.76
|
||||||
|
2024-07-05,52351.759999999995,40466.0,92817.76
|
||||||
|
2024-07-08,53531.759999999995,38242.0,91773.76
|
||||||
|
2024-07-09,52891.759999999995,40390.0,93281.76
|
||||||
|
2024-07-10,51451.719999999994,41648.04,93099.76
|
||||||
|
2024-07-11,51451.719999999994,42945.86,94397.57999999999
|
||||||
|
2024-07-12,51451.719999999994,42662.64,94114.35999999999
|
||||||
|
2024-07-15,52778.87999999999,40392.92,93171.79999999999
|
||||||
|
2024-07-16,52778.87999999999,41218.92,93997.79999999999
|
||||||
|
2024-07-17,57090.87999999999,36641.42,93732.29999999999
|
||||||
|
2024-07-18,55290.87999999999,38284.96,93575.84
|
||||||
|
2024-07-19,55290.87999999999,38665.44,93956.31999999999
|
||||||
|
2024-07-22,60996.87999999999,34089.5,95086.37999999999
|
||||||
|
2024-07-23,60996.87999999999,33558.479999999996,94555.35999999999
|
||||||
|
2024-07-24,62796.87999999999,31740.760000000002,94537.63999999998
|
||||||
|
2024-07-25,61256.87999999999,33841.24,95098.12
|
||||||
|
2024-07-26,61456.87999999999,33980.7,95437.57999999999
|
||||||
|
2024-07-29,59777.73999999999,35923.119999999995,95700.85999999999
|
||||||
|
2024-07-30,61777.73999999999,34529.72,96307.45999999999
|
||||||
|
2024-07-31,64101.73999999999,33334.0,97435.73999999999
|
||||||
|
2024-08-01,65125.73999999999,32018.0,97143.73999999999
|
||||||
|
2024-08-02,61925.73999999999,34468.0,96393.73999999999
|
||||||
|
2024-08-05,62605.73999999999,32892.0,95497.73999999999
|
||||||
|
2024-08-06,62605.73999999999,34194.0,96799.73999999999
|
||||||
|
2024-08-07,64405.73999999999,32874.0,97279.73999999999
|
||||||
|
2024-08-08,64605.73999999999,31938.0,96543.73999999999
|
||||||
|
2024-08-09,63005.73999999999,33154.0,96159.73999999999
|
||||||
|
2024-08-12,61315.73999999999,34852.0,96167.73999999999
|
||||||
|
2024-08-13,59515.73999999999,36410.0,95925.73999999999
|
||||||
|
2024-08-14,59515.73999999999,35968.0,95483.73999999999
|
||||||
|
2024-08-15,58515.73999999999,37140.0,95655.73999999999
|
||||||
|
2024-08-16,56715.73999999999,39058.0,95773.73999999999
|
||||||
|
2024-08-19,56764.19999999999,38072.64,94836.84
|
||||||
|
2024-08-20,56764.19999999999,38040.52,94804.71999999999
|
||||||
|
2024-08-21,55164.19999999999,38808.92,93973.12
|
||||||
|
2024-08-22,53564.19999999999,39192.04,92756.23999999999
|
||||||
|
2024-08-23,55364.19999999999,37672.44,93036.63999999998
|
||||||
|
2024-08-26,56940.25999999999,36384.899999999994,93325.15999999997
|
||||||
|
2024-08-27,57540.25999999999,35327.28,92867.53999999998
|
||||||
|
2024-08-28,52940.25999999999,39837.560000000005,92777.81999999999
|
||||||
|
2024-08-29,51892.25999999999,41458.62,93350.87999999999
|
||||||
|
2024-08-30,52183.51999999999,42771.06,94954.57999999999
|
||||||
|
2024-09-02,56710.33999999999,37626.06,94336.4
|
||||||
|
2024-09-03,58710.33999999999,36281.9,94992.23999999999
|
||||||
|
2024-09-04,58710.33999999999,35629.16,94339.5
|
||||||
|
2024-09-05,58710.33999999999,36421.92,95132.25999999998
|
||||||
|
2024-09-06,58710.33999999999,35878.58,94588.91999999998
|
||||||
|
2024-09-09,58906.33999999999,35322.54000000001,94228.88
|
||||||
|
2024-09-10,57306.33999999999,37236.6,94542.93999999999
|
||||||
|
2024-09-11,57306.33999999999,36978.36,94284.69999999998
|
||||||
|
2024-09-12,62642.33999999999,31378.359999999997,94020.69999999998
|
||||||
|
2024-09-13,62642.33999999999,30741.5,93383.84
|
||||||
|
2024-09-18,58008.74,34825.06,92833.79999999999
|
||||||
|
2024-09-19,58359.32,35364.84,93724.16
|
||||||
|
2024-09-20,58359.32,34882.94,93242.26000000001
|
||||||
|
2024-09-23,59825.32,33529.54,93354.86
|
||||||
|
2024-09-24,59825.32,35009.0,94834.32
|
||||||
|
2024-09-25,62217.32,33031.08,95248.4
|
||||||
|
2024-09-26,62723.32000000001,33992.1,96715.42000000001
|
||||||
|
2024-09-27,69235.32,29121.08,98356.40000000001
|
||||||
|
2024-09-30,80349.32,21369.96,101719.28
|
||||||
|
2024-10-08,85077.28,19476.0,104553.28
|
||||||
|
2024-10-09,77483.28,25692.0,103175.28
|
||||||
|
2024-10-10,65483.28,35852.0,101335.28
|
||||||
|
2024-10-11,56083.28,43112.0,99195.28
|
||||||
|
2024-10-14,54845.28,47550.0,102395.28
|
||||||
|
2024-10-15,62245.28,40032.0,102277.28
|
||||||
|
2024-10-16,64429.28,38264.0,102693.28
|
||||||
|
2024-10-17,71101.28,33832.0,104933.28
|
||||||
|
2024-10-18,71101.28,35670.0,106771.28
|
||||||
|
2024-10-21,81899.28,27310.0,109209.28
|
||||||
|
2024-10-22,78499.28,29890.0,108389.28
|
||||||
|
2024-10-23,79145.28,31210.0,110355.28
|
||||||
|
2024-10-24,83457.28,27304.0,110761.28
|
||||||
|
2024-10-25,87055.28,25324.0,112379.28
|
||||||
|
2024-10-28,82369.28,32322.0,114691.28
|
||||||
|
2024-10-29,94723.28,21330.0,116053.28
|
||||||
|
2024-10-30,93926.66,22730.62,116657.28
|
||||||
|
2024-10-31,92874.66,23630.56,116505.22
|
||||||
|
2024-11-01,90986.66,26929.52,117916.18000000001
|
||||||
|
2024-11-04,88286.66,31429.6,119716.26000000001
|
||||||
|
2024-11-05,99332.66,22827.28,122159.94
|
||||||
|
2024-11-06,100274.82,22557.2,122832.02
|
||||||
|
2024-11-07,97836.82,26869.02,124705.84000000001
|
||||||
|
2024-11-08,100636.82,23667.66,124304.48000000001
|
||||||
|
2024-11-11,97436.82,27560.78,124997.6
|
||||||
|
2024-11-12,97436.82,27386.06,124822.88
|
||||||
|
2024-11-13,95636.82,29058.3,124695.12000000001
|
||||||
|
2024-11-14,97636.82,26820.22,124457.04000000001
|
||||||
|
2024-11-15,96557.20000000001,28499.719999999998,125056.92000000001
|
||||||
|
2024-11-18,99403.46,26804.239999999998,126207.70000000001
|
||||||
|
2024-11-19,87403.46,38321.020000000004,125724.48000000001
|
||||||
|
2024-11-20,91665.46,36476.68,128142.14000000001
|
||||||
|
2024-11-21,97525.46,31670.04,129195.5
|
||||||
|
2024-11-22,102164.48000000001,26932.02,129096.50000000001
|
||||||
|
2024-11-25,100326.48000000001,29415.52,129742.00000000001
|
||||||
|
2024-11-26,98726.48000000001,30748.68,129475.16
|
||||||
|
2024-11-27,97126.48000000001,32619.879999999997,129746.36000000002
|
||||||
|
2024-11-28,101950.1,29081.36,131031.46
|
||||||
|
2024-11-29,101950.1,29600.280000000002,131550.38
|
||||||
|
2024-12-02,108792.78,23990.58,132783.36
|
||||||
|
2024-12-03,105192.78,27452.98,132645.76
|
||||||
|
2024-12-04,103392.78,27856.059999999998,131248.84
|
||||||
|
2024-12-05,103392.78,28402.48,131795.26
|
||||||
|
2024-12-06,103392.78,28411.32,131804.1
|
||||||
|
2024-12-09,97964.12,32072.58,130036.7
|
||||||
|
2024-12-10,96164.12,34057.399999999994,130221.51999999999
|
||||||
|
2024-12-11,94564.12,35279.64,129843.76
|
||||||
|
2024-12-12,94844.12,35000.0,129844.12
|
||||||
|
2024-12-13,96844.12,33198.0,130042.12
|
||||||
|
2024-12-16,92244.12,37306.0,129550.12
|
||||||
|
2024-12-17,90444.12,36824.0,127268.12
|
||||||
|
2024-12-18,85644.12,41096.0,126740.12
|
||||||
|
2024-12-19,82444.12,45412.0,127856.12
|
||||||
|
2024-12-20,82444.12,44764.0,127208.12
|
||||||
|
2024-12-23,86146.12,38902.0,125048.12
|
||||||
|
2024-12-24,88234.12,37016.0,125250.12
|
||||||
|
2024-12-25,83634.12,39390.0,123024.12
|
||||||
|
2024-12-26,85918.12,38396.0,124314.12
|
||||||
|
2024-12-27,89318.12,35982.0,125300.12
|
||||||
|
2024-12-30,84450.12,39132.0,123582.12
|
||||||
|
2024-12-31,86250.12,38410.0,124660.12
|
||||||
|
2025-01-02,85608.12,39822.0,125430.12
|
||||||
|
2025-01-03,87408.12,37578.0,124986.12
|
||||||
|
2025-01-06,87180.12,36526.0,123706.12
|
||||||
|
2025-01-07,85580.12,39196.0,124776.12
|
||||||
|
2025-01-08,85580.12,39276.0,124856.12
|
||||||
|
2025-01-09,85580.12,40108.0,125688.12
|
||||||
|
2025-01-10,85580.12,38096.0,123676.12
|
||||||
|
2025-01-13,86472.12,36632.0,123104.12
|
||||||
|
2025-01-14,90534.12,35542.0,126076.12
|
||||||
|
2025-01-15,92964.12,33396.0,126360.12
|
||||||
|
2025-01-16,92964.12,33474.0,126438.12
|
||||||
|
2025-01-17,92964.12,32718.0,125682.12
|
||||||
|
2025-01-20,92444.12,33334.0,125778.12
|
||||||
|
2025-01-21,90644.12,34562.0,125206.12
|
||||||
|
2025-01-22,88844.12,35200.0,124044.12
|
||||||
|
2025-01-23,92964.12,31104.0,124068.12
|
||||||
|
2025-01-24,92964.12,30942.0,123906.12
|
||||||
|
2025-01-27,93264.12,29920.0,123184.12
|
||||||
|
2025-02-05,95550.12,28902.0,124452.12
|
||||||
|
2025-02-06,95386.12,30334.0,125720.12
|
||||||
|
2025-02-07,99682.12,27098.0,126780.12
|
||||||
|
2025-02-10,101682.12,26282.0,127964.12
|
||||||
|
2025-02-11,102255.36,25700.760000000002,127956.12
|
||||||
|
2025-02-12,106503.36,22042.74,128546.1
|
||||||
|
2025-02-13,106503.36,21696.8,128200.16
|
||||||
|
2025-02-14,106503.36,21418.78,127922.14
|
||||||
|
2025-02-17,106503.36,22392.739999999998,128896.1
|
||||||
|
2025-02-18,106863.36,21594.6,128457.95999999999
|
||||||
|
2025-02-19,107549.72,21399.64,128949.36
|
||||||
|
2025-02-20,105749.72,23389.28,129139.0
|
||||||
|
2025-02-21,105749.72,23782.4,129532.12
|
||||||
|
2025-02-24,107749.72,22060.94,129810.66
|
||||||
|
2025-02-25,106050.72,23940.18,129990.9
|
||||||
|
2025-02-26,106050.72,24078.079999999998,130128.8
|
||||||
|
2025-02-27,104528.72,25574.48,130103.2
|
||||||
|
2025-02-28,102728.72,26542.96,129271.68
|
||||||
|
2025-03-03,99240.72,30762.88,130003.6
|
||||||
|
2025-03-04,104273.36,27485.84,131759.2
|
||||||
|
2025-03-05,106519.36,25571.420000000002,132090.78
|
||||||
|
2025-03-06,103171.36,29194.32,132365.68
|
||||||
|
2025-03-07,105425.36,27040.4,132465.76
|
||||||
|
2025-03-10,105425.36,27684.64,133110.0
|
||||||
|
2025-03-11,105757.36,27476.72,133234.08000000002
|
||||||
|
2025-03-12,107757.36,26166.48,133923.84
|
||||||
|
2025-03-13,110301.82,23848.38,134150.2
|
||||||
|
2025-03-14,115013.82,19782.36,134796.18
|
||||||
|
2025-03-17,115373.82,19713.06,135086.88
|
||||||
|
2025-03-18,116287.82,19132.559999999998,135420.38
|
||||||
|
2025-03-19,112687.82,22446.72,135134.54
|
||||||
|
2025-03-20,111223.82,24020.72,135244.54
|
||||||
|
2025-03-21,109423.82,25211.120000000003,134634.94
|
||||||
|
2025-03-24,102104.94,32562.0,134666.94
|
||||||
|
2025-03-25,104460.1,30420.84,134880.94
|
||||||
|
2025-03-26,106460.1,29221.84,135681.94
|
||||||
|
2025-03-27,106660.1,28888.8,135548.9
|
||||||
|
2025-03-28,103822.1,31484.3,135306.4
|
||||||
|
2025-03-31,100434.62000000001,34067.08,134501.7
|
||||||
|
2025-04-01,101400.62000000001,32980.64,134381.26
|
||||||
|
2025-04-02,101600.62000000001,32563.239999999998,134163.86000000002
|
||||||
|
2025-04-03,99800.62000000001,34518.32,134318.94
|
||||||
|
2025-04-07,87000.62000000001,41837.2,128837.82
|
||||||
|
2025-04-08,80800.62000000001,49853.04,130653.66
|
||||||
|
2025-04-09,88600.62000000001,46010.08,134610.7
|
||||||
|
2025-04-10,98000.62000000001,38655.6,136656.22
|
||||||
|
2025-04-11,99600.62000000001,37063.76,136664.38
|
||||||
|
2025-04-14,106254.62000000001,31782.72,138037.34000000003
|
||||||
|
2025-04-15,104654.62000000001,33317.28,137971.90000000002
|
||||||
|
2025-04-16,106747.54000000001,31677.72,138425.26
|
||||||
|
2025-04-17,108747.54000000001,30180.46,138928.0
|
||||||
|
2025-04-18,109341.54000000001,30561.36,139902.90000000002
|
||||||
|
2025-04-21,107815.54000000001,32425.2,140240.74000000002
|
||||||
|
2025-04-22,107815.54000000001,31336.8,139152.34
|
||||||
|
2025-04-23,109415.54000000001,30456.64,139872.18
|
||||||
|
2025-04-24,109657.54000000001,29465.66,139123.2
|
||||||
|
2025-04-25,106835.54000000001,32281.18,139116.72
|
||||||
|
2025-04-28,106345.54000000001,32082.7,138428.24000000002
|
||||||
|
2025-04-29,102745.54000000001,35483.0,138228.54
|
||||||
|
2025-04-30,102745.54000000001,35759.3,138504.84000000003
|
||||||
|
2025-05-06,104510.84000000001,35040.0,139550.84000000003
|
||||||
|
2025-05-07,107283.84000000001,32649.0,139932.84000000003
|
||||||
|
2025-05-08,104437.84000000001,35792.24,140230.08000000002
|
||||||
|
2025-05-09,102637.84000000001,37585.88,140223.72
|
||||||
|
2025-05-12,103367.84000000001,37894.72,141262.56
|
||||||
|
2025-05-13,103367.84000000001,37302.54,140670.38
|
||||||
|
2025-05-14,103763.84000000001,36662.0,140425.84000000003
|
||||||
|
2025-05-15,101963.84000000001,38680.0,140643.84000000003
|
||||||
|
2025-05-16,101963.84000000001,38900.0,140863.84000000003
|
||||||
|
2025-05-19,101963.84000000001,39840.0,141803.84000000003
|
||||||
|
2025-05-20,105763.84000000001,36696.0,142459.84000000003
|
||||||
|
2025-05-21,107363.84000000001,35314.0,142677.84000000003
|
||||||
|
2025-05-22,109423.84000000001,33250.0,142673.84000000003
|
||||||
|
2025-05-23,109423.84000000001,32758.0,142181.84000000003
|
||||||
|
2025-05-26,110715.84000000001,32416.0,143131.84000000003
|
||||||
|
2025-05-27,114765.84000000001,28756.0,143521.84000000003
|
||||||
|
2025-05-28,118565.84000000001,24386.0,142951.84000000003
|
||||||
|
2025-05-29,118565.84000000001,24558.0,143123.84000000003
|
||||||
|
2025-05-30,115165.84000000001,27606.0,142771.84000000003
|
||||||
|
2025-06-03,113691.88,29479.86,143171.74
|
||||||
|
2025-06-04,117691.88,26375.22,144067.1
|
||||||
|
2025-06-05,118367.88,25461.82,143829.7
|
||||||
|
2025-06-06,118567.88,25523.98,144091.86000000002
|
||||||
|
2025-06-09,118468.06,26145.58,144613.64
|
||||||
|
2025-06-10,119242.06,26013.68,145255.74
|
||||||
|
2025-06-11,115642.06,29543.460000000003,145185.52
|
||||||
|
2025-06-12,119442.06,26731.8,146173.86
|
||||||
|
2025-06-13,121827.45999999999,23271.14,145098.59999999998
|
||||||
|
2025-06-16,118827.45999999999,26558.000000000004,145385.46
|
||||||
|
2025-06-17,119851.45999999999,25974.019999999997,145825.47999999998
|
||||||
|
2025-06-18,118051.45999999999,27032.4,145083.86
|
||||||
|
2025-06-19,112651.45999999999,31251.42,143902.88
|
||||||
|
2025-06-20,109651.45999999999,33717.020000000004,143368.47999999998
|
||||||
|
2025-06-23,108051.45999999999,36004.66,144056.12
|
||||||
|
2025-06-24,108051.45999999999,36450.659999999996,144502.12
|
||||||
|
2025-06-25,108567.45999999999,36190.72,144758.18
|
||||||
|
2025-06-26,108767.45999999999,36286.82,145054.28
|
||||||
|
2025-06-27,108767.45999999999,36246.7,145014.15999999997
|
||||||
|
2025-06-30,108321.45999999999,37252.479999999996,145573.94
|
||||||
|
2025-07-01,115200.18,31736.68,146936.86
|
||||||
|
2025-07-02,117302.28,30046.74,147349.02
|
||||||
|
2025-07-03,117302.28,29892.84,147195.12
|
||||||
|
2025-07-04,117302.28,29383.94,146686.22
|
||||||
|
2025-07-07,117586.28,29861.88,147448.16
|
||||||
|
2025-07-08,117586.28,29913.9,147500.18
|
||||||
|
2025-07-09,117912.28,29733.94,147646.22
|
||||||
|
2025-07-10,118112.28,29558.0,147670.28
|
||||||
|
2025-07-11,116312.28,31418.0,147730.28
|
||||||
|
2025-07-14,114316.28,33108.0,147424.28
|
||||||
|
2025-07-15,112716.28,34186.0,146902.28
|
||||||
|
2025-07-16,114716.28,32426.0,147142.28
|
||||||
|
2025-07-17,114960.2,32414.08,147374.28
|
||||||
|
2025-07-18,113160.2,33946.38,147106.58
|
||||||
|
2025-07-21,116704.2,30680.16,147384.36
|
||||||
|
2025-07-22,116980.59999999999,30577.559999999998,147558.15999999997
|
||||||
|
2025-07-23,116980.59999999999,30195.579999999998,147176.18
|
||||||
|
2025-07-24,115180.59999999999,32133.800000000003,147314.4
|
||||||
|
2025-07-25,115180.59999999999,32153.94,147334.53999999998
|
||||||
|
2025-07-28,115180.59999999999,32243.62,147424.22
|
||||||
|
2025-07-29,115180.59999999999,31921.92,147102.52
|
||||||
|
2025-07-30,115180.59999999999,31987.88,147168.47999999998
|
||||||
|
2025-07-31,113580.59999999999,33084.16,146664.76
|
||||||
|
2025-08-01,113316.59999999999,33357.8,146674.4
|
||||||
|
2025-08-04,116562.59999999999,30359.96,146922.56
|
||||||
|
2025-08-05,114762.59999999999,32258.28,147020.88
|
||||||
|
2025-08-06,114762.59999999999,32168.1,146930.69999999998
|
||||||
|
2025-08-07,114762.59999999999,32379.9,147142.5
|
||||||
|
2025-08-08,119086.59999999999,28390.0,147476.59999999998
|
||||||
|
2025-08-11,119218.59999999999,28752.0,147970.59999999998
|
||||||
|
2025-08-12,117418.59999999999,30502.0,147920.59999999998
|
||||||
|
2025-08-13,121062.59999999999,26722.0,147784.59999999998
|
||||||
|
2025-08-14,117662.59999999999,29492.0,147154.59999999998
|
||||||
|
2025-08-15,119662.59999999999,28798.0,148460.59999999998
|
||||||
|
2025-08-18,123252.59999999999,26458.0,149710.59999999998
|
||||||
|
2025-08-19,122090.59999999999,27948.0,150038.59999999998
|
||||||
|
2025-08-20,120290.59999999999,29984.0,150274.59999999998
|
||||||
|
2025-08-21,126290.59999999999,24298.0,150588.59999999998
|
||||||
|
2025-08-22,126652.59999999999,23932.0,150584.59999999998
|
||||||
|
2025-08-25,126652.59999999999,24162.0,150814.59999999998
|
||||||
|
2025-08-26,126852.59999999999,24104.0,150956.59999999998
|
||||||
|
2025-08-27,123646.59999999999,26804.0,150450.59999999998
|
||||||
|
2025-08-28,118640.59999999999,32296.0,150936.59999999998
|
||||||
|
2025-08-29,116840.59999999999,33900.0,150740.59999999998
|
||||||
|
2025-09-01,122140.01999999999,29354.24,151494.25999999998
|
||||||
|
2025-09-02,120726.01999999999,30304.0,151030.02
|
||||||
|
2025-09-03,117326.01999999999,32868.0,150194.02
|
||||||
|
2025-09-04,114126.01999999999,35582.0,149708.02
|
||||||
|
2025-09-05,114126.01999999999,36400.0,150526.02
|
||||||
|
2025-09-08,114126.01999999999,36670.0,150796.02
|
||||||
|
2025-09-09,114126.01999999999,35764.0,149890.02
|
||||||
|
2025-09-10,114126.01999999999,36264.0,150390.02
|
||||||
|
2025-09-11,116326.01999999999,34852.0,151178.02
|
||||||
|
2025-09-12,116580.01999999999,34638.0,151218.02
|
||||||
|
2025-09-15,116840.01999999999,34224.0,151064.02
|
||||||
|
2025-09-16,116840.01999999999,34266.0,151106.02
|
||||||
|
2025-09-17,116840.01999999999,34016.0,150856.02
|
||||||
|
2025-09-18,115522.01999999999,34918.0,150440.02
|
||||||
|
2025-09-19,115522.01999999999,34548.0,150070.02
|
||||||
|
2025-09-22,116524.01999999999,33574.0,150098.02
|
||||||
|
2025-09-23,111924.01999999999,37476.0,149400.02
|
||||||
|
2025-09-24,112264.01999999999,37360.0,149624.02
|
||||||
|
2025-09-25,112264.01999999999,36962.0,149226.02
|
||||||
|
2025-09-26,112264.01999999999,36744.0,149008.02
|
||||||
|
2025-09-29,116726.01999999999,32582.0,149308.02
|
||||||
|
2025-09-30,116726.01999999999,32560.0,149286.02
|
||||||
|
2025-10-09,118370.01999999999,30188.0,148558.02
|
||||||
|
2025-10-10,116570.01999999999,31992.0,148562.02
|
||||||
|
2025-10-13,112600.01999999999,36462.0,149062.02
|
||||||
|
2025-10-14,112600.01999999999,36110.0,148710.02
|
||||||
|
2025-10-15,112600.01999999999,36570.0,149170.02
|
||||||
|
2025-10-16,114600.01999999999,34026.0,148626.02
|
||||||
|
2025-10-17,113000.01999999999,34894.0,147894.02
|
||||||
|
2025-10-20,112998.01999999999,35922.0,148920.02
|
||||||
|
2025-10-21,114998.01999999999,34854.0,149852.02
|
||||||
|
2025-10-22,114998.01999999999,34606.0,149604.02
|
||||||
|
2025-10-23,113198.01999999999,36532.0,149730.02
|
||||||
|
2025-10-24,113198.01999999999,36844.0,150042.02
|
||||||
|
2025-10-27,116430.01999999999,33332.0,149762.02
|
||||||
|
2025-10-28,116430.01999999999,33280.0,149710.02
|
||||||
|
2025-10-29,116430.01999999999,33934.0,150364.02
|
||||||
|
2025-10-30,116430.01999999999,33806.0,150236.02
|
||||||
|
2025-10-31,116430.01999999999,34148.0,150578.02
|
||||||
|
2025-11-03,121148.01999999999,29008.0,150156.02
|
||||||
|
2025-11-04,120108.01999999999,30110.0,150218.02
|
||||||
|
2025-11-05,120108.01999999999,30552.0,150660.02
|
||||||
|
2025-11-06,118308.01999999999,32286.0,150594.02
|
||||||
|
2025-11-07,118702.01999999999,31342.0,150044.02
|
||||||
|
2025-11-10,118702.01999999999,31688.0,150390.02
|
||||||
|
2025-11-11,123102.01999999999,27790.0,150892.02
|
||||||
|
2025-11-12,118426.01999999999,32408.0,150834.02
|
||||||
|
2025-11-13,119016.01999999999,32752.0,151768.02
|
||||||
|
2025-11-14,119016.01999999999,33214.0,152230.02
|
||||||
|
2025-11-17,123270.01999999999,29114.0,152384.02
|
||||||
|
2025-11-18,119670.01999999999,31876.0,151546.02
|
||||||
|
2025-11-19,118070.01999999999,33268.0,151338.02
|
||||||
|
2025-11-20,116470.01999999999,34108.0,150578.02
|
||||||
|
2025-11-21,109870.01999999999,38562.0,148432.02
|
||||||
|
2025-11-24,109938.01999999999,38512.0,148450.02
|
||||||
|
2025-11-25,111938.01999999999,37762.0,149700.02
|
||||||
|
2025-11-26,111938.01999999999,37170.0,149108.02
|
||||||
|
2025-11-27,111938.01999999999,37172.0,149110.02
|
||||||
|
2025-11-28,111938.01999999999,37834.0,149772.02
|
||||||
|
2025-12-01,115825.68,33942.38,149768.06
|
||||||
|
2025-12-02,115825.68,33994.38,149820.06
|
||||||
|
2025-12-03,117825.68,31736.9,149562.58
|
||||||
|
2025-12-04,112425.68,36213.44,148639.12
|
||||||
|
2025-12-05,109425.68,40135.04,149560.72
|
||||||
|
2025-12-08,112603.68,37374.88,149978.56
|
||||||
|
2025-12-09,116729.68,33392.68,150122.36
|
||||||
|
2025-12-10,117313.68,33230.36,150544.03999999998
|
||||||
|
2025-12-11,115769.68,34872.0,150641.68
|
||||||
|
2025-12-12,115769.68,35290.0,151059.68
|
||||||
|
2025-12-15,118523.68,33424.0,151947.68
|
||||||
|
2025-12-16,118723.68,32706.0,151429.68
|
||||||
|
2025-12-17,111723.68,39646.0,151369.68
|
||||||
|
2025-12-18,111723.68,39308.0,151031.68
|
||||||
|
2025-12-19,110123.68,41948.0,152071.68
|
||||||
|
2025-12-22,116025.68,36470.0,152495.68
|
||||||
|
2025-12-23,116225.68,36004.0,152229.68
|
||||||
|
2025-12-24,115195.68,37596.0,152791.68
|
||||||
|
2025-12-25,115571.68,37138.0,152709.68
|
||||||
|
2025-12-26,115371.68,37724.0,153095.68
|
||||||
|
2025-12-29,118263.68,34576.0,152839.68
|
||||||
|
2025-12-30,116959.68,35302.0,152261.68
|
||||||
|
2025-12-31,115159.68,36376.0,151535.68
|
||||||
|
2026-01-05,114658.76,36630.8,151289.56
|
||||||
|
2026-01-06,113458.76,38219.44,151678.2
|
||||||
|
2026-01-07,113854.76,37808.0,151662.76
|
||||||
|
2026-01-08,112054.76,40598.0,152652.76
|
||||||
|
2026-01-09,113854.76,39384.0,153238.76
|
||||||
|
2026-01-12,114728.76,38852.0,153580.76
|
||||||
|
2026-01-13,120616.76,32848.0,153464.76
|
||||||
|
2026-01-14,121016.76,32938.0,153954.76
|
||||||
|
2026-01-15,121216.76,32146.0,153362.76
|
||||||
|
2026-01-16,117816.76,34904.0,152720.76
|
||||||
|
2026-01-19,118854.76,34260.0,153114.76
|
||||||
|
2026-01-20,117516.76,35734.0,153250.76
|
||||||
|
2026-01-21,120376.76,34212.0,154588.76
|
||||||
|
2026-01-22,120376.76,34816.0,155192.76
|
||||||
|
2026-01-23,120376.76,35548.0,155924.76
|
||||||
|
2026-01-26,119168.76,36470.0,155638.76
|
||||||
|
2026-01-27,119368.76,36470.0,155838.76
|
||||||
|
2026-01-28,119368.76,35508.0,154876.76
|
||||||
|
2026-01-29,117768.76,37012.0,154780.76
|
||||||
|
2026-01-30,118104.76,36686.0,154790.76
|
||||||
|
2026-02-02,123830.76,30870.0,154700.76
|
||||||
|
2026-02-03,123830.76,31876.000000000004,155706.76
|
||||||
|
2026-02-04,123830.76,31492.0,155322.76
|
||||||
|
2026-02-05,123830.76,31724.0,155554.76
|
||||||
|
2026-02-06,123830.76,32184.0,156014.76
|
||||||
|
2026-02-09,124128.76,32940.0,157068.76
|
||||||
|
2026-02-10,130252.76000000001,27476.0,157728.76
|
||||||
|
2026-02-11,128452.76000000001,29178.0,157630.76
|
||||||
|
2026-02-12,130452.76000000001,27600.0,158052.76
|
||||||
|
2026-02-13,130652.76000000001,27454.0,158106.76
|
||||||
|
2026-02-24,129478.76000000001,29166.0,158644.76
|
||||||
|
2026-02-25,129678.76000000001,29674.0,159352.76
|
||||||
|
2026-02-26,129878.76000000001,29368.0,159246.76
|
||||||
|
2026-02-27,128078.76000000001,31448.0,159526.76
|
||||||
|
2026-03-02,126568.76000000001,31928.0,158496.76
|
||||||
|
2026-03-03,123168.76000000001,33314.0,156482.76
|
||||||
|
2026-03-04,121530.76000000001,35378.0,156908.76
|
||||||
|
2026-03-05,123530.76000000001,33996.0,157526.76
|
||||||
|
2026-03-06,121930.76000000001,35786.0,157716.76
|
||||||
|
2026-03-09,120130.76000000001,37128.0,157258.76
|
||||||
|
2026-03-10,122130.76000000001,36208.0,158338.76
|
||||||
|
2026-03-11,122498.76000000001,35428.0,157926.76
|
||||||
|
2026-03-12,122498.76000000001,34782.0,157280.76
|
||||||
|
2026-03-13,122818.76000000001,33916.0,156734.76
|
||||||
|
2026-03-16,119866.98000000001,36893.56,156760.54
|
||||||
|
2026-03-17,120266.98000000001,35880.16,156147.14
|
||||||
|
2026-03-18,120266.98000000001,36240.88,156507.86000000002
|
||||||
|
2026-03-19,115666.98000000001,39534.56,155201.54
|
||||||
|
2026-03-20,114066.98000000001,39770.48,153837.46000000002
|
||||||
|
2026-03-23,112544.98000000001,40740.8,153285.78000000003
|
||||||
|
2026-03-24,111144.98000000001,44227.28,155372.26
|
||||||
|
2026-03-25,113144.98000000001,43183.8,156328.78000000003
|
||||||
|
2026-03-26,114944.98000000001,40874.96,155819.94
|
||||||
|
2026-03-27,114944.98000000001,41492.52,156437.5
|
||||||
|
2026-03-30,118332.98000000001,38077.28,156410.26
|
||||||
|
2026-03-31,118332.98000000001,37634.52,155967.5
|
||||||
|
2026-04-01,121430.98000000001,35512.04,156943.02000000002
|
||||||
|
2026-04-02,121430.98000000001,34988.72,156419.7
|
||||||
|
2026-04-03,118420.98000000001,37343.56,155764.54
|
||||||
|
2026-04-07,117714.98000000001,38003.479999999996,155718.46000000002
|
||||||
|
2026-04-08,117980.98000000001,39241.32,157222.30000000002
|
||||||
|
2026-04-09,117980.98000000001,38689.08,156670.06
|
||||||
|
2026-04-10,118180.98000000001,38458.6,156639.58000000002
|
||||||
|
2026-04-13,116651.58000000002,39420.0,156071.58000000002
|
||||||
|
2026-04-14,115051.58000000002,40588.0,155639.58000000002
|
||||||
|
2026-04-15,114451.58000000002,40568.0,155019.58000000002
|
||||||
|
2026-04-16,113051.58000000002,41612.0,154663.58000000002
|
||||||
|
2026-04-17,111851.58000000002,42540.0,154391.58000000002
|
||||||
|
2026-04-20,111939.58000000002,43314.0,155253.58000000002
|
||||||
|
2026-04-21,111939.58000000002,43070.0,155009.58000000002
|
||||||
|
2026-04-22,111939.58000000002,42160.0,154099.58000000002
|
||||||
|
2026-04-23,110939.58000000002,41660.0,152599.58000000002
|
||||||
|
2026-04-24,109899.58000000002,42320.0,152219.58000000002
|
||||||
|
2026-04-27,113003.58000000002,39480.0,152483.58000000002
|
||||||
|
2026-04-28,112317.58000000002,38134.0,150451.58000000002
|
||||||
|
2026-04-29,113317.58000000002,37898.0,151215.58000000002
|
||||||
|
2026-04-30,111717.58000000002,39436.0,151153.58000000002
|
||||||
|
@@ -0,0 +1,37 @@
|
|||||||
|
date,cash,stock_value,total_value,positions,month
|
||||||
|
2023-05-31,17736.34,41098.4,58834.74,10,2023-05
|
||||||
|
2023-06-30,20515.46,40323.66,60839.12,10,2023-06
|
||||||
|
2023-07-31,30397.84,29960.78,60358.62,9,2023-07
|
||||||
|
2023-08-31,26136.7,34300.62,60437.32,10,2023-08
|
||||||
|
2023-09-30,39873.34,27709.4,67582.74,10,2023-09
|
||||||
|
2023-10-31,36088.52,31940.92,68029.44,10,2023-10
|
||||||
|
2023-11-30,49700.74,27047.76,76748.5,10,2023-11
|
||||||
|
2023-12-31,56387.94,33956.0,90343.94,10,2023-12
|
||||||
|
2024-01-31,43543.94,44782.0,88325.94,10,2024-01
|
||||||
|
2024-02-29,41861.28,44551.96,86413.24,10,2024-02
|
||||||
|
2024-03-31,60401.36,30781.6,91182.96,9,2024-03
|
||||||
|
2024-04-30,51342.72,39697.38,91040.1,10,2024-04
|
||||||
|
2024-05-31,65813.5,29130.0,94943.5,9,2024-05
|
||||||
|
2024-06-30,52527.76,40070.0,92597.76,10,2024-06
|
||||||
|
2024-07-31,61456.88,33980.7,95437.58,10,2024-07
|
||||||
|
2024-08-31,52183.52,42771.06,94954.58,10,2024-08
|
||||||
|
2024-09-30,80349.32,21369.96,101719.28,10,2024-09
|
||||||
|
2024-10-31,87055.28,25324.0,112379.28,10,2024-10
|
||||||
|
2024-11-30,101950.1,29600.28,131550.38,10,2024-11
|
||||||
|
2024-12-31,89318.12,35982.0,125300.12,8,2024-12
|
||||||
|
2025-01-31,95062.12,29920.0,124982.12,9,2025-01
|
||||||
|
2025-02-28,102728.72,26542.96,129271.68,9,2025-02
|
||||||
|
2025-03-31,103822.1,31484.3,135306.4,10,2025-03
|
||||||
|
2025-04-30,102745.54,35759.3,138504.84,10,2025-04
|
||||||
|
2025-05-31,115165.84,27606.0,142771.84,8,2025-05
|
||||||
|
2025-06-30,108767.46,36246.7,145014.16,9,2025-06
|
||||||
|
2025-07-31,115180.6,32153.94,147334.54,10,2025-07
|
||||||
|
2025-08-31,116840.6,33900.0,150740.6,10,2025-08
|
||||||
|
2025-09-30,116726.02,32560.0,149286.02,10,2025-09
|
||||||
|
2025-10-31,116430.02,34148.0,150578.02,10,2025-10
|
||||||
|
2025-11-30,111938.02,37834.0,149772.02,10,2025-11
|
||||||
|
2025-12-31,115159.68,36376.0,151535.68,10,2025-12
|
||||||
|
2026-01-31,118104.76,36686.0,154790.76,10,2026-01
|
||||||
|
2026-02-28,128078.76,31448.0,159526.76,10,2026-02
|
||||||
|
2026-03-31,114944.98,41492.52,156437.5,10,2026-03
|
||||||
|
2026-04-30,111717.58,39436.0,151153.58,10,2026-04
|
||||||
|
@@ -0,0 +1,21 @@
|
|||||||
|
{
|
||||||
|
"version": "v6.7r2",
|
||||||
|
"rank_model": "lambdarank (56-dim v6.7)",
|
||||||
|
"backtest_start": "2023-05-01",
|
||||||
|
"backtest_end": "2026-04-30",
|
||||||
|
"n_weeks": 154,
|
||||||
|
"n_stocks_in_pool": 5378,
|
||||||
|
"top_n": 10,
|
||||||
|
"shares_per_grid": 200,
|
||||||
|
"initial_cash": 60000.0,
|
||||||
|
"final_total_value": 151153.58,
|
||||||
|
"total_return_pct": 151.92,
|
||||||
|
"annual_return_pct": 36.1,
|
||||||
|
"annual_sharpe": 1.7404,
|
||||||
|
"max_drawdown_pct": -12.1,
|
||||||
|
"weekly_win_rate_pct": 59.48,
|
||||||
|
"n_trades_buy": 1144,
|
||||||
|
"n_trades_sell": 866,
|
||||||
|
"realized_pnl_total": 95495.58,
|
||||||
|
"n_lifecycles": 431
|
||||||
|
}
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,155 @@
|
|||||||
|
date,cash,stock_value,total_value,positions,year
|
||||||
|
2023-05-05,29353.86,32311.96,61665.82,10,2023
|
||||||
|
2023-05-12,24353.86,37200.04,61553.9,10,2023
|
||||||
|
2023-05-19,19999.86,40128.84,60128.7,10,2023
|
||||||
|
2023-05-26,17736.34,41098.4,58834.74,10,2023
|
||||||
|
2023-06-02,22233.92,40253.44,62487.36,10,2023
|
||||||
|
2023-06-09,23083.9,39432.4,62516.3,10,2023
|
||||||
|
2023-06-16,27171.9,36662.04,63833.94,10,2023
|
||||||
|
2023-06-21,27177.36,35306.82,62484.18,10,2023
|
||||||
|
2023-06-30,20515.46,40323.66,60839.12,10,2023
|
||||||
|
2023-07-07,27155.76,33151.0,60306.76,10,2023
|
||||||
|
2023-07-14,29091.76,31705.8,60797.56,10,2023
|
||||||
|
2023-07-21,29114.82,32509.1,61623.92,9,2023
|
||||||
|
2023-07-28,30397.84,29960.78,60358.62,9,2023
|
||||||
|
2023-08-04,31326.78,29340.22,60667.0,10,2023
|
||||||
|
2023-08-11,28602.46,31713.8,60316.26,10,2023
|
||||||
|
2023-08-18,33136.7,28257.34,61394.04,10,2023
|
||||||
|
2023-08-25,26136.7,34300.62,60437.32,10,2023
|
||||||
|
2023-09-01,33946.78,29311.82,63258.6,10,2023
|
||||||
|
2023-09-08,29682.92,33243.98,62926.9,10,2023
|
||||||
|
2023-09-15,33929.1,29926.24,63855.34,10,2023
|
||||||
|
2023-09-22,35117.34,29932.44,65049.78,10,2023
|
||||||
|
2023-09-28,39873.34,27709.4,67582.74,10,2023
|
||||||
|
2023-10-13,44083.08,23683.52,67766.6,10,2023
|
||||||
|
2023-10-20,33289.08,32655.7,65944.78,10,2023
|
||||||
|
2023-10-27,36088.52,31940.92,68029.44,10,2023
|
||||||
|
2023-11-03,40429.7,29377.8,69807.5,10,2023
|
||||||
|
2023-11-10,46479.74,25900.26,72380.0,10,2023
|
||||||
|
2023-11-17,49341.34,24523.56,73864.9,10,2023
|
||||||
|
2023-11-24,49700.74,27047.76,76748.5,10,2023
|
||||||
|
2023-12-01,33892.34,39456.38,73348.72,10,2023
|
||||||
|
2023-12-08,50831.34,30194.3,81025.64,10,2023
|
||||||
|
2023-12-15,52387.94,31884.0,84271.94,10,2023
|
||||||
|
2023-12-22,52909.94,32946.0,85855.94,10,2023
|
||||||
|
2023-12-29,56387.94,33956.0,90343.94,10,2023
|
||||||
|
2024-01-05,56405.94,34602.0,91007.94,10,2024
|
||||||
|
2024-01-12,42405.94,42438.0,84843.94,10,2024
|
||||||
|
2024-01-19,44405.94,46458.0,90863.94,10,2024
|
||||||
|
2024-01-26,43543.94,44782.0,88325.94,10,2024
|
||||||
|
2024-02-02,27305.94,52690.0,79995.94,10,2024
|
||||||
|
2024-02-08,31419.94,51926.0,83345.94,10,2024
|
||||||
|
2024-02-23,41861.28,44551.96,86413.24,10,2024
|
||||||
|
2024-03-01,49575.3,40919.28,90494.58,10,2024
|
||||||
|
2024-03-08,53677.94,35737.8,89415.74,10,2024
|
||||||
|
2024-03-15,60047.92,31026.78,91074.7,10,2024
|
||||||
|
2024-03-22,65873.84,26076.62,91950.46,10,2024
|
||||||
|
2024-03-29,60401.36,30781.6,91182.96,9,2024
|
||||||
|
2024-04-03,66965.58,26641.44,93607.02,9,2024
|
||||||
|
2024-04-12,56903.58,32507.18,89410.76,10,2024
|
||||||
|
2024-04-19,33499.58,52126.22,85625.8,10,2024
|
||||||
|
2024-04-26,42761.58,46693.66,89455.24,10,2024
|
||||||
|
2024-04-30,51342.72,39697.38,91040.1,10,2024
|
||||||
|
2024-05-10,56205.06,34632.66,90837.72,10,2024
|
||||||
|
2024-05-17,60869.06,31647.16,92516.22,10,2024
|
||||||
|
2024-05-24,59605.06,32880.44,92485.5,10,2024
|
||||||
|
2024-05-31,65813.5,29130.0,94943.5,9,2024
|
||||||
|
2024-06-07,47960.4,42130.56,90090.96,10,2024
|
||||||
|
2024-06-14,56152.4,36035.36,92187.76,10,2024
|
||||||
|
2024-06-21,62239.76,31984.0,94223.76,10,2024
|
||||||
|
2024-06-28,52527.76,40070.0,92597.76,10,2024
|
||||||
|
2024-07-05,52351.76,40466.0,92817.76,10,2024
|
||||||
|
2024-07-12,51451.72,42662.64,94114.36,10,2024
|
||||||
|
2024-07-19,55290.88,38665.44,93956.32,10,2024
|
||||||
|
2024-07-26,61456.88,33980.7,95437.58,10,2024
|
||||||
|
2024-08-02,61925.74,34468.0,96393.74,10,2024
|
||||||
|
2024-08-09,63005.74,33154.0,96159.74,10,2024
|
||||||
|
2024-08-16,56715.74,39058.0,95773.74,10,2024
|
||||||
|
2024-08-23,55364.2,37672.44,93036.64,10,2024
|
||||||
|
2024-08-30,52183.52,42771.06,94954.58,10,2024
|
||||||
|
2024-09-06,60506.34,35878.58,96384.92,9,2024
|
||||||
|
2024-09-13,62642.34,30741.5,93383.84,8,2024
|
||||||
|
2024-09-20,58359.32,34882.94,93242.26,10,2024
|
||||||
|
2024-09-27,69235.32,29121.08,98356.4,10,2024
|
||||||
|
2024-09-30,80349.32,21369.96,101719.28,10,2024
|
||||||
|
2024-10-11,56083.28,43112.0,99195.28,10,2024
|
||||||
|
2024-10-18,71101.28,35670.0,106771.28,10,2024
|
||||||
|
2024-10-25,87055.28,25324.0,112379.28,10,2024
|
||||||
|
2024-11-01,90986.66,26929.52,117916.18,10,2024
|
||||||
|
2024-11-08,100636.82,23667.66,124304.48,10,2024
|
||||||
|
2024-11-15,96557.2,28499.72,125056.92,10,2024
|
||||||
|
2024-11-22,102164.48,26932.02,129096.5,10,2024
|
||||||
|
2024-11-29,101950.1,29600.28,131550.38,10,2024
|
||||||
|
2024-12-06,103392.78,28411.32,131804.1,10,2024
|
||||||
|
2024-12-13,96844.12,33198.0,130042.12,10,2024
|
||||||
|
2024-12-20,82444.12,44764.0,127208.12,10,2024
|
||||||
|
2024-12-27,89318.12,35982.0,125300.12,8,2024
|
||||||
|
2025-01-03,87408.12,37578.0,124986.12,10,2025
|
||||||
|
2025-01-10,85580.12,38096.0,123676.12,10,2025
|
||||||
|
2025-01-17,92964.12,32718.0,125682.12,9,2025
|
||||||
|
2025-01-24,97680.12,30942.0,128622.12,8,2025
|
||||||
|
2025-01-27,95062.12,29920.0,124982.12,9,2025
|
||||||
|
2025-02-07,99682.12,27098.0,126780.12,9,2025
|
||||||
|
2025-02-14,106503.36,21418.78,127922.14,9,2025
|
||||||
|
2025-02-21,105749.72,23782.4,129532.12,9,2025
|
||||||
|
2025-02-28,102728.72,26542.96,129271.68,9,2025
|
||||||
|
2025-03-07,105425.36,27040.4,132465.76,10,2025
|
||||||
|
2025-03-14,115013.82,19782.36,134796.18,9,2025
|
||||||
|
2025-03-21,109423.82,25211.12,134634.94,9,2025
|
||||||
|
2025-03-28,103822.1,31484.3,135306.4,10,2025
|
||||||
|
2025-04-03,99800.62,34518.32,134318.94,10,2025
|
||||||
|
2025-04-11,99600.62,37063.76,136664.38,10,2025
|
||||||
|
2025-04-18,109341.54,30561.36,139902.9,10,2025
|
||||||
|
2025-04-25,106835.54,32281.18,139116.72,10,2025
|
||||||
|
2025-04-30,102745.54,35759.3,138504.84,10,2025
|
||||||
|
2025-05-09,102637.84,37585.88,140223.72,10,2025
|
||||||
|
2025-05-16,101963.84,38900.0,140863.84,10,2025
|
||||||
|
2025-05-23,109423.84,32758.0,142181.84,9,2025
|
||||||
|
2025-05-30,115165.84,27606.0,142771.84,8,2025
|
||||||
|
2025-06-06,118567.88,25523.98,144091.86,10,2025
|
||||||
|
2025-06-13,121827.46,23271.14,145098.6,9,2025
|
||||||
|
2025-06-20,109651.46,33717.02,143368.48,9,2025
|
||||||
|
2025-06-27,108767.46,36246.7,145014.16,9,2025
|
||||||
|
2025-07-04,117302.28,29383.94,146686.22,10,2025
|
||||||
|
2025-07-11,116312.28,31418.0,147730.28,10,2025
|
||||||
|
2025-07-18,113160.2,33946.38,147106.58,10,2025
|
||||||
|
2025-07-25,115180.6,32153.94,147334.54,10,2025
|
||||||
|
2025-08-01,113316.6,33357.8,146674.4,10,2025
|
||||||
|
2025-08-08,119086.6,28390.0,147476.6,10,2025
|
||||||
|
2025-08-15,119662.6,28798.0,148460.6,9,2025
|
||||||
|
2025-08-22,126652.6,23932.0,150584.6,10,2025
|
||||||
|
2025-08-29,116840.6,33900.0,150740.6,10,2025
|
||||||
|
2025-09-05,114126.02,36400.0,150526.02,10,2025
|
||||||
|
2025-09-12,116580.02,34638.0,151218.02,10,2025
|
||||||
|
2025-09-19,115522.02,34548.0,150070.02,10,2025
|
||||||
|
2025-09-26,115364.02,36744.0,152108.02,9,2025
|
||||||
|
2025-09-30,116726.02,32560.0,149286.02,10,2025
|
||||||
|
2025-10-10,116570.02,31992.0,148562.02,10,2025
|
||||||
|
2025-10-17,113000.02,34894.0,147894.02,10,2025
|
||||||
|
2025-10-24,113198.02,36844.0,150042.02,10,2025
|
||||||
|
2025-10-31,116430.02,34148.0,150578.02,10,2025
|
||||||
|
2025-11-07,118702.02,31342.0,150044.02,10,2025
|
||||||
|
2025-11-14,119016.02,33214.0,152230.02,10,2025
|
||||||
|
2025-11-21,109870.02,38562.0,148432.02,10,2025
|
||||||
|
2025-11-28,111938.02,37834.0,149772.02,10,2025
|
||||||
|
2025-12-05,109425.68,40135.04,149560.72,10,2025
|
||||||
|
2025-12-12,115769.68,35290.0,151059.68,10,2025
|
||||||
|
2025-12-19,110123.68,41948.0,152071.68,10,2025
|
||||||
|
2025-12-26,115371.68,37724.0,153095.68,10,2025
|
||||||
|
2025-12-31,115159.68,36376.0,151535.68,10,2025
|
||||||
|
2026-01-09,113854.76,39384.0,153238.76,10,2026
|
||||||
|
2026-01-16,117816.76,34904.0,152720.76,10,2026
|
||||||
|
2026-01-23,120376.76,35548.0,155924.76,10,2026
|
||||||
|
2026-01-30,118104.76,36686.0,154790.76,10,2026
|
||||||
|
2026-02-06,123830.76,32184.0,156014.76,10,2026
|
||||||
|
2026-02-13,130652.76,27454.0,158106.76,10,2026
|
||||||
|
2026-02-27,128078.76,31448.0,159526.76,10,2026
|
||||||
|
2026-03-06,121930.76,35786.0,157716.76,9,2026
|
||||||
|
2026-03-13,122818.76,33916.0,156734.76,9,2026
|
||||||
|
2026-03-20,114066.98,39770.48,153837.46,10,2026
|
||||||
|
2026-03-27,114944.98,41492.52,156437.5,10,2026
|
||||||
|
2026-04-03,118420.98,37343.56,155764.54,10,2026
|
||||||
|
2026-04-10,118180.98,38458.6,156639.58,10,2026
|
||||||
|
2026-04-17,111851.58,42540.0,154391.58,10,2026
|
||||||
|
2026-04-24,109899.58,42320.0,152219.58,10,2026
|
||||||
|
2026-04-30,111717.58,39436.0,151153.58,10,2026
|
||||||
|
Binary file not shown.
@@ -0,0 +1,57 @@
|
|||||||
|
{
|
||||||
|
"version": "v6.7-rank-lambdarank-mvp",
|
||||||
|
"feature_version": "v3.4",
|
||||||
|
"objective": "lambdarank",
|
||||||
|
"metric": "ndcg@5,10",
|
||||||
|
"ndcg_at_5": 0.5108501630463596,
|
||||||
|
"ndcg_at_10": 0.577072484777789,
|
||||||
|
"spearman": 0.5896180660523218,
|
||||||
|
"spearman_baseline_regression": 0.573016131374212,
|
||||||
|
"spearman_ratio_vs_baseline": 1.0289728923307881,
|
||||||
|
"best_iter": 29,
|
||||||
|
"train_seconds": 1.4682528972625732,
|
||||||
|
"n_train": 254234,
|
||||||
|
"n_val": 73785,
|
||||||
|
"top10_features": [
|
||||||
|
{
|
||||||
|
"name": "dist_to_grid_lower",
|
||||||
|
"gain": 26718.906676471233
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "amp_x_grid",
|
||||||
|
"gain": 5439.311601281166
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "cross_freq_x_bb",
|
||||||
|
"gain": 4232.088328957558
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "amp_x_grid_vol",
|
||||||
|
"gain": 3015.4479908943176
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "dist_to_grid_upper",
|
||||||
|
"gain": 2406.65438079834
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "ln_float_mv",
|
||||||
|
"gain": 1248.8392915129662
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "avg_daily_amp",
|
||||||
|
"gain": 794.0413353443146
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "amount_mean_20d",
|
||||||
|
"gain": 670.1584417819977
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "vol_decay_x_dist_lower",
|
||||||
|
"gain": 659.5440436601639
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "vol_decay_x_grid_balance",
|
||||||
|
"gain": 653.8379725217819
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -0,0 +1,158 @@
|
|||||||
|
# v6.7r3 代码使用说明
|
||||||
|
|
||||||
|
`code/` 目录包含 v6.7r3 策略的**自包含**实现,可在不依赖项目其他模块的情况下独立运行。
|
||||||
|
|
||||||
|
## 文件清单
|
||||||
|
|
||||||
|
| 文件 | 大小 | 作用 |
|
||||||
|
|---|---|---|
|
||||||
|
| `strategy.py` | ~22 KB | 完整策略实现(模型加载/特征/网格/沉寂/周度淘汰) |
|
||||||
|
|
||||||
|
## 文件结构
|
||||||
|
|
||||||
|
```
|
||||||
|
strategy.py
|
||||||
|
├── 配置常量 (网格/价格/沉寂/周度)
|
||||||
|
├── 1. 持仓 + 网格交易
|
||||||
|
│ ├── Position dataclass
|
||||||
|
│ ├── compute_initial_position() 初始建仓
|
||||||
|
│ ├── compute_single_position() 单格建仓
|
||||||
|
│ └── simulate_grid_day() 单日网格 (LIFO)
|
||||||
|
├── 2. 5 特征沉寂检测
|
||||||
|
│ └── is_slumbering() 5 特征 ≥ 3 触发
|
||||||
|
├── 3. 模型加载 + 三件套预测
|
||||||
|
│ ├── ModelBundle class
|
||||||
|
│ │ ├── load 3 .pkl
|
||||||
|
│ │ └── predict(X56) → {rank_score, top_prob, stack_prob}
|
||||||
|
├── 4. 特征计算
|
||||||
|
│ ├── compute_52_base_features() 52 维 v3.4 基础
|
||||||
|
│ └── compute_4_v67_new_features() 4 维 v6.7 新增
|
||||||
|
├── 5. 评分池
|
||||||
|
│ └── score_pool() 单日全市场评分
|
||||||
|
├── 6. 主回测入口(精简版)
|
||||||
|
│ └── quick_backtest() 生产级完整版见 tools/backtest_v67r2.py
|
||||||
|
└── 7. 入口示例
|
||||||
|
└── __main__ 加载模型 + 加载行情 + 跑回测
|
||||||
|
```
|
||||||
|
|
||||||
|
## 快速开始
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 1. 安装依赖
|
||||||
|
pip install pandas numpy lightgbm scipy
|
||||||
|
|
||||||
|
# 2. 准备数据
|
||||||
|
# 方式 A: 用项目内的 dump_market_data_to_parquet.py 拉 Postgres
|
||||||
|
python tools/dump_market_data_to_parquet.py
|
||||||
|
# 方式 B: 直接用现有 parquet (release/v6.7r3 之前已生成 5025 个)
|
||||||
|
|
||||||
|
# 3. 运行
|
||||||
|
cd release/v6.7r3/code
|
||||||
|
python strategy.py
|
||||||
|
```
|
||||||
|
|
||||||
|
## 核心 API 速查
|
||||||
|
|
||||||
|
### 1. 加载模型
|
||||||
|
```python
|
||||||
|
from strategy import ModelBundle
|
||||||
|
|
||||||
|
models = ModelBundle("../models")
|
||||||
|
# 等价: models = ModelBundle("release/v6.7r3/models")
|
||||||
|
print(models.rank_feats[:5]) # ['rolling_grid_ratio_20d', ...]
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. 三件套预测
|
||||||
|
```python
|
||||||
|
import numpy as np
|
||||||
|
import pandas as pd
|
||||||
|
|
||||||
|
# 加载单只股 120 日窗口
|
||||||
|
df_window = pd.read_parquet("data/market_data/share/000001.parquet")
|
||||||
|
df_window["date"] = pd.to_datetime(df_window["date"])
|
||||||
|
df_window = df_window.tail(120).reset_index(drop=True)
|
||||||
|
|
||||||
|
# 算 56 维特征 (这里用简化版, 生产建议用项目 core.features)
|
||||||
|
from strategy import compute_52_base_features, compute_4_v67_new_features
|
||||||
|
fd = compute_52_base_features(df_window)
|
||||||
|
fd = compute_4_v67_new_features(df_window, fd)
|
||||||
|
X56 = np.array([fd.get(k, 0.0) for k in models.rank_feats], dtype=np.float64).reshape(1, -1)
|
||||||
|
|
||||||
|
# 三件套预测
|
||||||
|
pred = models.predict(X56)
|
||||||
|
print(f"rank_score: {pred['rank_score'][0]:.3f}")
|
||||||
|
print(f"top_prob: {pred['top_prob'][0]:.3f}")
|
||||||
|
print(f"stack_prob: {pred['stack_prob'][0]:.3f}") # 月末选股用
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. 沉寂检测
|
||||||
|
```python
|
||||||
|
from strategy import is_slumbering
|
||||||
|
|
||||||
|
df = pd.read_parquet("data/market_data/share/000001.parquet")
|
||||||
|
df["date"] = pd.to_datetime(df["date"])
|
||||||
|
slumbering = is_slumbering(df, min_triggers=3)
|
||||||
|
# True = 5 特征中至少 3 个触发 → 资金离场
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4. 网格交易(单日)
|
||||||
|
```python
|
||||||
|
from strategy import Position, simulate_grid_day
|
||||||
|
|
||||||
|
pos = Position(code="000001", base=10, queue=[10.0, 9.5], entry_date="2023-05-01")
|
||||||
|
new_base, new_queue, trades = simulate_grid_day(
|
||||||
|
pos.base, pos.queue,
|
||||||
|
open_p=9.4, high_p=10.6, low_p=9.3, close_p=10.5,
|
||||||
|
)
|
||||||
|
# 触发 buy at 9.0 (low 9.3 <= 9.0? no, 9.3 > 9.0 不触发)
|
||||||
|
# 触发 sell at 10.0 (high 10.6 >= 10.0, 卖出 1 格)
|
||||||
|
# 最终: base=11, queue=[9.5] (1 格清仓)
|
||||||
|
```
|
||||||
|
|
||||||
|
### 5. 评分池(每日全市场)
|
||||||
|
```python
|
||||||
|
from strategy import score_pool, ModelBundle
|
||||||
|
import pandas as pd
|
||||||
|
|
||||||
|
# 假设 kline_cache 是 dict[code, DataFrame]
|
||||||
|
models = ModelBundle("../models")
|
||||||
|
pool = score_pool(pd.Timestamp("2024-03-15"), kline_cache, models, models.rank_feats)
|
||||||
|
# pool 列: code6, latest_close, rank_score, top_prob, stack_prob
|
||||||
|
# 按 stack_prob 降序, 取 top 10
|
||||||
|
top10 = pool.head(10)
|
||||||
|
```
|
||||||
|
|
||||||
|
## 关键参数(可调)
|
||||||
|
|
||||||
|
| 参数 | 默认 | 说明 | 调优方向 |
|
||||||
|
|---|---|---|---|
|
||||||
|
| `WEEKLY_ELIM_N` | 2 | 周度淘汰: 连续 N 周不在 top 50 | 1 太频, 3+ 太慢 |
|
||||||
|
| `SLUMBER_TRIGGERS` | 3 | 沉寂检测: >= 3/5 特征触发 | 2 太宽, 4 太严 |
|
||||||
|
| `SLUMBER_DAYS` | 10 | 连续触发多少天清仓 | 5 太短, 20 太长 |
|
||||||
|
| `TOP_N` | 10 | 最大持仓数 | 5-15 视资金量 |
|
||||||
|
| `SHARES_PER_GRID` | 200 | 单格股数 (2 手) | 100 (1 手) 也可 |
|
||||||
|
| `REFILL_PRICE` | 9.0-9.8 | 补仓价格区间 | 紧贴 9-10 网格上限 |
|
||||||
|
|
||||||
|
## 依赖项目其他模块?
|
||||||
|
|
||||||
|
为保持 `code/` 目录**自包含**:
|
||||||
|
- ✅ 不依赖 `core/features.py` (内置 `compute_52_base_features` 简化版)
|
||||||
|
- ✅ 不依赖 `training/dataset_builder.py` (内置 `compute_4_v67_new_features`)
|
||||||
|
- ❌ 需要数据: parquet 行情文件
|
||||||
|
|
||||||
|
**生产部署建议**:用 `core/features.calculate_features` 替换 `compute_52_base_features`,
|
||||||
|
它有完整版 v3.4 52 维特征实现,精度更高。
|
||||||
|
|
||||||
|
## 完整版 vs 精简版
|
||||||
|
|
||||||
|
| 维度 | `code/strategy.py` (精简) | `tools/backtest_v67r2.py` (生产) |
|
||||||
|
|---|---|---|
|
||||||
|
| 特征计算 | 简化版 (10 维示例) | 完整版 (52 维 v3.4 + 4 维 v6.7) |
|
||||||
|
| 数据加载 | dict of DataFrame | parquet 目录 + score cache |
|
||||||
|
| 日志 | 无 | 详细进度打印 |
|
||||||
|
| 输出 | dict 指标 | CSV/JSON/PNG 完整产物 |
|
||||||
|
| 速度 | 慢 (无缓存) | 快 (有 score cache) |
|
||||||
|
| 用途 | 教学/集成 | 完整回测 |
|
||||||
|
|
||||||
|
**生产环境**:用 `tools/backtest_v67r2.py` 跑回测,确保完整功能。
|
||||||
|
**集成到实盘系统**:用 `code/strategy.py` 中的 `ModelBundle` 和 `quick_backtest` 作为模板。
|
||||||
@@ -0,0 +1,574 @@
|
|||||||
|
"""
|
||||||
|
v6.7r3 策略核心实现 —— 自包含版
|
||||||
|
================================
|
||||||
|
|
||||||
|
包含:
|
||||||
|
1. 模型加载
|
||||||
|
2. 56 维特征计算
|
||||||
|
3. 三件套预测 (rank → top → stacking)
|
||||||
|
4. 网格交易模拟器
|
||||||
|
5. 5 特征沉寂检测
|
||||||
|
6. 周度评分淘汰
|
||||||
|
7. 月末调仓 + 清仓补入
|
||||||
|
|
||||||
|
依赖:
|
||||||
|
pip install pandas numpy lightgbm scipy
|
||||||
|
(内嵌了核心算法, 不依赖项目其他模块, 可独立运行)
|
||||||
|
"""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import math
|
||||||
|
import pickle
|
||||||
|
import time
|
||||||
|
from collections import defaultdict
|
||||||
|
from dataclasses import dataclass, field
|
||||||
|
from pathlib import Path
|
||||||
|
from typing import Dict, List, Optional, Tuple
|
||||||
|
|
||||||
|
import numpy as np
|
||||||
|
import pandas as pd
|
||||||
|
|
||||||
|
# ============================================================
|
||||||
|
# 0. 配置
|
||||||
|
# ============================================================
|
||||||
|
|
||||||
|
# 网格
|
||||||
|
INITIAL_CASH = 60_000.0
|
||||||
|
TOP_N = 10
|
||||||
|
TOP_MODEL_N = 50
|
||||||
|
SHARES_PER_GRID = 200
|
||||||
|
MIN_BUY_PRICE = 7.0
|
||||||
|
MAX_BUY_PRICE = 10.0
|
||||||
|
REFILL_MIN_PRICE = 9.0
|
||||||
|
REFILL_MAX_PRICE = 9.8
|
||||||
|
GRID_LOWER, GRID_UPPER = 1, 11
|
||||||
|
|
||||||
|
# 沉寂检测
|
||||||
|
SLUMBER_TRIGGERS = 3 # >= 3/5 特征触发
|
||||||
|
SLUMBER_DAYS = 10 # 连续 10 日触发
|
||||||
|
SLUMBER_LOOKBACK_60 = 60
|
||||||
|
SLUMBER_LOOKBACK_20 = 20
|
||||||
|
|
||||||
|
# 周度淘汰
|
||||||
|
WEEKLY_ELIM_N = 2 # 连续 2 周不在 top 50 → 卖
|
||||||
|
|
||||||
|
|
||||||
|
# ============================================================
|
||||||
|
# 1. 持仓 + 网格交易
|
||||||
|
# ============================================================
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class Position:
|
||||||
|
code: str
|
||||||
|
base: int # 当前基准价 (整数)
|
||||||
|
queue: list = field(default_factory=list) # 持仓队列: 每格成本价
|
||||||
|
entry_date: str = ""
|
||||||
|
|
||||||
|
|
||||||
|
def compute_initial_position(close: float) -> Tuple[int, list]:
|
||||||
|
"""初始建仓: base=ceil(close), queue=[10, 9, ..., base] 且 >= close"""
|
||||||
|
base = math.ceil(close)
|
||||||
|
base = max(GRID_LOWER, min(base, GRID_UPPER))
|
||||||
|
queue = [g for g in range(GRID_UPPER, base - 1, -1) if g >= close]
|
||||||
|
return base, queue
|
||||||
|
|
||||||
|
|
||||||
|
def compute_single_position(close: float) -> Tuple[int, list]:
|
||||||
|
"""单格建仓"""
|
||||||
|
base = math.ceil(close)
|
||||||
|
base = max(GRID_LOWER, min(base, GRID_UPPER))
|
||||||
|
return base, [base]
|
||||||
|
|
||||||
|
|
||||||
|
def simulate_grid_day(base, queue, open_p, high_p, low_p, close_p, can_buy=True):
|
||||||
|
"""单日网格交易 (LIFO)"""
|
||||||
|
trades = []
|
||||||
|
new_base, new_queue = base, list(queue)
|
||||||
|
|
||||||
|
# 1) 买
|
||||||
|
buy_price = new_base - 1
|
||||||
|
if low_p <= buy_price and new_base > GRID_LOWER and can_buy:
|
||||||
|
new_base = buy_price
|
||||||
|
new_queue.append(buy_price)
|
||||||
|
trades.append({"direction": "buy", "price": buy_price, "shares": SHARES_PER_GRID, "pnl": 0.0})
|
||||||
|
|
||||||
|
# 2) 卖 (循环)
|
||||||
|
while True:
|
||||||
|
sell_price = new_base + 1
|
||||||
|
if high_p >= sell_price and new_queue:
|
||||||
|
buy_cost = new_queue.pop()
|
||||||
|
pnl = (sell_price - buy_cost) * SHARES_PER_GRID
|
||||||
|
trades.append({"direction": "sell", "price": sell_price, "shares": SHARES_PER_GRID, "pnl": pnl})
|
||||||
|
new_base = sell_price
|
||||||
|
else:
|
||||||
|
break
|
||||||
|
|
||||||
|
return new_base, new_queue, trades
|
||||||
|
|
||||||
|
|
||||||
|
# ============================================================
|
||||||
|
# 2. 5 特征沉寂检测
|
||||||
|
# ============================================================
|
||||||
|
|
||||||
|
def is_slumbering(df: pd.DataFrame, lookback_60=60, lookback_20=20,
|
||||||
|
min_triggers=SLUMBER_TRIGGERS) -> bool:
|
||||||
|
"""检测一只股是否陷入'沉寂' (资金离场后长期低位震荡).
|
||||||
|
5 特征, >= min_triggers 触发.
|
||||||
|
"""
|
||||||
|
if df is None or len(df) < lookback_60:
|
||||||
|
return False
|
||||||
|
sub = df.tail(lookback_60)
|
||||||
|
close = sub["close"].values
|
||||||
|
high = sub["high"].values
|
||||||
|
low = sub["low"].values
|
||||||
|
vol = sub["volume"].values
|
||||||
|
|
||||||
|
# 1. 波动率塌陷
|
||||||
|
log_ret = np.log(close[1:] / close[:-1])
|
||||||
|
if len(log_ret) < lookback_20:
|
||||||
|
return False
|
||||||
|
vol_20d = float(np.std(log_ret[-lookback_20:], ddof=1))
|
||||||
|
vol_60d = float(np.std(log_ret, ddof=1))
|
||||||
|
vol_collapse = (vol_60d > 0) and (vol_20d / vol_60d < 0.6)
|
||||||
|
|
||||||
|
# 2. 振幅萎缩
|
||||||
|
amp_20d = float(np.mean((high[-lookback_20:] - low[-lookback_20:]) / close[-lookback_20:]) * 100)
|
||||||
|
amp_shrink = amp_20d < 2.5
|
||||||
|
|
||||||
|
# 3. 成交量枯竭
|
||||||
|
avg_vol_20 = float(np.mean(vol[-lookback_20:]))
|
||||||
|
avg_vol_60 = float(np.mean(vol))
|
||||||
|
vol_dry = (avg_vol_60 > 0) and (avg_vol_20 / avg_vol_60 < 0.5)
|
||||||
|
|
||||||
|
# 4. 价格弱势
|
||||||
|
price_max_60 = float(np.max(close))
|
||||||
|
price_weak = price_max_60 > 0 and (close[-1] / price_max_60) < 0.85
|
||||||
|
|
||||||
|
# 5. 反弹失败
|
||||||
|
recent_high_30 = float(np.max(high[-30:]))
|
||||||
|
past_high_60 = float(np.max(high))
|
||||||
|
rebound_fail = past_high_60 > 0 and (recent_high_30 / past_high_60) < 0.95
|
||||||
|
|
||||||
|
triggers = [vol_collapse, amp_shrink, vol_dry, price_weak, rebound_fail]
|
||||||
|
return sum(triggers) >= min_triggers
|
||||||
|
|
||||||
|
|
||||||
|
# ============================================================
|
||||||
|
# 3. 模型加载 + 三件套预测
|
||||||
|
# ============================================================
|
||||||
|
|
||||||
|
class ModelBundle:
|
||||||
|
"""v6.7r3 三件套模型封装"""
|
||||||
|
def __init__(self, model_dir: str | Path):
|
||||||
|
model_dir = Path(model_dir)
|
||||||
|
with open(model_dir / "rank_lambdarank.pkl", "rb") as f:
|
||||||
|
rank_b = pickle.load(f)
|
||||||
|
with open(model_dir / "top_v67r2.pkl", "rb") as f:
|
||||||
|
top_b = pickle.load(f)
|
||||||
|
with open(model_dir / "stacking_v67r2.pkl", "rb") as f:
|
||||||
|
stack_b = pickle.load(f)
|
||||||
|
|
||||||
|
self.rank_model = rank_b["model"]
|
||||||
|
self.rank_feats = rank_b["feat_names"] # 56 维
|
||||||
|
self.top_model = top_b["model"]
|
||||||
|
self.top_feats = top_b["feat_names"] # 53 维
|
||||||
|
self.stack_model = stack_b["model"]
|
||||||
|
self.stack_feats = stack_b["feat_names"] # 55 维
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _safe_predict_proba(model, X):
|
||||||
|
if hasattr(model, "predict_proba"):
|
||||||
|
return model.predict_proba(X)[:, 1]
|
||||||
|
return model.predict(X, raw_score=False)
|
||||||
|
|
||||||
|
def predict(self, X56: np.ndarray) -> dict:
|
||||||
|
"""输入 56 维特征矩阵 (n, 56), 返回三件套预测 dict.
|
||||||
|
返回: rank_score (n,), top_prob (n,), stack_prob (n,)
|
||||||
|
"""
|
||||||
|
rank_pred = self.rank_model.predict(X56)
|
||||||
|
|
||||||
|
# 52 维基础特征在 X56 中的索引
|
||||||
|
base_52_idx = [self.rank_feats.index(f) for f in self.top_feats if f != "rank_predicted_rounds"]
|
||||||
|
X53 = np.column_stack([X56[:, base_52_idx], rank_pred])
|
||||||
|
top_prob = self._safe_predict_proba(self.top_model, X53)
|
||||||
|
|
||||||
|
X55 = np.column_stack([X53, top_prob])
|
||||||
|
stack_prob = self._safe_predict_proba(self.stack_model, X55)
|
||||||
|
|
||||||
|
return {
|
||||||
|
"rank_score": rank_pred,
|
||||||
|
"top_prob": top_prob,
|
||||||
|
"stack_prob": stack_prob,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
# ============================================================
|
||||||
|
# 4. 特征计算 (从项目 core/features.py 抽取, 关键函数)
|
||||||
|
# ============================================================
|
||||||
|
|
||||||
|
def _log_returns(close: np.ndarray) -> np.ndarray:
|
||||||
|
return np.log(close[1:] / close[:-1])
|
||||||
|
|
||||||
|
|
||||||
|
def _ema(arr: np.ndarray, period: int) -> np.ndarray:
|
||||||
|
"""指数移动平均"""
|
||||||
|
alpha = 2.0 / (period + 1)
|
||||||
|
out = np.zeros_like(arr)
|
||||||
|
out[0] = arr[0]
|
||||||
|
for i in range(1, len(arr)):
|
||||||
|
out[i] = alpha * arr[i] + (1 - alpha) * out[i-1]
|
||||||
|
return out
|
||||||
|
|
||||||
|
|
||||||
|
def compute_52_base_features(df: pd.DataFrame, total_share: Optional[float] = None) -> dict:
|
||||||
|
"""计算 v3.4 的 52 维基础特征 (简化版, 不完全等同于原版).
|
||||||
|
注: 完整版在 core/features.py, 这里用 pandas/numpy 简化.
|
||||||
|
"""
|
||||||
|
n = len(df)
|
||||||
|
if n < 60:
|
||||||
|
return None
|
||||||
|
|
||||||
|
close = df["close"].values
|
||||||
|
high = df["high"].values
|
||||||
|
low = df["low"].values
|
||||||
|
open_ = df["open"].values
|
||||||
|
vol = df["volume"].values
|
||||||
|
|
||||||
|
feats = {}
|
||||||
|
|
||||||
|
# 1. rolling_grid_ratio_20d
|
||||||
|
feats["rolling_grid_ratio_20d"] = float(np.mean((close[-20:] >= 1) & (close[-20:] <= 11)) * 100)
|
||||||
|
|
||||||
|
# 2. cross_freq_20d
|
||||||
|
diff = close[1:] - close[:-1]
|
||||||
|
sign_change = np.sum(np.abs(np.diff(np.sign(diff[-19:]))) > 0)
|
||||||
|
feats["cross_freq_20d"] = float(sign_change / 19 * 100) if 19 > 0 else 0.0
|
||||||
|
|
||||||
|
# 3. avg_daily_amp
|
||||||
|
feats["avg_daily_amp"] = float(np.mean((high - low) / open_) * 100) if n > 0 else 0.0
|
||||||
|
|
||||||
|
# 4. high_amp_days
|
||||||
|
feats["high_amp_days"] = float(np.mean((high - low) / open_ > 0.02) * 100) if n > 0 else 0.0
|
||||||
|
|
||||||
|
# 5. atr_pct
|
||||||
|
tr = np.maximum(high - low, np.maximum(np.abs(high - np.roll(close, 1)),
|
||||||
|
np.abs(low - np.roll(close, 1))))
|
||||||
|
feats["atr_pct"] = float(np.mean(tr[-14:]) / close[-1] * 100) if close[-1] > 0 else 0.0
|
||||||
|
|
||||||
|
# 6. volatility_20d (年化)
|
||||||
|
log_ret = _log_returns(close)
|
||||||
|
feats["volatility_20d"] = float(np.std(log_ret[-20:], ddof=1) * np.sqrt(252) * 100) if len(log_ret) >= 20 else 0.0
|
||||||
|
|
||||||
|
# 7. price_cv
|
||||||
|
feats["price_cv"] = float(np.std(close, ddof=1) / np.mean(close) * 100) if n > 1 and np.mean(close) > 0 else 0.0
|
||||||
|
|
||||||
|
# 8. bb_width (布林带宽)
|
||||||
|
ma20 = np.mean(close[-20:])
|
||||||
|
sd20 = np.std(close[-20:], ddof=1)
|
||||||
|
feats["bb_width"] = float((4 * sd20) / ma20 * 100) if ma20 > 0 else 0.0
|
||||||
|
|
||||||
|
# 9. volume_ratio
|
||||||
|
avg_vol_20 = float(np.mean(vol[-20:])) if n >= 20 else float(np.mean(vol))
|
||||||
|
avg_vol_60 = float(np.mean(vol[-60:])) if n >= 60 else float(np.mean(vol))
|
||||||
|
feats["volume_ratio"] = avg_vol_20 / avg_vol_60 if avg_vol_60 > 0 else 0.0
|
||||||
|
|
||||||
|
# 10. obv_slope
|
||||||
|
direction = np.sign(np.diff(close))
|
||||||
|
direction = np.concatenate([[0], direction])
|
||||||
|
obv = np.cumsum(direction * vol)
|
||||||
|
if len(obv) >= 20:
|
||||||
|
x = np.arange(20)
|
||||||
|
y = obv[-20:]
|
||||||
|
feats["obv_slope"] = float((np.polyfit(x, y, 1)[0]) / (np.mean(np.abs(y)) + 1e-10))
|
||||||
|
else:
|
||||||
|
feats["obv_slope"] = 0.0
|
||||||
|
|
||||||
|
# ... (其他 42 维特征省略, 完整版在 core/features.py)
|
||||||
|
# 这里只展示 10 个核心特征的计算模式
|
||||||
|
# 实际部署时建议直接调用项目 core.features.calculate_features
|
||||||
|
|
||||||
|
return feats
|
||||||
|
|
||||||
|
|
||||||
|
def compute_4_v67_new_features(df: pd.DataFrame, fd: dict) -> dict:
|
||||||
|
"""计算 v6.7 新增的 4 维特征"""
|
||||||
|
n = len(df)
|
||||||
|
if n < 60:
|
||||||
|
return fd
|
||||||
|
|
||||||
|
close = df["close"].values
|
||||||
|
high = df["high"].values
|
||||||
|
low = df["low"].values
|
||||||
|
|
||||||
|
# 53. vol_decay_5d
|
||||||
|
log_ret = np.log(close[1:] / close[:-1])
|
||||||
|
if len(log_ret) >= 20:
|
||||||
|
vol_5d = float(np.std(log_ret[-5:], ddof=1))
|
||||||
|
vol_20d = float(np.std(log_ret[-20:], ddof=1))
|
||||||
|
fd["vol_decay_5d"] = vol_5d / vol_20d if vol_20d > 0 else 0.0
|
||||||
|
else:
|
||||||
|
fd["vol_decay_5d"] = 0.0
|
||||||
|
|
||||||
|
# 54. grid_touch_relative_10d
|
||||||
|
if n >= 60:
|
||||||
|
range_10d = float(np.max(high[-10:]) - np.min(low[-10:]))
|
||||||
|
range_60d = float(np.max(high[-60:]) - np.min(low[-60:]))
|
||||||
|
close_now = float(close[-1])
|
||||||
|
close_60d_mean = float(np.mean(close[-60:]))
|
||||||
|
if close_now > 0 and close_60d_mean > 0 and range_60d > 0:
|
||||||
|
fd["grid_touch_relative_10d"] = (range_10d / close_now) / (range_60d / close_60d_mean)
|
||||||
|
else:
|
||||||
|
fd["grid_touch_relative_10d"] = 0.0
|
||||||
|
else:
|
||||||
|
fd["grid_touch_relative_10d"] = 0.0
|
||||||
|
|
||||||
|
# 55. vol_decay_x_grid_balance
|
||||||
|
fd["vol_decay_x_grid_balance"] = fd.get("vol_decay_5d", 0.0) * fd.get("grid_room_balance", 0.0)
|
||||||
|
|
||||||
|
# 56. vol_decay_x_dist_lower
|
||||||
|
fd["vol_decay_x_dist_lower"] = fd.get("vol_decay_5d", 0.0) * fd.get("dist_to_grid_lower", 0.0)
|
||||||
|
|
||||||
|
return fd
|
||||||
|
|
||||||
|
|
||||||
|
# ============================================================
|
||||||
|
# 5. 评分池(单日)
|
||||||
|
# ============================================================
|
||||||
|
|
||||||
|
def score_pool(date: pd.Timestamp,
|
||||||
|
kline_cache: Dict[str, pd.DataFrame],
|
||||||
|
models: ModelBundle,
|
||||||
|
feat_names: list) -> pd.DataFrame:
|
||||||
|
"""对所有有 120 日历史的股算 v6.7 三件套预测.
|
||||||
|
返回 DataFrame: code6, latest_close, rank_score, top_prob, stack_prob
|
||||||
|
"""
|
||||||
|
PRICE_MIN, PRICE_MAX = 1.0, 11.0
|
||||||
|
rows = []
|
||||||
|
codes = []
|
||||||
|
closes = []
|
||||||
|
|
||||||
|
for code, df in kline_cache.items():
|
||||||
|
sub = df[df["date"] <= date]
|
||||||
|
if len(sub) < 120:
|
||||||
|
continue
|
||||||
|
latest = float(sub["close"].iloc[-1])
|
||||||
|
if not (PRICE_MIN <= latest <= PRICE_MAX):
|
||||||
|
continue
|
||||||
|
|
||||||
|
# 算 56 维特征
|
||||||
|
obs = sub.tail(120).reset_index(drop=True)
|
||||||
|
fd = compute_52_base_features(obs)
|
||||||
|
if fd is None:
|
||||||
|
continue
|
||||||
|
fd = compute_4_v67_new_features(obs, fd)
|
||||||
|
try:
|
||||||
|
X = np.array([fd.get(k, 0.0) for k in feat_names], dtype=np.float64).reshape(1, -1)
|
||||||
|
pred = models.predict(X)
|
||||||
|
except Exception:
|
||||||
|
continue
|
||||||
|
rows.append(pred)
|
||||||
|
codes.append(code)
|
||||||
|
closes.append(latest)
|
||||||
|
|
||||||
|
if not rows:
|
||||||
|
return pd.DataFrame(columns=["code6", "latest_close", "rank_score", "top_prob", "stack_prob"])
|
||||||
|
|
||||||
|
import numpy as np
|
||||||
|
return pd.DataFrame({
|
||||||
|
"code6": codes,
|
||||||
|
"latest_close": closes,
|
||||||
|
"rank_score": [r["rank_score"][0] for r in rows],
|
||||||
|
"top_prob": [r["top_prob"][0] for r in rows],
|
||||||
|
"stack_prob": [r["stack_prob"][0] for r in rows],
|
||||||
|
}).sort_values("stack_prob", ascending=False).reset_index(drop=True)
|
||||||
|
|
||||||
|
|
||||||
|
# ============================================================
|
||||||
|
# 6. 主回测入口(精简版, 仅展示核心逻辑)
|
||||||
|
# ============================================================
|
||||||
|
|
||||||
|
def quick_backtest(kline_cache: Dict[str, pd.DataFrame],
|
||||||
|
models: ModelBundle,
|
||||||
|
start_date: str = "2023-05-01",
|
||||||
|
end_date: str = "2026-04-30",
|
||||||
|
weekly_elim_n: int = WEEKLY_ELIM_N,
|
||||||
|
slumber_days: int = SLUMBER_DAYS) -> dict:
|
||||||
|
"""精简版 3 年回测 (生产级完整版见 tools/backtest_v67r2.py).
|
||||||
|
|
||||||
|
核心流程:
|
||||||
|
1. 初始建仓
|
||||||
|
2. 每日: 网格交易 + 沉寂检测
|
||||||
|
3. 周五: 周度评分淘汰 + 补仓
|
||||||
|
4. 月末: 清仓补入 (触及 11 元)
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
dict: 总收益率, 年化夏普, 最大回撤, 周胜率, 终值
|
||||||
|
"""
|
||||||
|
feat_names = models.rank_feats
|
||||||
|
|
||||||
|
# 交易日索引
|
||||||
|
sample = next(iter(kline_cache.values()))
|
||||||
|
all_dates = pd.DatetimeIndex(sorted(sample["date"].unique()))
|
||||||
|
mask = (all_dates >= start_date) & (all_dates <= end_date)
|
||||||
|
backtest_dates = all_dates[mask]
|
||||||
|
|
||||||
|
# 初始评分 (INIT_SELECT_DATE)
|
||||||
|
init_date = pd.Timestamp("2023-04-28")
|
||||||
|
init_pool = score_pool(init_date, kline_cache, models, feat_names)
|
||||||
|
init_pool = init_pool[init_pool["latest_close"].apply(lambda p: MIN_BUY_PRICE <= p <= MAX_BUY_PRICE)]
|
||||||
|
init_pool = init_pool.sort_values("stack_prob", ascending=False).head(TOP_N)
|
||||||
|
|
||||||
|
# 初始建仓
|
||||||
|
positions: Dict[str, Position] = {}
|
||||||
|
cash = INITIAL_CASH
|
||||||
|
for _, row in init_pool.iterrows():
|
||||||
|
code = row["code6"]
|
||||||
|
actual_close = float(row["latest_close"])
|
||||||
|
base, grid_queue = compute_initial_position(actual_close)
|
||||||
|
if not grid_queue:
|
||||||
|
continue
|
||||||
|
positions[code] = Position(code, base, [actual_close] * len(grid_queue), "2023-04-28")
|
||||||
|
for _ in grid_queue:
|
||||||
|
cash -= actual_close * SHARES_PER_GRID
|
||||||
|
|
||||||
|
# 周度淘汰历史
|
||||||
|
top50_history = defaultdict(list)
|
||||||
|
slumber_streak: Dict[str, int] = {}
|
||||||
|
total_asset_history = []
|
||||||
|
weekly_pnl = []
|
||||||
|
|
||||||
|
for i, cur_date in enumerate(backtest_dates):
|
||||||
|
cur_str = cur_date.strftime("%Y-%m-%d")
|
||||||
|
is_week_end = (i == len(backtest_dates) - 1) or (backtest_dates[i + 1].week != cur_date.week)
|
||||||
|
|
||||||
|
# === 网格日间交易 ===
|
||||||
|
for code, pos in list(positions.items()):
|
||||||
|
if not pos.queue:
|
||||||
|
continue
|
||||||
|
df = kline_cache[code]
|
||||||
|
sub = df[df["date"] == cur_date]
|
||||||
|
if sub.empty:
|
||||||
|
continue
|
||||||
|
row = sub.iloc[0]
|
||||||
|
new_base, new_queue, day_trades = simulate_grid_day(
|
||||||
|
pos.base, pos.queue,
|
||||||
|
float(row["open"]), float(row["high"]), float(row["low"]), float(row["close"]),
|
||||||
|
)
|
||||||
|
if day_trades:
|
||||||
|
pos.base, pos.queue = new_base, new_queue
|
||||||
|
for t in day_trades:
|
||||||
|
if t["direction"] == "buy":
|
||||||
|
cash -= t["price"] * t["shares"]
|
||||||
|
else:
|
||||||
|
cash += t["price"] * t["shares"]
|
||||||
|
|
||||||
|
# === 沉寂检测 ===
|
||||||
|
for code, pos in list(positions.items()):
|
||||||
|
if not pos.queue:
|
||||||
|
continue
|
||||||
|
df = kline_cache[code]
|
||||||
|
sub = df[df["date"] <= cur_date]
|
||||||
|
if len(sub) < 60:
|
||||||
|
continue
|
||||||
|
slumber = is_slumbering(sub)
|
||||||
|
slumber_streak[code] = slumber_streak.get(code, 0) + 1 if slumber else 0
|
||||||
|
if slumber_streak[code] >= slumber_days and pos.queue:
|
||||||
|
# 全仓清仓
|
||||||
|
px = float(sub["close"].iloc[-1])
|
||||||
|
cash += px * len(pos.queue) * SHARES_PER_GRID
|
||||||
|
positions[code] = Position(code, 0, [], cur_str)
|
||||||
|
slumber_streak[code] = 0
|
||||||
|
|
||||||
|
# === 资产快照 ===
|
||||||
|
mv = sum((float(kline_cache[c][kline_cache[c]["date"] <= cur_date]["close"].iloc[-1])
|
||||||
|
* len(p.queue) * SHARES_PER_GRID)
|
||||||
|
for c, p in positions.items() if p.queue)
|
||||||
|
total_asset = cash + mv
|
||||||
|
total_asset_history.append(total_asset)
|
||||||
|
|
||||||
|
# === 周度淘汰 + 补仓 ===
|
||||||
|
if is_week_end and i > 0 and weekly_elim_n > 0:
|
||||||
|
pool = score_pool(cur_date, kline_cache, models, feat_names)
|
||||||
|
top50 = set(pool.head(TOP_MODEL_N)["code6"].tolist())
|
||||||
|
for code in list(positions.keys()):
|
||||||
|
top50_history[code].append(code in top50)
|
||||||
|
|
||||||
|
# 连续 N 周不在 top 50 → 卖出
|
||||||
|
inactive = []
|
||||||
|
for code, p in positions.items():
|
||||||
|
if not p.queue:
|
||||||
|
continue
|
||||||
|
hist = top50_history.get(code, [])
|
||||||
|
if len(hist) >= weekly_elim_n and all(x is False for x in hist[-weekly_elim_n:]):
|
||||||
|
inactive.append(code)
|
||||||
|
for code in inactive[:1]: # 每月最多淘汰 1 只 (与 v6.3 一致)
|
||||||
|
pos = positions[code]
|
||||||
|
sub = kline_cache[code][kline_cache[code]["date"] <= cur_date]
|
||||||
|
px = float(sub["close"].iloc[-1])
|
||||||
|
cash += px * len(pos.queue) * SHARES_PER_GRID
|
||||||
|
positions[code] = Position(code, 0, [], cur_str)
|
||||||
|
|
||||||
|
# 补仓
|
||||||
|
positions = {c: p for c, p in positions.items() if p.queue}
|
||||||
|
refill_needed = max(0, TOP_N - len(positions))
|
||||||
|
if refill_needed > 0:
|
||||||
|
ref_pool = pool[pool["latest_close"].apply(lambda p: REFILL_MIN_PRICE < p < REFILL_MAX_PRICE)]
|
||||||
|
ref_pool = ref_pool[~ref_pool["code6"].isin(positions.keys())]
|
||||||
|
ref_pool = ref_pool.head(refill_needed)
|
||||||
|
for _, row in ref_pool.iterrows():
|
||||||
|
code = row["code6"]
|
||||||
|
actual_close = float(row["latest_close"])
|
||||||
|
base, grid_queue = compute_single_position(actual_close)
|
||||||
|
if not grid_queue:
|
||||||
|
continue
|
||||||
|
cost = actual_close * SHARES_PER_GRID * len(grid_queue)
|
||||||
|
if cash < cost:
|
||||||
|
continue
|
||||||
|
positions[code] = Position(code, base, [actual_close] * len(grid_queue), cur_str)
|
||||||
|
cash -= cost
|
||||||
|
|
||||||
|
# 计算指标
|
||||||
|
final_value = total_asset_history[-1] if total_asset_history else INITIAL_CASH
|
||||||
|
total_return = final_value / INITIAL_CASH - 1
|
||||||
|
rets = np.diff(total_asset_history) / total_asset_history[:-1]
|
||||||
|
sharpe = float(rets.mean() / rets.std() * np.sqrt(52)) if len(rets) > 1 and rets.std() > 0 else 0.0
|
||||||
|
cum_max = np.maximum.accumulate(total_asset_history)
|
||||||
|
dd = (np.array(total_asset_history) - cum_max) / cum_max
|
||||||
|
max_dd = float(dd.min())
|
||||||
|
win_rate = float((rets > 0).mean()) if len(rets) > 0 else 0.0
|
||||||
|
|
||||||
|
return {
|
||||||
|
"total_return_pct": round(total_return * 100, 2),
|
||||||
|
"annual_sharpe": round(sharpe, 4),
|
||||||
|
"max_drawdown_pct": round(max_dd * 100, 2),
|
||||||
|
"weekly_win_rate_pct": round(win_rate * 100, 2),
|
||||||
|
"final_value": round(final_value, 2),
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
# ============================================================
|
||||||
|
# 7. 入口示例
|
||||||
|
# ============================================================
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
# 1. 加载模型
|
||||||
|
models = ModelBundle("models") # 默认从当前目录的 models/ 加载
|
||||||
|
print(f"✓ 加载模型: rank {len(models.rank_feats)} 维, "
|
||||||
|
f"top {len(models.top_feats)} 维, stack {len(models.stack_feats)} 维")
|
||||||
|
|
||||||
|
# 2. 加载行情 (示例: 从 parquet 目录)
|
||||||
|
# 实际部署时, 从 market_data.kline_stock (Postgres) 或本地 parquet 加载
|
||||||
|
from pathlib import Path
|
||||||
|
parquet_dir = Path("data/market_data/share")
|
||||||
|
kline_cache = {}
|
||||||
|
for p in parquet_dir.glob("*.parquet"):
|
||||||
|
df = pd.read_parquet(p)
|
||||||
|
df["date"] = pd.to_datetime(df["date"])
|
||||||
|
kline_cache[p.stem] = df
|
||||||
|
print(f"✓ 加载行情: {len(kline_cache)} 只股")
|
||||||
|
|
||||||
|
# 3. 跑精简版回测
|
||||||
|
metrics = quick_backtest(kline_cache, models)
|
||||||
|
print("\n=== v6.7r3 三年回测结果 (精简版) ===")
|
||||||
|
for k, v in metrics.items():
|
||||||
|
print(f" {k}: {v}")
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
date,code,exit_price,realized_pnl,slumber_streak_days
|
||||||
|
2023-07-21,920870,7.53,-374.0,10
|
||||||
|
2023-07-25,920414,9.44,-1.9999999999999574,10
|
||||||
|
2024-03-27,920641,7.56,-734.0000000000001,10
|
||||||
|
2024-04-03,920001,8.93,-164.00000000000006,10
|
||||||
|
2024-05-31,603825,8.36,-130.00000000000006,10
|
||||||
|
2024-09-06,300462,8.98,-16.000000000000014,10
|
||||||
|
2024-09-11,920641,6.67,-1404.0,10
|
||||||
|
2024-12-23,920090,6.48,-1365.9999999999995,10
|
||||||
|
2024-12-25,920021,5.71,-1352.0,10
|
||||||
|
2025-01-13,920792,8.58,-107.99999999999983,10
|
||||||
|
2025-01-22,920371,6.9,-1199.9999999999998,10
|
||||||
|
2025-01-24,920339,7.86,-571.9999999999997,10
|
||||||
|
2025-01-27,920792,8.99,-85.99999999999994,10
|
||||||
|
2025-02-05,920810,8.18,-217.99999999999997,10
|
||||||
|
2025-03-13,002789,7.35,-942.0,10
|
||||||
|
2025-05-21,300052,10.3,258.00000000000017,10
|
||||||
|
2025-05-26,920639,9.54,185.9999999999996,10
|
||||||
|
2025-05-26,920553,10.17,94.00000000000013,10
|
||||||
|
2025-06-12,300052,9.94,77.99999999999976,10
|
||||||
|
2025-08-12,300798,9.11,-53.90000000000015,10
|
||||||
|
2025-09-26,000679,7.75,-501.99999999999994,10
|
||||||
|
2026-03-03,300086,8.81,-114.00000000000006,10
|
||||||
|
Binary file not shown.
@@ -0,0 +1,36 @@
|
|||||||
|
{
|
||||||
|
"rank": {
|
||||||
|
"v6.6": {
|
||||||
|
"spearman_on_val": 0.5741312551267312
|
||||||
|
},
|
||||||
|
"v6.7r2": {
|
||||||
|
"spearman_on_val": 0.5896180660523218
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"top": {
|
||||||
|
"v6.6": {
|
||||||
|
"pr_auc_val": 0.6881080916474673
|
||||||
|
},
|
||||||
|
"v6.7r2": {
|
||||||
|
"pr_auc_val": 0.6953262363660502
|
||||||
|
},
|
||||||
|
"delta": 0.007218144718582842
|
||||||
|
},
|
||||||
|
"stacking": {
|
||||||
|
"v6.6": {
|
||||||
|
"pr_auc_val": 0.6474384440874665,
|
||||||
|
"optimal_threshold": 0.32116277663299964,
|
||||||
|
"f1_at_thr": 0.6333791329260092
|
||||||
|
},
|
||||||
|
"v6.7r2": {
|
||||||
|
"pr_auc_val": 0.6640333379409579,
|
||||||
|
"optimal_threshold": 0.3311218467281351,
|
||||||
|
"f1_at_thr": 0.6402777365656805
|
||||||
|
},
|
||||||
|
"delta_pr_auc": 0.016594893853491333
|
||||||
|
},
|
||||||
|
"n_train": 254234,
|
||||||
|
"n_val": 73785,
|
||||||
|
"elite_rate_train": 0.2665890478850193,
|
||||||
|
"elite_rate_val": 0.19013349596801518
|
||||||
|
}
|
||||||
Binary file not shown.
@@ -1,31 +1,32 @@
|
|||||||
{
|
{
|
||||||
"version": "v6.6",
|
"version": "v6.7r3",
|
||||||
"feature_version": "v3.4",
|
"feature_version": "v3.4",
|
||||||
"architecture": "stacking_calibrated",
|
"architecture": "stacking_calibrated",
|
||||||
"data_source": "mysql://100.121.118.116:3306/grid_seeker_model_base",
|
"data_source": "mysql://100.121.118.116:3306/grid_seeker_model_base",
|
||||||
"training_date": "2026-05-28T14:23:23.662118",
|
"training_date": "2026-06-24T11:00:00.000000",
|
||||||
"n_stocks_total": 4358,
|
"n_stocks_total": 5378,
|
||||||
"n_stocks_after_filter": 1533,
|
"n_stocks_after_filter": 1533,
|
||||||
"n_training_samples": 205491,
|
"n_training_samples": 254234,
|
||||||
"window_days": 120,
|
"window_days": 120,
|
||||||
"future_days": 60,
|
"future_days": 60,
|
||||||
"step_days": 20,
|
"step_days": 20,
|
||||||
"y_rounds_mean": 0.1998384357465777,
|
"y_rounds_mean": 0.1998384357465777,
|
||||||
"y_rounds_median": 0.0,
|
"y_rounds_median": 0.0,
|
||||||
"y_rounds_zero_rate": 0.7108340511263267,
|
"y_rounds_zero_rate": 0.7108340511263267,
|
||||||
"elite_rate": 20.52109338121864,
|
"elite_rate": 26.66,
|
||||||
"rank": {
|
"rank": {
|
||||||
"cv_mae": 0.2053,
|
"cv_mae": 0.2053,
|
||||||
"cv_r2": 0.2258,
|
"cv_r2": 0.2258,
|
||||||
|
"spearman": 0.5896,
|
||||||
"best_params": {
|
"best_params": {
|
||||||
"num_leaves": 63,
|
"num_leaves": 63,
|
||||||
"min_child_samples": 30,
|
"min_child_samples": 30,
|
||||||
"max_depth": 7
|
"max_depth": 7
|
||||||
},
|
},
|
||||||
"n_features": 52
|
"n_features": 56
|
||||||
},
|
},
|
||||||
"top": {
|
"top": {
|
||||||
"cv_pr_auc": 0.5333,
|
"cv_pr_auc": 0.6953,
|
||||||
"best_params": {
|
"best_params": {
|
||||||
"num_leaves": 63,
|
"num_leaves": 63,
|
||||||
"min_child_samples": 30,
|
"min_child_samples": 30,
|
||||||
@@ -34,13 +35,27 @@
|
|||||||
"n_features": 53
|
"n_features": 53
|
||||||
},
|
},
|
||||||
"stacking": {
|
"stacking": {
|
||||||
"cv_pr_auc": 0.8207,
|
"cv_pr_auc": 0.6640,
|
||||||
"best_params": {
|
"best_params": {
|
||||||
"num_leaves": 31,
|
"num_leaves": 31,
|
||||||
"min_child_samples": 20,
|
"min_child_samples": 20,
|
||||||
"max_depth": -1
|
"max_depth": -1
|
||||||
},
|
},
|
||||||
"n_features": 54,
|
"n_features": 55,
|
||||||
"optimal_threshold": 0.35
|
"optimal_threshold": 0.33
|
||||||
}
|
},
|
||||||
|
"backtest": {
|
||||||
|
"start": "2023-05-04",
|
||||||
|
"end": "2026-04-30",
|
||||||
|
"total_return_pct": 151.92,
|
||||||
|
"annual_return_pct": 36.46,
|
||||||
|
"annual_sharpe": 1.7404,
|
||||||
|
"max_drawdown_pct": -12.10,
|
||||||
|
"weekly_win_rate_pct": 59.48,
|
||||||
|
"final_value": 151154,
|
||||||
|
"rebalancing_frequency": "weekly",
|
||||||
|
"elimination_window": "2_weeks"
|
||||||
|
},
|
||||||
|
"previous_version": "v6.6",
|
||||||
|
"previous_version_backup": "models_backup_20260624_110913"
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user