From 39252ec46c56c2f444b18af97180a9c07519bff6 Mon Sep 17 00:00:00 2001
From: Administrator <15274802129@163.com>
Date: Tue, 06 Jan 2026 16:20:15 +0800
Subject: [PATCH] refactor(okxNewPrice): 重构交易订单处理逻辑
---
src/main/java/com/xcong/excoin/modules/okxNewPrice/OkxQuantWebSocketClient.java | 5
src/main/java/com/xcong/excoin/modules/okxNewPrice/OkxKlineWebSocketClient.java | 61 ------------
src/main/java/com/xcong/excoin/modules/okxNewPrice/okxWs/OrderInfoWs.java | 47 +++++++++
src/main/java/com/xcong/excoin/modules/okxNewPrice/okxWs/TradeOrderWs.java | 129 +++++++++++++------------
4 files changed, 115 insertions(+), 127 deletions(-)
diff --git a/src/main/java/com/xcong/excoin/modules/okxNewPrice/OkxKlineWebSocketClient.java b/src/main/java/com/xcong/excoin/modules/okxNewPrice/OkxKlineWebSocketClient.java
index 8498bd6..cf5c9fd 100644
--- a/src/main/java/com/xcong/excoin/modules/okxNewPrice/OkxKlineWebSocketClient.java
+++ b/src/main/java/com/xcong/excoin/modules/okxNewPrice/OkxKlineWebSocketClient.java
@@ -357,8 +357,7 @@
// 使用策略分析最新价格数据
MacdEmaStrategy.TradingOrder tradingOrderOpenOpen = strategy.generateTradingOrder(historicalPrices1M, MacdMaStrategy.OperationType.open.name());
- MacdEmaStrategy.TradingOrder tradingOrderOpenClose = strategy.generateTradingOrder(historicalPrices1M, MacdMaStrategy.OperationType.close.name());
- if (tradingOrderOpenOpen == null && tradingOrderOpenClose == null){
+ if (tradingOrderOpenOpen == null){
return;
}
@@ -375,10 +374,6 @@
log.info("{}开仓{}:{}",instId,tradingOrderOpenOpen.getPosSide(),tradingOrderOpenOpen.getSide());
doOpen(client.getWebSocketClient(),accountName, tradingOrderOpenOpen, closePx);
}
- if (ObjectUtil.isNotEmpty(tradingOrderOpenClose)){
- log.info("{}平仓{}:{}",instId,tradingOrderOpenClose.getPosSide(),tradingOrderOpenClose.getSide());
- doclose(client.getWebSocketClient(),accountName, tradingOrderOpenClose, closePx);
- }
}
}
}
@@ -386,60 +381,6 @@
} catch (Exception e) {
log.error("处理 K线频道推送数据失败", e);
}
- }
-
- private void doclose(WebSocketClient webSocketClient, String accountName, MacdEmaStrategy.TradingOrder tradingOrderOpenClose, BigDecimal closePx) {
- // 根据信号执行交易操作
- TradeRequestParam tradeRequestParam = new TradeRequestParam();
- tradeRequestParam.setAccountName(accountName);
- tradeRequestParam.setMarkPx(String.valueOf(closePx));
- tradeRequestParam.setInstId(CoinEnums.HE_YUE.getCode());
- tradeRequestParam.setTdMode(CoinEnums.CROSS.getCode());
- tradeRequestParam.setOrdType(CoinEnums.ORDTYPE_MARKET.getCode());
- String posSide = tradingOrderOpenClose.getPosSide();
- tradeRequestParam.setPosSide(posSide);
-
- String side = tradingOrderOpenClose.getSide();
- tradeRequestParam.setSide(side);
-
- String clOrdId = WsParamBuild.getOrderNum(side);
- tradeRequestParam.setClOrdId(clOrdId);
-
- String positionAccountName = PositionsWs.initAccountName(accountName, posSide);
- BigDecimal pos = PositionsWs.getAccountMap(positionAccountName).get("pos");
- if (BigDecimal.ZERO.compareTo( pos) >= 0) {
- log.error("历史网格止损方向没有持仓");
- tradeRequestParam.setTradeType(OrderParamEnums.TRADE_NO.getValue());
- }
- tradeRequestParam.setSz(String.valueOf(pos));
-
- BigDecimal cashBal = WsMapBuild.parseBigDecimalSafe(AccountWs.getAccountMap(accountName).get("cashBal"));
- BigDecimal realKuiSunAmount = PositionsWs.getAccountMap(positionAccountName).get("upl");
- log.info("实际盈亏金额: {}", realKuiSunAmount);
- String zhiSunPercent = InstrumentsWs.getAccountMap(accountName).get(CoinEnums.ZHI_SUN.name());
- BigDecimal zhiSunAmount = cashBal.multiply(new BigDecimal(zhiSunPercent));
- log.info("预期亏损金额: {}", zhiSunAmount);
- String kangYaPercent = InstrumentsWs.getAccountMap(accountName).get(CoinEnums.KANG_CANG.name());
- BigDecimal kangYaAmount = cashBal.multiply(new BigDecimal(kangYaPercent));
- log.info("预期抗仓金额: {}", kangYaAmount);
-
- if (realKuiSunAmount.compareTo(BigDecimal.ZERO) < 0){
- realKuiSunAmount = realKuiSunAmount.multiply(new BigDecimal("-1"));
- // 账户预期亏损金额比这个还小时,立即止损
- if (realKuiSunAmount.compareTo(zhiSunAmount) > 0){
- log.error("账户冷静止损......");
- WsMapBuild.saveStringToMap(InstrumentsWs.getAccountMap(accountName), CoinEnums.OUT.name(), OrderParamEnums.OUT_YES.getValue());
- tradeRequestParam.setTradeType(OrderParamEnums.TRADE_YES.getValue());
- }
- // 判断抗压
- if (realKuiSunAmount.compareTo(kangYaAmount) > 0 && realKuiSunAmount.compareTo(zhiSunAmount) <= 0){
- log.error("账户紧张扛仓......");
- tradeRequestParam.setTradeType(OrderParamEnums.TRADE_NO.getValue());
- }
- }
-
-
- TradeOrderWs.orderZhiYingZhiSunEventNoState(webSocketClient, tradeRequestParam);
}
private void doOpen(WebSocketClient webSocketClient, String accountName, MacdEmaStrategy.TradingOrder tradingOrderOpenOpen, BigDecimal closePx) {
diff --git a/src/main/java/com/xcong/excoin/modules/okxNewPrice/OkxQuantWebSocketClient.java b/src/main/java/com/xcong/excoin/modules/okxNewPrice/OkxQuantWebSocketClient.java
index cadf607..fd30e06 100644
--- a/src/main/java/com/xcong/excoin/modules/okxNewPrice/OkxQuantWebSocketClient.java
+++ b/src/main/java/com/xcong/excoin/modules/okxNewPrice/OkxQuantWebSocketClient.java
@@ -18,6 +18,7 @@
import java.math.BigDecimal;
import java.net.URI;
import java.net.URISyntaxException;
+import java.util.List;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReference;
@@ -384,8 +385,8 @@
// 这会导致多账号之间的数据冲突。需要进一步修改这些类的设计,让数据存储与特定账号关联
if (OrderInfoWs.ORDERINFOWS_CHANNEL.equals(channel)) {
// OrderInfoWs.handleEvent(response, redisUtils, account.name());
- TradeRequestParam tradeRequestParam = OrderInfoWs.handleEvent(response, redisUtils, account.name());
- TradeOrderWs.orderZhiYingZhiSunEventNoState(webSocketClient, tradeRequestParam);
+ List<TradeRequestParam> tradeRequestParams = OrderInfoWs.handleEvent(response, redisUtils, account.name());
+ TradeOrderWs.orderZhiYingZhiSunEventNoState(webSocketClient, tradeRequestParams);
}else if (AccountWs.ACCOUNTWS_CHANNEL.equals(channel)) {
AccountWs.handleEvent(response, account.name());
} else if (PositionsWs.POSITIONSWS_CHANNEL.equals(channel)) {
diff --git a/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxWs/OrderInfoWs.java b/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxWs/OrderInfoWs.java
index ec8478f..5e3df73 100644
--- a/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxWs/OrderInfoWs.java
+++ b/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 {
@@ -116,6 +118,7 @@
log.info("{}: 订单详情已完成: {}, 自定义编号: {}", accountName, CoinEnums.HE_YUE.getCode(), clOrdId);
+ ArrayList<TradeRequestParam> tradeRequestParams = new ArrayList<>();
TradeRequestParam tradeRequestParam = new TradeRequestParam();
tradeRequestParam.setAccountName(accountName);
BigDecimal zhiYingPx = getZhiYingPx(
@@ -137,7 +140,30 @@
tradeRequestParam.setSide(CoinEnums.POSSIDE_LONG.getCode().equals(posSide) ? CoinEnums.SIDE_SELL.getCode() : CoinEnums.SIDE_BUY.getCode());
tradeRequestParam.setClOrdId(WsParamBuild.getOrderNum(tradeRequestParam.getSide()));
tradeRequestParam.setSz(accFillSz);
- return tradeRequestParam;
+
+ TradeRequestParam tradeRequestParamZhiSun = new TradeRequestParam();
+ tradeRequestParamZhiSun.setAccountName(accountName);
+ BigDecimal zhiSunPx = getZhiSunPx(
+ accountName,
+ posSide,
+ fillFee,
+ WsMapBuild.parseBigDecimalSafe(InstrumentsWs.getAccountMap(accountName).get(CoinEnums.CTVAL.name())),
+ WsMapBuild.parseBigDecimalSafe(accFillSz),
+ WsMapBuild.parseBigDecimalSafe(InstrumentsWs.getAccountMap(accountName).get(CoinEnums.CONTRACTMULTIPLIER.name())),
+ WsMapBuild.parseBigDecimalSafe(avgPx),
+ WsMapBuild.parseBigDecimalSafe(CoinEnums.LEVERAGE.getCode())
+ );
+ tradeRequestParamZhiSun.setMarkPx(String.valueOf(zhiSunPx));
+ 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(tradeRequestParamZhiSun.getSide()));
+ tradeRequestParamZhiSun.setSz(accFillSz);
+ tradeRequestParams.add(tradeRequestParamZhiSun);
+ return tradeRequestParams;
}
return null;
@@ -164,6 +190,23 @@
/**
* 计算预期收益
*/
+ public static BigDecimal getZhiSunPx(
+ String accountName, String posSide, String fillFee, BigDecimal coinValue, BigDecimal coinNum,
+ BigDecimal contractMultiplier, BigDecimal avgPx, BigDecimal leverage
+ ) {
+ BigDecimal initMargin = getInitMargin(coinValue, coinNum, contractMultiplier, avgPx, leverage);
+ String pingCangImr = StrUtil.isEmpty(InstrumentsWs.getAccountMap(accountName).get(CoinEnums.PING_CANG_SHOUYI.name())) ? "0.2" : InstrumentsWs.getAccountMap(accountName).get(CoinEnums.PING_CANG_SHOUYI.name());
+ BigDecimal expectProfit = (initMargin)
+ .multiply(new BigDecimal(pingCangImr))
+ .add(new BigDecimal(fillFee).abs())
+ .multiply(new BigDecimal("-1"))
+ .setScale(4, RoundingMode.DOWN);
+ log.info("{}: 订单详情-预期收益: {}", accountName, expectProfit);
+ return getMarkPrice(expectProfit,posSide, coinValue, coinNum, contractMultiplier, avgPx, leverage);
+ }
+ /**
+ * 计算预期收益
+ */
public static BigDecimal getZhiYingPx(
String accountName, String posSide, String fillFee, BigDecimal coinValue, BigDecimal coinNum,
BigDecimal contractMultiplier, BigDecimal avgPx, BigDecimal leverage
diff --git a/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxWs/TradeOrderWs.java b/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxWs/TradeOrderWs.java
index 4b707f0..496af0f 100644
--- a/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxWs/TradeOrderWs.java
+++ b/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxWs/TradeOrderWs.java
@@ -13,6 +13,7 @@
import org.java_websocket.client.WebSocketClient;
import java.math.BigDecimal;
+import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
@@ -136,83 +137,85 @@
}
}
- public static void orderZhiYingZhiSunEventNoState(WebSocketClient webSocketClient, TradeRequestParam tradeRequestParam) {
+ public static void orderZhiYingZhiSunEventNoState(WebSocketClient webSocketClient, List<TradeRequestParam> tradeRequestParams) {
log.info("开始执行TradeOrderWs......");
- if (tradeRequestParam == null){
+ if (tradeRequestParams == null){
- log.warn("下单{}参数缺失,取消发送",tradeRequestParam);
+ log.warn("下单{}参数缺失,取消发送",tradeRequestParams);
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();
+ for (TradeRequestParam tradeRequestParam : tradeRequestParams){
+ 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 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)
+ 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,ordType, markPx, instId, posSide,side, sz, tradeType, clOrdId);
- //验证是否允许下单
- if (StrUtil.isNotEmpty(tradeType) && OrderParamEnums.TRADE_NO.getValue().equals(tradeType)) {
- log.warn("账户{}不允许下单,取消发送", accountName);
- return;
- }
+ ){
+ log.warn("下单参数缺失,取消发送");
+ continue;
+ }
+ log.info("账户:{},类型:{},触发价格:{},币种:{},方向:{},买卖:{},数量:{},是否允许下单:{},编号:{},",
+ accountName,ordType, markPx, instId, posSide,side, sz, tradeType, clOrdId);
+ //验证是否允许下单
+ if (StrUtil.isNotEmpty(tradeType) && OrderParamEnums.TRADE_NO.getValue().equals(tradeType)) {
+ log.warn("账户{}不允许下单,取消发送", accountName);
+ continue;
+ }
- /**
- * 检验账户和仓位是否准备就绪
- * 开多:买入开多(side 填写 buy; posSide 填写 long )
- * 开空:卖出开空(side 填写 sell; posSide 填写 short ) 需要检验账户通道是否准备就绪
- * 平多:卖出平多(side 填写 sell;posSide 填写 long )
- * 平空:买入平空(side 填写 buy; posSide 填写 short ) 需要检验仓位通道是否准备就绪
- */
+ /**
+ * 检验账户和仓位是否准备就绪
+ * 开多:买入开多(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);
+ 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);
+ 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);
+ 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);
+ } catch (Exception e) {
+ log.error("下单构建失败", e);
+ }
}
}
--
Gitblit v1.9.1