KLineChart 库生成一个股票K线图

69 阅读2分钟

下面我将为您介绍如何使用 KLineChart 库生成一个股票K线图 Demo,并提供完整的代码示例和关键步骤说明。

🧰 准备工作

首先需要引入必要的 JavaScript 库,并准备好 StockTV API 密钥。

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>StockTV K线图实战Demo</title>
    <!-- 引入KLineChart库 -->
    <script src="https://cdn.dolphindb.cn/vendors/klinecharts/dist/umd/klinecharts.min.js"></script>
</head>
<body>
    <div id="k-line-chart" style="height: 600px; width: 100%;"></div>

    <script>
        // 配置参数
        const API_KEY = 'YOUR_API_KEY_HERE'; // 请替换为你的真实API密钥
        const API_BASE = 'https://api.stocktv.top';
        
        // 你的代码将在这里编写
    </script>
</body>
</html>

📡 获取股票K线数据

通过 StockTV API 获取股票数据需要两个步骤:先获取股票唯一ID,再请求K线数据。

// 配置股票参数
const symbol = 'AAPL'; // 股票代码
const interval = 'P1D'; // K线周期:日线

async function fetchKLineData() {
    try {
        // 1. 根据股票代码查询其唯一产品ID (pid)
        const listUrl = `${API_BASE}/stock/stocks?countryId=1&symbol=${symbol}&key=${API_KEY}`;
        const listResponse = await fetch(listUrl);
        const listData = await listResponse.json();
        
        if (listData.code !== 200 || listData.data.length === 0) {
            console.error('未找到该股票:', listData.message);
            return;
        }
        
        const stockPid = listData.data[0].id; // 获取股票的pid

        // 2. 使用pid请求历史K线数据
        const klineUrl = `${API_BASE}/stock/kline?pid=${stockPid}&interval=${interval}&key=${API_KEY}`;
        const klineResponse = await fetch(klineUrl);
        const klineData = await klineResponse.json();
        
        if (klineData.code === 200) {
            return klineData.data; // 返回数据用于绘图
        } else {
            console.error('获取K线数据失败:', klineData.message);
            return null;
        }
    } catch (error) {
        console.error('请求失败:', error);
        return null;
    }
}

⚙️ 初始化K线图表与数据转换

获取到数据后,需要将其转换为 KLineChart 可识别的格式并初始化图表。

// 初始化K线图容器
const chart = klinecharts.init('k-line-chart');

async function initChart() {
    const apiData = await fetchKLineData();
    if (!apiData) return;

    // 数据格式转换:将API返回的字段名映射为KLineChart要求的字段名
    const klineChartData = apiData.map(item => ({
        timestamp: item.time,   // 将 'time' 映射为 'timestamp'
        open: Number(item.open),
        high: Number(item.high),
        low: Number(item.low),
        close: Number(item.close),
        volume: Number(item.volume)
    }));

    // 按时间排序(防止API返回乱序)
    klineChartData.sort((a, b) => a.timestamp - b.timestamp);

    // 使用转换后的数据渲染图表
    chart.applyNewData(klineChartData);
    console.log('K线图初始化完成!');
}

// 执行初始化
initChart();

🎨 自定义样式与技术指标

KLineChart 支持丰富的样式自定义和技术指标添加。

// 设置样式选项
chart.setStyleOptions({
    candle: {
        type: 'candle_solid', // 蜡烛图类型
        bar: {
            upColor: '#26A69A', // 上涨颜色
            downColor: '#EF5350', // 下跌颜色
        },
        priceMark: { // 价格标记
            high: { show: true },
            low: { show: true }
        }
    },
    grid: { // 网格线
        show: true
    }
});

// 添加技术指标(如移动平均线MA)
chart.createIndicator('MA', false, { id: 'candle_pane' });
// 添加成交量指标
chart.createIndicator('VOL');

🔄 实现实时数据更新

对于金融应用,实时性很重要。以下是定时轮询的实现方式。

// 定时轮询更新函数
async function startPolling(pid) {
    setInterval(async () => {
        try {
            const klineUrl = `${API_BASE}/stock/kline?pid=${pid}&interval=${interval}&key=${API_KEY}`;
            const response = await fetch(klineUrl);
            const result = await response.json();
            
            if (result.code === 200 && result.data.length > 0) {
                const latestData = result.data[result.data.length - 1];
                const formattedData = {
                    timestamp: latestData.time,
                    open: Number(latestData.open),
                    high: Number(latestData.high),
                    low: Number(latestData.low),
                    close: Number(latestData.close),
                    volume: Number(latestData.volume)
                };
                
                // 增量更新图表
                chart.updateData(formattedData);
            }
        } catch (error) {
            console.error('实时更新失败:', error);
        }
    }, 5000); // 每5秒轮询一次
}

💡 完整示例代码

以下是整合所有功能的完整 HTML 示例。

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>StockTV K线图Demo</title>
    <script src="https://cdn.dolphindb.cn/vendors/klinecharts/dist/umd/klinecharts.min.js"></script>
    <style>
        body { margin: 20px; font-family: Arial, sans-serif; }
        .controls { margin-bottom: 20px; }
        button { padding: 8px 15px; margin-right: 10px; cursor: pointer; }
    </style>
</head>
<body>
    <div class="controls">
        <h3>股票K线图示例</h3>
        <button onclick="loadData('AAPL')">苹果(AAPL)</button>
        <button onclick="loadData('MSFT')">微软(MSFT)</button>
        <select id="intervalSelect">
            <option value="P1D">日线</option>
            <option value="PT1H">1小时</option>
            <option value="PT15M">15分钟</option>
        </select>
    </div>
    
    <div id="k-line-chart" style="height: 600px; width: 100%;"></div>

    <script>
        const API_KEY = 'YOUR_API_KEY_HERE'; // 请替换为你的真实API密钥
        const API_BASE = 'https://api.stocktv.top';
        const chart = klinecharts.init('k-line-chart');
        
        // 设置默认样式
        chart.setStyleOptions({
            candle: {
                bar: {
                    upColor: '#26A69A',
                    downColor: '#EF5350',
                }
            }
        });

        async function loadData(symbol, interval = 'P1D') {
            if (!interval) interval = document.getElementById('intervalSelect').value;
            
            try {
                // 获取股票PID
                const listUrl = `${API_BASE}/stock/stocks?countryId=1&symbol=${symbol}&key=${API_KEY}`;
                const listResponse = await fetch(listUrl);
                const listData = await listResponse.json();
                
                if (listData.code !== 200 || listData.data.length === 0) {
                    alert('未找到该股票');
                    return;
                }
                
                const stockPid = listData.data[0].id;
                
                // 获取K线数据
                const klineUrl = `${API_BASE}/stock/kline?pid=${stockPid}&interval=${interval}&key=${API_KEY}`;
                const klineResponse = await fetch(klineUrl);
                const klineData = await klineResponse.json();
                
                if (klineData.code !== 200) {
                    alert('获取数据失败: ' + klineData.message);
                    return;
                }

                // 数据转换
                const chartData = klineData.data.map(item => ({
                    timestamp: item.time,
                    open: Number(item.open),
                    high: Number(item.high),
                    low: Number(item.low),
                    close: Number(item.close),
                    volume: Number(item.volume)
                })).sort((a, b) => a.timestamp - b.timestamp);

                // 渲染图表
                chart.applyNewData(chartData);
                chart.createIndicator('MA');
                chart.createIndicator('VOL');
                
            } catch (error) {
                console.error('Error:', error);
                alert('请求失败,请检查控制台日志');
            }
        }

        // 页面加载默认数据
        window.onload = () => loadData('AAPL');
        
        // 响应式调整大小
        window.addEventListener('resize', () => {
            chart.resize();
        });
    </script>
</body>
</html>

📋 关键注意事项

  1. API密钥安全:切勿将真实 API 密钥直接硬编码在前端代码中并上传到公开仓库。生产环境应通过后端服务器转发请求。

  2. 数据格式转换:StockTV API 返回的数据字段需要转换为 KLineChart 要求的格式,特别是时间戳字段的映射。

  3. 错误处理:完善的错误处理能提升应用健壮性,包括网络请求失败、API返回错误码等情况。

  4. 频率限制:遵守 StockTV API 的调用频率限制,避免过于频繁的请求。

这个Demo展示了如何使用 KLineChart 和 StockTV API 快速构建一个功能完整的股票K线图应用,您可以根据实际需求进一步扩展功能。