Browse Source

Refine monitoring emergency mitigation

helium3@sina.com 8 hours ago
parent
commit
ff57bfb10f

+ 27 - 335
README.md

@@ -1,357 +1,49 @@
-# Pacifica 后台交易系统
+# Pacifica 双账户 Delta 中性策略
 
-一个纯后台运行的 Pacifica 多账户 BTC 对冲刷量交易系统,通过配置文件控制所有功能,无需 API 交互。
+本项目实现了一个面向 Pacifica 交易所的双账户 Delta 中性刷量策略。核心组件包括:
 
-## 🚀 特性
+- **AccountManager**:管理两个账户的余额/仓位,并计算共享的可用资金与利用率。
+- **SimpleStrategyEngine**:根据账户利用率分层(<60% 建仓、60–80% 仅平衡、≥80% 只减仓)生成中性化的刷量信号。
+- **ExposureRiskMonitor**:统一负责敞口再平衡,串行拆单并尊重利用率分层。
+- **SignalExecutor**:执行订单、处理拆单锁与限额绕过。
 
-- **纯后台运行**: 无 API 交互,完全通过配置文件控制
-- **多账户管理**: 支持多个交易账户的协调管理
-- **自动任务调度**: 基于 cron 表达式的自动任务执行
-- **实时监控**: 系统状态、性能指标和告警监控
-- **风险控制**: 多层次风险管理和自动停止机制
-- **配置驱动**: 所有功能通过 JSON 配置文件控制
-- **守护进程**: 系统级守护进程,支持优雅关闭和自动重启
-
-## 📋 系统架构
-
-```
-┌─────────────────────────────────────────────────────────────┐
-│                    Pacifica 后台交易系统                      │
-├─────────────────────────────────────────────────────────────┤
-│  ┌─────────────┐  ┌─────────────┐  ┌─────────────┐         │
-│  │   守护进程   │  │  后台系统   │  │  任务调度器  │         │
-│  │   Daemon    │  │ BackendSystem│  │TaskScheduler│         │
-│  └─────────────┘  └─────────────┘  └─────────────┘         │
-│                                                             │
-│  ┌─────────────┐  ┌─────────────┐  ┌─────────────┐         │
-│  │  监控系统   │  │  配置管理   │  │  账户管理   │         │
-│  │ Monitoring  │  │   Config    │  │   Account   │         │
-│  └─────────────┘  └─────────────┘  └─────────────┘         │
-│                                                             │
-│  ┌─────────────┐  ┌─────────────┐  ┌─────────────┐         │
-│  │  订单协调   │  │  风险管理   │  │  审计日志   │         │
-│  │   Order     │  │    Risk     │  │    Audit    │         │
-│  └─────────────┘  └─────────────┘  └─────────────┘         │
-└─────────────────────────────────────────────────────────────┘
-```
-
-## 🛠️ 安装和配置
-
-### 1. 环境要求
-
-- Node.js 18.0.0 或更高版本
-- TypeScript 5.0.0 或更高版本
-- 足够的系统资源(建议 2GB+ RAM)
-
-### 2. 安装依赖
+## 安装
 
 ```bash
 npm install
-```
-
-### 3. 配置文件设置
-
-#### 系统配置文件 (`config/system-config.json`)
-
-```json
-{
-  "system": {
-    "name": "Pacifica Wash Trading System",
-    "version": "1.0.0",
-    "environment": "development",
-    "logLevel": "info",
-    "maxConcurrentSessions": 5,
-    "sessionTimeout": 3600000,
-    "healthCheckInterval": 30000
-  },
-  "trading": {
-    "defaultSymbol": "BTC-PERP",
-    "maxOrderSize": 1.0,
-    "minOrderSize": 0.001,
-    "maxSlippage": 0.01,
-    "orderTimeout": 30000,
-    "retryAttempts": 3
-  },
-  "risk": {
-    "maxTotalVolume": 100.0,
-    "maxNetExposure": 0.1,
-    "maxDailyLoss": 1000.0,
-    "positionLimit": 10.0,
-    "stopLossThreshold": 0.05
-  },
-  "automation": {
-    "enabled": true,
-    "autoStartSessions": true,
-    "autoStopOnRisk": true,
-    "scheduleConfig": "0 */6 * * *",
-    "maxRunningSessions": 3
-  }
-}
-```
-
-#### 自动会话配置 (`config/auto-sessions.json`)
-
-```json
-{
-  "autoSessions": [
-    {
-      "id": "auto-session-1",
-      "name": "BTC 等量交易会话",
-      "enabled": true,
-      "strategy": {
-        "type": "EQUAL_VOLUME",
-        "symbol": "BTC-PERP",
-        "parameters": {
-          "volumePerOrder": 0.01,
-          "priceSpread": 0.0001,
-          "interval": 5000
-        }
-      },
-      "accounts": ["account-1", "account-2"],
-      "targetVolume": 1.0,
-      "duration": 3600000,
-      "schedule": {
-        "enabled": true,
-        "cron": "0 9 * * *",
-        "timezone": "Asia/Shanghai"
-      }
-    }
-  ]
-}
-```
-
-#### 账户配置 (`config/accounts.json`)
-
-```json
-[
-  {
-    "id": "account-1",
-    "name": "主账户",
-    "apiKey": "encrypted_api_key",
-    "privateKey": "encrypted_private_key",
-    "address": "0x...",
-    "balance": {
-      "total": 10000,
-      "available": 10000,
-      "used": 0
-    },
-    "riskLimits": {
-      "maxPosition": 1.0,
-      "dailyVolume": 100.0,
-      "maxLoss": 500.0
-    },
-    "isActive": true
-  }
-]
-```
-
-## 🚀 运行系统
-
-### 开发模式
-
-```bash
-npm run dev
-```
-
-### 生产模式
-
-```bash
-# 构建项目
 npm run build
-
-# 启动守护进程
-npm start
-```
-
-### 后台运行
-
-```bash
-# 使用 nohup 后台运行
-nohup npm start > logs/daemon.log 2>&1 &
-
-# 或使用 PM2
-pm2 start dist/daemon.js --name pacifica-daemon
-```
-
-## 📊 系统管理
-
-### 查看状态
-
-```bash
-# 查看进程状态
-npm run status
-
-# 查看日志
-tail -f logs/daemon.log
-```
-
-### 停止系统
-
-```bash
-# 优雅停止
-npm run stop
-
-# 或发送信号
-kill -TERM <pid>
-```
-
-### 重启系统
-
-```bash
-npm run restart
 ```
 
-## 🔧 配置管理
-
-### 重新加载配置
-
-```bash
-# 发送 SIGHUP 信号重新加载配置
-kill -HUP <pid>
-```
+## 必需配置
 
-### 生成状态报告
+所有配置位于 `config/`:
 
-```bash
-# 发送 SIGUSR1 信号生成状态报告
-kill -USR1 <pid>
-```
+- `accounts.json`:账户私钥等敏感信息。
+- `trading-strategy.json`:当前仅需设置 `symbol`。
+- `execution.json`:下单参数(最小/最大单笔价值、订单间隔等)。
+- `monitoring.json`:利用率阈值(例如 `build=0.6`, `reduce=0.8`)。
+- `delta-strategy-config.json`:生命周期、定价、敞口与阶段管理参数。
 
-### 重启服务
+## 运行
 
+开发模式:
 ```bash
-# 发送 SIGUSR2 信号重启服务
-kill -USR2 <pid>
+yarn trade
 ```
 
-## 📈 监控和日志
-
-### 日志文件
-
-- `logs/daemon.log` - 守护进程日志
-- `logs/system.log` - 系统日志
-- `logs/monitoring-report-*.json` - 监控报告
-- `logs/status-report-*.json` - 状态报告
-
-### 监控指标
-
-- 系统资源使用率(内存、CPU)
-- 交易会话状态和性能
-- 任务执行统计
-- 错误率和告警
-
-### 告警规则
-
-- 内存使用率 > 80%
-- 错误率 > 10
-- 会话成功率 < 70%
-
-## 🛡️ 风险管理
-
-### 自动风险控制
-
-- 最大并发会话数限制
-- 单账户风险限制
-- 全局风险限制
-- 自动停止机制
-
-### 风险指标
-
-- 总交易量限制
-- 净敞口限制
-- 最大损失限制
-- 持仓限制
-
-## 🔄 任务调度
-
-### 支持的任务类型
-
-- **自动会话**: 按计划启动交易会话
-- **健康检查**: 定期检查系统健康状态
-- **清理任务**: 清理过期数据和日志
-- **监控任务**: 实时监控系统状态
+生产环境推荐使用 PM2,并参考 `ecosystem.config.js`。
 
-### Cron 表达式示例
-
-```bash
-# 每天上午9点启动
-0 9 * * *
-
-# 每6小时启动一次
-0 */6 * * *
-
-# 每分钟检查一次
-*/1 * * * *
-```
-
-## 📁 项目结构
+## 目录结构
 
 ```
-pacifica-wash-trading-system/
-├── src/
-│   ├── core/                 # 核心系统
-│   │   ├── BackendSystem.ts  # 后台系统
-│   │   ├── ConfigManager.ts  # 配置管理
-│   │   ├── TaskScheduler.ts  # 任务调度
-│   │   └── MonitoringSystem.ts # 监控系统
-│   ├── services/             # 服务层
-│   ├── models/               # 数据模型
-│   ├── strategies/           # 交易策略
-│   ├── utils/                # 工具类
-│   └── daemon.ts             # 守护进程入口
-├── config/                   # 配置文件
-├── logs/                     # 日志文件
-├── tests/                    # 测试文件
-└── package.json
-```
-
-## 🔒 安全考虑
-
-- 敏感数据加密存储
-- 配置文件权限控制
-- 进程隔离运行
-- 日志脱敏处理
-
-## 🐛 故障排除
-
-### 常见问题
-
-1. **进程无法启动**
-   - 检查端口占用
-   - 验证配置文件格式
-   - 查看错误日志
-
-2. **任务不执行**
-   - 检查 cron 表达式
-   - 验证账户配置
-   - 查看任务日志
-
-3. **内存使用过高**
-   - 调整并发会话数
-   - 检查内存泄漏
-   - 优化配置参数
-
-### 调试模式
-
-```bash
-# 启用调试日志
-export LOG_LEVEL=debug
-npm run dev
+config/                 # 配置文件
+specs/                  # 变更记录与任务说明
+src/
+  modules/              # AccountManager、MonitoringManager 等协调模块
+  services/             # SignalExecutor、ExposureRiskMonitor、PricingEngine 等服务
+  strategies/           # SimpleStrategyEngine、ModularDeltaNeutralStrategy
 ```
 
-## 📞 支持
-
-如有问题或建议,请:
-
-1. 查看日志文件
-2. 检查配置文件
-3. 提交 Issue
-4. 联系技术支持
-
-## 📄 许可证
-
-MIT License - 详见 [LICENSE](LICENSE) 文件
-
----
+## 贡献
 
-**注意**: 本系统仅用于学习和研究目的,请遵守相关法律法规和交易所规则
+欢迎提交 Issue 或 PR,用于进一步优化资金分层策略、拆单效率或配置校验流程。

+ 0 - 178
config/README.md

@@ -1,178 +0,0 @@
-# 配置文件说明
-
-## 📋 核心配置文件
-
-### 1. `accounts.json` - 账户配置
-```json
-[
-  {
-    "id": "account-1",
-    "name": "主账户",
-    "privateKey": "YOUR_PRIVATE_KEY_HERE",
-    "address": "YOUR_WALLET_ADDRESS_HERE",
-    "isActive": true
-  }
-]
-```
-
-**字段说明:**
-- `id`: 账户唯一标识
-- `name`: 账户名称
-- `privateKey`: 钱包私钥(用于签名交易)
-- `address`: 钱包地址
-- `isActive`: 是否启用该账户
-
-### 2. `system-config.json` - 系统配置
-```json
-{
-  "system": {
-    "name": "PacificaWashTradingSystem",
-    "version": "1.0.0",
-    "environment": "development",
-    "logLevel": "info",
-    "timezone": "Asia/Shanghai"
-  },
-  "defaults": {
-    "symbol": "BTC-PERP",
-    "maxSessions": 2
-  }
-}
-```
-
-**字段说明:**
-- `system.name`: 系统名称
-- `system.version`: 系统版本
-- `system.environment`: 运行环境
-- `system.logLevel`: 日志级别
-- `system.timezone`: 时区设置
-- `defaults.symbol`: 默认交易对
-- `defaults.maxSessions`: 最大并发会话数
-
-### 3. `strategies.json` - 策略配置
-```json
-[
-  {
-    "id": "delta-neutral-strategy",
-    "name": "Delta中性敞口持仓策略",
-    "enabled": true,
-    "type": "DELTA_NEUTRAL",
-    "symbol": "BTC-PERP",
-    "accounts": ["account-1", "account-2"],
-    "parameters": {
-      "targetDeltaRatio": 0.6,
-      "hedgeRatio": 0.4,
-      "hedgeInterval": 3000
-    },
-    "triggers": [
-      {
-        "type": "frequency",
-        "interval": 30000,
-        "enabled": true
-      }
-    ]
-  }
-]
-```
-
-**字段说明:**
-- `id`: 策略唯一标识
-- `name`: 策略名称
-- `enabled`: 是否启用
-- `type`: 策略类型
-- `symbol`: 交易对符号
-- `accounts`: 参与的账户ID列表
-- `parameters`: 策略参数
-- `triggers`: 触发器配置
-
-## 🚀 快速开始
-
-### 1. 配置账户
-编辑 `accounts.json`,填入您的钱包信息:
-```json
-[
-  {
-    "id": "account-1",
-    "name": "主账户",
-    "privateKey": "0x你的私钥",
-    "address": "0x你的地址",
-    "isActive": true
-  }
-]
-```
-
-### 2. 配置系统
-编辑 `system-config.json`,设置系统参数:
-```json
-{
-  "system": {
-    "name": "PacificaWashTradingSystem",
-    "version": "1.0.0",
-    "environment": "development",
-    "logLevel": "info",
-    "timezone": "Asia/Shanghai"
-  },
-  "defaults": {
-    "symbol": "BTC-PERP",
-    "maxSessions": 2
-  }
-}
-```
-
-### 3. 配置策略
-编辑 `strategies.json`,设置交易策略:
-```json
-[
-  {
-    "id": "delta-neutral-strategy",
-    "name": "Delta中性敞口持仓策略",
-    "enabled": true,
-    "type": "DELTA_NEUTRAL",
-    "symbol": "BTC-PERP",
-    "accounts": ["account-1", "account-2"],
-    "parameters": {
-      "targetDeltaRatio": 0.6,
-      "hedgeRatio": 0.4,
-      "hedgeInterval": 3000
-    },
-    "triggers": [
-      {
-        "type": "frequency",
-        "interval": 30000,
-        "enabled": true
-      }
-    ]
-  }
-]
-```
-
-## ⚠️ 安全注意事项
-
-1. **私钥安全**: 私钥信息敏感,请妥善保管
-2. **文件权限**: 确保配置文件只有您有读写权限
-3. **备份**: 定期备份配置文件
-4. **测试**: 先在测试环境验证配置
-
-## 📅 Cron 表达式示例
-
-```bash
-# 每天上午9点执行
-0 9 * * *
-
-# 每6小时执行一次
-0 */6 * * *
-
-# 每分钟执行一次
-*/1 * * * *
-
-# 每周一上午9点执行
-0 9 * * 1
-```
-
-## 🔧 配置验证
-
-系统启动时会自动验证配置文件:
-- 检查必要字段是否存在
-- 验证数据格式是否正确
-- 检查账户配置是否有效
-
-如有配置错误,系统会记录错误日志并停止启动。

+ 0 - 35
config/auto-sessions.json

@@ -1,35 +0,0 @@
-{
-  "autoSessions": [
-    {
-      "id": "auto-session-1",
-      "name": "BTC 等量交易会话",
-      "enabled": true,
-      "strategy": {
-        "type": "EQUAL_VOLUME",
-        "symbol": "BTC-PERP",
-        "parameters": {
-          "volumePerOrder": 0.01,
-          "priceSpread": 0.0001,
-          "interval": 5000
-        }
-      },
-      "accounts": [
-        "account-1",
-        "account-2"
-      ],
-      "targetVolume": 1,
-      "duration": 3600000,
-      "schedule": {
-        "enabled": true,
-        "cron": "0 9 * * *",
-        "timezone": "Asia/Shanghai"
-      }
-    }
-  ],
-  "globalSettings": {
-    "maxConcurrentAutoSessions": 2,
-    "autoStartDelay": 5000,
-    "healthCheckBeforeStart": true,
-    "stopOnSystemShutdown": true
-  }
-}

+ 38 - 154
config/delta-strategy-config.json

@@ -1,198 +1,82 @@
 {
-  "description": "Delta中性刷量策略完整配置 - Sprint 1",
-  "version": "1.0.0",
-  "orderLifecycle": {
-    "_comment": "订单生命周期管理配置",
-    "enabled": true,
-    "maxOrderAge": 30000,
-    "_maxOrderAge注释": "订单最大存活时间(ms),默认30秒",
-    "lifecycleCheckInterval": 5000,
-    "_lifecycleCheckInterval注释": "检查间隔(ms),默认5秒",
-    "cancelRetryAttempts": 3,
-    "_cancelRetryAttempts注释": "取消重试次数,默认3次",
-    "cancelRetryDelay": 1000,
-    "_cancelRetryDelay注释": "重试延迟(ms),默认1秒"
-  },
-  "pricing": {
-    "_comment": "定价引擎配置 - 穿越价差快速成交策略(激进模式,更接近盘口)",
-    "priceBuffer": 1e-05,
-    "_priceBuffer注释": "价格缓冲,0.00001 (0.001%) - 非常接近盘口",
-    "dynamicPriceBuffer": true,
-    "_dynamicPriceBuffer注释": "是否启用动态缓冲,根据价差自动调整",
-    "minBuffer": 5e-06,
-    "_minBuffer注释": "最小缓冲,0.000005 (0.0005%) - 极小缓冲",
-    "maxBuffer": 5e-05,
-    "_maxBuffer注释": "最大缓冲,0.00005 (0.005%) - 降低最大值",
-    "bufferMultiplier": 0.5,
-    "_bufferMultiplier注释": "缓冲调整系数,0.5 - 减半以更接近盘口"
+  "strategy": {
+    "tradingInterval": 10000,
+    "symbols": ["BTC"],
+    "enabled": true
   },
   "orderbook": {
-    "_comment": "Orderbook数据管理配置",
     "wsUrl": "wss://ws.pacifica.fi/ws",
-    "_wsUrl注释": "WebSocket URL",
-    "symbols": [
-      "BTC"
-    ],
-    "_symbols注释": "订阅的交易对列表",
+    "symbols": ["BTC"],
     "reconnectDelay": 5000,
-    "_reconnectDelay注释": "重连延迟(ms),默认5秒",
     "heartbeatInterval": 30000,
-    "_heartbeatInterval注释": "心跳间隔(ms),默认30秒",
-    "maxDataAge": 10000,
-    "_maxDataAge注释": "最大数据年龄(ms),默认10秒,超过视为过期"
-  },
-  "strategy": {
-    "_comment": "策略基础配置",
-    "enabled": true,
-    "tradingInterval": 15000,
-    "_tradingInterval注释": "交易间隔(ms),15秒避免rate limit",
-    "symbols": [
-      "BTC"
-    ],
-    "_symbols注释": "交易的交易对"
-  },
-  "orderExecution": {
-    "_comment": "订单执行配置",
-    "preferredOrderType": "limit",
-    "_preferredOrderType注释": "优先订单类型: limit=限价单, market=市价单",
-    "orderTimeout": 30,
-    "_orderTimeout注释": "订单超时时间(秒),与orderLifecycle.maxOrderAge保持一致",
-    "minOrderValue": 10,
-    "_minOrderValue注释": "最小订单价值(USDC),Pacifica要求至少$10",
-    "maxOrderValue": 20,
-    "_maxOrderValue注释": "最大订单价值(USDC),限制单笔风险暴露",
-    "maxOrderValueRatio": 0.15,
-    "_maxOrderValueRatio注释": "最大订单占账户权益比例 (0.15=15%)",
-    "allowBypassMaxOrderValue": true
+    "maxDataAge": 10000
   },
-  "positions": {
-    "_comment": "仓位管理配置",
-    "basePositionRatio": 0.2,
-    "_basePositionRatio注释": "基础仓位比例 (0.2=20%)",
-    "volumePositionRatio": 0.8,
-    "_volumePositionRatio注释": "刷量仓位比例 (0.8=80%)",
-    "balanceUsageRatio": 0.2,
-    "_balanceUsageRatio注释": "账户余额使用比例 (0.2=20%,建议不超过30%)",
-    "maxPositionSize": 1000,
-    "_maxPositionSize注释": "最大仓位大小(USDC)"
-  },
-  "delta": {
-    "_comment": "Delta控制配置 - EnhancedDeltaController(已优化为更严格)",
-    "maxDeltaDeviation": 0.001,
-    "_maxDeltaDeviation注释": "最大Delta偏差 (0.001=0.1%, 更严格)",
-    "rebalanceThreshold": 0.01,
-    "_rebalanceThreshold注释": "再平衡阈值 (0.01=1%, 从5%降到1%)",
-    "baseDeltaTolerance": 0.001,
-    "_baseDeltaTolerance注释": "基础容忍度 (0.001=0.1%, 从0.5%降到0.1%)",
-    "stableDeltaTolerance": 0.001,
-    "_stableDeltaTolerance注释": "平稳市场容忍度 (0.001=0.1%)",
-    "volatileDeltaTolerance": 0.02,
-    "_volatileDeltaTolerance注释": "波动市场容忍度 (0.02=2%)"
+  "pricing": {
+    "priceBuffer": 0.00001,
+    "dynamicPriceBuffer": true,
+    "minBuffer": 0.000005,
+    "maxBuffer": 0.00005,
+    "bufferMultiplier": 0.5
   },
-  "risk": {
-    "_comment": "风险控制配置",
-    "maxDrawdown": 0.01,
-    "_maxDrawdown注释": "最大回撤 (0.01=1%)",
-    "stopLossThreshold": 0.005,
-    "_stopLossThreshold注释": "止损阈值 (0.005=0.5%)",
-    "maxSpreadThreshold": 0.002,
-    "_maxSpreadThreshold注释": "最大价差阈值 (0.002=0.2%),超过则不交易"
+  "orderLifecycle": {
+    "enabled": true,
+    "maxOrderAge": 30000,
+    "lifecycleCheckInterval": 5000,
+    "cancelRetryAttempts": 3,
+    "cancelRetryDelay": 1000
   },
   "dynamicTPSL": {
-    "_comment": "动态止盈止损配置 - 基于参考价格动态调整",
     "enabled": true,
-    "_enabled注释": "是否启用动态止盈止损",
     "updateInterval": 20000,
-    "_updateInterval注释": "更新间隔(ms),由12秒放宽至20秒,减少频繁改价",
+    "minExposure": 10,
     "takeProfit": {
       "enabled": true,
-      "_enabled注释": "是否启用止盈",
-      "percent": 0.004,
-      "_percent注释": "止盈百分比 (0.004=0.4%),基于建仓价"
+      "percent": 0.004
     },
     "stopLoss": {
       "enabled": true,
-      "_enabled注释": "是否启用止损",
-      "percent": 0.004,
-      "_percent注释": "止损百分比 (0.004=0.4%),对盈利方向提供追踪保护"
+      "percent": 0.004
     },
-    "minExposure": 10,
-    "_minExposure注释": "最小敞口(USDC),低于此值不设置TP/SL,避免小仓位频繁触发",
-    "priceChangeThreshold": 0.0015,
-    "_priceChangeThreshold注释": "价格变化阈值(相对比例),从0.05%提升至0.15%,避免无谓重发",
-    "tickSize": 1,
-    "_tickSize注释": "价格最小单位(Tick),TPSL价格需为其整数倍"
+    "priceChangeThreshold": 0.0007,
+    "tickSize": 1
   },
   "exposureControl": {
-    "_comment": "敞口风险控制配置 - 监控所有账户的净敞口,避免单边风险",
     "enabled": true,
-    "_enabled注释": "是否启用敞口风险监控",
     "stopLoss": {
       "enabled": true,
-      "_enabled注释": "是否启用止损",
       "threshold": 50,
-      "_threshold注释": "绝对止损阈值(USDC) - 净敞口亏损达到50 USDC时触发",
-      "thresholdPercent": 0.02,
-      "_thresholdPercent注释": "相对止损阈值 (0.02=2%) - 净敞口亏损占总权益2%时触发"
+      "thresholdPercent": 0.02
     },
     "takeProfit": {
       "enabled": true,
-      "_enabled注释": "是否启用止盈",
       "threshold": 100,
-      "_threshold注释": "绝对止盈阈值(USDC) - 净敞口盈利达到100 USDC时触发",
-      "thresholdPercent": 0.05,
-      "_thresholdPercent注释": "相对止盈阈值 (0.05=5%) - 净敞口盈利占总权益5%时触发"
+      "thresholdPercent": 0.05
     },
     "maxExposure": {
       "absolute": 500,
-      "_absolute注释": "最大绝对敞口(USDC) - 净敞口价值不能超过500 USDC",
-      "percent": 0.3,
-      "_percent注释": "最大敞口占权益百分比 (0.3=30%) - 净敞口不能超过总权益30%"
+      "percent": 0.6
     },
     "monitoringInterval": 5000,
-    "_monitoringInterval注释": "监控间隔(ms),默认5秒检查一次",
-    "leverage": 50,
-    "_leverage注释": "账户预估杠杆倍数,用于将名义敞口换算成保证金敞口"
-  },
-  "monitoring": {
-    "_comment": "监控配置",
-    "enableStats": true,
-    "_enableStats注释": "是否启用统计收集",
-    "statsInterval": 60000,
-    "_statsInterval注释": "统计输出间隔(ms),默认60秒",
-    "enableEvents": true,
-    "_enableEvents注释": "是否启用事件通知"
-  },
-  "sprint1Features": {
-    "_comment": "Sprint 1 特性开关",
-    "orderLifecycleManager": true,
-    "_orderLifecycleManager注释": "启用订单生命周期管理",
-    "pricingEngine": true,
-    "_pricingEngine注释": "启用定价引擎(穿越价差)",
-    "orderbookManager": true,
-    "_orderbookManager注释": "启用Orderbook实时数据(通过MarketDataManager适配器)"
+    "leverage": 50
   },
   "phaseManagement": {
-    "_comment": "三阶段交易状态机配置 - 紧急降仓 → 保持中性 → 逐步建仓",
     "enabled": true,
-    "_enabled注释": "是否启用阶段管理机制",
-    "emergencyNetExposureThreshold": 0.001,
-    "_emergencyNetExposureThreshold注释": "紧急降仓阈值(BTC) - 净敞口超过0.001 BTC (≈$125)触发紧急降仓",
+    "emergencyNetExposureThreshold": 0.003,
     "emergencyMarginUtilizationThreshold": 0.75,
-    "_emergencyMarginUtilizationThreshold注释": "紧急降仓保证金阈值 - 保证金利用率超过75%触发",
-    "neutralNetExposureThreshold": 0.0001,
-    "_neutralNetExposureThreshold注释": "中性阶段阈值(BTC) - 净敞口小于0.0001 BTC可进入中性阶段",
-    "buildNetExposureThreshold": 0.00005,
-    "_buildNetExposureThreshold注释": "建仓阶段阈值(BTC) - 净敞口小于0.00005 BTC才允许建仓",
+    "neutralNetExposureThreshold": 0.0003,
+    "buildNetExposureThreshold": 0.00015,
     "buildMarginUtilizationThreshold": 0.6,
-    "_buildMarginUtilizationThreshold注释": "建仓保证金阈值 - 保证金利用率低于60%才允许建仓",
     "buildMinBalance": 100,
-    "_buildMinBalance注释": "建仓最小余额(USDC) - 账户余额至少100 USDC才允许建仓",
     "emergencyMaxOrderSize": 1000,
-    "_emergencyMaxOrderSize注释": "紧急降仓阶段最大单笔订单(USDC)",
     "neutralMaxOrderSize": 50,
-    "_neutralMaxOrderSize注释": "中性阶段最大单笔订单(USDC)",
     "buildMaxOrderSize": 100,
-    "_buildMaxOrderSize注释": "建仓阶段最大单笔订单(USDC)"
+    "emergencyMitigation": {
+      "enabled": true,
+      "reduceFraction": 0.6,
+      "minNotional": 40,
+      "cooldownMs": 5000,
+      "useMarketOrder": true,
+      "netExposureThreshold": 0.001
+    }
   }
 }

+ 8 - 0
config/execution.json

@@ -0,0 +1,8 @@
+{
+  "minOrderValue": 60,
+  "maxOrderValue": 800,
+  "maxOrderValueRatio": 0.5,
+  "orderTimeout": 30,
+  "allowBypassMaxOrderValue": true,
+  "minOrderIntervalMs": 200
+}

+ 8 - 0
config/monitoring.json

@@ -0,0 +1,8 @@
+{
+  "utilizationThresholds": {
+    "build": 0.6,
+    "reduce": 0.8
+  },
+  "effectiveLeverage": 40,
+  "minOrderValue": 30
+}

+ 0 - 164
config/strategies.json

@@ -1,164 +0,0 @@
-[
-  {
-    "id": "strategy-1",
-    "name": "BTC 等量对刷策略",
-    "enabled": true,
-    "type": "EQUAL_VOLUME",
-    "symbol": "BTC",
-    "accounts": ["account-1", "account-2"],
-    "parameters": {
-      "orderSize": 0.01,
-      "priceSpread": 0.0001,
-      "interval": 5000,
-      "maxVolume": 1.0
-    },
-    "triggers": [
-      {
-        "type": "time",
-        "schedule": "0 9 * * *",
-        "enabled": true
-      },
-      {
-        "type": "price_change",
-        "threshold": 0.02,
-        "enabled": false
-      },
-      {
-        "type": "volume_spike",
-        "threshold": 1.5,
-        "enabled": false
-      }
-    ],
-    "risk": {
-      "maxPosition": 0.1,
-      "stopLoss": 0.05,
-      "maxDailyVolume": 10.0
-    }
-  },
-  {
-    "id": "strategy-2",
-    "name": "BTC 做市策略",
-    "enabled": false,
-    "type": "MARKET_MAKING",
-    "symbol": "BTC",
-    "accounts": ["account-1", "account-2"],
-    "parameters": {
-      "bidSpread": 0.0005,
-      "askSpread": 0.0005,
-      "orderSize": 0.005,
-      "refreshInterval": 10000,
-      "maxOrders": 5
-    },
-    "triggers": [
-      {
-        "type": "time",
-        "schedule": "0 */2 * * *",
-        "enabled": true
-      },
-      {
-        "type": "volatility",
-        "threshold": 0.01,
-        "enabled": true
-      }
-    ],
-    "risk": {
-      "maxPosition": 0.05,
-      "stopLoss": 0.03,
-      "maxDailyVolume": 5.0
-    }
-  },
-  {
-    "id": "strategy-3",
-    "name": "BTC 趋势跟随策略",
-    "enabled": false,
-    "type": "TREND_FOLLOWING",
-    "symbol": "BTC",
-    "accounts": ["account-1", "account-2"],
-    "parameters": {
-      "maPeriod": 20,
-      "orderSize": 0.02,
-      "priceSpread": 0.0002,
-      "trendThreshold": 0.001
-    },
-    "triggers": [
-      {
-        "type": "technical_signal",
-        "indicator": "MA_CROSSOVER",
-        "enabled": true
-      },
-      {
-        "type": "momentum",
-        "threshold": 0.005,
-        "enabled": true
-      }
-    ],
-    "risk": {
-      "maxPosition": 0.2,
-      "stopLoss": 0.08,
-      "maxDailyVolume": 15.0
-    }
-  },
-  {
-    "id": "delta-neutral-strategy",
-    "name": "Delta中性敞口持仓策略",
-    "enabled": true,
-    "type": "DELTA_NEUTRAL",
-    "symbol": "BTC",
-    "accounts": ["account-1", "account-2"],
-    "parameters": {
-      "targetDeltaRatio": 0.6,
-      "hedgeRatio": 0.4,
-      "basePositionSize": 0.1,
-      "hedgeOrderSize": 0.01,
-      "priceSpread": 0.0001,
-      "rebalanceThreshold": 0.05,
-      "maxHedgeVolume": 2.0,
-      "hedgeInterval": 3000,
-      "positionCheckInterval": 10000
-    },
-    "triggers": [
-      {
-        "type": "frequency",
-        "interval": 30000,
-        "enabled": true,
-        "parameters": {
-          "description": "每5分钟执行一次Delta中性策略检查",
-          "startTime": "09:00",
-          "endTime": "21:00",
-          "timezone": "Asia/Shanghai"
-        }
-      },
-      {
-        "type": "delta_deviation",
-        "threshold": 0.03,
-        "enabled": true,
-        "parameters": {
-          "description": "Delta偏离超过3%时触发再平衡"
-        }
-      },
-      {
-        "type": "price_change",
-        "threshold": 0.02,
-        "enabled": true,
-        "parameters": {
-          "description": "价格变化超过2%时触发对冲"
-        }
-      },
-      {
-        "type": "volatility",
-        "threshold": 0.015,
-        "enabled": true,
-        "parameters": {
-          "description": "波动率超过1.5%时增加对冲频率"
-        }
-      }
-    ],
-    "risk": {
-      "maxPosition": 0.2,
-      "stopLoss": 0.08,
-      "maxDailyVolume": 20.0,
-      "maxDeltaExposure": 0.1,
-      "maxHedgeLoss": 0.05
-    }
-  }
-]

+ 0 - 14
config/system-config.json

@@ -1,14 +0,0 @@
-{
-  "system": {
-    "name": "PacificaWashTradingSystem",
-    "version": "1.0.0",
-    "environment": "development",
-    "logLevel": "info",
-    "timezone": "Asia/Shanghai"
-  },
-  "defaults": {
-    "symbol": "BTC-PERP",
-    "maxSessions": 2
-  }
-}
-

+ 1 - 113
config/trading-strategy.json

@@ -1,116 +1,4 @@
 {
   "description": "Delta中性刷量交易策略配置",
-  "symbol": "BTC",
-
-  "orderStrategy": {
-    "_comment": "订单策略 - 控制订单类型、价差和超时机制",
-    "preferredOrderType": "limit",
-    "_preferredOrderType注释": "优先订单类型: limit=限价单(手续费低), market=市价单(成交快)",
-    "limitOrderSpread": 0.005,
-    "_limitOrderSpread注释": "限价单价差比例 (0.005=0.5%, 更容易成交,减少资金占用)",
-    "bidSpread": 0.015,
-    "_bidSpread注释": "买单价差 (0.015=1.5%, 买入价格 = 当前价格 * (1 - bidSpread))",
-    "askSpread": 0.015,
-    "_askSpread注释": "卖单价差 (0.015=1.5%, 卖出价格 = 当前价格 * (1 + askSpread))",
-    "asymmetricSpread": true,
-    "_asymmetricSpread注释": "是否启用不对称价差(买低卖高)",
-    "marketBidSlippage": 0.003,
-    "_marketBidSlippage注释": "市价买单滑点 (0.003=0.3%, 更小的滑点减少成本)",
-    "marketAskSlippage": 0.007,
-    "_marketAskSlippage注释": "市价卖单滑点 (0.007=0.7%, 更大的滑点确保成交)",
-    "orderTimeout": 30,
-    "_orderTimeout注释": "限价单超时时间(秒), 超时后自动转市价单",
-    "checkInterval": 10,
-    "_checkInterval注释": "订单检查间隔(秒), 每隔多久检查一次订单状态",
-    "emergencyMarketThreshold": 0.01,
-    "_emergencyMarketThreshold注释": "紧急市价单阈值 (0.01=1%, 价格波动超过此值时直接用市价单)"
-  },
-
-  "positions": {
-    "_comment": "仓位管理 - 控制账户余额使用和仓位大小",
-    "basePositionRatio": 0.3,
-    "_basePositionRatio注释": "基础仓位比例 (0.2=20%, 普通交易使用的资金比例)",
-    "volumePositionRatio": 0.7,
-    "_volumePositionRatio注释": "刷量仓位比例 (0.8=80%, 刷量交易使用的资金比例)",
-    "balanceUsageRatio": 0.8,
-    "_balanceUsageRatio注释": "账户余额使用比例 (0.2=20%, 总共使用多少比例的账户余额, 建议不超过30%)",
-    "minOrderValue": 10,
-    "_minOrderValue注释": "最小订单价值(USDC), DEX要求每单至少$10"
-  },
-
-  "deltaRebalancing": {
-    "_comment": "Delta再平衡 - 自动修正仓位不平衡(已集成绝对阈值检测)",
-    "enabled": true,
-    "_enabled注释": "是否启用自动再平衡功能",
-    "checkInterval": 30,
-    "_checkInterval注释": "检查间隔(秒), 每隔30秒检查一次Delta偏差(加快响应)",
-    "absoluteThreshold": 0.0001,
-    "_absoluteThreshold注释": "绝对阈值 (0.0001 BTC ≈ $10 USDC, 已在策略引擎中硬编码)",
-    "rebalanceThreshold": 0.01,
-    "_rebalanceThreshold注释": "百分比阈值 (0.01=1%, 作为后备检测,已改用绝对阈值优先)",
-    "maxDeltaDeviation": 0.0005,
-    "_maxDeltaDeviation注释": "目标最大Delta偏差 (0.0005=0.05%, 更严格的目标)"
-  },
-
-  "dynamicPositionAdjustment": {
-    "_comment": "动态仓位调整 - 当保证金使用率过高时自动减仓 (已改用WebSocket事件驱动)",
-    "enabled": false,
-    "_enabled注释": "是否启用动态仓位调整功能 (禁用轮询,改用WebSocket监听)",
-    "maxMarginUsageThreshold": 0.75,
-    "_maxMarginUsageThreshold注释": "保证金使用率阈值 (0.75=75%, 超过此值时触发减仓)",
-    "targetMarginRelease": 0.3,
-    "_targetMarginRelease注释": "目标释放的保证金比例 (0.3=30%, 减仓时释放多少保证金)",
-    "minPositionRatio": 0.2,
-    "_minPositionRatio注释": "最小保留仓位比例 (0.2=20%, 减仓后至少保留多少仓位)",
-    "checkInterval": 300000,
-    "_checkInterval注释": "检查间隔(毫秒), 仅作为后备检查 (5分钟)"
-  },
-
-  "risk": {
-    "_comment": "风险控制 - 保护账户资金安全",
-    "maxDrawdown": 0.01,
-    "_maxDrawdown注释": "最大回撤比例 (0.01=1%, 亏损超过1%时触发风险控制)",
-    "stopLossThreshold": 0.005,
-    "_stopLossThreshold注释": "止损阈值 (0.005=0.5%, 单笔亏损超过此值时止损)",
-    "positionSizeMultiplier": 1.05,
-    "_positionSizeMultiplier注释": "仓位大小倍数 (1.05=105%, 用于计算最大允许仓位)"
-  },
-
-  "intervals": {
-    "_comment": "时间间隔 - 控制各个模块的执行频率(优化后更频繁检测)",
-    "volumeTrading": 3,
-    "_volumeTrading注释": "刷量交易间隔(秒), 每3秒执行一次(加快交易频率)",
-    "deltaMonitoring": 30,
-    "_deltaMonitoring注释": "Delta监控间隔(秒), 每30秒监控一次(加快响应)",
-    "orderCheck": 3,
-    "_orderCheck注释": "订单检查间隔(秒), 每3秒检查一次挂单状态",
-    "statusDisplay": 20,
-    "_statusDisplay注释": "状态显示间隔(秒), 每隔多久打印一次状态信息",
-    "statsSave": 600,
-    "_statsSave注释": "统计保存间隔(秒), 每隔多久保存一次统计数据",
-    "healthCheck": 300,
-    "_healthCheck注释": "健康检查间隔(秒), 每隔多久进行一次系统健康检查"
-  },
-
-  "retry": {
-    "_comment": "重试机制 - API调用失败时的重试策略",
-    "maxAttempts": 3,
-    "_maxAttempts注释": "最大重试次数, API调用失败后最多重试几次",
-    "delayMs": 10000,
-    "_delayMs注释": "重试延迟(毫秒), 每次重试前等待多久",
-    "apiCallInterval": 2000,
-    "_apiCallInterval注释": "API调用最小间隔(毫秒), 避免触发限流, 不要低于2000ms"
-  },
-
-  "limits": {
-    "_comment": "系统限制 - 防止异常情况",
-    "maxConsecutiveErrors": 3,
-    "_maxConsecutiveErrors注释": "最大连续错误次数, 连续失败超过此次数时暂停交易",
-    "tradingPauseDuration": 120000,
-    "_tradingPauseDuration注释": "交易暂停时长(毫秒), 触发风控后暂停多久",
-    "maxRuntime": 21600000,
-    "_maxRuntime注释": "最大运行时间(毫秒), 6小时=21600000ms, 防止长时间运行累积风险",
-    "errorRecoveryDelay": 60000,
-    "_errorRecoveryDelay注释": "错误恢复延迟(毫秒), 出错后等待多久再恢复交易"
-  }
+  "symbol": "BTC"
 }

+ 7 - 1
specs/001-ts-pacifica-perp/tasks.md

@@ -341,4 +341,10 @@ Task: "Run manual testing scenarios from quickstart.md"
 - [x] BTC trading pair focus maintained throughout
 - [x] Multi-account coordination requirements addressed
 - [x] Risk management and audit logging included
-- [x] Performance targets specified (<100ms latency, 1000+ orders/hour)
+- [x] Performance targets specified (<100ms latency, 1000+ orders/hour)
+## Config & Exposure Streamlining Plan (2025-10-05)
+- Use shared base equity = min(account balances) to derive unified capacity caps.
+- Introduce utilization regimes (<60% build, 60–80% balance, ≥80% reduce) and expose to strategy/monitoring modules.
+- Let ExposureRiskMonitor own rebalance signals; SimpleStrategyEngine only produces neutral volume orders respecting regime.
+- Refactor configs: execution.json (done), monitoring/phases next, plus schema validation.
+- Add logging & docs for key thresholds; ensure SignalExecutor locks prevent concurrent rebalance.

+ 110 - 0
src/modules/AccountManager.ts

@@ -41,6 +41,26 @@ export interface BalanceCheckResult {
   issues: string[];
 }
 
+export interface AccountUtilizationMetrics {
+  baseEquity: number;
+  baseAvailable: number;
+  baseEffectiveEquity: number;
+  baseEffectiveAvailable: number;
+  effectiveEquity: number;
+  effectiveAvailable: number;
+  leverageMultiplier: number;
+  maxUtilization: number;
+  minUtilization: number;
+  perAccount: Array<{
+    accountId: string;
+    total: number;
+    available: number;
+    effectiveEquity: number;
+    effectiveAvailable: number;
+    utilization: number;
+  }>;
+}
+
 export class AccountManager {
   private logger: Logger;
   private accounts: Map<string, AccountInfo> = new Map();
@@ -760,4 +780,94 @@ export class AccountManager {
 
     return position;
   }
+  public getUtilizationMetrics(leverageMultiplier: number = 1): AccountUtilizationMetrics {
+    const leverage = leverageMultiplier > 0 ? leverageMultiplier : 1;
+
+    const defaultMetrics: AccountUtilizationMetrics = {
+      baseEquity: 0,
+      baseAvailable: 0,
+      baseEffectiveEquity: 0,
+      baseEffectiveAvailable: 0,
+      effectiveEquity: 0,
+      effectiveAvailable: 0,
+      leverageMultiplier: leverage,
+      maxUtilization: 0,
+      minUtilization: 0,
+      perAccount: []
+    };
+
+    if (!this.dataAggregator) {
+      return defaultMetrics;
+    }
+
+    const accountsData = this.dataAggregator.getAllAccountsData();
+    if (!accountsData || accountsData.size === 0) {
+      return defaultMetrics;
+    }
+
+    let baseEquity = Number.POSITIVE_INFINITY;
+    let baseAvailable = Number.POSITIVE_INFINITY;
+    let baseEffectiveEquity = Number.POSITIVE_INFINITY;
+    let baseEffectiveAvailable = Number.POSITIVE_INFINITY;
+    let maxUtilization = 0;
+    let minUtilization = 1;
+    const perAccount: AccountUtilizationMetrics['perAccount'] = [];
+
+    for (const [accountId] of this.accounts) {
+      const data = accountsData.get(accountId);
+      const total = data?.balance?.total ?? 0;
+      const available = data?.balance?.available ?? 0;
+      const utilization = total > 0 ? Math.min(Math.max(1 - available / total, 0), 1) : 0;
+      const effectiveEquity = total * leverage;
+      const effectiveAvailable = available * leverage;
+
+      perAccount.push({ accountId, total, available, effectiveEquity, effectiveAvailable, utilization });
+
+      if (total > 0) {
+        baseEquity = Math.min(baseEquity, total);
+        baseEffectiveEquity = Math.min(baseEffectiveEquity, effectiveEquity);
+      }
+      if (available > 0) {
+        baseAvailable = Math.min(baseAvailable, available);
+        baseEffectiveAvailable = Math.min(baseEffectiveAvailable, effectiveAvailable);
+      }
+      maxUtilization = Math.max(maxUtilization, utilization);
+      minUtilization = Math.min(minUtilization, utilization);
+    }
+
+    if (!Number.isFinite(baseEquity)) {
+      baseEquity = 0;
+    }
+    if (!Number.isFinite(baseAvailable)) {
+      baseAvailable = 0;
+    }
+    if (!Number.isFinite(baseEffectiveEquity)) {
+      baseEffectiveEquity = baseEquity * leverage;
+    }
+    if (!Number.isFinite(baseEffectiveAvailable)) {
+      baseEffectiveAvailable = baseAvailable * leverage;
+    }
+    if (perAccount.length === 0) {
+      maxUtilization = 0;
+      minUtilization = 0;
+    }
+
+    const effectiveEquity = baseEffectiveEquity;
+    const effectiveAvailable = baseEffectiveAvailable;
+
+    return {
+      baseEquity,
+      baseAvailable,
+      baseEffectiveEquity,
+      baseEffectiveAvailable,
+      effectiveEquity,
+      effectiveAvailable,
+      leverageMultiplier: leverage,
+      maxUtilization,
+      minUtilization,
+      perAccount
+    };
+  }
+
+
 }

+ 17 - 7
src/modules/ComponentInitializer.ts

@@ -4,7 +4,7 @@
  */
 
 import Logger from '../utils/Logger';
-import { DeltaStrategyConfig } from './ConfigurationManager';
+import { DeltaStrategyConfig, ExecutionConfig, MonitoringSettings } from './ConfigurationManager';
 import WebSocket from 'ws';
 
 // Ensure WebSocket is available globally when running under Node.js
@@ -78,6 +78,8 @@ export class ComponentInitializer {
    */
   public async initializeCoreComponents(
     config: DeltaStrategyConfig,
+    executionConfig: ExecutionConfig,
+    monitoringSettings: MonitoringSettings,
     accountManager: AccountManager,
     tradingSymbol: string
   ): Promise<CoreComponents> {
@@ -123,6 +125,11 @@ export class ComponentInitializer {
       symbol: tradingSymbol,
       positionDiffThreshold: 0.05,
       volumeTargetPerCycle: 0.001
+    }, {
+      accountManager,
+      utilizationThresholds: monitoringSettings.utilizationThresholds,
+      minOrderValue: executionConfig.minOrderValue,
+      effectiveLeverage: monitoringSettings.effectiveLeverage
     });
 
     // Create HedgingModule
@@ -136,12 +143,12 @@ export class ComponentInitializer {
     const signalExecutor = new SignalExecutor({
       maxRetries: 3,
       retryDelay: 2000,
-      executionTimeout: config.orderExecution.orderTimeout * 1000,
+      executionTimeout: executionConfig.orderTimeout * 1000,
       enableDryRun: false,
-      minOrderInterval: 3000,
-      maxOrderValue: config.orderExecution.maxOrderValue,
-      maxOrderValueRatio: config.orderExecution.maxOrderValueRatio,
-      allowBypassMaxOrderValue: config.orderExecution.allowBypassMaxOrderValue || false,
+      minOrderInterval: executionConfig.minOrderIntervalMs ?? 3000,
+      maxOrderValue: executionConfig.maxOrderValue,
+      maxOrderValueRatio: executionConfig.maxOrderValueRatio,
+      allowBypassMaxOrderValue: executionConfig.allowBypassMaxOrderValue || false,
       positionTPSL: config.positionTPSL
     });
 
@@ -162,7 +169,10 @@ export class ComponentInitializer {
         buildMinBalance: config.phaseManagement.buildMinBalance,
         emergencyMaxOrderSize: config.phaseManagement.emergencyMaxOrderSize,
         neutralMaxOrderSize: config.phaseManagement.neutralMaxOrderSize,
-        buildMaxOrderSize: config.phaseManagement.buildMaxOrderSize
+        buildMaxOrderSize: config.phaseManagement.buildMaxOrderSize,
+        ...(config.phaseManagement.emergencyMitigation
+          ? { emergencyMitigation: config.phaseManagement.emergencyMitigation }
+          : {})
       };
 
       phaseManager = new TradingPhaseManager(phaseConfig, accountManager, tradingSymbol);

+ 88 - 8
src/modules/ConfigurationManager.ts

@@ -14,20 +14,12 @@ export interface AccountConfig {
 
 export interface StrategyConfig {
   symbol: string;
-  positionDiffThreshold: number;
-  volumeTargetPerCycle: number;
 }
 
 export interface DeltaStrategyConfig {
   strategy: {
     tradingInterval: number;
   };
-  orderExecution: {
-    orderTimeout: number;
-    maxOrderValue: number;
-    maxOrderValueRatio: number;
-    allowBypassMaxOrderValue?: boolean;
-  };
   positionTPSL: any;
   orderbook: {
     wsUrl: string;
@@ -80,7 +72,32 @@ export interface DeltaStrategyConfig {
     emergencyMaxOrderSize: number;
     neutralMaxOrderSize: number;
     buildMaxOrderSize: number;
+    emergencyMitigation?: {
+      enabled?: boolean;
+      reduceFraction?: number;
+      minNotional?: number;
+      cooldownMs?: number;
+      useMarketOrder?: boolean;
+    };
+  };
+}
+
+export interface ExecutionConfig {
+  minOrderValue: number;
+  maxOrderValue: number;
+  maxOrderValueRatio: number;
+  orderTimeout: number;
+  allowBypassMaxOrderValue?: boolean;
+  minOrderIntervalMs?: number;
+}
+
+export interface MonitoringSettings {
+  utilizationThresholds: {
+    build: number;
+    reduce: number;
   };
+  effectiveLeverage: number;
+  minOrderValue?: number;
 }
 
 export class ConfigurationManager {
@@ -90,6 +107,8 @@ export class ConfigurationManager {
   private accountsConfig: AccountConfig[] = [];
   private strategyConfig: StrategyConfig | null = null;
   private deltaConfig: DeltaStrategyConfig | null = null;
+  private executionConfig: ExecutionConfig | null = null;
+  private monitoringSettings: MonitoringSettings | null = null;
 
   private constructor() {
     this.logger = Logger.getInstance();
@@ -127,6 +146,18 @@ export class ConfigurationManager {
       );
       this.logger.info('Loaded delta strategy configuration');
 
+      // Load execution configuration
+      this.executionConfig = JSON.parse(
+        readFileSync('./config/execution.json', 'utf-8')
+      );
+      this.logger.info('Loaded execution configuration');
+
+      // Load monitoring settings
+      this.monitoringSettings = JSON.parse(
+        readFileSync('./config/monitoring.json', 'utf-8')
+      );
+      this.logger.info('Loaded monitoring settings');
+
       // Validate configurations
       this.validateConfigurations();
 
@@ -172,6 +203,41 @@ export class ConfigurationManager {
       };
     }
 
+    if (!this.executionConfig) {
+      throw new Error('Execution configuration not loaded');
+    }
+
+    if (this.executionConfig.minOrderValue <= 0) {
+      throw new Error('Execution config: minOrderValue must be positive');
+    }
+    if (this.executionConfig.maxOrderValue <= 0) {
+      throw new Error('Execution config: maxOrderValue must be positive');
+    }
+    if (this.executionConfig.maxOrderValue < this.executionConfig.minOrderValue) {
+      throw new Error('Execution config: maxOrderValue must be >= minOrderValue');
+    }
+    if (this.executionConfig.maxOrderValueRatio <= 0 || this.executionConfig.maxOrderValueRatio > 1) {
+      throw new Error('Execution config: maxOrderValueRatio must be between 0 and 1');
+    }
+    if (this.executionConfig.minOrderIntervalMs !== undefined && this.executionConfig.minOrderIntervalMs < 0) {
+      throw new Error('Execution config: minOrderIntervalMs cannot be negative');
+    }
+
+    if (!this.monitoringSettings) {
+      throw new Error('Monitoring settings not loaded');
+    }
+    const build = this.monitoringSettings.utilizationThresholds?.build ?? 0.6;
+    const reduce = this.monitoringSettings.utilizationThresholds?.reduce ?? 0.8;
+    if (build <= 0 || reduce <= 0 || build >= reduce) {
+      throw new Error('Monitoring settings: utilization thresholds must satisfy 0 < build < reduce');
+    }
+    if (!this.monitoringSettings.effectiveLeverage || this.monitoringSettings.effectiveLeverage <= 0) {
+      throw new Error('Monitoring settings: effectiveLeverage must be positive');
+    }
+    if (this.monitoringSettings.minOrderValue !== undefined && this.monitoringSettings.minOrderValue <= 0) {
+      throw new Error('Monitoring settings: minOrderValue must be positive when provided');
+    }
+
     this.logger.info('Configuration validation passed');
   }
 
@@ -205,6 +271,20 @@ export class ConfigurationManager {
     return this.deltaConfig;
   }
 
+  public getExecutionConfig(): ExecutionConfig {
+    if (!this.executionConfig) {
+      throw new Error('Execution configuration not loaded');
+    }
+    return this.executionConfig;
+  }
+
+  public getMonitoringSettings(): MonitoringSettings {
+    if (!this.monitoringSettings) {
+      throw new Error('Monitoring settings not loaded');
+    }
+    return this.monitoringSettings;
+  }
+
   /**
    * Get trading interval
    */

+ 391 - 35
src/modules/MonitoringManager.ts

@@ -57,11 +57,31 @@ export interface MonitoringConfig {
     tickSize?: number;
   };
   tradingSymbol: string;
+  utilizationThresholds?: {
+    build: number;
+    reduce: number;
+  };
+  minOrderValue?: number;
+  effectiveLeverage?: number;
+  emergencyMitigation?: {
+    enabled?: boolean;
+    reduceFraction?: number;
+    minNotional?: number;
+    cooldownMs?: number;
+    useMarketOrder?: boolean;
+    netExposureThreshold?: number;
+  };
 }
 
 export class MonitoringManager {
   private logger: Logger;
   private config: MonitoringConfig;
+  private utilizationThresholds: { build: number; reduce: number } = { build: 0.6, reduce: 0.8 };
+  private minOrderValue: number = 10;
+  private effectiveLeverage: number = 1;
+  private emergencyMitigationConfig: MonitoringConfig['emergencyMitigation'] | null = null;
+  private lastEmergencyMitigation = 0;
+  private emergencyReductionActive = false;
 
   // Dependencies
   private dataAggregator: DataAggregator;
@@ -82,6 +102,10 @@ export class MonitoringManager {
     const stopLossConfig = raw['stopLoss'] ?? {};
     const takeProfitConfig = raw['takeProfit'] ?? {};
     const maxExposureConfig = raw['maxExposure'] ?? {};
+    const leverageCandidate = Number(raw['leverage'] ?? raw['leverageMultiplier']);
+    const leverageMultiplier = Number.isFinite(leverageCandidate) && leverageCandidate > 0
+      ? leverageCandidate
+      : this.effectiveLeverage;
 
     return {
       enabled: Boolean(raw.enabled),
@@ -100,7 +124,7 @@ export class MonitoringManager {
         percent: Number(maxExposureConfig['percent'] ?? 0)
       },
       monitoringInterval: Number(raw['monitoringInterval'] ?? 5000),
-      leverageMultiplier: Number(raw['leverage'] ?? raw['leverageMultiplier'] ?? 1)
+      leverageMultiplier
     };
   }
 
@@ -120,6 +144,73 @@ export class MonitoringManager {
     return 0;
   }
 
+  private getUtilizationContext(): {
+    regime: 'build' | 'balance' | 'reduce';
+    metrics: ReturnType<AccountManager['getUtilizationMetrics']>;
+  } {
+    const metrics = this.accountManager.getUtilizationMetrics(this.effectiveLeverage);
+    const build = this.utilizationThresholds.build;
+    const reduce = this.utilizationThresholds.reduce;
+
+    let regime: 'build' | 'balance' | 'reduce';
+    if (metrics.maxUtilization >= reduce) {
+      regime = 'reduce';
+    } else if (metrics.maxUtilization >= build) {
+      regime = 'balance';
+    } else {
+      regime = 'build';
+    }
+
+    return { regime, metrics };
+  }
+
+  private clampExposureAmount(
+    amount: number,
+    currentPrice: number,
+    metrics: ReturnType<AccountManager['getUtilizationMetrics']>,
+    regime: 'build' | 'balance' | 'reduce'
+  ): number {
+    if (currentPrice <= 0) {
+      return amount;
+    }
+
+    const primaryEffective = metrics.baseEffectiveAvailable > 0
+      ? metrics.baseEffectiveAvailable
+      : metrics.baseEffectiveEquity;
+    const fallbackEffective = metrics.effectiveAvailable > 0
+      ? metrics.effectiveAvailable
+      : metrics.effectiveEquity;
+    const effectiveCapacity = primaryEffective > 0 ? primaryEffective : fallbackEffective;
+
+    if (effectiveCapacity <= 0) {
+      return amount;
+    }
+
+    let ratio = regime === 'balance' ? 0.25 : 0.35;
+    if (regime === 'reduce') {
+      ratio = 0.15;
+    }
+
+    const maxNotional = Math.max(effectiveCapacity * ratio, 0);
+    if (maxNotional <= 0) {
+      return amount;
+    }
+
+    const lotSize = 0.00001;
+    const maxAmount = Math.floor((maxNotional / currentPrice) / lotSize) * lotSize;
+    if (maxAmount <= 0) {
+      return amount;
+    }
+
+    const minNotional = this.minOrderValue;
+    const minAmount = Math.ceil((minNotional / currentPrice) / lotSize) * lotSize;
+    if (maxAmount < minAmount) {
+      return 0;
+    }
+
+    return Math.min(Math.max(amount, minAmount), maxAmount);
+  }
+
   constructor(
     config: MonitoringConfig,
     dependencies: {
@@ -136,6 +227,28 @@ export class MonitoringManager {
     this.signalExecutor = dependencies.signalExecutor;
     this.tradingCycleManager = dependencies.tradingCycleManager || null;
     this.tradingSymbol = config.tradingSymbol;
+    if (config.utilizationThresholds) {
+      this.utilizationThresholds = config.utilizationThresholds;
+    }
+    if (typeof config.minOrderValue === 'number' && config.minOrderValue > 0) {
+      this.minOrderValue = config.minOrderValue;
+    }
+    if (typeof config.effectiveLeverage === 'number' && config.effectiveLeverage > 0) {
+      this.effectiveLeverage = config.effectiveLeverage;
+    }
+    if (config.emergencyMitigation) {
+      this.emergencyMitigationConfig = {
+        enabled: config.emergencyMitigation.enabled ?? true,
+        reduceFraction: config.emergencyMitigation.reduceFraction ?? 0.5,
+        minNotional: config.emergencyMitigation.minNotional ?? this.minOrderValue,
+        cooldownMs: config.emergencyMitigation.cooldownMs ?? 5000,
+        useMarketOrder: config.emergencyMitigation.useMarketOrder ?? true
+      };
+
+      if (config.emergencyMitigation.netExposureThreshold !== undefined) {
+        this.emergencyMitigationConfig.netExposureThreshold = config.emergencyMitigation.netExposureThreshold;
+      }
+    }
   }
 
   /**
@@ -702,7 +815,7 @@ export class MonitoringManager {
       if (!priceData) continue;
 
       const markPrice = this.extractPrice(priceData);
-      const netPosition = typeof pos.amount === 'number' ? pos.amount : pos.size || 0;
+      const netPosition = this.normalizePositionSize(pos);
       const positionExposure: PositionExposure = {
         symbol: pos.symbol,
         netPosition,
@@ -754,6 +867,69 @@ export class MonitoringManager {
     await this.rebalanceExposurePositions(status.totalExposure, status.reason ?? undefined);
   }
 
+  public async triggerEmergencyMitigation(reason?: string): Promise<void> {
+    if (!this.emergencyMitigationConfig?.enabled) {
+      return;
+    }
+
+    const { netSize: currentNetExposure, currentPrice } = this.computeSymbolNetExposure(this.tradingSymbol);
+    const thresholdSize = this.resolveEmergencyNetThreshold(currentPrice);
+    const absNetExposure = Math.abs(currentNetExposure);
+
+    if (absNetExposure <= thresholdSize) {
+      if (this.emergencyReductionActive) {
+        this.logger.info('Emergency mitigation satisfied below threshold', {
+          netExposure: absNetExposure,
+          threshold: thresholdSize
+        });
+      }
+      this.clearEmergencyMitigation();
+      return;
+    }
+
+    const cooldown = this.emergencyMitigationConfig.cooldownMs ?? 5000;
+    const now = Date.now();
+    if (now - this.lastEmergencyMitigation < cooldown) {
+      return;
+    }
+
+    this.emergencyReductionActive = true;
+    this.lastEmergencyMitigation = now;
+
+    const reduceFraction = this.emergencyMitigationConfig.reduceFraction ?? 0.5;
+    const minNotional = this.emergencyMitigationConfig.minNotional ?? this.minOrderValue;
+    const allowMarketOrders = this.emergencyMitigationConfig.useMarketOrder ?? false;
+
+    this.logger.warn('🚨 Emergency mitigation activated', {
+      reason: reason ?? 'phase_emergency',
+      reduceFraction,
+      minNotional,
+      cooldown
+    });
+
+    await this.rebalanceExposurePositions(0, reason ?? 'phase_emergency', {
+      forceReduce: true,
+      reduceFraction,
+      minNotional,
+      allowMarketOrders
+    });
+
+    const { netSize: postNetExposure } = this.computeSymbolNetExposure(this.tradingSymbol);
+    const postAbs = Math.abs(postNetExposure);
+    if (postAbs <= thresholdSize) {
+      this.logger.info('Emergency mitigation completed', {
+        netExposure: postAbs,
+        threshold: thresholdSize
+      });
+      this.clearEmergencyMitigation();
+    } else {
+      this.logger.warn('Emergency mitigation incomplete', {
+        netExposure: postAbs,
+        threshold: thresholdSize
+      });
+    }
+  }
+
   /**
    * Close all positions for exposure control
    */
@@ -773,7 +949,7 @@ export class MonitoringManager {
         }
         const priceData: PriceTick | undefined = aggregatedData.market.prices.get(symbol);
         const currentPrice = this.extractPrice(priceData);
-        const positionSize = typeof pos.amount === 'number' ? pos.amount : 0;
+        const positionSize = this.normalizePositionSize(pos);
 
         const closePrice = positionSize > 0
           ? currentPrice * 0.995  // Sell lower
@@ -800,12 +976,41 @@ export class MonitoringManager {
   /**
    * Reduce positions for exposure control
    */
-  private async rebalanceExposurePositions(_: number, reason?: string): Promise<void> {
+  private async rebalanceExposurePositions(
+    _: number,
+    reason?: string,
+    options?: {
+      forceReduce?: boolean;
+      reduceFraction?: number;
+      minNotional?: number;
+      allowMarketOrders?: boolean;
+    }
+  ): Promise<void> {
+    if (this.emergencyReductionActive && !(options?.forceReduce)) {
+      this.logger.debug('Emergency mitigation active, skipping non-forced exposure rebalance');
+      return;
+    }
+
     const reasonText = reason ?? 'auto_exposure_rebalance';
     const aggregatedData = this.dataAggregator.getAggregatedData();
     const signals: TradingSignal[] = [];
 
-    let maxUtilization = 0;
+    const metricsContext = this.getUtilizationContext();
+    const regime = metricsContext.regime;
+    const metrics = metricsContext.metrics;
+
+    const forceReduce = options?.forceReduce ?? false;
+    const reduceFraction = Math.min(Math.max(options?.reduceFraction ?? 0.5, 0.05), 1);
+    const emergencyMinNotional = options?.minNotional ?? this.minOrderValue;
+    const allowMarketOrders = options?.allowMarketOrders ?? false;
+
+    this.logger.debug('Exposure utilization context', {
+      regime,
+      baseEquity: metrics.baseEquity,
+      baseAvailable: metrics.baseAvailable,
+      maxUtilization: metrics.maxUtilization.toFixed(3)
+    });
+
     const marginUtilizations = new Map<string, number>();
     const exposuresByAccount = new Map<string, Map<string, number>>();
     const symbolTotals = new Map<string, number>();
@@ -818,7 +1023,6 @@ export class MonitoringManager {
         utilization = Math.min(Math.max(1 - available / balance.total, 0), 1);
       }
       marginUtilizations.set(accountId, utilization);
-      maxUtilization = Math.max(maxUtilization, utilization);
 
       const accountExposureMap = new Map<string, number>();
       exposuresByAccount.set(accountId, accountExposureMap);
@@ -829,22 +1033,19 @@ export class MonitoringManager {
           if (!symbol) {
             continue;
           }
-          const size = typeof pos.amount === 'number' ? pos.amount : 0;
+          const size = this.normalizePositionSize(pos);
           if (!Number.isFinite(size) || size === 0) {
             continue;
           }
-
           accountExposureMap.set(symbol, (accountExposureMap.get(symbol) ?? 0) + size);
           symbolTotals.set(symbol, (symbolTotals.get(symbol) ?? 0) + size);
         }
       }
     });
 
-    const shouldOpen = maxUtilization < 0.5;
-
     const MIN_ORDER_SIZE = 0.00001;
 
-    if (shouldOpen) {
+    if (!forceReduce && regime !== 'reduce') {
       symbolTotals.forEach((totalExposure, symbol) => {
         if (Math.abs(totalExposure) < MIN_ORDER_SIZE) {
           return;
@@ -858,51 +1059,127 @@ export class MonitoringManager {
         );
 
         if (!targetAccountId) {
-          this.logger.warn('Unable to select account for exposure rebalance (open)', {
-            symbol,
-            totalExposure
-          });
+          this.logger.warn('Unable to select account for exposure rebalance (open)', { symbol, totalExposure });
           return;
         }
 
         const priceData: PriceTick | undefined = aggregatedData.market.prices.get(symbol);
         const currentPrice = this.extractPrice(priceData);
-
+        let amount = Math.abs(totalExposure);
+        amount = this.clampExposureAmount(amount, currentPrice, metrics, regime);
+        if (amount < MIN_ORDER_SIZE) {
+          return;
+        }
         const openSide: 'bid' | 'ask' = totalExposure > 0 ? 'ask' : 'bid';
-        const amount = Math.abs(totalExposure);
-
-       signals.push({
-         type: 'open',
-         accountId: targetAccountId,
-         symbol,
-         side: openSide,
-         amount,
-         price: currentPrice,
-         useMarketOrder: true,
-         reason: `exposure_rebalance_open: ${reasonText}`,
+
+        signals.push({
+          type: 'open',
+          accountId: targetAccountId,
+          symbol,
+          side: openSide,
+          amount,
+          price: currentPrice,
+          useMarketOrder: allowMarketOrders,
+          reason: `exposure_rebalance_open: ${reasonText}`,
           timestamp: Date.now(),
-          metadata: {
-            rebalance: true
-          }
+          metadata: { rebalance: true }
         });
       });
-    } else {
+    }
+
+    if (forceReduce) {
+      symbolTotals.forEach((totalExposure, symbol) => {
+        if (Math.abs(totalExposure) < MIN_ORDER_SIZE) {
+          return;
+        }
+
+        const priceData: PriceTick | undefined = aggregatedData.market.prices.get(symbol);
+        const currentPrice = this.extractPrice(priceData);
+        if (!(currentPrice > 0)) {
+          this.logger.warn('Unable to perform emergency reduction without price data', { symbol });
+          return;
+        }
+
+        const isNetLong = totalExposure > 0;
+        let remaining = Math.abs(totalExposure);
+        const minAmount = Math.max(emergencyMinNotional / currentPrice, MIN_ORDER_SIZE);
+
+        const candidateAccounts = Array.from(exposuresByAccount.entries())
+          .map(([accountId, exposureMap]) => ({
+            accountId,
+            size: exposureMap.get(symbol) ?? 0
+          }))
+          .filter(entry => isNetLong ? entry.size > MIN_ORDER_SIZE : entry.size < -MIN_ORDER_SIZE)
+          .sort((a, b) => isNetLong ? b.size - a.size : a.size - b.size);
+
+        for (const { accountId, size } of candidateAccounts) {
+          if (remaining <= MIN_ORDER_SIZE) {
+            break;
+          }
+
+          const available = Math.min(Math.abs(size), remaining);
+          let amount = Math.max(available, minAmount);
+          amount = Math.min(amount, Math.abs(size));
+          if (amount < MIN_ORDER_SIZE) {
+            continue;
+          }
+
+          const side: 'bid' | 'ask' = isNetLong ? 'ask' : 'bid';
+          const price = allowMarketOrders
+            ? currentPrice
+            : isNetLong
+              ? currentPrice * 0.998
+              : currentPrice * 1.002;
+
+          signals.push({
+            type: 'reduce',
+            accountId,
+            symbol,
+            side,
+            amount,
+            price,
+            useMarketOrder: allowMarketOrders,
+            reason: `emergency_force_reduce: ${reasonText}`,
+            timestamp: Date.now()
+          });
+
+          remaining = Math.max(0, remaining - amount);
+        }
+
+        if (remaining > MIN_ORDER_SIZE) {
+          this.logger.warn('Residual exposure remains after emergency reduction attempt', {
+            symbol,
+            remaining
+          });
+        }
+      });
+    } else if (regime !== 'build') {
       aggregatedData.accounts.forEach((accountData, accountId) => {
         if (!Array.isArray(accountData.positions) || accountData.positions.length === 0) {
           return;
         }
 
         for (const pos of accountData.positions) {
-          const positionSize = typeof pos.amount === 'number' ? pos.amount : 0;
+          const positionSize = this.normalizePositionSize(pos);
           if (positionSize === 0) {
             continue;
           }
 
           const priceData: PriceTick | undefined = aggregatedData.market.prices.get(pos.symbol);
           const currentPrice = this.extractPrice(priceData);
+          const clampRegime = regime === 'reduce' ? 'reduce' : 'balance';
+          const initialAmount = Math.max(Math.abs(positionSize) * reduceFraction, MIN_ORDER_SIZE);
+          let amount = this.clampExposureAmount(initialAmount, currentPrice, metrics, clampRegime);
+
+          if (amount > Math.abs(positionSize)) {
+            amount = Math.abs(positionSize);
+          }
+
+          if (amount < MIN_ORDER_SIZE) {
+            continue;
+          }
           const side: 'bid' | 'ask' = positionSize > 0 ? 'ask' : 'bid';
-          const amount = Math.max(Math.abs(positionSize) * 0.5, MIN_ORDER_SIZE);
-          const price = positionSize > 0 ? currentPrice * 0.998 : currentPrice * 1.002;
+          const aggressivePrice = positionSize > 0 ? currentPrice * 0.998 : currentPrice * 1.002;
 
           signals.push({
             type: 'reduce',
@@ -910,7 +1187,7 @@ export class MonitoringManager {
             symbol: pos.symbol,
             side,
             amount,
-            price,
+            price: aggressivePrice,
             reason: `exposure_rebalance_reduce: ${reasonText}`,
             timestamp: Date.now()
           });
@@ -920,7 +1197,86 @@ export class MonitoringManager {
 
     if (signals.length > 0) {
       await this.signalExecutor.executeSignalsBatch(signals);
+
+      if (options?.forceReduce) {
+        const accountsToRefresh = new Set<string>(signals.map(signal => signal.accountId));
+        await this.refreshAccounts(accountsToRefresh);
+      }
+    }
+  }
+
+  private normalizePositionSize(position: any): number {
+    const raw = typeof position?.amount === 'number'
+      ? position.amount
+      : Number(position?.amount ?? position?.size ?? 0);
+    if (!Number.isFinite(raw) || raw === 0) {
+      return 0;
+    }
+    const side = position?.side;
+    if (side === 'ask') {
+      return raw > 0 ? -raw : raw;
+    }
+    if (side === 'bid') {
+      return raw < 0 ? -raw : raw;
+    }
+    return raw;
+  }
+
+  private async refreshAccounts(accountIds: Iterable<string>): Promise<void> {
+    const unique = Array.from(new Set(accountIds));
+    if (unique.length === 0) {
+      return;
+    }
+
+    await Promise.all(unique.map(async accountId => {
+      try {
+        await this.accountManager.refreshAccountData(accountId);
+      } catch (error) {
+        this.logger.warn('Failed to refresh account during emergency mitigation', {
+          accountId,
+          error
+        });
+      }
+    }));
+  }
+
+  private computeSymbolNetExposure(symbol: string): { netSize: number; currentPrice: number } {
+    const aggregatedData = this.dataAggregator.getAggregatedData();
+    let netSize = 0;
+
+    aggregatedData.accounts.forEach(accountData => {
+      const positions = Array.isArray(accountData.positions) ? accountData.positions : [];
+      for (const pos of positions) {
+        if (!pos || pos.symbol !== symbol) {
+          continue;
+        }
+        netSize += this.normalizePositionSize(pos);
+      }
+    });
+
+    const priceData: PriceTick | undefined = aggregatedData.market.prices.get(symbol);
+    const currentPrice = this.extractPrice(priceData);
+
+    return { netSize, currentPrice };
+  }
+
+  private resolveEmergencyNetThreshold(currentPrice: number): number {
+    const configured = this.emergencyMitigationConfig?.netExposureThreshold;
+    if (configured && configured > 0) {
+      return configured;
+    }
+    if (currentPrice > 0) {
+      const minNotional = this.emergencyMitigationConfig?.minNotional ?? this.minOrderValue;
+      return Math.max(minNotional / currentPrice, 0.00001);
+    }
+    return 0.00001;
+  }
+
+  public clearEmergencyMitigation(): void {
+    if (this.emergencyReductionActive) {
+      this.logger.info('Emergency mitigation cleared, resuming normal exposure handling');
     }
+    this.emergencyReductionActive = false;
   }
 
   private selectAccountForExposureOpen(

+ 21 - 2
src/modules/TradingCycleManager.ts

@@ -9,7 +9,8 @@ import { SimpleStrategyEngine } from '../strategies/SimpleStrategyEngine';
 import { HedgingDecisionModule, HedgingDecision, TradingSignal } from '../core/HedgingDecisionModule';
 import { SignalExecutor } from '../services/SignalExecutor';
 import { OrderLifecycleManager } from '../services/OrderLifecycleManager';
-import { TradingPhaseManager, PhaseStatus } from './TradingPhaseManager';
+import { TradingPhaseManager, PhaseStatus, TradingPhase } from './TradingPhaseManager';
+import { MonitoringManager } from './MonitoringManager';
 
 export interface TradingCycleConfig {
   tradingInterval: number;
@@ -37,6 +38,7 @@ export class TradingCycleManager {
   private signalExecutor: SignalExecutor;
   private orderLifecycleManager: OrderLifecycleManager | null = null;
   private phaseManager: TradingPhaseManager | null = null;
+  private monitoringManager: MonitoringManager | null = null;
 
   // Cycle management
   private isRunning: boolean = false;
@@ -77,6 +79,10 @@ export class TradingCycleManager {
     this.phaseManager = components.phaseManager || null;
   }
 
+  public setMonitoringManager(monitoringManager: MonitoringManager | null): void {
+    this.monitoringManager = monitoringManager;
+  }
+
   /**
    * Start the trading cycle
    */
@@ -163,6 +169,8 @@ export class TradingCycleManager {
         const currentPrice = aggregatedData.market.prices.values().next().value?.midPrice || 0;
         phaseStatus = this.phaseManager.updatePhase(currentPrice);
 
+        this.strategyEngine.setTradingPhase(phaseStatus.currentPhase);
+
         this.logger.info('📊 Trading Phase Status', {
           phase: phaseStatus.currentPhase,
           netExposureBTC: phaseStatus.netExposureBTC.toFixed(5),
@@ -182,6 +190,17 @@ export class TradingCycleManager {
           this.stats.skippedCycles++;
           return;
         }
+
+        if (phaseStatus.currentPhase === TradingPhase.EMERGENCY_DELEVERAGE) {
+          this.logger.info('Emergency phase detected, strategy trades will be skipped this cycle');
+          await this.monitoringManager?.triggerEmergencyMitigation(phaseStatus.reason);
+        } else {
+          this.monitoringManager?.clearEmergencyMitigation();
+        }
+      }
+      if (!this.phaseManager) {
+        this.strategyEngine.setTradingPhase(TradingPhase.GRADUAL_BUILD);
+        this.monitoringManager?.clearEmergencyMitigation();
       }
 
       // Check if any account is in reduce mode
@@ -389,4 +408,4 @@ export class TradingCycleManager {
   public isCycleRunning(): boolean {
     return this.isRunning;
   }
-}
+}

+ 8 - 0
src/modules/TradingPhaseManager.ts

@@ -30,6 +30,14 @@ export interface PhaseConfig {
   emergencyMaxOrderSize: number;              // 紧急降仓阶段最大订单金额(USDC)
   neutralMaxOrderSize: number;                // 中性阶段最大订单金额(USDC)
   buildMaxOrderSize: number;                  // 建仓阶段最大订单金额(USDC)
+
+  emergencyMitigation?: {
+    enabled?: boolean;
+    reduceFraction?: number;
+    minNotional?: number;
+    cooldownMs?: number;
+    useMarketOrder?: boolean;
+  };
 }
 
 export interface PhaseStatus {

+ 155 - 104
src/services/SignalExecutor.ts

@@ -87,6 +87,7 @@ export class SignalExecutor extends EventEmitter {
   private clientMap: Map<string, PacificaSigningClient>;
   private lastOrderTime: number = 0;
   private phaseManager: TradingPhaseManager | null = null;
+  private rebalanceLocks: Set<string> = new Set();
 
   constructor(config?: Partial<ExecutorConfig>) {
     super();
@@ -138,7 +139,7 @@ export class SignalExecutor extends EventEmitter {
     const startTime = Date.now();
     let retryCount = 0;
     const requestedAmount = signal.amount;
-    const isRebalanceSignal = signal.metadata?.rebalance === true;
+    const isRebalanceSignal = this.isRebalanceSignal(signal);
 
     this.logger.info('Executing signal', {
       type: signal.type,
@@ -212,59 +213,65 @@ export class SignalExecutor extends EventEmitter {
     while (retryCount <= this.config.maxRetries) {
       try {
         if (shouldUseChunking) {
-          const chunkSummary = await this.executeRebalanceChunks(client, signal, requestedAmount);
-
-          const aggregatedSignal: TradingSignal = {
-            ...signal,
-            amount: chunkSummary.executedAmount,
-            metadata: {
-              ...signal.metadata,
-              originalAmount: requestedAmount,
-              executedAmount: chunkSummary.executedAmount,
-              executedInChunks: true,
-              chunkCount: chunkSummary.orderIds.length
+          await this.waitForRebalanceSlot(signal.symbol);
+          this.rebalanceLocks.add(signal.symbol);
+          try {
+            const chunkSummary = await this.executeRebalanceChunks(client, signal, requestedAmount);
+
+            const aggregatedSignal: TradingSignal = {
+              ...signal,
+              amount: chunkSummary.executedAmount,
+              metadata: {
+                ...signal.metadata,
+                originalAmount: requestedAmount,
+                executedAmount: chunkSummary.executedAmount,
+                executedInChunks: true,
+                chunkCount: chunkSummary.orderIds.length
+              }
+            };
+
+            const lastOrderId = chunkSummary.orderIds[chunkSummary.orderIds.length - 1];
+            const lastClientOrderId = chunkSummary.clientOrderIds[chunkSummary.clientOrderIds.length - 1];
+
+            if (!lastOrderId || !lastClientOrderId) {
+              throw new Error('Chunk execution completed without order identifiers');
             }
-          };
-
-          const lastOrderId = chunkSummary.orderIds[chunkSummary.orderIds.length - 1];
-          const lastClientOrderId = chunkSummary.clientOrderIds[chunkSummary.clientOrderIds.length - 1];
-
-          if (!lastOrderId || !lastClientOrderId) {
-            throw new Error('Chunk execution completed without order identifiers');
-          }
-
-          const resultInfo = {
-            orderId: lastOrderId,
-            clientOrderId: lastClientOrderId,
-            orderIds: chunkSummary.orderIds,
-            clientOrderIds: chunkSummary.clientOrderIds,
-            submittedAmount: chunkSummary.executedAmount
-          };
 
-          this.logger.info('Signal executed successfully (chunked)', {
-            signal: aggregatedSignal,
-            chunkCount: chunkSummary.orderIds.length,
-            requestedAmount,
-            perOrderAmount: signal.amount.toFixed(5)
-          });
+            const resultInfo = {
+              orderId: lastOrderId,
+              clientOrderId: lastClientOrderId,
+              orderIds: chunkSummary.orderIds,
+              clientOrderIds: chunkSummary.clientOrderIds,
+              submittedAmount: chunkSummary.executedAmount
+            };
+
+            this.logger.info('Signal executed successfully (chunked)', {
+              signal: aggregatedSignal,
+              chunkCount: chunkSummary.orderIds.length,
+              requestedAmount,
+              perOrderAmount: signal.amount.toFixed(5)
+            });
 
-          this.emit('execution_success', {
-            signal: aggregatedSignal,
-            result: resultInfo,
-            retryCount,
-            duration: Date.now() - startTime
-          });
+            this.emit('execution_success', {
+              signal: aggregatedSignal,
+              result: resultInfo,
+              retryCount,
+              duration: Date.now() - startTime
+            });
 
-          return {
-            success: true,
-            signal: aggregatedSignal,
-            orderId: lastOrderId,
-            clientOrderId: lastClientOrderId,
-            orderIds: resultInfo.orderIds,
-            clientOrderIds: resultInfo.clientOrderIds,
-            timestamp: Date.now(),
-            retryCount
-          };
+            return {
+              success: true,
+              signal: aggregatedSignal,
+              orderId: lastOrderId,
+              clientOrderId: lastClientOrderId,
+              orderIds: resultInfo.orderIds,
+              clientOrderIds: resultInfo.clientOrderIds,
+              timestamp: Date.now(),
+              retryCount
+            };
+          } finally {
+            this.rebalanceLocks.delete(signal.symbol);
+          }
         }
 
         // 控制订单间隔
@@ -313,6 +320,9 @@ export class SignalExecutor extends EventEmitter {
         };
 
       } catch (error) {
+        if (shouldUseChunking) {
+          this.rebalanceLocks.delete(signal.symbol);
+        }
         retryCount++;
         const errorMessage = error instanceof Error ? error.message : 'Unknown error';
 
@@ -462,9 +472,27 @@ export class SignalExecutor extends EventEmitter {
 
       const result1 = await this.executeSignal(signal1);
 
+      if (!result1.success) {
+        this.logger.warn('⏹️ 对冲对首腿执行失败,跳过另一条腿', {
+          accountId: signal1.accountId,
+          side: signal1.side,
+          error: result1.error
+        });
+
+        results.push(result1, {
+          success: false,
+          signal: signal2,
+          error: 'Skipped because paired leg failed to execute',
+          timestamp: Date.now(),
+          retryCount: 0
+        });
+
+        continue;
+      }
+
       // 🔄 如果signal1的金额被调整了,同步调整signal2的金额以确保匹配
       let adjustedSignal2 = signal2;
-      if (result1.success && result1.signal.amount !== signal1.amount) {
+      if (result1.signal.amount !== signal1.amount) {
         this.logger.warn('🔄 对冲对金额同步调整', {
           originalSignal1Amount: signal1.amount,
           adjustedSignal1Amount: result1.signal.amount,
@@ -480,62 +508,47 @@ export class SignalExecutor extends EventEmitter {
 
       const result2 = await this.executeSignal(adjustedSignal2);
 
-      // 检查原子性: 必须都成功或都失败
-      if (result1.success && result2.success) {
-        // ✅ 双方都成功 - 对冲完成
+      if (result2.success) {
         this.logger.info('✅ 对冲对执行成功', {
           signal1Result: result1.orderId,
           signal2Result: result2.orderId
         });
         results.push(result1, result2);
-      } else if (!result1.success && !result2.success) {
-        // ⚠️  双方都失败 - 无敞口风险
-        this.logger.warn('⚠️  对冲对都失败 (无敞口风险)', {
-          signal1Error: result1.error,
-          signal2Error: result2.error
-        });
-        results.push(result1, result2);
-      } else {
-        // ❌ 部分成功 - 敞口暴露! 需要回滚
-        const successResult = result1.success ? result1 : result2;
-        const failedResult = result1.success ? result2 : result1;
-        const failedSignal = result1.success ? signal2 : signal1;
-
-        this.logger.error('🚨 对冲对部分成功 - 敞口暴露!', {
-          successOrder: successResult.orderId,
-          failedSignal: `${failedSignal.accountId} ${failedSignal.side}`,
-          error: failedResult.error
-        });
+        continue;
+      }
 
-        // 🔄 尝试取消成功的订单以避免敞口
-        if (successResult.orderId) {
-          try {
-            const successSignal = successResult.signal ?? (result1.success ? signal1 : signal2);
-            const client = successSignal ? this.clientMap.get(successSignal.accountId) : undefined;
-            if (client) {
-              this.logger.warn('🔄 尝试取消单边成功订单', { orderId: successResult.orderId });
-              const cancelSymbol = successSignal?.symbol ?? signal1.symbol;
-              await client.cancelOrder(successResult.orderId, cancelSymbol);
-              this.logger.info('✅ 单边订单已取消 - 避免敞口');
-
-              // 标记为失败
-              results.push({
-                ...successResult,
-                success: false,
-                error: 'Cancelled due to hedging pair atomicity failure'
-              }, failedResult);
-            }
-          } catch (cancelError: any) {
-            this.logger.error('❌ 无法取消单边订单 - 敞口已暴露!', {
-              orderId: successResult.orderId,
-              error: cancelError.message
-            });
-            results.push(successResult, failedResult);
+      this.logger.error('🚨 对冲对部分成功 - 敞口暴露!', {
+        successOrder: result1.orderId,
+        failedSignal: `${signal2.accountId} ${signal2.side}`,
+        error: result2.error
+      });
+
+      if (result1.orderId) {
+        try {
+          const successSignal = result1.signal ?? signal1;
+          const client = this.clientMap.get(successSignal.accountId);
+          if (client) {
+            this.logger.warn('🔄 尝试取消单边成功订单', { orderId: result1.orderId });
+            const cancelSymbol = successSignal.symbol ?? signal1.symbol;
+            await client.cancelOrder(result1.orderId, cancelSymbol);
+            this.logger.info('✅ 单边订单已取消 - 避免敞口');
+
+            results.push({
+              ...result1,
+              success: false,
+              error: 'Cancelled due to hedging pair atomicity failure'
+            }, result2);
+            continue;
           }
-        } else {
-          results.push(successResult, failedResult);
+        } catch (cancelError: any) {
+          this.logger.error('❌ 无法取消单边订单 - 敞口已暴露!', {
+            orderId: result1.orderId,
+            error: cancelError.message
+          });
         }
       }
+
+      results.push(result1, result2);
     }
 
     // 执行非配对信号
@@ -576,6 +589,14 @@ export class SignalExecutor extends EventEmitter {
     requestedAmount: number
   ): Promise<ChunkExecutionSummary> {
     const chunkAmount = Math.abs(baseSignal.amount);
+    const LOT_SIZE = 0.00001;
+
+    const floorToLot = (value: number): number => {
+      if (!Number.isFinite(value)) {
+        return 0;
+      }
+      return Math.floor(value / LOT_SIZE) * LOT_SIZE;
+    };
 
     if (!Number.isFinite(chunkAmount) || chunkAmount <= 0) {
       throw new Error('Invalid chunk amount for rebalance execution');
@@ -606,10 +627,22 @@ export class SignalExecutor extends EventEmitter {
 
     while (remaining > epsilon) {
       const amountForChunk = Math.min(chunkAmount, remaining);
-      const roundedAmount = Math.floor(amountForChunk * 100000) / 100000;
+      let roundedAmount = floorToLot(amountForChunk);
 
       if (roundedAmount <= 0) {
-        throw new Error('Calculated chunk amount rounded to zero, aborting to avoid infinite loop');
+        const remainingRounded = floorToLot(remaining);
+        if (remainingRounded > 0) {
+          roundedAmount = remainingRounded;
+        } else {
+          this.logger.info('Remaining exposure below minimum lot size, skipping final chunk', {
+            remaining,
+            lotSize: LOT_SIZE,
+            signalType: baseSignal.type,
+            reason: baseSignal.reason
+          });
+          remaining = 0;
+          break;
+        }
       }
 
       const chunkSignal: TradingSignal = {
@@ -641,7 +674,7 @@ export class SignalExecutor extends EventEmitter {
       }
     }
 
-    if (orderIds.length === 0 || clientOrderIds.length === 0) {
+    if ((orderIds.length === 0 || clientOrderIds.length === 0) && executed <= 0) {
       throw new Error('No orders were placed during rebalance chunk execution');
     }
 
@@ -668,9 +701,11 @@ export class SignalExecutor extends EventEmitter {
   ): Promise<{ orderId: string; clientOrderId: string; submittedAmount: number }> {
     const clientOrderId = uuidv4(); // 使用标准UUID格式,符合Pacifica API要求
 
+    const isRebalanceSignal = this.isRebalanceSignal(signal);
+
     const shouldBypassValueLimit =
       this.config.allowBypassMaxOrderValue &&
-      (signal.type === 'balance' || signal.type === 'reduce');
+      (signal.type === 'balance' || signal.type === 'reduce' || isRebalanceSignal);
 
     const maxValue = this.config.maxOrderValue;
 
@@ -801,6 +836,20 @@ export class SignalExecutor extends EventEmitter {
     throw new Error(`Invalid signal: neither market order nor limit order with price`);
   }
 
+  private isRebalanceSignal(signal: TradingSignal): boolean {
+    if (signal.metadata?.rebalance === true) {
+      return true;
+    }
+    const reason = signal.reason?.toLowerCase() ?? '';
+    return reason.includes('rebalance');
+  }
+
+  private async waitForRebalanceSlot(symbol: string): Promise<void> {
+    while (this.rebalanceLocks.has(symbol)) {
+      await this.sleep(50);
+    }
+  }
+
   /**
    * 调整订单金额以符合限制
    *
@@ -815,14 +864,16 @@ export class SignalExecutor extends EventEmitter {
     client: PacificaSigningClient
   ): Promise<TradingSignal> {
     // 如果未配置限额,则不调整
+    const isRebalance = this.isRebalanceSignal(signal);
     const bypass =
       this.config.allowBypassMaxOrderValue &&
-      (signal.type === 'balance' || signal.type === 'reduce');
+      (signal.type === 'balance' || signal.type === 'reduce' || isRebalance);
 
     this.logger.info('🔍 Bypass check', {
       signalType: signal.type,
       allowBypassMaxOrderValue: this.config.allowBypassMaxOrderValue,
       isBalanceOrReduce: signal.type === 'balance' || signal.type === 'reduce',
+      isRebalance,
       bypass,
       willSkipAdjustment: (!this.config.maxOrderValue && !this.config.maxOrderValueRatio) || bypass
     });
@@ -831,7 +882,7 @@ export class SignalExecutor extends EventEmitter {
       this.logger.info('✅ Bypassing amount adjustment', {
         signalType: signal.type,
         amount: signal.amount,
-        reason: bypass ? 'bypass enabled for balance/reduce' : 'no limits configured'
+        reason: bypass ? 'bypass enabled for balance/reduce/rebalance' : 'no limits configured'
       });
       return signal;
     }

+ 14 - 1
src/strategies/ModularDeltaNeutralStrategy.ts

@@ -61,8 +61,13 @@ export class ModularDeltaNeutralStrategy {
 
       // 3. Initialize core components
       console.log('\n📡 Initializing core components...');
+      const executionConfig = this.configManager.getExecutionConfig();
+      const monitoringSettings = this.configManager.getMonitoringSettings();
+
       const coreComponents = await this.componentInitializer.initializeCoreComponents(
         deltaConfig,
+        executionConfig,
+        monitoringSettings,
         this.accountManager,
         tradingSymbol
       );
@@ -181,7 +186,13 @@ export class ModularDeltaNeutralStrategy {
           ...deltaConfig.exposureControl
         },
         dynamicTPSL: dynamicTPSLConfig,
-        tradingSymbol
+        tradingSymbol,
+        utilizationThresholds: monitoringSettings.utilizationThresholds,
+        minOrderValue: executionConfig.minOrderValue,
+        effectiveLeverage: monitoringSettings.effectiveLeverage,
+        ...(deltaConfig.phaseManagement?.emergencyMitigation
+          ? { emergencyMitigation: deltaConfig.phaseManagement.emergencyMitigation }
+          : {})
       };
 
       this.monitoringManager = new MonitoringManager(
@@ -194,6 +205,8 @@ export class ModularDeltaNeutralStrategy {
         }
       );
 
+      this.tradingCycleManager.setMonitoringManager(this.monitoringManager);
+
       await this.monitoringManager.initialize();
 
       // 10. Setup signal executor event handlers

+ 131 - 281
src/strategies/SimpleStrategyEngine.ts

@@ -13,7 +13,9 @@ import { DualAccountCoordinator } from '../services/DualAccountCoordinator';
 import { OrderSizeOptimizer } from '../services/OrderSizeOptimizer';
 import { TimingOptimizer } from '../services/TimingOptimizer';
 import { AdvancedPricingOptimizer } from '../services/AdvancedPricingOptimizer';
-import { EnhancedDeltaController, PositionData } from '../services/EnhancedDeltaController';
+import { EnhancedDeltaController } from '../services/EnhancedDeltaController';
+import { AccountManager, AccountUtilizationMetrics } from '../modules/AccountManager';
+import { TradingPhase } from '../modules/TradingPhaseManager';
 
 export interface StrategyConfig {
   symbol: string;
@@ -21,6 +23,18 @@ export interface StrategyConfig {
   volumeTargetPerCycle: number;
 }
 
+export interface UtilizationThresholds {
+  build: number;
+  reduce: number;
+}
+
+interface StrategyOptions {
+  accountManager?: AccountManager;
+  utilizationThresholds?: UtilizationThresholds;
+  minOrderValue?: number;
+  effectiveLeverage?: number;
+}
+
 export interface Sprint1Components {
   pricingEngine: PricingEngine;
   orderLifecycleManager: OrderLifecycleManager;
@@ -37,6 +51,11 @@ export interface Sprint2Components {
 export class SimpleStrategyEngine {
   private logger: Logger;
   private config: StrategyConfig;
+  private accountManager: AccountManager | null = null;
+  private utilizationThresholds: UtilizationThresholds = { build: 0.6, reduce: 0.8 };
+  private minOrderValue: number = 30;
+  private effectiveLeverage: number = 1;
+  private currentPhase: TradingPhase = TradingPhase.GRADUAL_BUILD;
 
   // Sprint 1 components
   private pricingEngine: PricingEngine | null = null;
@@ -49,13 +68,23 @@ export class SimpleStrategyEngine {
   private advancedPricingOptimizer: AdvancedPricingOptimizer | null = null;
   private enhancedDeltaController: EnhancedDeltaController | null = null;
 
-  constructor(config: Partial<StrategyConfig>) {
+  constructor(config: Partial<StrategyConfig>, options?: StrategyOptions) {
     this.logger = Logger.getInstance();
     this.config = {
       symbol: config.symbol || 'BTC',
       positionDiffThreshold: config.positionDiffThreshold || 0.05,
       volumeTargetPerCycle: config.volumeTargetPerCycle || 0.001
     };
+    this.accountManager = options?.accountManager ?? null;
+    if (options?.utilizationThresholds) {
+      this.utilizationThresholds = options.utilizationThresholds;
+    }
+    if (options?.minOrderValue) {
+      this.minOrderValue = options.minOrderValue;
+    }
+    if (options?.effectiveLeverage && options.effectiveLeverage > 0) {
+      this.effectiveLeverage = options.effectiveLeverage;
+    }
   }
 
   /**
@@ -100,12 +129,21 @@ export class SimpleStrategyEngine {
     }
   }
 
+  public setTradingPhase(phase: TradingPhase): void {
+    this.currentPhase = phase;
+  }
+
   /**
    * Generate trading signals based on aggregated data
    */
   public async generateSignals(aggregatedData: any): Promise<TradingSignal[]> {
     const signals: TradingSignal[] = [];
 
+    if (this.currentPhase === TradingPhase.EMERGENCY_DELEVERAGE) {
+      this.logger.info('Emergency phase active, skipping new open signals');
+      return signals;
+    }
+
     // Get market price
     const btcPrice = aggregatedData.market.prices.get(this.config.symbol);
     if (!btcPrice) {
@@ -156,18 +194,39 @@ export class SimpleStrategyEngine {
       calculatedPrice
     );
 
-    // Check for position rebalancing
-    const rebalanceSignal = this.checkDeltaRebalance(
-      accounts,
-      currentPrice,
-      calculatedPrice,
-      optimizedAmount
-    );
+    const utilizationContext = this.getUtilizationContext();
+
+    this.logger.debug('Utilization context', {
+      regime: utilizationContext.regime,
+      maxUtilization: utilizationContext.metrics.maxUtilization.toFixed(3),
+      baseEquity: utilizationContext.metrics.baseEquity,
+      baseAvailable: utilizationContext.metrics.baseAvailable,
+      baseEffectiveEquity: utilizationContext.metrics.baseEffectiveEquity,
+      baseEffectiveAvailable: utilizationContext.metrics.baseEffectiveAvailable,
+      effectiveEquity: utilizationContext.metrics.effectiveEquity,
+      effectiveAvailable: utilizationContext.metrics.effectiveAvailable,
+      leverage: this.effectiveLeverage
+    });
+
+    if (utilizationContext.regime === 'reduce') {
+      this.logger.info('Utilization in reduce regime, skipping open signals');
+      return [];
+    }
+
+    optimizedAmount = this.clampAmountForRegime(optimizedAmount, currentPrice, utilizationContext);
 
-    if (rebalanceSignal) {
-      return [rebalanceSignal];
+    const LOT_SIZE = 0.00001;
+    if (optimizedAmount < LOT_SIZE) {
+      this.logger.debug('Optimized amount below minimum lot after utilization clamp', {
+        optimizedAmount,
+        regime: utilizationContext.regime
+      });
+      return [];
     }
 
+
+    // 由敞口监控模块负责再平衡
+
     // Generate normal trading signal
     signals.push({
       type: 'open',
@@ -275,293 +334,84 @@ export class SimpleStrategyEngine {
     return optimizedAmount;
   }
 
-  /**
-   * Check if delta rebalancing is needed
-   */
-  private checkDeltaRebalance(
-    accounts: any[],
-    currentPrice: number,
-    calculatedPrice: number,
-    _optimizedAmount: number
-  ): TradingSignal | null {
-    if (!this.enhancedDeltaController) {
-      return null;
-    }
-
-    // Calculate total position across accounts and track per-account exposure / margin usage
-    let totalPositionBTC = 0;
-    const accountExposures = new Map<string, number>();
-    const accountMarginUtil = new Map<string, number>();
-
-    for (const account of accounts) {
-      const positions = account.positions || [];
-      let accountExposure = 0;
-
-      for (const pos of positions) {
-        if (pos.symbol === this.config.symbol) {
-          const rawSize =
-            typeof pos.amount === 'number'
-              ? pos.amount
-              : typeof pos.size === 'number'
-                ? pos.size
-                : 0;
-
-          const magnitude = Math.abs(rawSize);
-          const signedSize = pos.side === 'bid' ? magnitude : -magnitude;
-
-          totalPositionBTC += signedSize;
-          accountExposure += signedSize;
-        }
-      }
-
-      if (account.accountId) {
-        accountExposures.set(account.accountId, accountExposure);
-
-        const balance = account.balance;
-        let utilization = 0;
-        if (balance && typeof balance.total === 'number' && balance.total > 0) {
-          const available = typeof balance.available === 'number' ? balance.available : balance.total;
-          utilization = Math.min(Math.max(1 - available / balance.total, 0), 1);
-        }
-        accountMarginUtil.set(account.accountId, utilization);
-      }
-    }
-
-    // Record current position
-    const currentPositionData: PositionData = {
-      symbol: this.config.symbol,
-      size: totalPositionBTC,
-      value: totalPositionBTC * currentPrice,
-      timestamp: Date.now()
+  private getUtilizationContext(): { regime: 'build' | 'balance' | 'reduce'; metrics: AccountUtilizationMetrics } {
+    const defaultMetrics: AccountUtilizationMetrics = {
+      baseEquity: 0,
+      baseAvailable: 0,
+      baseEffectiveEquity: 0,
+      baseEffectiveAvailable: 0,
+      effectiveEquity: 0,
+      effectiveAvailable: 0,
+      leverageMultiplier: this.effectiveLeverage,
+      maxUtilization: 0,
+      minUtilization: 0,
+      perAccount: []
     };
 
-    this.enhancedDeltaController.recordPrice(this.config.symbol, currentPrice);
-
-    // Assess delta
-    const deltaAssessment = this.enhancedDeltaController.assessDelta(
-      this.config.symbol,
-      currentPositionData
-    );
-
-    // ✅ 使用绝对阈值检测(更精确,防止小敞口被忽略)
-    const ABSOLUTE_THRESHOLD_BTC = 0.0001; // 0.0001 BTC ≈ $10 USDC
-    const absoluteExposure = Math.abs(totalPositionBTC);
-    const shouldRebalance = absoluteExposure > ABSOLUTE_THRESHOLD_BTC;
-
-    // 🔍 增强 Delta 评估日志(始终输出,便于诊断)
-    this.logger.info('📊 Delta Assessment', {
-      symbol: this.config.symbol,
-      totalPositionBTC: totalPositionBTC.toFixed(5),
-      positionValueUSDC: (totalPositionBTC * currentPrice).toFixed(2),
-      absoluteExposure: absoluteExposure.toFixed(5) + ' BTC',
-      absoluteThreshold: ABSOLUTE_THRESHOLD_BTC.toFixed(5) + ' BTC',
-      shouldRebalance: shouldRebalance ? '⚠️  YES' : '✅ NO',
-      weightedDelta: (deltaAssessment.weightedDelta * 100).toFixed(4) + '%',
-      currentTolerance: (deltaAssessment.currentTolerance * 100).toFixed(4) + '%',
-      recommendation: deltaAssessment.recommendation
-    });
-
-    // Generate rebalance signal if absolute threshold exceeded
-    if (shouldRebalance) {
-      // ✅ 100% 对冲整个敞口(而非 50%)
-      const balanceSide: 'bid' | 'ask' = totalPositionBTC > 0 ? 'ask' : 'bid';
-
-      let maxUtilization = 0;
-      for (const util of accountMarginUtil.values()) {
-        maxUtilization = Math.max(maxUtilization, util);
-      }
-
-      const SHOULD_OPEN = maxUtilization < 0.5;
-      let balancePrice = calculatedPrice;
-
-      if (SHOULD_OPEN) {
-        // Open additional opposing position instead of reducing, to maintain delta neutrality without shrinking exposure.
-        const targetAccountId = this.selectAccountForOpening(accountExposures, accountMarginUtil, totalPositionBTC);
-        if (!targetAccountId) {
-          this.logger.warn('Unable to determine account for delta rebalance (open path)', {
-            totalPositionBTC: totalPositionBTC.toFixed(5),
-            exposures: Array.from(accountExposures.entries()).map(([id, exp]) => ({ id, exposure: exp.toFixed(5) }))
-          });
-          return null;
-        }
-
-        const openSide: 'bid' | 'ask' = totalPositionBTC > 0 ? 'ask' : 'bid';
-        const openAmount = absoluteExposure;
-
-        const openSignal: TradingSignal = {
-          type: 'open',
-          accountId: targetAccountId,
-          symbol: this.config.symbol,
-          side: openSide,
-          amount: openAmount,
-          price: balancePrice,
-          useMarketOrder: true,
-          reason: `Delta rebalance via additional ${openSide} (util ${maxUtilization.toFixed(2)})`,
-          timestamp: Date.now(),
-          metadata: {
-            positionDiff: totalPositionBTC,
-            rebalance: true
-          }
-        };
-
-        this.logger.warn('⚖️ DELTA EXCEEDS THRESHOLD - Opening counter position for rebalance', {
-          totalPositionBTC: totalPositionBTC.toFixed(5),
-          absoluteExposure: absoluteExposure.toFixed(5) + ' BTC',
-          threshold: ABSOLUTE_THRESHOLD_BTC.toFixed(5) + ' BTC',
-          side: openSide,
-          targetAccount: targetAccountId,
-          marginUtilization: maxUtilization.toFixed(3)
-        });
-
-        return openSignal;
-      }
-
-      // Reduce-only path when margin utilization is high
-      const balanceAccountId = this.selectAccountForReduction(accountExposures, accounts, totalPositionBTC);
-
-      if (!balanceAccountId) {
-        this.logger.warn('Unable to determine account for delta rebalance (reduce path)', {
-          totalPositionBTC: totalPositionBTC.toFixed(5),
-          exposures: Array.from(accountExposures.entries()).map(([id, exp]) => ({ id, exposure: exp.toFixed(5) }))
-        });
-        return null;
-      }
-
-      const accountExposure = accountExposures.get(balanceAccountId) ?? 0;
-      const balanceAmount = Math.min(absoluteExposure, Math.abs(accountExposure));
-
-      const MIN_ORDER_SIZE = 0.00001;
-      if (balanceAmount < MIN_ORDER_SIZE) {
-        this.logger.info('Delta exposure below minimum order size, skipping rebalance', {
-          totalPositionBTC: totalPositionBTC.toFixed(5),
-          balanceAccountId,
-          balanceAmount: balanceAmount.toFixed(5)
-        });
-        return null;
-      }
-
-      // 🚀 对于 balance 信号,使用更激进的 taker 价格以确保快速成交
-      // bid (买入): 使用 ask 价格 (支付更高价格)
-      // ask (卖出): 使用 bid 价格 (接受更低价格)
-      if (this.pricingEngine) {
-        if (balanceSide === 'bid') {
-          // 买入:使用卖单价格(高于市场价)以确保成交
-          const askPrice = this.pricingEngine.calculateAskPrice(this.config.symbol);
-          if (askPrice) {
-            balancePrice = askPrice.price;
-            this.logger.info('🚀 Using aggressive taker price for balance signal', {
-              side: balanceSide,
-              makerPrice: calculatedPrice,
-              takerPrice: balancePrice,
-              reason: 'Quick execution for delta rebalance'
-            });
-          }
-        } else {
-          // 卖出:使用买单价格(低于市场价)以确保成交
-          const bidPrice = this.pricingEngine.calculateBidPrice(this.config.symbol);
-          if (bidPrice) {
-            balancePrice = bidPrice.price;
-            this.logger.info('🚀 Using aggressive taker price for balance signal', {
-              side: balanceSide,
-              makerPrice: calculatedPrice,
-              takerPrice: balancePrice,
-              reason: 'Quick execution for delta rebalance'
-            });
-          }
-        }
-      }
-
-      const signal: TradingSignal = {
-        type: 'reduce',
-        accountId: balanceAccountId,
-        symbol: this.config.symbol,
-        side: balanceSide,
-        amount: balanceAmount,
-        price: balancePrice,  // 使用 taker 价格
-        useMarketOrder: true,  // 🚀 使用市价单确保成交
-        reason: `Absolute delta rebalance: exposure=${absoluteExposure.toFixed(5)} BTC > threshold=${ABSOLUTE_THRESHOLD_BTC.toFixed(5)} BTC`,
-        timestamp: Date.now(),
-        metadata: {
-          positionDiff: totalPositionBTC
-        }
-      };
-
-      this.logger.warn('⚖️ DELTA EXCEEDS ABSOLUTE THRESHOLD - Generating 100% rebalance signal', {
-        totalPositionBTC: totalPositionBTC.toFixed(5),
-        absoluteExposure: absoluteExposure.toFixed(5) + ' BTC',
-        threshold: ABSOLUTE_THRESHOLD_BTC.toFixed(5) + ' BTC',
-        balanceAmount: balanceAmount.toFixed(5) + ' BTC',
-        balanceSide,
-        targetAccount: balanceAccountId
-      });
+    if (!this.accountManager) {
+      return { regime: 'build', metrics: defaultMetrics };
+    }
 
-      return signal;
+    const metrics = this.accountManager.getUtilizationMetrics(this.effectiveLeverage);
+    const build = this.utilizationThresholds.build;
+    const reduce = this.utilizationThresholds.reduce;
+
+    let regime: 'build' | 'balance' | 'reduce';
+    if (metrics.maxUtilization >= reduce) {
+      regime = 'reduce';
+    } else if (metrics.maxUtilization >= build) {
+      regime = 'balance';
+    } else {
+      regime = 'build';
     }
 
-    return null;
+    return { regime, metrics };
   }
 
-  private selectAccountForOpening(
-    exposures: Map<string, number>,
-    marginUtil: Map<string, number>,
-    totalPositionBTC: number
-  ): string | null {
-    let selectedId: string | null = null;
-    let comparator = totalPositionBTC > 0 ? Infinity : -Infinity;
-
-    for (const [accountId, exposure] of exposures.entries()) {
-      const util = marginUtil.get(accountId) ?? 0;
-      if (util >= 0.95) {
-        continue;
-      }
+  private clampAmountForRegime(
+    amount: number,
+    currentPrice: number,
+    context: { regime: 'build' | 'balance' | 'reduce'; metrics: AccountUtilizationMetrics }
+  ): number {
+    if (currentPrice <= 0) {
+      return amount;
+    }
 
-      if (totalPositionBTC > 0) {
-        // Net long → prefer accounts already short (negative exposure) or with smallest long
-        if (selectedId === null || exposure < comparator) {
-          selectedId = accountId;
-          comparator = exposure;
-        }
-      } else {
-        // Net short → prefer accounts already long (positive exposure) or smallest short
-        if (selectedId === null || exposure > comparator) {
-          selectedId = accountId;
-          comparator = exposure;
-        }
-      }
+    const baseAvailable = context.metrics.baseEffectiveAvailable;
+    if (baseAvailable <= 0) {
+      return amount;
     }
 
-    return selectedId;
-  }
+    const lotSize = 0.00001;
+    let ratio = context.regime === 'balance' ? 0.25 : 0.4;
+    if (context.regime === 'reduce') {
+      ratio = 0.1;
+    }
 
-  private selectAccountForReduction(
-    exposures: Map<string, number>,
-    accounts: any[],
-    totalPositionBTC: number
-  ): string | null {
-    let balanceAccountId: string | null = null;
-    let maxAccountExposure = 0;
-
-    for (const [accountId, exposure] of exposures.entries()) {
-      if (totalPositionBTC > 0 && exposure > 0 && exposure > maxAccountExposure) {
-        maxAccountExposure = exposure;
-        balanceAccountId = accountId;
-      } else if (totalPositionBTC < 0 && exposure < 0 && Math.abs(exposure) > maxAccountExposure) {
-        maxAccountExposure = Math.abs(exposure);
-        balanceAccountId = accountId;
-      }
+    const maxNotional = Math.max(baseAvailable * ratio, 0);
+    if (maxNotional <= 0) {
+      return amount;
+    }
+    const maxAmount = Math.floor((maxNotional / currentPrice) / lotSize) * lotSize;
+    if (maxAmount <= 0) {
+      return amount;
     }
 
-    if (!balanceAccountId) {
-      const primaryAccount = accounts[0];
-      const secondaryAccount = accounts[1];
-      balanceAccountId = totalPositionBTC > 0
-        ? primaryAccount?.accountId ?? null
-        : secondaryAccount?.accountId ?? null;
+    const minNotional = this.minOrderValue;
+    const minAmount = Math.ceil((minNotional / currentPrice) / lotSize) * lotSize;
+    if (maxAmount < minAmount) {
+      return 0;
     }
 
-    return balanceAccountId;
+    const clamped = Math.min(Math.max(amount, minAmount), maxAmount);
+    return clamped;
   }
 
+  /**
+   * Check if delta rebalancing is needed
+   */
+
+
   /**
    * Get configuration
    */