From 3015f832329028cbabef2c45fc0d4586bf60510c Mon Sep 17 00:00:00 2001
From: Administrator <15274802129@163.com>
Date: Thu, 07 May 2026 13:53:09 +0800
Subject: [PATCH] fix(okxWs): 修复OKX生产环境配置的调试模式设置

---
 src/main/java/com/xcong/excoin/modules/gateApi/GateGridTradeService.java       |  343 ++++++++++++++++++++++++++++++++++++++
 src/main/java/com/xcong/excoin/modules/gateApi/GateWebSocketClientManager.java |   71 ++++---
 src/main/java/com/xcong/excoin/modules/gateApi/GateKlineWebSocketClient.java   |   88 +--------
 3 files changed, 392 insertions(+), 110 deletions(-)

diff --git a/src/main/java/com/xcong/excoin/modules/gateApi/GateGridTradeService.java b/src/main/java/com/xcong/excoin/modules/gateApi/GateGridTradeService.java
new file mode 100644
index 0000000..13b72e4
--- /dev/null
+++ b/src/main/java/com/xcong/excoin/modules/gateApi/GateGridTradeService.java
@@ -0,0 +1,343 @@
+package com.xcong.excoin.modules.gateApi;
+
+import io.gate.gateapi.ApiClient;
+import io.gate.gateapi.ApiException;
+import io.gate.gateapi.GateApiException;
+import io.gate.gateapi.api.FuturesApi;
+import io.gate.gateapi.models.FuturesAccount;
+import io.gate.gateapi.models.FuturesOrder;
+import lombok.extern.slf4j.Slf4j;
+
+import java.math.BigDecimal;
+import java.math.RoundingMode;
+import java.util.List;
+
+/**
+ * Gate 网格交易服务类,使用 gate-api SDK 进行合约下单。
+ * 策略:多空双开 → 设置止盈止损点位 → 网格循环交易
+ *
+ * 测试参数:
+ *   品种: XAU_USDT(黄金)
+ *   杠杆: 100x(全仓)
+ *   数量: 0.01 XAU
+ *   网格: 0.0035(千分之三点五)
+ *   整体止盈: 0.5 USDT
+ *   循环次数: 3
+ *   报警: 本金亏损 15%(初始本金 50 USDT)
+ *
+ * @author Administrator
+ */
+@Slf4j
+public class GateGridTradeService {
+
+    private final ApiClient apiClient;
+    private final FuturesApi futuresApi;
+    private static final String SETTLE = "usdt";
+
+    private final String contract;
+    private final String leverage;
+    private final String marginMode;
+    private final BigDecimal gridRate;
+    private final BigDecimal overallTp;
+    private final int maxCycles;
+    private final BigDecimal maxLoss;
+    private final String quantity;
+
+    private volatile boolean strategyActive = false;
+    private int currentCycle = 0;
+    private BigDecimal totalProfit = BigDecimal.ZERO;
+    private BigDecimal longEntryPrice;
+    private BigDecimal shortEntryPrice;
+    private Long longOrderId;
+    private Long shortOrderId;
+
+    private volatile BigDecimal lastClosePrice;
+
+    public GateGridTradeService(String apiKey, String apiSecret,
+                                 String contract, String leverage, String marginMode,
+                                 BigDecimal gridRate, BigDecimal overallTp,
+                                 int maxCycles, BigDecimal maxLoss, String quantity) {
+        this.contract = contract;
+        this.leverage = leverage;
+        this.marginMode = marginMode;
+        this.gridRate = gridRate;
+        this.overallTp = overallTp;
+        this.maxCycles = maxCycles;
+        this.maxLoss = maxLoss;
+        this.quantity = quantity;
+
+        this.apiClient = new ApiClient();
+        this.apiClient.setBasePath("https://api-testnet.gateapi.io/api/v4");
+        this.apiClient.setApiKeySecret(apiKey, apiSecret);
+        this.futuresApi = new FuturesApi(apiClient);
+    }
+
+    /**
+     * 初始化账户:设置持仓模式 + 杠杆
+     */
+    public void init() {
+        try {
+            futuresApi.setPositionMode(SETTLE, "dual");
+            log.info("[GateGrid] 已设置双向持仓模式");
+
+            futuresApi.updateContractPositionLeverageCall(
+                    SETTLE, contract, leverage, marginMode, "dual", null);
+            log.info("[GateGrid] 已设置杠杆: {}x, 保证金模式: {}", leverage, marginMode);
+
+            FuturesAccount account = futuresApi.listFuturesAccounts(SETTLE);
+            log.info("[GateGrid] 账户可用余额: {}, 总资产: {}",
+                    account.getAvailable(), account.getTotal());
+        } catch (GateApiException e) {
+            log.error("[GateGrid] 初始化失败, label: {}, msg: {}", e.getErrorLabel(), e.getMessage());
+        } catch (ApiException e) {
+            log.error("[GateGrid] 初始化API调用失败, code: {}", e.getCode());
+        }
+    }
+
+    /**
+     * 启动网格策略
+     */
+    public void startGrid() {
+        if (strategyActive) {
+            log.warn("[GateGrid] 策略已在运行中");
+            return;
+        }
+        strategyActive = true;
+        currentCycle = 0;
+        totalProfit = BigDecimal.ZERO;
+        log.info("[GateGrid] 网格策略启动, cycle: {}", currentCycle + 1);
+        dualOpenPositions();
+    }
+
+    /**
+     * 停止网格策略
+     */
+    public void stopGrid() {
+        strategyActive = false;
+        closeAllPositions();
+        log.info("[GateGrid] 网格策略已停止, 总盈亏: {}, 循环: {}", totalProfit, currentCycle);
+    }
+
+    /**
+     * K线回调:收到新的收盘价
+     */
+    public void onKline(BigDecimal closePrice, boolean isKlineClosed) {
+        lastClosePrice = closePrice;
+        if (!strategyActive || !isKlineClosed) {
+            return;
+        }
+        checkPositions(closePrice);
+    }
+
+    /**
+     * 多空双开
+     */
+    private void dualOpenPositions() {
+        try {
+            FuturesOrder longOrder = new FuturesOrder();
+            longOrder.setContract(contract);
+            longOrder.setSize(quantity);
+            longOrder.setPrice("0");
+            longOrder.setTif(FuturesOrder.TifEnum.IOC);
+            longOrder.setText("t-grid-long-" + (currentCycle + 1));
+            FuturesOrder longResult = futuresApi.createFuturesOrder(SETTLE, longOrder, null);
+            longOrderId = longResult.getId();
+            longEntryPrice = safeDecimal(longResult.getFillPrice());
+            log.info("[GateGrid] 开多成功, price: {}, id: {}", longEntryPrice, longOrderId);
+
+            FuturesOrder shortOrder = new FuturesOrder();
+            shortOrder.setContract(contract);
+            shortOrder.setSize(negateQuantity(quantity));
+            shortOrder.setPrice("0");
+            shortOrder.setTif(FuturesOrder.TifEnum.IOC);
+            shortOrder.setText("t-grid-short-" + (currentCycle + 1));
+            FuturesOrder shortResult = futuresApi.createFuturesOrder(SETTLE, shortOrder, null);
+            shortOrderId = shortResult.getId();
+            shortEntryPrice = safeDecimal(shortResult.getFillPrice());
+            log.info("[GateGrid] 开空成功, price: {}, id: {}", shortEntryPrice, shortOrderId);
+
+            printGridInfo();
+        } catch (GateApiException e) {
+            log.error("[GateGrid] 双开失败, label: {}, msg: {}", e.getErrorLabel(), e.getMessage());
+            strategyActive = false;
+        } catch (Exception e) {
+            log.error("[GateGrid] 双开异常", e);
+            strategyActive = false;
+        }
+    }
+
+    /**
+     * 检查多空仓位是否触及止盈止损
+     */
+    private void checkPositions(BigDecimal currentPrice) {
+        if (longEntryPrice == null || shortEntryPrice == null) {
+            return;
+        }
+
+        BigDecimal longTp = longEntryPrice.multiply(BigDecimal.ONE.add(gridRate)).setScale(1, RoundingMode.HALF_UP);
+        BigDecimal longSl = longEntryPrice.multiply(BigDecimal.ONE.subtract(gridRate)).setScale(1, RoundingMode.HALF_UP);
+        BigDecimal shortTp = shortEntryPrice.multiply(BigDecimal.ONE.subtract(gridRate)).setScale(1, RoundingMode.HALF_UP);
+        BigDecimal shortSl = shortEntryPrice.multiply(BigDecimal.ONE.add(gridRate)).setScale(1, RoundingMode.HALF_UP);
+
+        System.out.println("========== Gate 网格状态 ==========");
+        System.out.println("当前价格: " + currentPrice);
+        System.out.println("多头入场: " + longEntryPrice + " TP: " + longTp + " SL: " + longSl);
+        System.out.println("空头入场: " + shortEntryPrice + " TP: " + shortTp + " SL: " + shortSl);
+        System.out.println("累计盈亏: " + totalProfit + " 循环: " + currentCycle + "/" + maxCycles);
+        System.out.println("===================================");
+
+        // 多头止盈
+        if (currentPrice.compareTo(longTp) >= 0) {
+            log.info("[GateGrid] 多头止盈触发! entry:{}, current:{}", longEntryPrice, currentPrice);
+            BigDecimal cnt = new BigDecimal(quantity);
+            BigDecimal profit = currentPrice.subtract(longEntryPrice).multiply(cnt);
+            totalProfit = totalProfit.add(profit);
+            log.info("[GateGrid] 多头止盈 profit:{}, totalProfit:{}", profit, totalProfit);
+            closeLongPosition();
+            closeShortPosition();
+            currentCycle++;
+            checkStopConditions();
+            return;
+        }
+        // 多头止损
+        if (currentPrice.compareTo(longSl) <= 0) {
+            log.info("[GateGrid] 多头止损触发! entry:{}, current:{}", longEntryPrice, currentPrice);
+            BigDecimal cnt = new BigDecimal(quantity);
+            BigDecimal loss = longEntryPrice.subtract(currentPrice).multiply(cnt);
+            totalProfit = totalProfit.subtract(loss);
+            log.info("[GateGrid] 多头止损 loss:{}, totalProfit:{}", loss, totalProfit);
+            closeLongPosition();
+            currentCycle++;
+            checkStopConditions();
+            return;
+        }
+        // 空头止盈
+        if (currentPrice.compareTo(shortTp) <= 0) {
+            log.info("[GateGrid] 空头止盈触发! entry:{}, current:{}", shortEntryPrice, currentPrice);
+            BigDecimal cnt = new BigDecimal(quantity);
+            BigDecimal profit = shortEntryPrice.subtract(currentPrice).multiply(cnt);
+            totalProfit = totalProfit.add(profit);
+            log.info("[GateGrid] 空头止盈 profit:{}, totalProfit:{}", profit, totalProfit);
+            closeShortPosition();
+            closeLongPosition();
+            currentCycle++;
+            checkStopConditions();
+            return;
+        }
+        // 空头止损
+        if (currentPrice.compareTo(shortSl) >= 0) {
+            log.info("[GateGrid] 空头止损触发! entry:{}, current:{}", shortEntryPrice, currentPrice);
+            BigDecimal cnt = new BigDecimal(quantity);
+            BigDecimal loss = currentPrice.subtract(shortEntryPrice).multiply(cnt);
+            totalProfit = totalProfit.subtract(loss);
+            log.info("[GateGrid] 空头止损 loss:{}, totalProfit:{}", loss, totalProfit);
+            closeShortPosition();
+            currentCycle++;
+            checkStopConditions();
+        }
+    }
+
+    private void checkStopConditions() {
+        if (totalProfit.compareTo(overallTp) >= 0) {
+            log.info("[GateGrid] 达到整体止盈 {} USDT,停止策略", overallTp);
+            strategyActive = false;
+            return;
+        }
+        if (BigDecimal.ZERO.subtract(totalProfit).compareTo(maxLoss) >= 0) {
+            log.info("[GateGrid] 亏损 {} 达到上限 {} USDT,停止策略", totalProfit.negate(), maxLoss);
+            strategyActive = false;
+            return;
+        }
+        if (currentCycle >= maxCycles) {
+            log.info("[GateGrid] 达到最大循环次数 {},停止策略", maxCycles);
+            strategyActive = false;
+            return;
+        }
+        log.info("[GateGrid] 进入下一轮循环: {}", currentCycle + 1);
+        dualOpenPositions();
+    }
+
+    private void closeLongPosition() {
+        if (longEntryPrice == null) return;
+        try {
+            FuturesOrder closeOrder = new FuturesOrder();
+            closeOrder.setContract(contract);
+            closeOrder.setSize(negateQuantity(quantity));
+            closeOrder.setPrice("0");
+            closeOrder.setTif(FuturesOrder.TifEnum.IOC);
+            closeOrder.setReduceOnly(true);
+            closeOrder.setText("t-grid-close-long");
+            FuturesOrder result = futuresApi.createFuturesOrder(SETTLE, closeOrder, null);
+            log.info("[GateGrid] 平多成功, id: {}, fillPrice: {}", result.getId(), result.getFillPrice());
+        } catch (Exception e) {
+            log.error("[GateGrid] 平多失败", e);
+        }
+        longEntryPrice = null;
+        longOrderId = null;
+    }
+
+    private void closeShortPosition() {
+        if (shortEntryPrice == null) return;
+        try {
+            FuturesOrder closeOrder = new FuturesOrder();
+            closeOrder.setContract(contract);
+            closeOrder.setSize(quantity);
+            closeOrder.setPrice("0");
+            closeOrder.setTif(FuturesOrder.TifEnum.IOC);
+            closeOrder.setReduceOnly(true);
+            closeOrder.setText("t-grid-close-short");
+            FuturesOrder result = futuresApi.createFuturesOrder(SETTLE, closeOrder, null);
+            log.info("[GateGrid] 平空成功, id: {}, fillPrice: {}", result.getId(), result.getFillPrice());
+        } catch (Exception e) {
+            log.error("[GateGrid] 平空失败", e);
+        }
+        shortEntryPrice = null;
+        shortOrderId = null;
+    }
+
+    private void closeAllPositions() {
+        closeLongPosition();
+        closeShortPosition();
+    }
+
+    private void printGridInfo() {
+        System.out.println("========== Gate 网格开仓 ==========");
+        System.out.println("合约: " + contract + " 杠杆: " + leverage + "x " + marginMode);
+        System.out.println("多头入场: " + longEntryPrice);
+        System.out.println("空头入场: " + shortEntryPrice);
+        System.out.println("数量: " + quantity + " 网格间距: " + gridRate.multiply(new BigDecimal("100")) + "%");
+        System.out.println("整体止盈: " + overallTp + " USDT 最大循环: " + maxCycles);
+        System.out.println("最大亏损: " + maxLoss + " USDT");
+        System.out.println("=====================================");
+    }
+
+    private String negateQuantity(String qty) {
+        if (qty.startsWith("-")) {
+            return qty.substring(1);
+        }
+        return "-" + qty;
+    }
+
+    private BigDecimal safeDecimal(String val) {
+        if (val == null || val.isEmpty()) {
+            return BigDecimal.ZERO;
+        }
+        return new BigDecimal(val);
+    }
+
+    public BigDecimal getLastClosePrice() {
+        return lastClosePrice;
+    }
+
+    public boolean isStrategyActive() {
+        return strategyActive;
+    }
+
+    public BigDecimal getTotalProfit() {
+        return totalProfit;
+    }
+
+    public int getCurrentCycle() {
+        return currentCycle;
+    }
+}
diff --git a/src/main/java/com/xcong/excoin/modules/gateApi/GateKlineWebSocketClient.java b/src/main/java/com/xcong/excoin/modules/gateApi/GateKlineWebSocketClient.java
index ca59116..828568c 100644
--- a/src/main/java/com/xcong/excoin/modules/gateApi/GateKlineWebSocketClient.java
+++ b/src/main/java/com/xcong/excoin/modules/gateApi/GateKlineWebSocketClient.java
@@ -58,7 +58,9 @@
     private static final String FUTURES_PING = "futures.ping";
     private static final String FUTURES_PONG = "futures.pong";
     private static final String GATE_INTERVAL = "1m";
-    private static final String GATE_CONTRACT = "BTC_USDT";
+    private static final String GATE_CONTRACT = "XAU_USDT";
+
+    private GateGridTradeService gridTradeService;
 
     // 心跳超时时间(秒),小于30秒
     private static final int HEARTBEAT_TIMEOUT = 10;
@@ -77,6 +79,10 @@
         this.caoZuoService = caoZuoService;
         this.clientManager = clientManager;
         this.wangGeListService = wangGeListService;
+    }
+
+    public void setGridTradeService(GateGridTradeService gridTradeService) {
+        this.gridTradeService = gridTradeService;
     }
 
     /**
@@ -366,85 +372,13 @@
             System.out.println("成交额(a): " + baseVol);
             System.out.println("K线完结(w): " + windowClosed);
             System.out.println("==================================");
+
+            if (gridTradeService != null) {
+                gridTradeService.onKline(closePx, windowClosed);
+            }
         } catch (Exception e) {
             log.error("处理 K线频道推送数据失败", e);
         }
-    }
-
-    private void doOpen(WebSocketClient webSocketClient, String accountName, MacdEmaStrategy.TradingOrder tradingOrderOpenOpen, BigDecimal closePx) {
-        // 根据信号执行交易操作
-        TradeRequestParam tradeRequestParam = new TradeRequestParam();
-
-        String posSide = tradingOrderOpenOpen.getPosSide();
-        tradeRequestParam.setPosSide(posSide);
-        String currentPrice = String.valueOf(closePx);
-        tradeRequestParam = caoZuoService.caoZuoStrategy(accountName, currentPrice, posSide);
-
-        String side = tradingOrderOpenOpen.getSide();
-        tradeRequestParam.setSide(side);
-
-        String clOrdId = WsParamBuild.getOrderNum(side);
-        tradeRequestParam.setClOrdId(clOrdId);
-
-        String sz = InstrumentsWs.getAccountMap(accountName).get(CoinEnums.BUY_CNT_INIT.name());
-        tradeRequestParam.setSz(sz);
-        TradeOrderWs.orderEvent(webSocketClient, tradeRequestParam);
-    }
-
-    private List<Kline> getKlineDataByInstIdAndBar(String instId, String bar) {
-        List<Kline> klineList = new ArrayList<>();
-        try {
-            LinkedHashMap<String, Object> requestParam = new LinkedHashMap<>();
-            requestParam.put("instId", instId);
-            requestParam.put("bar", bar);
-            requestParam.put("limit", "200");
-            String result = ExchangeLoginService.getInstance(ExchangeInfoEnum.OKX_UAT.name()).lineHistory(requestParam);
-            JSONObject json = JSON.parseObject(result);
-            String data = json.getString("data");
-            
-            if (data != null) {
-                List<String[]> klinesList = JSON.parseArray(data, String[].class);
-                if (!CollUtil.isEmpty(klinesList)) {
-                    for (String[] s : klinesList) {
-                        // 确保数组有足够的元素
-                        if (s != null && s.length >= 9) {
-                            String s1 = s[8];
-                            try {
-                                if ("1".equals(s1)){
-                                    Kline kline = new Kline();
-                                    kline.setTs(s[0]);
-                                    kline.setO(new BigDecimal(s[1]));
-                                    kline.setH(new BigDecimal(s[2]));
-                                    kline.setL(new BigDecimal(s[3]));
-                                    kline.setC(new BigDecimal(s[4]));
-                                    kline.setVol(new BigDecimal(s[5]));
-                                    kline.setConfirm(s[8]);
-                                    klineList.add(kline);
-                                }
-                            } catch (NumberFormatException e) {
-                                log.error("K线数据转换为BigDecimal失败: {}", Arrays.toString(s), e);
-                            }
-                        } else {
-                            log.warn("K线数据数组长度不足: {}", Arrays.toString(s));
-                        }
-                    }
-                }
-            } else {
-                log.warn("K线数据为空");
-            }
-        } catch (JSONException e) {
-            log.error("K线数据解析失败", e);
-        } catch (Exception e) {
-            log.error("获取K线数据异常", e);
-        }
-        return klineList;
-    }
-
-    /**
-     * 构建 Redis Key
-     */
-    private String buildRedisKey(String instId) {
-        return "PRICE_" + instId.replace("-", "");
     }
 
     /**
diff --git a/src/main/java/com/xcong/excoin/modules/gateApi/GateWebSocketClientManager.java b/src/main/java/com/xcong/excoin/modules/gateApi/GateWebSocketClientManager.java
index f020544..bc49fbe 100644
--- a/src/main/java/com/xcong/excoin/modules/gateApi/GateWebSocketClientManager.java
+++ b/src/main/java/com/xcong/excoin/modules/gateApi/GateWebSocketClientManager.java
@@ -1,24 +1,18 @@
 package com.xcong.excoin.modules.gateApi;
 
-import com.xcong.excoin.modules.okxNewPrice.OkxKlineWebSocketClient;
-import com.xcong.excoin.modules.okxNewPrice.OkxQuantWebSocketClient;
 import com.xcong.excoin.modules.okxNewPrice.celue.CaoZuoService;
-import com.xcong.excoin.modules.okxNewPrice.okxWs.enums.ExchangeInfoEnum;
 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.boot.autoconfigure.condition.ConditionalOnProperty;
 import org.springframework.stereotype.Component;
 
 import javax.annotation.PostConstruct;
 import javax.annotation.PreDestroy;
-import java.util.Collection;
-import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
+import java.math.BigDecimal;
 
 /**
- * 管理多个OKX WebSocket客户端实例,每个实例对应一个账号
+ * 管理 Gate WebSocket 客户端和网格交易服务实例
  */
 @Slf4j
 @Component
@@ -31,53 +25,64 @@
     private WangGeListService wangGeListService;
 
     private GateKlineWebSocketClient klinePriceClient;
+    private GateGridTradeService gridTradeService;
 
+    private static final String API_KEY = "d90ca272391992b8e74f8f92cedb21ec";
+    private static final String API_SECRET = "1861e4f52de4bb53369ea3208d9ede38ece4777368030f96c77d27934c46c274";
 
-    /**
-     * 初始化方法,在Spring Bean构造完成后执行
-     * 创建并初始化所有账号的WebSocket客户端实例
-     */
     @PostConstruct
     public void init() {
-        log.info("开始初始化OkxWebSocketClientManager");
-        
-        // 初始化价格WebSocket客户端
+        log.info("开始初始化GateWebSocketClientManager");
+
         try {
+            gridTradeService = new GateGridTradeService(
+                    API_KEY, API_SECRET,
+                    "XAUT_USDT",
+                    "100",
+                    "cross",
+                    new BigDecimal("0.0035"),
+                    new BigDecimal("0.5"),
+                    3,
+                    new BigDecimal("7.5"),
+                    "1"
+            );
+            gridTradeService.init();
+
             klinePriceClient = new GateKlineWebSocketClient(caoZuoService, this, wangGeListService);
+            klinePriceClient.setGridTradeService(gridTradeService);
             klinePriceClient.init();
-            log.info("已初始化OkxNewPriceWebSocketClient");
+            log.info("已初始化GateKlineWebSocketClient");
+
+            gridTradeService.startGrid();
         } catch (Exception e) {
-            log.error("初始化OkxNewPriceWebSocketClient失败", e);
+            log.error("初始化GateWebSocketClientManager失败", e);
         }
-        
     }
 
-    /**
-     * 销毁方法,在Spring Bean销毁前执行
-     * 关闭所有WebSocket客户端连接和相关资源
-     */
     @PreDestroy
     public void destroy() {
-        log.info("开始销毁OkxWebSocketClientManager");
-        
-        // 关闭价格WebSocket客户端
+        log.info("开始销毁GateWebSocketClientManager");
+
+        if (gridTradeService != null) {
+            gridTradeService.stopGrid();
+        }
         if (klinePriceClient != null) {
             try {
                 klinePriceClient.destroy();
-                log.info("已销毁OkxNewPriceWebSocketClient");
+                log.info("已销毁GateKlineWebSocketClient");
             } catch (Exception e) {
-                log.error("销毁OkxNewPriceWebSocketClient失败", e);
+                log.error("销毁GateKlineWebSocketClient失败", e);
             }
         }
-        
-        log.info("OkxWebSocketClientManager销毁完成");
+
+        log.info("GateWebSocketClientManager销毁完成");
     }
 
-    /**
-     * 获取OkxNewPriceWebSocketClient实例
-     * @return 价格WebSocket客户端实例
-     */
     public GateKlineWebSocketClient getKlineWebSocketClient() {
         return klinePriceClient;
     }
+
+    public GateGridTradeService getGridTradeService() {
+        return gridTradeService;
+    }
 }
\ No newline at end of file

--
Gitblit v1.9.1