| | |
| | | public OkxGridTradeService(OkxConfig config, String accountName) { |
| | | this.config = config; |
| | | this.accountName = accountName; |
| | | this.executor = new OkxTradeExecutor(config.getContract(), config.getMarginMode(), accountName); |
| | | this.executor = new OkxTradeExecutor(config.getContract(), config.getMarginMode(), accountName, config.getInstIdCode()); |
| | | } |
| | | |
| | | public void setWebSocketClient(WebSocketClient wsClient) { |
| | |
| | | if (state == StrategyState.WAITING_KLINE) { |
| | | state = StrategyState.OPENING; |
| | | log.info("[{}] 首根K线到达,开基底仓位...", config.getContract()); |
| | | executor.openLong(config.getQuantity(), () -> { |
| | | log.info("[{}] 基底多单已提交", config.getContract()); |
| | | }, null); |
| | | executor.openShort(config.getQuantity(), () -> { |
| | | log.info("[{}] 基底空单已提交", config.getContract()); |
| | | }, null); |
| | | executor.openLong(config.getQuantity(), null, null); |
| | | executor.openShort(config.getQuantity(), null, null); |
| | | return; |
| | | } |
| | | |
| | |
| | | } |
| | | |
| | | cumulativePnl = longRealizedPnl.add(shortRealizedPnl); |
| | | log.info("[{}] 持仓更新, 多已实现盈亏:{}, 空已实现盈亏:{}, 累计:{}", |
| | | config.getContract(), longRealizedPnl, shortRealizedPnl, cumulativePnl); |
| | | |
| | | if (state == StrategyState.WAITING_KLINE) { |
| | | return; |
| | |
| | | return; |
| | | } |
| | | |
| | | log.info("[{}] 订单成交, 方向:{}, 数量:{}, 成交价:{}, 盈亏:{}", |
| | | config.getContract(), posSide, fillSz, avgPx, pnl); |
| | | |
| | | if (OkxEnums.POSSIDE_LONG.equals(posSide)) { |
| | | if (!baseLongOpened) { |
| | | longBaseEntryPrice = avgPx; |
| | |
| | | log.info("[{}] 基底多成交价: {}", config.getContract(), longBaseEntryPrice); |
| | | tryGenerateQueues(); |
| | | } else if (fillSz.compareTo(BigDecimal.ZERO) > 0) { |
| | | if (longPriceQueue.isEmpty()) { |
| | | log.warn("[{}] 多仓队列为空,无法设止盈", config.getContract()); |
| | | } else { |
| | | if (!longPriceQueue.isEmpty()) { |
| | | BigDecimal tpPrice = longPriceQueue.get(0); |
| | | executor.placeTakeProfit(tpPrice, OkxEnums.ORDER_TYPE_CLOSE_LONG, config.getQuantity()); |
| | | log.info("[{}] 多单止盈已设, 成交价:{}, tp:{}, size:{}", |
| | |
| | | log.info("[{}] 基底空成交价: {}", config.getContract(), shortBaseEntryPrice); |
| | | tryGenerateQueues(); |
| | | } else if (fillSz.compareTo(BigDecimal.ZERO) > 0) { |
| | | if (shortPriceQueue.isEmpty()) { |
| | | log.warn("[{}] 空仓队列为空,无法设止盈", config.getContract()); |
| | | } else { |
| | | if (!shortPriceQueue.isEmpty()) { |
| | | BigDecimal tpPrice = shortPriceQueue.get(0); |
| | | executor.placeTakeProfit(tpPrice, OkxEnums.ORDER_TYPE_CLOSE_SHORT, config.getQuantity()); |
| | | log.info("[{}] 空单止盈已设, 成交价:{}, tp:{}, size:{}", |
| | |
| | | } |
| | | } |
| | | } |
| | | log.info("[{}] 原空队列:{}", config.getContract(), shortPriceQueue); |
| | | if (matched.isEmpty()) { |
| | | log.info("[{}] 空仓队列未触发, 当前价:{}", config.getContract(), currentPrice); |
| | | return; |
| | | } |
| | | log.info("[{}] 空仓队列触发, 匹配{}个元素, 当前价:{}", config.getContract(), matched.size(), currentPrice); |
| | |
| | | } |
| | | } |
| | | } |
| | | log.info("[{}] 原多队列:{}", config.getContract(), longPriceQueue); |
| | | if (matched.isEmpty()) { |
| | | log.info("[{}] 多仓队列未触发, 当前价:{}", config.getContract(), currentPrice); |
| | | return; |
| | | } |
| | | log.info("[{}] 多仓队列触发, 匹配{}个元素, 当前价:{}", config.getContract(), matched.size(), currentPrice); |
| | |
| | | ? tail.subtract(fixedStep).setScale(1, RoundingMode.HALF_UP) |
| | | : tail.add(fixedStep).setScale(1, RoundingMode.HALF_UP); |
| | | queue.add(tail); |
| | | log.info("[{}] {}队列增加:{}", config.getContract(), label, tail); |
| | | } |
| | | queue.sort(comparator); |
| | | log.info("[{}] 现{}队列:{}", config.getContract(), label, queue); |
| | | } |
| | | } |
| | | |
| | |
| | | : first.subtract(offset).setScale(1, RoundingMode.HALF_UP); |
| | | if (filterEntryPrice.compareTo(BigDecimal.ZERO) > 0 |
| | | && currentPrice.subtract(filterEntryPrice).abs().compareTo(filterEntryPrice.multiply(config.getGridRate())) < 0) { |
| | | log.info("[{}] {}队列跳过(price≈entry):{}", config.getContract(), label, elem); |
| | | continue; |
| | | } |
| | | targetQueue.add(elem); |
| | | log.info("[{}] {}队列增加:{}", config.getContract(), label, elem); |
| | | } |
| | | targetQueue.sort(comparator); |
| | | while (targetQueue.size() > config.getGridQueueSize()) { |
| | | targetQueue.remove(targetQueue.size() - 1); |
| | | } |
| | | log.info("[{}] 现{}队列:{}", config.getContract(), label, targetQueue); |
| | | } |
| | | } |
| | | |
| | |
| | | shortPnl = shortPositionSize.multiply(multiplier).multiply(shortEntryPrice.subtract(price)); |
| | | } |
| | | unrealizedPnl = longPnl.add(shortPnl); |
| | | log.info("[{}] 未实现盈亏: {}", config.getContract(), unrealizedPnl); |
| | | } |
| | | |
| | | public BigDecimal getLastKlinePrice() { return lastKlinePrice; } |