admin
2025-04-11 576549ed43a3dd635c9c091f8221c48cf2719467
strategy/market_sentiment_analysis.py
@@ -6,13 +6,9 @@
import datetime
import json
import time
import constant
from log_module import async_log_util
from log_module.log import logger_common, logger_Overall_market_strength_score, logger_debug
# import time
# 引入掘金API
# from gm.api import *
from strategy import basic_methods, kpl_api
from strategy import data_cache
@@ -20,163 +16,6 @@
# 获取logger实例
logger = logger_common
# ======================
# 模拟数据生成(完整版)
# ======================
# data = {
#     'total_stocks': 5000,  # 全市场股票总数
#     'limit_up': 120,  # 涨停股数量
#     'limit_down': 5,  # 跌停股数量
#     'advance_count': 2800,  # 上涨家数
#     'decline_count': 1500,  # 下跌家数
#     'high_retreat_count': 30,  # 当日回撤超10%的个股数量
#     'turnover': 1.2e12,  # 当日成交额(元)
#     'turnover_prev_day': 1.0e12,  # 前一日成交额
#     'northbound_inflow': 8e9,  # 北向资金净流入(元)
#     'max_northbound_30d': 15e9,  # 近30日最大北向净流入
#     'margin_buy': 8e10,  # 融资买入额
#     'sector_gains': [3.5, 2.8, 1.9, -0.5],  # 前4大板块涨幅(%)
#     'max_continuous_boards': 7,  # 最高连板数(如7连板)
#     'continuous_boards': [7, 5, 3, 2],  # 连板梯队(各层级连板数量)
# }
#
#
# # ======================
# # 因子计算与标准化处理
# # ======================
# def calculate_factors(data):
#     factors = {}
#
#     # === 新增核心因子 ===
#     # 1. 涨跌家数比(0-100分)
#     if data['decline_count'] == 0:
#         factors['advance_ratio'] = 100.0
#     else:
#         factors['advance_ratio'] = min(
#             (data['advance_count'] / data['decline_count']) * 50,  # 比值1:2对应100分
#             100.0
#         )
#
#     # 2. 涨停强度(标准化到0-100)
#     factors['limit_strength'] = (
#             (data['limit_up'] - data['limit_down']) / data['total_stocks'] * 1000  # 放大差异
#     )
#
#     # 3. 大幅回撤比例(0-100分)
#     factors['high_retreat_ratio'] = (
#             data['high_retreat_count'] / data['total_stocks'] * 1000  # 千分比更敏感
#     )
#
#     # 4. 连板高度与梯队(根据历史极值归一化)
#     factors['max_continuous'] = (
#             data['max_continuous_boards'] / 10 * 100  # 假设历史最高10连板
#     )
#     factors['board_ladder'] = (
#             len(data['continuous_boards']) / 5 * 100  # 假设最多5个连板层级
#     )
#
#     # === 原有因子优化 ===
#     # 5. 量能变化(成交额增长率)
#     turnover_growth = (
#             (data['turnover'] - data['turnover_prev_day']) /
#             data['turnover_prev_day'] * 100
#     )
#     factors['liquidity'] = turnover_growth
#
#     # 6. 板块强度(前3板块平均涨幅)
#     top_sectors = sorted(data['sector_gains'], reverse=True)[:3]
#     sector_avg = sum(top_sectors) / len(top_sectors)
#
#     factors['sector_strength'] = ((sector_avg - (-5.0)) / (10.0 - (-5.0)) * 100)  # 历史范围-5%~10%
#     # 7. 北向资金强度
#     factors['northbound_ratio'] = (data['northbound_inflow'] / data['max_northbound_30d'] * 100)
#
#     # 8. 融资买入占比
#     factors['margin_ratio'] = (data['margin_buy'] / data['turnover'] * 100)
#
#     # # 强制所有因子在0-100范围内
#     for key in factors:
#         factors[key] = max(0.0, min(factors[key], 100.0))
#
#     return factors
#
#
# # ======================
# # 权重分配(总权重1.0)
# # ======================
# def get_weights():
#     return {
#         # 新增因子权重
#         'advance_ratio': 0.15,  # 涨跌家数比
#         'limit_strength': 0.2,  # 涨停强度
#         'high_retreat_ratio': 0.1,  # 大幅回撤
#         'max_continuous': 0.1,  # 连板高度
#         'board_ladder': 0.05,  # 连板梯队
#         # 原有因子权重
#         'liquidity': 0.15,  # 量能变化
#         'sector_strength': 0.1,  # 板块强度
#         'northbound_ratio': 0.1,  # 北向资金
#         'margin_ratio': 0.05  # 融资买入
#     }
#
#
# # ======================
# # 综合强度分数计算(含动态修正)
# # ======================
# def composite_strength_score(data):
#     factors = calculate_factors(data)
#     weights = get_weights()
#
#     # 基础加权得分
#     score = sum(factors[key] * weights[key] for key in factors)
#
#     # === 动态修正规则 ===
#     # 规则1:涨停数量超过100家时额外加分
#     if data['limit_up'] > 100:
#         score += min((data['limit_up'] - 100) * 0.2, 10)  # 最多加10分
#
#     # 规则2:连板梯队断裂时扣分(如最高板与次高板差距≥3)
#     continuous_boards = sorted(data['continuous_boards'], reverse=True)
#     if len(continuous_boards) >= 2 and (continuous_boards[0] - continuous_boards[1] >= 3):
#         score -= 15  # 梯队断裂惩罚
#
#     # 规则3:北向资金与涨跌家数背离时调整
#     if (factors['northbound_ratio'] > 50) and (factors['advance_ratio'] < 40):
#         score *= 0.9  # 权重股拉升导致的虚假繁荣
#
#     return max(0.0, min(score, 100.0))
# ======================
# 执行计算与结果输出
# ======================
# final_score = composite_strength_score(data)
# print("=== 综合强度分数 ===")
# print(f"当前得分: {final_score:.1f}/100")
#
# # 输出因子贡献度分析
# factors = calculate_factors(data)
# weights = get_weights()
# print("\n=== 因子贡献度明细 ===")
# for key in factors:
#     print(f"{key:20s}: {factors[key]:5.1f} × {weights[key]:.0%} = {factors[key] * weights[key]:5.1f}")
''' 代码输出示例:
=== 综合强度分数 ===
当前得分: 78.4/100
=== 因子贡献度明细 ===
advance_ratio        :  93.3 × 15% = 14.0
limit_strength       :  23.0 × 20% =  4.6
high_retreat_ratio   :   6.0 × 10% =  0.6
max_continuous       :  70.0 × 10% =  7.0
board_ladder         :  80.0 ×  5% =  4.0
liquidity            :  20.0 × 15% =  3.0
sector_strength      :  60.0 × 10% =  6.0
northbound_ratio     :  53.3 × 10% =  5.3
margin_ratio         :  10.0 ×  5% =  0.5
'''
# 指数行情策略函数
@@ -189,6 +28,8 @@
        'TSXV': {}
    }
    if current_info is not None and len_current_info > 0:
        now_time_str = tool.get_now_time_str()
        if data_cache.L1_DATA_START_TIME < now_time_str < data_cache.CLOSING_TIME:
        # print(f"current_info------------{current_info}")
        # 上证指数数据
        Shanghai_index_data = current_info.get('000001')
@@ -561,140 +402,162 @@
# 计算市场分布形态因子 函数
def calculate_market_distribution_pattern_factor(data):
# ====================== 输入数据 ======================
data = {'-1': '210', '-10': '4', '-2': '134', '-3': '71', '-4': '45', '-5': '18', '-6': '15', '-7': '7', '-8': '6', '-9': '2', '0': '83', '1': '650', '10': '41', '2': '1242', '3': '1182', '4': '784', '5': '334', '6': '139', '7': '77', '8': '46', '9': '16', 'DT': 5, 'SJDT': '1', 'SJZT': '17', 'STDT': '4', 'STZT': '2', 'SZJS': 4530, 'XDJS': 517, 'ZSZDFB': '1929,247,56,435,61,3,259,29,4,44,5,1,38,9,3,239,51,10,', 'ZT': 19, 'sign': '市场人气较好', 'szln': 1723817, 'qscln': 5291241, 's_zrcs': 2413498, 'q_zrcs': 6183792, 's_zrtj': 75543024, 'q_zrtj': 169960513}
# ====================== 数据预处理 ======================
def preprocess_data(data):
    """
        原生Python数据预处理
        返回:
            sorted_bins   : 排序后的涨跌幅区间(整数列表)
            sorted_counts : 对应区间的股票数量
            total         : 总股票数
            pos_counts    : 正涨跌区间的数量列表
            neg_counts    : 负涨跌区间的数量列表
    预处理原始数据:
    1. 转换所有数值字段为整数
    2. 解析涨跌分布(ZSZDFB)为整数列表
    3. 分离涨跌幅分布数据
        """
    # 将字符串键转为整数并排序
    sorted_items = sorted(data.items(), key=lambda x: int(x[0]))
    sorted_bins = [int(k) for k, v in sorted_items]
    sorted_counts = [v for k, v in sorted_items]
    processed = {}
    # 计算总股票数
    total = sum(sorted_counts)
    # 分离正负区间(排除0%)
    pos_counts = [v for k, v in sorted_items if int(k) > 0]
    neg_counts = [v for k, v in sorted_items if int(k) < 0]
    return sorted_bins, sorted_counts, total, pos_counts, neg_counts
# 执行预处理
bins, counts, total, pos_counts, neg_counts = calculate_market_distribution_pattern_factor(data_cache.rise_and_fall_statistics_dirt)
# ====================== 因子计算模块 ======================
class NativeFactorCalculator:
    def __init__(self, bins, counts, total, pos_counts, neg_counts):
        self.bins = bins
        self.counts = counts
        # todo total 会默认为0的情况
        if total != 0:
            self.total = total
    # 通用字段类型转换
    for key, value in data.items():
        if isinstance(value, str) and value.isdigit():  # 处理字符串数字
            processed[key] = int(value)
        elif key == 'ZSZDFB':  # 特殊处理涨跌分布
            # 过滤空值并转换为整数列表
            processed[key] = [int(x) for x in value.strip(',').split(',')]
        else:
            self.total = 1
        self.pos_counts = pos_counts
        self.neg_counts = neg_counts
            processed[key] = value  # 保留原始类型
    def calculate_bdr(self):
        """原生涨跌比计算"""
        sum_pos = sum(self.pos_counts)
        sum_neg = sum(self.neg_counts)
        return sum_pos / sum_neg if sum_neg != 0 else float('nan')
    def calculate_extreme_ratio(self):
        """极端波动比例计算"""
        extreme_total = 0
        for b, c in zip(self.bins, self.counts):
            if b >= 5 or b <= -5:
                extreme_total += c
        return extreme_total / self.total
    def calculate_market_breadth(self):
        """市场宽度因子计算"""
        diff = sum(self.pos_counts) - sum(self.neg_counts)
        return diff / self.total
    def _expand_distribution(self):
        """将分箱数据展开为原始数据点(用于计算统计指标)"""
        expanded = []
        for value, count in zip(self.bins, self.counts):
            expanded.extend([value] * count)
        return expanded
    def calculate_distribution_metrics(self):
        """原生偏度与峰度计算"""
        data = self._expand_distribution()
        n = len(data)
        if n < 2:
            return (float('nan'), float('nan'))
        # 计算均值
        mean = sum(data) / n
        # 计算标准差
        variance = sum((x - mean) ** 2 for x in data) / (n - 1)
        std_dev = variance ** 0.5
        # 计算偏度
        skewness = (sum((x - mean) ** 3 for x in data) / n) / (std_dev ** 3) if std_dev != 0 else 0
        # 计算峰度(Fisher定义,即正态分布峰度为0)
        kurtosis = (sum((x - mean) ** 4 for x in data) / n) / (std_dev ** 4) - 3 if std_dev != 0 else 0
        return (skewness, kurtosis)
    # 分离涨跌幅分布数据(示例划分,具体区间需确认)
    # 假设ZSZDFB对应从-10%到10%的18个区间分布(根据数据长度推测)
    processed['price_distribution'] = {
        'bins': list(range(-10, 11)),  # 生成-10到10的整数区间标识
        'counts': processed['ZSZDFB']
    }
    return processed
# 实例化并计算因子
calculator = NativeFactorCalculator(bins, counts, total, pos_counts, neg_counts)
bdr = calculator.calculate_bdr()
extreme_ratio = calculator.calculate_extreme_ratio()
market_breadth = calculator.calculate_market_breadth()
skewness, kurtosis = calculator.calculate_distribution_metrics()
# data = preprocess_data(raw_data)
# ====================== 策略信号生成模块 ======================
class NativeTradingStrategy:
    def __init__(self, bdr_threshold=1.5, extreme_threshold=0.15):
        self.bdr_threshold = bdr_threshold
        self.extreme_threshold = extreme_threshold
# ====================== 核心因子计算 ======================
def calculate_factors(data):
    if data is not None:
        zero = int(data.get('0'))
        rise_one = int(data.get('1'))
        rise_two = int(data.get('2'))
        rise_three = int(data.get('3'))
        rise_four = int(data.get('4'))
        rise_five = int(data.get('5'))
        rise_six = int(data.get('6'))
        rise_seven = int(data.get('7'))
        rise_eight = int(data.get('8'))
        rise_nine = int(data.get('9'))
        rise_ten = int(data.get('10'))
        fall_one = int(data.get('-1'))
        fall_two = int(data.get('-2'))
        fall_three = int(data.get('-3'))
        fall_four = int(data.get('-4'))
        fall_five = int(data.get('-5'))
        fall_six = int(data.get('-6'))
        fall_seven = int(data.get('-7'))
        fall_eight = int(data.get('-8'))
        fall_nine = int(data.get('-9'))
        fall_ten = int(data.get('-10'))
        print(type(fall_ten))
    def generate_signals(self, bdr, extreme_ratio, market_breadth, skewness):
        """生成交易信号(与之前相同,保持策略逻辑)"""
        """计算市场关键指标因子"""
        factors = {}
        # 总票数
        total_stocks = zero + rise_one + rise_two + rise_three + rise_four + rise_five + rise_six + rise_seven + rise_eight + rise_nine + rise_ten + fall_one + fall_two + fall_three + fall_four + fall_five + fall_six + fall_seven + fall_eight + fall_nine + fall_ten
        print(f"total_stocks = {total_stocks}")
        factors['total_stocks'] = total_stocks
        # 涨跌统计(排除0%)
        rise = rise_one + rise_two + rise_three + rise_four + rise_five + rise_six + rise_seven + rise_eight + rise_nine + rise_ten
        fall = fall_one + fall_two + fall_three + fall_four + fall_five + fall_six + fall_seven + fall_eight + fall_nine + fall_ten
        rise_dirt = {
            'rise_one': rise_one,
            'rise_two': rise_two,
            'rise_three': rise_three,
            'rise_four': rise_four,
            'rise_five': rise_five,
            'rise_six': rise_six,
            'rise_seven': rise_seven,
            'rise_eight': rise_eight,
            'rise_nine': rise_nine,
            'rise_ten': rise_ten,
        }
        fall_dirt = {
            'fall_one': fall_one,
            'fall_two': fall_two,
            'fall_three': fall_three,
            'fall_four': fall_four,
            'fall_five': fall_five,
            'fall_six': fall_six,
            'fall_seven': fall_seven,
            'fall_eight': fall_eight,
            'fall_nine': fall_nine,
            'fall_ten': fall_ten,
        }
        # 计算所有值的总和
        total_sum = sum(rise_dirt.values())
        # 计算每个键的值占总和的百分比
        percentages = {key: round((value / total_sum) * 100, 2) for key, value in rise_dirt.items()}
        # 找到最大值对应的键
        max_key = max(rise_dirt, key=rise_dirt.get)
        # 找到最小值对应的键
        min_key = min(rise_dirt, key=rise_dirt.get)
        # 涨跌比因子 ---------------------------------------------------
        factors['rise_vs_fall'] = {
            'rise_vs_fall_ratio': rise / fall if fall > 0 else 0,  # 涨跌比
            'rise_gather_area': max_key,  # 找到最大值
            'rise_scattered_area': min_key,  # 找到最小值
            'percentages': percentages,  # 找到最小值
        }
        # 资金流向因子 --------------------------------------------------
        factors['capital_flow'] = {
            'buy': data['q_zrtj'],  # 买方资金净流入
            'sell': data['s_zrtj'],  # 卖方资金净流出
            'net': data['q_zrtj'] - data['s_zrtj']  # 资金净流入
        }
        # 市场情绪因子 --------------------------------------------------
        factors['sentiment'] = {
            'zt_ratio': data['ZT'] / total_stocks,  # 涨停占总比
            'zt_vs_dt_ratio': data['ZT'] / data['DT'],  # 涨停跌停比
            'sign': 1 if '较好' in data['sign'] else 0,  # 情绪标签量化
            'rise_vs_all_stocks_ratio': data['SZJS'] / total_stocks,  # 活跃股占比
            'rise_vs_fall_ratio': data['SZJS'] / data['SZJS'],  # 活跃股占比
            'extreme_ratio': (data['ZT'] + data['DT']) / total_stocks,  # 极端波动(涨停+跌停占总比)
        }
        return factors
#
# # ====================== 策略信号生成 ======================
def generate_signals(factors):
    """生成多维度交易信号"""
        signals = []
    # 信号1:趋势强度判断
    if factors['sentiment']['rise_vs_fall_ratio'] > 1.5:
        signals.append("多头强势:涨跌比高于阈值1.5")
    elif factors['sentiment']['rise_vs_fall_ratio'] < 0.67:
        signals.append("空头强势:涨跌比低于阈值0.67")
        # 信号1:基于涨跌比
        if bdr > self.bdr_threshold:
            signals.append("多头趋势增强 - 加仓指数ETF")
        elif bdr < 1 / self.bdr_threshold:
            signals.append("空头趋势增强 - 减仓或反向操作")
        else:
            signals.append("趋势中性 - 保持当前仓位")
    # 信号2:资金动能判断
    if factors['capital_flow']['net'] > 1e8:  # 假设1亿为阈值
        signals.append("资金大幅净流入:关注主力进场")
    elif factors['capital_flow']['net'] < -5e7:
        signals.append("资金大幅净流出:警惕风险")
        # 信号2:极端波动
        if extreme_ratio > self.extreme_threshold:
            signals.append("波动风险升高 - 启动对冲或降低杠杆")
        else:
            signals.append("波动正常 - 维持现有风险敞口")
    # 信号3:极端波动预警
    if factors['sentiment']['extreme_ratio'] > 0.1:
        signals.append("极端波动:涨停跌停股超10%")
        # 信号3:市场宽度与偏度
        if market_breadth > 0.2 and skewness > 0.5:
            signals.append("市场普涨且偏度正向 - 超配行业龙头股")
        elif market_breadth < -0.2 and skewness < -0.5:
            signals.append("市场普跌且偏度负向 - 低估值防御型配置")
        return signals
    # 信号4:市场情绪综合
    if factors['sentiment']['zt_ratio'] > 0.05 and factors['sentiment']['sign'] == 1:
        signals.append("高情绪热度:涨停股多且人气向好")
# 实例化策略并生成信号
strategy = NativeTradingStrategy()
signals = strategy.generate_signals(bdr, extreme_ratio, market_breadth, skewness)
    return signals if signals else ["无显著信号:维持当前策略"]
# 实时设置计划持仓数量 函数
@@ -792,11 +655,24 @@
    # print(f"指数K线{data_cache.all_index_k_line_property_dict}")
    # all_index_k_line_dict_write()
    # ====================== 结果输出 ======================
    print("========== 因子数值(原生计算) ==========")
    print(f"涨跌比(BDR): {bdr:.2f}")
    print(f"极端波动比例: {extreme_ratio:.2%}")
    print(f"市场宽度因子: {market_breadth:.2f}")
    print(f"分布偏度: {skewness:.2f}, 峰度: {kurtosis:.2f}")
    print(f"data=={data}")
    # 因子计算
    factors = calculate_factors(data)
    # 生成信号
    signals = generate_signals(factors)
    # 结果输出
    print("========== 市场关键指标 ==========")
    print(f"总股票数: {factors['total_stocks']}")
    print(f"涨跌比(BDR): {factors['rise_vs_fall']['rise_vs_fall_ratio']:.2f}")
    print(f"极端波动比例: {factors['sentiment']['extreme_ratio']:.2%}")
    print(f"资金净流入(元): {factors['capital_flow']['net']:,}")
    print(f"涨停股占比: {factors['sentiment']['zt_ratio']:.2%}")
    print(f"市场情绪量化: {'积极' if factors['sentiment']['sign'] else '谨慎'}")
    print(f"上涨聚集区域:{factors['rise_vs_fall']['rise_gather_area']}")
    print(f"上涨零散区域:{factors['rise_vs_fall']['percentages']}")
    print("\n========== 策略信号 ==========")
    for i, signal in enumerate(signals, 1):