API接口分为订阅数据、实时行情数据、财务数据三个部分。

包括股票实时盘口数据、实时K线数据、实时一分钟数据、实时分时数据等。

除了订阅接口是Websocket API,其余接口为Http API接口且均支持GET和POST方法,下面以GET请求示例。

package org.xtick;


import com.google.common.collect.ImmutableList;
import com.google.common.util.concurrent.ThreadFactoryBuilder;
import jakarta.websocket.*;
import org.apache.catalina.util.StringUtil;
import org.apache.commons.lang3.StringUtils;
import org.xtick.bean.MinutePacket;
import org.xtick.bean.TickPacket;
import org.xtick.bean.TickSubcribeInfo;
import org.xtick.constant.XTickConst;
import org.xtick.util.JsonUtil;
import org.xtick.util.XTickUtil;

import java.io.ByteArrayInputStream;
import java.io.UnsupportedEncodingException;
import java.net.URI;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.function.Consumer;

/**
 * WebSocket客户端,用于连接XTick的WebSocket服务。
 * 官网:http://www.xtick.top/
 */
@ClientEndpoint
public class XTickWebSocketClient {
    private URI endpointURI;
    private static final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS");
    private LinkedBlockingQueue<Object> queue = new LinkedBlockingQueue<>(100000);
    private ThreadPoolExecutor taskThreadPool = new ThreadPoolExecutor(3, 3, 60, TimeUnit.SECONDS, new LinkedBlockingDeque<>(1000), new ThreadFactoryBuilder().setNameFormat("xtick-task-%d").build());

    private Consumer<String> dataConsumer = result -> {
        Object packet;
        if (StringUtils.isNotBlank(result)) {
            if (result.contains("1m")) {
                packet = JsonUtil.jsonToObj(result, MinutePacket.class);
            } else {
                packet = JsonUtil.jsonToObj(result, TickPacket.class);
            }
            if (Objects.nonNull(packet)) {//数据包加入队列中,后续业务模块调用处理
                queue.offer(packet);
            }
        }
    };

    private XTickWebSocketClient(URI endpointURI) {
        try {
            this.endpointURI = endpointURI;
            connectToServer(endpointURI, null);
        } catch (Exception e) {
            System.err.println("Failed to connect to WebSocket server" + e.getMessage());
        }
    }

    private void connectToServer(URI endpointURI, CloseReason reason) {
        if (Objects.isNull(reason) || !reason.getCloseCode().equals(CloseReason.CloseCodes.NORMAL_CLOSURE)) {
            try {
                WebSocketContainer container = ContainerProvider.getWebSocketContainer();
                container.setDefaultMaxBinaryMessageBufferSize(1 * 1024 * 1024);
                container.setDefaultMaxTextMessageBufferSize(1 * 1024 * 1024);
                container.setDefaultMaxSessionIdleTimeout(1 * 60 * 60 * 1000L);
                container.connectToServer(this, endpointURI);
                XTickUtil.sleepSeconds(1);
            } catch (Exception e) {
                System.err.println("Failed to connect to WebSocket server" + e.getMessage());
                XTickUtil.sleepSeconds(10);
                connectToServer(endpointURI, reason);
            }
        }
    }

    @OnOpen
    public void onOpen(Session session) {
        System.out.println("Connected to WebSocket server");
    }

    @OnClose
    public void onClose(Session session, CloseReason reason) {
        System.out.println("Disconnected from WebSocket server. Reason: " + reason.toString());
        connectToServer(endpointURI, reason);
    }

    @OnMessage
    public void onMessage(String data) {
        System.out.println("Received message: " + data);
    }

    @OnMessage
    public void onMessage(byte[] data) {
        XTickUtil.processData(new ByteArrayInputStream(data), dataConsumer);
    }

    @OnError
    public void onError(Session session, Throwable throwable) {
        System.err.println("WebSocket连接发生错误.error=" + throwable.getMessage());
    }


    public void exec() {
        taskThreadPool.execute(() -> {
            while (true) {
                try {
                    Object data = queue.take();
                    if (data instanceof TickPacket) { //处理业务逻辑....
                        TickPacket packet = (TickPacket) data;
                        System.out.println(String.format("%s,received tick data.[authCode=%s,period=%s,size=%s]", LocalDateTime.now().format(formatter), packet.getAuthCode(), packet.getPeriod(), packet.getData().size()));
                    } else {
                        MinutePacket packet = (MinutePacket) data;
                        System.out.println(String.format("%s,received minute data.[authCode=%s,period=%s,size=%s]", LocalDateTime.now().format(formatter), packet.getAuthCode(), packet.getPeriod(), packet.getData().size()));
                    }
                } catch (Exception e) {
                    System.err.println("Failed to process data." + e.getMessage());
                }
            }
        });
    }

    public static void main(String[] args) throws UnsupportedEncodingException {
        //List<String> authCodes = ImmutableList.of("time.SZ", "time.SH", "time.BJ", "time.HK", "tick.SZ", "tick.SH", "tick.BJ", "tick.HK");
        List<String> authCodes = ImmutableList.of("tick.BJ");//新用户,可以订阅北交所的tick行情数据
        String user = URLEncoder.encode(JsonUtil.toJson(TickSubcribeInfo.builder().token(XTickConst.token).authCodes(authCodes).build()), StandardCharsets.UTF_8.toString());
        XTickWebSocketClient wsClient = new XTickWebSocketClient(URI.create(String.format("ws://ws.xtick.top/ws/%s", user)));
        wsClient.exec();
    }
}

实时行情数据:

package org.xtick;

import com.google.common.collect.ImmutableMap;
import org.xtick.bean.Minute;
import org.xtick.bean.Tick;
import org.xtick.bean.finance.*;
import org.xtick.constant.MethodType;
import org.xtick.constant.XTickConst;
import org.xtick.http.HttpClientRest;
import org.xtick.util.JsonUtil;

import java.io.IOException;
import java.time.LocalDate;
import java.util.List;
import java.util.Map;
/**
 * 行情实时数据、财务报表数据获取API接口。
 * 官网:http://www.xtick.top/
 */
public class XTickStockApiClient {
    /**
     * 获取财务数据
     */
    public String getFinancialData(int type, String code, String report, String startDate, String endDate, String token, MethodType method) throws IOException {
        String url = "http://api.xtick.top/doc/financial";
        Map<String, Object> para = ImmutableMap.<String, Object>builder().put("type", type).put("zip", true).put("code", code).put("report", report).put("startDate", startDate).put("endDate", endDate).put("token", token).build();
        return method.equals(MethodType.GET) ? HttpClientRest.getIntance().get(url, para) : HttpClientRest.getIntance().post(url, para);
    }

    /**
     * 获取市场行情数据数据
     */
    public String getMarketData(int type, String code, String period, String fq, String startDate, String endDate, String token, MethodType method) throws IOException {
        String url = "http://api.xtick.top/doc/market";
        Map<String, Object> para = ImmutableMap.<String, Object>builder().put("type", type).put("zip", true).put("code", code).put("period", period).put("fq", fq).put("startDate", startDate).put("endDate", endDate).put("token", token).build();
        return method.equals(MethodType.GET) ? HttpClientRest.getIntance().get(url, para) : HttpClientRest.getIntance().post(url, para);
    }

    public void DemoFinancialData() throws IOException {
        int type = 1;//沪深京A股Type=1,港股Type=3
        String code = "000001";
        String startDate = "2020-04-25";
        String endDate = LocalDate.now().toString();
        //获取财务指标数据
        String report = "Pershareindex";
        String result = getFinancialData(type, code, report, startDate, endDate, XTickConst.token, MethodType.GET);
        List<XTickFinancePershareIndex> financePershareIndexDatas = JsonUtil.jsonToList(result, XTickFinancePershareIndex.class);
        System.out.println(String.format("code=%s,report=%s,date=%s,financial data size=%s", code, report, startDate, financePershareIndexDatas.size()));

        report = "Balance";
        result = getFinancialData(type, code, report, startDate, endDate, XTickConst.token, MethodType.GET);
        List<XTickFinanceBalance> financeBalanceDatas = JsonUtil.jsonToList(result, XTickFinanceBalance.class);
        System.out.println(String.format("code=%s,report=%s,date=%s,financial data size=%s", code, report, startDate, financeBalanceDatas.size()));

        report = "CashFlow";
        result = getFinancialData(type, code, report, startDate, endDate, XTickConst.token, MethodType.GET);
        List<XTickFinanceCashFlow> financeCashFlowDatas = JsonUtil.jsonToList(result, XTickFinanceCashFlow.class);
        System.out.println(String.format("code=%s,report=%s,date=%s,financial data size=%s", code, report, startDate, financeCashFlowDatas.size()));

        report = "Capital";
        result = getFinancialData(type, code, report, startDate, endDate, XTickConst.token, MethodType.GET);
        List<XTickFinanceCapital> financeCapitalDatas = JsonUtil.jsonToList(result, XTickFinanceCapital.class);
        System.out.println(String.format("code=%s,report=%s,date=%s,financial data size=%s", code, report, startDate, financeCapitalDatas.size()));

        report = "Holdernum";
        result = getFinancialData(type, code, report, startDate, endDate, XTickConst.token, MethodType.GET);
        List<XTickFinanceHoldernum> financeHoldernumDatas = JsonUtil.jsonToList(result, XTickFinanceHoldernum.class);
        System.out.println(String.format("code=%s,report=%s,date=%s,financial data size=%s", code, report, startDate, financeHoldernumDatas.size()));

        report = "Top10holder";
        result = getFinancialData(type, code, report, startDate, endDate, XTickConst.token, MethodType.GET);
        List<XTickFinanceTop10holder> financeTop10holderDatas = JsonUtil.jsonToList(result, XTickFinanceTop10holder.class);
        System.out.println(String.format("code=%s,report=%s,date=%s,financial data size=%s", code, report, startDate, financeTop10holderDatas.size()));

        report = "Top10flowholder";
        result = getFinancialData(type, code, report, startDate, endDate, XTickConst.token, MethodType.GET);
        List<XTickFinanceTop10flowholder> financeTop10flowholderDatas = JsonUtil.jsonToList(result, XTickFinanceTop10flowholder.class);
        System.out.println(String.format("code=%s,report=%s,date=%s,financial data size=%s", code, report, startDate, financeTop10flowholderDatas.size()));
    }

    public void DemoForMarketData() throws IOException {
        int type = 1;//沪深京A股Type=1,港股Type=3
        String code = "000001";
        String startDate = "2025-04-25";
        String endDate = LocalDate.now().toString();
        String result = getMarketData(type, code, "tick", "", startDate, startDate, XTickConst.token, MethodType.GET);
        List<Tick> ticks = JsonUtil.jsonToList(result, Tick.class);//获取tick数据
        System.out.println(String.format("code=%s,period=tick,date=%s,history data size=%s", code, startDate, ticks.size()));
        for (String period : XTickConst.historyKlinePeriods) {//获取K线数据
            for (String fq : XTickConst.dividends) {
                result = getMarketData(type, code, period, fq, startDate, endDate, XTickConst.token, MethodType.GET);
                List<Minute> klines = JsonUtil.jsonToList(result, Minute.class);
                System.out.println(String.format("code=%s,period=%s,fq=%s,startDate=%s,endDate=%s,history data size=%s", code, period, fq, startDate, endDate, klines.size()));
            }
        }
    }

    public static void main(String[] args) throws IOException {
        XTickStockApiClient client = new XTickStockApiClient();
        client.DemoFinancialData();//获取财务数据代码示例
        //client.DemoForMarketData();//获取历史数据代码示例
    }
}

Logo

火山引擎开发者社区是火山引擎打造的AI技术生态平台,聚焦Agent与大模型开发,提供豆包系列模型(图像/视频/视觉)、智能分析与会话工具,并配套评测集、动手实验室及行业案例库。社区通过技术沙龙、挑战赛等活动促进开发者成长,新用户可领50万Tokens权益,助力构建智能应用。

更多推荐