package com.xcong.excoin.modules.gateApi; import io.gate.gateapi.ApiClient; import io.gate.gateapi.GateApiException; import io.gate.gateapi.api.FuturesApi; import io.gate.gateapi.models.FuturesInitialOrder; import io.gate.gateapi.models.FuturesOrder; import io.gate.gateapi.models.FuturesPriceTrigger; import io.gate.gateapi.models.FuturesPriceTriggeredOrder; import io.gate.gateapi.models.TriggerOrderResponse; import lombok.extern.slf4j.Slf4j; import java.math.BigDecimal; import java.util.concurrent.ExecutorService; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; /** * Gate REST API 执行器。 * *
* GateGridTradeService.onKline → executor.openLong/openShort → REST API * GateGridTradeService.onPositionUpdate → executor.openLong/openShort → REST API * (每一次开仓后) → executor.placeTakeProfit → REST API ** * @author Administrator */ @Slf4j public class GateTradeExecutor { private static final String SETTLE = "usdt"; private final FuturesApi futuresApi; private final String contract; /** 交易线程池:单线程 + 有界队列 + 背压策略 */ private final ExecutorService executor; public GateTradeExecutor(ApiClient apiClient, String contract) { this.futuresApi = new FuturesApi(apiClient); this.contract = contract; this.executor = new ThreadPoolExecutor( 1, 1, 60L, TimeUnit.SECONDS, new LinkedBlockingQueue<>(64), r -> { Thread t = new Thread(r, "gate-trade-worker"); t.setDaemon(true); return t; }, new ThreadPoolExecutor.CallerRunsPolicy() ); ((ThreadPoolExecutor) executor).allowCoreThreadTimeOut(true); } /** * 优雅关闭:等待 10 秒,超时则强制中断。 */ public void shutdown() { executor.shutdown(); try { executor.awaitTermination(10, TimeUnit.SECONDS); } catch (InterruptedException e) { Thread.currentThread().interrupt(); executor.shutdownNow(); } } /** * 异步市价开多。quantity 为正数(如 "10")。 */ public void openLong(String quantity, Runnable onSuccess, Runnable onFailure) { openPosition(quantity, "t-grid-long", "开多", onSuccess, onFailure); } /** * 异步市价开空。quantity 为负数(如 "-10")。 */ public void openShort(String quantity, Runnable onSuccess, Runnable onFailure) { openPosition(quantity, "t-grid-short", "开空", onSuccess, onFailure); } private void openPosition(String size, String text, String label, Runnable onSuccess, Runnable onFailure) { executor.execute(() -> { try { FuturesOrder order = new FuturesOrder(); order.setContract(contract); order.setSize(size); order.setPrice("0"); order.setTif(FuturesOrder.TifEnum.IOC); order.setText(text); FuturesOrder result = futuresApi.createFuturesOrder(SETTLE, order, null); log.info("[TradeExec] {}成功, 价格:{}, id:{}", label, result.getFillPrice(), result.getId()); if (onSuccess != null) { onSuccess.run(); } } catch (Exception e) { log.error("[TradeExec] {}失败", label, e); if (onFailure != null) { onFailure.run(); } } }); } /** * 异步创建止盈条件单。 *
使用 Gate 的 PriceTriggeredOrder:服务器监控价格,达到触发价后自动平仓。 * 如果账户已有同方向同规则的条件单(label=UNIQUE),自动清除后重试一次。 * * @param triggerPrice 触发价格 * @param rule 触发规则(NUMBER_1: ≥ 触发价,NUMBER_2: ≤ 触发价) * @param orderType stop 类型(close-long-position / close-short-position) * @param autoSize 双仓平仓方向(close_long / close_short) */ public void placeTakeProfit(BigDecimal triggerPrice, FuturesPriceTrigger.RuleEnum rule, String orderType, String autoSize) { executor.execute(() -> { FuturesPriceTriggeredOrder order = buildTriggeredOrder(triggerPrice, rule, orderType, autoSize); try { TriggerOrderResponse response = futuresApi.createPriceTriggeredOrder(SETTLE, order); log.info("[TradeExec] 止盈单已创建, 触发价:{}, 类型:{}, id:{}", triggerPrice, orderType, response.getId()); } catch (GateApiException e) { if ("AUTO_USER_EXIST_POSITION_ORDER".equals(e.getErrorLabel())) { log.warn("[TradeExec] 止盈单已存在,清除旧单后重试"); try { futuresApi.cancelPriceTriggeredOrderList(SETTLE, contract); TriggerOrderResponse response = futuresApi.createPriceTriggeredOrder(SETTLE, order); log.info("[TradeExec] 止盈单重试成功, 触发价:{}, id:{}", triggerPrice, response.getId()); } catch (Exception retryEx) { log.error("[TradeExec] 止盈单重试失败", retryEx); } } else { log.error("[TradeExec] 止盈单创建失败, 触发价:{}", triggerPrice, e); } } catch (Exception e) { log.error("[TradeExec] 止盈单创建失败, 触发价:{}", triggerPrice, e); } }); } /** * 异步清除指定合约的所有止盈止损条件单。 */ public void cancelAllPriceTriggeredOrders() { executor.execute(() -> { try { futuresApi.cancelPriceTriggeredOrderList(SETTLE, contract); log.info("[TradeExec] 已清除所有止盈止损条件单"); } catch (Exception e) { log.error("[TradeExec] 清除止盈止损条件单失败", e); } }); } /** * 构建 FuturesPriceTriggeredOrder 对象。 *
策略=0(价格触发),price_type=0(最新价),expiration=0(永不过期), * tif=IOC(立即成交或取消),reduce_only=true(只减仓不开新仓)。 */ private FuturesPriceTriggeredOrder buildTriggeredOrder(BigDecimal triggerPrice, FuturesPriceTrigger.RuleEnum rule, String orderType, String autoSize) { FuturesPriceTrigger trigger = new FuturesPriceTrigger(); trigger.setStrategyType(FuturesPriceTrigger.StrategyTypeEnum.NUMBER_0); trigger.setPriceType(FuturesPriceTrigger.PriceTypeEnum.NUMBER_0); trigger.setPrice(triggerPrice.toString()); trigger.setRule(rule); trigger.setExpiration(0); FuturesInitialOrder initial = new FuturesInitialOrder(); initial.setContract(contract); initial.setSize(0L); initial.setPrice("0"); initial.setTif(FuturesInitialOrder.TifEnum.IOC); initial.setReduceOnly(true); initial.setAutoSize(autoSize); FuturesPriceTriggeredOrder order = new FuturesPriceTriggeredOrder(); order.setTrigger(trigger); order.setInitial(initial); order.setOrderType(orderType); return order; } }