ipo
zyy
2026-01-07 b816da7165bf9c80e588a4977583992de46b73ee
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
package com.yami.trading.huobi.wss;
 
import cn.hutool.http.Header;
import cn.hutool.http.HttpRequest;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.yami.trading.bean.item.domain.Item;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.java_websocket.handshake.ServerHandshake;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.client.WebSocketClient;
 
import java.net.URI;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.Random;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.stream.Collectors;
 
/**
 * 极度证券 数据源
 * https://m.jdnx.com/
 * @author 哪吒
 */
@Slf4j
@Component
public class JiduWebSocket {
 
    public static final List<String> JD_WSS = Arrays.asList(
            "wss://stream.jdnx3.com",
            "wss://stream.jdnx4.com",
            "wss://stream.jdnx5.com",
            "wss://stream.jdnx6.com",
            "wss://stream.jdnx7.com",
            "wss://stream.jdnx8.com",
            "wss://stream.jdnx9.com",
            "wss://stream.jdnx10.com"
    );
 
    /**
     * 获取订阅token
     */
    public static final String JD_TOKEN = "https://api.jdnx6.com/Public/openSubscribe";
 
    /**
     * 更新订阅产品 [配合前端更新,传wss token]
     */
    public static final String JD_PRODUCT = "https://api.jdnx7.com/Public/updateSubscribe";
 
    /**
     * 全局token key
     */
    public static final String WSS_TOKEN_KEY = "JD_WSS_TOKEN";
 
    private ExecutorService wssTask = Executors.newCachedThreadPool();
 
    /*使用线程安全的 ConcurrentMap 来记录已启动的 token*/
    private ConcurrentMap<String, Boolean> startedTokens = new ConcurrentHashMap<>();
 
    /**
     * 各个 行情的token值
     */
    private ConcurrentMap<String, String> tokens = new ConcurrentHashMap<>();
 
    /**
     * 启动行情
     * @param symbols
     */
    public void startWss(List<String> symbols, String type){
        Random random = new Random();
        String wssUrl = JD_WSS.get(random.nextInt(JD_WSS.size()));
        String token = socketToken();
        tokens.put(type,token);
        if (Item.HK_STOCKS.equalsIgnoreCase(type)) {
            //处理symbol对
            symbols = symbols.stream()
                    .map(val -> val + ".HK")
                    .collect(Collectors.toList());
        }
        updateSubscribe(symbols,token);
        if(Objects.nonNull(token)){
            //开始连接
            wssTask.execute(() -> {
                log.info("【极度证券】 {} 行情开启成功!",type);
                connectionWss(wssUrl + "/Quotation/" + token);
            });
        }
    }
 
    private void connectionWss(String url){
        try {
            JiduWebSocketClient webSocketClient = new JiduWebSocketClient(new URI(url));
            webSocketClient.connect();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
 
    /**
     * 开启ws连接
     * @param token
     */
    public void startWs(String token){
        //如果这个用户token 启动了wss 无需再开启
        if (startedTokens.putIfAbsent(token, Boolean.TRUE) != null) {
            return;
        }
        Random random = new Random();
        String wssUrl = JD_WSS.get(random.nextInt(JD_WSS.size()));
        if(Objects.nonNull(token)){
            //开始连接
            wssTask.execute(() -> {
                connectionWss(wssUrl + "/Quotation/" + token,token);
            });
        }
    }
 
    private void connectionWss(String url, String token){
        try {
            JiduWebSocketClient webSocketClient = new JiduWebSocketClient(new URI(url));
            webSocketClient.connect();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
 
    private void updateSubscribeOne(String symbol, String token){
        updateSubscribe(Arrays.asList(symbol),token);
    }
    private void updateSubscribe(List<String> symbols, String token){
        String body = HttpRequest
                .post(JD_PRODUCT)
                .form("symbols", JSON.toJSONString(symbols))
                .header(Header.AUTHORIZATION,"Bearer " + token)
                .execute()
                .body();
        JSONObject bodyJson = JSON.parseObject(body);
        if(bodyJson.getInteger("code").intValue() == 200){
            System.out.println("【极度证券】产品订阅设置为:" + JSON.toJSONString(symbols));
        }
    }
 
    /**
     * 根据用户指定获取的token 更新产品订阅
     * @param token
     * @param symbols
     */
    public boolean updateSubscribe(String token, List<String> symbols){
        String body = HttpRequest
                .post(JD_PRODUCT)
                .form("symbols", JSON.toJSONString(symbols))
                .header(Header.AUTHORIZATION,"Bearer " + token)
                .execute()
                .body();
        JSONObject bodyJson = JSON.parseObject(body);
        if(bodyJson.getInteger("code").intValue() == 200){
            System.out.println("【极度证券】产品订阅设置为:" + JSON.toJSONString(symbols));
            return true;
        }
        return false;
    }
 
 
    public String socketToken(){
        String body = HttpRequest.post(JD_TOKEN).execute().body();
        JSONObject bodyJson = JSON.parseObject(body);
        if(bodyJson.getInteger("code").intValue() == 200){
            String token = bodyJson.getJSONObject("data").getString("token");
            System.out.println("成功获取到【极度socketToken】:" + token);
            return token;
        } else {
            System.out.println("获取【极度token报错】 :" + body);
        }
        return null;
    }
 
 
}