src/main/java/com/xcong/excoin/modules/okxNewPrice/OkxQuantWebSocketClient.java
@@ -395,15 +395,14 @@ // 这会导致多账号之间的数据冲突。需要进一步修改这些类的设计,让数据存储与特定账号关联 if (OrderInfoWs.ORDERINFOWS_CHANNEL.equals(channel)) { TradeRequestParam tradeRequestParam = OrderInfoWs.handleEvent(response, redisUtils, account.name()); TradeOrderWs.orderZhiYingEvent(webSocketClient, tradeRequestParam); List<TradeRequestParam> tradeRequestParams = OrderInfoWs.handleEvent(response, redisUtils, account.name()); TradeOrderWs.orderZhiYingEvent(webSocketClient, tradeRequestParams); }else if (AccountWs.ACCOUNTWS_CHANNEL.equals(channel)) { AccountWs.handleEvent(response, account.name()); } else if (PositionsWs.POSITIONSWS_CHANNEL.equals(channel)) { List<TradeRequestParam> tradeRequestParams = PositionsWs.handleEvent(response, account.name()); TradeOrderWs.orderZhiSunEvent(webSocketClient, tradeRequestParams); PositionsWs.handleEvent(response, account.name()); } else if (BalanceAndPositionWs.CHANNEL_NAME.equals(channel)) { BalanceAndPositionWs.handleEvent(response); src/main/java/com/xcong/excoin/modules/okxNewPrice/celue/CaoZuoServiceImpl.java
@@ -81,6 +81,17 @@ // 账户预期亏损金额比这个还小时,立即止损 if (realKuiSunAmount.compareTo(zhiSunAmount) > 0){ log.warn("账户冷静止损......"); //目前止损掉损失较大的一个方向 String positionAccountName = PositionsWs.initAccountName(accountName, posSide); BigDecimal upl = PositionsWs.getAccountMap(positionAccountName).get("upl"); String posSideOther = CoinEnums.POSSIDE_LONG.getCode().equals(posSide) ? CoinEnums.POSSIDE_SHORT.getCode() : CoinEnums.POSSIDE_LONG.getCode(); String positionAccountOther = PositionsWs.initAccountName(accountName, posSideOther); BigDecimal uplOther = PositionsWs.getAccountMap(positionAccountOther).get("upl"); if (upl.compareTo(uplOther) > 0){ log.warn("{}的亏损{},{}的亏损{},止损{}......",posSide,upl,posSideOther,uplOther,uplOther); posSide = posSideOther; } WsMapBuild.saveStringToMap(InstrumentsWs.getAccountMap(accountName), CoinEnums.OUT.name(), OrderParamEnums.OUT_YES.getValue()); tradeRequestParam.setTradeType(OrderParamEnums.TRADE_YES.getValue()); return caoZuoZhiSunEvent(accountName, markPx, posSide); src/main/java/com/xcong/excoin/modules/okxNewPrice/okxWs/OrderInfoWs.java
@@ -16,6 +16,8 @@ import java.math.BigDecimal; import java.math.RoundingMode; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; @@ -69,7 +71,7 @@ private static final String STATE_KEY = "state"; private static final String FILLFEE_KEY = "fillFee"; private static final String POSSIDE_KEY = "posSide"; public static TradeRequestParam handleEvent(JSONObject response, RedisUtils redisUtils, String accountName) { public static List<TradeRequestParam> handleEvent(JSONObject response, RedisUtils redisUtils, String accountName) { log.info("开始执行OrderInfoWs......"); try { @@ -140,7 +142,7 @@ log.info("{}: 订单详情已完成: {}, 自定义编号: {}", accountName, CoinEnums.HE_YUE.getCode(), clOrdId); List<TradeRequestParam> tradeRequestParamList = new ArrayList<>(); TradeRequestParam tradeRequestParam = new TradeRequestParam(); tradeRequestParam.setAccountName(accountName); @@ -176,7 +178,25 @@ tradeRequestParam.setSide(CoinEnums.POSSIDE_LONG.getCode().equals(posSide) ? CoinEnums.SIDE_SELL.getCode() : CoinEnums.SIDE_BUY.getCode()); tradeRequestParam.setClOrdId(WsParamBuild.getOrderNum(side)); tradeRequestParam.setSz(accFillSz); return tradeRequestParam; tradeRequestParamList.add(tradeRequestParam); // 1. 判断当前价格属于哪个网格去限价止损 WangGeListEnum gridByPriceNew = WangGeListEnum.getGridByPrice(new BigDecimal(avgPx)); if (gridByPriceNew != null) { TradeRequestParam tradeRequestParamZhiSun = new TradeRequestParam(); tradeRequestParamZhiSun.setAccountName(accountName); tradeRequestParamZhiSun.setMarkPx(String.valueOf(gridByPriceNew.getZhi_sun_dian())); tradeRequestParamZhiSun.setInstId(CoinEnums.HE_YUE.getCode()); tradeRequestParamZhiSun.setTdMode(CoinEnums.CROSS.getCode()); tradeRequestParamZhiSun.setPosSide(posSide); tradeRequestParamZhiSun.setOrdType(CoinEnums.ORDTYPE_LIMIT.getCode()); tradeRequestParamZhiSun.setTradeType(OrderParamEnums.TRADE_YES.getValue()); tradeRequestParamZhiSun.setSide(CoinEnums.POSSIDE_LONG.getCode().equals(posSide) ? CoinEnums.SIDE_SELL.getCode() : CoinEnums.SIDE_BUY.getCode()); tradeRequestParamZhiSun.setClOrdId(WsParamBuild.getOrderNum(side)); tradeRequestParamZhiSun.setSz(accFillSz); tradeRequestParamList.add(tradeRequestParamZhiSun); } return tradeRequestParamList; } return null; src/main/java/com/xcong/excoin/modules/okxNewPrice/okxWs/PositionsWs.java
@@ -65,7 +65,7 @@ initParam(arg, accountName,CoinEnums.POSSIDE_SHORT.getCode()); } public static List<TradeRequestParam> handleEvent(JSONObject response, String accountName) { public static void handleEvent(JSONObject response, String accountName) { log.info("开始执行PositionsWs......"); @@ -73,10 +73,8 @@ JSONArray dataArray = response.getJSONArray("data"); if (dataArray == null || dataArray.isEmpty()) { log.info("账户持仓频道数据为空,等待更新"); return null; return; } List<TradeRequestParam> tradeRequestParamList = new ArrayList<>(); for (int i = 0; i < dataArray.size(); i++) { JSONObject posData = dataArray.getJSONObject(i); @@ -118,45 +116,11 @@ ); //先更新缓存 Map<String, BigDecimal> stringBigDecimalMap = initParam(posData, accountName, posSide); //构建止损参数 if (stringBigDecimalMap.get("pos").compareTo(BigDecimal.ZERO) > 0){ TradeRequestParam tradeRequestParam = new TradeRequestParam(); // 1. 判断当前价格属于哪个网格 WangGeListEnum gridByPriceNew = WangGeListEnum.getGridByPrice(new BigDecimal(avgPx)); if (gridByPriceNew != null) { String zhiSunDian = gridByPriceNew.getZhi_sun_dian(); String fangXiang = gridByPriceNew.getFang_xiang(); BigDecimal fangXiangNow = stringBigDecimalMap.get("posSide"); if (fangXiangNow.equals(fangXiang)){ tradeRequestParam.setOrdType(CoinEnums.ORDTYPE_LIMIT.getCode()); tradeRequestParam.setMarkPx(String.valueOf(zhiSunDian)); }else{ tradeRequestParam.setOrdType(CoinEnums.ORDTYPE_MARKET.getCode()); tradeRequestParam.setMarkPx(String.valueOf(markPx)); } }else{ tradeRequestParam.setOrdType(CoinEnums.ORDTYPE_MARKET.getCode()); tradeRequestParam.setMarkPx(String.valueOf(markPx)); } tradeRequestParam.setAccountName(accountName); tradeRequestParam.setInstId(CoinEnums.HE_YUE.getCode()); tradeRequestParam.setTdMode(CoinEnums.CROSS.getCode()); tradeRequestParam.setPosSide(posSide); tradeRequestParam.setTradeType(OrderParamEnums.TRADE_YES.getValue()); tradeRequestParam.setSide(CoinEnums.POSSIDE_LONG.getCode().equals(posSide) ? CoinEnums.SIDE_SELL.getCode() : CoinEnums.SIDE_BUY.getCode()); tradeRequestParam.setClOrdId(WsParamBuild.getOrderNum(tradeRequestParam.getSide())); tradeRequestParam.setSz(String.valueOf(stringBigDecimalMap.get("pos"))); tradeRequestParamList.add(tradeRequestParam); } } } return tradeRequestParamList; } catch (Exception e) { log.error("处理持仓频道推送数据失败", e); } return null; } private static Map<String, BigDecimal> initParam(JSONObject posData, String accountName,String posSide) { src/main/java/com/xcong/excoin/modules/okxNewPrice/okxWs/TradeOrderWs.java
@@ -130,91 +130,12 @@ } } public static void orderZhiYingEvent(WebSocketClient webSocketClient, TradeRequestParam tradeRequestParam) { public static void orderZhiYingEvent(WebSocketClient webSocketClient, List<TradeRequestParam> tradeRequestParams) { log.info("开始执行TradeOrderWs......"); if (tradeRequestParam == null){ log.warn("下单{}参数缺失,取消发送",tradeRequestParam); return; } String accountName = tradeRequestParam.getAccountName(); String markPx = tradeRequestParam.getMarkPx(); String instId = tradeRequestParam.getInstId(); String tdMode = tradeRequestParam.getTdMode(); String posSide = tradeRequestParam.getPosSide(); String ordType = tradeRequestParam.getOrdType(); String tradeType = tradeRequestParam.getTradeType(); String clOrdId = tradeRequestParam.getClOrdId(); String side = tradeRequestParam.getSide(); String sz = tradeRequestParam.getSz(); /** * 校验必要参数 * 验证下单参数是否存在空值 */ if ( StrUtil.isBlank(accountName) || StrUtil.isBlank(instId) || StrUtil.isBlank(tdMode) || StrUtil.isBlank(posSide) || StrUtil.isBlank(ordType) || StrUtil.isBlank(clOrdId) || StrUtil.isBlank(side) || StrUtil.isBlank(sz) || StrUtil.isBlank(markPx) ){ log.warn("下单参数缺失,取消发送"); return; } log.info("账户:{},触发价格:{},币种:{},方向:{},买卖:{},数量:{},是否允许下单:{},编号:{},", accountName, markPx, instId, posSide,side, sz, tradeType, clOrdId); //验证是否允许下单 if (StrUtil.isNotEmpty(tradeType) && OrderParamEnums.TRADE_NO.getValue().equals(tradeType)) { log.warn("账户{}不允许下单,取消发送", accountName); return; } /** * 检验账户和仓位是否准备就绪 * 开多:买入开多(side 填写 buy; posSide 填写 long ) * 开空:卖出开空(side 填写 sell; posSide 填写 short ) 需要检验账户通道是否准备就绪 * 平多:卖出平多(side 填写 sell;posSide 填写 long ) * 平空:买入平空(side 填写 buy; posSide 填写 short ) 需要检验仓位通道是否准备就绪 */ try { JSONArray argsArray = new JSONArray(); JSONObject args = new JSONObject(); args.put("instId", instId); args.put("tdMode", tdMode); args.put("clOrdId", clOrdId); args.put("side", side); args.put("posSide", posSide); args.put("ordType", ordType); args.put("sz", sz); args.put("px", markPx); argsArray.add(args); String connId = WsParamBuild.getOrderNum(ORDERWS_CHANNEL); JSONObject jsonObject = WsParamBuild.buildJsonObject(connId, ORDERWS_CHANNEL, argsArray); webSocketClient.send(jsonObject.toJSONString()); log.info("发送下单频道:{},数量:{}", side, sz); } catch (Exception e) { log.error("下单构建失败", e); } } public static void orderZhiSunEvent(WebSocketClient webSocketClient, List<TradeRequestParam> tradeRequestParams) { log.info("开始止损......"); if (CollUtil.isEmpty(tradeRequestParams)){ log.error("止损下单{}参数缺失,取消发送", JSONUtil.parse(tradeRequestParams)); log.info("开始执行限价{}......",JSONUtil.parse(tradeRequestParams)); if (tradeRequestParams == null){ log.warn("限价下单参数缺失,取消发送"); return; } for (TradeRequestParam tradeRequestParam : tradeRequestParams){ @@ -246,16 +167,17 @@ || StrUtil.isBlank(markPx) ){ log.error("止损下单参数缺失,取消发送"); log.warn("下单参数缺失,取消发送"); return; } log.info("止损账户:{},触发价格:{},币种:{},方向:{},买卖:{},数量:{},是否允许下单:{},编号:{},", log.info("账户:{},触发价格:{},币种:{},方向:{},买卖:{},数量:{},是否允许下单:{},编号:{},", accountName, markPx, instId, posSide,side, sz, tradeType, clOrdId); //验证是否允许下单 if (StrUtil.isNotEmpty(tradeType) && OrderParamEnums.TRADE_NO.getValue().equals(tradeType)) { log.error("止损账户{}不允许下单,取消发送", accountName); log.warn("账户{}不允许下单,取消发送", accountName); return; } /** * 检验账户和仓位是否准备就绪 * 开多:买入开多(side 填写 buy; posSide 填写 long ) @@ -263,6 +185,7 @@ * 平多:卖出平多(side 填写 sell;posSide 填写 long ) * 平空:买入平空(side 填写 buy; posSide 填写 short ) 需要检验仓位通道是否准备就绪 */ try { JSONArray argsArray = new JSONArray(); JSONObject args = new JSONObject(); @@ -280,13 +203,13 @@ String connId = WsParamBuild.getOrderNum(ORDERWS_CHANNEL); JSONObject jsonObject = WsParamBuild.buildJsonObject(connId, ORDERWS_CHANNEL, argsArray); webSocketClient.send(jsonObject.toJSONString()); log.info("止损已发送......"); log.info("发送下单频道:{},数量:{}", side, sz); } catch (Exception e) { log.error("下单构建失败", e); } } } /**