kline_app.py

import dearpygui.dearpygui as dpg
import random
from datetime import datetime, timedelta


# 全局变量
kline_data = None


def generate_random_kline_data(num_points=200, timeframe="1D"):
    """生成随机K线数据(A股风格:涨红跌绿)"""
    global kline_data
    now = datetime.now()
    data = []
    
    # 根据时间周期计算时间间隔
    if timeframe == "1D":
        delta = timedelta(days=1)
    elif timeframe == "4H":
        delta = timedelta(hours=4)
    elif timeframe == "1H":
        delta = timedelta(hours=1)
    elif timeframe == "15M":
        delta = timedelta(minutes=15)
    elif timeframe == "5M":
        delta = timedelta(minutes=5)
    elif timeframe == "1M":
        delta = timedelta(minutes=1)
    else:
        delta = timedelta(days=1)
    
    # 初始价格
    open_price = 100.0
    for i in range(num_points):
        timestamp = now - delta * (num_points - i)
        
        # 随机价格波动
        volatility = 0.02
        high = open_price * (1 + random.uniform(0, volatility))
        low = open_price * (1 - random.uniform(0, volatility))
        close = open_price + random.uniform(-volatility * open_price, volatility * open_price)
        
        # 随机成交量
        volume = random.randint(1000, 10000)
        
        data.append({
            "timestamp": timestamp,
            "open": open_price,
            "high": high,
            "low": low,
            "close": close,
            "volume": volume
        })
        
        open_price = close
    
    kline_data = data
    return data


def create_chart_series():
    """创建图表数据序列"""
    if kline_data is None:
        return
    
    try:
        # 提取K线数据
        dates = list(range(len(kline_data)))
        opens = [d["open"] for d in kline_data]
        highs = [d["high"] for d in kline_data]
        lows = [d["low"] for d in kline_data]
        closes = [d["close"] for d in kline_data]
        volumes = [d["volume"] for d in kline_data]
        
        # 创建蜡烛图数据序列
        dpg.add_candle_series(
            dates=dates,
            opens=opens,
            closes=closes,
            highs=highs,
            lows=lows,
            tag="candles",
            parent="y_axis",
            # A股风格:涨红跌绿
            bull_color=(255, 0, 0, 255),  # 上涨颜色:红色
            bear_color=(0, 255, 0, 255)   # 下跌颜色:绿色
        )
        
        # 创建成交量数据序列
        dpg.add_bar_series(
            x=dates,
            y=volumes,
            tag="volumes",
            parent="volume_axis"
        )
        
        return True
    except Exception as e:
        print(f"创建图表数据序列错误: {e}")
        return False


def regenerate_data():
    """重新生成随机数据"""
    try:
        generate_random_kline_data()
        
        # 清空现有数据序列
        if dpg.does_item_exist("candles"):
            dpg.delete_item("candles")
        if dpg.does_item_exist("volumes"):
            dpg.delete_item("volumes")
        
        # 创建新的数据序列
        create_chart_series()
        
        return True
    except Exception as e:
        print(f"重新生成数据错误: {e}")
        return False


def create_main_window():
    """创建主窗口"""
    with dpg.window(label="K线图分析系统", tag="main_window", width=1200, height=800):
        
        # 顶部工具栏
        with dpg.group(horizontal=True):
            dpg.add_text("时间周期:")
            dpg.add_radio_button(
                ["1M", "5M", "15M", "1H", "4H", "1D"],
                label="时间周期",
                default_value="1D",
                tag="timeframe_radio"
            )
            
            dpg.add_spacer(width=20)
            
            dpg.add_button(
                label="重新生成数据",
                callback=regenerate_data,
                tag="regenerate_btn",
                width=150
            )
        
        dpg.add_separator()
        
        # 图表区域
        with dpg.child_window(height=-1, width=-1, border=True):
            with dpg.plot(width=-1, height=-1, tag="kline_plot"):
                
                # 主图:K线蜡烛图
                with dpg.plot_axis(dpg.mvXAxis, label="时间", tag="x_axis"):
                    pass
                with dpg.plot_axis(dpg.mvYAxis, label="价格", tag="y_axis"):
                    pass
                
                # 副图:成交量柱状图
                with dpg.plot_axis(dpg.mvYAxis, label="成交量", tag="volume_axis", opposite=True):
                    pass


def main():
    """主函数"""
    try:
        # 初始化Dear PyGui
        dpg.create_context()
        
        # 配置主题(深色主题)
        with dpg.theme(tag="theme"):
            with dpg.theme_component(dpg.mvAll):
                dpg.add_theme_color(dpg.mvThemeCol_WindowBg, (30, 30, 30, 255))
                dpg.add_theme_color(dpg.mvThemeCol_ChildBg, (40, 40, 40, 255))
                dpg.add_theme_color(dpg.mvThemeCol_Text, (255, 255, 255, 255))
                dpg.add_theme_style(dpg.mvStyleVar_WindowPadding, 10, 10)
                dpg.add_theme_style(dpg.mvStyleVar_FramePadding, 5, 5)
        
        dpg.bind_theme("theme")
        
        # 创建主窗口
        create_main_window()
        
        # 生成初始数据
        generate_random_kline_data()
        
        # 创建图表数据序列
        create_chart_series()
        
        # 创建视图
        dpg.create_viewport(title="K线图分析系统", width=1200, height=800)
        dpg.setup_dearpygui()
        
        # 显示窗口
        dpg.show_viewport()
        dpg.start_dearpygui()
        dpg.destroy_context()
    
    except Exception as e:
        print(f"程序启动错误: {e}")
        import traceback
        print("完整错误信息:")
        print(traceback.format_exc())
    finally:
        if dpg.does_item_exist("main_window"):
            try:
                dpg.destroy_context()
            except:
                pass


if __name__ == "__main__":
    main()