CoinServiceImpl.java 93 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736
  1. package top.lvzhiqiang.service.impl;
  2. import com.alibaba.fastjson.JSONArray;
  3. import com.alibaba.fastjson.JSONObject;
  4. import com.github.pagehelper.PageHelper;
  5. import com.github.pagehelper.PageInfo;
  6. import lombok.extern.slf4j.Slf4j;
  7. import me.chanjar.weixin.common.error.WxErrorException;
  8. import me.chanjar.weixin.cp.api.WxCpGroupRobotService;
  9. import me.chanjar.weixin.cp.api.WxCpService;
  10. import me.chanjar.weixin.cp.api.impl.WxCpServiceImpl;
  11. import me.chanjar.weixin.cp.bean.article.NewArticle;
  12. import me.chanjar.weixin.cp.bean.message.WxCpMessage;
  13. import me.chanjar.weixin.cp.bean.message.WxCpMessageSendResult;
  14. import me.chanjar.weixin.cp.config.impl.WxCpDefaultConfigImpl;
  15. import org.jsoup.Connection;
  16. import org.springframework.beans.factory.annotation.Autowired;
  17. import org.springframework.scheduling.annotation.Async;
  18. import org.springframework.stereotype.Service;
  19. import org.springframework.transaction.annotation.Propagation;
  20. import org.springframework.transaction.annotation.Transactional;
  21. import org.springframework.util.StopWatch;
  22. import top.lvzhiqiang.config.InitRunner;
  23. import top.lvzhiqiang.config.WorkWeixinProperties;
  24. import top.lvzhiqiang.entity.*;
  25. import top.lvzhiqiang.exception.BusinessException;
  26. import top.lvzhiqiang.mapper.CoinApiConfigMapper;
  27. import top.lvzhiqiang.mapper.CoinMapper;
  28. import top.lvzhiqiang.service.CoinService;
  29. import top.lvzhiqiang.util.*;
  30. import javax.annotation.Resource;
  31. import java.io.UnsupportedEncodingException;
  32. import java.math.BigDecimal;
  33. import java.math.MathContext;
  34. import java.math.RoundingMode;
  35. import java.security.InvalidKeyException;
  36. import java.text.DecimalFormat;
  37. import java.time.Duration;
  38. import java.time.LocalDate;
  39. import java.time.LocalDateTime;
  40. import java.time.temporal.ChronoUnit;
  41. import java.util.*;
  42. import java.util.concurrent.*;
  43. import java.util.concurrent.atomic.AtomicInteger;
  44. import java.util.function.Function;
  45. import java.util.stream.Collectors;
  46. import java.util.stream.Stream;
  47. /**
  48. * Coin ServiceImpl
  49. *
  50. * @author lvzhiqiang
  51. * 2023/9/5 15:23
  52. */
  53. @Service
  54. @Slf4j
  55. public class CoinServiceImpl implements CoinService {
  56. /**
  57. * 任务告警方式-应用文本卡片
  58. */
  59. public static final String JOB_ALARM_MODE_APP_TEXT_CARD = "1";
  60. /**
  61. * 任务告警方式-群聊机器人
  62. */
  63. public static final String JOB_ALARM_MODE_CHAT_BOT = "2";
  64. /**
  65. * 任务告警方式(1:应用文本卡片,2:群聊机器人文本消息)
  66. */
  67. public static String JOB_ALARM_MODE = "1";
  68. // 所有REST请求的header都必须包含以下key:
  69. private static final Map<String, String> basicHeaderMap = new HashMap<>();
  70. private static final Map<String, String> basicHeaderMap4OKX = new HashMap<>();
  71. // 主域名 URL
  72. private static final String mainUrl = "https://api.bitget.com";
  73. // 私钥,由系统随机生成,用于签名的生成。
  74. private static final String secretKey = "1fdd0fc2976bea80189ba13710e12825ca3ef6c5e25a0d76fd03f8f6cd4a61d9";
  75. private static final String secretKey4OKX = "32AC470662FBB633374B9A41950995A9";
  76. @Resource
  77. private CoinMapper coinMapper;
  78. @Resource
  79. private WxCpService wxCpService;
  80. @Autowired(required = false)
  81. private WorkWeixinProperties properties;
  82. private final Map<String, String> orderMap = new ConcurrentHashMap<>();
  83. private final Map<String, JSONObject> mixMap = new ConcurrentHashMap<>();
  84. private final static ScheduledExecutorService scheduler = new ScheduledThreadPoolExecutor(10);
  85. private final ForkJoinPool forkJoinPool = new ForkJoinPool(16);
  86. private final ForkJoinPool forkJoinPool2 = new ForkJoinPool(16);
  87. private final ForkJoinPool forkJoinPool3 = new ForkJoinPool(16);
  88. private final ForkJoinPool forkJoinPool4 = new ForkJoinPool(16);
  89. private final ForkJoinPool forkJoinPool5 = new ForkJoinPool(16);
  90. private static final DecimalFormat df1 = new DecimalFormat("#,##0.00");
  91. private static final DecimalFormat df2 = new DecimalFormat("#,##0");
  92. private static final WxCpServiceImpl wxCpService4News;
  93. @Resource
  94. private CoinApiConfigMapper coinApiConfigMapper;
  95. static {
  96. // API KEY作为一个字符串。
  97. basicHeaderMap.put("ACCESS-KEY", "bg_433d37306df0e8901c6d107c6d9e9111");
  98. // 使用base64编码签名(请参阅签名消息)。
  99. basicHeaderMap.put("ACCESS-SIGN", "");
  100. // 您请求的时间戳。
  101. basicHeaderMap.put("ACCESS-TIMESTAMP", "");
  102. // 您在创建API KEY时设置的口令。
  103. basicHeaderMap.put("ACCESS-PASSPHRASE", "7f934f62f2701bee932204580d115228");
  104. // 统一设置为application/json。
  105. basicHeaderMap.put("Content-Type", "application/json");
  106. // 支持多语言, 如:中文(zh-CN),英语(en-US)
  107. basicHeaderMap.put("locale", "zh-CN");
  108. // 字符串类型的APIKey
  109. basicHeaderMap4OKX.put("OK-ACCESS-KEY","25e4f515-5efd-4bb9-a934-3949b21d9f10");
  110. // 使用HMAC SHA256哈希函数获得哈希值,再使用Base-64编码(请参阅签名)
  111. basicHeaderMap4OKX.put("OK-ACCESS-SIGN","");
  112. // 发起请求的时间(UTC),如:2020-12-08T09:08:57.715Z
  113. basicHeaderMap4OKX.put("OK-ACCESS-TIMESTAMP","");
  114. // 您在创建API密钥时指定的Passphrase
  115. basicHeaderMap4OKX.put("OK-ACCESS-PASSPHRASE","tmvxeGY#Q#Y2qm8");
  116. // 统一设置为application/json
  117. basicHeaderMap4OKX.put("Content-Type", "application/json");
  118. df1.setRoundingMode(RoundingMode.HALF_UP);
  119. WxCpDefaultConfigImpl wxCpDefaultConfig = new WxCpDefaultConfigImpl();
  120. wxCpDefaultConfig.setCorpId("ww95a4adba56acb55f");
  121. wxCpDefaultConfig.setAgentId(1000004);
  122. wxCpDefaultConfig.setCorpSecret("hG50gbVZ8pXm3tSzY3BpwTzbrMmm6sTf8_bPfJG_6Yc");
  123. wxCpService4News = new WxCpServiceImpl();
  124. wxCpService4News.setWxCpConfigStorage(wxCpDefaultConfig);
  125. }
  126. @Override
  127. @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
  128. public void syncData(String startTime, String endTime, String pageSize) {
  129. // 获取全部历史委托
  130. Map<String, String> paramMap = new LinkedHashMap<>();
  131. paramMap.put("productType", "umcbl");
  132. paramMap.put("startTime", startTime);
  133. paramMap.put("endTime", endTime);
  134. paramMap.put("pageSize", pageSize);
  135. String signQueryString = paramMap.entrySet().stream().map(e -> e.getKey() + "=" + e.getValue()).collect(Collectors.joining("&"));
  136. JSONObject response = requestApi4Common("/api/mix/v1/order/historyProductType", signQueryString, null, JsoupUtil.HTTP_GET, paramMap);
  137. JSONArray orderList = response.getJSONObject("data").getJSONArray("orderList");
  138. if (orderList.size() > 0) {
  139. coinMapper.insertHistoryOrderList(JSONArray.parseArray(orderList.toJSONString(), CoinHistoryOrder.class));
  140. log.warn("syncData->insertHistoryOrderList,startTime={},endTime={},size={}", startTime, endTime, orderList.size());
  141. }
  142. }
  143. @Override
  144. public void syncData4TraderList() {
  145. StopWatch stopWatch = new StopWatch();
  146. stopWatch.start();
  147. // 获取交易员列表
  148. Map<String, String> paramMap = new LinkedHashMap<>();
  149. paramMap.put("sortRule", "composite");
  150. paramMap.put("sortFlag", "desc");
  151. paramMap.put("languageType", "en-US");
  152. paramMap.put("pageSize", "20");
  153. int i = 0;
  154. String url = "/api/mix/v1/trace/traderList";
  155. JSONObject response;
  156. int totalNum = 0;
  157. for (; ; ) {
  158. paramMap.put("pageNo", String.valueOf(++i));
  159. String signQueryString = paramMap.entrySet().stream().map(e -> e.getKey() + "=" + e.getValue()).collect(Collectors.joining("&"));
  160. response = requestApi4Common(url, signQueryString, null, JsoupUtil.HTTP_GET, paramMap);
  161. JSONArray dataList = response.getJSONArray("data");
  162. if (dataList.size() == 0) {
  163. break;
  164. }
  165. try {
  166. syncData4TraderListSub(dataList);
  167. } catch (Exception e) {
  168. log.error("syncData4TraderListSub error,paramMap={}", paramMap, e);
  169. }
  170. totalNum += dataList.size();
  171. }
  172. log.warn("syncData4TraderList 结束:time={},totalNum={}", stopWatch.getTotalTimeSeconds(), totalNum);
  173. }
  174. @Override
  175. public void syncCoinmarketcapCMap() {
  176. StopWatch stopWatch = new StopWatch();
  177. stopWatch.start();
  178. String coinmarketcapApikey = InitRunner.dicCodeMap.get("coinmarketcap_apikey").getCodeValue();
  179. String coinmarketcapIdmapUrl = InitRunner.dicCodeMap.get("coinmarketcap_idmap_url").getCodeValue();
  180. String coinmarketcapIdmapParams4listingStatus = InitRunner.dicCodeMap.get("coinmarketcap_idmap_params_listing_status").getCodeValue();
  181. String coinmarketcapIdmapParams4aux = InitRunner.dicCodeMap.get("coinmarketcap_idmap_params_aux").getCodeValue();
  182. Map<String, String> headerMap = new HashMap<>();
  183. headerMap.put("Accept", "application/json");
  184. headerMap.put("Accept-Encoding", "deflate,gzip");
  185. headerMap.put("X-CMC_PRO_API_KEY", coinmarketcapApikey);
  186. String[] listingStatusArr = coinmarketcapIdmapParams4listingStatus.split(",");
  187. Map<String, String> paramMap = new LinkedHashMap<>();
  188. int MAX_NUMBER = 1000;
  189. int MAX_NUMBER2 = 5000;
  190. Long totalNum = 0L;
  191. for (String listingStatus : listingStatusArr) {
  192. paramMap.put("listing_status", listingStatus);
  193. paramMap.put("aux", coinmarketcapIdmapParams4aux);
  194. try {
  195. int j = 0;
  196. Long totalNum2 = 0L;
  197. for (; ; ) {
  198. Thread.sleep(3000L);
  199. j++;
  200. paramMap.put("start", String.valueOf((j - 1) * MAX_NUMBER2 + 1));
  201. paramMap.put("limit", String.valueOf(MAX_NUMBER2));
  202. Connection.Response response = JsoupUtil.requestBody(coinmarketcapIdmapUrl, JsoupUtil.HTTP_GET, InitRunner.proxy, headerMap, paramMap);
  203. JSONObject result = JSONObject.parseObject(response.body());
  204. JSONArray dataJA = result.getJSONArray("data");
  205. List<CoinCmcMap> cmcMapList = new ArrayList<>();
  206. CoinCmcMap coinCmcMap;
  207. for (int i = 0; i < dataJA.size(); i++) {
  208. JSONObject dataJO = dataJA.getJSONObject(i);
  209. coinCmcMap = new CoinCmcMap();
  210. coinCmcMap.setCmcId(dataJO.getLong("id"));
  211. coinCmcMap.setCmcRank(dataJO.getLong("rank"));
  212. coinCmcMap.setName(dataJO.getString("name"));
  213. coinCmcMap.setSymbol(dataJO.getString("symbol"));
  214. coinCmcMap.setSlug(dataJO.getString("slug"));
  215. coinCmcMap.setIsActive(dataJO.getInteger("is_active"));
  216. coinCmcMap.setStatus(dataJO.getString("status"));
  217. coinCmcMap.setFirstHistoricalData(DateUtils.stringutcToLocalDateTime(dataJO.getString("first_historical_data")));
  218. coinCmcMap.setLastHistoricalData(DateUtils.stringutcToLocalDateTime(dataJO.getString("last_historical_data")));
  219. coinCmcMap.setPlatform(dataJO.getString("platform"));
  220. cmcMapList.add(coinCmcMap);
  221. }
  222. // 新增或者更新
  223. Stream.iterate(0, n -> n + 1).limit((cmcMapList.size() + MAX_NUMBER - 1) / MAX_NUMBER)
  224. .forEach(i -> {
  225. List<CoinCmcMap> list = cmcMapList.stream().skip((long) i * MAX_NUMBER).limit(MAX_NUMBER).collect(Collectors.toList());
  226. coinMapper.insertCmcMapList(list);
  227. });
  228. totalNum += cmcMapList.size();
  229. totalNum2 += cmcMapList.size();
  230. if (dataJA.size() < MAX_NUMBER2) {
  231. break;
  232. }
  233. }
  234. log.warn("syncCoinmarketcapCMap {} success,totalNum={}", listingStatus, totalNum2);
  235. } catch (Exception e) {
  236. log.error("syncCoinmarketcapCMap {} error", listingStatus, e);
  237. }
  238. }
  239. log.warn("syncCoinmarketcapCMap 结束:time={},totalNum={}", stopWatch.getTotalTimeSeconds(), totalNum);
  240. }
  241. @Override
  242. @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
  243. public void syncData4TraderListSub(JSONArray dataList) {
  244. coinMapper.insertMixTradeList(parseMixTradeList(dataList));
  245. }
  246. @Override
  247. public String watchlistDetail(String symbol, String operationType) {
  248. CoinWatchlist coinWatchlist = coinMapper.findWatchlistBySymbol(symbol);
  249. if (coinWatchlist == null) {
  250. throw new BusinessException(1, "symbol不存在!");
  251. }
  252. if ("detail".equals(operationType)) {
  253. return MarkdownToHtmlUtils.markdownToHtmlExtensions(coinWatchlist.getRemark());
  254. } else if ("update".equals(operationType)) {
  255. return coinWatchlist.getRemark();
  256. } else {
  257. return "暂不支持该操作!";
  258. }
  259. }
  260. @Override
  261. public Object watchlistUpdate(String symbol, String remark) {
  262. CoinWatchlist coinWatchlist = new CoinWatchlist();
  263. coinWatchlist.setSymbol(symbol);
  264. coinWatchlist.setRemark(remark);
  265. int num = coinMapper.updateCoinWatchlistRemark(coinWatchlist);
  266. return num;
  267. }
  268. private List<CoinTrader> parseMixTradeList(JSONArray dataList) {
  269. List<CoinTrader> mixTraderList = JSONArray.parseArray(dataList.toJSONString(), CoinTrader.class);
  270. mixTraderList.stream().forEach(e -> {
  271. Map<String, String> columnMap = e.getColumnList().stream().filter(Objects::nonNull)
  272. .collect(Collectors.toMap(
  273. object -> {
  274. JSONObject item = (JSONObject) object;
  275. return item.getString("describe");
  276. },
  277. object -> {
  278. JSONObject item = (JSONObject) object;
  279. return item.getString("value");
  280. }
  281. ));
  282. e.setRoi(columnMap.get("ROI"));
  283. e.setTotalProfit(columnMap.get("Total PnL").replace("$", "").replace(",", ""));
  284. e.setTotalFollowersProfit(columnMap.get("Total followers PnL").replace("$", "").replace(",", ""));
  285. e.setAum(columnMap.get("AUM").replace("$", "").replace(",", ""));
  286. e.setMaxCallbackRate(columnMap.get("Max drawdown"));
  287. e.setLast3wWinRate(columnMap.get("Last 3W win rate"));
  288. e.setAverageWinRate(StringUtils.isNotEmpty(e.getAverageWinRate()) ? new BigDecimal(e.getAverageWinRate()).setScale(2, RoundingMode.HALF_UP).toPlainString() : "0.00");
  289. });
  290. return mixTraderList;
  291. }
  292. @Override
  293. public String orderDetail(String trackingNo) {
  294. Map<String, String> paramMap = new LinkedHashMap<>();
  295. paramMap.put("traderId", "b1b5467f8bb73f53ac97");
  296. paramMap.put("pageSize", "20");
  297. StringBuffer sb = new StringBuffer();
  298. // 交易员当前带单列表筛选
  299. for (int j = 1; j < 5; j++) {
  300. try {
  301. paramMap.put("pageNo", j + "");
  302. JSONObject response = requestApi4Common("/api/mix/v1/trace/report/order/currentList", null, JSONObject.toJSONString(paramMap), JsoupUtil.HTTP_POST, paramMap);
  303. JSONArray orderList = response.getJSONArray("data");
  304. for (int i = 0; i < orderList.size(); i++) {
  305. JSONObject order = orderList.getJSONObject(i);
  306. String trackingNo1 = order.getString("trackingNo");
  307. if (trackingNo.equals(trackingNo1)) {
  308. sb.append("<table border=\"1\" cellspacing=\"0\"><tr><th>键</th><th>值</th></tr>");
  309. sb.append("<tr><td>交易对</td><td>").append(order.getString("symbol")).append("</td></tr>");
  310. sb.append("<tr><td>持仓方向</td><td>").append(InitRunner.publicParamsMap.get("holdSide").getString(order.getString("holdSide"))).append("</td></tr>");
  311. sb.append("<tr><td>杠杆倍数</td><td>").append(order.getString("leverage")).append("</td></tr>");
  312. sb.append("<tr><td>开仓均价</td><td>").append(order.getString("openPrice")).append("</td></tr>");
  313. sb.append("<tr><td>开仓时间</td><td>").append(DateUtils.longToString(order.getLong("openTime"))).append("</td></tr>");
  314. sb.append("<tr><td>此笔订单跟单人数</td><td>").append(order.getString("followerNum")).append("</td></tr>");
  315. sb.append("<tr><td>保证金</td><td>").append(order.getString("marginAmount")).append("</td></tr>");
  316. sb.append("<tr><td>止盈价</td><td>").append(order.getString("takeProfitPrice")).append("</td></tr>");
  317. sb.append("<tr><td>止损价</td><td>").append(order.getString("stopLossPrice")).append("</td></tr>");
  318. sb.append("<tr><td>交易员</td><td>").append("hale").append("</td></tr>");
  319. sb.append("</table>");
  320. break;
  321. }
  322. }
  323. } catch (Exception e) {
  324. }
  325. }
  326. // 交易员历史带单列表筛选
  327. if (sb.length() == 0) {
  328. for (int j = 1; j < 5; j++) {
  329. try {
  330. paramMap.put("pageNo", j + "");
  331. JSONObject response = requestApi4Common("/api/mix/v1/trace/report/order/historyList", null, JSONObject.toJSONString(paramMap), JsoupUtil.HTTP_POST, paramMap);
  332. JSONArray orderList = response.getJSONArray("data");
  333. for (int i = 0; i < orderList.size(); i++) {
  334. JSONObject order = orderList.getJSONObject(i);
  335. String trackingNo1 = order.getString("trackingNo");
  336. if (trackingNo.equals(trackingNo1)) {
  337. sb.append("<table border=\"1\" cellspacing=\"0\" style=\"font-size: 20px;\"><tr><th>键</th><th>值</th></tr>");
  338. sb.append("<tr><td>交易对</td><td>").append(order.getString("symbol")).append("</td></tr>");
  339. sb.append("<tr><td>持仓方向</td><td>").append(InitRunner.publicParamsMap.get("holdSide").getString(order.getString("holdSide"))).append("</td></tr>");
  340. sb.append("<tr><td>杠杆倍数</td><td>").append(order.getString("leverage")).append("</td></tr>");
  341. sb.append("<tr><td>开仓均价</td><td>").append(order.getString("openPrice")).append("</td></tr>");
  342. sb.append("<tr><td>开仓时间</td><td>").append(DateUtils.longToString(order.getLong("openTime"))).append("</td></tr>");
  343. sb.append("<tr><td>此笔订单跟单人数</td><td>").append(order.getString("followerNum")).append("</td></tr>");
  344. sb.append("<tr><td>保证金</td><td>").append(order.getString("marginAmount")).append("</td></tr>");
  345. sb.append("<tr><td>平仓均价</td><td>").append(order.getString("closePrice")).append("</td></tr>");
  346. sb.append("<tr><td>平仓时间</td><td>").append(DateUtils.longToString(order.getLong("closeTime"))).append("</td></tr>");
  347. sb.append("<tr><td>平仓数量</td><td>").append(order.getString("closeAmount")).append("</td></tr>");
  348. sb.append("<tr><td>交易员</td><td>").append("hale").append("</td></tr>");
  349. sb.append("</table>");
  350. break;
  351. }
  352. }
  353. } catch (Exception e) {
  354. }
  355. }
  356. }
  357. return sb.toString();
  358. }
  359. @Override
  360. public String orderDetail2(String orderId, String symbol) {
  361. Map<String, String> paramMap = new LinkedHashMap<>();
  362. paramMap.put("symbol", symbol);
  363. paramMap.put("orderId", orderId);
  364. StringBuffer sb = new StringBuffer("<table border=\"1\" cellspacing=\"0\" style=\"font-size: 20px;\"><tr><th>键</th><th>值</th></tr>");
  365. // 获取订单详情
  366. try {
  367. String signQueryString = paramMap.entrySet().stream().map(e -> e.getKey() + "=" + e.getValue()).collect(Collectors.joining("&"));
  368. JSONObject response = requestApi4Common("/api/mix/v1/order/detail", signQueryString, null, JsoupUtil.HTTP_GET, paramMap);
  369. JSONObject order = response.getJSONObject("data");
  370. sb.append("<tr><td>交易对</td><td>").append(order.getString("symbol")).append("</td></tr>");
  371. sb.append("<tr><td>交易方向</td><td>").append(InitRunner.publicParamsMap.get("side").getString(order.getString("side"))).append("</td></tr>");
  372. sb.append("<tr><td>杠杆倍数</td><td>").append(order.getString("leverage")).append("</td></tr>");
  373. sb.append("<tr><td>成交均价</td><td>").append(order.getString("priceAvg")).append("</td></tr>");
  374. sb.append("<tr><td>委托价格</td><td>").append(order.getString("price")).append("</td></tr>");
  375. sb.append("<tr><td>手续费</td><td>").append(order.getString("fee")).append("</td></tr>");
  376. sb.append("<tr><td>订单状态</td><td>").append(InitRunner.publicParamsMap.get("state").getString(order.getString("state"))).append("</td></tr>");
  377. sb.append("<tr><td>交易类型</td><td>").append(InitRunner.publicParamsMap.get("orderType").getString(order.getString("orderType"))).append("</td></tr>");
  378. sb.append("<tr><td>总盈亏</td><td>").append(order.getString("totalProfits")).append("</td></tr>");
  379. sb.append("<tr><td>预设止盈价格</td><td>").append(order.getString("presetTakeProfitPrice")).append("</td></tr>");
  380. sb.append("<tr><td>预设止损价格</td><td>").append(order.getString("presetStopLossPrice")).append("</td></tr>");
  381. sb.append("<tr><td>创建时间</td><td>").append(DateUtils.longToString(order.getLong("cTime"))).append("</td></tr>");
  382. sb.append("<tr><td>更新时间</td><td>").append(DateUtils.longToString(order.getLong("uTime"))).append("</td></tr>");
  383. } catch (Exception e) {
  384. log.error("orderDetail2 error,orderId={},symbol={}", orderId, symbol, e);
  385. }
  386. sb.append("</table>");
  387. return sb.toString();
  388. }
  389. @Override
  390. public String monitorJob() {
  391. // BITGET开仓平仓监控报警
  392. scheduler.scheduleWithFixedDelay(() -> {
  393. LocalDateTime endTime = LocalDateTime.now();
  394. // 全部历史委托列表
  395. Map<String, String> paramMap = new LinkedHashMap<>();
  396. paramMap.put("productType", "umcbl");
  397. paramMap.put("startTime", String.valueOf(DateUtils.localDateTimeToMilliseconds(endTime.minusMinutes(1))));
  398. paramMap.put("endTime", String.valueOf(DateUtils.localDateTimeToMilliseconds(endTime)));
  399. paramMap.put("pageSize", "100");
  400. String signQueryString = paramMap.entrySet().stream().map(e -> e.getKey() + "=" + e.getValue()).collect(Collectors.joining("&"));
  401. try {
  402. JSONObject response = requestApi4Common("/api/mix/v1/order/historyProductType", signQueryString, null, JsoupUtil.HTTP_GET, paramMap);
  403. JSONArray orderList = response.getJSONObject("data").getJSONArray("orderList");
  404. for (int i = 0; i < orderList.size(); i++) {
  405. JSONObject order = orderList.getJSONObject(i);
  406. LocalDateTime cTime = DateUtils.longToLocalDateTime(order.getLong("cTime"));
  407. String orderId = order.getString("orderId");
  408. String symbol = order.getString("symbol");
  409. if (Duration.between(cTime, endTime).getSeconds() < 50 && !orderMap.containsKey(orderId)) {
  410. orderMap.put(orderId, "1");
  411. String content = "<div class=\"highlight\">交易对:" + order.getString("symbol") + "</div>" +
  412. "<div>交易方向:" + InitRunner.publicParamsMap.get("side").getString(order.getString("side")) + "</div>" +
  413. "<div>杠杆倍数:" + order.getString("leverage") + "</div>" +
  414. "<div>成交均价:" + order.getString("priceAvg") + "</div>" +
  415. "<div>委托价格:" + order.getString("price") + "</div>" +
  416. "<div>订单状态:" + InitRunner.publicParamsMap.get("state").getString(order.getString("state")) + "</div>" +
  417. "<div>订单类型:" + InitRunner.publicParamsMap.get("orderType").getString(order.getString("orderType")) + "</div>" +
  418. "<div class=\"gray\">订单时间:" + DateUtils.longToString(order.getLong("cTime")) + "</div>";
  419. JSONObject params = new JSONObject();
  420. params.put("title", (order.getString("side").contains("open") ? "BITGET合约开单" : "BITGET合约平单") + "报警");
  421. params.put("logUrl", "https://jav.lvzhiqiang.top/coin/orderDetail2/" + orderId + "/" + symbol);
  422. params.put("btnTxt", "订单详情");
  423. SpringUtils.getBean(CoinServiceImpl.class).monitorAlarm4APP_TEXT_CARD(content, params, null);
  424. }
  425. }
  426. } catch (Exception e) {
  427. }
  428. }, 0, 2, TimeUnit.SECONDS);
  429. // OKX开仓平仓监控报警
  430. scheduler.scheduleWithFixedDelay(() -> {
  431. LocalDateTime endTime = LocalDateTime.now();
  432. // 查看历史持仓信息
  433. Map<String, String> paramMap = new LinkedHashMap<>();
  434. paramMap.put("instType", "SWAP");
  435. String signQueryString = paramMap.entrySet().stream().map(e -> e.getKey() + "=" + e.getValue()).collect(Collectors.joining("&"));
  436. try {
  437. JSONObject response = requestApi4Common4OKX("/api/v5/account/positions-history", signQueryString, null, JsoupUtil.HTTP_GET, paramMap);
  438. JSONArray orderList = response.getJSONArray("data");
  439. for (int i = 0; i < orderList.size(); i++) {
  440. JSONObject order = orderList.getJSONObject(i);
  441. //LocalDateTime cTime = DateUtils.longToLocalDateTime(order.getLong("cTime"));
  442. String orderId = "okx" + order.getString("posId");
  443. String symbol = order.getString("ccy");
  444. if (!orderMap.containsKey(orderId)) {
  445. orderMap.put(orderId, "1");
  446. log.warn("okx ={}", order);
  447. String content = "<div class=\"highlight\">交易对:" + symbol + "</div>";
  448. JSONObject params = new JSONObject();
  449. params.put("title", "OKX报警");
  450. params.put("logUrl", "https://jav.lvzhiqiang.top/coin/orderDetail2/" + orderId + "/" + symbol);
  451. params.put("btnTxt", "订单详情");
  452. SpringUtils.getBean(CoinServiceImpl.class).monitorAlarm4APP_TEXT_CARD(content, params, null);
  453. }
  454. }
  455. } catch (Exception e) {
  456. }
  457. }, 0, 10, TimeUnit.SECONDS);
  458. scheduler.scheduleAtFixedRate(() -> {
  459. // BITGET全部合约仓位信息V2
  460. Map<String, String> paramMap = new HashMap<>();
  461. paramMap.put("productType", "umcbl");
  462. String signQueryString = paramMap.entrySet().stream().map(e -> e.getKey() + "=" + e.getValue()).collect(Collectors.joining("&"));
  463. try {
  464. JSONObject response = requestApi4Common("/api/mix/v1/position/allPosition-v2", signQueryString, null, JsoupUtil.HTTP_GET, paramMap);
  465. JSONArray mixList = response.getJSONArray("data");
  466. for (int i = 0; i < mixList.size(); i++) {
  467. JSONObject mixData = mixList.getJSONObject(i);
  468. String symbol = mixData.getString("symbol");
  469. String margin = mixData.getString("margin");
  470. String averageOpenPrice = mixData.getString("averageOpenPrice");
  471. String key = symbol + margin + averageOpenPrice;
  472. // 回报率=未实现盈亏/保证金
  473. // 持仓方向 long:多头 short:空头
  474. String holdSide = mixData.getString("holdSide");
  475. BigDecimal returnRate = new BigDecimal(mixData.getString("unrealizedPL")).divide(new BigDecimal(margin), 4, RoundingMode.HALF_UP);
  476. for (int j = 1; j <= 10; j++) {
  477. BigDecimal grid = BigDecimal.valueOf(0.5).multiply(BigDecimal.valueOf(j));
  478. BigDecimal minusGrid = BigDecimal.valueOf(-0.5).multiply(BigDecimal.valueOf(j));
  479. if (returnRate.compareTo(grid) < 0) {
  480. if (mixMap.containsKey(key)) {
  481. mixMap.get(key).put("returnRate", returnRate);
  482. } else {
  483. JSONObject jsonObject = new JSONObject();
  484. jsonObject.put("returnRate", returnRate);
  485. mixMap.put(key, jsonObject);
  486. }
  487. break;
  488. }
  489. if (returnRate.compareTo(grid) > 0) {
  490. if (mixMap.containsKey(key)) {
  491. mixMap.get(key).put("returnRate", returnRate);
  492. if (mixMap.get(key).containsKey(grid.toPlainString())) {
  493. continue;
  494. } else {
  495. mixMap.get(key).put(grid.toPlainString(), true);
  496. String requestUrl = mainUrl + "/api/mix/v1/market/ticker?symbol=" + symbol;
  497. String last = "--";
  498. try {
  499. Connection.Response responseTicker = JsoupUtil.requestBody(requestUrl, JsoupUtil.HTTP_GET, InitRunner.proxy, null, null);
  500. last = JSONObject.parseObject(responseTicker.body()).getJSONObject("data").getString("last");
  501. } catch (Exception e) {
  502. }
  503. String content = "币对名称:" + symbol + "\n" +
  504. "持仓方向:" + InitRunner.publicParamsMap.get("holdSide").getString(mixData.getString("holdSide")) + "\n" +
  505. "杠杆倍数:" + mixData.getString("leverage") + "\n" +
  506. "开仓均价:" + mixData.getString("averageOpenPrice") + "\n" +
  507. "当前价格:" + last + "\n" +
  508. "回报率:" + returnRate.multiply(BigDecimal.valueOf(100)).setScale(2, RoundingMode.HALF_UP).toPlainString() + ",超过" + grid.multiply(BigDecimal.valueOf(100)).setScale(2, RoundingMode.HALF_UP).toPlainString();
  509. SpringUtils.getBean(CoinServiceImpl.class).monitorAlarm4CHAT_BOT(content, null);
  510. }
  511. } else {
  512. JSONObject jsonObject = new JSONObject();
  513. jsonObject.put("returnRate", returnRate);
  514. jsonObject.put(grid.toPlainString(), true);
  515. mixMap.put(key, jsonObject);
  516. String requestUrl = mainUrl + "/api/mix/v1/market/ticker?symbol=" + symbol;
  517. String last = "--";
  518. try {
  519. Connection.Response responseTicker = JsoupUtil.requestBody(requestUrl, JsoupUtil.HTTP_GET, InitRunner.proxy, null, null);
  520. last = JSONObject.parseObject(responseTicker.body()).getJSONObject("data").getString("last");
  521. } catch (Exception e) {
  522. }
  523. String content = "币对名称:" + symbol + "\n" +
  524. "持仓方向:" + InitRunner.publicParamsMap.get("holdSide").getString(mixData.getString("holdSide")) + "\n" +
  525. "杠杆倍数:" + mixData.getString("leverage") + "\n" +
  526. "开仓均价:" + mixData.getString("averageOpenPrice") + "\n" +
  527. "当前价格:" + last + "\n" +
  528. "回报率:" + returnRate.multiply(BigDecimal.valueOf(100)).setScale(2, RoundingMode.HALF_UP).toPlainString() + ",超过" + grid.multiply(BigDecimal.valueOf(100)).setScale(2, RoundingMode.HALF_UP).toPlainString();
  529. SpringUtils.getBean(CoinServiceImpl.class).monitorAlarm4CHAT_BOT(content, null);
  530. //break;
  531. }
  532. }
  533. }
  534. }
  535. } catch (Exception e) {
  536. e.printStackTrace();
  537. }
  538. }, 0, 5, TimeUnit.SECONDS);
  539. // BITGET跟单员监控报警
  540. scheduler.scheduleWithFixedDelay(() -> {
  541. List<String> monitorTraderList = coinMapper.findMonitorTraderList();
  542. forkJoinPool5.submit(() -> monitorTraderList.parallelStream().forEach(e -> {
  543. LocalDateTime endTime = LocalDateTime.now();
  544. // 交易员当前带单列表
  545. Map<String, String> paramMap = new LinkedHashMap<>();
  546. String[] split = e.split("\\|");
  547. paramMap.put("traderId", split[0]);
  548. paramMap.put("pageNo", "1");
  549. paramMap.put("pageSize", "20");
  550. try {
  551. JSONObject response = requestApi4Common("/api/mix/v1/trace/report/order/currentList", null, JSONObject.toJSONString(paramMap), JsoupUtil.HTTP_POST, paramMap);
  552. JSONArray orderList = response.getJSONArray("data");
  553. for (int i = 0; i < orderList.size(); i++) {
  554. JSONObject order = orderList.getJSONObject(i);
  555. LocalDateTime openTime = DateUtils.longToLocalDateTime(order.getLong("openTime"));
  556. String trackingNo = order.getString("trackingNo");
  557. if (Duration.between(openTime, endTime).getSeconds() < 50 && !orderMap.containsKey(trackingNo)) {
  558. orderMap.put(trackingNo, "1");
  559. String content = "<div class=\"highlight\">交易对:" + order.getString("symbol") + "</div>" +
  560. "<div>持仓方向:" + InitRunner.publicParamsMap.get("holdSide").getString(order.getString("holdSide")) + "</div>" +
  561. "<div>杠杆倍数:" + order.getString("leverage") + "</div>" +
  562. "<div>开仓均价:" + order.getString("openPrice") + "</div>" +
  563. "<div>止盈价:" + order.getString("takeProfitPrice") + "</div>" +
  564. "<div>止损价:" + order.getString("stopLossPrice") + "</div>" +
  565. "<div >交易员:" + split[1] + "</div>" +
  566. "<div class=\"gray\">开仓时间:" + DateUtils.longToString(order.getLong("openTime")) + "</div>";
  567. JSONObject params = new JSONObject();
  568. params.put("title", "BITGET交易员开单报警");
  569. params.put("logUrl", "https://jav.lvzhiqiang.top/coin/orderDetail/" + order.getString("trackingNo"));
  570. params.put("btnTxt", "跟单详情");
  571. SpringUtils.getBean(CoinServiceImpl.class).monitorAlarm4APP_TEXT_CARD(content, params, null);
  572. }
  573. }
  574. } catch (Exception ex) {
  575. }
  576. })).join();
  577. }, 0, 3, TimeUnit.SECONDS);
  578. // 星球日报新闻快讯监控报警
  579. /*scheduler.scheduleWithFixedDelay(() -> {
  580. try {
  581. Connection.Response response = JsoupUtil.requestBody("https://www.odaily.news/v1/openapi/feeds", JsoupUtil.HTTP_GET, InitRunner.proxy, null, null);
  582. JSONObject result = JSONObject.parseObject(response.body());
  583. JSONArray newsList = result.getJSONObject("data").getJSONArray("arr_news");
  584. LocalDateTime endTime = LocalDateTime.now();
  585. for (int i = 0; i < newsList.size(); i++) {
  586. if (i == 5) {
  587. break;
  588. }
  589. JSONObject news = newsList.getJSONObject(i);
  590. String id = "Odaily" + news.getString("id");
  591. String publishedAt = news.getString("published_at");
  592. LocalDateTime publishedAtTime = DateUtils.stringToLocalDateTime(publishedAt);
  593. if (Duration.between(publishedAtTime, endTime).getSeconds() < 20 && !orderMap.containsKey(id)) {
  594. orderMap.put(id, "1");
  595. String type = news.getString("type");
  596. String title = news.getString("title");
  597. String link = news.getString("link");
  598. String content = "";
  599. JSONObject params = new JSONObject();
  600. params.put("title", "Odaily监控报警");
  601. params.put("btnTxt", "新闻详情");
  602. params.put("logUrl", link);
  603. params.put("user", "@all");
  604. params.put("agentId", 1000004);
  605. if ("newsflashes".equals(type)) {
  606. String newsUrl = news.getString("news_url");
  607. content = "<div class=\"highlight\">标题:" + title + "</div>" +
  608. "<div>类型:" + "新闻快讯" + "</div>" +
  609. "<div>发布时间:" + publishedAt + "</div>" +
  610. "<div class=\"gray\">描述:" + news.getString("description").replace("\n", "&nbsp;&nbsp;&nbsp;&nbsp;") + "</div>";
  611. } else if ("posts".equals(type)) {
  612. content = "<div class=\"highlight\">标题:" + title + "</div>" +
  613. "<div>类型:" + "帖子" + "</div>" +
  614. "<div>发布时间:" + publishedAt + "</div>" +
  615. "<div class=\"gray\">描述:" + news.getString("summary").replace("\n", "&nbsp;&nbsp;&nbsp;&nbsp;") + "</div>";
  616. }
  617. SpringUtils.getBean(CoinServiceImpl.class).monitorAlarm4APP_TEXT_CARD(content, params, wxCpService4News);
  618. }
  619. }
  620. } catch (Exception e) {
  621. }
  622. }, 0, 3, TimeUnit.SECONDS);*/
  623. // 律动日报新闻快讯监控报警
  624. scheduler.scheduleWithFixedDelay(() -> {
  625. try {
  626. Map<String, String> paramMap = new HashMap<>();
  627. paramMap.put("size", "10");
  628. paramMap.put("page", "1");
  629. Connection.Response response = JsoupUtil.requestBody("https://api.theblockbeats.news/v1/open-api/open-flash", JsoupUtil.HTTP_GET, InitRunner.proxy, null, paramMap);
  630. JSONObject result = JSONObject.parseObject(response.body());
  631. JSONArray newsList = result.getJSONObject("data").getJSONArray("data");
  632. LocalDateTime endTime = LocalDateTime.now();
  633. for (int i = 0; i < newsList.size(); i++) {
  634. if (i == 5) {
  635. break;
  636. }
  637. JSONObject news = newsList.getJSONObject(i);
  638. String id = "BlockBeats" + news.getString("id");
  639. String createTime = news.getString("create_time");
  640. LocalDateTime createTimeTime = DateUtils.longToLocalDateTime_(Long.valueOf(createTime));
  641. createTime = DateUtils.localDateTimeToString(createTimeTime);
  642. if (Duration.between(createTimeTime, endTime).getSeconds() < 20 && !orderMap.containsKey(id)) {
  643. orderMap.put(id, "1");
  644. String title = news.getString("title");
  645. String content = news.getString("content");
  646. String pic = news.getString("pic");
  647. String link = news.getString("link");
  648. String url = news.getString("url");
  649. JSONObject params = new JSONObject();
  650. params.put("title", "BlockBeats监控报警");
  651. params.put("btnTxt", "新闻详情");
  652. params.put("logUrl", link);
  653. params.put("user", "@all");
  654. params.put("agentId", 1000004);
  655. if (StringUtils.isEmpty(pic)) {
  656. // 文本卡片
  657. String contentStr = "<div class=\"highlight\">标题:" + title + "</div>" +
  658. "<div>类型:" + "新闻快讯" + "</div>" +
  659. "<div>发布时间:" + createTime + "</div>" +
  660. "<div class=\"gray\">描述:" + content.replace("\n", "&nbsp;&nbsp;&nbsp;&nbsp;") + "</div>";
  661. if (title.contains("Upbit") || title.contains("upbit")) {
  662. JSONObject params4Upbit = new JSONObject();
  663. params4Upbit.put("title", "BlockBeats监控报警");
  664. params4Upbit.put("logUrl", link);
  665. params4Upbit.put("btnTxt", "新闻详情");
  666. SpringUtils.getBean(CoinServiceImpl.class).monitorAlarm4APP_TEXT_CARD(contentStr, params4Upbit, null);
  667. }
  668. SpringUtils.getBean(CoinServiceImpl.class).monitorAlarm4APP_TEXT_CARD(contentStr, params, wxCpService4News);
  669. } else {
  670. // 图文
  671. NewArticle article1 = new NewArticle();
  672. article1.setUrl(link);
  673. article1.setPicUrl(pic);
  674. article1.setDescription(content);
  675. article1.setTitle(title);
  676. if (title.contains("Upbit") || title.contains("upbit")) {
  677. JSONObject params4Upbit = new JSONObject();
  678. params4Upbit.put("title", "BlockBeats监控报警");
  679. params4Upbit.put("logUrl", link);
  680. params4Upbit.put("btnTxt", "新闻详情");
  681. SpringUtils.getBean(CoinServiceImpl.class).monitorAlarm4NEWS(params4Upbit, null, article1);
  682. }
  683. SpringUtils.getBean(CoinServiceImpl.class).monitorAlarm4NEWS(params, wxCpService4News, article1);
  684. }
  685. }
  686. }
  687. } catch (Exception e) {
  688. }
  689. }, 0, 3, TimeUnit.SECONDS);
  690. // coingecko
  691. scheduler.scheduleAtFixedRate(() -> {
  692. Map<String, Object> params = new HashMap<>();
  693. params.put("sortField", "create_time");
  694. params.put("sort", "desc");
  695. List<CoinWatchlist> watchlistList = coinMapper.findWatchlistList(params);
  696. Map<String, CoinWatchlist> coinWatchlistMap4CoingeckoId = watchlistList.stream().collect(Collectors.toMap(CoinWatchlist::getCoingeckoId, coinWatchlist -> coinWatchlist));
  697. parseWatchlistMap4Coingecko(coinWatchlistMap4CoingeckoId);
  698. Map<Long, CoinWatchlist> coinWatchlistMap4CmcId = coinWatchlistMap4CoingeckoId.values().stream().collect(Collectors.toMap(CoinWatchlist::getCmcId, coinWatchlist -> coinWatchlist));
  699. parseWatchlistMap4CmC(coinWatchlistMap4CmcId);
  700. }, 0, 1, TimeUnit.HOURS);
  701. // Upbit交易所监控报警
  702. scheduler.scheduleWithFixedDelay(() -> {
  703. try {
  704. Map<String, String> paramMap = new HashMap<>();
  705. paramMap.put("page", "1");
  706. paramMap.put("per_page", "20");
  707. paramMap.put("thread_name", "general");
  708. Connection.Response response = JsoupUtil.requestBody("https://api-manager.upbit.com/api/v1/notices", JsoupUtil.HTTP_GET, InitRunner.proxy, null, paramMap);
  709. JSONObject result = JSONObject.parseObject(response.body());
  710. JSONArray noticeList = result.getJSONObject("data").getJSONArray("list");
  711. for (int i = 0; i < noticeList.size(); i++) {
  712. if (i == 5) {
  713. break;
  714. }
  715. JSONObject notice = noticeList.getJSONObject(i);
  716. String idOri = notice.getString("id");
  717. String id = "Upbit" + idOri;
  718. String title = notice.getString("title");
  719. if (title.contains("New digital asset on KRW Market") && !orderMap.containsKey(id)) {
  720. orderMap.put(id, "1");
  721. String createTime = notice.getString("created_at");
  722. String updateTime = notice.getString("updated_at");
  723. String viewCount = notice.getString("view_count");
  724. JSONObject params = new JSONObject();
  725. params.put("title", "Upbit监控报警");
  726. params.put("btnTxt", "通知详情");
  727. params.put("logUrl", "https://sg-api-manager.upbit.com/api/v1/notices/" + idOri);
  728. // 文本卡片
  729. String contentStr = "<div class=\"highlight\">标题:" + title + "</div>" +
  730. "<div>发布时间:" + createTime + "</div>" +
  731. "<div>更新时间:" + updateTime + "</div>" +
  732. "<div class=\"gray\">查看次数:" + viewCount + "</div>";
  733. SpringUtils.getBean(CoinServiceImpl.class).monitorAlarm4APP_TEXT_CARD(contentStr, params, null);
  734. }
  735. }
  736. } catch (Exception e) {
  737. }
  738. }, 0, 3, TimeUnit.SECONDS);
  739. return null;
  740. }
  741. public void parseWatchlistMap4Coingecko(Map<String, CoinWatchlist> watchlistMap4Coingecko) {
  742. String coingeckoCoinsMarketsUrl = InitRunner.dicCodeMap.get("coingecko_coins_markets_url").getCodeValue();
  743. Map<String, String> headerMap = new HashMap<>();
  744. headerMap.put("Accept", "application/json");
  745. headerMap.put("Accept-Encoding", "deflate,gzip");
  746. Map<String, String> paramMap = new LinkedHashMap<>();
  747. paramMap.put("ids", StringUtils.join(watchlistMap4Coingecko.keySet(), ","));
  748. paramMap.put("vs_currency", "usd");
  749. AtomicInteger i = new AtomicInteger();
  750. try {
  751. Connection.Response response = JsoupUtil.requestBody(coingeckoCoinsMarketsUrl, JsoupUtil.HTTP_GET, InitRunner.proxy, headerMap, paramMap);
  752. JSONArray result = JSONArray.parseArray(response.body());
  753. for (int j = 0; j < result.size(); j++) {
  754. JSONObject marketData = result.getJSONObject(j);
  755. String id = marketData.getString("id");
  756. if (watchlistMap4Coingecko.containsKey(id)) {
  757. CoinWatchlist coinWatchlist = watchlistMap4Coingecko.get(id);
  758. // 总市值排名
  759. if (marketData.containsKey("market_cap_rank") && null != marketData.get("market_cap_rank")) {
  760. Integer totalMarketRanking = marketData.getInteger("market_cap_rank");
  761. coinWatchlist.setTotalMarketRanking(totalMarketRanking);
  762. }
  763. // 总市值
  764. if (marketData.containsKey("market_cap") && null != marketData.get("market_cap")) {
  765. BigDecimal totalMarketValue = marketData.getBigDecimal("market_cap").setScale(2, RoundingMode.HALF_UP);
  766. coinWatchlist.setTotalMarketValue(totalMarketValue);
  767. }
  768. // 市场价格
  769. if (marketData.containsKey("current_price") && null != marketData.get("current_price")) {
  770. String markPrice = marketData.getBigDecimal("current_price").toPlainString();
  771. coinWatchlist.setMarkPrice(markPrice);
  772. }
  773. // 历史最高价格
  774. if (marketData.containsKey("ath") && null != marketData.get("ath")) {
  775. String highestHistoricalPrice = marketData.getBigDecimal("ath").toPlainString();
  776. coinWatchlist.setHighestHistoricalPrice(highestHistoricalPrice);
  777. }
  778. // 历史最高日期
  779. if (marketData.containsKey("ath_date") && null != marketData.get("ath_date")) {
  780. LocalDate highestHistoricalDate = LocalDate.parse(marketData.getString("ath_date"), DateUtils.utcTimeFormatter);
  781. coinWatchlist.setHighestHistoricalDate(highestHistoricalDate);
  782. }
  783. // 历史最低价格
  784. if (marketData.containsKey("atl") && null != marketData.get("atl")) {
  785. String lowestHistoricalPrice = marketData.getBigDecimal("atl").toPlainString();
  786. coinWatchlist.setLowestHistoricalPrice(lowestHistoricalPrice);
  787. }
  788. // 历史最低日期
  789. if (marketData.containsKey("atl_date") && null != marketData.get("atl_date")) {
  790. LocalDate lowestHistoricalDate = LocalDate.parse(marketData.getString("atl_date"), DateUtils.utcTimeFormatter);
  791. coinWatchlist.setLowestHistoricalDate(lowestHistoricalDate);
  792. }
  793. // 涨幅倍数
  794. if (StringUtils.isNotEmpty(coinWatchlist.getHighestHistoricalPrice()) && StringUtils.isNotEmpty(coinWatchlist.getLowestHistoricalPrice())) {
  795. BigDecimal increaseMultiple = new BigDecimal(coinWatchlist.getHighestHistoricalPrice()).divide(new BigDecimal(coinWatchlist.getLowestHistoricalPrice()), 0, RoundingMode.HALF_UP);
  796. coinWatchlist.setIncreaseMultiple(increaseMultiple.intValue());
  797. }
  798. // 发行日期
  799. // 发行天数
  800. if (coinWatchlist.getIssuingDate() != null) {
  801. long totalDays = ChronoUnit.DAYS.between(coinWatchlist.getIssuingDate(), LocalDate.now());
  802. coinWatchlist.setIssuingDays((int) totalDays);
  803. }
  804. coinMapper.updateCoinWatchlist(coinWatchlist);
  805. }
  806. }
  807. } catch (Exception e) {
  808. log.error("parseWatchlistMap4Coingecko error,size={},i={}", watchlistMap4Coingecko.size(), i.get(), e);
  809. }
  810. }
  811. public void parseWatchlistMap4CmC(Map<Long, CoinWatchlist> watchlistMap4CmC) {
  812. String coinmarketcapApikey = InitRunner.dicCodeMap.get("coinmarketcap_apikey").getCodeValue();
  813. String coinmarketcapQuotesLatestUrl = InitRunner.dicCodeMap.get("coinmarketcap_quotes_latest_url").getCodeValue();
  814. Map<String, String> headerMap = new HashMap<>();
  815. headerMap.put("Accept", "application/json");
  816. headerMap.put("Accept-Encoding", "deflate,gzip");
  817. headerMap.put("X-CMC_PRO_API_KEY", coinmarketcapApikey);
  818. Map<String, String> paramMap = new LinkedHashMap<>();
  819. paramMap.put("id", StringUtils.join(watchlistMap4CmC.keySet(), ","));
  820. AtomicInteger i = new AtomicInteger();
  821. try {
  822. Connection.Response response = JsoupUtil.requestBody(coinmarketcapQuotesLatestUrl, JsoupUtil.HTTP_GET, InitRunner.proxy, headerMap, paramMap);
  823. JSONObject result = JSONObject.parseObject(response.body());
  824. JSONObject dataJO = result.getJSONObject("data");
  825. watchlistMap4CmC.forEach((key, value) -> {
  826. i.getAndIncrement();
  827. if (dataJO.containsKey(key)) {
  828. JSONObject jsonObject = dataJO.getJSONObject(String.valueOf(key));
  829. value.setTotalMarketRanking(jsonObject.getInteger("cmc_rank"));
  830. BigDecimal totalMarketValue = jsonObject.getJSONObject("quote").getJSONObject("USD").getBigDecimal("market_cap").setScale(2, RoundingMode.HALF_UP);
  831. if (totalMarketValue.compareTo(BigDecimal.ZERO) == 0) {
  832. totalMarketValue = jsonObject.getBigDecimal("self_reported_market_cap").setScale(2, RoundingMode.HALF_UP);
  833. }
  834. value.setTotalMarketValue(totalMarketValue);
  835. coinMapper.updateCoinWatchlist(value);
  836. }
  837. });
  838. } catch (Exception e) {
  839. log.error("parseWatchlistMap4CmC error,size={},i={}", watchlistMap4CmC.size(), i.get(), e);
  840. }
  841. }
  842. @Override
  843. @Async("coinTaskExecutor")
  844. public void monitorAlarm4APP_TEXT_CARD(String content, JSONObject params, WxCpService wxCpServiceFinal) {
  845. // 文本卡片模式发消息
  846. String title = "监控告警明细";
  847. if (params.containsKey("title")) {
  848. title = params.getString("title");
  849. }
  850. String logUrl = "https://lvzhiqiang.top";
  851. if (params.containsKey("logUrl")) {
  852. logUrl = params.getString("logUrl");
  853. }
  854. String btnTxt = "日志详情";
  855. if (params.containsKey("btnTxt")) {
  856. btnTxt = params.getString("btnTxt");
  857. }
  858. String user = "LvZhiQiang";
  859. if (params.containsKey("user")) {
  860. user = params.getString("user");
  861. }
  862. String party = "";
  863. if (params.containsKey("party")) {
  864. party = params.getString("party");
  865. }
  866. String tag = "";
  867. if (params.containsKey("tag")) {
  868. tag = params.getString("tag");
  869. }
  870. Integer agentId = properties.getAgentId();
  871. if (params.containsKey("agentId")) {
  872. agentId = params.getInteger("agentId");
  873. }
  874. if (wxCpServiceFinal == null) {
  875. wxCpServiceFinal = wxCpService;
  876. }
  877. WxCpMessage wxCpMessage = WxCpMessage.TEXTCARD().agentId(agentId)
  878. .toUser(user)
  879. .toParty(party)
  880. .toTag(tag)
  881. .title(title).description(content)
  882. .url(logUrl).btnTxt(btnTxt)
  883. .build();
  884. try {
  885. log.info("企业微信推送消息,send message: {}", wxCpMessage);
  886. WxCpMessageSendResult sendResult = wxCpServiceFinal.getMessageService().send(wxCpMessage);
  887. log.info("企业微信推送消息成功,send result: {}", sendResult);
  888. } catch (WxErrorException e) {
  889. log.error("企业微信推送消息失败!Detail: ", e);
  890. }
  891. }
  892. @Override
  893. @Async("coinTaskExecutor")
  894. public void monitorAlarm4NEWS(JSONObject params, WxCpService wxCpServiceFinal, NewArticle... articles) {
  895. // 图文消息
  896. String title = "监控告警明细";
  897. if (params.containsKey("title")) {
  898. title = params.getString("title");
  899. }
  900. String logUrl = "https://lvzhiqiang.top";
  901. if (params.containsKey("logUrl")) {
  902. logUrl = params.getString("logUrl");
  903. }
  904. String btnTxt = "日志详情";
  905. if (params.containsKey("btnTxt")) {
  906. btnTxt = params.getString("btnTxt");
  907. }
  908. String user = "LvZhiQiang";
  909. if (params.containsKey("user")) {
  910. user = params.getString("user");
  911. }
  912. String party = "";
  913. if (params.containsKey("party")) {
  914. party = params.getString("party");
  915. }
  916. String tag = "";
  917. if (params.containsKey("tag")) {
  918. tag = params.getString("tag");
  919. }
  920. Integer agentId = properties.getAgentId();
  921. if (params.containsKey("agentId")) {
  922. agentId = params.getInteger("agentId");
  923. }
  924. if (wxCpServiceFinal == null) {
  925. wxCpServiceFinal = wxCpService;
  926. }
  927. WxCpMessage wxCpMessage = WxCpMessage.NEWS().agentId(agentId)
  928. .toUser(user)
  929. .toParty(party)
  930. .toTag(tag)
  931. .addArticle(articles)
  932. .build();
  933. try {
  934. log.info("企业微信推送消息,send message: {}", wxCpMessage);
  935. WxCpMessageSendResult sendResult = wxCpServiceFinal.getMessageService().send(wxCpMessage);
  936. log.info("企业微信推送消息成功,send result: {}", sendResult);
  937. } catch (WxErrorException e) {
  938. log.error("企业微信推送消息失败!Detail: ", e);
  939. }
  940. }
  941. @Override
  942. @Async("coinTaskExecutor")
  943. public void monitorAlarm4CHAT_BOT(String content, JSONObject params) {
  944. // 调用企业微信群聊机器人发消息
  945. WxCpGroupRobotService groupRobotService = wxCpService.getGroupRobotService();
  946. String webhookUrl = "https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=082970da-2a33-422a-81f6-15f9bde87940";
  947. List<String> userList = Collections.singletonList("LvZhiQiang");
  948. if (params != null && params.containsKey("user")) {
  949. userList = Arrays.asList(params.getString("user").split("[|,]"));
  950. }
  951. try {
  952. log.info("企业微信推送消息,send content: {}, userIdSet: {}", content, userList);
  953. groupRobotService.sendText(webhookUrl, content, userList, Collections.emptyList());
  954. log.info("企业微信推送消息成功");
  955. } catch (WxErrorException e) {
  956. log.error("企业微信推送消息失败!Detail: ", e);
  957. }
  958. }
  959. @Override
  960. @Async("coinTaskExecutor")
  961. public void monitorAlarm(String content, String jobAlarmMode) {
  962. // 判断告警模式
  963. if (StringUtils.isEmpty(JOB_ALARM_MODE)) {
  964. jobAlarmMode = JOB_ALARM_MODE;
  965. }
  966. // 文本卡片模式发消息
  967. if (JOB_ALARM_MODE_APP_TEXT_CARD.equals(jobAlarmMode)) {
  968. String title = "监控告警明细";
  969. String logUrl = "https://lvzhiqiang.top";
  970. String btnTxt = "日志详情";
  971. WxCpMessage wxCpMessage = WxCpMessage.TEXTCARD().agentId(properties.getAgentId())
  972. .toUser("LvZhiQiang")
  973. .toParty("")
  974. .toTag("")
  975. .title(title).description(content)
  976. .url(logUrl).btnTxt(btnTxt)
  977. .build();
  978. try {
  979. log.info("企业微信推送消息,send message: {}", wxCpMessage);
  980. WxCpMessageSendResult sendResult = wxCpService.getMessageService().send(wxCpMessage);
  981. log.info("企业微信推送消息成功,send result: {}", sendResult);
  982. } catch (WxErrorException e) {
  983. log.error("企业微信推送消息失败!Detail: ", e);
  984. }
  985. }
  986. // 调用企业微信群聊机器人发消息
  987. if (JOB_ALARM_MODE_CHAT_BOT.equals(jobAlarmMode)) {
  988. WxCpGroupRobotService groupRobotService = wxCpService.getGroupRobotService();
  989. String webhookUrl = "https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=082970da-2a33-422a-81f6-15f9bde87940";
  990. try {
  991. log.info("企业微信推送消息,send content: {}, userIdSet: {}", content, "LvZhiQiang");
  992. groupRobotService.sendText(webhookUrl, content, Collections.singletonList("LvZhiQiang"), Collections.emptyList());
  993. log.info("企业微信推送消息成功");
  994. } catch (WxErrorException e) {
  995. log.error("企业微信推送消息失败!Detail: ", e);
  996. }
  997. }
  998. }
  999. /**
  1000. * 请求通用API方法
  1001. */
  1002. private JSONObject requestApi4Common(String requestPath, String signQueryString, String signBody, String httpMethod, Map<String, String> paramMap) {
  1003. String timestamp = String.valueOf(System.currentTimeMillis());
  1004. Map<String, String> headerMap = new HashMap<>();
  1005. headerMap.putAll(basicHeaderMap);
  1006. try {
  1007. String accessSign = CheckSign4Bitget.generate(timestamp, httpMethod, requestPath, signQueryString, signBody, secretKey);
  1008. headerMap.put("ACCESS-TIMESTAMP", timestamp);
  1009. headerMap.put("ACCESS-SIGN", accessSign);
  1010. } catch (CloneNotSupportedException e) {
  1011. throw new RuntimeException(e);
  1012. } catch (InvalidKeyException e) {
  1013. throw new RuntimeException(e);
  1014. } catch (UnsupportedEncodingException e) {
  1015. throw new RuntimeException(e);
  1016. }
  1017. try {
  1018. String requestUrl = mainUrl + requestPath;
  1019. if (httpMethod.equals(JsoupUtil.HTTP_GET)) {
  1020. Connection.Response response = JsoupUtil.requestBody(requestUrl, httpMethod, InitRunner.proxy, headerMap, paramMap);
  1021. return JSONObject.parseObject(response.body());
  1022. } else {
  1023. Connection.Response response = JsoupUtil.requestBodyJSON(requestUrl, httpMethod, InitRunner.proxy, null, headerMap, paramMap);
  1024. return JSONObject.parseObject(response.body());
  1025. }
  1026. } catch (Exception e) {
  1027. throw new RuntimeException(e);
  1028. }
  1029. }
  1030. private JSONObject requestApi4Common4OKX(String requestPath, String signQueryString, String signBody, String httpMethod, Map<String, String> paramMap) {
  1031. String timestamp = DateUtils.getUTCTimeStr();
  1032. Map<String, String> headerMap = new HashMap<>();
  1033. headerMap.putAll(basicHeaderMap4OKX);
  1034. try {
  1035. String accessSign = CheckSign4OKX.generate(timestamp, httpMethod, requestPath, signQueryString, signBody, secretKey4OKX);
  1036. headerMap.put("OK-ACCESS-TIMESTAMP", timestamp);
  1037. headerMap.put("OK-ACCESS-SIGN", accessSign);
  1038. } catch (CloneNotSupportedException e) {
  1039. throw new RuntimeException(e);
  1040. } catch (InvalidKeyException e) {
  1041. throw new RuntimeException(e);
  1042. } catch (UnsupportedEncodingException e) {
  1043. throw new RuntimeException(e);
  1044. }
  1045. try {
  1046. String requestUrl = "https://www.okx.com" + requestPath;
  1047. if (httpMethod.equals(JsoupUtil.HTTP_GET)) {
  1048. Connection.Response response = JsoupUtil.requestBody(requestUrl, httpMethod, InitRunner.proxy, headerMap, paramMap);
  1049. return JSONObject.parseObject(response.body());
  1050. } else {
  1051. Connection.Response response = JsoupUtil.requestBodyJSON(requestUrl, httpMethod, InitRunner.proxy, null, headerMap, paramMap);
  1052. return JSONObject.parseObject(response.body());
  1053. }
  1054. } catch (Exception e) {
  1055. throw new RuntimeException(e);
  1056. }
  1057. }
  1058. @Override
  1059. public Object mainSearch(JSONObject params) throws Exception {
  1060. JSONArray result = new JSONArray();
  1061. if (params.getString("nameEn").equals("allPositionv2")) {
  1062. Map<String, String> paramMap = new HashMap<>();
  1063. paramMap.put("productType", "umcbl");
  1064. String signQueryString = paramMap.entrySet().stream().map(e -> e.getKey() + "=" + e.getValue()).collect(Collectors.joining("&"));
  1065. JSONObject response = requestApi4Common(params.getString("url"), signQueryString, null, JsoupUtil.HTTP_GET, paramMap);
  1066. result = response.getJSONArray("data");
  1067. renderMainSearch4AllPositionv2(result, params.getInteger("unrealizedPLSort"));
  1068. } else if (params.getString("nameEn").equals("orderMarginCoinCurrent")) {
  1069. Map<String, String> paramMap = new LinkedHashMap<>();
  1070. paramMap.put("productType", "umcbl");
  1071. paramMap.put("marginCoin", "USDT");
  1072. String signQueryString = paramMap.entrySet().stream().map(e -> e.getKey() + "=" + e.getValue()).collect(Collectors.joining("&"));
  1073. JSONObject response = requestApi4Common(params.getString("url"), signQueryString, null, JsoupUtil.HTTP_GET, paramMap);
  1074. result = response.getJSONArray("data");
  1075. renderMainSearch4OrderMarginCoinCurrent(result, params.getInteger("chaRateSort"));
  1076. } else if (params.getString("nameEn").equals("orderHistoryProductType")) {
  1077. PageHelper.startPage(params.getInteger("pageNo"), params.getInteger("pageSize"), true);
  1078. List<CoinHistoryOrder> historyOrderList = coinMapper.findHistoryOrderList(params.toJavaObject(Map.class));
  1079. PageInfo<CoinHistoryOrder> historyOrderPageInfo = new PageInfo<>(historyOrderList);
  1080. renderMainSearch4OrderHistoryProductType(historyOrderList);
  1081. //result = (JSONArray) JSON.toJSON(historyOrderList);
  1082. return historyOrderPageInfo;
  1083. } else if (params.getString("nameEn").equals("traderList")) {
  1084. PageHelper.startPage(params.getInteger("pageNo"), params.getInteger("pageSize"), true);
  1085. List<CoinTrader> mixTraderList = coinMapper.findMixTraderList(params.toJavaObject(Map.class));
  1086. PageInfo<CoinTrader> coinTraderPageInfo = new PageInfo<>(mixTraderList);
  1087. renderMainSearch4TraderList(mixTraderList);
  1088. //result = (JSONArray) JSON.toJSON(mixTraderList);
  1089. return coinTraderPageInfo;
  1090. } else if (params.getString("nameEn").equals("watchlist")) {
  1091. PageHelper.startPage(params.getInteger("pageNo"), params.getInteger("pageSize"), true);
  1092. List<CoinWatchlist> watchlistList = coinMapper.findWatchlistList(params.toJavaObject(Map.class));
  1093. PageInfo<CoinWatchlist> watchlistPageInfo = new PageInfo<>(watchlistList);
  1094. renderMainSearch4Watchlist(watchlistList);
  1095. return watchlistPageInfo;
  1096. } else if (params.getString("nameEn").equals("image")) {
  1097. PageHelper.startPage(params.getInteger("pageNo"), params.getInteger("pageSize"), true);
  1098. List<FileImage> fileImageList = coinMapper.findImageList(params.toJavaObject(Map.class));
  1099. PageInfo<FileImage> imagePageInfo = new PageInfo<>(fileImageList);
  1100. renderMainSearch4Image(fileImageList);
  1101. return imagePageInfo;
  1102. } else if (params.getString("nameEn").equals("cmcmap")) {
  1103. PageHelper.startPage(params.getInteger("pageNo"), params.getInteger("pageSize"), true);
  1104. List<CoinCmcMap> cmcMapList = coinMapper.findCmcMapList(params.toJavaObject(Map.class));
  1105. PageInfo<CoinCmcMap> cmcMapPageInfo = new PageInfo<>(cmcMapList);
  1106. renderMainSearch4CmcMap(cmcMapList);
  1107. return cmcMapPageInfo;
  1108. }else if (params.getString("nameEn").equals("monitorCurrency")) {
  1109. List<CoinMonitorCurrency> monitorCurrencyList = coinMapper.findMonitorCurrencyList();
  1110. Map<String, JSONArray> resultMulti = new ConcurrentHashMap<>();
  1111. Arrays.stream(params.getString("url").split(",")).parallel().forEach(e -> {
  1112. String requestUrl = mainUrl + e;
  1113. try {
  1114. Connection.Response response = JsoupUtil.requestBody(requestUrl, JsoupUtil.HTTP_GET, InitRunner.proxy, null, null);
  1115. resultMulti.put(e, JSONObject.parseObject(response.body()).getJSONArray("data"));
  1116. } catch (Exception ex) {
  1117. throw new RuntimeException(ex);
  1118. }
  1119. });
  1120. result = renderMainSearch4MonitorCurrency(resultMulti, monitorCurrencyList, params.getInteger("changeUtcSort"));
  1121. } else if (params.getString("nameEn").equals("currentPlan")) {
  1122. Map<String, String> paramMap = new LinkedHashMap<>();
  1123. paramMap.put("productType", "umcbl");
  1124. paramMap.put("isPlan", "plan");
  1125. String signQueryString = paramMap.entrySet().stream().map(e -> e.getKey() + "=" + e.getValue()).collect(Collectors.joining("&"));
  1126. JSONObject response = requestApi4Common(params.getString("url"), signQueryString, null, JsoupUtil.HTTP_GET, paramMap);
  1127. result = response.getJSONArray("data");
  1128. renderMainSearch4CurrentPlan(result, params.getInteger("chaRateSort"));
  1129. }
  1130. return result;
  1131. }
  1132. private void renderMainSearch4CmcMap(List<CoinCmcMap> cmcMapList) {
  1133. for (CoinCmcMap coinCmcMap : cmcMapList) {
  1134. String platform = coinCmcMap.getPlatform();
  1135. if (StringUtils.isNotEmpty(platform)) {
  1136. JSONObject jsonObject = JSONObject.parseObject(platform);
  1137. jsonObject.remove("token_address");
  1138. coinCmcMap.setPlatform(jsonObject.toJSONString());
  1139. }
  1140. }
  1141. }
  1142. private void renderMainSearch4Image(List<FileImage> fileImageList) {
  1143. for (FileImage fileImage : fileImageList) {
  1144. String newPath = "<a target=\"_blank\" href=\" " + fileImage.getPath() + "\">" + fileImage.getPath() + "</a>";
  1145. fileImage.setPath(newPath);
  1146. }
  1147. }
  1148. private void renderMainSearch4Watchlist(List<CoinWatchlist> watchlistList) {
  1149. BigDecimal bigDecimal10000 = new BigDecimal("10000");
  1150. List<String> trackCategoryList = coinApiConfigMapper.findTrackCategoryList();
  1151. Map<String, String> trackCategoryMap = new HashMap<>();
  1152. List<String> colorList = coinApiConfigMapper.findColorStyleList();
  1153. int j = 0;
  1154. for (int i = 0; i < trackCategoryList.size(); i++) {
  1155. if (j > colorList.size() - 1) {
  1156. j = 0;
  1157. }
  1158. trackCategoryMap.put(trackCategoryList.get(i), colorList.get(j));
  1159. j++;
  1160. }
  1161. for (CoinWatchlist coinWatchlist : watchlistList) {
  1162. if (null != coinWatchlist.getTotalMarketValue()) {
  1163. BigDecimal divide = coinWatchlist.getTotalMarketValue().divide(bigDecimal10000, 8, RoundingMode.HALF_UP);
  1164. if (divide.compareTo(bigDecimal10000) <= 0) {
  1165. coinWatchlist.setTotalMarketValueStr(divide.setScale(4, RoundingMode.HALF_UP) + "万");
  1166. } else {
  1167. divide = divide.divide(bigDecimal10000, 4, RoundingMode.HALF_UP);
  1168. coinWatchlist.setTotalMarketValueStr(divide + "亿");
  1169. }
  1170. }
  1171. // 赛道分类
  1172. String[] trackCategoryArr = coinWatchlist.getTrackCategory().split(",");
  1173. StringBuffer sb = new StringBuffer();
  1174. for (int i = 0; i < trackCategoryArr.length; i++) {
  1175. if (i == trackCategoryArr.length - 1) {
  1176. sb.append("<span class=\"selected-value\" style=\"" + trackCategoryMap.get(trackCategoryArr[i]) + " \" >" + trackCategoryArr[i] + " </span>");
  1177. } else {
  1178. sb.append("<span class=\"selected-value\" style=\"margin-right:0.3em;" + trackCategoryMap.get(trackCategoryArr[i]) + " \" >" + trackCategoryArr[i] + " </span>");
  1179. }
  1180. }
  1181. coinWatchlist.setTrackCategoryStyle(" style=\"padding:0em 0.3em;\"");
  1182. coinWatchlist.setTrackCategory(sb.toString());
  1183. // 名称
  1184. coinWatchlist.setSymbolStyle(" style=\"background-color:rgba(70,169,244,.72);font-weight: bold;\"");
  1185. }
  1186. }
  1187. private void renderMainSearch4TraderList(List<CoinTrader> mixTraderList) {
  1188. for (CoinTrader mixTrader : mixTraderList) {
  1189. mixTrader.setLastTradeTime(DateUtils.longToString(Long.valueOf(mixTrader.getLastTradeTime())));
  1190. }
  1191. }
  1192. /**
  1193. * 渲染获取当前计划委托(止盈止损)列表
  1194. *
  1195. * @param result
  1196. */
  1197. private void renderMainSearch4CurrentPlan(JSONArray result, Integer chaRateSort) {
  1198. forkJoinPool3.submit(() -> result.parallelStream().forEach(e -> {
  1199. JSONObject jsonObject = (JSONObject) e;
  1200. // 币对名称
  1201. String symbol = jsonObject.getString("symbol");
  1202. jsonObject.put("symbol", "<strong style=\"background-color:#F1B90d;\"><font color=\"#242A30\">" + symbol.replace("USDT_UMCBL", "") + "</font></strong>USDT_UMCBL");
  1203. // 订单状态
  1204. jsonObject.put("status", InitRunner.publicParamsMap.get("status").getString(jsonObject.getString("status")));
  1205. // 交易类型
  1206. jsonObject.put("orderType", InitRunner.publicParamsMap.get("orderType").getString(jsonObject.getString("orderType")));
  1207. // 订单类型
  1208. jsonObject.put("planType", InitRunner.publicParamsMap.get("planType").getString(jsonObject.getString("planType")));
  1209. // 开单方向
  1210. String side = jsonObject.getString("side");
  1211. jsonObject.put("side", InitRunner.publicParamsMap.get("side").getString(side));
  1212. if (side.equals("open_long")) {
  1213. jsonObject.put("sideStyle", " style=\"color:#FFFFFF;background-color:#1DA2B4;\"");
  1214. } else if (side.equals("open_short")) {
  1215. jsonObject.put("sideStyle", " style=\"color:#FFFFFF;background-color:#F1493F;\"");
  1216. } else {
  1217. jsonObject.put("sideStyle", " style=\"color:#FFFFFF;background-color:#F0F0F0;\"");
  1218. }
  1219. // 触发类型
  1220. jsonObject.put("triggerType", InitRunner.publicParamsMap.get("triggerType").getString(jsonObject.getString("triggerType")));
  1221. jsonObject.put("cTime", DateUtils.longToString(jsonObject.getLong("cTime")));
  1222. jsonObject.put("uTime", StringUtils.isEmpty(jsonObject.getString("uTime")) ? "--" : DateUtils.longToString(jsonObject.getLong("uTime")));
  1223. // 获取合约标记价格
  1224. String requestUrl = mainUrl + "/api/mix/v1/market/mark-price?symbol=" + symbol;
  1225. try {
  1226. Connection.Response response = JsoupUtil.requestBody(requestUrl, JsoupUtil.HTTP_GET, InitRunner.proxy, null, null);
  1227. String markPrice = JSONObject.parseObject(response.body()).getJSONObject("data").getString("markPrice");
  1228. BigDecimal chaRate = BigDecimal.ZERO;
  1229. BigDecimal triggerPriceDecimal = new BigDecimal(jsonObject.getString("triggerPrice"));
  1230. BigDecimal markPriceDecimal = new BigDecimal(markPrice);
  1231. if (markPriceDecimal.compareTo(triggerPriceDecimal) < 0) {
  1232. chaRate = markPriceDecimal.divide(triggerPriceDecimal, 4, RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(100)).setScale(2, RoundingMode.HALF_UP);
  1233. } else if (markPriceDecimal.compareTo(triggerPriceDecimal) > 0) {
  1234. chaRate = triggerPriceDecimal.divide(markPriceDecimal, 4, RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(100)).setScale(2, RoundingMode.HALF_UP);
  1235. }
  1236. jsonObject.put("markPrice", markPrice);
  1237. jsonObject.put("markPriceStyle", " style=\"color:#252B31;background-color:#C4ADE9;font-weight:bold;\"");
  1238. jsonObject.put("chaRate", chaRate);
  1239. jsonObject.put("chaRateStyle", " style=\"color:#FFFFFF;background-color:#5EA294;\"");
  1240. } catch (Exception ex) {
  1241. throw new RuntimeException(ex);
  1242. }
  1243. })).join();
  1244. if (chaRateSort != 0) {
  1245. Collections.sort(result, (o1, o2) -> chaRateSort * (((JSONObject) o1).getBigDecimal("chaRate").compareTo(((JSONObject) o2).getBigDecimal("chaRate"))));
  1246. }
  1247. }
  1248. /**
  1249. * 渲染获取监控币种列表
  1250. *
  1251. * @param monitorCurrencyList
  1252. */
  1253. private JSONArray renderMainSearch4MonitorCurrency(Map<String, JSONArray> resultMulti, List<CoinMonitorCurrency> monitorCurrencyList, Integer changeUtcSort) {
  1254. Map<String, CoinMonitorCurrency> monitorCurrencyMap4Mix = monitorCurrencyList.stream().filter(e -> e.getType().equals("2")).collect(Collectors.toMap(CoinMonitorCurrency::getSymbol, Function.identity(), (key1, key2) -> key1));
  1255. Set<String> symbolSet4Mix = monitorCurrencyMap4Mix.keySet();
  1256. Map<String, CoinMonitorCurrency> monitorCurrencyMap4Spot = monitorCurrencyList.stream().filter(e -> e.getType().contains("1")).collect(Collectors.toMap(CoinMonitorCurrency::getSymbol, Function.identity(), (key1, key2) -> key1));
  1257. Set<String> symbolSet4Spot = monitorCurrencyMap4Spot.keySet();
  1258. JSONArray array4Spot = resultMulti.get("/api/spot/v1/market/tickers").stream()
  1259. .filter(iter -> symbolSet4Spot.contains(((JSONObject) iter).getString("symbol")))
  1260. .collect(Collectors.toCollection(JSONArray::new));
  1261. JSONArray array4Mix = resultMulti.get("/api/mix/v1/market/tickers?productType=umcbl").stream()
  1262. .filter(iter -> symbolSet4Mix.contains(((JSONObject) iter).getString("symbol")))
  1263. .collect(Collectors.toCollection(JSONArray::new));
  1264. forkJoinPool.submit(() -> array4Spot.parallelStream().forEach(e -> {
  1265. JSONObject jsonObject = (JSONObject) e;
  1266. jsonObject.put("changeUtc", jsonObject.getBigDecimal("changeUtc").multiply(BigDecimal.valueOf(100)).setScale(2, RoundingMode.HALF_UP));
  1267. jsonObject.put("change", jsonObject.getBigDecimal("change").multiply(BigDecimal.valueOf(100)).setScale(2, RoundingMode.HALF_UP));
  1268. jsonObject.put("ts", DateUtils.longToString(jsonObject.getLong("ts")));
  1269. jsonObject.put("category", monitorCurrencyMap4Spot.get(jsonObject.getString("symbol")).getCategory());
  1270. // UTC0时涨跌幅
  1271. if (jsonObject.getBigDecimal("changeUtc").compareTo(BigDecimal.ZERO) < 0) {
  1272. jsonObject.put("changeUtcStyle", " style=\"color:#FFFFFF;background-color:#F1493F;\"");
  1273. } else {
  1274. jsonObject.put("changeUtcStyle", " style=\"color:#FFFFFF;background-color:#1DA2B4;\"");
  1275. }
  1276. // 24小时涨跌幅
  1277. if (jsonObject.getBigDecimal("change").compareTo(BigDecimal.ZERO) < 0) {
  1278. jsonObject.put("changeStyle", " style=\"color:#FFFFFF;background-color:#F1493F;\"");
  1279. } else {
  1280. jsonObject.put("changeStyle", " style=\"color:#FFFFFF;background-color:#1DA2B4;\"");
  1281. }
  1282. // 币对名称
  1283. String symbol = jsonObject.getString("symbol").replace("USDT", "");
  1284. if ("BTC".equals(symbol) || "ETH".equals(symbol)) {
  1285. jsonObject.put("symbol", "<strong style=\"background-color:#FF6EB4;\"><font color=\"#242A30\">" + symbol + "</font></strong>USDT");
  1286. } else {
  1287. jsonObject.put("symbol", "<strong style=\"background-color:#F1B90d;\"><font color=\"#242A30\">" + symbol + "</font></strong>USDT");
  1288. }
  1289. // 标记价格
  1290. jsonObject.put("closeStyle", " style=\"color:#252B31;background-color:#C4ADE9;font-weight:bold;\"");
  1291. // 基础币量 计价币量 usdt币量
  1292. jsonObject.put("baseVol", readableFileSize(jsonObject.getDouble("baseVol")));
  1293. jsonObject.put("quoteVol", readableFileSize(jsonObject.getDouble("quoteVol")));
  1294. jsonObject.put("usdtVol", readableFileSize(jsonObject.getDouble("usdtVol")));
  1295. })).join();
  1296. forkJoinPool.submit(() -> array4Mix.parallelStream().forEach(e -> {
  1297. JSONObject jsonObject = (JSONObject) e;
  1298. jsonObject.put("changeUtc", jsonObject.getBigDecimal("chgUtc").multiply(BigDecimal.valueOf(100)).setScale(2, RoundingMode.HALF_UP));
  1299. jsonObject.put("change", jsonObject.getBigDecimal("priceChangePercent").multiply(BigDecimal.valueOf(100)).setScale(2, RoundingMode.HALF_UP));
  1300. jsonObject.put("ts", DateUtils.longToString(jsonObject.getLong("timestamp")));
  1301. jsonObject.put("category", monitorCurrencyMap4Mix.get(jsonObject.getString("symbol")).getCategory());
  1302. // UTC0时涨跌幅
  1303. if (jsonObject.getBigDecimal("changeUtc").compareTo(BigDecimal.ZERO) < 0) {
  1304. jsonObject.put("changeUtcStyle", " style=\"color:#FFFFFF;background-color:#F1493F;\"");
  1305. } else {
  1306. jsonObject.put("changeUtcStyle", " style=\"color:#FFFFFF;background-color:#1DA2B4;\"");
  1307. }
  1308. // 24小时涨跌幅
  1309. if (jsonObject.getBigDecimal("change").compareTo(BigDecimal.ZERO) < 0) {
  1310. jsonObject.put("changeStyle", " style=\"color:#FFFFFF;background-color:#F1493F;\"");
  1311. } else {
  1312. jsonObject.put("changeStyle", " style=\"color:#FFFFFF;background-color:#1DA2B4;\"");
  1313. }
  1314. // 币对名称
  1315. String symbol = jsonObject.getString("symbol").replace("USDT_UMCBL", "");
  1316. jsonObject.put("symbol", "<strong style=\"background-color:#F1B90d;\"><font color=\"#242A30\">" + symbol + "</font></strong>USDT_UMCBL");
  1317. // 标记价格
  1318. jsonObject.put("close",jsonObject.getString("last"));
  1319. jsonObject.put("closeStyle", " style=\"color:#252B31;background-color:#C4ADE9;font-weight:bold;\"");
  1320. // 基础币量 计价币量 usdt币量
  1321. jsonObject.put("baseVol", readableFileSize(jsonObject.getDouble("baseVolume")));
  1322. jsonObject.put("quoteVol", readableFileSize(jsonObject.getDouble("quoteVolume")));
  1323. jsonObject.put("usdtVol", readableFileSize(jsonObject.getDouble("quoteVolume")));
  1324. // 其他字段兼容
  1325. jsonObject.put("openUtc0",jsonObject.getString("openUtc"));
  1326. jsonObject.put("buyOne",jsonObject.getString("bestBid"));
  1327. jsonObject.put("sellOne",jsonObject.getString("bestAsk"));
  1328. })).join();
  1329. array4Spot.addAll(array4Mix);
  1330. if (changeUtcSort != 0) {
  1331. Collections.sort(array4Spot, (o1, o2) -> changeUtcSort * (((JSONObject) o1).getBigDecimal("changeUtc").compareTo(((JSONObject) o2).getBigDecimal("changeUtc"))));
  1332. }
  1333. return array4Spot;
  1334. }
  1335. /**
  1336. * 渲染获取全部历史委托
  1337. *
  1338. * @param historyOrderList
  1339. */
  1340. private void renderMainSearch4OrderHistoryProductType(List<CoinHistoryOrder> historyOrderList) {
  1341. for (CoinHistoryOrder coinHistoryOrder : historyOrderList) {
  1342. // 币种名称
  1343. coinHistoryOrder.setSymbol(coinHistoryOrder.getSymbol().replace("USDT_UMCBL", ""));
  1344. // 订单状态
  1345. coinHistoryOrder.setState(InitRunner.publicParamsMap.get("state").getString(coinHistoryOrder.getState()));
  1346. // 开单方向
  1347. coinHistoryOrder.setSide(InitRunner.publicParamsMap.get("side").getString(coinHistoryOrder.getSide()));
  1348. // 总盈亏
  1349. String TotalProfits = "0E-8";
  1350. if (!coinHistoryOrder.getTotalProfits().contains("0E-8")) {
  1351. TotalProfits = new BigDecimal(coinHistoryOrder.getTotalProfits()).setScale(2, RoundingMode.HALF_UP).toPlainString();
  1352. }
  1353. coinHistoryOrder.setTotalProfits(TotalProfits);
  1354. // 手续费
  1355. String fee = "0E-8";
  1356. if (!coinHistoryOrder.getFee().contains("0E-8")) {
  1357. fee = new BigDecimal(coinHistoryOrder.getFee()).setScale(2, RoundingMode.HALF_UP).toPlainString();
  1358. }
  1359. coinHistoryOrder.setFee(fee);
  1360. // 持仓方向
  1361. coinHistoryOrder.setPosSide(InitRunner.publicParamsMap.get("posSide").getString(coinHistoryOrder.getPosSide()));
  1362. // 仓位模式
  1363. coinHistoryOrder.setMarginMode(InitRunner.publicParamsMap.get("marginMode").getString(coinHistoryOrder.getMarginMode()));
  1364. // 交易类型
  1365. coinHistoryOrder.setOrderType(InitRunner.publicParamsMap.get("orderType").getString(coinHistoryOrder.getOrderType()));
  1366. // 交易方向
  1367. coinHistoryOrder.setTradeSide(InitRunner.publicParamsMap.get("tradeSide").getString(coinHistoryOrder.getTradeSide()));
  1368. // 持仓模式
  1369. coinHistoryOrder.setHoldMode(InitRunner.publicParamsMap.get("holdMode").getString(coinHistoryOrder.getHoldMode()));
  1370. // orderSource
  1371. coinHistoryOrder.setOrderSource(InitRunner.publicParamsMap.get("orderSource").getString(coinHistoryOrder.getOrderSource()));
  1372. coinHistoryOrder.setCTime(DateUtils.longToString(Long.valueOf(coinHistoryOrder.getCTime())));
  1373. coinHistoryOrder.setUTime(DateUtils.longToString(Long.valueOf(coinHistoryOrder.getUTime())));
  1374. }
  1375. }
  1376. /**
  1377. * 渲染获取全部当前委托
  1378. *
  1379. * @param result
  1380. */
  1381. private void renderMainSearch4OrderMarginCoinCurrent(JSONArray result, Integer chaRateSort) {
  1382. forkJoinPool2.submit(() -> result.parallelStream().forEach(e -> {
  1383. JSONObject jsonObject = (JSONObject) e;
  1384. // 币对名称
  1385. String symbol = jsonObject.getString("symbol");
  1386. jsonObject.put("symbol", "<strong style=\"background-color:#F1B90d;\"><font color=\"#242A30\">" + symbol.replace("USDT_UMCBL", "") + "</font></strong>USDT_UMCBL");
  1387. // 订单状态
  1388. jsonObject.put("state", InitRunner.publicParamsMap.get("state").getString(jsonObject.getString("state")));
  1389. // 开单方向
  1390. String side = jsonObject.getString("side");
  1391. jsonObject.put("side", InitRunner.publicParamsMap.get("side").getString(side));
  1392. if (side.equals("open_long")) {
  1393. jsonObject.put("sideStyle", " style=\"color:#FFFFFF;background-color:#1DA2B4;\"");
  1394. } else if (side.equals("open_short")) {
  1395. jsonObject.put("sideStyle", " style=\"color:#FFFFFF;background-color:#F1493F;\"");
  1396. } else {
  1397. jsonObject.put("sideStyle", " style=\"color:#FFFFFF;background-color:#F0F0F0;\"");
  1398. }
  1399. // 交易类型
  1400. jsonObject.put("orderType", InitRunner.publicParamsMap.get("orderType").getString(jsonObject.getString("orderType")));
  1401. // 止盈止损
  1402. jsonObject.put("presetTakeProfitPrice", StringUtils.isEmpty(jsonObject.getString("presetTakeProfitPrice")) ? "--" : jsonObject.getString("presetTakeProfitPrice"));
  1403. jsonObject.put("presetStopLossPrice", StringUtils.isEmpty(jsonObject.getString("presetTakeProfitPrice")) ? "--" : jsonObject.getString("presetTakeProfitPrice"));
  1404. // 持仓模式
  1405. jsonObject.put("holdMode", InitRunner.publicParamsMap.get("holdMode").getString(jsonObject.getString("holdMode")));
  1406. // orderSource
  1407. jsonObject.put("orderSource", InitRunner.publicParamsMap.get("orderSource").getString(jsonObject.getString("orderSource")));
  1408. // 仓位模式
  1409. jsonObject.put("marginMode", InitRunner.publicParamsMap.get("marginMode").getString(jsonObject.getString("marginMode")));
  1410. jsonObject.put("cTime", DateUtils.longToString(jsonObject.getLong("cTime")));
  1411. jsonObject.put("uTime", DateUtils.longToString(jsonObject.getLong("uTime")));
  1412. // 获取合约标记价格
  1413. String requestUrl = mainUrl + "/api/mix/v1/market/mark-price?symbol=" + symbol;
  1414. try {
  1415. Connection.Response response = JsoupUtil.requestBody(requestUrl, JsoupUtil.HTTP_GET, InitRunner.proxy, null, null);
  1416. String markPrice = JSONObject.parseObject(response.body()).getJSONObject("data").getString("markPrice");
  1417. BigDecimal chaRate = BigDecimal.ZERO;
  1418. if ("open_short".equals(side)) {
  1419. chaRate = new BigDecimal(markPrice).divide(new BigDecimal(jsonObject.getString("price")), 4, RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(100)).setScale(2, RoundingMode.HALF_UP);
  1420. } else if ("open_long".equals(side)) {
  1421. chaRate = new BigDecimal(jsonObject.getString("price")).divide(new BigDecimal(markPrice), 4, RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(100)).setScale(2, RoundingMode.HALF_UP);
  1422. }
  1423. jsonObject.put("markPrice", markPrice);
  1424. jsonObject.put("markPriceStyle", " style=\"color:#252B31;background-color:#C4ADE9;font-weight:bold;\"");
  1425. jsonObject.put("chaRate", chaRate);
  1426. jsonObject.put("chaRateStyle", " style=\"color:#FFFFFF;background-color:#5EA294;\"");
  1427. } catch (Exception ex) {
  1428. throw new RuntimeException(ex);
  1429. }
  1430. })).join();
  1431. if (chaRateSort != 0) {
  1432. Collections.sort(result, (o1, o2) -> chaRateSort * (((JSONObject) o1).getBigDecimal("chaRate").compareTo(((JSONObject) o2).getBigDecimal("chaRate"))));
  1433. }
  1434. }
  1435. /**
  1436. * 渲染获取全部合约仓位信息V2
  1437. *
  1438. * @param result
  1439. */
  1440. private void renderMainSearch4AllPositionv2(JSONArray result, Integer unrealizedPLSort) {
  1441. forkJoinPool4.submit(() -> result.parallelStream().forEach(e -> {
  1442. JSONObject jsonObject = (JSONObject) e;
  1443. // 币对名称
  1444. String symbol = jsonObject.getString("symbol");
  1445. jsonObject.put("symbol", "<strong style=\"background-color:#F1B90d;\"><font color=\"#242A30\">" + symbol.replace("USDT_UMCBL", "") + "</font></strong>USDT_UMCBL");
  1446. // 持仓方向
  1447. String holdSide = jsonObject.getString("holdSide");
  1448. jsonObject.put("holdSide", InitRunner.publicParamsMap.get("holdSide").getString(holdSide));
  1449. if (holdSide.equals("long")) {
  1450. jsonObject.put("holdSideStyle", " style=\"color:#FFFFFF;background-color:#1DA2B4;\"");
  1451. } else if (holdSide.equals("short")) {
  1452. jsonObject.put("holdSideStyle", " style=\"color:#FFFFFF;background-color:#F1493F;\"");
  1453. } else {
  1454. jsonObject.put("holdSideStyle", " style=\"color:#FFFFFF;background-color:#F0F0F0;\"");
  1455. }
  1456. // 保证金模式
  1457. jsonObject.put("marginMode", InitRunner.publicParamsMap.get("marginMode").getString(jsonObject.getString("marginMode")));
  1458. // 持仓模式
  1459. jsonObject.put("holdMode", InitRunner.publicParamsMap.get("holdMode").getString(jsonObject.getString("holdMode")));
  1460. // 最近更新时间 保证金数量 (保证金币种) 平均开仓价 未实现盈亏 预估强平价
  1461. jsonObject.put("cTime", DateUtils.longToString(jsonObject.getLong("cTime")));
  1462. jsonObject.put("margin", new BigDecimal(jsonObject.getString("margin")).setScale(4, RoundingMode.HALF_UP));
  1463. jsonObject.put("averageOpenPrice", new BigDecimal(jsonObject.getString("averageOpenPrice")).divide(BigDecimal.ONE, new MathContext(4)));
  1464. jsonObject.put("unrealizedPL", new BigDecimal(jsonObject.getString("unrealizedPL")).setScale(4, RoundingMode.HALF_UP));
  1465. jsonObject.put("liquidationPrice", new BigDecimal(jsonObject.getString("liquidationPrice")).divide(BigDecimal.ONE, new MathContext(4)));
  1466. // 未实现盈亏
  1467. if (jsonObject.getBigDecimal("unrealizedPL").compareTo(BigDecimal.ZERO) < 0) {
  1468. jsonObject.put("unrealizedPLStyle", " style=\"color:#FFFFFF;background-color:#F1493F;\"");
  1469. } else {
  1470. jsonObject.put("unrealizedPLStyle", " style=\"color:#FFFFFF;background-color:#1DA2B4;\"");
  1471. }
  1472. // 回报率=未实现盈亏/保证金
  1473. BigDecimal returnRate = jsonObject.getBigDecimal("unrealizedPL").divide(jsonObject.getBigDecimal("margin"), 4, RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(100)).setScale(2, RoundingMode.HALF_UP);
  1474. jsonObject.put("returnRate", returnRate);
  1475. if (returnRate.compareTo(BigDecimal.ZERO) < 0) {
  1476. jsonObject.put("returnRateStyle", " style=\"color:#FFFFFF;background-color:#F1493F;\"");
  1477. } else {
  1478. jsonObject.put("returnRateStyle", " style=\"color:#FFFFFF;background-color:#1DA2B4;\"");
  1479. }
  1480. // 获取当前资金费率
  1481. String requestUrl = mainUrl + "/api/mix/v1/market/current-fundRate?symbol=" + symbol;
  1482. try {
  1483. Connection.Response response = JsoupUtil.requestBody(requestUrl, JsoupUtil.HTTP_GET, InitRunner.proxy, null, null);
  1484. String fundingRate = JSONObject.parseObject(response.body()).getJSONObject("data").getString("fundingRate");
  1485. if (new BigDecimal(fundingRate).compareTo(BigDecimal.ZERO) < 0) {
  1486. jsonObject.put("fundingRateStyle", " style=\"color:#FFFFFF;background-color:#F1493F;\"");
  1487. } else {
  1488. jsonObject.put("fundingRateStyle", " style=\"color:#FFFFFF;background-color:#1DA2B4;\"");
  1489. }
  1490. jsonObject.put("fundingRate", new BigDecimal(fundingRate).multiply(BigDecimal.valueOf(100)).setScale(4, RoundingMode.HALF_UP).toPlainString() + "%");
  1491. } catch (Exception ex) {
  1492. throw new RuntimeException(ex);
  1493. }
  1494. // 标记价格
  1495. jsonObject.put("marketPriceStyle", " style=\"color:#252B31;background-color:#C4ADE9;font-weight:bold;\"");
  1496. })).join();
  1497. if (unrealizedPLSort != 0) {
  1498. Collections.sort(result, (o1, o2) -> unrealizedPLSort * (((JSONObject) o1).getBigDecimal("unrealizedPL").compareTo(((JSONObject) o2).getBigDecimal("unrealizedPL"))));
  1499. }
  1500. }
  1501. /**
  1502. * Java实现字节转换,可以自动转换为B、KB、MB、GB、TB
  1503. *
  1504. * @param size
  1505. * @return
  1506. */
  1507. private String readableFileSize(double size) {
  1508. if (size <= 0) {
  1509. return "0";
  1510. }
  1511. final String[] units = new String[]{"B", "K", "M", "G", "T"};
  1512. int digitGroups = (int) (Math.log10(size) / Math.log10(1000));
  1513. return df1.format(size / Math.pow(1000, digitGroups)) + units[digitGroups];
  1514. }
  1515. }