| | |
| | | |
| | | /** |
| | | * 生成空仓价格队列。 |
| | | * 以空头基底入场价 shortBaseEntryPrice 为基准,按 gridRate 递减生成 gridQueueSize 个价格元素: |
| | | * <pre>shortBaseEntryPrice × (1 − gridRate × i), i=1..gridQueueSize</pre> |
| | | * 以 shortBaseEntryPrice × gridRate 作为绝对步长 step,存到 config。 |
| | | * 第1个元素 = shortBaseEntryPrice − step,后续依次递减 step,共 gridQueueSize 个。 |
| | | * 队列降序排列(大→小),方便 processShortGrid 中从头遍历。 |
| | | */ |
| | | private void generateShortQueue() { |
| | | shortPriceQueue.clear(); |
| | | BigDecimal step = config.getGridRate(); |
| | | for (int i = 1; i <= config.getGridQueueSize(); i++) { |
| | | shortPriceQueue.add(shortBaseEntryPrice.multiply(BigDecimal.ONE.subtract(step.multiply(BigDecimal.valueOf(i)))).setScale(1, RoundingMode.HALF_UP)); |
| | | BigDecimal step = shortBaseEntryPrice.multiply(config.getGridRate()).setScale(1, 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); |
| | | } |
| | | shortPriceQueue.sort((a, b) -> b.compareTo(a)); |
| | | //输出队列:shortPriceQueue; |
| | | log.info("[Gate] 空队列:{}", shortPriceQueue); |
| | | } |
| | | |
| | | /** |
| | | * 生成多仓价格队列。 |
| | | * 以多头基底入场价 longBaseEntryPrice 为基准,按 gridRate 递增生成 gridQueueSize 个价格元素: |
| | | * <pre>longBaseEntryPrice × (1 + gridRate × i), i=1..gridQueueSize</pre> |
| | | * 以 shortBaseEntryPrice + step 为首元素,后续依次递增 step,共 gridQueueSize 个。 |
| | | * 队列升序排列(小→大),方便 processLongGrid 中从头遍历。 |
| | | */ |
| | | private void generateLongQueue() { |
| | | longPriceQueue.clear(); |
| | | BigDecimal step = config.getGridRate(); |
| | | for (int i = 1; i <= config.getGridQueueSize(); i++) { |
| | | longPriceQueue.add(longBaseEntryPrice.multiply(BigDecimal.ONE.add(step.multiply(BigDecimal.valueOf(i)))).setScale(1, RoundingMode.HALF_UP)); |
| | | BigDecimal step = config.getStep(); |
| | | BigDecimal elem = shortBaseEntryPrice.add(step).setScale(1, RoundingMode.HALF_UP); |
| | | for (int i = 0; i < config.getGridQueueSize(); i++) { |
| | | longPriceQueue.add(elem); |
| | | elem = elem.add(step).setScale(1, RoundingMode.HALF_UP); |
| | | } |
| | | longPriceQueue.sort(BigDecimal::compareTo); |
| | | log.info("[Gate] 多队列:{}", longPriceQueue); |
| | |
| | | * <h3>执行流程</h3> |
| | | * <ol> |
| | | * <li>匹配队列元素 → 为空则直接返回</li> |
| | | * <li>空仓队列:移除 matched 元素,尾部补充新元素(尾价 × (1 − gridRate) 循环递减)</li> |
| | | * <li>多仓队列:以多仓队列首元素(最小价)为种子,生成 matched.size() 个递减元素加入</li> |
| | | * <li>空仓队列:移除 matched 元素,尾部补充新元素(尾价 − step 循环递减)</li> |
| | | * <li>多仓队列:以多仓队列首元素(最小价)为种子,递减 step 生成 matched.size() 个元素加入</li> |
| | | * <li>保证金检查 → 安全则开空一次</li> |
| | | * <li>额外反向开多:若多仓均价 > 空仓均价 且 当前价夹在中间且远离多仓均价</li> |
| | | * </ol> |
| | |
| | | synchronized (shortPriceQueue) { |
| | | shortPriceQueue.removeAll(matched); |
| | | BigDecimal min = shortPriceQueue.isEmpty() ? matched.get(matched.size() - 1) : shortPriceQueue.get(shortPriceQueue.size() - 1); |
| | | BigDecimal step = config.getGridRate(); |
| | | BigDecimal gridStep = config.getStep(); |
| | | for (int i = 0; i < matched.size(); i++) { |
| | | min = min.multiply(BigDecimal.ONE.subtract(step)).setScale(1, RoundingMode.HALF_UP); |
| | | min = min.subtract(gridStep).setScale(1, RoundingMode.HALF_UP); |
| | | shortPriceQueue.add(min); |
| | | log.info("[Gate] 空队列增加:{}", min); |
| | | } |
| | |
| | | |
| | | synchronized (longPriceQueue) { |
| | | BigDecimal first = longPriceQueue.isEmpty() ? matched.get(matched.size() - 1) : longPriceQueue.get(0); |
| | | BigDecimal step = config.getGridRate(); |
| | | BigDecimal gridStep = config.getStep(); |
| | | for (int i = 1; i <= matched.size(); i++) { |
| | | BigDecimal elem = first.multiply(BigDecimal.ONE.subtract(step.multiply(BigDecimal.valueOf(i)))).setScale(1, RoundingMode.HALF_UP); |
| | | if (longEntryPrice.compareTo(BigDecimal.ZERO) > 0 |
| | | && currentPrice.subtract(longEntryPrice).abs().compareTo(longEntryPrice.multiply(step)) < 0) { |
| | | log.info("[Gate] 多队列跳过(price≈longEntry):{}", elem); |
| | | continue; |
| | | } |
| | | BigDecimal elem = first.subtract(gridStep.multiply(BigDecimal.valueOf(i))).setScale(1, RoundingMode.HALF_UP); |
| | | // if (longEntryPrice.compareTo(BigDecimal.ZERO) > 0 |
| | | // && currentPrice.subtract(longEntryPrice).abs().compareTo(longEntryPrice.multiply(config.getGridRate())) < 0) { |
| | | // log.info("[Gate] 多队列跳过(price≈longEntry):{}", elem); |
| | | // continue; |
| | | // } |
| | | longPriceQueue.add(elem); |
| | | log.info("[Gate] 多队列增加:{}", elem); |
| | | } |
| | |
| | | * <h3>执行流程</h3> |
| | | * <ol> |
| | | * <li>匹配队列元素 → 为空则直接返回</li> |
| | | * <li>多仓队列:移除 matched 元素,尾部补充新元素(尾价 × (1 + gridRate) 循环递增)</li> |
| | | * <li>空仓队列:以空仓队列首元素(最高价)为种子,生成 matched.size() 个递增元素加入</li> |
| | | * <li>多仓队列:移除 matched 元素,尾部补充新元素(尾价 + step 循环递增)</li> |
| | | * <li>空仓队列:以空仓队列首元素(最高价)为种子,递增 step 生成 matched.size() 个元素加入</li> |
| | | * <li>保证金检查 → 安全则开多一次</li> |
| | | * <li>额外反向开空:若多仓均价 > 空仓均价 且 当前价夹在中间且远离空仓均价</li> |
| | | * </ol> |
| | |
| | | synchronized (longPriceQueue) { |
| | | longPriceQueue.removeAll(matched); |
| | | BigDecimal max = longPriceQueue.isEmpty() ? matched.get(matched.size() - 1) : longPriceQueue.get(longPriceQueue.size() - 1); |
| | | BigDecimal step = config.getGridRate(); |
| | | BigDecimal gridStep = config.getStep(); |
| | | for (int i = 0; i < matched.size(); i++) { |
| | | max = max.multiply(BigDecimal.ONE.add(step)).setScale(1, RoundingMode.HALF_UP); |
| | | max = max.add(gridStep).setScale(1, RoundingMode.HALF_UP); |
| | | longPriceQueue.add(max); |
| | | |
| | | log.info("[Gate] 多队列增加:{}", max); |
| | |
| | | |
| | | synchronized (shortPriceQueue) { |
| | | BigDecimal first = shortPriceQueue.isEmpty() ? matched.get(0) : shortPriceQueue.get(0); |
| | | BigDecimal step = config.getGridRate(); |
| | | BigDecimal gridStep = config.getStep(); |
| | | for (int i = 1; i <= matched.size(); i++) { |
| | | BigDecimal elem = first.multiply(BigDecimal.ONE.add(step.multiply(BigDecimal.valueOf(i)))).setScale(1, RoundingMode.HALF_UP); |
| | | if (shortEntryPrice.compareTo(BigDecimal.ZERO) > 0 |
| | | && currentPrice.subtract(shortEntryPrice).abs().compareTo(shortEntryPrice.multiply(step)) < 0) { |
| | | log.info("[Gate] 空队列跳过(price≈shortEntry):{}", elem); |
| | | continue; |
| | | } |
| | | BigDecimal elem = first.add(gridStep.multiply(BigDecimal.valueOf(i))).setScale(1, RoundingMode.HALF_UP); |
| | | // if (shortEntryPrice.compareTo(BigDecimal.ZERO) > 0 |
| | | // && currentPrice.subtract(shortEntryPrice).abs().compareTo(shortEntryPrice.multiply(config.getGridRate())) < 0) { |
| | | // log.info("[Gate] 空队列跳过(price≈shortEntry):{}", elem); |
| | | // continue; |
| | | // } |
| | | shortPriceQueue.add(elem); |
| | | log.info("[Gate] 空队列增加:{}", elem); |
| | | } |