Administrator
4 days ago 04063bcb7b9e9d8e0242c1313f54ccc1b71f0b6e
src/main/java/com/xcong/excoin/modules/okxApi/OkxWebSocketClientManager.java
@@ -1,7 +1,7 @@
package com.xcong.excoin.modules.okxApi;
import com.xcong.excoin.modules.okxApi.wsHandler.handler.MarkPriceOkxChannelHandler;
import com.xcong.excoin.modules.okxApi.wsHandler.handler.OrderAlgoOkxChannelHandler;
import com.xcong.excoin.modules.okxApi.wsHandler.handler.OrdersOkxChannelHandler;
import com.xcong.excoin.modules.okxApi.wsHandler.handler.PositionsOkxChannelHandler;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
@@ -11,28 +11,55 @@
import java.math.BigDecimal;
/**
 * OKX 模块 Spring 容器入口 — 组件组装 + 生命周期管理。
 * OKX 盈利回收策略 — 唯一入口,所有参数集中在此。
 *
 * <h3>组装顺序({@code @PostConstruct})</h3>
 * <ol>
 *   <li>{@link OkxConfig} — 构建配置(API 密钥、合约、策略参数)</li>
 *   <li>{@link OkxGridTradeService} — init():切双向持仓 → 清旧条件单 → 平仓 → 设杠杆</li>
 *   <li>{@link OkxKlineWebSocketClient} — 注册 3 个频道处理器 → init():建立 WS 连接并订阅</li>
 *   <li>{@code gridTradeService.startGrid()} — 状态重置,等待首根 K 线</li>
 * </ol>
 * <pre>
 * ┌─────────────────────────────────────────────────────────────────┐
 * │                     🔧 全部参数在此修改                          │
 * ├──────────────────┬──────────────────────────────────────────────┤
 * │ 参数名            │ 值                                  │ 说明    │
 * ├──────────────────┼──────────────────────────────────────┼────────┤
 * │ apiKey           │ ac76252d-...                         │ API密钥 │
 * │ apiSecret        │ A8168543...                          │ 签名密钥│
 * │ passphrase       │ Aa12345678@                          │ 口令密码│
 * ├──────────────────┼──────────────────────────────────────┼────────┤
 * │ contract         │ BTC-USDT-SWAP                        │ 交易合约│
 * │ leverage         │ 50                                   │ 杠杆倍数│
 * │ baseQuantity     │ 10                                   │ 底仓张数│
 * ├──────────────────┼──────────────────────────────────────┼────────┤
 * │ profitTriggerRatio│ 0.5                                 │ 触发ROI │
 * │ reinvestRatio    │ 0.5                                  │ 补仓比例│
 * ├──────────────────┼──────────────────────────────────────┼────────┤
 * │ maxPositionMult  │ 10  (= base×10 = 100张上限)          │ 风控1   │
 * │ maxLoss          │ 15 USDT                              │ 风控2   │
 * │ equityRestartRatio│ 0.05 (= 5%)                         │ 风控3   │
 * ├──────────────────┼──────────────────────────────────────┼────────┤
 * │ contractMult     │ 0.01        (BTC 每张0.01个币)        │ 合约乘数│
 * │ priceScale       │ 2           (价格精度0.01)            │ 价格精度│
 * │ pnlPriceMode     │ LAST_PRICE                           │ 盈亏计价│
 * │ isProduction     │ false       (false=模拟盘)            │ 交易环境│
 * └──────────────────┴──────────────────────────────────────────────┘
 * </pre>
 *
 * <h3>3 个频道处理器</h3>
 * <ol>
 *   <li>MarkPriceOkxChannelHandler — 公开频道,标记价格 → onKline() + setMarkPrice()</li>
 *   <li>PositionsOkxChannelHandler — 私有频道,仓位 → onPositionUpdate()</li>
 *   <li>OrderAlgoOkxChannelHandler — 私有频道,条件单状态 → onAutoOrder()</li>
 * </ol>
 * <h3>策略核心公式</h3>
 * <ul>
 *   <li>保证金 = 张数 × 合约乘数 × 开仓均价 / 杠杆</li>
 *   <li>ROI = 未实现盈亏 / 该方向保证金</li>
 *   <li>触发条件:ROI ≥ profitTriggerRatio</li>
 *   <li>平仓:floor(盈利仓位张数 / 2)</li>
 *   <li>补仓保证金 B = 已实现利润 × reinvestRatio</li>
 *   <li>单张保证金 = 合约乘数 × 开仓均价 / 杠杆</li>
 *   <li>补仓张数 = max(baseQuantity, floor(B / 单张保证金))</li>
 * </ul>
 *
 * <h3>销毁顺序({@code @PreDestroy})</h3>
 * <ol>
 *   <li>gridTradeService.stopGrid():取消所有条件单 → 关闭交易线程池</li>
 *   <li>wsClient.destroy():取消订阅 → 断开 WS → 关闭线程池</li>
 * </ol>
 * <h3>仓位演化示例 (BTC-USDT-SWAP, 50x, base10)</h3>
 * <pre>
 *   初始: LONG=10  SHORT=10
 *   多盈: LONG=5   SHORT=12
 *   多盈: LONG=3   SHORT=15
 *   多盈: LONG=2   SHORT=18
 *   → 权益达+5% → 全平重置 → LONG=10 SHORT=10
 * </pre>
 *
 * @author Administrator
 */
@@ -40,78 +67,117 @@
@Component
public class OkxWebSocketClientManager {
    // ╔══════════════════════════════════════════════════════════════╗
    // ║                  🔐 OKX API 认证信息                         ║
    // ╚══════════════════════════════════════════════════════════════╝
    private static final String OKX_API_KEY       = "ac76252d-e717-4459-a6f9-80512aed5ea0";
    private static final String OKX_API_SECRET    = "A8168543EF4F08A6DBFE27AB23956898";
    private static final String OKX_PASSPHRASE    = "Aa12345678@";
    // ╔══════════════════════════════════════════════════════════════╗
    // ║                    📊 交易标的参数                            ║
    // ╚══════════════════════════════════════════════════════════════╝
    private static final String CONTRACT          = "BTC-USDT-SWAP";    // 合约名称
    private static final String LEVERAGE          = "50";               // 杠杆倍数
    private static final String MARGIN_MODE       = "cross";            // 全仓 cross / 逐仓 isolated
    private static final String POSITION_MODE     = "long_short_mode";  // 双向持仓
    // ╔══════════════════════════════════════════════════════════════╗
    // ║                  🎯 策略核心参数                              ║
    // ╚══════════════════════════════════════════════════════════════╝
    /** 基础仓位张数 — 初始化时多空各开此张数,也是最小开仓单位 */
    private static final String BASE_QUANTITY     = "10";
    /** 盈利触发比例 — ROI=未实现盈亏/保证金 达到此值时触发平仓 */
    private static final BigDecimal PROFIT_TRIGGER_RATIO = new BigDecimal("0.5");  // 50%
    /** 再投资比例 — 已实现利润中用于补反向仓的比例 */
    private static final BigDecimal REINVEST_RATIO = new BigDecimal("0.5");  // 50%
    // ╔══════════════════════════════════════════════════════════════╗
    // ║                   🛡 风控参数                                ║
    // ╚══════════════════════════════════════════════════════════════╝
    /** 风控1: 反向仓位倍数上限 — 反向最大持仓 = baseQuantity × 此值 (10×10=100张) */
    private static final int MAX_POSITION_MULTIPLIER = 10;
    /** 风控2: 最大亏损阈值(USDT) — 全局盈亏≤-此值时停止策略 */
    private static final BigDecimal MAX_LOSS = new BigDecimal("15");
    /** 风控3: 权益重置比例 — 账户权益 ≥ 初始权益 × (1+此值) 时全平重新双开 */
    private static final BigDecimal EQUITY_RESTART_RATIO = new BigDecimal("0.05");  // 5%
    // ╔══════════════════════════════════════════════════════════════╗
    // ║                  ⚙ 技术与环境参数                            ║
    // ╚══════════════════════════════════════════════════════════════╝
    /** 合约乘数 — BTC-USDT-SWAP 每张=0.01 BTC */
    private static final BigDecimal CONTRACT_MULTIPLIER = new BigDecimal("0.01");
    /** 价格精度 — OKX 价格小数位数 (BTC=2, ETH=2) */
    private static final int PRICE_SCALE = 2;
    /** 盈亏计价模式 — LAST_PRICE(最新价) / MARK_PRICE(标记价) */
    private static final OkxConfig.PnLPriceMode PNL_PRICE_MODE = OkxConfig.PnLPriceMode.LAST_PRICE;
    /** false=模拟盘 (wspap.okx.com) / true=实盘 (ws.okx.com) */
    private static final boolean IS_PRODUCTION = false;
    // ==================== 以下为启动代码,通常无需修改 ====================
    private OkxKlineWebSocketClient wsClient;
    private OkxGridTradeService gridTradeService;
    private OkxProfitRecycleStrategy strategy;
    private OkxConfig config;
    @PostConstruct
    public void init() {
        log.info("[OKX管理器] 开始初始化...");
        log.info("[OKX] 正在初始化盈利回收策略...");
        try {
            // TODO: 替换为实际 API 密钥
            config = OkxConfig.builder()
                    .apiKey("ac76252d-e717-4459-a6f9-80512aed5ea0")
                    .apiSecret("A8168543EF4F08A6DBFE27AB23956898")
                    .passphrase("Aa12345678@")
                    .contract("ETH-USDT-SWAP")
                    .leverage("100")
                    .marginMode("cross")
                    .positionMode("long_short_mode")
                    .gridRate(new BigDecimal("0.003"))
                    .expectedProfit(new BigDecimal("25"))
                    .maxLoss(new BigDecimal("15"))
                    .baseQuantity("15")
                    .quantity("15")
                    .restartGridSpan(6)
                    .maxPositionSize(2)
                    .priceScale(2)
                    .contractMultiplier(new BigDecimal("0.01"))
                    .unrealizedPnlPriceMode(OkxConfig.PnLPriceMode.LAST_PRICE)
                    .isProduction(false)
                    .reopenMaxRetries(3)
                    .apiKey(OKX_API_KEY)
                    .apiSecret(OKX_API_SECRET)
                    .passphrase(OKX_PASSPHRASE)
                    .contract(CONTRACT)
                    .leverage(LEVERAGE)
                    .marginMode(MARGIN_MODE)
                    .positionMode(POSITION_MODE)
                    .baseQuantity(BASE_QUANTITY)
                    .maxLoss(MAX_LOSS)
                    .priceScale(PRICE_SCALE)
                    .contractMultiplier(CONTRACT_MULTIPLIER)
                    .unrealizedPnlPriceMode(PNL_PRICE_MODE)
                    .isProduction(IS_PRODUCTION)
                    .profitTriggerRatio(PROFIT_TRIGGER_RATIO)
                    .reinvestRatio(REINVEST_RATIO)
                    .maxPositionMultiplier(MAX_POSITION_MULTIPLIER)
                    .equityRestartRatio(EQUITY_RESTART_RATIO)
                    .build();
            // 1. 初始化交易服务
            gridTradeService = new OkxGridTradeService(config);
            gridTradeService.init();
            strategy = new OkxProfitRecycleStrategy(config);
            strategy.init();
            // 2. 创建 WS 客户端并注册频道处理器
            wsClient = new OkxKlineWebSocketClient(config);
            wsClient.addPublicHandler(new MarkPriceOkxChannelHandler(config.getContract(), strategy));
            wsClient.addPrivateHandler(new PositionsOkxChannelHandler(config, strategy));
            wsClient.addPrivateHandler(new OrdersOkxChannelHandler(config, strategy));
            // 公开频道:标记价格(替代 K 线,同时驱动策略 onKline 和 PnL 计算)
            wsClient.addPublicHandler(new MarkPriceOkxChannelHandler(
                    config.getContract(), gridTradeService));
            // 私有频道:仓位
            wsClient.addPrivateHandler(new PositionsOkxChannelHandler(
                    config, gridTradeService));
            // 私有频道:条件单
            wsClient.addPrivateHandler(new OrderAlgoOkxChannelHandler(
                    config, gridTradeService));
            gridTradeService.setWsClient(wsClient);
            strategy.setWsClient(wsClient);
            wsClient.init();
            log.info("[OKX管理器] WS已连接, 已注册 3 个频道处理器");
            log.info("[OKX] WS已连接 | 合约: {} | 杠杆: {}x | 基础张数: {} | "
                            + "触发ROI: {}% | 补仓比例: {}% | 仓位上限: {}x | 重置阈值: {}%",
                    CONTRACT, LEVERAGE, BASE_QUANTITY,
                    PROFIT_TRIGGER_RATIO.multiply(new BigDecimal("100")),
                    REINVEST_RATIO.multiply(new BigDecimal("100")),
                    MAX_POSITION_MULTIPLIER,
                    EQUITY_RESTART_RATIO.multiply(new BigDecimal("100")));
            // 3. 激活策略
            gridTradeService.startGrid();
            strategy.startStrategy();
        } catch (Exception e) {
            log.error("[OKX管理器] 初始化失败", e);
            log.error("[OKX] 初始化失败", e);
        }
    }
    @PreDestroy
    public void destroy() {
        log.info("[OKX管理器] 开始销毁...");
        if (gridTradeService != null) {
            gridTradeService.stopGrid();
        }
        if (wsClient != null) {
            wsClient.destroy();
        }
        log.info("[OKX管理器] 销毁完成");
        log.info("[OKX] 正在销毁...");
        if (strategy != null) strategy.stopStrategy();
        if (wsClient != null) wsClient.destroy();
        log.info("[OKX] 销毁完成");
    }
    public OkxKlineWebSocketClient getKlineWebSocketClient() { return wsClient; }
    public OkxGridTradeService getGridTradeService() { return gridTradeService; }
    public OkxProfitRecycleStrategy getStrategy() { return strategy; }
    public IOkxStrategy getActiveStrategy() { return strategy; }
}