From 74a275cb88dfb60eb5f14b16bf4dced3753619ed Mon Sep 17 00:00:00 2001
From: Administrator <15274802129@163.com>
Date: Mon, 18 May 2026 17:31:26 +0800
Subject: [PATCH] 第二个版本
---
src/main/java/com/xcong/excoin/modules/gateApi/GateGridTradeService.java | 661 +++++++++++++++++++++++++++++++++++++++++++-----------
1 files changed, 522 insertions(+), 139 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 409f59c..4b4e83c 100644
--- a/src/main/java/com/xcong/excoin/modules/gateApi/GateGridTradeService.java
+++ b/src/main/java/com/xcong/excoin/modules/gateApi/GateGridTradeService.java
@@ -360,15 +360,23 @@
return;
}
+ //初始化0位置的开仓,并且用空的开仓价格,作为价格基准来划分网格
if (state == StrategyState.WAITING_KLINE) {
state = StrategyState.OPENING;
log.info("[Gate] 首根K线到达,开基底仓位...");
executor.openLong(config.getQuantity(), (orderId) -> {
- log.info("[Gate] 基底多单已提交{}", orderId);
+ TraderParam baseLongTp = TraderParam.builder()
+ .entryOrderId(orderId)
+ .build();
+ config.setBaseLongTraderParam(baseLongTp);
}, null);
executor.openShort(negate(config.getQuantity()), (orderId) -> {
- log.info("[Gate] 基底空单已提交{}",orderId);
+ TraderParam baseShortTp = TraderParam.builder()
+ .entryOrderId(orderId)
+ .build();
+ config.setBaseShortTraderParam(baseShortTp);
}, null);
+
return;
}
@@ -422,32 +430,12 @@
baseLongOpened = true;
log.info("[Gate] 基底多成交价: {}", longBaseEntryPrice);
tryGenerateQueues();
- } else if(size.compareTo(longPositionSize) < 0){
- if (entryPrice.compareTo(shortEntryPrice) > 0
- && entryPrice.compareTo(longEntryPrice) < 0
- && shortPositionSize.compareTo(new BigDecimal("3")) < 0) {
-
- BigDecimal reverseShortTp = entryPrice.subtract(config.getStep()).setScale(1, RoundingMode.HALF_UP);
- executor.openShort(negate(config.getQuantity()),
- orderId -> { currentShortOrderIds.put(orderId, reverseShortTp);},
- null);
- log.info("[Gate] 反向条件空单已挂, trigger:{}, size:{}, 止盈:{}", entryPrice, negate(config.getQuantity()), reverseShortTp);
- }
- } else {
+ }else {
longPositionSize = size;
}
} else {
longActive = false;
longPositionSize = BigDecimal.ZERO;
- }
- synchronized (currentLongOrderIds) {
- if (currentLongOrderIds.size() > 5) {
- Iterator<String> it = currentLongOrderIds.keySet().iterator();
- for (int i = 0, remove = currentLongOrderIds.size() - 5; i < remove; i++) {
- it.next();
- it.remove();
- }
- }
}
} else if (Position.ModeEnum.DUAL_SHORT == mode) {
if (hasPosition) {
@@ -459,32 +447,12 @@
baseShortOpened = true;
log.info("[Gate] 基底空成交价: {}", shortBaseEntryPrice);
tryGenerateQueues();
- } else if(size.abs().compareTo(shortPositionSize) < 0){
- if (entryPrice.compareTo(shortEntryPrice) > 0
- && entryPrice.compareTo(longEntryPrice) < 0
- && longPositionSize.compareTo(new BigDecimal("3")) < 0) {
-
- BigDecimal reverseLongTp = entryPrice.add(config.getStep()).setScale(1, RoundingMode.HALF_UP);
- executor.openLong(config.getQuantity(),
- orderId -> { currentLongOrderIds.put(orderId, reverseLongTp);},
- null);
- log.info("[Gate] 反向条件多单已挂, trigger:{}, size:{}, 止盈:{}", entryPrice, negate(config.getQuantity()), reverseLongTp);
- }
- } else {
+ }else {
shortPositionSize = size.abs();
}
} else {
shortActive = false;
shortPositionSize = BigDecimal.ZERO;
- }
- synchronized (currentShortOrderIds) {
- if (currentShortOrderIds.size() > 5) {
- Iterator<String> it = currentShortOrderIds.keySet().iterator();
- for (int i = 0, remove = currentShortOrderIds.size() - 5; i < remove; i++) {
- it.next();
- it.remove();
- }
- }
}
}
}
@@ -536,18 +504,84 @@
if (!"finished".equals(status) || !"filled".equals(finishAs)) {
return;
}
- BigDecimal longTp = currentLongOrderIds.remove(orderId);
- if (longTp != null) {
- executor.placeTakeProfit(longTp,
- FuturesPriceTrigger.RuleEnum.NUMBER_1, ORDER_TYPE_CLOSE_LONG, negate(config.getQuantity()));
- log.info("[Gate] 多单成交匹配止盈, orderId:{}, 止盈价:{}, size:{}", orderId, longTp, negate(config.getQuantity()));
- return;
+
+ /**
+ * 匹配止盈单止盈
+ */
+ GridElement byLongTakeProfitOrderId = GridElement.findByLongTakeProfitOrderId(orderId);
+ if (byLongTakeProfitOrderId != null){
+ longTakeProfitTraderIdParam(
+ byLongTakeProfitOrderId,
+ null,
+ false
+ );
+ longEntryTraderIdParam(
+ byLongTakeProfitOrderId,
+ null,
+ false
+ );
}
- BigDecimal shortTp = currentShortOrderIds.remove(orderId);
- if (shortTp != null) {
- executor.placeTakeProfit(shortTp,
- FuturesPriceTrigger.RuleEnum.NUMBER_2, ORDER_TYPE_CLOSE_SHORT, config.getQuantity());
- log.info("[Gate] 空单成交匹配止盈, orderId:{}, 止盈价:{}, size:{}", orderId, shortTp, config.getQuantity());
+ GridElement byShortTakeProfitOrderId = GridElement.findByShortTakeProfitOrderId(orderId);
+ if (byShortTakeProfitOrderId != null){
+ shortTakeProfitTraderIdParam(
+ byShortTakeProfitOrderId,
+ null,
+ false
+ );
+ shortEntryTraderIdParam(
+ byShortTakeProfitOrderId,
+ null,
+ false
+ );
+ }
+
+ /**
+ * 匹配挂单
+ */
+ GridElement longGridElement = GridElement.findByLongOrderId(orderId);
+ if (longGridElement != null) {
+ if (longGridElement.isHasLongOrder()){
+ if (longGridElement.getLongTakeProfitOrderId() == null){
+ BigDecimal longTp = longGridElement.getLongTraderParam().getTakeProfitPrice();
+ if (longTp != null) {
+ executor.placeTakeProfit(longTp,
+ FuturesPriceTrigger.RuleEnum.NUMBER_1,
+ ORDER_TYPE_CLOSE_LONG,
+ negate(config.getQuantity()),
+ (profitId) -> {
+ longTakeProfitTraderIdParam(
+ longGridElement,
+ profitId,
+ true
+ );
+ });
+ log.info("[Gate] 多单成交匹配止盈, orderId:{}, 止盈价:{}, size:{}", orderId, longTp, negate(config.getQuantity()));
+ return;
+ }
+ }
+ }
+ }
+ GridElement shortGridElement = GridElement.findByShortOrderId(orderId);
+ if (shortGridElement != null) {
+ if (shortGridElement.isHasShortOrder()){
+ if (shortGridElement.getShortTakeProfitOrderId() == null){
+ BigDecimal shortTp = shortGridElement.getShortTraderParam().getTakeProfitPrice();
+ if (shortTp != null) {
+ executor.placeTakeProfit(shortTp,
+ FuturesPriceTrigger.RuleEnum.NUMBER_2,
+ ORDER_TYPE_CLOSE_SHORT,
+ config.getQuantity(),
+ (profitId) -> {
+ shortTakeProfitTraderIdParam(
+ shortGridElement,
+ profitId,
+ true
+ );
+ });
+ log.info("[Gate] 空单成交匹配止盈, orderId:{}, 止盈价:{}, size:{}", orderId, shortTp, config.getQuantity());
+ }
+ }
+ }
}
}
@@ -567,33 +601,135 @@
*/
private void tryGenerateQueues() {
if (baseLongOpened && baseShortOpened) {
+ //初始化空仓队列
generateShortQueue();
+ //初始化多仓队列
generateLongQueue();
+ //初始化网格数据
+ updateGridElements();
- BigDecimal step = config.getStep();
+ /**
+ * 挂初始位置多空仓条件单
+ * 0位置的多单止盈
+ * 0位置的空单止盈
+ */
+ GridElement baseGridElement = GridElement.findById(0);
+ TraderParam baseLongTraderParam = config.getBaseLongTraderParam();
+ baseGridElement.setLongOrderId(baseLongTraderParam.getEntryOrderId());
+ //0位置的网格的多单止盈
+ BigDecimal upTakeProfitPrice = baseGridElement.getLongTraderParam().getTakeProfitPrice();
+ executor.placeTakeProfit(
+ upTakeProfitPrice,
+ FuturesPriceTrigger.RuleEnum.NUMBER_1,
+ ORDER_TYPE_CLOSE_LONG,
+ negate(config.getQuantity()),
+ profitId -> {
+ longTakeProfitTraderIdParam(
+ baseGridElement,
+ profitId,
+ true
+ );
+ }
+ );
+ //0位置的网格的空单止盈
+ TraderParam baseShortTraderParam = config.getBaseShortTraderParam();
+ baseGridElement.setShortOrderId(baseShortTraderParam.getEntryOrderId());
+ BigDecimal downTakeProfitPrice = baseGridElement.getShortTraderParam().getTakeProfitPrice();
+ executor.placeTakeProfit(
+ downTakeProfitPrice,
+ FuturesPriceTrigger.RuleEnum.NUMBER_2,
+ ORDER_TYPE_CLOSE_SHORT,
+ config.getQuantity(),
+ profitId -> {
+ shortTakeProfitTraderIdParam(
+ baseGridElement,
+ profitId,
+ true
+ );
+ }
+ );
- BigDecimal longPriceQueueOne = longPriceQueue.get(0);
- BigDecimal longTp = longPriceQueueOne.add(step).setScale(1, RoundingMode.HALF_UP);
- executor.placeConditionalEntryOrder(longPriceQueueOne,
- FuturesPriceTrigger.RuleEnum.NUMBER_1, config.getQuantity(),
- orderId -> { currentLongOrderIds.put(orderId, longTp); log.info("[Gate] 初始条件多单已挂, id:{}, trigger:{}, 止盈:{}", orderId, longPriceQueue.get(0), longTp); },
+ /**
+ * 挂初始位置的up位置的多单
+ * 挂初始位置的down位置的空单
+ */
+ Integer upId = baseGridElement.getUpId();
+ GridElement upGridElementOne = GridElement.findById(upId);
+ BigDecimal longTp = upGridElementOne.getGridPrice();
+ executor.placeConditionalEntryOrder(
+ longTp,
+ FuturesPriceTrigger.RuleEnum.NUMBER_1,
+ config.getQuantity(),
+ orderId -> {
+ longEntryTraderIdParam(
+ upGridElementOne,
+ orderId,
+ true
+ );
+ },
+ null);
+ Integer downId = baseGridElement.getDownId();
+ GridElement downGridElementOne = GridElement.findById(downId);
+ BigDecimal shortTp = downGridElementOne.getGridPrice();
+ executor.placeConditionalEntryOrder(
+ shortTp,
+ FuturesPriceTrigger.RuleEnum.NUMBER_2,
+ negate(config.getQuantity()),
+ orderId -> {
+ shortEntryTraderIdParam(
+ downGridElementOne,
+ orderId,
+ true
+ );
+ },
null);
-
- BigDecimal shortPriceQueueOne = shortPriceQueue.get(0);
- BigDecimal shortTp = shortPriceQueueOne.subtract(step).setScale(1, RoundingMode.HALF_UP);
- executor.placeConditionalEntryOrder(shortPriceQueueOne,
- FuturesPriceTrigger.RuleEnum.NUMBER_2, negate(config.getQuantity()),
- orderId -> { currentShortOrderIds.put(orderId, shortTp); log.info("[Gate] 初始条件空单已挂, id:{}, trigger:{}, 止盈:{}", orderId, shortPriceQueue.get(0), shortTp); },
- null);
-
-
- log.info("[Gate] 网格队列已生成, 空队首:{} → 尾:{}, 多队首:{} → 尾:{}, step:{}, 已激活",
- shortPriceQueueOne, shortPriceQueue.get(shortPriceQueue.size() - 1),
- longPriceQueueOne, longPriceQueue.get(longPriceQueue.size() - 1),
- step);
state = StrategyState.ACTIVE;
}
+ }
+
+ /**
+ * 更新基座止盈信息,将止盈价、订单ID等写入 TraderParam 并回填到 ID=0 的网格元素中。
+ */
+ private void longTakeProfitTraderIdParam(
+ GridElement baseElement,String profitId, boolean flag
+ ) {
+ TraderParam tp = baseElement.getLongTraderParam();
+ tp.setTakeProfitOrderId(profitId);
+ tp.setTakeProfitPlaced(flag);
+ baseElement.setLongTakeProfitOrderId(profitId);
+ GridElement.refreshIndices();
+ }
+ private void shortTakeProfitTraderIdParam(
+ GridElement baseElement,String profitId, boolean flag
+ ) {
+ TraderParam tp = baseElement.getShortTraderParam();
+ tp.setTakeProfitOrderId(profitId);
+ tp.setTakeProfitPlaced(flag);
+ baseElement.setShortTakeProfitOrderId(profitId);
+ GridElement.refreshIndices();
+ }
+
+ private void longEntryTraderIdParam(
+ GridElement baseElement,String entryId,boolean flag
+ ) {
+ TraderParam tp = baseElement.getLongTraderParam();
+ tp.setEntryOrderId(entryId);
+ tp.setEntryOrderPlaced(flag);
+ baseElement.setHasLongOrder(flag);
+ baseElement.setLongOrderId(entryId);
+ GridElement.refreshIndices();
+ }
+
+ private void shortEntryTraderIdParam(
+ GridElement baseElement, String entryId, boolean flag
+ ) {
+ TraderParam tp = baseElement.getShortTraderParam();
+ tp.setEntryOrderId(entryId);
+ tp.setEntryOrderPlaced(flag);
+ baseElement.setHasShortOrder(flag);
+ baseElement.setShortOrderId(entryId);
+ GridElement.refreshIndices();
}
/**
@@ -604,13 +740,17 @@
*/
private void generateShortQueue() {
shortPriceQueue.clear();
- BigDecimal step = shortBaseEntryPrice.multiply(config.getGridRate()).setScale(1, RoundingMode.HALF_UP);
+ int prec = config.getPriceScale();
+ BigDecimal step = shortBaseEntryPrice.multiply(config.getGridRate()).setScale(prec, RoundingMode.HALF_UP);
config.setStep(step);
- BigDecimal elem = shortBaseEntryPrice.subtract(step).setScale(1, RoundingMode.HALF_UP);
- for (int i = 0; i < config.getGridQueueSize(); i++) {
- shortPriceQueue.add(elem);
- elem = elem.subtract(step).setScale(1, RoundingMode.HALF_UP);
- }
+ BigDecimal elem = shortBaseEntryPrice.subtract(step).setScale(prec, RoundingMode.HALF_UP);
+ for (int i = 0; i < config.getGridQueueSize(); i++) {
+ shortPriceQueue.add(elem);
+ elem = elem.subtract(step).setScale(prec, RoundingMode.HALF_UP);
+ if (elem.compareTo(BigDecimal.ZERO) <= 0) {
+ break;
+ }
+ }
shortPriceQueue.sort((a, b) -> b.compareTo(a));
log.info("[Gate] 空队列:{}", shortPriceQueue);
}
@@ -622,14 +762,124 @@
*/
private void generateLongQueue() {
longPriceQueue.clear();
+ int prec = config.getPriceScale();
BigDecimal step = config.getStep();
- BigDecimal elem = shortBaseEntryPrice.add(step).setScale(1, RoundingMode.HALF_UP);
+ BigDecimal elem = shortBaseEntryPrice.add(step).setScale(prec, RoundingMode.HALF_UP);
for (int i = 0; i < config.getGridQueueSize(); i++) {
longPriceQueue.add(elem);
- elem = elem.add(step).setScale(1, RoundingMode.HALF_UP);
+ elem = elem.add(step).setScale(prec, RoundingMode.HALF_UP);
}
longPriceQueue.sort(BigDecimal::compareTo);
log.info("[Gate] 多队列:{}", longPriceQueue);
+ }
+
+ /**
+ * 根据当前多空价格队列同步构建网格元素列表,写入 config。
+ *
+ * <h3>ID 分配规则</h3>
+ * <ul>
+ * <li>空仓队列:id 从 -1 自减(-1, -2, -3...),第一个元素 upId=0,最后一个 downId=null</li>
+ * <li>位置 0:gridPrice=shortBaseEntryPrice,upId=-1,downId=1,其数据在基座开仓时更新</li>
+ * <li>多仓队列:id 从 1 自增(1, 2, 3...),第一个元素 upId=0,最后一个 downId=null</li>
+ * </ul>
+ *
+ * <h3>链表关系</h3>
+ * 所有元素通过 upId/downId 串成一条双向链表:
+ * ... → -3 → -2 → -1 → 0 → 1 → 2 → 3 → ...
+ */
+ private void updateGridElements() {
+ List<GridElement> elements = new ArrayList<>();
+ int shortSize = shortPriceQueue.size();
+ int longSize = longPriceQueue.size();
+ //根据精度转换成小数
+ int prec = config.getPriceScale();
+ BigDecimal minTick = BigDecimal.ONE.scaleByPowerOfTen(-prec);
+ BigDecimal step = config.getStep().subtract(minTick);
+ String qty = config.getQuantity();
+
+ // 空仓队列:id 从 -1 自减, shortPriceQueue[i] → id=-(i+1)
+ for (int i = 0; i < shortSize; i++) {
+ int id = -(i + 1);
+ Integer upId = (i == 0) ? 0 : id + 1;
+ Integer downId = (i == shortSize - 1) ? null : id - 1;
+ BigDecimal price = shortPriceQueue.get(i);
+ TraderParam longParam = TraderParam.builder()
+ .direction(TraderParam.Direction.LONG)
+ .entryPrice(price)
+ .takeProfitPrice(price.add(step).setScale(prec, RoundingMode.HALF_UP))
+ .quantity(qty)
+ .build();
+ TraderParam shortParam = TraderParam.builder()
+ .direction(TraderParam.Direction.SHORT)
+ .entryPrice(price)
+ .takeProfitPrice(price.subtract(step).setScale(prec, RoundingMode.HALF_UP))
+ .quantity(qty)
+ .build();
+ elements.add(GridElement.builder()
+ .id(id)
+ .gridPrice(price)
+ .upId(upId)
+ .downId(downId)
+ .longTraderParam(longParam)
+ .shortTraderParam(shortParam)
+ .build());
+ }
+
+ // 位置 0:基底价格,数据在基座开仓时更新
+ {
+ BigDecimal price = shortBaseEntryPrice;
+ TraderParam longParam = TraderParam.builder()
+ .direction(TraderParam.Direction.LONG)
+ .entryPrice(price)
+ .takeProfitPrice(price.add(step).setScale(prec, RoundingMode.HALF_UP))
+ .quantity(qty)
+ .build();
+ TraderParam shortParam = TraderParam.builder()
+ .direction(TraderParam.Direction.SHORT)
+ .entryPrice(price)
+ .takeProfitPrice(price.subtract(step).setScale(prec, RoundingMode.HALF_UP))
+ .quantity(qty)
+ .build();
+ elements.add(GridElement.builder()
+ .id(0)
+ .gridPrice(price)
+ .upId(shortSize > 0 ? 1 : null)
+ .downId(longSize > 0 ? -1 : null)
+ .longTraderParam(longParam)
+ .shortTraderParam(shortParam)
+ .build());
+ }
+
+ // 多仓队列:id 从 1 自增, longPriceQueue[i] → id=i+1
+ for (int i = 0; i < longSize; i++) {
+ int id = i + 1;
+ Integer downId = (i == 0) ? 0 : id - 1;
+ Integer upId = (i == longSize - 1) ? null : id + 1;
+ BigDecimal price = longPriceQueue.get(i);
+ TraderParam longParam = TraderParam.builder()
+ .direction(TraderParam.Direction.LONG)
+ .entryPrice(price)
+ .takeProfitPrice(price.add(step).setScale(prec, RoundingMode.HALF_UP))
+ .quantity(qty)
+ .build();
+ TraderParam shortParam = TraderParam.builder()
+ .direction(TraderParam.Direction.SHORT)
+ .entryPrice(price)
+ .takeProfitPrice(price.subtract(step).setScale(prec, RoundingMode.HALF_UP))
+ .quantity(qty)
+ .build();
+ elements.add(GridElement.builder()
+ .id(id)
+ .gridPrice(price)
+ .upId(upId)
+ .downId(downId)
+ .longTraderParam(longParam)
+ .shortTraderParam(shortParam)
+ .build());
+ }
+
+ config.setGridElements(elements);
+ log.info("[Gate] 网格元素列表已构建, 共{}个元素 (空仓:{} 位置:0 多仓:{})", elements.size(), shortSize, longSize);
}
/**
@@ -657,6 +907,7 @@
* @param currentPrice 当前 K 线收盘价(最新成交价)
*/
private void processShortGrid(BigDecimal currentPrice) {
+ int prec = config.getPriceScale();
List<BigDecimal> matched = new ArrayList<>();
synchronized (shortPriceQueue) {
for (BigDecimal p : shortPriceQueue) {
@@ -677,45 +928,111 @@
BigDecimal min = shortPriceQueue.isEmpty() ? matched.get(matched.size() - 1) : shortPriceQueue.get(shortPriceQueue.size() - 1);
BigDecimal gridStep = config.getStep();
for (int i = 0; i < matched.size(); i++) {
- min = min.subtract(gridStep).setScale(1, RoundingMode.HALF_UP);
+ min = min.subtract(gridStep).setScale(prec, RoundingMode.HALF_UP);
shortPriceQueue.add(min);
}
shortPriceQueue.sort((a, b) -> b.compareTo(a));
}
-// synchronized (longPriceQueue) {
-// BigDecimal first = longPriceQueue.isEmpty() ? matched.get(matched.size() - 1) : longPriceQueue.get(0);
-// BigDecimal gridStep = config.getStep();
-// for (int i = 1; i <= matched.size(); i++) {
-// BigDecimal elem = first.subtract(gridStep.multiply(BigDecimal.valueOf(i))).setScale(1, RoundingMode.HALF_UP);
-// longPriceQueue.add(elem);
-// }
-// longPriceQueue.sort(BigDecimal::compareTo);
-// while (longPriceQueue.size() > config.getGridQueueSize()) {
-// longPriceQueue.remove(longPriceQueue.size() - 1);
-// }
-// }
+ synchronized (longPriceQueue) {
+ BigDecimal first = longPriceQueue.isEmpty() ? matched.get(matched.size() - 1) : longPriceQueue.get(0);
+ BigDecimal gridStep = config.getStep();
+ for (int i = 1; i <= matched.size(); i++) {
+ BigDecimal elem = first.subtract(gridStep.multiply(BigDecimal.valueOf(i))).setScale(prec, RoundingMode.HALF_UP);
+ longPriceQueue.add(elem);
+ }
+ longPriceQueue.sort(BigDecimal::compareTo);
+ while (longPriceQueue.size() > config.getGridQueueSize()) {
+ longPriceQueue.remove(longPriceQueue.size() - 1);
+ }
+ }
if (!isMarginSafe()) {
log.warn("[Gate] 保证金超限,跳过挂条件单");
} else {
- BigDecimal newShortFirst = shortPriceQueue.get(0);
- BigDecimal step = config.getStep();
- BigDecimal stpElem = newShortFirst.subtract(step).setScale(1, RoundingMode.HALF_UP);
- executor.placeConditionalEntryOrder(newShortFirst,
- FuturesPriceTrigger.RuleEnum.NUMBER_2, negate(config.getQuantity()),
- orderId -> { currentShortOrderIds.put(orderId, stpElem); log.info("[Gate] 新条件空单, id:{}, trigger:{}, 止盈:{}", orderId, newShortFirst, stpElem); },
- null);
+ /**
+ * 下一个开仓位置
+ * 获取队列第一个元素的价格对应的网格
+ * 判断网格是否能开空仓,如果不能则跳过
+ * 前进方向挂空仓条件单
+ * 后置方向挂多空条件单
+ */
+ //下一个开仓位置
+ BigDecimal newLongFirst = shortPriceQueue.get(0);
+ GridElement UpGridElement = GridElement.findByPrice(newLongFirst);
- BigDecimal newLongFirst = newShortFirst.add( step.multiply(new BigDecimal("2")));
- if (newLongFirst.compareTo(longEntryPrice) < 0) {
+ // 判断网格是否能开空仓,如果不能则跳过
+ if (UpGridElement != null) {
- BigDecimal ltpElem = newLongFirst.add(step).setScale(1, RoundingMode.HALF_UP);
- executor.placeConditionalEntryOrder(newLongFirst,
- FuturesPriceTrigger.RuleEnum.NUMBER_1, config.getQuantity(),
- orderId -> { currentLongOrderIds.put(orderId, ltpElem); log.info("[Gate] 新条件多单, id:{}, trigger:{}, 止盈:{}", orderId, newLongFirst, ltpElem); },
- null);
+ if (!UpGridElement.isHasShortOrder()) {
+
+ //挂空仓条件单
+ TraderParam upShortTraderParam = UpGridElement.getShortTraderParam();
+ executor.placeConditionalEntryOrder(
+ upShortTraderParam.getEntryPrice(),
+ FuturesPriceTrigger.RuleEnum.NUMBER_2,
+ negate(upShortTraderParam.getQuantity()),
+ orderId ->
+ {
+ shortEntryTraderIdParam(
+ UpGridElement,
+ orderId,
+ true
+ );
+ },
+ null
+ );
+ }
+ }
+
+
+
+ int i = UpGridElement.getId() + 2;
+ GridElement downGridElement = GridElement.findById(i);
+ if (downGridElement != null){
+
+ TraderParam downLongTraderParam = downGridElement.getLongTraderParam();
+ if (!downGridElement.isHasShortOrder()){
+ executor.placeConditionalEntryOrder(
+ downLongTraderParam.getEntryPrice(),
+ FuturesPriceTrigger.RuleEnum.NUMBER_1,
+ downLongTraderParam.getQuantity(),
+ orderId ->
+ {
+ longEntryTraderIdParam(
+ downGridElement,
+ orderId,
+ true
+ );
+ },
+ null
+ );
+ }
+
+ TraderParam downShortTraderParam = downGridElement.getShortTraderParam();
+ BigDecimal downGridPrice = downGridElement.getGridPrice();
+ if (
+ !downGridElement.isHasShortOrder() &&
+ downGridPrice.compareTo(longEntryPrice) <= 0 &&
+ downGridPrice.compareTo(shortEntryPrice) >= 0
+ ){
+ executor.placeConditionalEntryOrder(
+ downShortTraderParam.getEntryPrice(),
+ FuturesPriceTrigger.RuleEnum.NUMBER_2,
+ negate(downShortTraderParam.getQuantity()),
+ orderId ->
+ {
+ shortEntryTraderIdParam(
+ downGridElement,
+ orderId,
+ true
+ );
+ },
+ null
+ );
+
+ }
}
}
@@ -747,6 +1064,7 @@
* @param currentPrice 当前 K 线收盘价(最新成交价)
*/
private void processLongGrid(BigDecimal currentPrice) {
+ int prec = config.getPriceScale();
List<BigDecimal> matched = new ArrayList<>();
synchronized (longPriceQueue) {
for (BigDecimal p : longPriceQueue) {
@@ -763,54 +1081,119 @@
log.info("[Gate] 多仓队列触发, 匹配{}个元素, 当前价:{}", matched.size(), currentPrice);
+ /**
+ * 匹配到元素后,
+ * 多仓队列更新
+ * 空仓队列更新
+ */
synchronized (longPriceQueue) {
longPriceQueue.removeAll(matched);
BigDecimal max = longPriceQueue.isEmpty() ? matched.get(matched.size() - 1) : longPriceQueue.get(longPriceQueue.size() - 1);
BigDecimal gridStep = config.getStep();
for (int i = 0; i < matched.size(); i++) {
- max = max.add(gridStep).setScale(1, RoundingMode.HALF_UP);
+ max = max.add(gridStep).setScale(prec, RoundingMode.HALF_UP);
longPriceQueue.add(max);
}
longPriceQueue.sort(BigDecimal::compareTo);
}
-
-// synchronized (shortPriceQueue) {
-// BigDecimal first = shortPriceQueue.isEmpty() ? matched.get(0) : shortPriceQueue.get(0);
-// BigDecimal gridStep = config.getStep();
-// for (int i = 1; i <= matched.size(); i++) {
-// BigDecimal elem = first.add(gridStep.multiply(BigDecimal.valueOf(i))).setScale(1, RoundingMode.HALF_UP);
-// shortPriceQueue.add(elem);
-// }
-// shortPriceQueue.sort((a, b) -> b.compareTo(a));
-// while (shortPriceQueue.size() > config.getGridQueueSize()) {
-// shortPriceQueue.remove(shortPriceQueue.size() - 1);
-// }
-// }
-
-
+ synchronized (shortPriceQueue) {
+ BigDecimal first = shortPriceQueue.isEmpty() ? matched.get(0) : shortPriceQueue.get(0);
+ BigDecimal gridStep = config.getStep();
+ for (int i = 1; i <= matched.size(); i++) {
+ BigDecimal elem = first.add(gridStep.multiply(BigDecimal.valueOf(i))).setScale(prec, RoundingMode.HALF_UP);
+ shortPriceQueue.add(elem);
+ }
+ shortPriceQueue.sort((a, b) -> b.compareTo(a));
+ while (shortPriceQueue.size() > config.getGridQueueSize()) {
+ shortPriceQueue.remove(shortPriceQueue.size() - 1);
+ }
+ }
if (!isMarginSafe()) {
log.warn("[Gate] 保证金超限,跳过挂条件单");
} else {
- BigDecimal step = config.getStep();
-
+ /**
+ * 下一个开仓位置
+ * 获取队列第一个元素的价格对应的网格
+ * 判断网格是否能开多仓,如果不能则跳过
+ * 前进方向挂多仓条件单
+ * 后置方向挂多空条件单
+ */
+ //下一个开仓位置
BigDecimal newLongFirst = longPriceQueue.get(0);
- BigDecimal ltpElem = newLongFirst.add(step).setScale(1, RoundingMode.HALF_UP);
- executor.placeConditionalEntryOrder(newLongFirst,
- FuturesPriceTrigger.RuleEnum.NUMBER_1, config.getQuantity(),
- orderId -> { currentLongOrderIds.put(orderId, ltpElem); log.info("[Gate] 新条件多单, id:{}, trigger:{}, 止盈:{}", orderId, newLongFirst, ltpElem); },
- null);
+ GridElement UpGridElement = GridElement.findByPrice(newLongFirst);
+
+ // 判断网格是否能开多仓,如果不能则跳过
+ if (UpGridElement != null) {
+
+ if (!UpGridElement.isHasLongOrder()) {
+ //挂多仓条件单
+ TraderParam upLongTraderParam = UpGridElement.getLongTraderParam();
+ executor.placeConditionalEntryOrder(
+ upLongTraderParam.getEntryPrice(),
+ FuturesPriceTrigger.RuleEnum.NUMBER_1,
+ config.getQuantity(),
+ orderId ->
+ {
+ longEntryTraderIdParam(
+ UpGridElement,
+ orderId,
+ true
+ );
+ },
+ null
+ );
+ }
+ }
- BigDecimal newShortFirst = newLongFirst.subtract( step.multiply(new BigDecimal("2")));
- if (newShortFirst.compareTo(shortEntryPrice) > 0){
- BigDecimal stpElem = newShortFirst.subtract(step).setScale(1, RoundingMode.HALF_UP);
- executor.placeConditionalEntryOrder(newShortFirst,
- FuturesPriceTrigger.RuleEnum.NUMBER_2, negate(config.getQuantity()),
- orderId -> { currentShortOrderIds.put(orderId, stpElem); log.info("[Gate] 新条件空单, id:{}, trigger:{}, 止盈:{}", orderId, newShortFirst, stpElem); },
- null);
+ int i = UpGridElement.getId() - 2;
+ GridElement downGridElement = GridElement.findById(i);
+ if (downGridElement != null){
+
+ TraderParam shortTraderParam = downGridElement.getShortTraderParam();
+ if (!downGridElement.isHasShortOrder()){
+ executor.placeConditionalEntryOrder(
+ shortTraderParam.getEntryPrice(),
+ FuturesPriceTrigger.RuleEnum.NUMBER_2,
+ negate(config.getQuantity()),
+ orderId ->
+ {
+ shortEntryTraderIdParam(
+ downGridElement,
+ orderId,
+ true
+ );
+ },
+ null
+ );
+ }
+
+ TraderParam downLongTraderParam = downGridElement.getLongTraderParam();
+ BigDecimal downGridPrice = downGridElement.getGridPrice();
+ if (
+ !downGridElement.isHasLongOrder() &&
+ downGridPrice.compareTo(longEntryPrice) <= 0 &&
+ downGridPrice.compareTo(shortEntryPrice) >= 0
+ ){
+ executor.placeConditionalEntryOrder(
+ downLongTraderParam.getEntryPrice(),
+ FuturesPriceTrigger.RuleEnum.NUMBER_1,
+ config.getQuantity(),
+ orderId ->
+ {
+ longEntryTraderIdParam(
+ downGridElement,
+ orderId,
+ true
+ );
+ },
+ null
+ );
+
+ }
}
}
--
Gitblit v1.9.1