From b3b9edaf5eb570a899ce90d05310f6a1aef11807 Mon Sep 17 00:00:00 2001
From: Administrator <15274802129@163.com>
Date: Thu, 28 May 2026 16:52:34 +0800
Subject: [PATCH] feat(gateApi): 添加保证金比例限制和网格队列容量配置选项
---
src/main/java/com/xcong/excoin/modules/gateApi/GateGridTradeService.java | 300 +++++++++++++++++++++++++++++------------------------------
1 files changed, 146 insertions(+), 154 deletions(-)
diff --git a/src/main/java/com/xcong/excoin/modules/gateApi/GateGridTradeService.java b/src/main/java/com/xcong/excoin/modules/gateApi/GateGridTradeService.java
index f953866..4ee0d14 100644
--- a/src/main/java/com/xcong/excoin/modules/gateApi/GateGridTradeService.java
+++ b/src/main/java/com/xcong/excoin/modules/gateApi/GateGridTradeService.java
@@ -1,6 +1,8 @@
package com.xcong.excoin.modules.gateApi;
import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.util.StrUtil;
+import com.xcong.excoin.utils.dingtalk.DingTalkUtils;
import io.gate.gateapi.ApiClient;
import io.gate.gateapi.ApiException;
import io.gate.gateapi.GateApiException;
@@ -377,8 +379,8 @@
if (state != StrategyState.ACTIVE) {
return;
}
-// processLongGrid(closePrice);
-// processShortGrid(closePrice);
+ processLongGrid(closePrice);
+ processShortGrid(closePrice);
}
// ---- 仓位推送回调 ----
@@ -426,35 +428,8 @@
tryGenerateQueues();
}else {
longPositionSize = size;
- //取消多仓位线以上的开空仓挂单
- List<GridElement> allShortOrders = GridElement.findAllShortOrders(longEntryPrice);
- if (CollUtil.isNotEmpty(allShortOrders)){
- for (GridElement e : allShortOrders) {
- executor.cancelConditionalOrder(
- e.getShortOrderId(),
- orderId -> {
- shortEntryTraderIdParam(
- e,
- null,
- false
- );
- }
- );
-
- if (e.getShortTakeProfitOrderId() != null){
- executor.cancelConditionalOrder(
- e.getShortTakeProfitOrderId(),
- orderId -> {
- shortTakeProfitTraderIdParam(
- e,
- null,
- false
- );
- }
- );
- }
- }
- }
+ checkShortEntryOrderToCancel();
+ checkLongEntryOrderToCancel();
}
} else {
longActive = false;
@@ -472,38 +447,85 @@
tryGenerateQueues();
}else {
shortPositionSize = size.abs();
- //取消空仓仓位线以下的开多仓挂单
- List<GridElement> allLongOrders = GridElement.findAllLongOrders(shortEntryPrice);
- if (CollUtil.isNotEmpty(allLongOrders)){
- for (GridElement e : allLongOrders) {
- executor.cancelConditionalOrder(
- e.getLongOrderId(),
- orderId -> {
- longEntryTraderIdParam(
- e,
- null,
- false
- );
- }
- );
- if (e.getLongTakeProfitOrderId() != null){
- executor.cancelConditionalOrder(
- e.getLongTakeProfitOrderId(),
- orderId -> {
- longTakeProfitTraderIdParam(
- e,
- null,
- false
- );
- }
- );
- }
- }
- }
+ checkShortEntryOrderToCancel();
+ checkLongEntryOrderToCancel();
}
} else {
shortActive = false;
shortPositionSize = BigDecimal.ZERO;
+ }
+ }
+ }
+
+ private void checkShortEntryOrderToCancel() {
+ List<GridElement> allLongOrders = GridElement.findAllShortOrders(shortEntryPrice);
+ if (CollUtil.isNotEmpty(allLongOrders)){
+ GridElement keep = allLongOrders.stream()
+ .min((a, b) -> a.getGridPrice().compareTo(b.getGridPrice()))
+ .orElse(null);
+ for (GridElement e : allLongOrders) {
+ if (e == keep) {
+ continue;
+ }
+ executor.cancelConditionalOrder(
+ e.getShortOrderId(),
+ orderId -> {
+ shortEntryTraderIdParam(
+ e,
+ null,
+ false
+ );
+ }
+ );
+ if (e.getShortTakeProfitOrderId() != null){
+ executor.cancelConditionalOrder(
+ e.getShortTakeProfitOrderId(),
+ orderId -> {
+ shortTakeProfitTraderIdParam(
+ e,
+ null,
+ false
+ );
+ }
+ );
+ }
+ }
+ }
+ }
+
+ private void checkLongEntryOrderToCancel() {
+ List<GridElement> allShortOrders = GridElement.findAllLongOrders(longEntryPrice);
+ if (CollUtil.isNotEmpty(allShortOrders)){
+ GridElement keep = allShortOrders.stream()
+ .max((a, b) -> a.getGridPrice().compareTo(b.getGridPrice()))
+ .orElse(null);
+ for (GridElement e : allShortOrders) {
+ if (e == keep) {
+ continue;
+ }
+ executor.cancelConditionalOrder(
+ e.getLongOrderId(),
+ orderId -> {
+ longEntryTraderIdParam(
+ e,
+ null,
+ false
+ );
+ }
+ );
+
+ if (e.getLongTakeProfitOrderId() != null){
+ executor.cancelConditionalOrder(
+ e.getLongTakeProfitOrderId(),
+ orderId -> {
+ longTakeProfitTraderIdParam(
+ e,
+ null,
+ false
+ );
+ }
+ );
+ }
}
}
}
@@ -526,6 +548,7 @@
return;
}
cumulativePnl = cumulativePnl.add(pnl);
+ updateUnrealizedPnl();
BigDecimal totalPnl = cumulativePnl.add(unrealizedPnl);
log.info("[Gate] 已实现:{}, 未实现:{}, 合计:{}",
cumulativePnl, unrealizedPnl, totalPnl);
@@ -535,9 +558,13 @@
totalPnl, cumulativePnl, unrealizedPnl);
state = StrategyState.STOPPED;
} else if (totalPnl.compareTo(config.getMaxLoss().negate()) <= 0) {
- log.info("[Gate] 已达亏损上限(合计{})→已停止, 已实现:{}, 未实现:{}",
+ String logMessage = StrUtil.format("[Gate] 已达亏损风险值(合计{}), 已实现:{}, 未实现:{}",
totalPnl, cumulativePnl, unrealizedPnl);
- state = StrategyState.STOPPED;
+ log.info(logMessage);
+
+
+ DingTalkUtils.getDefault().sendActionCard("风险提醒", logMessage, config.getApiKey(), "");
+// state = StrategyState.STOPPED;
}
}
@@ -779,43 +806,20 @@
if (!isMarginSafe()) {
log.warn("[Gate] 保证金超限,跳过挂条件单");
} else {
-
- /**
- * 下一个开仓位置
- * 获取队列第一个元素的价格对应的网格
- * 判断网格是否能开空仓,如果不能则跳过
- * 前进方向挂空仓条件单
- * 后置方向挂多空条件单
- */
- //下一个开仓位置
- BigDecimal gridPrice = gridElement.getGridPrice();
-
- // 判断网格是否能开空仓,如果不能则跳过
- if (gridElement != null) {
- TraderParam downShortTraderParam = gridElement.getShortTraderParam();
+ // 判断网格是否能开多仓,如果不能则跳过
+ GridElement upGridElement = GridElement.findById(gridElement.getUpId());
+ if (upGridElement != null){
+ BigDecimal upGridPrice = upGridElement.getGridPrice();
+ TraderParam downLongTraderParam = upGridElement.getLongTraderParam();
if (
- !gridElement.isHasShortOrder() &&
- gridPrice.compareTo(longEntryPrice) <= 0 &&
- gridPrice.compareTo(shortEntryPrice) >= 0
+ !upGridElement.isHasLongOrder() &&
+ upGridPrice.compareTo(longEntryPrice) <= 0
){
- placeEntryOrderWithPreFlag(gridElement, false,
- downShortTraderParam.getEntryPrice(),
- FuturesPriceTrigger.RuleEnum.NUMBER_1,
- negate(downShortTraderParam.getQuantity()));
-
- }
-
- TraderParam downLongTraderParam = gridElement.getLongTraderParam();
- if (
- !gridElement.isHasLongOrder() &&
- gridPrice.compareTo(longEntryPrice) <= 0
- ){
- placeEntryOrderWithPreFlag(gridElement, true,
+ placeEntryOrderWithPreFlag(upGridElement, true,
downLongTraderParam.getEntryPrice(),
FuturesPriceTrigger.RuleEnum.NUMBER_1,
downLongTraderParam.getQuantity());
}
-
}
}
}
@@ -824,31 +828,18 @@
if (!isMarginSafe()) {
log.warn("[Gate] 保证金超限,跳过挂条件单");
} else {
- BigDecimal newLongFirst = gridElement.getGridPrice() ;
+ // 判断网格是否能开空仓,如果不能则跳过
+ GridElement downGridElement = GridElement.findById(gridElement.getDownId());
+ if (downGridElement != null){
- // 判断网格是否能开多空仓,如果不能则跳过
- if (gridElement != null) {
+ BigDecimal downGridPrice = downGridElement.getGridPrice();
- TraderParam downLongTraderParam = gridElement.getLongTraderParam();
+ TraderParam shortTraderParam = downGridElement.getShortTraderParam();
if (
- !gridElement.isHasLongOrder() &&
- newLongFirst.compareTo(shortEntryPrice) >= 0 &&
- newLongFirst.compareTo(longEntryPrice) <= 0
+ !downGridElement.isHasShortOrder() &&
+ downGridPrice.compareTo(shortEntryPrice) >= 0
){
- placeEntryOrderWithPreFlag(gridElement, true,
- downLongTraderParam.getEntryPrice(),
- FuturesPriceTrigger.RuleEnum.NUMBER_2,
- config.getQuantity());
-
- }
-
- TraderParam shortTraderParam = gridElement.getShortTraderParam();
- if (
- !gridElement.isHasShortOrder() &&
- newLongFirst.compareTo(shortEntryPrice) >= 0
- ){
-
- placeEntryOrderWithPreFlag(gridElement, false,
+ placeEntryOrderWithPreFlag(downGridElement, false,
shortTraderParam.getEntryPrice(),
FuturesPriceTrigger.RuleEnum.NUMBER_2,
negate(config.getQuantity()));
@@ -1096,8 +1087,9 @@
int longSize = longPriceQueue.size();
//根据精度转换成小数
int prec = config.getPriceScale();
- BigDecimal minTick = BigDecimal.ONE.scaleByPowerOfTen(-prec);
- BigDecimal step = config.getStep().subtract(minTick);
+// BigDecimal minTick = BigDecimal.ONE.scaleByPowerOfTen(-prec);
+// BigDecimal step = config.getStep().subtract(minTick);
+ BigDecimal step = config.getStep();
String qty = config.getQuantity();
// 空仓队列:id 从 -1 自减, shortPriceQueue[i] → id=-(i+1)
@@ -1244,32 +1236,32 @@
// 判断网格是否能开空仓,如果不能则跳过
if (UpGridElement != null) {
- if (!UpGridElement.isHasShortOrder() && shortEntryPrice.compareTo(newLongFirst) > 0) {
-
- TraderParam upShortTraderParam = UpGridElement.getShortTraderParam();
- placeEntryOrderWithPreFlag(UpGridElement, false,
- upShortTraderParam.getEntryPrice(),
- FuturesPriceTrigger.RuleEnum.NUMBER_2,
- negate(upShortTraderParam.getQuantity()));
- }
+// if (!UpGridElement.isHasShortOrder() && shortEntryPrice.compareTo(newLongFirst) > 0) {
+//
+// TraderParam upShortTraderParam = UpGridElement.getShortTraderParam();
+// placeEntryOrderWithPreFlag(UpGridElement, false,
+// upShortTraderParam.getEntryPrice(),
+// FuturesPriceTrigger.RuleEnum.NUMBER_2,
+// negate(upShortTraderParam.getQuantity()));
+// }
int i = UpGridElement.getId() + 2;
GridElement downGridElement = GridElement.findById(i);
if (downGridElement != null){
BigDecimal downGridPrice = downGridElement.getGridPrice();
- TraderParam downShortTraderParam = downGridElement.getShortTraderParam();
- if (
- !downGridElement.isHasShortOrder() &&
- downGridPrice.compareTo(longEntryPrice) <= 0 &&
- downGridPrice.compareTo(shortEntryPrice) >= 0
- ){
- placeEntryOrderWithPreFlag(downGridElement, false,
- downShortTraderParam.getEntryPrice(),
- FuturesPriceTrigger.RuleEnum.NUMBER_1,
- negate(downShortTraderParam.getQuantity()));
-
- }
+// TraderParam downShortTraderParam = downGridElement.getShortTraderParam();
+// if (
+// !downGridElement.isHasShortOrder() &&
+// downGridPrice.compareTo(longEntryPrice) <= 0 &&
+// downGridPrice.compareTo(shortEntryPrice) >= 0
+// ){
+// placeEntryOrderWithPreFlag(downGridElement, false,
+// downShortTraderParam.getEntryPrice(),
+// FuturesPriceTrigger.RuleEnum.NUMBER_1,
+// negate(downShortTraderParam.getQuantity()));
+//
+// }
TraderParam downLongTraderParam = downGridElement.getLongTraderParam();
if (
@@ -1350,13 +1342,13 @@
// 判断网格是否能开多仓,如果不能则跳过
if (UpGridElement != null) {
- if (!UpGridElement.isHasLongOrder() && longEntryPrice.compareTo(newLongFirst) < 0) {
- TraderParam upLongTraderParam = UpGridElement.getLongTraderParam();
- placeEntryOrderWithPreFlag(UpGridElement, true,
- upLongTraderParam.getEntryPrice(),
- FuturesPriceTrigger.RuleEnum.NUMBER_1,
- config.getQuantity());
- }
+// if (!UpGridElement.isHasLongOrder() && longEntryPrice.compareTo(newLongFirst) < 0) {
+// TraderParam upLongTraderParam = UpGridElement.getLongTraderParam();
+// placeEntryOrderWithPreFlag(UpGridElement, true,
+// upLongTraderParam.getEntryPrice(),
+// FuturesPriceTrigger.RuleEnum.NUMBER_1,
+// config.getQuantity());
+// }
int i = UpGridElement.getId() - 2;
GridElement downGridElement = GridElement.findById(i);
@@ -1364,18 +1356,18 @@
BigDecimal downGridPrice = downGridElement.getGridPrice();
- TraderParam downLongTraderParam = downGridElement.getLongTraderParam();
- if (
- !downGridElement.isHasLongOrder() &&
- downGridPrice.compareTo(shortEntryPrice) >= 0 &&
- downGridPrice.compareTo(longEntryPrice) <= 0
- ){
- placeEntryOrderWithPreFlag(downGridElement, true,
- downLongTraderParam.getEntryPrice(),
- FuturesPriceTrigger.RuleEnum.NUMBER_2,
- config.getQuantity());
-
- }
+// TraderParam downLongTraderParam = downGridElement.getLongTraderParam();
+// if (
+// !downGridElement.isHasLongOrder() &&
+// downGridPrice.compareTo(shortEntryPrice) >= 0 &&
+// downGridPrice.compareTo(longEntryPrice) <= 0
+// ){
+// placeEntryOrderWithPreFlag(downGridElement, true,
+// downLongTraderParam.getEntryPrice(),
+// FuturesPriceTrigger.RuleEnum.NUMBER_2,
+// config.getQuantity());
+//
+// }
TraderParam shortTraderParam = downGridElement.getShortTraderParam();
if (
--
Gitblit v1.9.1