package com.xcong.excoin.modules.okxNewPrice.okxWs;
|
|
import cn.hutool.json.JSONUtil;
|
import com.alibaba.fastjson.JSONArray;
|
import com.alibaba.fastjson.JSONObject;
|
import com.xcong.excoin.modules.okxNewPrice.okxWs.enums.CoinEnums;
|
import com.xcong.excoin.modules.okxNewPrice.okxWs.enums.OrderParamEnums;
|
import com.xcong.excoin.modules.okxNewPrice.okxpi.MallUtils;
|
import com.xcong.excoin.modules.okxNewPrice.utils.WsMapBuild;
|
import com.xcong.excoin.modules.okxNewPrice.utils.WsParamBuild;
|
import io.micrometer.core.instrument.util.JsonUtils;
|
import lombok.extern.slf4j.Slf4j;
|
import org.java_websocket.client.WebSocketClient;
|
|
import java.math.BigDecimal;
|
import java.math.RoundingMode;
|
import java.util.Map;
|
import java.util.concurrent.ConcurrentHashMap;
|
|
/**
|
* 账户 WebSocket 处理类,用于订阅 OKX 的账户频道并处理账户信息推送。
|
* 包含账户资金状态判断、计算下单保证金及保存到 Redis 的逻辑。
|
*
|
* @author Administrator
|
*/
|
@Slf4j
|
public class AccountWs {
|
|
// 使用双层Map,第一层key为账号名称,第二层key为数据key
|
private static final Map<String, Map<String, String>> ACCOUNTWSMAP = new ConcurrentHashMap<>();
|
|
// 获取指定账号的Map,如果不存在则创建
|
public static Map<String, String> getAccountMap(String accountName) {
|
return ACCOUNTWSMAP.computeIfAbsent(accountName, k -> new ConcurrentHashMap<>());
|
}
|
/**
|
* 账户频道名称常量
|
*/
|
public static final String ACCOUNTWS_CHANNEL = "account";
|
|
/**
|
* 订阅账户频道
|
*
|
* @param webSocketClient WebSocket 客户端实例
|
* @param option 请求选项(如 unsubscribe 或 subscribe)
|
*/
|
public static void subscribeAccountChannel(WebSocketClient webSocketClient, String option) {
|
try {
|
JSONArray argsArray = new JSONArray();
|
JSONObject args = new JSONObject();
|
args.put("channel", ACCOUNTWS_CHANNEL);
|
args.put("ccy", CoinEnums.USDT.getCode());
|
argsArray.add(args);
|
|
String connId = MallUtils.getOrderNum(ACCOUNTWS_CHANNEL);
|
JSONObject jsonObject = WsParamBuild.buildJsonObject(connId, option, argsArray);
|
webSocketClient.send(jsonObject.toJSONString());
|
// log.info("发送账户频道:{}", option);
|
} catch (Exception e) {
|
log.error("订阅账户频道构建失败", e);
|
}
|
}
|
|
public static void initEvent(JSONObject response, String accountName) {
|
// log.info("订阅成功: {}", response.getJSONObject("arg"));
|
JSONObject arg = response.getJSONObject("arg");
|
initParam(arg, accountName);
|
}
|
|
/**
|
* 处理账户频道推送的数据
|
*
|
* @param response 推送的 JSON 数据对象
|
* @param accountName 账号名称
|
*/
|
public static void handleEvent(JSONObject response, String accountName) {
|
|
|
// log.info("开始执行AccountWs......{}",ACCOUNTWS_CHANNEL);
|
try {
|
JSONArray dataArray = response.getJSONArray("data");
|
if (dataArray == null || dataArray.isEmpty()) {
|
log.warn("账户频道数据为空");
|
return;
|
}
|
|
for (int i = 0; i < dataArray.size(); i++) {
|
try {
|
JSONObject accountData = dataArray.getJSONObject(i);
|
JSONArray detailsArray = accountData.getJSONArray("details");
|
if (detailsArray == null || detailsArray.isEmpty()) {
|
log.warn("账户频道{}数据为空",CoinEnums.USDT.getCode());
|
continue;
|
}
|
|
for (int j = 0; j < detailsArray.size(); j++) {
|
JSONObject detail = detailsArray.getJSONObject(j);
|
initParam(detail, accountName);
|
|
Map<String, String> accountMap = getAccountMap(accountName);
|
WsMapBuild.saveStringToMap(accountMap, CoinEnums.READY_STATE.name(), CoinEnums.READY_STATE_YES.getCode());
|
}
|
} catch (Exception innerEx) {
|
log.warn("处理账户频道数据失败", innerEx);
|
}
|
}
|
} catch (Exception e) {
|
log.error("处理账户频道推送数据失败", e);
|
}
|
}
|
|
|
public static final String ccyKey = "ccy";
|
public static final String availBalKey = "availBal";
|
public static final String cashBalKey = "cashBal";
|
public static final String eqKey = "eq";
|
public static final String uplKey = "upl";
|
private static void initParam(JSONObject detail, String accountName) {
|
Map<String, String> accountMap = getAccountMap(accountName);
|
|
String ccy = WsMapBuild.parseStringSafe( detail.getString(ccyKey));
|
WsMapBuild.saveStringToMap(accountMap, ccyKey, ccy);
|
|
String availBal = WsMapBuild.parseStringSafe(detail.getString(availBalKey));
|
WsMapBuild.saveStringToMap(accountMap, availBalKey, availBal);
|
|
String cashBal = WsMapBuild.parseStringSafe(detail.getString(cashBalKey));
|
WsMapBuild.saveStringToMap(accountMap, cashBalKey, cashBal);
|
|
String eq = WsMapBuild.parseStringSafe(detail.getString(eqKey));
|
WsMapBuild.saveStringToMap(accountMap, eqKey, eq);
|
|
String upl = WsMapBuild.parseStringSafe(detail.getString(uplKey));
|
WsMapBuild.saveStringToMap(accountMap, uplKey, upl);
|
|
BigDecimal cashBalDecimal = WsMapBuild.parseBigDecimalSafe(cashBal);
|
// 根据可用余额计算下单总保证金
|
String total_order_usdtpecent = InstrumentsWs.getAccountMap(accountName).get(CoinEnums.TOTAL_ORDER_USDTPECENT.name());
|
BigDecimal total_order_usdt_factor = WsMapBuild.parseBigDecimalSafe(total_order_usdtpecent);
|
BigDecimal totalOrderUsdt = cashBalDecimal.multiply(total_order_usdt_factor).setScale(2, RoundingMode.DOWN);
|
WsMapBuild.saveStringToMap(accountMap, CoinEnums.TOTAL_ORDER_USDT.name(), String.valueOf(totalOrderUsdt));
|
|
WsMapBuild.saveStringToMap(accountMap, CoinEnums.READY_STATE.name(), CoinEnums.READY_STATE_YES.getCode());
|
|
log.info(
|
"{}: 账户详情-币种: {}, 可用余额: {}, 现金余额: {}, 余额: {}, 全仓未实现盈亏: {}, 下单总保证金: {}",
|
accountName, ccy, availBal, cashBal, eq, upl, totalOrderUsdt
|
);
|
}
|
}
|