src/main/java/com/xcong/excoin/modules/gateApi/GateGridTradeService.java
@@ -15,6 +15,30 @@ import java.math.BigDecimal; import java.math.RoundingMode; /** * Gate 网格交易服务类。 * * <h3>策略概述</h3> * 多空双开 → 各放止盈条件单 → 仓位推送驱动补仓 → history_pnl 判断停止 * * <h3>触发逻辑</h3> * <pre> * K线首次价格就绪 → dualOpenPositions() // 多空双开 + 止盈条件单 * 仓位推送 size=0 → reopenXxxPosition() // 该方向被止盈平掉 → 补开 * 仓位推送 history_pnl ≥ overallTp → 停止 * 仓位推送 history_pnl ≤ -maxLoss → 停止 * </pre> * * <h3>止盈计算</h3> * 多头止盈价 = entryPrice × (1 + gridRate)<br> * 空头止盈价 = entryPrice × (1 - gridRate) * * <h3>依赖</h3> * 使用 {@code io.gate:gate-api (7.2.71)} SDK 通过 REST API 下单, * 市场数据由 {@link GateKlineWebSocketClient} 通过 WebSocket 提供。 * * @author Administrator */ @Slf4j public class GateGridTradeService { @@ -31,19 +55,36 @@ private final String quantity; private final String positionMode; /** 策略是否处于运行状态 */ private volatile boolean strategyActive = false; /** 是否已完成首次双开 */ private volatile boolean dualOpened = false; /** 多头仓位是否活跃 */ private volatile boolean longActive = false; /** 空头仓位是否活跃 */ private volatile boolean shortActive = false; /** 多头入场价 */ private BigDecimal longEntryPrice; /** 空头入场价 */ private BigDecimal shortEntryPrice; /** WebSocket 推送的最新 K 线收盘价 */ private volatile BigDecimal lastKlinePrice; /** 服务器返回的累计已实现盈亏 */ private BigDecimal totalHistoryPnl = BigDecimal.ZERO; /** * 构造函数,初始化 Gate 期货 API 客户端。 * * @param contract 合约名称(如 XAU_USDT) * @param leverage 杠杆倍数 * @param marginMode 保证金模式(cross/isolated) * @param positionMode 持仓模式(single/dual/dual_plus) * @param gridRate 网格间距比例(如 0.0035) * @param overallTp 整体止盈阈值(USDT) * @param maxLoss 最大亏损阈值(USDT) * @param quantity 下单数量(合约张数) */ public GateGridTradeService(String apiKey, String apiSecret, String contract, String leverage, String marginMode, String positionMode, @@ -65,6 +106,9 @@ this.futuresApi = new FuturesApi(apiClient); } /** * 初始化账户。设置杠杆、查询余额、切换持仓模式。 */ public void init() { try { futuresApi.updateContractPositionLeverageCall( @@ -86,6 +130,9 @@ } } /** * 启动网格策略。策略激活后等待 K 线价格就绪,然后自动首次双开。 */ public void startGrid() { if (strategyActive) { log.warn("[GateGrid] 策略已在运行中"); @@ -96,13 +143,19 @@ log.info("[GateGrid] 网格策略启动,等待K线价格..."); } /** * 停止网格策略。 */ public void stopGrid() { strategyActive = false; log.info("[GateGrid] 网格策略已停止, history_pnl: {}", totalHistoryPnl); } /** * K线回调:存储最新价格,首次价格就绪时双开 * K 线回调入口。由 调用。 * 首次收到价格时触发多空双开,后续仅缓存最新价格供补仓使用。 * * @param closePrice K 线收盘价 */ public void onKline(BigDecimal closePrice) { lastKlinePrice = closePrice; @@ -116,7 +169,20 @@ } /** * 仓位推送回调:检测止盈平仓 → 补仓,累加 history_pnl → 判断停止 * 仓位推送回调入口。由 {@link GateKlineWebSocketClient} 调用。 * 根据仓位模式(dual_long/dual_short)和 size 判断: * <ul> * <li>size=0 且之前活跃 → 该方向被平仓 → 补开</li> * <li>size>0 → 确认仓位活跃,更新入场价</li> * </ul> * 每次推送更新 history_pnl 并检查停止条件。 * * @param contract 合约名 * @param mode 仓位模式(dual_long / dual_short) * @param size 仓位数量(0 表示无仓位) * @param entryPrice 入场价格 * @param historyPnl 已实现累计盈亏 * @param realisedPnl 已实现盈亏 */ public void onPositionUpdate(String contract, String mode, BigDecimal size, BigDecimal entryPrice, BigDecimal historyPnl, @@ -151,6 +217,13 @@ checkStopConditions(); } /** * 检查策略停止条件。满足任一即置 strategyActive=false: * <ul> * <li>累计盈利 ≥ overallTp</li> * <li>累计亏损 ≤ -maxLoss</li> * </ul> */ private void checkStopConditions() { if (totalHistoryPnl.compareTo(overallTp) >= 0) { log.info("[GateGrid] 累计止盈 {} 达到 {} USDT,停止策略", totalHistoryPnl, overallTp); @@ -163,6 +236,10 @@ } } /** * 首次多空双开。使用当前 K 线价格以市价单同时开多和开空, * 开仓成功后立即为每个方向创建止盈条件单。 */ private void dualOpenPositions() { if (lastKlinePrice == null) { log.warn("[GateGrid] K线价格未就绪,跳过双开"); @@ -204,6 +281,9 @@ } } /** * 补开多头仓位。多头被止盈平掉后调用,市价重新开多并创建止盈单。 */ private void reopenLongPosition() { if (lastKlinePrice == null || !strategyActive) { return; @@ -229,6 +309,9 @@ } } /** * 补开空头仓位。空头被止盈平掉后调用,市价重新开空并创建止盈单。 */ private void reopenShortPosition() { if (lastKlinePrice == null || !strategyActive) { return; @@ -254,18 +337,34 @@ } } /** * 创建多头止盈条件单。 * 触发价 = entryPrice × (1 + gridRate),价格 ≥ 触发价时平多。 */ private void placeLongTp(BigDecimal entryPrice) { BigDecimal tpPrice = entryPrice.multiply(BigDecimal.ONE.add(gridRate)).setScale(1, RoundingMode.HALF_UP); placePriceTriggeredOrder(tpPrice, FuturesPriceTrigger.RuleEnum.NUMBER_1, "close-long-position", "close_long"); log.info("[GateGrid] 多头止盈已设置, TP:{}", tpPrice); } /** * 创建空头止盈条件单。 * 触发价 = entryPrice × (1 - gridRate),价格 ≤ 触发价时平空。 */ private void placeShortTp(BigDecimal entryPrice) { BigDecimal tpPrice = entryPrice.multiply(BigDecimal.ONE.subtract(gridRate)).setScale(1, RoundingMode.HALF_UP); placePriceTriggeredOrder(tpPrice, FuturesPriceTrigger.RuleEnum.NUMBER_2, "close-short-position", "close_short"); log.info("[GateGrid] 空头止盈已设置, TP:{}", tpPrice); } /** * 通过 Gate REST API 创建止盈条件单。 * * @param triggerPrice 触发价格 * @param rule 触发规则(1: ≥, 2: ≤) * @param orderType 止盈止损类型(close-long-position / close-short-position) * @param autoSize 双仓平仓方向(close_long / close_short) */ private void placePriceTriggeredOrder(BigDecimal triggerPrice, FuturesPriceTrigger.RuleEnum rule, String orderType, @@ -300,6 +399,9 @@ } } /** * 打印当前网格配置和入场信息。 */ private void printGridInfo() { BigDecimal longTp = BigDecimal.ZERO; BigDecimal shortTp = BigDecimal.ZERO; @@ -318,6 +420,7 @@ log.info("====================================="); } /** 对数量取反(开多用正数,开空用负数) */ private String negateQuantity(String qty) { if (qty.startsWith("-")) { return qty.substring(1); @@ -325,6 +428,7 @@ return "-" + qty; } /** 安全转换字符串为 BigDecimal,null 返回 0 */ private BigDecimal safeDecimal(String val) { if (val == null || val.isEmpty()) { return BigDecimal.ZERO; src/main/java/com/xcong/excoin/modules/gateApi/GateKlineWebSocketClient.java
@@ -16,14 +16,33 @@ import java.math.BigDecimal; import java.net.URI; import java.net.URISyntaxException; import java.nio.charset.StandardCharsets; import java.util.concurrent.*; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicReference; /** * Gate K线 WebSocket 客户端类,用于连接 Gate 的 WebSocket 接口, * 实时获取并处理 K线(candlestick)数据。 * 同时支持心跳检测、自动重连以及异常恢复机制。 * Gate WebSocket 客户端,通过 Java-WebSocket 库连接 Gate.io 的 WebSocket 接口。 * * <h3>订阅频道</h3> * <ul> * <li>{@code futures.candlesticks} — 1m K 线数据(公开频道)</li> * <li>{@code futures.positions} — 用户仓位更新(私有频道,需 HMAC-SHA512 签名认证)</li> * <li>{@code futures.ping} — 应用层心跳</li> * </ul> * * <h3>数据流</h3> * <pre> * onMessage → handleWebSocketMessage → 按 channel 分流: * futures.pong → 取消心跳超时 * subscribe/unsubscribe/error → 日志 * futures.candlesticks → processPushDataV2 → GateGridTradeService.onKline() * futures.positions → processPositionData → GateGridTradeService.onPositionUpdate() * </pre> * * <h3>连接管理</h3> * 支持心跳检测、指数退避重连(最多 3 次)、优雅关闭。 * * @author Administrator */ @Slf4j @@ -35,23 +54,35 @@ private WebSocketClient webSocketClient; private ScheduledExecutorService heartbeatExecutor; private volatile ScheduledFuture<?> pongTimeoutFuture; /** 最后收到消息的时间戳,用于心跳超时检测 */ private final AtomicReference<Long> lastMessageTime = new AtomicReference<>(System.currentTimeMillis()); // 连接状态标志 /** 连接状态 */ private final AtomicBoolean isConnected = new AtomicBoolean(false); /** 连接中标记,防止重复连接 */ private final AtomicBoolean isConnecting = new AtomicBoolean(false); /** 初始化标记,防止重复初始化 */ private final AtomicBoolean isInitialized = new AtomicBoolean(false); /** K 线频道 */ private static final String CHANNEL = "futures.candlesticks"; /** 仓位频道(私有,需认证) */ private static final String POSITIONS_CHANNEL = "futures.positions"; /** 应用层 ping 频道 */ private static final String FUTURES_PING = "futures.ping"; /** 应用层 pong 频道 */ private static final String FUTURES_PONG = "futures.pong"; /** K 线周期 */ private static final String GATE_INTERVAL = "1m"; /** 订阅合约 */ private static final String GATE_CONTRACT = "XAUT_USDT"; /** 网格交易策略实例 */ private GateGridTradeService gridTradeService; /** API 密钥,用于私有频道签名 */ private final String apiKey; /** API 密钥 */ private final String apiSecret; private static final char[] HEX_ARRAY = "0123456789abcdef".toCharArray(); @@ -251,6 +282,10 @@ webSocketClient.send(subscribeMsg.toJSONString()); log.info("已发送 K线频道订阅请求,合约: {}, 周期: {}", GATE_CONTRACT, GATE_INTERVAL); } /** * 发送应用层 ping 请求。 * 用于探测连接状态,服务器会返回 futures.pong。 */ private void subscribePingChannels() { JSONObject subscribeMsg = new JSONObject(); subscribeMsg.put("time", System.currentTimeMillis() / 1000); @@ -259,6 +294,10 @@ log.info("已发送 futures.ping"); } /** * 订阅仓位频道(私有频道,需 HMAC-SHA512 签名认证)。 * 签名算法: Hex(HmacSHA512(secret, "channel={channel}&event={event}&time={time}")) */ private void subscribePositionsChannels() { JSONObject subscribeMsg = new JSONObject(); long timeSec = System.currentTimeMillis() / 1000; @@ -280,25 +319,38 @@ log.info("已发送仓位频道订阅请求(含认证),合约: {}", GATE_CONTRACT); } /** * 计算 Gate API v4 的 HMAC-SHA512 签名。 * * @param channel 频道名 * @param event 事件名(subscribe/unsubscribe) * @param timeSec 时间戳(秒) * @return 十六进制签名字符串 */ private String hs512Sign(String channel, String event, long timeSec) { try { String message = "channel=" + channel + "&event=" + event + "&time=" + timeSec; Mac mac = Mac.getInstance("HmacSHA512"); SecretKeySpec spec = new SecretKeySpec(apiSecret.getBytes(), "HmacSHA512"); SecretKeySpec spec = new SecretKeySpec(apiSecret.getBytes(StandardCharsets.UTF_8), "HmacSHA512"); mac.init(spec); byte[] hash = mac.doFinal(message.getBytes()); byte[] hash = mac.doFinal(message.getBytes(StandardCharsets.UTF_8)); StringBuilder hex = new StringBuilder(hash.length * 2); for (byte b : hash) { hex.append(HEX_ARRAY[(b >> 4) & 0xF]); hex.append(HEX_ARRAY[b & 0xF]); } return hex.toString(); String sign = hex.toString(); log.debug("签名计算, message: {}, sign: {}", message, sign); return sign; } catch (Exception e) { log.error("签名计算失败", e); return ""; } } /** * 取消订阅 K 线频道。 */ private void unsubscribeKlineChannels() { JSONObject unsubscribeMsg = new JSONObject(); unsubscribeMsg.put("time", System.currentTimeMillis() / 1000); @@ -312,6 +364,9 @@ log.info("已发送 K线频道取消订阅请求,合约: {}, 周期: {}", GATE_CONTRACT, GATE_INTERVAL); } /** * 取消订阅仓位频道。 */ private void unsubscribePositionsChannels() { JSONObject unsubscribeMsg = new JSONObject(); unsubscribeMsg.put("time", System.currentTimeMillis() / 1000); @@ -434,6 +489,12 @@ } } /** * 解析仓位推送数据,提取目标合约的仓位信息并回调交易服务。 * 推送字段: contract, mode(dual_long/dual_short), size, entry_price, history_pnl, realised_pnl * * @param response 仓位推送的 JSON 对象 */ private void processPositionData(JSONObject response) { try { JSONArray resultArray = response.getJSONArray("result"); src/main/java/com/xcong/excoin/modules/gateApi/GateWebSocketClientMain.java
@@ -1,19 +1,21 @@ package com.xcong.excoin.modules.gateApi; import com.xcong.excoin.modules.okxNewPrice.OkxWebSocketClientManager; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; /** * Gate 网格交易的独立测试入口(main 方法)。 * 通过 Spring XML 上下文初始化管理器,运行一段时间后手动关闭。 * * @author Administrator */ public class GateWebSocketClientMain { public static void main(String[] args) throws InterruptedException { // 使用Spring上下文初始化管理器 ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); GateWebSocketClientManager manager = context.getBean(GateWebSocketClientManager.class); // 运行一段时间以观察结果 Thread.sleep(1200000000L); // 运行一小时 // 关闭连接 Thread.sleep(1200000000L); manager.destroy(); } } } src/main/java/com/xcong/excoin/modules/gateApi/GateWebSocketClientManager.java
@@ -2,7 +2,6 @@ import com.xcong.excoin.modules.okxNewPrice.celue.CaoZuoService; import com.xcong.excoin.modules.okxNewPrice.okxWs.wanggeList.WangGeListService; import com.xcong.excoin.utils.RedisUtils; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @@ -12,7 +11,32 @@ import java.math.BigDecimal; /** * 管理 Gate WebSocket 客户端和网格交易服务实例 * Gate 模块入口管理类,作为 Spring Bean 负责组件的生命周期。 * * <h3>启动流程</h3> * <pre> * @PostConstruct init(): * 1. new GateGridTradeService(参数) → init() // 设杠杆、查余额、切双向持仓 * 2. new GateKlineWebSocketClient → init() // 连接 WebSocket,订阅 K 线 + 仓位 * 3. gridTradeService.startGrid() // 激活策略,等待 K 线触发首次双开 * </pre> * * <h3>销毁流程</h3> * <pre> * @PreDestroy destroy(): * 1. gridTradeService.stopGrid() // 停止策略 * 2. klinePriceClient.destroy() // 取消订阅 → 关闭 WS → 关闭线程池 * </pre> * * <h3>配置参数</h3> * 当前配置在代码中硬编码: * <ul> * <li>合约: XAU_USDT, 杠杆: 30x, 全仓, 双向持仓</li> * <li>网格间距: 0.35%, 整体止盈: 0.5 USDT, 最大亏损: 7.5 USDT</li> * <li>数量: 10 张</li> * </ul> * * @author Administrator */ @Slf4j @Component @@ -22,12 +46,19 @@ @Autowired private WangGeListService wangGeListService; /** K 线 WebSocket 客户端 */ private GateKlineWebSocketClient klinePriceClient; /** 网格交易服务 */ private GateGridTradeService gridTradeService; /** Gate 测试网 API Key */ private static final String API_KEY = "d90ca272391992b8e74f8f92cedb21ec"; /** Gate 测试网 API Secret */ private static final String API_SECRET = "1861e4f52de4bb53369ea3208d9ede38ece4777368030f96c77d27934c46c274"; /** * Spring 容器启动后自动调用。初始化网格交易服务和 WebSocket 客户端。 */ @PostConstruct public void init() { log.info("开始初始化GateWebSocketClientManager"); @@ -57,6 +88,9 @@ } } /** * Spring 容器销毁前自动调用。停止策略并关闭所有连接。 */ @PreDestroy public void destroy() { log.info("开始销毁GateWebSocketClientManager"); @@ -83,4 +117,4 @@ public GateGridTradeService getGridTradeService() { return gridTradeService; } } } src/main/java/com/xcong/excoin/modules/gateApi/gateApi-logic.md
New file @@ -0,0 +1,243 @@ # Gate Api 模块 — 网格交易系统 ## 文件列表 | 文件 | 类型 | 说明 | |------|------|------| | [GateWebSocketClientManager](#gatewebsocketclientmanager) | `@Component` | 启动入口,生命周期管理 | | [GateKlineWebSocketClient](#gateklinewebsocketclient) | WebSocket 客户端 | K 线 + 仓位数据监听 | | [GateGridTradeService](#gategridtradeservice) | 交易服务 | 网格策略 + REST 下单 | | [GateWebSocketClientMain](#gatewebsocketclientmain) | main 入口 | 独立测试启动 | | [Example.java](#examplejava) | 示例 | Gate SDK 用法参考 | --- ## 架构总览 ``` ┌────────────────────────────────────────────────────────────┐ │ GateWebSocketClientManager │ │ (Spring @Component) │ │ │ │ @PostConstruct init(): │ │ ┌──────────────────────┐ ┌─────────────────────────┐ │ │ │ GateGridTradeService │ │ GateKlineWebSocketClient │ │ │ │ ▶ init() │ │ ▶ init() │ │ │ │ ▶ startGrid() │←──│ ▶ connect() │ │ │ └──────┬───────────────┘ └───────────┬─────────────┘ │ │ │ REST API │ WebSocket │ │ ▼ ▼ │ │ Gate Testnet API Gate Testnet WS │ │ (https://api-testnet...) (wss://ws-testnet.gate.com) │ └────────────────────────────────────────────────────────────┘ ``` --- ## 数据流 ``` WebSocket 推送 │ ├─ futures.candlesticks (update) │ └─ GateKlineWebSocketClient.processPushDataV2() │ ├─ 解析: o/h/l/c/v/a/t/w │ ├─ 打印 K 线日志 │ └─ GateGridTradeService.onKline(closePx) │ ├─ 首次 → dualOpenPositions() → 开多 + 开空 + TP 单 │ └─ 后续 → 仅缓存 lastKlinePrice │ ├─ futures.positions (update) [需 HMAC-SHA512 签名] │ └─ GateKlineWebSocketClient.processPositionData() │ ├─ 解析: contract/mode/size/entry_price/history_pnl/realised_pnl │ └─ GateGridTradeService.onPositionUpdate(...) │ ├─ size=0 && longActive → reopenLongPosition() │ ├─ size=0 && shortActive → reopenShortPosition() │ ├─ size>0 → 确认仓位活跃 │ └─ checkStopConditions(history_pnl) │ ├─ futures.pong │ └─ cancelPongTimeout() │ └─ subscribe/unsubscribe/error └─ 日志输出 ``` --- ## 策略时序 ### 阶段 1:启动与初始化 ``` Spring 启动 → GateWebSocketClientManager.init() → GateGridTradeService.init() → REST: 设杠杆 30x cross → REST: 查账户余额 → REST: 切双向持仓 dual → GateKlineWebSocketClient.init() → WebSocket: connect() → onOpen: subscribe candlesticks + positions + ping → GateGridTradeService.startGrid() → strategyActive = true ``` ### 阶段 2:首次开仓 ``` K 线推送 closePrice=80000 → onKline(80000) → dualOpened = true → dualOpenPositions() → REST: 市价开多 10 张 → longEntryPrice=80000 → REST: 创建多头止盈单 TP=80000×1.0035=80280 → REST: 市价开空 10 张 → shortEntryPrice=80000 → REST: 创建空头止盈单 TP=80000×0.9965=79720 ``` ### 阶段 3:止盈触发 → 补仓 ``` 仓位推送: mode=dual_long, size=0 (多头被止盈平掉了) → longActive=true && size=0 → longActive=false → reopenLongPosition() → REST: 市价开多 10 张 (用最新 K 线价) → REST: 创建新的多头止盈单 仓位推送: history_pnl=0.12 (未达阈值,继续) ``` ### 阶段 4:停止 ``` 仓位推送: history_pnl ≥ 0.5 (累计盈利达标) → strategyActive = false → 不再补仓 仓位推送: history_pnl ≤ -7.5 (亏损超限) → strategyActive = false → 不再补仓 ``` --- ## GateWebSocketClientManager **角色**: Spring Bean 入口,组装并管理所有 Gate 模块组件。 **关键方法**: - `init()`: 创建 `GateGridTradeService` → 初始化 → 创建 `GateKlineWebSocketClient` → 启动策略 - `destroy()`: 停止策略 → 关闭 WebSocket **当前参数**(硬编码在 `init()` 中): | 参数 | 值 | 说明 | |------|-----|------| | 合约 | XAU_USDT | 黄金 | | 杠杆 | 30x | 全仓模式 | | 持仓模式 | dual | 双向持仓 | | 网格间距 | 0.0035 | 0.35% | | 整体止盈 | 0.5 USDT | | | 最大亏损 | 7.5 USDT | 本金 50×15% | | 下单量 | 10 张 | | --- ## GateKlineWebSocketClient **角色**: WebSocket 客户端,订阅 Gate 的行情和仓位频道。 **订阅频道**: | 频道 | 类型 | 认证 | 用途 | |------|------|------|------| | `futures.candlesticks` | 公开 | 否 | 1m K 线数据 | | `futures.positions` | 私有 | HMAC-SHA512 | 用户仓位更新 | | `futures.ping` | 公开 | 否 | 应用层心跳 | **签名算法**(`futures.positions` 订阅时使用): ``` message = "channel=futures.positions&event=subscribe&time={秒级时间戳}" SIGN = Hex(HmacSHA512(apiSecret, message)) ``` **连接管理**: - 心跳: 10 秒超时,每 25 秒检查,超时发 ping - 重连: 指数退避,最多 3 次,初始 5 秒 - 关闭: 先取消订阅 → 等 500ms → 关闭连接 → 关闭线程池 **消息路由** (`handleWebSocketMessage`): | channel | event | 处理 | |---------|-------|------| | `futures.pong` | — | `cancelPongTimeout()` | | — | `subscribe` | 打日志 | | — | `unsubscribe` | 打日志 | | — | `error` | 打错误日志 | | `futures.candlesticks` | `update`/`all` | `processPushDataV2()` | | `futures.positions` | `update`/`all` | `processPositionData()` | --- ## GateGridTradeService **角色**: 使用 Gate SDK (`io.gate:gate-api:7.2.71`) 通过 REST API 执行合约下单。 **状态机**: ``` strategyActive=false ──startGrid()──→ strategyActive=true (等待K线) │ onKline(price) │ dualOpened=true dualOpenPositions() │ ┌───────────┴───────────┐ ▼ ▼ longActive=true shortActive=true │ │ 仓位推送 size=0 仓位推送 size=0 │ │ ▼ ▼ reopenLong() reopenShort() │ │ └───────────┬───────────┘ │ checkStopConditions() │ ┌───────────┴───────────┐ ▼ ▼ history_pnl≥0.5 history_pnl≤-7.5 strategyActive=false strategyActive=false ``` **止盈计算**: | 方向 | 公式 | 触发条件 | order_type | auto_size | |------|------|----------|------------|-----------| | 多头 TP | entryPrice × 1.0035 | 最新价 ≥ 触发价 | `close-long-position` | `close_long` | | 空头 TP | entryPrice × 0.9965 | 最新价 ≤ 触发价 | `close-short-position` | `close_short` | **REST API 调用**: | 操作 | API | |------|-----| | 设杠杆 | `POST /futures/usdt/positions/{contract}/leverage` | | 查账户 | `GET /futures/usdt/accounts` | | 设持仓模式 | `POST /futures/usdt/set_position_mode` | | 市价下单 | `POST /futures/usdt/orders` (price=0, tif=IOC) | | 止盈条件单 | `POST /futures/usdt/price_orders` | --- ## GateWebSocketClientMain **角色**: 独立的 `main()` 方法入口,通过 Spring XML 上下文启动。 --- ## Example.java Gate SDK 使用示例,展示 `FuturesApi` 的基本用法:获取账户、设置仓位模式、设置杠杆。仅作参考,不参与实际策略运行。