package com.xcong.excoin.modules.gateApi.wsHandler.handler; import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; import com.xcong.excoin.modules.blackchain.service.DateUtil; import com.xcong.excoin.modules.gateApi.GateGridTradeService; import com.xcong.excoin.modules.gateApi.wsHandler.GateChannelHandler; import lombok.extern.slf4j.Slf4j; import org.java_websocket.client.WebSocketClient; import java.math.BigDecimal; /** * K 线(Candlestick)频道处理器。 * *

特点

* 公开频道,无需 HMAC-SHA512 认证签名。订阅 1m 周期的 K 线数据。 * *

数据流

*
 *   WebSocket 推送 update event
 *     → handleMessage() → 解析 OHLCV → log 打印 → gridTradeService.onKline(closePx)
 *       → 首次 K 线触发双开
 *       → 后续 K 线仅缓存 lastKlinePrice 供补仓参考
 * 
* *

订阅格式

* payload: {@code ["1m", contract]} * * @author Administrator */ @Slf4j public class CandlestickChannelHandler implements GateChannelHandler { private static final String CHANNEL_NAME = "futures.candlesticks"; private static final String INTERVAL = "1m"; private final String contract; private final GateGridTradeService gridTradeService; public CandlestickChannelHandler(String contract, GateGridTradeService gridTradeService) { this.contract = contract; this.gridTradeService = gridTradeService; } @Override public String getChannelName() { return CHANNEL_NAME; } @Override public void subscribe(WebSocketClient ws) { JSONObject msg = new JSONObject(); msg.put("time", System.currentTimeMillis() / 1000); msg.put("channel", CHANNEL_NAME); msg.put("event", "subscribe"); JSONArray payload = new JSONArray(); payload.add(INTERVAL); payload.add(contract); msg.put("payload", payload); ws.send(msg.toJSONString()); log.info("[{}] 订阅成功, 合约:{}, 周期:{}", CHANNEL_NAME, contract, INTERVAL); } @Override public void unsubscribe(WebSocketClient ws) { JSONObject msg = new JSONObject(); msg.put("time", System.currentTimeMillis() / 1000); msg.put("channel", CHANNEL_NAME); msg.put("event", "unsubscribe"); JSONArray payload = new JSONArray(); payload.add(INTERVAL); payload.add(contract); msg.put("payload", payload); ws.send(msg.toJSONString()); log.info("[{}] 取消订阅成功", CHANNEL_NAME); } @Override public boolean handleMessage(JSONObject response) { if (!CHANNEL_NAME.equals(response.getString("channel"))) return false; try { JSONArray resultArray = response.getJSONArray("result"); if (resultArray == null || resultArray.isEmpty()) { log.warn("[{}] 数据为空", CHANNEL_NAME); return true; } JSONObject data = resultArray.getJSONObject(0); BigDecimal closePx = new BigDecimal(data.getString("c")); log.info("========== Gate K线数据 =========="); log.info("名称: {} 时间: {}", data.getString("n"), DateUtil.TimeStampToDateTime(data.getLong("t"))); log.info("开盘: {} 最高: {} 最低: {} 收盘: {} 成交量: {} 成交额: {} 已完结: {}", data.getString("o"), data.getString("h"), data.getString("l"), data.getString("c"), data.getString("v"), data.getString("a"), data.getBooleanValue("w")); log.info("=================================="); if (gridTradeService != null) gridTradeService.onKline(closePx); } catch (Exception e) { log.error("[{}] 处理数据失败", CHANNEL_NAME, e); } return true; } }