Administrator
4 days ago 04063bcb7b9e9d8e0242c1313f54ccc1b71f0b6e
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
package com.xcong.excoin.modules.okxApi;
 
import com.xcong.excoin.modules.okxApi.wsHandler.handler.MarkPriceOkxChannelHandler;
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;
 
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import java.math.BigDecimal;
 
/**
 * OKX 盈利回收策略 — 唯一入口,所有参数集中在此。
 *
 * <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>策略核心公式</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>仓位演化示例 (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
 */
@Slf4j
@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 OkxProfitRecycleStrategy strategy;
    private OkxConfig config;
 
    @PostConstruct
    public void init() {
        log.info("[OKX] 正在初始化盈利回收策略...");
 
        try {
            config = OkxConfig.builder()
                    .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();
 
            strategy = new OkxProfitRecycleStrategy(config);
            strategy.init();
 
            wsClient = new OkxKlineWebSocketClient(config);
            wsClient.addPublicHandler(new MarkPriceOkxChannelHandler(config.getContract(), strategy));
            wsClient.addPrivateHandler(new PositionsOkxChannelHandler(config, strategy));
            wsClient.addPrivateHandler(new OrdersOkxChannelHandler(config, strategy));
 
            strategy.setWsClient(wsClient);
            wsClient.init();
            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")));
 
            strategy.startStrategy();
        } catch (Exception e) {
            log.error("[OKX] 初始化失败", e);
        }
    }
 
    @PreDestroy
    public void destroy() {
        log.info("[OKX] 正在销毁...");
        if (strategy != null) strategy.stopStrategy();
        if (wsClient != null) wsClient.destroy();
        log.info("[OKX] 销毁完成");
    }
 
    public OkxKlineWebSocketClient getKlineWebSocketClient() { return wsClient; }
    public OkxProfitRecycleStrategy getStrategy() { return strategy; }
    public IOkxStrategy getActiveStrategy() { return strategy; }
}