Java WebSocket百分比价格告警:如何存储首条消息计算阈值
实现百分比条件告警的方案
1. 扩展告警类型与实体字段
首先需要在告警类型枚举(AlertType)中新增百分比相关的类型:
l_percent:价格下跌指定百分比触发告警u_percent:价格上涨指定百分比触发告警
同时在Alert实体中添加percentage字段,用来存储用户设置的百分比数值(例如用户设置下跌5%,该字段值为5)。
2. 修改告警逻辑,存储初始价格与计算阈值
在AlertUserByPrice方法中,我们需要在WebSocket消息处理器里记录初始价格并计算告警阈值。由于WebSocket消息处理是异步的,用AtomicReference安全存储初始价格(保证线程可见性),用volatile变量存储计算后的阈值。
修改后的AlertUserByPrice代码如下:
public void AlertUserByPrice(Long id) { Alert alert = alertRepository.findById(id).orElseThrow(() -> new NoSuchElementException()); String type = alert.getAlertType().getKey(); double setPrice = alert.getPrice(); double percentage = alert.getPercentage(); // 获取用户设置的百分比 String ticker = alert.getTicker(); JSONParser jsonParser = new JSONParser(); NotificationRequest build = null; // 修复字符串比较:用equals代替== if (type.equals("l_break")) { build = NotificationRequest.builder() .title(ticker + " alert") .message(setPrice + " broke down") .token(notificationService.getToken(userDetailService.returnUser().getEmail())) .build(); } else if (type.equals("upper_break")) { build = NotificationRequest.builder() .title(ticker + " alert") .message(setPrice + " pierced upward") .token(notificationService.getToken(userDetailService.returnUser().getEmail())) .build(); } else if (type.equals("l_percent")) { build = NotificationRequest.builder() .title(ticker + " percentage alert") .message("Price dropped by " + percentage + "%") .token(notificationService.getToken(userDetailService.returnUser().getEmail())) .build(); } else if (type.equals("u_percent")) { build = NotificationRequest.builder() .title(ticker + " percentage alert") .message("Price rose by " + percentage + "%") .token(notificationService.getToken(userDetailService.returnUser().getEmail())) .build(); } try { final WebsocketClientEndpoint clientEndPoint = new WebsocketClientEndpoint(); Session session = clientEndPoint.connect(new URI("wss://ws.coincap.io/prices?assets=" + ticker)); // 用AtomicReference存储初始价格,保证线程安全 final AtomicReference<Double> initialPrice = new AtomicReference<>(); // 用volatile存储阈值,保证后续消息处理时能读到最新值 volatile double thresholdPrice = 0.0; WebsocketClientEndpoint.MessageHandler handler = new WebsocketClientEndpoint.MessageHandler() { public void handleMessage(String message) throws ParseException, IOException { Object obj = jsonParser.parse(message); JSONObject jsonObject = (JSONObject) obj; double currentPrice = Double.parseDouble(jsonObject.get(ticker).toString()); System.out.println("当前价格 : " + currentPrice); // 百分比类型告警:第一次收到消息时计算阈值 if ((type.equals("l_percent") || type.equals("u_percent")) && initialPrice.get() == null) { initialPrice.set(currentPrice); if (type.equals("l_percent")) { // 下跌阈值:初始价格 * (1 - 百分比/100) thresholdPrice = currentPrice * (1 - percentage / 100); System.out.println("下跌告警阈值已计算:" + thresholdPrice); } else { // 上涨阈值:初始价格 * (1 + 百分比/100) thresholdPrice = currentPrice * (1 + percentage / 100); System.out.println("上涨告警阈值已计算:" + thresholdPrice); } // 第一次仅计算阈值,不触发告警 return; } // 判断告警触发条件 boolean shouldAlert = false; if (type.equals("l_break")) { shouldAlert = currentPrice < setPrice; } else if (type.equals("upper_break")) { shouldAlert = currentPrice > setPrice; } else if (type.equals("l_percent")) { shouldAlert = currentPrice <= thresholdPrice; } else if (type.equals("u_percent")) { shouldAlert = currentPrice >= thresholdPrice; } if (shouldAlert) { System.out.println("触发告警"); notificationService.sendNotification(build); session.close(); } try { Thread.sleep(1000); } catch (InterruptedException ex) { System.err.println("InterruptedException exception: " + ex.getMessage()); } } }; clientEndPoint.addMessageHandler(handler); } catch (URISyntaxException ex) { System.err.println("URISyntaxException exception: " + ex.getMessage()); } }
3. 关键说明
- 初始价格存储:用
AtomicReference存储初始价格,适配WebSocket可能的多线程消息处理场景,保证读写的线程安全。 - 阈值计算时机:第一次收到WebSocket消息时,以当前价格为基准计算阈值,后续消息直接用阈值判断,避免重复计算。
- 字符串比较修复:原代码中用
==比较字符串是错误的,Java中必须用equals()方法,否则会因对象引用不同导致判断失效。 - 告警触发逻辑:百分比类型告警,下跌时判断当前价格是否小于等于阈值,上涨时判断是否大于等于阈值,符合“触及即告警”的需求。
内容的提问来源于stack exchange,提问作者YSEO
相关产品推荐
相关产品推荐

