| | |
| | | import com.alibaba.fastjson.JSONArray; |
| | | import com.alibaba.fastjson.JSONObject; |
| | | import com.xcong.excoin.modules.okxNewPrice.celue.CaoZuoService; |
| | | import com.xcong.excoin.modules.okxNewPrice.OkxWebSocketClientManager; |
| | | import com.xcong.excoin.modules.okxNewPrice.okxWs.AccountWs; |
| | | import com.xcong.excoin.modules.okxNewPrice.okxWs.PositionsWs; |
| | | import com.xcong.excoin.modules.okxNewPrice.okxWs.TradeOrderWs; |
| | | import com.xcong.excoin.modules.okxNewPrice.okxWs.enums.CoinEnums; |
| | | import com.xcong.excoin.modules.okxNewPrice.okxWs.enums.OrderParamEnums; |
| | | import com.xcong.excoin.modules.okxNewPrice.okxWs.param.TradeRequestParam; |
| | | import com.xcong.excoin.modules.okxNewPrice.okxWs.wanggeList.WangGeListEnum; |
| | | import com.xcong.excoin.modules.okxNewPrice.okxWs.wanggeList.WangGeListService; |
| | | import com.xcong.excoin.modules.okxNewPrice.utils.SSLConfig; |
| | | import com.xcong.excoin.rabbit.pricequeue.WebsocketPriceService; |
| | | import com.xcong.excoin.utils.CoinTypeConvert; |
| | | import com.xcong.excoin.modules.okxNewPrice.utils.WsMapBuild; |
| | | import com.xcong.excoin.utils.RedisUtils; |
| | | import java.math.BigDecimal; |
| | | import lombok.extern.slf4j.Slf4j; |
| | | import org.java_websocket.client.WebSocketClient; |
| | | import org.java_websocket.handshake.ServerHandshake; |
| | | |
| | | import java.net.URI; |
| | | import java.net.URISyntaxException; |
| | | import java.util.Collection; |
| | | import java.util.concurrent.*; |
| | | import java.util.concurrent.atomic.AtomicBoolean; |
| | | import java.util.concurrent.atomic.AtomicReference; |
| | |
| | | private final RedisUtils redisUtils; |
| | | private final CaoZuoService caoZuoService; |
| | | private final OkxWebSocketClientManager clientManager; |
| | | private final WangGeListService wangGeListService; |
| | | |
| | | private WebSocketClient webSocketClient; |
| | | private ScheduledExecutorService heartbeatExecutor; |
| | |
| | | }); |
| | | |
| | | public OkxNewPriceWebSocketClient(RedisUtils redisUtils, |
| | | CaoZuoService caoZuoService, OkxWebSocketClientManager clientManager) { |
| | | CaoZuoService caoZuoService, OkxWebSocketClientManager clientManager, |
| | | WangGeListService wangGeListService) { |
| | | this.redisUtils = redisUtils; |
| | | this.caoZuoService = caoZuoService; |
| | | this.clientManager = clientManager; |
| | | this.wangGeListService = wangGeListService; |
| | | } |
| | | |
| | | /** |
| | |
| | | */ |
| | | private void triggerQuantOperations(String markPx) { |
| | | try { |
| | | |
| | | // markPx = String.valueOf(new BigDecimal(markPx).subtract(new BigDecimal("20"))); |
| | | // 1. 判断当前价格属于哪个网格 |
| | | WangGeListEnum gridByPriceNew = WangGeListEnum.getGridByPrice(new BigDecimal(markPx)); |
| | | if (gridByPriceNew == null) { |
| | | log.error("当前价格{}不在任何网格范围内,无法触发量化操作", markPx); |
| | | return; |
| | | } |
| | | /** |
| | | * 获取当前网格信息 |
| | | * 根据当前网格的持仓方向获取反方向是否存在持仓 |
| | | * 如果持有,直接止损 |
| | | */ |
| | | Collection<OkxQuantWebSocketClient> allClients = clientManager.getAllClients(); |
| | | //如果为空,则直接返回 |
| | | if (allClients.isEmpty()) { |
| | | return; |
| | | } |
| | | // 获取所有OkxQuantWebSocketClient实例 |
| | | for (OkxQuantWebSocketClient client : clientManager.getAllClients()) { |
| | | // 由于OkxQuantWebSocketClient没有直接暴露账号名称的方法,我们需要从clientManager中获取 |
| | | // 这里可以通过遍历clientMap的方式获取账号名称 |
| | | // 或者修改OkxQuantWebSocketClient,添加getAccountName方法 |
| | | // 暂时使用这种方式获取账号名称 |
| | | String accountName = getAccountNameFromClient(client); |
| | | String accountName = client.getAccountName(); |
| | | if (accountName != null) { |
| | | // 调用CaoZuoService的caoZuo方法,触发量化操作 |
| | | String side = caoZuoService.caoZuo(accountName); |
| | | TradeOrderWs.orderEvent(client.getWebSocketClient(), side, accountName); |
| | | log.info("价格变化触发量化操作: 账号={}, 价格={}, 操作方向={}", accountName, markPx, side); |
| | | log.error("当前价格{}属于网格: {}-{}({}-{})", markPx, gridByPriceNew.getName(),gridByPriceNew.getFang_xiang(), gridByPriceNew.getJiage_xiaxian(), gridByPriceNew.getJiage_shangxian()); |
| | | //处理历史网格信息 |
| | | String fangXiang = gridByPriceNew.getFang_xiang(); |
| | | String posSideOld = null; |
| | | if (CoinEnums.POSSIDE_LONG.getCode().equals(fangXiang)) { |
| | | posSideOld = CoinEnums.POSSIDE_SHORT.getCode(); |
| | | } |
| | | if (CoinEnums.POSSIDE_SHORT.getCode().equals(fangXiang)) { |
| | | posSideOld = CoinEnums.POSSIDE_LONG.getCode(); |
| | | } |
| | | |
| | | String positionAccountName = PositionsWs.initAccountName(accountName, posSideOld); |
| | | // 判断是否保证金超标 |
| | | if ( |
| | | PositionsWs.getAccountMap(positionAccountName).get("pos") != null |
| | | && PositionsWs.getAccountMap(positionAccountName).get("pos").compareTo(BigDecimal.ZERO) > 0 |
| | | ){ |
| | | BigDecimal avgPx = PositionsWs.getAccountMap(positionAccountName).get("avgPx"); |
| | | WangGeListEnum gridByPriceOld = WangGeListEnum.getGridByPrice(avgPx); |
| | | if (gridByPriceOld != null){ |
| | | String zhiSunDian = gridByPriceOld.getZhi_sun_dian(); |
| | | if (CoinEnums.POSSIDE_SHORT.getCode().equals(posSideOld)) { |
| | | boolean flag = new BigDecimal(markPx).compareTo(new BigDecimal(zhiSunDian)) > 0; |
| | | log.error("{}历史网格方向{},当前价格大于止损点{}",gridByPriceOld.name(),posSideOld,flag); |
| | | if (flag){ |
| | | TradeRequestParam tradeRequestParam = caoZuoService.caoZuoZhiSunEvent(accountName, markPx, posSideOld); |
| | | TradeOrderWs.orderEvent(client.getWebSocketClient(), tradeRequestParam); |
| | | |
| | | } |
| | | } |
| | | if (CoinEnums.POSSIDE_LONG.getCode().equals(posSideOld)) { |
| | | boolean flag = new BigDecimal(markPx).compareTo(new BigDecimal(zhiSunDian)) < 0; |
| | | log.error("{}历史网格方向{},当前价格小于止损点{}",gridByPriceOld.name(),posSideOld,flag); |
| | | if (flag){ |
| | | TradeRequestParam tradeRequestParam = caoZuoService.caoZuoZhiSunEvent(accountName, markPx, posSideOld); |
| | | TradeOrderWs.orderEvent(client.getWebSocketClient(), tradeRequestParam); |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | //当前下单 |
| | | wangGeListService.initWangGe(markPx); |
| | | TradeRequestParam tradeRequestParam = caoZuoService.caoZuoHandler(accountName, markPx, gridByPriceNew.getFang_xiang()); |
| | | TradeOrderWs.orderEvent(client.getWebSocketClient(), tradeRequestParam); |
| | | log.info("价格变化触发量化操作: 账号={}, 价格={}", accountName, markPx); |
| | | } |
| | | } |
| | | } catch (Exception e) { |
| | | log.error("触发量化操作失败", e); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 从OkxQuantWebSocketClient实例中获取账号名称 |
| | | * 由于OkxQuantWebSocketClient没有直接暴露账号名称的方法,这里需要通过反射获取 |
| | | * 更好的方式是修改OkxQuantWebSocketClient,添加getAccountName方法 |
| | | */ |
| | | private String getAccountNameFromClient(OkxQuantWebSocketClient client) { |
| | | try { |
| | | // 通过反射获取account字段的值 |
| | | java.lang.reflect.Field accountField = OkxQuantWebSocketClient.class.getDeclaredField("account"); |
| | | accountField.setAccessible(true); |
| | | Object account = accountField.get(client); |
| | | // 调用account的name()方法获取账号名称 |
| | | java.lang.reflect.Method nameMethod = account.getClass().getMethod("name"); |
| | | return (String) nameMethod.invoke(account); |
| | | } catch (Exception e) { |
| | | log.error("获取账号名称失败", e); |
| | | return null; |
| | | } |
| | | } |
| | | |
| | |
| | | private void sendPing() { |
| | | try { |
| | | if (webSocketClient != null && webSocketClient.isOpen()) { |
| | | JSONObject ping = new JSONObject(); |
| | | ping.put("op", "ping"); |
| | | webSocketClient.send(ping.toJSONString()); |
| | | webSocketClient.send("ping"); |
| | | log.debug("发送ping请求"); |
| | | } |
| | | } catch (Exception e) { |
| | |
| | | */ |
| | | private void reconnectWithBackoff() throws InterruptedException { |
| | | int attempt = 0; |
| | | int maxAttempts = 5; |
| | | int maxAttempts = 3; |
| | | long delayMs = 5000; |
| | | |
| | | while (attempt < maxAttempts) { |