| | |
| | | package com.xcong.excoin.modules.okxNewPrice; |
| | | |
| | | import cn.hutool.core.util.ObjectUtil; |
| | | import cn.hutool.core.util.StrUtil; |
| | | import com.alibaba.fastjson.JSON; |
| | | import com.alibaba.fastjson.JSONObject; |
| | | import com.xcong.excoin.modules.okxNewPrice.celue.CaoZuoService; |
| | | import com.xcong.excoin.modules.okxNewPrice.okxWs.*; |
| | | import com.xcong.excoin.modules.okxNewPrice.okxWs.enums.CoinEnums; |
| | | import com.xcong.excoin.modules.okxNewPrice.okxWs.enums.ExchangeInfoEnum; |
| | | import com.xcong.excoin.modules.okxNewPrice.okxWs.enums.OrderParamEnums; |
| | | import com.xcong.excoin.modules.okxNewPrice.utils.SSLConfig; |
| | | import com.xcong.excoin.modules.okxNewPrice.wangge.WangGeService; |
| | |
| | | |
| | | private static final String WS_URL_MONIPAN = "wss://wspap.okx.com:8443/ws/v5/private"; |
| | | private static final String WS_URL_SHIPAN = "wss://ws.okx.com:8443/ws/v5/private"; |
| | | private static final boolean INTERNET = false; |
| | | |
| | | private ScheduledExecutorService reconnectScheduler; |
| | | private final AtomicReference<Long> lastReconnectTime = new AtomicReference<>(System.currentTimeMillis()); |
| | | |
| | | |
| | | /** |
| | | * 订阅频道指令 |
| | |
| | | pongTimeoutFuture.cancel(true); |
| | | } |
| | | shutdownExecutorGracefully(sharedExecutor); |
| | | |
| | | if (reconnectScheduler != null) { |
| | | reconnectScheduler.shutdownNow(); |
| | | } |
| | | } |
| | | |
| | | private void shutdownExecutorGracefully(ExecutorService executor) { |
| | |
| | | SSLConfig.configureSSL(); |
| | | System.setProperty("https.protocols", "TLSv1.2,TLSv1.3"); |
| | | String WS_URL = WS_URL_MONIPAN; |
| | | if (INTERNET){ |
| | | if (ExchangeInfoEnum.OKX_UAT.isAccountType()){ |
| | | WS_URL = WS_URL_SHIPAN; |
| | | } |
| | | URI uri = new URI(WS_URL); |
| | |
| | | OrderInfoWs.handleEvent(response, redisUtils); |
| | | }else if (AccountWs.ACCOUNTWS_CHANNEL.equals(channel)) { |
| | | AccountWs.handleEvent(response, redisUtils); |
| | | String side = caoZuoService.caoZuo(); |
| | | TradeOrderWs.orderEvent(webSocketClient, redisUtils, side); |
| | | } else if (PositionsWs.POSITIONSWS_CHANNEL.equals(channel)) { |
| | | PositionsWs.handleEvent(response, redisUtils); |
| | | |
| | | String posKey = PositionsWs.POSITIONSWS_CHANNEL + ":" + CoinEnums.HE_YUE.getCode() + ":pos"; |
| | | String pos = (String) redisUtils.get(posKey); |
| | | if (StrUtil.isBlank(pos)) { |
| | | log.error("未获取到持仓数量"); |
| | | TradeOrderWs.orderEvent(webSocketClient, redisUtils, OrderParamEnums.INIT.getValue()); |
| | | return; |
| | | } |
| | | |
| | | String state = (String) redisUtils.get(InstrumentsWs.INSTRUMENTSWS_CHANNEL + ":" + CoinEnums.HE_YUE.getCode() + ":state"); |
| | | String uplKey = PositionsWs.POSITIONSWS_CHANNEL + ":" + CoinEnums.HE_YUE.getCode() + ":upl"; |
| | | String totalOrderUsdtKey = AccountWs.ACCOUNTWS_CHANNEL + ":" + CoinEnums.USDT.getCode() + ":totalOrderUsdt"; |
| | | |
| | | String upl = (String) redisUtils.get(uplKey); |
| | | String totalOrderUsdt = (String) redisUtils.get(totalOrderUsdtKey); |
| | | BigDecimal multiply = new BigDecimal(upl).multiply(new BigDecimal("-1")); |
| | | |
| | | if (new BigDecimal(totalOrderUsdt).compareTo(multiply) < 0 || OrderParamEnums.STATE_3.getValue().equals(state)) { |
| | | log.error("持仓盈亏超过下单总保证金,止损冷静一天......"); |
| | | TradeOrderWs.orderEvent(webSocketClient, redisUtils, OrderParamEnums.OUT.getValue()); |
| | | return; |
| | | } |
| | | |
| | | String side = caoZuoService.caoZuo(); |
| | | if (StrUtil.isNotBlank(pos)) { |
| | | TradeOrderWs.orderEvent(webSocketClient, redisUtils, side); |
| | | } |
| | | } else if (BalanceAndPositionWs.CHANNEL_NAME.equals(channel)) { |
| | | BalanceAndPositionWs.handleEvent(response); |
| | | } |
| | |
| | | }); |
| | | |
| | | heartbeatExecutor.scheduleWithFixedDelay(this::checkHeartbeatTimeout, 25, 25, TimeUnit.SECONDS); |
| | | // 添加每小时重连的定时任务 |
| | | if (reconnectScheduler != null && !reconnectScheduler.isTerminated()) { |
| | | reconnectScheduler.shutdownNow(); |
| | | } |
| | | |
| | | reconnectScheduler = Executors.newSingleThreadScheduledExecutor(r -> { |
| | | Thread t = new Thread(r, "okx-scheduled-reconnect"); |
| | | t.setDaemon(true); |
| | | return t; |
| | | }); |
| | | |
| | | // 每小时执行一次重连 |
| | | reconnectScheduler.scheduleWithFixedDelay(this::performScheduledReconnect, 60, 60, TimeUnit.MINUTES); |
| | | } |
| | | |
| | | /** |
| | |
| | | } |
| | | } |
| | | |
| | | private void performScheduledReconnect() { |
| | | if (webSocketClient != null && webSocketClient.isOpen()) { |
| | | log.info("关闭当前连接准备重连"); |
| | | webSocketClient.close(); |
| | | } |
| | | // 更新最后重连时间 |
| | | lastReconnectTime.set(System.currentTimeMillis()); |
| | | } |
| | | |
| | | /** |
| | | * 检查心跳超时情况。 |
| | | * 若长时间未收到任何消息则主动发送 ping 请求保持连接活跃。 |