Administrator
3 hours ago 1278ee2bd43b401489b4377b0eee5259b3d5bbbb
refactor(okxNewPrice): 账户配置
8 files modified
97 ■■■■ changed files
src/main/java/com/xcong/excoin/modules/okxApi/OkxGridTradeService.java 34 ●●●● patch | view | raw | blame | history
src/main/java/com/xcong/excoin/modules/okxApi/OkxKlineWebSocketClient.java 12 ●●●●● patch | view | raw | blame | history
src/main/java/com/xcong/excoin/modules/okxApi/OkxRestClient.java 8 ●●●● patch | view | raw | blame | history
src/main/java/com/xcong/excoin/modules/okxApi/OkxTradeExecutor.java 5 ●●●● patch | view | raw | blame | history
src/main/java/com/xcong/excoin/modules/okxApi/wsHandler/handler/OkxAccountChannelHandler.java 18 ●●●●● patch | view | raw | blame | history
src/main/java/com/xcong/excoin/modules/okxApi/wsHandler/handler/OkxCandlestickChannelHandler.java 7 ●●●●● patch | view | raw | blame | history
src/main/java/com/xcong/excoin/modules/okxApi/wsHandler/handler/OkxOrderInfoChannelHandler.java 7 ●●●●● patch | view | raw | blame | history
src/main/java/com/xcong/excoin/modules/okxApi/wsHandler/handler/OkxPositionsChannelHandler.java 6 ●●●●● patch | view | raw | blame | history
src/main/java/com/xcong/excoin/modules/okxApi/OkxGridTradeService.java
@@ -95,12 +95,8 @@
        if (state == StrategyState.WAITING_KLINE) {
            state = StrategyState.OPENING;
            log.info("[{}] 首根K线到达,开基底仓位...", config.getContract());
            executor.openLong(config.getQuantity(), () -> {
                log.info("[{}] 基底多单已提交", config.getContract());
            }, null);
            executor.openShort(config.getQuantity(), () -> {
                log.info("[{}] 基底空单已提交", config.getContract());
            }, null);
            executor.openLong(config.getQuantity(), null, null);
            executor.openShort(config.getQuantity(), null, null);
            return;
        }
@@ -143,8 +139,6 @@
        }
        cumulativePnl = longRealizedPnl.add(shortRealizedPnl);
        log.info("[{}] 持仓更新, 多已实现盈亏:{}, 空已实现盈亏:{}, 累计:{}",
                config.getContract(), longRealizedPnl, shortRealizedPnl, cumulativePnl);
        if (state == StrategyState.WAITING_KLINE) {
            return;
@@ -164,9 +158,6 @@
            return;
        }
        log.info("[{}] 订单成交, 方向:{}, 数量:{}, 成交价:{}, 盈亏:{}",
                config.getContract(), posSide, fillSz, avgPx, pnl);
        if (OkxEnums.POSSIDE_LONG.equals(posSide)) {
            if (!baseLongOpened) {
                longBaseEntryPrice = avgPx;
@@ -174,9 +165,7 @@
                log.info("[{}] 基底多成交价: {}", config.getContract(), longBaseEntryPrice);
                tryGenerateQueues();
            } else if (fillSz.compareTo(BigDecimal.ZERO) > 0) {
                if (longPriceQueue.isEmpty()) {
                    log.warn("[{}] 多仓队列为空,无法设止盈", config.getContract());
                } else {
                if (!longPriceQueue.isEmpty()) {
                    BigDecimal tpPrice = longPriceQueue.get(0);
                    executor.placeTakeProfit(tpPrice, OkxEnums.ORDER_TYPE_CLOSE_LONG, config.getQuantity());
                    log.info("[{}] 多单止盈已设, 成交价:{}, tp:{}, size:{}",
@@ -190,9 +179,7 @@
                log.info("[{}] 基底空成交价: {}", config.getContract(), shortBaseEntryPrice);
                tryGenerateQueues();
            } else if (fillSz.compareTo(BigDecimal.ZERO) > 0) {
                if (shortPriceQueue.isEmpty()) {
                    log.warn("[{}] 空仓队列为空,无法设止盈", config.getContract());
                } else {
                if (!shortPriceQueue.isEmpty()) {
                    BigDecimal tpPrice = shortPriceQueue.get(0);
                    executor.placeTakeProfit(tpPrice, OkxEnums.ORDER_TYPE_CLOSE_SHORT, config.getQuantity());
                    log.info("[{}] 空单止盈已设, 成交价:{}, tp:{}, size:{}",
@@ -272,9 +259,7 @@
                }
            }
        }
        log.info("[{}] 原空队列:{}", config.getContract(), shortPriceQueue);
        if (matched.isEmpty()) {
            log.info("[{}] 空仓队列未触发, 当前价:{}", config.getContract(), currentPrice);
            return;
        }
        log.info("[{}] 空仓队列触发, 匹配{}个元素, 当前价:{}", config.getContract(), matched.size(), currentPrice);
@@ -330,9 +315,7 @@
                }
            }
        }
        log.info("[{}] 原多队列:{}", config.getContract(), longPriceQueue);
        if (matched.isEmpty()) {
            log.info("[{}] 多仓队列未触发, 当前价:{}", config.getContract(), currentPrice);
            return;
        }
        log.info("[{}] 多仓队列触发, 匹配{}个元素, 当前价:{}", config.getContract(), matched.size(), currentPrice);
@@ -372,10 +355,8 @@
                        ? tail.subtract(fixedStep).setScale(1, RoundingMode.HALF_UP)
                        : tail.add(fixedStep).setScale(1, RoundingMode.HALF_UP);
                queue.add(tail);
                log.info("[{}] {}队列增加:{}", config.getContract(), label, tail);
            }
            queue.sort(comparator);
            log.info("[{}] 现{}队列:{}", config.getContract(), label, queue);
        }
    }
@@ -392,17 +373,11 @@
                        : first.subtract(offset).setScale(1, RoundingMode.HALF_UP);
                if (filterEntryPrice.compareTo(BigDecimal.ZERO) > 0
                        && currentPrice.subtract(filterEntryPrice).abs().compareTo(filterEntryPrice.multiply(config.getGridRate())) < 0) {
                    log.info("[{}] {}队列跳过(price≈entry):{}", config.getContract(), label, elem);
                    continue;
                }
                targetQueue.add(elem);
                log.info("[{}] {}队列增加:{}", config.getContract(), label, elem);
            }
            targetQueue.sort(comparator);
            while (targetQueue.size() > config.getGridQueueSize()) {
                targetQueue.remove(targetQueue.size() - 1);
            }
            log.info("[{}] 现{}队列:{}", config.getContract(), label, targetQueue);
        }
    }
@@ -425,7 +400,6 @@
            shortPnl = shortPositionSize.multiply(multiplier).multiply(shortEntryPrice.subtract(price));
        }
        unrealizedPnl = longPnl.add(shortPnl);
        log.info("[{}] 未实现盈亏: {}", config.getContract(), unrealizedPnl);
    }
    public BigDecimal getLastKlinePrice() { return lastKlinePrice; }
src/main/java/com/xcong/excoin/modules/okxApi/OkxKlineWebSocketClient.java
@@ -117,7 +117,6 @@
            JSONObject login = OkxWsUtil.buildJsonObject(null, "login", argsArray);
            webSocketClient.send(login.toJSONString());
            log.info("[WS] 发送登录请求");
        } catch (Exception e) {
            log.error("[WS] 登录请求构建失败", e);
        }
@@ -264,11 +263,9 @@
                return;
            }
            if ("subscribe".equals(event)) {
                log.info("[WS] 订阅成功: {}", response.getJSONObject("arg"));
                return;
            }
            if ("unsubscribe".equals(event)) {
                log.info("[WS] 取消订阅成功: {}", response.getJSONObject("arg"));
                return;
            }
            if ("error".equals(event)) {
@@ -281,7 +278,14 @@
            }
            String op = response.getString("op");
            if ("order".equals(op) || "batch-orders".equals(op)) {
                log.info("[WS] 收到下单推送结果: {}", JSON.toJSONString(response.get("data")));
                JSONArray dataArr = response.getJSONArray("data");
                if (dataArr != null && !dataArr.isEmpty()) {
                    JSONObject first = dataArr.getJSONObject(0);
                    String sCode = first.getString("sCode");
                    if (sCode != null && !"0".equals(sCode)) {
                        log.error("[WS] 下单失败, sCode:{}, sMsg:{}", sCode, first.getString("sMsg"));
                    }
                }
                return;
            }
            for (OkxChannelHandler handler : channelHandlers) {
src/main/java/com/xcong/excoin/modules/okxApi/OkxRestClient.java
@@ -86,7 +86,9 @@
            int code = conn.getResponseCode();
            String response = readResponse(conn);
            log.info("[REST] GET {} → HTTP {} body:{}", path, code, response);
            if (code < 200 || code >= 300) {
                log.error("[REST] GET {} → HTTP {} body:{}", path, code, response);
            }
            return JSON.parseObject(response);
        } catch (Exception e) {
@@ -128,7 +130,9 @@
            int code = conn.getResponseCode();
            String response = readResponse(conn);
            log.info("[REST] POST {} → HTTP {} body:{}", path, code, response);
            if (code < 200 || code >= 300) {
                log.error("[REST] POST {} → HTTP {} body:{}", path, code, response);
            }
            return JSON.parseObject(response);
        } catch (Exception e) {
src/main/java/com/xcong/excoin/modules/okxApi/OkxTradeExecutor.java
@@ -275,10 +275,7 @@
        String connId = OkxWsUtil.getOrderNum("order");
        JSONObject msg = OkxWsUtil.buildJsonObject(connId, "order", argsArray);
        String msgStr = msg.toJSONString();
        log.info("[TradeExec] 发送下单: {}", msgStr);
        wsClient.send(msgStr);
        log.info("[TradeExec] 下单已发送: side={}, sz={}, instId={}", param.getSide(), param.getSz(), param.getInstId());
        wsClient.send(msg.toJSONString());
    }
    private void sendBatchOrders(List<TradeRequestParam> params) {
src/main/java/com/xcong/excoin/modules/okxApi/wsHandler/handler/OkxAccountChannelHandler.java
@@ -44,7 +44,6 @@
        args.add(arg);
        msg.put("args", args);
        ws.send(msg.toJSONString());
        log.info("[{}] 订阅成功", CHANNEL_NAME);
    }
    @Override
@@ -57,7 +56,6 @@
        args.add(arg);
        msg.put("args", args);
        ws.send(msg.toJSONString());
        log.info("[{}] 取消订阅成功", CHANNEL_NAME);
    }
    @Override
@@ -77,22 +75,6 @@
            }
            for (int i = 0; i < dataArray.size(); i++) {
                JSONObject acct = dataArray.getJSONObject(i);
                log.info("[{}] 账户更新, 总权益:{}, 未实现盈亏:{}, 保证金:{}",
                        CHANNEL_NAME,
                        acct.get("totalEq"), acct.get("upl"), acct.get("imr"));
                JSONArray details = acct.getJSONArray("details");
                if (details != null) {
                    for (int j = 0; j < details.size(); j++) {
                        JSONObject detail = details.getJSONObject(j);
                        if ("USDT".equals(detail.getString("ccy"))) {
                            log.info("[{}] USDT可用余额:{}, 权益:{}",
                                    CHANNEL_NAME,
                                    detail.get("availBal"), detail.get("eq"));
                        }
                    }
                }
            }
        } catch (Exception e) {
            log.error("[{}] 处理数据失败", CHANNEL_NAME, e);
        }
src/main/java/com/xcong/excoin/modules/okxApi/wsHandler/handler/OkxCandlestickChannelHandler.java
@@ -38,7 +38,6 @@
        args.add(arg);
        msg.put("args", args);
        ws.send(msg.toJSONString());
        log.info("[{}] 订阅成功, 合约:{}, 周期:1m", OkxEnums.CHANNEL_CANDLE, instId);
    }
    @Override
@@ -52,7 +51,6 @@
        args.add(arg);
        msg.put("args", args);
        ws.send(msg.toJSONString());
        log.info("[{}] 取消订阅成功", OkxEnums.CHANNEL_CANDLE);
    }
    @Override
@@ -72,15 +70,10 @@
        try {
            JSONArray dataArray = response.getJSONArray("data");
            if (dataArray == null || dataArray.isEmpty()) {
                log.warn("[{}] 数据为空", OkxEnums.CHANNEL_CANDLE);
                return true;
            }
            JSONArray data = dataArray.getJSONArray(0);
            BigDecimal closePx = new BigDecimal(data.getString(4));
            String time = OkxWsUtil.timestampToDateTime(Long.parseLong(data.getString(0)));
            String confirm = data.getString(8);
            log.info("[{}] 收盘:{}, 时间:{}, 完结:{}", OkxEnums.CHANNEL_CANDLE, closePx, time, "1".equals(confirm));
            if (gridTradeService != null) {
                gridTradeService.onKline(closePx);
src/main/java/com/xcong/excoin/modules/okxApi/wsHandler/handler/OkxOrderInfoChannelHandler.java
@@ -58,7 +58,6 @@
        args.add(arg);
        msg.put("args", args);
        ws.send(msg.toJSONString());
        log.info("[{}] 订阅成功, 合约:{}", CHANNEL_NAME, instId);
    }
    @Override
@@ -73,7 +72,6 @@
        args.add(arg);
        msg.put("args", args);
        ws.send(msg.toJSONString());
        log.info("[{}] 取消订阅成功", CHANNEL_NAME);
    }
    @Override
@@ -98,14 +96,9 @@
                }
                String state = detail.getString("state");
                String accFillSz = detail.getString("accFillSz");
                String fillPx = detail.getString("fillPx");
                String pnl = detail.getString("pnl");
                String posSide = detail.getString("posSide");
                String avgPx = detail.getString("avgPx");
                String clOrdId = detail.getString("clOrdId");
                log.info("[{}] 订单, 方向:{}, 状态:{}, 成交量:{}, 末笔成交价:{}, 均价:{}, 盈亏:{}, 编号:{}",
                        CHANNEL_NAME, posSide, state, accFillSz, fillPx, avgPx, pnl, clOrdId);
                if ("filled".equals(state) && accFillSz != null && new BigDecimal(accFillSz).compareTo(BigDecimal.ZERO) > 0) {
                    if (gridTradeService != null) {
src/main/java/com/xcong/excoin/modules/okxApi/wsHandler/handler/OkxPositionsChannelHandler.java
@@ -38,7 +38,6 @@
        args.add(arg);
        msg.put("args", args);
        ws.send(msg.toJSONString());
        log.info("[{}] 订阅成功, 合约:{}", OkxEnums.CHANNEL_POSITIONS, instId);
    }
    @Override
@@ -53,7 +52,6 @@
        args.add(arg);
        msg.put("args", args);
        ws.send(msg.toJSONString());
        log.info("[{}] 取消订阅成功", OkxEnums.CHANNEL_POSITIONS);
    }
    @Override
@@ -82,10 +80,6 @@
                        ? new BigDecimal(pos.getString("avgPx")) : BigDecimal.ZERO;
                BigDecimal realizedPnl = pos.containsKey("realizedPnl") && pos.getString("realizedPnl") != null
                        ? new BigDecimal(pos.getString("realizedPnl")) : BigDecimal.ZERO;
                log.info("[{}] 持仓更新, 方向:{}, 数量:{}, 均价:{}, 未实现盈亏:{}, 已实现盈亏:{}, 保证金:{}",
                        OkxEnums.CHANNEL_POSITIONS, posSide, size, avgPx,
                        pos.get("upl"), realizedPnl, pos.get("imr"));
                if (gridTradeService != null) {
                    gridTradeService.onPositionUpdate(posSide, size, avgPx, realizedPnl);