Administrator
5 days ago 6f574e424527acd732ec72ddd56dd028dad339d3
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
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
package com.xcong.excoin.modules.okxApi;
 
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
 
/**
 * OKX 交易模块全局配置,策略的唯一参数入口。
 *
 * <h3>定位</h3>
 * 通过 Builder 模式将所有运行参数集中管理,避免策略参数散落在多个类中。
 * 运行时动态参数(step、gridElements、baseLongTraderParam、baseShortTraderParam)
 * 由 OkxGridTradeService 在策略执行过程中写入。
 *
 * <h3>与 GateConfig 的主要差异</h3>
 * <ul>
 *   <li>新增 {@code passphrase} 字段 — OKX API 认证需要 passphrase</li>
 *   <li>REST 基础路径:生产环境 {@code https://www.okx.com},测试环境 {@code https://www.okx.cab}</li>
 *   <li>WebSocket 分为 public/private 两个地址</li>
 *   <li>合约格式:{@code ETH-USDT-SWAP}(OKX 用短横线分隔)</li>
 *   <li>持仓模式默认值:{@code long_short_mode}(OKX)替代 {@code dual}(Gate)</li>
 *   <li>数据模型(GridElement、TraderParam)复用 gateApi 包中的定义</li>
 * </ul>
 *
 * <h3>参数分类</h3>
 * <table>
 *   <tr><th>类别</th><th>参数</th><th>用途</th></tr>
 *   <tr><td>认证</td><td>apiKey, apiSecret, passphrase</td><td>REST/WS 签名认证</td></tr>
 *   <tr><td>交易标的</td><td>contract, leverage, quantity, contractMultiplier</td><td>合约、杠杆、张数、乘数</td></tr>
 *   <tr><td>持仓</td><td>marginMode, positionMode</td><td>全仓/逐仓、单向/双向</td></tr>
 *   <tr><td>网格策略</td><td>gridRate, gridQueueSize, priceScale</td><td>间距比例、队列容量、价格精度(交易所tick)</td></tr>
 *   <tr><td>止盈止损</td><td>overallTp, maxLoss</td><td>整体止盈/亏损阈值(USDT),触发后策略停止</td></tr>
 *   <tr><td>风控</td><td>marginRatioLimit, reopenMaxRetries</td><td>保证金占比上限、补仓重试次数</td></tr>
 *   <tr><td>盈亏计算</td><td>contractMultiplier, unrealizedPnlPriceMode</td><td>合约乘数、未实现盈亏计价模式</td></tr>
 *   <tr><td>运行时</td><td>step, gridElements, baseLongTraderParam, baseShortTraderParam</td><td>由策略动态填充</td></tr>
 * </table>
 *
 * <h3>gridElements 生命周期</h3>
 * <ol>
 *   <li>项目启动时初始化为空 ArrayList</li>
 *   <li>队列生成逻辑中通过 {@code updateGridElements()} 填充,同时触发
 *       {@link GridElement#rebuildIndex(List)} 建立全局 O(1) 索引</li>
 *   <li>每次挂单/止盈操作后通过 {@link GridElement#refreshIndices()} 更新索引</li>
 * </ol>
 *
 * @author Administrator
 */
public class OkxConfig {
 
    /**
     * 未实现盈亏(unrealizedPnl)计价模式。
     *
     * <ul>
     *   <li>{@link #LAST_PRICE} — 按最新成交价计算,变动快、更贴近实际平仓价</li>
     *   <li>{@link #MARK_PRICE} — 按标记价格计算,变动平稳、过滤市场噪音</li>
     * </ul>
     */
    public enum PnLPriceMode {
        /** 按最新成交价计算未实现盈亏 */
        LAST_PRICE,
        /** 按标记价格计算未实现盈亏,需通过外部注入 */
        MARK_PRICE
    }
 
    // ==================== 认证信息 ====================
 
    /** OKX API v5 密钥 */
    private final String apiKey;
    /** OKX API v5 签名密钥 */
    private final String apiSecret;
    /** OKX API v5 口令密码(passphrase),创建 API Key 时设置 */
    private final String passphrase;
 
    // ==================== 交易标的 ====================
 
    /** 合约名称(如 ETH-USDT-SWAP,注意 OKX 使用短横线分隔) */
    private final String contract;
    /** 杠杆倍数 */
    private final String leverage;
    /** 保证金模式(cross / isolated) */
    private final String marginMode;
    /** 持仓模式(long_short_mode=双向 / net_mode=单向) */
    private final String positionMode;
 
    // ==================== 策略参数 ====================
 
    /** 网格间距比例(如 0.0035 表示 0.35%) */
    private final BigDecimal gridRate;
    /** 整体止盈阈值(USDT) */
    private final BigDecimal overallTp;
    /** 最大亏损阈值(USDT) */
    private final BigDecimal maxLoss;
    /** 下单数量(合约张数) */
    private final String quantity;
    /** 基底开仓张数(初始化时多空各开的张数,如 "10") */
    private final String baseQuantity;
    /** 预期收益(USDT),unrealisedPnl + available > 初始本金 + 此值时重置 */
    private final BigDecimal expectedProfit;
    /** 是否为生产环境 */
    private final boolean isProduction;
    /** 补仓最大重试次数 */
    private final int reopenMaxRetries;
    /** 网格队列容量 */
    private final int gridQueueSize;
    /** 保证金占初始本金比例上限 */
    private final BigDecimal marginRatioLimit;
    /** 合约乘数(单张合约代表的基础资产数量,如 ETH-USDT-SWAP=0.01) */
    private final BigDecimal contractMultiplier;
    /** 价格精度(交易所价格的最小小数位数,如 1 表示 0.1 精度,2 表示 0.01 精度) */
    private final int priceScale;
    /** 未实现盈亏计价模式:最新价 / 标记价格 */
    private final PnLPriceMode unrealizedPnlPriceMode;
    /** 最大持仓张数(单方向),0=不限制 */
    private final int maxPositionSize;
    /** 策略重启跨度阈值:多空两边止盈触发数量均达到此值后触发重启,0=禁用 */
    private final int restartGridSpan;
 
    // ==================== 运行时参数 ====================
 
    /** 网格绝对步长(shortBaseEntryPrice × gridRate),运行时由队列生成逻辑设置 */
    private BigDecimal step;
    /** 网格元素列表,由队列初始化时同步填充,包含完整的多空仓挂单状态 */
    private volatile List<GridElement> gridElements = new ArrayList<>();
    /** 基座多头挂单参数,在基座成交后由队列生成逻辑填充 */
    private TraderParam baseLongTraderParam;
    /** 基座空头挂单参数,在基座成交后由队列生成逻辑填充 */
    private TraderParam baseShortTraderParam;
 
    // ==================== 构造器 ====================
 
    private OkxConfig(Builder builder) {
        this.apiKey = builder.apiKey;
        this.apiSecret = builder.apiSecret;
        this.passphrase = builder.passphrase;
        this.contract = builder.contract;
        this.leverage = builder.leverage;
        this.marginMode = builder.marginMode;
        this.positionMode = builder.positionMode;
        this.gridRate = builder.gridRate;
        this.overallTp = builder.overallTp;
        this.maxLoss = builder.maxLoss;
        this.quantity = builder.quantity;
        this.baseQuantity = builder.baseQuantity;
        this.expectedProfit = builder.expectedProfit;
        this.isProduction = builder.isProduction;
        this.reopenMaxRetries = builder.reopenMaxRetries;
        this.gridQueueSize = builder.gridQueueSize;
        this.marginRatioLimit = builder.marginRatioLimit;
        this.contractMultiplier = builder.contractMultiplier;
        this.priceScale = builder.priceScale;
        this.unrealizedPnlPriceMode = builder.unrealizedPnlPriceMode;
        this.maxPositionSize = builder.maxPositionSize;
        this.restartGridSpan = builder.restartGridSpan;
    }
 
    // ==================== REST/WS 地址 ====================
 
    /**
     * 返回 REST API 基础路径。
     * <p>实盘和模拟盘使用相同的 REST 地址,通过 {@code x-simulated-trading: 1} 请求头区分。
     * <ul>
     *   <li>生产网/测试网: {@code https://openapi.okx.com}</li>
     * </ul>
     */
    public String getRestBasePath() {
        return "https://openapi.okx.com";
    }
 
    /**
     * 根据环境返回 WebSocket 公开频道地址。
     * <ul>
     *   <li>测试网: {@code wss://wspap.okx.com:8443/ws/v5/public}</li>
     *   <li>生产网: {@code wss://ws.okx.com:8443/ws/v5/public}</li>
     * </ul>
     */
    public String getWsPublicUrl() {
        return isProduction
                ? "wss://ws.okx.com:8443/ws/v5/public"
                : "wss://wspap.okx.com:8443/ws/v5/public";
    }
 
    /**
     * 根据环境返回 WebSocket 私有频道地址。
     * <ul>
     *   <li>测试网: {@code wss://wspap.okx.com:8443/ws/v5/private}</li>
     *   <li>生产网: {@code wss://ws.okx.com:8443/ws/v5/private}</li>
     * </ul>
     */
    public String getWsPrivateUrl() {
        return isProduction
                ? "wss://ws.okx.com:8443/ws/v5/private"
                : "wss://wspap.okx.com:8443/ws/v5/private";
    }
 
    // ==================== 认证信息 ====================
 
    /** @return OKX API v5 密钥 */
    public String getApiKey() { return apiKey; }
    /** @return OKX API v5 签名密钥,用于 HMAC-SHA256 签名 */
    public String getApiSecret() { return apiSecret; }
    /** @return OKX API v5 口令密码(passphrase) */
    public String getPassphrase() { return passphrase; }
 
    // ==================== 交易标的 ====================
 
    /** @return 合约名称(如 ETH-USDT-SWAP,OKX 使用短横线分隔) */
    public String getContract() { return contract; }
    /** @return 杠杆倍数(如 "100" 表示 100x) */
    public String getLeverage() { return leverage; }
 
    // ==================== 持仓配置 ====================
 
    /** @return 保证金模式(cross=全仓 / isolated=逐仓) */
    public String getMarginMode() { return marginMode; }
    /** @return 持仓模式(long_short_mode=双向 / net_mode=单向) */
    public String getPositionMode() { return positionMode; }
 
    // ==================== 策略参数 ====================
 
    /** @return 网格间距比例(如 0.0015 表示 0.15%),用于生成价格队列和计算止盈价 */
    public BigDecimal getGridRate() { return gridRate; }
    /** @return 整体止盈阈值(USDT),累计已实现盈亏 ≥ 此值时策略停止 */
    public BigDecimal getOverallTp() { return overallTp; }
    /** @return 最大亏损阈值(USDT),累计已实现盈亏 ≤ -此值时策略停止 */
    public BigDecimal getMaxLoss() { return maxLoss; }
    /** @return 每次下单的张数(如 "1" 表示 1 张合约) */
    public String getQuantity() { return quantity; }
    /** @return 基底开仓张数(初始化时多空各开的张数,如 "10") */
    public String getBaseQuantity() { return baseQuantity; }
    /** @return 预期收益(USDT),unrealisedPnl + available > 初始本金 + 此值时重置 */
    public BigDecimal getExpectedProfit() { return expectedProfit; }
    /** @return 网格价格队列的容量上限(超出时截断尾部) */
    public int getGridQueueSize() { return gridQueueSize; }
 
    // ==================== 风险控制 ====================
 
    /** @return 保证金占初始本金比例上限(默认 0.2 即 20%),超限跳过开仓 */
    public BigDecimal getMarginRatioLimit() { return marginRatioLimit; }
    /** @return 补仓最大重试次数(当前版本未使用) */
    public int getReopenMaxRetries() { return reopenMaxRetries; }
 
    // ==================== 盈亏计算 ====================
 
    /** @return 合约乘数(单张合约代表的基础资产数量,如 ETH-USDT-SWAP=0.01) */
    public BigDecimal getContractMultiplier() { return contractMultiplier; }
    /** @return 价格精度(交易所价格的小数位数,如 1=0.1精度,2=0.01精度),用于价格四舍五入 */
    public int getPriceScale() { return priceScale; }
    /** @return 未实现盈亏计价模式:LAST_PRICE(最新成交价)/ MARK_PRICE(标记价格) */
    public PnLPriceMode getUnrealizedPnlPriceMode() { return unrealizedPnlPriceMode; }
    /** @return 最大持仓张数(单方向),0=不限制 */
    public int getMaxPositionSize() { return maxPositionSize; }
    /** @return 策略重启跨度阈值:多空两边止盈触发数均达到此值后触发重启,0=禁用 */
    public int getRestartGridSpan() { return restartGridSpan; }
 
    // ==================== 运行时参数 ====================
 
    /** @return 网格绝对步长(shortBaseEntryPrice × gridRate),运行时设置 */
    public BigDecimal getStep() { return step; }
    /** 设置网格绝对步长(由队列生成逻辑在运行时计算并注入) */
    public void setStep(BigDecimal step) { this.step = step; }
 
    // ==================== 网格元素列表 ====================
 
    /** @return 网格元素列表(队列初始化后填充),线程不安全,仅由策略线程单线程写入 */
    public List<GridElement> getGridElements() { return gridElements; }
    /** 设置网格元素列表(由队列生成逻辑写入),同时重建全局 ID 索引 */
    public void setGridElements(List<GridElement> gridElements) {
        this.gridElements = gridElements;
        GridElement.rebuildIndex(gridElements);
    }
 
    // ==================== 基座挂单参数 ====================
 
    /** @return 基座多头挂单参数 */
    public TraderParam getBaseLongTraderParam() { return baseLongTraderParam; }
    /** 设置基座多头挂单参数(由队列生成逻辑在基座成交后填充) */
    public void setBaseLongTraderParam(TraderParam baseLongTraderParam) { this.baseLongTraderParam = baseLongTraderParam; }
 
    /** @return 基座空头挂单参数 */
    public TraderParam getBaseShortTraderParam() { return baseShortTraderParam; }
    /** 设置基座空头挂单参数(由队列生成逻辑在基座成交后填充) */
    public void setBaseShortTraderParam(TraderParam baseShortTraderParam) { this.baseShortTraderParam = baseShortTraderParam; }
 
    // ==================== 环境 ====================
 
    /** @return 是否为生产环境(true=实盘生产网 / false=模拟盘测试网) */
    public boolean isProduction() { return isProduction; }
 
    // ==================== Builder ====================
 
    public static Builder builder() {
        return new Builder();
    }
 
    /**
     * OkxConfig 的流式构造器,提供合理的默认值。
     *
     * <h3>必填项</h3>
     * {@code apiKey}、{@code apiSecret}、{@code passphrase} 必须设置,其余参数均有默认值。
     *
     * <h3>默认值</h3>
     * ETH-USDT-SWAP / 10x / cross(全仓) / long_short_mode(双向) / gridRate=0.35% /
     * overallTp=0.5 / maxLoss=7.5 / quantity=1 / isProduction=false
     */
    public static class Builder {
        /** OKX API v5 密钥(必填) */
        private String apiKey;
        /** OKX API v5 签名密钥(必填) */
        private String apiSecret;
        /** OKX API v5 口令密码(必填) */
        private String passphrase;
        /** 合约名称,默认 ETH-USDT-SWAP */
        private String contract = "ETH-USDT-SWAP";
        /** 杠杆倍数,默认 "10" */
        private String leverage = "10";
        /** 保证金模式,默认 "cross"(全仓) */
        private String marginMode = "cross";
        /** 持仓模式,默认 "long_short_mode"(双向) */
        private String positionMode = "long_short_mode";
        /** 网格间距比例,默认 0.0035(0.35%) */
        private BigDecimal gridRate = new BigDecimal("0.0035");
        /** 整体止盈阈值(USDT),默认 0.5 */
        private BigDecimal overallTp = new BigDecimal("0.5");
        /** 最大亏损阈值(USDT),默认 7.5 */
        private BigDecimal maxLoss = new BigDecimal("7.5");
        /** 每次下单张数,默认 "1" */
        private String quantity = "1";
        /** 基底开仓张数,默认 "10"(初始化时多空各开10张) */
        private String baseQuantity = "10";
        /** 预期收益(USDT),默认 0.5 */
        private BigDecimal expectedProfit = new BigDecimal("0.5");
        /** 是否为生产环境,默认 false(测试网) */
        private boolean isProduction = false;
        /** 补仓最大重试次数,默认 3 */
        private int reopenMaxRetries = 3;
        /** 网格队列容量,默认 300 */
        private int gridQueueSize = 300;
        /** 保证金占初始本金比例上限,默认 0.2(20%) */
        private BigDecimal marginRatioLimit = new BigDecimal("0.2");
        /** 合约乘数,默认 0.01(ETH-USDT-SWAP=0.01) */
        private BigDecimal contractMultiplier = new BigDecimal("0.01");
        /** 价格精度(交易所价格的小数位数),默认 2(0.01 精度,适配 ETH) */
        private int priceScale = 2;
        /** 未实现盈亏计价模式,默认 LAST_PRICE(最新成交价) */
        private PnLPriceMode unrealizedPnlPriceMode = PnLPriceMode.LAST_PRICE;
        /** 最大持仓张数(单方向),默认 0=不限制 */
        private int maxPositionSize = 0;
        /** 策略重启跨度阈值:多空两边止盈触发数量均达到此值后触发重启,默认 0=禁用 */
        private int restartGridSpan = 0;
 
        /** 设置 API Key */
        public Builder apiKey(String apiKey) { this.apiKey = apiKey; return this; }
        /** 设置 API Secret */
        public Builder apiSecret(String apiSecret) { this.apiSecret = apiSecret; return this; }
        /** 设置 API Passphrase */
        public Builder passphrase(String passphrase) { this.passphrase = passphrase; return this; }
        /** 设置合约名称(如 ETH-USDT-SWAP) */
        public Builder contract(String contract) { this.contract = contract; return this; }
        /** 设置杠杆倍数 */
        public Builder leverage(String leverage) { this.leverage = leverage; return this; }
        /** 设置保证金模式(cross=全仓 / isolated=逐仓) */
        public Builder marginMode(String marginMode) { this.marginMode = marginMode; return this; }
        /** 设置持仓模式(long_short_mode=双向 / net_mode=单向) */
        public Builder positionMode(String positionMode) { this.positionMode = positionMode; return this; }
        /** 设置网格间距比例 */
        public Builder gridRate(BigDecimal gridRate) { this.gridRate = gridRate; return this; }
        /** 设置整体止盈阈值(USDT) */
        public Builder overallTp(BigDecimal overallTp) { this.overallTp = overallTp; return this; }
        /** 设置最大亏损阈值(USDT) */
        public Builder maxLoss(BigDecimal maxLoss) { this.maxLoss = maxLoss; return this; }
        /** 设置每次下单张数 */
        public Builder quantity(String quantity) { this.quantity = quantity; return this; }
        /** 设置基底开仓张数 */
        public Builder baseQuantity(String baseQuantity) { this.baseQuantity = baseQuantity; return this; }
        /** 设置预期收益(USDT) */
        public Builder expectedProfit(BigDecimal expectedProfit) { this.expectedProfit = expectedProfit; return this; }
        /** 设置环境(true=实盘生产网 / false=模拟盘测试网) */
        public Builder isProduction(boolean isProduction) { this.isProduction = isProduction; return this; }
        /** 设置补仓最大重试次数 */
        public Builder reopenMaxRetries(int reopenMaxRetries) { this.reopenMaxRetries = reopenMaxRetries; return this; }
        /** 设置合约乘数(单张合约代表的基础资产数量) */
        public Builder contractMultiplier(BigDecimal contractMultiplier) { this.contractMultiplier = contractMultiplier; return this; }
        /** 设置价格精度(交易所价格的小数位数,如 1=0.1精度,2=0.01精度) */
        public Builder priceScale(int priceScale) { this.priceScale = priceScale; return this; }
        /** 设置保证金占初始本金比例上限 */
        public Builder marginRatioLimit(BigDecimal marginRatioLimit) { this.marginRatioLimit = marginRatioLimit; return this; }
        /** 设置网格队列容量 */
        public Builder gridQueueSize(int gridQueueSize) { this.gridQueueSize = gridQueueSize; return this; }
        /** 设置未实现盈亏计价模式 */
        public Builder unrealizedPnlPriceMode(PnLPriceMode mode) { this.unrealizedPnlPriceMode = mode; return this; }
        /** 设置最大持仓张数(单方向),0=不限制 */
        public Builder maxPositionSize(int maxPositionSize) { this.maxPositionSize = maxPositionSize; return this; }
        /** 设置策略重启跨度阈值:多空两边止盈触发数均达到此值后触发重启,0=禁用 */
        public Builder restartGridSpan(int restartGridSpan) { this.restartGridSpan = restartGridSpan; return this; }
 
        public OkxConfig build() {
            return new OkxConfig(this);
        }
    }
}