Преглед изворни кода

新增移动平均线过滤器以优化网格对冲策略,避免在强下跌趋势中进行对冲入场。同时扩展了历史数据获取逻辑,确保MA计算所需数据的充足性,并更新了相关配置和日志输出。调整了基础头寸交易逻辑,确保在价格低于网格水平时主动开仓。

maxfeng пре 1 месец
родитељ
комит
e10c631fec
1 измењених фајлова са 325 додато и 74 уклоњено
  1. 325 74
      Lib/research/future_grid_trading_analysis.py

+ 325 - 74
Lib/research/future_grid_trading_analysis.py

@@ -9,12 +9,15 @@
 3. 基础头寸交易 - 价格-数量网格配置,支持合约切换时重新建仓
 4. 网格交易策略 - 限价订单网格买入卖出,合约切换时根据价格条件重新建仓
 5. 网格对冲策略 - 带止损的增强网格交易,合约切换时根据价格条件重新建仓
-6. 统计分析对比 - 四种交易场景性能分析
+6. 移动平均线过滤器 - 基于MA趋势过滤对冲入场,避免强下跌趋势中的对冲
+7. 统计分析对比 - 四种交易场景性能分析
 
 主要特点:
 - 主力合约自动监控:每日检测主力合约变化
 - 强制平仓机制:合约切换时立即平掉旧合约所有头寸
 - 智能重新建仓:根据价格条件在新合约中重新建立头寸
+- MA趋势过滤:检测强下跌趋势(30K<20K<10K<5K或30K<20K<5K<10K),阻止对冲入场
+- 智能数据扩展:当MA计算所需数据不足时,自动扩展历史数据范围并缓存
 - 标准期货盈亏计算:使用正确的合约倍数和期货盈亏公式
 - 最终持仓结算:分析期结束时对所有未平仓头寸进行市值计价
 - 完整交易记录:记录所有交易包括合约切换引起的强制平仓
@@ -66,14 +69,14 @@ class GridTradingConfig:
         
         # 化工
         'FG': 20, 'TA': 5, 'MA': 10, 'SA': 20, 'L': 5, 'V': 5, 'EG': 10,
-        'PP': 5, 'EB': 5, 'PG': 20,
+        'PP': 5, 'EB': 5, 'PG': 20, 'UR': 20,
         
         # 农产品
         'RM': 10, 'OI': 10, 'CF': 5, 'SR': 10, 'PF': 5, 'C': 10, 'CS': 10,
         'CY': 5, 'A': 10, 'B': 10, 'M': 10, 'Y': 10, 'P': 10,
         
         # 股指期货
-        'IF': 300, 'IH': 300, 'IC': 200, 'IM': 200,
+        'IF': 300, 'IH': 300, 'IC': 200, 'IM': 200, 'TL': 10000,
         
         # 其他
         'AP': 10, 'CJ': 5, 'PK': 5, 'JD': 10, 'LH': 16
@@ -81,12 +84,11 @@ class GridTradingConfig:
     
     # ==================== 核心商品配置 ====================
     CORE_COMMODITIES = {
-        'SA': ['SA2509.XZCE', 'SA2601.XZCE'],  # 纯碱
-        'M': ['M2507.XDCE', 'M2605.XDCE'],  # 豆粕
-        # 'MA': ['MA2501.XZCE', 'MA2505.XZCE'],  # 甲醇
-        # 'AU': ['AU2412.XSGE', 'AU2502.XSGE'],  # 黄金
-        # 'AG': ['AG2412.XSGE', 'AG2502.XSGE'],  # 白银
-        # 'RU': ['RU2501.XSGE', 'RU2505.XSGE'],  # 橡胶
+        # 'SA': ['SA2501.XZCE', 'SA2505.XZCE', 'SA2509.XZCE', 'SA2601.XZCE'],  # 纯碱
+        # 'M': ['M2501.XDCE', 'M2505.XDCE', 'M2509.XDCE', 'M2605.XDCE'],  # 豆粕
+        'UR': ['UR2501.XZCE', 'UR2505.XZCE', 'UR2509.XZCE', 'UR2601.XZCE'],  # 尿素
+        # 'LH': ['LH2501.XDCE', 'LH2505.XDCE', 'LH2509.XDCE', 'LH2601.XDCE'],  # 生猪
+        # 'TL': ['TL2503.CCFX', 'TL2506.CCFX', 'TL2509.CCFX', 'TL2512.CCFX']  # 30年期国债
     }
     
     # ==================== 合约切换配置 ====================
@@ -96,20 +98,18 @@ class GridTradingConfig:
     BASE_POSITION_GRID = {
         'SA': {1400: 4, 1300: 6, 1200: 8, 1100: 12, 1000: 14, 900: 16},
         'M': {2800: 4, 2750: 6, 2700: 8, 2650: 12, 2600: 14, 2550: 16},
-        # 'MA': {2500: 8, 2400: 8, 2300: 8, 2200: 8, 2100: 8, 2000: 8},
-        # 'AU': {520: 2, 510: 2, 500: 2, 490: 2, 480: 2, 470: 2},
-        # 'AG': {6500: 10, 6000: 10, 5500: 10, 5000: 10, 4500: 10, 4000: 10},
-        # 'RU': {18000: 5, 17000: 5, 16000: 5, 15000: 5, 14000: 5, 13000: 5}
+        'UR': {1750: 4, 1700: 6, 1650: 8, 1600: 12, 1550: 14, 1500: 16},
+        'LH': {13000: 1, 12500: 1, 12000: 1, 11500: 1, 11000: 2},
+        'TL': {118: 1, 117: 1, 116: 1, 115: 1, 114: 2, 113: 2},
     }
     
     # 统一退出价格(无止损)
     BASE_POSITION_EXIT_PRICE = {
         'SA': 1500,
         'M': 3800,
-        # 'MA': 2600,  
-        # 'AU': 530,
-        # 'AG': 7000,
-        # 'RU': 19000
+        'UR': 2400,
+        'LH': 20000,
+        'TL': 121,
     }
     
     # ==================== 网格交易配置 ====================
@@ -118,44 +118,44 @@ class GridTradingConfig:
             'start_price': 1250, # 开始价格
             'grid_size': 50, # 网格大小
             'quantity_per_grid': 5, # 每网格数量
-            'exit_grid_size': 50 # 退出网格大小
+            'exit_grid_size': 50, # 退出网格大小
+            'hedge_stop_price': 1100 # 对冲停止价格(低于此价格不触发对冲)
         },
         'M': {
             'start_price': 2800,
             'grid_size': 100,
             'quantity_per_grid': 10,
-            'exit_grid_size': 100
+            'exit_grid_size': 100,
+            'hedge_stop_price': 2400
+        },
+        'UR': {
+            'start_price': 1800,
+            'grid_size': 50,
+            'quantity_per_grid': 10,
+            'exit_grid_size': 50,
+            'hedge_stop_price': 1600
+        },
+        'LH': {
+            'start_price': 13500,
+            'grid_size': 500,
+            'quantity_per_grid': 1,
+            'exit_grid_size': 500,
+            'hedge_stop_price': 12000
+        },
+        'TL': {
+            'start_price': 118,
+            'grid_size': 1,
+            'quantity_per_grid': 1,
+            'exit_grid_size': 1,
+            'hedge_stop_price': 113  # 对冲停止价格(低于113不触发对冲)
         },
-        # 'MA': {
-        #     'start_price': 2300,
-        #     'grid_size': 50,
-        #     'quantity_per_grid': 4,
-        #     'exit_grid_size': 50
-        # },
-        # 'AU': {
-        #     'start_price': 480,
-        #     'grid_size': 10,
-        #     'quantity_per_grid': 1,
-        #     'exit_grid_size': 10
-        # },
-        # 'AG': {
-        #     'start_price': 5500,
-        #     'grid_size': 200,
-        #     'quantity_per_grid': 8,
-        #     'exit_grid_size': 200
-        # },
-        # 'RU': {
-        #     'start_price': 15000,
-        #     'grid_size': 500,
-        #     'quantity_per_grid': 3,
-        #     'exit_grid_size': 500
-        # }
     }
     
     # ==================== 网格对冲策略配置 ====================
     GRID_HEDGE_CONFIG = {
-        'stop_loss_percentage': 0.02,  # 2%止损百分比
-        'enable_hedge_strategy': True   # 是否启用网格对冲策略
+        'stop_loss_percentage': 0.01,  # 2%止损百分比
+        'enable_hedge_strategy': True,  # 是否启用网格对冲策略
+        'use_ma_filter': True           # 是否启用移动平均线过滤器(阻止特定趋势下的对冲入场)
     }
     
     # ==================== 输出设置 ====================
@@ -171,8 +171,14 @@ class GridTradingConfig:
         print("核心商品列表:")
         for commodity, contracts in cls.CORE_COMMODITIES.items():
             print(f"  {commodity}: {contracts}")
-        print(f"网格对冲策略: {'启用' if cls.GRID_HEDGE_CONFIG['enable_hedge_strategy'] else '禁用'}")
+        print(f"\n网格交易配置:")
+        for commodity, config in cls.GRID_TRADING_CONFIG.items():
+            hedge_stop = config.get('hedge_stop_price', '未设置')
+            print(f"  {commodity}: 起始价{config['start_price']}, 网格大小{config['grid_size']}, "
+                  f"对冲停止价{hedge_stop}")
+        print(f"\n网格对冲策略: {'启用' if cls.GRID_HEDGE_CONFIG['enable_hedge_strategy'] else '禁用'}")
         print(f"止损百分比: {cls.GRID_HEDGE_CONFIG['stop_loss_percentage']*100}%")
+        print(f"MA过滤器: {'启用' if cls.GRID_HEDGE_CONFIG.get('use_ma_filter', False) else '禁用'}")
         print(f"详细日志: {'开启' if cls.VERBOSE_LOGGING else '关闭'}")
         print("=" * 50)
 
@@ -211,6 +217,9 @@ class FutureGridTradingAnalyzer:
             'combined': []
         }
         
+        # MA过滤器扩展数据缓存(避免重复获取)
+        self.ma_extended_data_cache = {}
+        
         if self.verbose_logging:
             print("初始化期货网格交易分析器")
             print(f"核心商品: {list(self.core_commodities.keys())}")
@@ -448,6 +457,8 @@ class FutureGridTradingAnalyzer:
                     )
                     
                     if data is not None and len(data) > 0:
+                        # print(f"第一条有数据的日期是: {data.index[0].date()},数据是: {data.iloc[0]}")
+                        # print(f"最后一条有数据的日期是: {data.index[-1].date()}, 数据是: {data.iloc[-1]}")
                         self.price_data[commodity][contract] = data
 
                         # 检查这个数据里有多少条空值数据
@@ -569,10 +580,10 @@ class FutureGridTradingAnalyzer:
             if isinstance(contract_end, datetime.date):
                 contract_end = datetime.datetime.combine(contract_end, datetime.time.max)
             
-            # 添加缓冲期(前后各3天)以确保数据充足
-            buffer_days = 3
-            contract_start_buffered = contract_start - datetime.timedelta(days=buffer_days)
-            contract_end_buffered = contract_end + datetime.timedelta(days=buffer_days)
+            # 添加缓冲期以确保有足够的历史数据满足最低交易日要求
+            # 使用REQUIRED_TRADING_DAYS作为缓冲,保证数据充足性
+            contract_start_buffered = contract_start - datetime.timedelta(days=self.config.REQUIRED_TRADING_DAYS)
+            contract_end_buffered = contract_end # + datetime.timedelta(days=self.config.REQUIRED_TRADING_DAYS)
             
             # 确保不超出总体分析范围
             contract_start_final = max(contract_start_buffered, self.start_date)
@@ -755,6 +766,27 @@ class FutureGridTradingAnalyzer:
         """
         if self.verbose_logging:
             print("\n=== 步骤3: 带合约切换的交易模拟 ===")
+            
+            # 打印对冲配置信息
+            if self.grid_hedge_config['enable_hedge_strategy']:
+                print("\n网格对冲策略配置:")
+                for commodity, config in self.grid_trading_config.items():
+                    start_price = config['start_price']
+                    hedge_stop_price = config.get('hedge_stop_price', 0)
+                    grid_size = config['grid_size']
+                    exit_grid_size = config['exit_grid_size']
+                    
+                    # 计算对冲范围
+                    hedge_levels = []
+                    current_grid = start_price
+                    while current_grid >= hedge_stop_price and current_grid > 0:
+                        hedge_entry = current_grid + exit_grid_size
+                        hedge_levels.append(hedge_entry)
+                        current_grid -= grid_size
+                    
+                    print(f"  {commodity}: 对冲范围 {min(hedge_levels)}-{max(hedge_levels)} "
+                          f"(对应主网格 {hedge_stop_price}-{start_price}), "
+                          f"共{len(hedge_levels)}个对冲级别")
         
         # 按日期顺序处理所有交易日
         current_date = self.start_date.date()
@@ -1484,26 +1516,35 @@ class FutureGridTradingAnalyzer:
         return None
     
     def _check_base_position_trading(self, commodity, contract, current_date, daily_prices):
-        """检查基础头寸交易机会"""
+        """检查基础头寸交易机会
+        
+        逻辑:每日主动检查所有网格水平
+        - 如果当前收盘价低于某个网格水平价格
+        - 且该网格水平没有未平仓头寸
+        - 则以当日收盘价在该网格水平开仓
+        """
         if commodity not in self.base_position_grid:
             return
         
-        # 检查入场机会
+        # 检查入场机会 - 遍历所有网格水平
         price_grid = self.base_position_grid[commodity]
+        current_close_price = daily_prices['close']
+        
         for entry_price, quantity in price_grid.items():
-            # 检查是否已经有这个价格水平的头寸(包括重建的头寸)
+            # 检查是否已经有这个价格水平的头寸
             position_exists = False
             if commodity in self.active_positions['base_position']:
                 for position in self.active_positions['base_position'][commodity].values():
                     if (position['contract'] == contract and position['status'] == 'open'):
-                        # 检查原始价格水平或入场价格
+                        # 检查原始价格水平
                         position_price_level = position.get('original_price_level', position['entry_price'])
                         if position_price_level == entry_price:
                             position_exists = True
                             break
             
-            if not position_exists and daily_prices['low'] <= entry_price <= daily_prices['high']:
-                # 建立头寸
+            # 主动开仓逻辑:当前价格低于网格水平价格 且 该水平没有头寸
+            if not position_exists and current_close_price < entry_price:
+                # 以当日收盘价建立头寸
                 position_id = f"{commodity}_{contract}_{current_date}_base_{entry_price}"
                 if commodity not in self.active_positions['base_position']:
                     self.active_positions['base_position'][commodity] = {}
@@ -1511,17 +1552,15 @@ class FutureGridTradingAnalyzer:
                 self.active_positions['base_position'][commodity][position_id] = {
                     'contract': contract,
                     'entry_date': current_date.strftime('%Y-%m-%d'),
-                    'entry_price': entry_price,
-                    'original_price_level': entry_price,  # 记录原始格水平
+                    'entry_price': current_close_price,  # 使用收盘价作为入场价格
+                    'original_price_level': entry_price,  # 记录原始格水平
                     'quantity': quantity,
                     'status': 'open',
                     'exit_target': self.base_position_exit_price.get(commodity)
                 }
                 
                 if self.verbose_logging:
-                    print(f"  {current_date}: {commodity} 基础头寸入场 @ {entry_price}, 数量: {quantity},当天最低价格为{daily_prices['low']},最高价格为{daily_prices['high']}")
-                    # print(f"    创建头寸: {position_id}")
-                    # print(f"    当日价格范围: 最低 {daily_prices['low']}, 最高 {daily_prices['high']}")
+                    print(f"  {current_date}: {commodity} 基础头寸入场 @ 网格{entry_price} (实际价格: {current_close_price:.2f}), 数量: {quantity},当天收盘价{current_close_price:.2f}低于网格价格{entry_price}")
         
         # 检查退出机会
         exit_target = self.base_position_exit_price.get(commodity)
@@ -1644,8 +1683,201 @@ class FutureGridTradingAnalyzer:
                 if self.verbose_logging:
                     print(f"  {current_date}: {commodity} 网格退出 {position['entry_price']} -> {exit_price:.2f}, 盈亏: {profit_loss:.2f} ({profit_loss_pct:.2%})")
     
+    def _extend_price_data_for_ma(self, commodity, contract, current_date, required_days=30):
+        """扩展价格数据以满足MA计算需求
+        
+        参数:
+            commodity: 商品代码
+            contract: 合约代码
+            current_date: 当前日期
+            required_days: 所需的最少数据天数
+        
+        返回:
+            扩展后的价格数据DataFrame,如果获取失败则返回None
+        """
+        cache_key = f"{commodity}_{contract}"
+        
+        # 检查缓存
+        if cache_key in self.ma_extended_data_cache:
+            cached_data = self.ma_extended_data_cache[cache_key]
+            target_date = current_date if isinstance(current_date, datetime.date) else current_date.date()
+            historical_data = cached_data[cached_data.index.date <= target_date]
+            
+            if len(historical_data) >= required_days:
+                if self.verbose_logging:
+                    print(f"  ℹ️  MA过滤器:使用缓存的扩展数据,共{len(historical_data)}天")
+                return historical_data
+        
+        # 获取现有数据
+        if commodity not in self.price_data or contract not in self.price_data[commodity]:
+            return None
+        
+        existing_data = self.price_data[commodity][contract]
+        target_date = current_date if isinstance(current_date, datetime.date) else current_date.date()
+        existing_historical = existing_data[existing_data.index.date <= target_date]
+        
+        if len(existing_historical) >= required_days:
+            return existing_historical
+        
+        # 数据不足,需要扩展获取
+        existing_count = len(existing_historical)
+        shortage = required_days - existing_count
+        
+        if self.verbose_logging:
+            print(f"  📊 MA过滤器:数据不足,开始扩展获取(当前{existing_count}天,需要{required_days}天,缺少{shortage}天)")
+        
+        # 计算扩展的开始日期:从现有数据最早日期往前推至少30个交易日
+        if len(existing_data) > 0:
+            earliest_date = existing_data.index.min().date()
+        else:
+            earliest_date = target_date
+        
+        # 往前推60个自然日(约等于40-45个交易日,提供充足缓冲)
+        extended_start_date = earliest_date - datetime.timedelta(days=60)
+        extended_end_date = target_date
+        
+        if self.verbose_logging:
+            print(f"  📊 扩展日期范围: {extended_start_date} 至 {extended_end_date}")
+        
+        try:
+            # 获取扩展的价格数据
+            extended_data = get_price(
+                contract,
+                start_date=extended_start_date,
+                end_date=extended_end_date,
+                frequency='daily',
+                fields=['open', 'close', 'high', 'low', 'volume'],
+                skip_paused=False,
+                panel=False
+            )
+            
+            if extended_data is None or len(extended_data) == 0:
+                if self.verbose_logging:
+                    print(f"  ⚠️  扩展数据获取失败:未获取到数据")
+                return existing_historical
+            
+            # 合并数据:将扩展数据与现有数据合并,保留所有日期的数据
+            # 使用concat合并,然后去重并按日期排序
+            combined_data = pd.concat([existing_data, extended_data])
+            combined_data = combined_data[~combined_data.index.duplicated(keep='first')]
+            combined_data = combined_data.sort_index()
+            
+            # 过滤到当前日期(仅用于返回给MA计算)
+            combined_historical = combined_data[combined_data.index.date <= target_date]
+            
+            if self.verbose_logging:
+                print(f"  ✅ 扩展数据获取成功:从{len(existing_historical)}天扩展到{len(combined_historical)}天")
+                print(f"     合并后完整数据范围:{combined_data.index.min().date()} 至 {combined_data.index.max().date()}(共{len(combined_data)}天)")
+            
+            # 缓存扩展后的完整数据
+            self.ma_extended_data_cache[cache_key] = combined_data
+            
+            # 更新主price_data,保留原有数据和新扩展的数据
+            self.price_data[commodity][contract] = combined_data
+            
+            return combined_historical
+            
+        except Exception as e:
+            if self.verbose_logging:
+                print(f"  ⚠️  扩展数据获取异常:{str(e)}")
+            return existing_historical
+    
+    def _should_block_hedge_by_ma_filter(self, commodity, contract, current_date):
+        """检查是否应该通过移动平均线过滤器阻止对冲入场
+        
+        返回值:
+            True: 应该阻止对冲入场(满足以下趋势之一)
+            False: 允许对冲入场
+        
+        阻止条件(强下跌趋势):
+            1. 30K < 20K < 10K < 5K(所有均线呈下降顺序)
+            2. 30K < 20K < 5K < 10K(5K与10K交叉的下跌趋势)
+        """
+        try:
+            # 获取价格数据
+            if commodity not in self.price_data or contract not in self.price_data[commodity]:
+                if self.verbose_logging:
+                    print(f"  ⚠️  MA过滤器:无法获取 {commodity} {contract} 的价格数据")
+                return False  # 没有数据时不阻止
+            
+            price_data = self.price_data[commodity][contract]
+            
+            # 获取当前日期及之前的数据(确保有足够的历史数据来计算30日均线)
+            target_date = current_date if isinstance(current_date, datetime.date) else current_date.date()
+            
+            # 过滤出当前日期及之前的数据
+            historical_data = price_data[price_data.index.date <= target_date]
+            
+            # 如果数据不足,尝试扩展获取
+            if len(historical_data) < 30:
+                if self.verbose_logging:
+                    print(f"  ⚠️  MA过滤器:{commodity} {contract} 历史数据不足(需要30天,实际{len(historical_data)}天)")
+                
+                # 尝试扩展数据获取
+                extended_data = self._extend_price_data_for_ma(commodity, contract, current_date, required_days=30)
+                
+                if extended_data is not None and len(extended_data) >= 30:
+                    historical_data = extended_data
+                    if self.verbose_logging:
+                        print(f"  ✅ 扩展数据成功,现在有{len(historical_data)}天数据,继续MA过滤器检查")
+                else:
+                    if self.verbose_logging:
+                        print(f"  ⚠️  扩展数据失败,数据仍不足,阻止对冲入场")
+                    return True  # 扩展失败,数据仍不足时阻止
+            
+            # 使用收盘价计算移动平均线
+            close_prices = historical_data['close']
+            
+            # 计算最近的移动平均线值
+            ma5 = close_prices.iloc[-5:].mean()
+            ma10 = close_prices.iloc[-10:].mean()
+            ma20 = close_prices.iloc[-20:].mean()
+            ma30 = close_prices.iloc[-30:].mean()
+            
+            # 检查是否为NaN
+            if pd.isna(ma5) or pd.isna(ma10) or pd.isna(ma20) or pd.isna(ma30):
+                if self.verbose_logging:
+                    print(f"  ⚠️  MA过滤器:{commodity} {contract} 移动平均线计算结果包含NaN")
+                return True  # 计算失败时阻止
+            
+            # 检查阻止条件
+            # 条件1:30K < 20K < 10K < 5K(所有均线呈下降顺序的强上涨趋势)
+            condition1 = (ma30 < ma20) and (ma20 < ma10) and (ma10 < ma5)
+            
+            # 条件2:30K < 20K < 5K < 10K(5K与10K交叉的上涨趋势)
+            condition2 = (ma30 < ma20) and (ma20 < ma5) and (ma5 < ma10)
+            
+            should_block = condition1 or condition2
+            
+            if self.verbose_logging and should_block:
+                print(f"  🚫 MA过滤器触发:{commodity} {contract} 检测到强上涨趋势,阻止对冲入场")
+                print(f"     MA5={ma5:.2f}, MA10={ma10:.2f}, MA20={ma20:.2f}, MA30={ma30:.2f}")
+                if condition1:
+                    print(f"     触发条件1: 30K < 20K < 10K < 5K")
+                if condition2:
+                    print(f"     触发条件2: 30K < 20K < 5K < 10K")
+            
+            return should_block
+            
+        except Exception as e:
+            if self.verbose_logging:
+                print(f"  ⚠️  MA过滤器异常:{commodity} {contract} - {str(e)}")
+            return True  # 异常时阻止
+    
     def _check_grid_hedge_trading(self, commodity, contract, current_date, daily_prices):
-        """检查网格对冲交易机会"""
+        """检查网格对冲交易机会
+        
+        逻辑:独立的对冲网格系统,不依赖主网格交易执行
+        - 基于主网格结构创建独立的对冲网格
+        - 对冲网格水平 = 主网格水平 + exit_grid_size
+        - 当价格突破网格水平时(如118→119),立即触发对冲空头头寸
+        - 对冲范围受 hedge_stop_price 限制,低于该价格不触发对冲
+        
+        示例:start_price=118, hedge_stop_price=113, exit_grid_size=1
+        - 主网格水平:118, 117, 116, 115, 114, 113, 112, ...
+        - 对冲触发价格:119, 118, 117, 116, 115, 114(对应主网格113-118)
+        - 低于113的主网格不触发对冲
+        """
         if not self.grid_hedge_config['enable_hedge_strategy'] or commodity not in self.grid_trading_config:
             return
         
@@ -1653,40 +1885,59 @@ class FutureGridTradingAnalyzer:
         start_price = config['start_price']
         grid_size = config['grid_size']
         quantity_per_grid = config['quantity_per_grid']
+        exit_grid_size = config['exit_grid_size']
+        hedge_stop_price = config.get('hedge_stop_price', 0)  # 对冲停止价格,默认为0(不限制)
         stop_loss_pct = self.grid_hedge_config['stop_loss_percentage']
         
-        # 检查入场机会(对冲是在start_price之上)
-        current_level = start_price + grid_size
-        while current_level < daily_prices['high']:
+        # 检查入场机会(独立对冲网格系统)
+        # 从start_price开始,向下遍历所有可能的网格级别
+        # 只有在 hedge_stop_price 及以上的网格级别才会触发对冲
+        current_grid_level = start_price
+        while current_grid_level >= hedge_stop_price and current_grid_level > 0:
+            # 计算该网格级别对应的对冲开仓价格(独立触发,不依赖主网格交易)
+            hedge_entry_level = current_grid_level + exit_grid_size
+            
+            # 检查是否已经有这个对冲级别的头寸
             position_exists = False
             if commodity in self.active_positions['grid_hedge']:
                 for position in self.active_positions['grid_hedge'][commodity].values():
                     if (position['contract'] == contract and 
-                        position.get('original_grid_level', position['entry_price']) == current_level and 
+                        position.get('original_grid_level', position['entry_price']) == hedge_entry_level and 
                         position['status'] == 'open'):
                         position_exists = True
                         break
             
-            if not position_exists and daily_prices['low'] <= current_level <= daily_prices['high']:
-                position_id = f"{commodity}_{contract}_{current_date}_hedge_{current_level}"
+            # 当价格触及对冲级别时独立开仓(不需要等待主网格交易)
+            if not position_exists and daily_prices['low'] <= hedge_entry_level <= daily_prices['high']:
+                # 检查MA过滤器:如果启用且检测到强上涨趋势,则阻止对冲入场
+                if self.grid_hedge_config.get('use_ma_filter', False):
+                    if self._should_block_hedge_by_ma_filter(commodity, contract, current_date):
+                        if self.verbose_logging:
+                            print(f"  {current_date}: {commodity} 对冲入场被MA过滤器阻止 @ {hedge_entry_level}")
+                        # 跳过此次对冲入场
+                        current_grid_level -= grid_size
+                        continue
+                
+                position_id = f"{commodity}_{contract}_{current_date}_hedge_{hedge_entry_level}"
                 if commodity not in self.active_positions['grid_hedge']:
                     self.active_positions['grid_hedge'][commodity] = {}
                 
                 self.active_positions['grid_hedge'][commodity][position_id] = {
                     'contract': contract,
                     'entry_date': current_date.strftime('%Y-%m-%d'),
-                    'entry_price': current_level,
-                    'original_grid_level': current_level,
+                    'entry_price': hedge_entry_level,
+                    'original_grid_level': hedge_entry_level,
+                    'base_grid_level': current_grid_level,  # 记录对应的基础网格级别
                     'quantity': quantity_per_grid,
                     'status': 'open',
-                    'profit_target': current_level - grid_size,
-                    'stop_loss': current_level * (1 + stop_loss_pct)
+                    'profit_target': hedge_entry_level - grid_size,  # 对冲平仓目标:回到原网格级别
+                    'stop_loss': hedge_entry_level * (1 + stop_loss_pct)
                 }
                 
                 if self.verbose_logging:
-                    print(f"  {current_date}: {commodity} 对冲入场 @ {current_level},数量:{quantity_per_grid},当天最低价为{daily_prices['low']},最高价为{daily_prices['high']}")
+                    print(f"  {current_date}: {commodity} 对冲入场 @ {hedge_entry_level}(对应网格级别{current_grid_level}),数量:{quantity_per_grid},目标:{hedge_entry_level - grid_size},当天价格区间[{daily_prices['low']}, {daily_prices['high']}]")
             
-            current_level += grid_size
+            current_grid_level -= grid_size
         
         # 检查退出机会
         if commodity in self.active_positions['grid_hedge']: