fix(gateApi): 修复双向持仓模式下的杠杆设置功能
- 更新文档中的API接口路径和方法名,将updateContractPositionLeverageCall改为updateDualModePositionLeverageCall
- 修改Example.java中的杠杆设置方法调用,适配双向持仓模式
- 移除position_mode参数,因为新方法不再需要此参数
- 为杠杆设置功能添加双向持仓模式专用的注释说明
| | |
| | | state = StrategyState.OPENING; |
| | | log.info("[Gate] 首根K线到达,开基底仓位..."); |
| | | executor.openLong(config.getQuantity(), () -> { |
| | | baseLongOpened = true; |
| | | longActive = true; |
| | | log.info("[Gate] 基底多已开"); |
| | | log.info("[Gate] 基底多单已提交"); |
| | | }, null); |
| | | executor.openShort(negate(config.getQuantity()), () -> { |
| | | baseShortOpened = true; |
| | | shortActive = true; |
| | | log.info("[Gate] 基底空已开"); |
| | | log.info("[Gate] 基底空单已提交"); |
| | | }, null); |
| | | return; |
| | | } |
| | |
| | | log.info("[Gate] 基底多成交价: {}", longBaseEntryPrice); |
| | | tryGenerateQueues(); |
| | | } else { |
| | | executor.placeTakeProfit(entryPrice.add(config.getGridRate()).setScale(1, RoundingMode.HALF_UP), |
| | | BigDecimal tpPrice = entryPrice.multiply(BigDecimal.ONE.add(config.getGridRate())).setScale(1, RoundingMode.HALF_UP); |
| | | executor.placeTakeProfit(tpPrice, |
| | | FuturesPriceTrigger.RuleEnum.NUMBER_1, ORDER_TYPE_CLOSE_LONG, AUTO_SIZE_LONG); |
| | | log.info("[Gate] 多单止盈已设, entry:{}, tp:{}", entryPrice, |
| | | entryPrice.add(config.getGridRate()).setScale(1, RoundingMode.HALF_UP)); |
| | | log.info("[Gate] 多单止盈已设, entry:{}, tp:{}", entryPrice, tpPrice); |
| | | } |
| | | } else { |
| | | longActive = false; |
| | |
| | | log.info("[Gate] 基底空成交价: {}", shortBaseEntryPrice); |
| | | tryGenerateQueues(); |
| | | } else { |
| | | executor.placeTakeProfit(entryPrice.subtract(config.getGridRate()).setScale(1, RoundingMode.HALF_UP), |
| | | BigDecimal tpPrice = entryPrice.multiply(BigDecimal.ONE.subtract(config.getGridRate())).setScale(1, RoundingMode.HALF_UP); |
| | | executor.placeTakeProfit(tpPrice, |
| | | FuturesPriceTrigger.RuleEnum.NUMBER_2, ORDER_TYPE_CLOSE_SHORT, AUTO_SIZE_SHORT); |
| | | log.info("[Gate] 空单止盈已设, entry:{}, tp:{}", entryPrice, |
| | | entryPrice.subtract(config.getGridRate()).setScale(1, RoundingMode.HALF_UP)); |
| | | log.info("[Gate] 空单止盈已设, entry:{}, tp:{}", entryPrice, tpPrice); |
| | | } |
| | | } else { |
| | | shortActive = false; |
| | |
| | | shortPriceQueue.clear(); |
| | | BigDecimal step = config.getGridRate(); |
| | | for (int i = 1; i <= config.getGridQueueSize(); i++) { |
| | | shortPriceQueue.add(shortBaseEntryPrice.subtract(step.multiply(BigDecimal.valueOf(i))).setScale(1, RoundingMode.HALF_UP)); |
| | | shortPriceQueue.add(shortBaseEntryPrice.multiply(BigDecimal.ONE.subtract(step.multiply(BigDecimal.valueOf(i)))).setScale(1, RoundingMode.HALF_UP)); |
| | | } |
| | | shortPriceQueue.sort((a, b) -> b.compareTo(a)); |
| | | //输出队列:shortPriceQueue; |
| | |
| | | longPriceQueue.clear(); |
| | | BigDecimal step = config.getGridRate(); |
| | | for (int i = 1; i <= config.getGridQueueSize(); i++) { |
| | | longPriceQueue.add(longBaseEntryPrice.add(step.multiply(BigDecimal.valueOf(i))).setScale(1, RoundingMode.HALF_UP)); |
| | | longPriceQueue.add(longBaseEntryPrice.multiply(BigDecimal.ONE.add(step.multiply(BigDecimal.valueOf(i)))).setScale(1, RoundingMode.HALF_UP)); |
| | | } |
| | | longPriceQueue.sort(BigDecimal::compareTo); |
| | | log.info("[Gate] 多队列:{}", longPriceQueue); |
| | |
| | | BigDecimal min = shortPriceQueue.isEmpty() ? matched.get(matched.size() - 1) : shortPriceQueue.get(shortPriceQueue.size() - 1); |
| | | BigDecimal step = config.getGridRate(); |
| | | for (int i = 0; i < matched.size(); i++) { |
| | | min = min.subtract(step).setScale(1, RoundingMode.HALF_UP); |
| | | min = min.multiply(BigDecimal.ONE.subtract(step)).setScale(1, RoundingMode.HALF_UP); |
| | | shortPriceQueue.add(min); |
| | | } |
| | | shortPriceQueue.sort((a, b) -> b.compareTo(a)); |
| | |
| | | BigDecimal max = longPriceQueue.isEmpty() ? matched.get(matched.size() - 1) : longPriceQueue.get(longPriceQueue.size() - 1); |
| | | BigDecimal step = config.getGridRate(); |
| | | for (int i = 0; i < matched.size(); i++) { |
| | | max = max.add(step).setScale(1, RoundingMode.HALF_UP); |
| | | max = max.multiply(BigDecimal.ONE.add(step)).setScale(1, RoundingMode.HALF_UP); |
| | | longPriceQueue.add(max); |
| | | } |
| | | longPriceQueue.sort(BigDecimal::compareTo); |
| | |
| | | shortPnl = shortPositionSize.multiply(multiplier).multiply(shortEntryPrice.subtract(price)); |
| | | } |
| | | unrealizedPnl = longPnl.add(shortPnl); |
| | | |
| | | log.info("[Gate] 未实现盈亏: {}", unrealizedPnl); |
| | | } |
| | | |
| | | /** |
| | |
| | | .leverage("100") |
| | | .marginMode("cross") |
| | | .positionMode("dual") |
| | | .gridRate(new BigDecimal("0.002")) |
| | | .gridRate(new BigDecimal("0.004")) |
| | | .overallTp(new BigDecimal("0.5")) |
| | | .maxLoss(new BigDecimal("7.5")) |
| | | .quantity("1") |
| | |
| | | |
| | | ### 网格队列生成 |
| | | |
| | | 以基底入场价为基准,按 `gridRate` 步长生成 N 个价格(N = gridQueueSize,默认50): |
| | | 以基底入场价为基准,按 `gridRate`(百分比步长)生成 N 个价格(N = gridQueueSize,默认50): |
| | | |
| | | | 队列 | 计算方式 | 排序 | |
| | | |------|---------|------| |
| | | | 空仓队列 shortPriceQueue | 基底空入场价 - gridRate × i (i=1..N) | 降序(大→小) | |
| | | | 多仓队列 longPriceQueue | 基底多入场价 + gridRate × i (i=1..N) | 升序(小→大) | |
| | | | 空仓队列 shortPriceQueue | 基底空入场价 × (1 − gridRate × i) (i=1..N) | 降序(大→小) | |
| | | | 多仓队列 longPriceQueue | 基底多入场价 × (1 + gridRate × i) (i=1..N) | 升序(小→大) | |
| | | |
| | | ### K线触发网格 |
| | | |
| | |
| | | │ ├─ 保证金检查: positionInitialMargin / initialPrincipal < marginRatioLimit(20%) |
| | | │ │ ├─ 安全 → openShort 开空单(成交后仓位推送会自动设止盈) |
| | | │ │ └─ 超限 → 跳过开仓,队列照常更新 |
| | | │ ├─ 空仓队列: 移除匹配元素,尾部补充新价格(按步长递减) |
| | | │ ├─ 空仓队列: 移除匹配元素,尾部补充新价格(尾价 × (1 − gridRate)) |
| | | │ └─ 多仓队列: 接收匹配元素,升序排列,截断到 gridQueueSize |
| | | │ |
| | | └─ processLongGrid: 当前价 > 多仓队列元素(价格涨超了队列中的低价) |
| | |
| | | ├─ 保证金检查: 同上 |
| | | │ ├─ 安全 → openLong 开多单 |
| | | │ └─ 超限 → 跳过开仓 |
| | | ├─ 多仓队列: 移除匹配元素,尾部补充新价格(按步长递增) |
| | | ├─ 多仓队列: 移除匹配元素,尾部补充新价格(尾价 × (1 + gridRate)) |
| | | └─ 空仓队列: 接收匹配元素,降序排列,截断到 gridQueueSize |
| | | ``` |
| | | |
| | | ### 队列转移示意 |
| | | |
| | | ``` |
| | | 初始状态: |
| | | 空仓队列: [100, 99, 98, 97] (降序) |
| | | 多仓队列: [102, 103, 104, 105] (升序) |
| | | ETH_USDT, gridRate=0.0035, 基底空入场价=2275, 基底多入场价=2275: |
| | | |
| | | 价格跌到 98.5 → processShortGrid 触发: |
| | | 匹配: [100, 99](都 > 98.5) |
| | | 初始状态: |
| | | 空仓队列: [2267.1, 2270.0, 2272.5, 2275.0] (降序,base×0.9965, base×0.993...) |
| | | 多仓队列: [2275.0, 2277.5, 2280.0, 2282.5] (升序,base×1.0035, base×1.007...) |
| | | |
| | | 价格跌到 2271 → processShortGrid 触发: |
| | | 匹配: [2275.0, 2272.5](都 > 2271) |
| | | |
| | | 空仓队列: 移除[100,99] → [98,97] → 补充[96,95] → [98,97,96,95] |
| | | 多仓队列: 接收[100,99] → [100,99,102,103,104,105] → 截断到4 → [102,103,104,105] |
| | | 空仓队列: 移除[2275.0,2272.5] → [2270.0,2267.1] → 补充[2267.1×0.9965≈2259.1, 2259.1×0.9965≈2251.2] → [2270.0,2267.1,2259.1,2251.2] |
| | | 多仓队列: 接收[2275.0,2272.5] → 合并后截断到4 → [2272.5,2275.0,2277.5,2280.0] |
| | | ``` |
| | | |
| | | --- |