<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-Content-Type-Options" content="nosniff">
    <meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate">
    <meta http-equiv="Pragma" content="no-cache">
    <meta http-equiv="Expires" content="0">
    <title>实时K线图</title>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/4.0.1/socket.io.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/echarts@5.4.3/dist/echarts.min.js"></script>
    <style>
        #kline-chart {
            width: 100%;
            height: 800px;
            margin: 20px auto;
        }
        .symbol-selector {
            margin: 20px;
            text-align: center;
        }
        button {
            margin: 10px;
            padding: 10px;
            cursor: pointer;
        }
        .active-symbol {
            background-color: #e0e0e0;
        }
        body {
            margin: 0;
            padding: 0;
            background-color: #f5f5f5;
        }
    </style>
</head>
<body>
    <div class="symbol-selector" id="symbol-buttons">
        <!-- 动态生成按钮 -->
    </div>
    <div id="kline-chart"></div>

    <script>
        let currentSymbol = null;
        const socket = io();
        const symbolButtons = document.getElementById('symbol-buttons');
        let chart = null;

        // 初始化图表
        function initChart() {
            if (!chart) {
                chart = echarts.init(document.getElementById('kline-chart'));
            }
        }

        // 初始化数据
        fetch('/api/data')
            .then(response => response.json())
            .then(data => {
                updateSymbolButtons(data);
                if (Object.keys(data).length > 0) {
                    currentSymbol = Object.keys(data)[0];
                    updateChart(data[currentSymbol]);
                }
            })
            .catch(error => {
                console.error('Error fetching data:', error);
            });

        // WebSocket事件处理
        socket.on('connect', () => {
            console.log('Connected to server');
        });

        socket.on('data_update', (data) => {
            updateSymbolButtons(data);
            if (currentSymbol && data[currentSymbol]) {
                updateChart(data[currentSymbol]);
            }
        });

        function updateSymbolButtons(data) {
            symbolButtons.innerHTML = '';
            Object.keys(data).forEach(symbol => {
                const button = document.createElement('button');
                button.textContent = symbol;
                button.onclick = () => {
                    currentSymbol = symbol;
                    updateChart(data[symbol]);
                };
                if (symbol === currentSymbol) {
                    button.classList.add('active-symbol');
                }
                symbolButtons.appendChild(button);
            });
        }

        function updateChart(data) {
            initChart();
            
            // 准备数据
            const dates = data.map(item => item.datetime);
            const klineData = data.map(item => [
                parseFloat(item.open),
                parseFloat(item.close),
                parseFloat(item.low),
                parseFloat(item.high)
            ]);
            const volumes = data.map(item => parseFloat(item.volume));
            const ultimateValues = data.map(item => parseFloat(item.终极平滑值));
            
            // 处理POC数据，将缺值替换为前一个有效值
            let pocValues = data.map(item => item.POC);
            let lastValidPoc = null;
            pocValues = pocValues.map(value => {
                if (value === '缺值') {
                    return lastValidPoc;
                } else {
                    lastValidPoc = parseFloat(value);
                    return lastValidPoc;
                }
            });

            // 处理delta累计数据，将缺值替换为前一个有效值
            let deltaSumValues = data.map(item => item.delta累计);
            let lastValidDelta = null;
            deltaSumValues = deltaSumValues.map(value => {
                if (value === '缺值') {
                    return lastValidDelta;
                } else {
                    lastValidDelta = parseFloat(value);
                    return lastValidDelta;
                }
            });
            
            // 计算48日均线
            const closes = data.map(item => parseFloat(item.close));
            const ma48 = calculateMA(closes, 48);
            
            // 配置图表选项
            const option = {
                title: {
                    text: `${currentSymbol} K线图`,
                    left: 'center'
                },
                tooltip: {
                    trigger: 'axis',
                    axisPointer: {
                        type: 'cross'
                    }
                },
                legend: {
                    data: ['K线', '48日均线', '终极平滑值', 'POC', 'Delta累计'],
                    top: 30
                },
                grid: [
                    {
                        left: '10%',
                        right: '8%',
                        height: '50%'
                    },
                    {
                        left: '10%',
                        right: '8%',
                        top: '65%',
                        height: '15%'
                    },
                    {
                        left: '10%',
                        right: '8%',
                        top: '85%',
                        height: '15%'
                    }
                ],
                xAxis: [
                    {
                        type: 'category',
                        data: dates,
                        scale: true,
                        boundaryGap: false,
                        axisLine: {onZero: false},
                        splitLine: {show: false},
                        splitNumber: 20,
                        gridIndex: 0
                    },
                    {
                        type: 'category',
                        gridIndex: 1,
                        data: dates,
                        axisLabel: {show: false},
                        splitLine: {show: false},
                        axisLine: {show: false},
                        splitNumber: 20
                    },
                    {
                        type: 'category',
                        gridIndex: 2,
                        data: dates,
                        axisLabel: {show: false},
                        splitLine: {show: false},
                        axisLine: {show: false},
                        splitNumber: 20
                    }
                ],
                yAxis: [
                    {
                        scale: true,
                        splitArea: {
                            show: true
                        },
                        gridIndex: 0
                    },
                    {
                        scale: true,
                        gridIndex: 1,
                        splitNumber: 2,
                        axisLabel: {show: false},
                        axisLine: {show: false},
                        splitLine: {show: false}
                    },
                    {
                        scale: true,
                        gridIndex: 2,
                        splitNumber: 2,
                        axisLabel: {show: true},
                        axisLine: {show: true},
                        splitLine: {show: false},
                        position: 'right'
                    }
                ],
                dataZoom: [
                    {
                        type: 'inside',
                        xAxisIndex: [0, 1, 2],
                        start: 50,
                        end: 100
                    },
                    {
                        show: true,
                        xAxisIndex: [0, 1, 2],
                        type: 'slider',
                        bottom: '5%',
                        start: 50,
                        end: 100
                    }
                ],
                series: [
                    {
                        name: 'K线',
                        type: 'candlestick',
                        data: klineData,
                        itemStyle: {
                            color: '#ef232a',
                            color0: '#14b143',
                            borderColor: '#ef232a',
                            borderColor0: '#14b143'
                        }
                    },
                    {
                        name: '48日均线',
                        type: 'line',
                        data: ma48,
                        smooth: true,
                        lineStyle: {
                            opacity: 0.5
                        }
                    },
                    {
                        name: '终极平滑值',
                        type: 'line',
                        data: ultimateValues,
                        smooth: true,
                        lineStyle: {
                            opacity: 0.5
                        }
                    },
                    {
                        name: 'POC',
                        type: 'line',
                        data: pocValues,
                        smooth: true,
                        lineStyle: {
                            color: '#FFD700',
                            width: 2,
                            opacity: 0.8
                        },
                        symbol: 'circle',
                        symbolSize: 6
                    },
                    {
                        name: '成交量',
                        type: 'bar',
                        xAxisIndex: 1,
                        yAxisIndex: 1,
                        data: volumes
                    },
                    {
                        name: 'Delta累计',
                        type: 'line',
                        xAxisIndex: 2,
                        yAxisIndex: 2,
                        data: deltaSumValues,
                        smooth: true,
                        lineStyle: {
                            color: '#4169E1',
                            width: 2,
                            opacity: 0.8
                        },
                        markLine: {
                            silent: true,
                            data: [
                                {
                                    yAxis: 0,
                                    lineStyle: {
                                        color: '#999',
                                        type: 'dashed'
                                    }
                                }
                            ]
                        }
                    }
                ]
            };

            // 使用配置项显示图表
            chart.setOption(option);
        }

        function calculateMA(data, dayCount) {
            const result = [];
            for (let i = 0, len = data.length; i < len; i++) {
                if (i < dayCount - 1) {
                    result.push('-');
                    continue;
                }
                let sum = 0;
                for (let j = 0; j < dayCount; j++) {
                    sum += data[i - j];
                }
                result.push(+(sum / dayCount).toFixed(2));
            }
            return result;
        }

        // 响应窗口大小变化
        window.addEventListener('resize', function() {
            if (chart) {
                chart.resize();
            }
        });

        // 初始化图表
        initChart();
    </script>
</body>
</html> 