package top.lvzhiqiang.service.impl; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; import lombok.extern.slf4j.Slf4j; import me.chanjar.weixin.common.error.WxErrorException; import me.chanjar.weixin.cp.api.WxCpGroupRobotService; import me.chanjar.weixin.cp.api.WxCpService; import me.chanjar.weixin.cp.bean.message.WxCpMessage; import me.chanjar.weixin.cp.bean.message.WxCpMessageSendResult; import org.jsoup.Connection; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Propagation; import org.springframework.transaction.annotation.Transactional; import top.lvzhiqiang.config.InitRunner; import top.lvzhiqiang.config.WorkWeixinProperties; import top.lvzhiqiang.entity.CoinHistoryOrder; import top.lvzhiqiang.mapper.CoinMapper; import top.lvzhiqiang.service.CoinService; import top.lvzhiqiang.util.*; import javax.annotation.Resource; import java.io.UnsupportedEncodingException; import java.math.BigDecimal; import java.math.RoundingMode; import java.security.InvalidKeyException; import java.text.DecimalFormat; import java.time.Duration; import java.time.LocalDateTime; import java.util.*; import java.util.concurrent.*; import java.util.stream.Collectors; /** * Coin ServiceImpl * * @author lvzhiqiang * 2023/9/5 15:23 */ @Service @Slf4j public class CoinServiceImpl implements CoinService { /** * 任务告警方式-应用文本卡片 */ public static final String JOB_ALARM_MODE_APP_TEXT_CARD = "1"; /** * 任务告警方式-群聊机器人 */ public static final String JOB_ALARM_MODE_CHAT_BOT = "2"; /** * 任务告警方式(1:应用文本卡片,2:群聊机器人文本消息) */ public static String JOB_ALARM_MODE = "1"; // 所有REST请求的header都必须包含以下key: private static final Map basicHeaderMap = new HashMap<>(); // 主域名 URL private static final String mainUrl = "https://api.bitget.com"; // 私钥,由系统随机生成,用于签名的生成。 private static final String secretKey = "1fdd0fc2976bea80189ba13710e12825ca3ef6c5e25a0d76fd03f8f6cd4a61d9"; @Resource private CoinMapper coinMapper; @Resource private WxCpService wxCpService; @Autowired(required = false) private WorkWeixinProperties properties; private final Map orderMap = new ConcurrentHashMap<>(); private final Map mixMap = new ConcurrentHashMap<>(); private final static ScheduledExecutorService scheduler = new ScheduledThreadPoolExecutor(10); private final ForkJoinPool forkJoinPool = new ForkJoinPool(16); private final ForkJoinPool forkJoinPool2 = new ForkJoinPool(16); private final ForkJoinPool forkJoinPool3 = new ForkJoinPool(16); private final ForkJoinPool forkJoinPool4 = new ForkJoinPool(16); private static final DecimalFormat df1 = new DecimalFormat("#,##0.00"); static { // API KEY作为一个字符串。 basicHeaderMap.put("ACCESS-KEY", "bg_433d37306df0e8901c6d107c6d9e9111"); // 使用base64编码签名(请参阅签名消息)。 basicHeaderMap.put("ACCESS-SIGN", ""); // 您请求的时间戳。 basicHeaderMap.put("ACCESS-TIMESTAMP", ""); // 您在创建API KEY时设置的口令。 basicHeaderMap.put("ACCESS-PASSPHRASE", "7f934f62f2701bee932204580d115228"); // 统一设置为application/json。 basicHeaderMap.put("Content-Type", "application/json"); // 支持多语言, 如:中文(zh-CN),英语(en-US) basicHeaderMap.put("locale", "zh-CN"); df1.setRoundingMode(RoundingMode.HALF_UP); } @Override @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class) public void syncData(String startTime, String endTime, String pageSize) { // 获取全部历史委托 Map paramMap = new LinkedHashMap<>(); paramMap.put("productType", "umcbl"); paramMap.put("startTime", startTime); paramMap.put("endTime", endTime); paramMap.put("pageSize", pageSize); String signQueryString = paramMap.entrySet().stream().map(e -> e.getKey() + "=" + e.getValue()).collect(Collectors.joining("&")); JSONObject response = requestApi4Common("/api/mix/v1/order/historyProductType", signQueryString, null, JsoupUtil.HTTP_GET, paramMap); JSONArray orderList = response.getJSONObject("data").getJSONArray("orderList"); if (orderList.size() > 0) { coinMapper.insertHistoryOrderList(JSONArray.parseArray(orderList.toJSONString(), CoinHistoryOrder.class)); log.warn("syncData->insertHistoryOrderList,startTime={},endTime={},size={}", startTime, endTime, orderList.size()); } } @Override public String monitorJob() { scheduler.scheduleWithFixedDelay(() -> { LocalDateTime endTime = LocalDateTime.now(); // 全部历史委托监控 Map paramMap = new LinkedHashMap<>(); paramMap.put("productType", "umcbl"); paramMap.put("startTime", String.valueOf(DateUtils.localDateTimeToMilliseconds(endTime.minusMinutes(1)))); paramMap.put("endTime", String.valueOf(DateUtils.localDateTimeToMilliseconds(endTime))); paramMap.put("pageSize", "100"); String signQueryString = paramMap.entrySet().stream().map(e -> e.getKey() + "=" + e.getValue()).collect(Collectors.joining("&")); try { JSONObject response = requestApi4Common("/api/mix/v1/order/historyProductType", signQueryString, null, JsoupUtil.HTTP_GET, paramMap); JSONArray orderList = response.getJSONObject("data").getJSONArray("orderList"); for (int i = 0; i < orderList.size(); i++) { JSONObject order = orderList.getJSONObject(i); LocalDateTime cTime = DateUtils.longToLocalDateTime(order.getLong("cTime")); String orderId = order.getString("orderId"); if (Duration.between(cTime, endTime).getSeconds() < 50 && !orderMap.containsKey(orderId)) { orderMap.put(orderId, "1"); String content = order.getString("symbol") + "委托单已经触发,成交均价为" + order.getString("priceAvg"); SpringUtils.getBean(CoinServiceImpl.class).monitorAlarm(content, JOB_ALARM_MODE_APP_TEXT_CARD); } } } catch (Exception e) { } }, 0, 2, TimeUnit.SECONDS); scheduler.scheduleAtFixedRate(() -> { // 全部合约仓位信息V2 Map paramMap = new HashMap<>(); paramMap.put("productType", "umcbl"); String signQueryString = paramMap.entrySet().stream().map(e -> e.getKey() + "=" + e.getValue()).collect(Collectors.joining("&")); try { JSONObject response = requestApi4Common("/api/mix/v1/position/allPosition-v2", signQueryString, null, JsoupUtil.HTTP_GET, paramMap); JSONArray mixList = response.getJSONArray("data"); for (int i = 0; i < mixList.size(); i++) { JSONObject mixData = mixList.getJSONObject(i); String symbol = mixData.getString("symbol"); String margin = mixData.getString("margin"); String averageOpenPrice = mixData.getString("averageOpenPrice"); String key = symbol + margin + averageOpenPrice; // 回报率=未实现盈亏/保证金 // 持仓方向 long:多头 short:空头 String holdSide = mixData.getString("holdSide"); BigDecimal returnRate = new BigDecimal(mixData.getString("unrealizedPL")).divide(new BigDecimal(margin), 4, RoundingMode.HALF_UP); for (int j = 1; j <= 10; j++) { BigDecimal grid = BigDecimal.valueOf(0.5).multiply(BigDecimal.valueOf(j)); if ("long".equalsIgnoreCase(holdSide)) { if (returnRate.compareTo(grid) < 0) { if (mixMap.containsKey(key)) { mixMap.get(key).put("returnRate", returnRate); } else { JSONObject jsonObject = new JSONObject(); jsonObject.put("returnRate", returnRate); mixMap.put(key, jsonObject); } break; } if (returnRate.compareTo(grid) > 0) { if (mixMap.containsKey(key)) { mixMap.get(key).put("returnRate", returnRate); if (mixMap.get(key).containsKey(grid.toPlainString())) { continue; } else { mixMap.get(key).put(grid.toPlainString(), true); SpringUtils.getBean(CoinServiceImpl.class).monitorAlarm(symbol.concat("回报率超过").concat(grid.toPlainString()), JOB_ALARM_MODE_CHAT_BOT); } } else { JSONObject jsonObject = new JSONObject(); jsonObject.put("returnRate", returnRate); jsonObject.put(grid.toPlainString(), true); mixMap.put(key, jsonObject); SpringUtils.getBean(CoinServiceImpl.class).monitorAlarm(symbol.concat("回报率超过").concat(grid.toPlainString()), JOB_ALARM_MODE_CHAT_BOT); break; } } } if ("short".equalsIgnoreCase(holdSide)) { // TODO } } } } catch (Exception e) { e.printStackTrace(); } }, 0, 5, TimeUnit.SECONDS); return null; } @Override @Async("coinTaskExecutor") public void monitorAlarm(String content, String jobAlarmMode) { // 判断告警模式 if (StringUtils.isEmpty(JOB_ALARM_MODE)) { jobAlarmMode = JOB_ALARM_MODE; } // 文本卡片模式发消息 if (JOB_ALARM_MODE_APP_TEXT_CARD.equals(jobAlarmMode)) { String title = "监控告警明细"; String logUrl = "https://lvzhiqiang.top"; String btnTxt = "日志详情"; WxCpMessage wxCpMessage = WxCpMessage.TEXTCARD().agentId(properties.getAgentId()) .toUser("LvZhiQiang") .toParty("") .toTag("") .title(title).description(content) .url(logUrl).btnTxt(btnTxt) .build(); try { log.info("企业微信推送消息,send message: {}", wxCpMessage); WxCpMessageSendResult sendResult = wxCpService.getMessageService().send(wxCpMessage); log.info("企业微信推送消息成功,send result: {}", sendResult); } catch (WxErrorException e) { log.error("企业微信推送消息失败!Detail: ", e); } } // 调用企业微信群聊机器人发消息 if (JOB_ALARM_MODE_CHAT_BOT.equals(jobAlarmMode)) { WxCpGroupRobotService groupRobotService = wxCpService.getGroupRobotService(); String webhookUrl = "https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=082970da-2a33-422a-81f6-15f9bde87940"; try { log.info("企业微信推送消息,send content: {}, userIdSet: {}", content, "LvZhiQiang"); groupRobotService.sendText(webhookUrl, content, Collections.singletonList("LvZhiQiang"), Collections.emptyList()); log.info("企业微信推送消息成功"); } catch (WxErrorException e) { log.error("企业微信推送消息失败!Detail: ", e); } } } /** * 请求通用API方法 */ private JSONObject requestApi4Common(String requestPath, String signQueryString, String signBody, String httpMethod, Map paramMap) { String timestamp = String.valueOf(System.currentTimeMillis()); Map headerMap = new HashMap<>(); headerMap.putAll(basicHeaderMap); try { String accessSign = CheckSign4Bitget.generate(timestamp, "GET", requestPath, signQueryString, signBody, secretKey); headerMap.put("ACCESS-TIMESTAMP", timestamp); headerMap.put("ACCESS-SIGN", accessSign); } catch (CloneNotSupportedException e) { throw new RuntimeException(e); } catch (InvalidKeyException e) { throw new RuntimeException(e); } catch (UnsupportedEncodingException e) { throw new RuntimeException(e); } try { String requestUrl = mainUrl + requestPath; Connection.Response response = JsoupUtil.requestBody(requestUrl, httpMethod, InitRunner.proxy, headerMap, paramMap); return JSONObject.parseObject(response.body()); } catch (Exception e) { throw new RuntimeException(e); } } @Override public JSONArray mainSearch(JSONObject params) throws Exception { JSONArray result = new JSONArray(); if (params.getString("nameEn").equals("allPositionv2")) { Map paramMap = new HashMap<>(); paramMap.put("productType", "umcbl"); String signQueryString = paramMap.entrySet().stream().map(e -> e.getKey() + "=" + e.getValue()).collect(Collectors.joining("&")); JSONObject response = requestApi4Common(params.getString("url"), signQueryString, null, JsoupUtil.HTTP_GET, paramMap); result = response.getJSONArray("data"); renderMainSearch4AllPositionv2(result); } else if (params.getString("nameEn").equals("orderMarginCoinCurrent")) { Map paramMap = new LinkedHashMap<>(); paramMap.put("productType", "umcbl"); paramMap.put("marginCoin", "USDT"); String signQueryString = paramMap.entrySet().stream().map(e -> e.getKey() + "=" + e.getValue()).collect(Collectors.joining("&")); JSONObject response = requestApi4Common(params.getString("url"), signQueryString, null, JsoupUtil.HTTP_GET, paramMap); result = response.getJSONArray("data"); renderMainSearch4OrderMarginCoinCurrent(result); } else if (params.getString("nameEn").equals("orderHistoryProductType")) { List historyOrderList = coinMapper.findByParams(); renderMainSearch4OrderHistoryProductType(historyOrderList); result = (JSONArray) JSON.toJSON(historyOrderList); } else if (params.getString("nameEn").equals("monitorCurrency")) { List monitorCurrencyList = coinMapper.findMonitorCurrencyList(); String requestUrl = mainUrl + params.getString("url"); Connection.Response response = JsoupUtil.requestBody(requestUrl, JsoupUtil.HTTP_GET, InitRunner.proxy, null, null); result = JSONObject.parseObject(response.body()).getJSONArray("data"); result = renderMainSearch4MonitorCurrency(result, monitorCurrencyList); } else if (params.getString("nameEn").equals("currentPlan")) { Map paramMap = new LinkedHashMap<>(); paramMap.put("productType", "umcbl"); paramMap.put("isPlan", "plan"); String signQueryString = paramMap.entrySet().stream().map(e -> e.getKey() + "=" + e.getValue()).collect(Collectors.joining("&")); JSONObject response = requestApi4Common(params.getString("url"), signQueryString, null, JsoupUtil.HTTP_GET, paramMap); result = response.getJSONArray("data"); renderMainSearch4CurrentPlan(result); } return result; } /** * 渲染获取当前计划委托(止盈止损)列表 * * @param result */ private void renderMainSearch4CurrentPlan(JSONArray result) { forkJoinPool3.submit(() -> result.parallelStream().forEach(e -> { JSONObject jsonObject = (JSONObject) e; // 币对名称 String symbol = jsonObject.getString("symbol"); jsonObject.put("symbol", "" + symbol.replace("USDT_UMCBL", "") + "USDT_UMCBL"); // 订单状态 jsonObject.put("status", InitRunner.publicParamsMap.get("status").getString(jsonObject.getString("status"))); // 交易类型 jsonObject.put("orderType", InitRunner.publicParamsMap.get("orderType").getString(jsonObject.getString("orderType"))); // 订单类型 jsonObject.put("planType", InitRunner.publicParamsMap.get("planType").getString(jsonObject.getString("planType"))); // 开单方向 String side = jsonObject.getString("side"); jsonObject.put("side", InitRunner.publicParamsMap.get("side").getString(side)); if (side.equals("open_long")) { jsonObject.put("sideStyle", " style=\"color:#FFFFFF;background-color:#1DA2B4;\""); } else if (side.equals("open_short")) { jsonObject.put("sideStyle", " style=\"color:#FFFFFF;background-color:#F1493F;\""); } else { jsonObject.put("sideStyle", " style=\"color:#FFFFFF;background-color:#F0F0F0;\""); } // 触发类型 jsonObject.put("triggerType", InitRunner.publicParamsMap.get("triggerType").getString(jsonObject.getString("triggerType"))); jsonObject.put("cTime", DateUtils.longToString(jsonObject.getLong("cTime"))); jsonObject.put("uTime", StringUtils.isEmpty(jsonObject.getString("uTime")) ? "--" : DateUtils.longToString(jsonObject.getLong("uTime"))); String requestUrl = mainUrl + "/api/mix/v1/market/ticker?symbol=" + symbol; try { Connection.Response response = JsoupUtil.requestBody(requestUrl, JsoupUtil.HTTP_GET, InitRunner.proxy, null, null); String last = JSONObject.parseObject(response.body()).getJSONObject("data").getString("last"); BigDecimal chaRate = null; if ("open_long".equals(side)) { chaRate = new BigDecimal(last).divide(new BigDecimal(jsonObject.getString("triggerPrice")), 4, RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(100)).setScale(2, RoundingMode.HALF_UP); } else if ("open_short".equals(side)) { chaRate = new BigDecimal(jsonObject.getString("triggerPrice")).divide(new BigDecimal(last), 4, RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(100)).setScale(2, RoundingMode.HALF_UP); } jsonObject.put("last", last); jsonObject.put("chaRate", chaRate != null ? chaRate : "--"); jsonObject.put("chaRateStyle", " style=\"color:#FFFFFF;background-color:#5EA294;\""); } catch (Exception ex) { throw new RuntimeException(ex); } })).join(); } /** * 渲染获取监控币种列表 * * @param monitorCurrencyList */ private JSONArray renderMainSearch4MonitorCurrency(JSONArray result, List monitorCurrencyList) { JSONArray array = result.stream() .filter(iter -> monitorCurrencyList.contains(((JSONObject) iter).getString("symbol"))) .collect(Collectors.toCollection(JSONArray::new)); forkJoinPool.submit(() -> array.parallelStream().forEach(e -> { JSONObject jsonObject = (JSONObject) e; jsonObject.put("changeUtc", jsonObject.getBigDecimal("changeUtc").multiply(BigDecimal.valueOf(100)).setScale(2, RoundingMode.HALF_UP)); jsonObject.put("change", jsonObject.getBigDecimal("change").multiply(BigDecimal.valueOf(100)).setScale(2, RoundingMode.HALF_UP)); jsonObject.put("ts", DateUtils.longToString(jsonObject.getLong("ts"))); // UTC0时涨跌幅 if (jsonObject.getBigDecimal("changeUtc").compareTo(BigDecimal.ZERO) < 0) { jsonObject.put("changeUtcStyle", " style=\"color:#FFFFFF;background-color:#F1493F;\""); } else { jsonObject.put("changeUtcStyle", " style=\"color:#FFFFFF;background-color:#1DA2B4;\""); } // 24小时涨跌幅 if (jsonObject.getBigDecimal("change").compareTo(BigDecimal.ZERO) < 0) { jsonObject.put("changeStyle", " style=\"color:#FFFFFF;background-color:#F1493F;\""); } else { jsonObject.put("changeStyle", " style=\"color:#FFFFFF;background-color:#1DA2B4;\""); } // 币对名称 String symbol = jsonObject.getString("symbol").replace("USDT", ""); jsonObject.put("symbol", "" + symbol + "USDT"); // 标记价格 jsonObject.put("closeStyle", " style=\"color:#252B31;background-color:#C4ADE9;font-weight:bold;\""); // 基础币量 计价币量 usdt币量 jsonObject.put("baseVol", readableFileSize(jsonObject.getDouble("baseVol"))); jsonObject.put("quoteVol", readableFileSize(jsonObject.getDouble("quoteVol"))); jsonObject.put("usdtVol", readableFileSize(jsonObject.getDouble("usdtVol"))); })).join(); return array; } /** * 渲染获取全部历史委托 * * @param historyOrderList */ private void renderMainSearch4OrderHistoryProductType(List historyOrderList) { for (CoinHistoryOrder coinHistoryOrder : historyOrderList) { // 币种名称 coinHistoryOrder.setSymbol(coinHistoryOrder.getSymbol().replace("USDT_UMCBL", "")); // 订单状态 coinHistoryOrder.setState(InitRunner.publicParamsMap.get("state").getString(coinHistoryOrder.getState())); // 开单方向 coinHistoryOrder.setSide(InitRunner.publicParamsMap.get("side").getString(coinHistoryOrder.getSide())); // 总盈亏 String TotalProfits = "0E-8"; if (!coinHistoryOrder.getTotalProfits().contains("0E-8")) { TotalProfits = new BigDecimal(coinHistoryOrder.getTotalProfits()).setScale(2, RoundingMode.HALF_UP).toPlainString(); } coinHistoryOrder.setTotalProfits(TotalProfits); // 手续费 String fee = "0E-8"; if (!coinHistoryOrder.getFee().contains("0E-8")) { fee = new BigDecimal(coinHistoryOrder.getFee()).setScale(2, RoundingMode.HALF_UP).toPlainString(); } coinHistoryOrder.setFee(fee); // 持仓方向 coinHistoryOrder.setPosSide(InitRunner.publicParamsMap.get("posSide").getString(coinHistoryOrder.getPosSide())); // 仓位模式 coinHistoryOrder.setMarginMode(InitRunner.publicParamsMap.get("marginMode").getString(coinHistoryOrder.getMarginMode())); // 交易类型 coinHistoryOrder.setOrderType(InitRunner.publicParamsMap.get("orderType").getString(coinHistoryOrder.getOrderType())); // 交易方向 coinHistoryOrder.setTradeSide(InitRunner.publicParamsMap.get("tradeSide").getString(coinHistoryOrder.getTradeSide())); // 持仓模式 coinHistoryOrder.setHoldMode(InitRunner.publicParamsMap.get("holdMode").getString(coinHistoryOrder.getHoldMode())); // orderSource coinHistoryOrder.setOrderSource(InitRunner.publicParamsMap.get("orderSource").getString(coinHistoryOrder.getOrderSource())); coinHistoryOrder.setCTime(DateUtils.longToString(Long.valueOf(coinHistoryOrder.getCTime()))); coinHistoryOrder.setUTime(DateUtils.longToString(Long.valueOf(coinHistoryOrder.getUTime()))); } } /** * 渲染获取全部当前委托 * * @param result */ private void renderMainSearch4OrderMarginCoinCurrent(JSONArray result) { forkJoinPool2.submit(() -> result.parallelStream().forEach(e -> { JSONObject jsonObject = (JSONObject) e; // 币对名称 String symbol = jsonObject.getString("symbol"); jsonObject.put("symbol", "" + symbol.replace("USDT_UMCBL", "") + "USDT_UMCBL"); // 订单状态 jsonObject.put("state", InitRunner.publicParamsMap.get("state").getString(jsonObject.getString("state"))); // 开单方向 String side = jsonObject.getString("side"); jsonObject.put("side", InitRunner.publicParamsMap.get("side").getString(side)); // 交易类型 jsonObject.put("orderType", InitRunner.publicParamsMap.get("orderType").getString(jsonObject.getString("orderType"))); // 止盈止损 jsonObject.put("presetTakeProfitPrice", StringUtils.isEmpty(jsonObject.getString("presetTakeProfitPrice")) ? "--" : jsonObject.getString("presetTakeProfitPrice")); jsonObject.put("presetStopLossPrice", StringUtils.isEmpty(jsonObject.getString("presetTakeProfitPrice")) ? "--" : jsonObject.getString("presetTakeProfitPrice")); // 持仓模式 jsonObject.put("holdMode", InitRunner.publicParamsMap.get("holdMode").getString(jsonObject.getString("holdMode"))); // orderSource jsonObject.put("orderSource", InitRunner.publicParamsMap.get("orderSource").getString(jsonObject.getString("orderSource"))); // 仓位模式 jsonObject.put("marginMode", InitRunner.publicParamsMap.get("marginMode").getString(jsonObject.getString("marginMode"))); jsonObject.put("cTime", DateUtils.longToString(jsonObject.getLong("cTime"))); jsonObject.put("uTime", DateUtils.longToString(jsonObject.getLong("uTime"))); String requestUrl = mainUrl + "/api/mix/v1/market/ticker?symbol=" + symbol; try { Connection.Response response = JsoupUtil.requestBody(requestUrl, JsoupUtil.HTTP_GET, InitRunner.proxy, null, null); String last = JSONObject.parseObject(response.body()).getJSONObject("data").getString("last"); BigDecimal chaRate = null; if ("open_short".equals(side)) { chaRate = new BigDecimal(last).divide(new BigDecimal(jsonObject.getString("price")), 4, RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(100)).setScale(2, RoundingMode.HALF_UP); } else if ("open_long".equals(side)) { chaRate = new BigDecimal(jsonObject.getString("price")).divide(new BigDecimal(last), 4, RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(100)).setScale(2, RoundingMode.HALF_UP); } jsonObject.put("last", last); jsonObject.put("chaRate", chaRate != null ? chaRate : "--"); jsonObject.put("chaRateStyle", " style=\"color:#FFFFFF;background-color:#5EA294;\""); } catch (Exception ex) { throw new RuntimeException(ex); } })).join(); } /** * 渲染获取全部合约仓位信息V2 * * @param result */ private void renderMainSearch4AllPositionv2(JSONArray result) { forkJoinPool4.submit(() -> result.parallelStream().forEach(e -> { JSONObject jsonObject = (JSONObject) e; // 币对名称 String symbol = jsonObject.getString("symbol").replace("USDT_UMCBL", ""); jsonObject.put("symbol", "" + symbol + "USDT_UMCBL"); // 持仓方向 jsonObject.put("holdSide", InitRunner.publicParamsMap.get("holdSide").getString(jsonObject.getString("holdSide"))); // 保证金模式 jsonObject.put("marginMode", InitRunner.publicParamsMap.get("marginMode").getString(jsonObject.getString("marginMode"))); // 持仓模式 jsonObject.put("holdMode", InitRunner.publicParamsMap.get("holdMode").getString(jsonObject.getString("holdMode"))); // 最近更新时间 保证金数量 (保证金币种) 平均开仓价 未实现盈亏 预估强平价 jsonObject.put("cTime", DateUtils.longToString(jsonObject.getLong("cTime"))); jsonObject.put("margin", new BigDecimal(jsonObject.getString("margin")).setScale(4, RoundingMode.HALF_UP)); jsonObject.put("averageOpenPrice", new BigDecimal(jsonObject.getString("averageOpenPrice")).setScale(4, RoundingMode.HALF_UP)); jsonObject.put("unrealizedPL", new BigDecimal(jsonObject.getString("unrealizedPL")).setScale(4, RoundingMode.HALF_UP)); jsonObject.put("liquidationPrice", new BigDecimal(jsonObject.getString("liquidationPrice")).setScale(4, RoundingMode.HALF_UP)); // 未实现盈亏 if (jsonObject.getBigDecimal("unrealizedPL").compareTo(BigDecimal.ZERO) < 0) { jsonObject.put("unrealizedPLStyle", " style=\"color:#FFFFFF;background-color:#F1493F;\""); } else { jsonObject.put("unrealizedPLStyle", " style=\"color:#FFFFFF;background-color:#1DA2B4;\""); } // 标记价格 jsonObject.put("marketPriceStyle", " style=\"color:#252B31;background-color:#C4ADE9;font-weight:bold;\""); })).join(); } /** * Java实现字节转换,可以自动转换为B、KB、MB、GB、TB * * @param size * @return */ private String readableFileSize(double size) { if (size <= 0) { return "0"; } final String[] units = new String[]{"B", "K", "M", "G", "T"}; int digitGroups = (int) (Math.log10(size) / Math.log10(1000)); return df1.format(size / Math.pow(1000, digitGroups)) + units[digitGroups]; } }