系统概述

盈立证券交易系统是基于盈立证券OpenAPI开发的证券交易客户端,支持港股和美股交易。该系统提供账户管理、资金管理、实时行情查询等功能,采用Python开发,使用tkinter构建图形用户界面。

主要功能包括账户登录与管理、港股和美股交易、资金入金/出金操作、持仓查询与管理、实时行情查看、AI交易策略以及API功能测试。系统设计简洁直观,便于用户快速上手操作。

在这里插入图片描述

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import tkinter as tk
from tkinter import ttk, messagebox
import webbrowser
import threading
import sys
import os
# 将示例代码路径添加到系统路径中
sys.path.append(os.path.join(os.path.dirname(__file__), '..', 'open_api_demo_python', 'openapi-demo-py'))
from api_client import APIClient
from utils import ConfigUtil
try:
    from api import trade as example_trade
except ImportError:
    example_trade = None

class MainWindow:
    def __init__(self, parent, token):
        self.parent = parent
        self.token = token
        self.api_client = None
        self.example_api_client = None
        
        # 加载配置并设置token
        try:
            config = ConfigUtil.load_config()
            self.api_client = APIClient(config)
            # 如果不是测试token,则设置实际token
            if token != "test_token_123456":
                self.api_client.token = token
                
            # 尝试创建示例API客户端
            if example_trade:
                try:
                    # 设置环境变量
                    demo_path = os.path.join(os.path.dirname(__file__), '..', 'open_api_demo_python', 'openapi-demo-py')
                    os.environ['API_DEMO_HOMEPATH'] = demo_path
                    # 确保配置文件存在
                    config_path = os.path.join(demo_path, 'conf', 'config.json')
                    if os.path.exists(config_path):
                        self.example_api_client = example_trade.get_context_by_phonenumber(phoneNumber="13750062348")
                        # 如果我们有实际token,设置到示例客户端中
                        if token and token != "test_token_123456":
                            self.example_api_client.token = token
                        # 如果是测试模式,设置测试token
                        elif token == "test_token_123456":
                            self.example_api_client.token = "test_token_123456"
                    else:
                        print(f"示例API配置文件不存在: {config_path}")
                except Exception as e:
                    print(f"创建示例API客户端失败: {str(e)}")
        except Exception as e:
            messagebox.showerror("错误", f"加载配置失败: {str(e)}")
            return
        
        # 创建主界面
        self.create_widgets()
        
    def create_widgets(self):
        # 创建笔记本控件(标签页)
        self.notebook = ttk.Notebook(self.parent)
        self.notebook.grid(row=0, column=0, sticky=(tk.W, tk.E, tk.N, tk.S))
        
        # 配置网格权重
        self.parent.columnconfigure(0, weight=1)
        self.parent.rowconfigure(0, weight=1)
        
        # 创建各个功能标签页
        self.create_account_frame()
        self.create_hk_trade_frame()
        self.create_us_trade_frame()
        self.create_fund_frame()
        self.create_ai_strategy_frame()  # 添加AI交易策略页面
        self.create_demo_frame()
        
    def create_account_frame(self):
        """创建账户管理标签页"""
        self.account_frame = ttk.Frame(self.notebook, padding="10")
        self.notebook.add(self.account_frame, text="账户管理")
        
        # 标题
        title_label = ttk.Label(self.account_frame, text="账户信息", font=("Arial", 14, "bold"))
        title_label.grid(row=0, column=0, columnspan=2, pady=(0, 20))
        
        # 持仓信息
        holdings_label = ttk.Label(self.account_frame, text="持仓信息:", font=("Arial", 12))
        holdings_label.grid(row=1, column=0, sticky=tk.W, pady=5)
        
        # 持仓列表
        self.holdings_tree = ttk.Treeview(self.account_frame, columns=("证券代码", "证券名称", "持仓数量", "可用数量", "成本价", "当前价", "盈亏"), show="headings", height=10)
        
        # 设置列标题
        for col in self.holdings_tree["columns"]:
            self.holdings_tree.heading(col, text=col)
            self.holdings_tree.column(col, width=100)
            
        self.holdings_tree.grid(row=2, column=0, columnspan=2, pady=10, sticky=(tk.W, tk.E))
        
        # 滚动条
        holdings_scroll = ttk.Scrollbar(self.account_frame, orient="vertical", command=self.holdings_tree.yview)
        holdings_scroll.grid(row=2, column=2, sticky=(tk.N, tk.S))
        self.holdings_tree.configure(yscrollcommand=holdings_scroll.set)
        
        # 刷新按钮
        refresh_button = ttk.Button(self.account_frame, text="刷新持仓", command=self.refresh_holdings)
        refresh_button.grid(row=3, column=0, columnspan=2, pady=10)
        
        # 交易员管理
        trader_label = ttk.Label(self.account_frame, text="交易员管理:", font=("Arial", 12))
        trader_label.grid(row=4, column=0, sticky=tk.W, pady=(20, 5))
        
        # 交易员列表
        self.trader_tree = ttk.Treeview(self.account_frame, columns=("交易员ID", "姓名", "权限"), show="headings", height=5)
        
        # 设置列标题
        for col in self.trader_tree["columns"]:
            self.trader_tree.heading(col, text=col)
            self.trader_tree.column(col, width=150)
            
        self.trader_tree.grid(row=5, column=0, columnspan=2, pady=10, sticky=(tk.W, tk.E))
        
        # 滚动条
        trader_scroll = ttk.Scrollbar(self.account_frame, orient="vertical", command=self.trader_tree.yview)
        trader_scroll.grid(row=5, column=2, sticky=(tk.N, tk.S))
        self.trader_tree.configure(yscrollcommand=trader_scroll.set)
        
        # 添加交易员按钮
        add_trader_button = ttk.Button(self.account_frame, text="添加交易员")
        add_trader_button.grid(row=6, column=0, pady=5, padx=5, sticky=tk.W)
        
        # 删除交易员按钮
        delete_trader_button = ttk.Button(self.account_frame, text="删除交易员")
        delete_trader_button.grid(row=6, column=1, pady=5, padx=5, sticky=tk.W)
        
        # 设置列权重
        self.account_frame.columnconfigure(0, weight=1)
        self.account_frame.columnconfigure(1, weight=1)
        
    def create_hk_trade_frame(self):
        """创建港股交易标签页"""
        self.hk_trade_frame = ttk.Frame(self.notebook, padding="10")
        self.notebook.add(self.hk_trade_frame, text="港股交易")
        
        # 标题
        title_label = ttk.Label(self.hk_trade_frame, text="港股交易", font=("Arial", 14, "bold"))
        title_label.grid(row=0, column=0, columnspan=2, pady=(0, 20))
        
        # 股票代码搜索
        code_label = ttk.Label(self.hk_trade_frame, text="股票代码:")
        code_label.grid(row=1, column=0, sticky=tk.W, pady=5)
        
        self.hk_code_var = tk.StringVar()
        self.hk_code_entry = ttk.Entry(self.hk_trade_frame, textvariable=self.hk_code_var, width=20)
        self.hk_code_entry.grid(row=1, column=1, sticky=tk.W, pady=5)
        
        # 搜索按钮
        search_button = ttk.Button(self.hk_trade_frame, text="搜索", command=self.search_hk_stock)
        search_button.grid(row=1, column=2, pady=5, padx=5)
        
        # 股票信息显示
        info_frame = ttk.LabelFrame(self.hk_trade_frame, text="股票信息", padding="10")
        info_frame.grid(row=2, column=0, columnspan=3, pady=10, sticky=(tk.W, tk.E))
        
        self.hk_stock_info_var = tk.StringVar()
        self.hk_stock_info_var.set("请输入股票代码进行搜索")
        self.hk_stock_info_label = ttk.Label(info_frame, textvariable=self.hk_stock_info_var)
        self.hk_stock_info_label.grid(row=0, column=0)
        
        # 交易信息输入
        trade_frame = ttk.LabelFrame(self.hk_trade_frame, text="交易信息", padding="10")
        trade_frame.grid(row=3, column=0, columnspan=3, pady=10, sticky=(tk.W, tk.E))
        
        # 交易方向
        direction_label = ttk.Label(trade_frame, text="交易方向:")
        direction_label.grid(row=0, column=0, sticky=tk.W, pady=5)
        
        self.hk_direction_var = tk.StringVar(value="买入")
        ttk.Radiobutton(trade_frame, text="买入", variable=self.hk_direction_var, value="买入").grid(row=0, column=1, sticky=tk.W)
        ttk.Radiobutton(trade_frame, text="卖出", variable=self.hk_direction_var, value="卖出").grid(row=0, column=2, sticky=tk.W)
        
        # 数量
        quantity_label = ttk.Label(trade_frame, text="数量:")
        quantity_label.grid(row=1, column=0, sticky=tk.W, pady=5)
        
        self.hk_quantity_var = tk.StringVar()
        self.hk_quantity_entry = ttk.Entry(trade_frame, textvariable=self.hk_quantity_var, width=20)
        self.hk_quantity_entry.grid(row=1, column=1, sticky=tk.W, pady=5)
        
        # 价格
        price_label = ttk.Label(trade_frame, text="价格:")
        price_label.grid(row=2, column=0, sticky=tk.W, pady=5)
        
        self.hk_price_var = tk.StringVar()
        self.hk_price_entry = ttk.Entry(trade_frame, textvariable=self.hk_price_var, width=20)
        self.hk_price_entry.grid(row=2, column=1, sticky=tk.W, pady=5)
        
        # 下单按钮
        self.hk_order_button = ttk.Button(trade_frame, text="下单", command=self.place_hk_order)
        self.hk_order_button.grid(row=3, column=0, columnspan=3, pady=20)
        
        # 设置列权重
        self.hk_trade_frame.columnconfigure(1, weight=1)
        
    def create_us_trade_frame(self):
        """创建美股交易标签页"""
        self.us_trade_frame = ttk.Frame(self.notebook, padding="10")
        self.notebook.add(self.us_trade_frame, text="美股交易")
        
        # 标题
        title_label = ttk.Label(self.us_trade_frame, text="美股交易", font=("Arial", 14, "bold"))
        title_label.grid(row=0, column=0, columnspan=2, pady=(0, 20))
        
        # 股票代码搜索
        code_label = ttk.Label(self.us_trade_frame, text="股票代码:")
        code_label.grid(row=1, column=0, sticky=tk.W, pady=5)
        
        self.us_code_var = tk.StringVar()
        self.us_code_entry = ttk.Entry(self.us_trade_frame, textvariable=self.us_code_var, width=20)
        self.us_code_entry.grid(row=1, column=1, sticky=tk.W, pady=5)
        
        # 搜索按钮
        search_button = ttk.Button(self.us_trade_frame, text="搜索", command=self.search_us_stock)
        search_button.grid(row=1, column=2, pady=5, padx=5)
        
        # 股票信息显示
        info_frame = ttk.LabelFrame(self.us_trade_frame, text="股票信息", padding="10")
        info_frame.grid(row=2, column=0, columnspan=3, pady=10, sticky=(tk.W, tk.E))
        
        self.us_stock_info_var = tk.StringVar()
        self.us_stock_info_var.set("请输入股票代码进行搜索")
        self.us_stock_info_label = ttk.Label(info_frame, textvariable=self.us_stock_info_var)
        self.us_stock_info_label.grid(row=0, column=0)
        
        # 交易信息输入
        trade_frame = ttk.LabelFrame(self.us_trade_frame, text="交易信息", padding="10")
        trade_frame.grid(row=3, column=0, columnspan=3, pady=10, sticky=(tk.W, tk.E))
        
        # 交易方向
        direction_label = ttk.Label(trade_frame, text="交易方向:")
        direction_label.grid(row=0, column=0, sticky=tk.W, pady=5)
        
        self.us_direction_var = tk.StringVar(value="买入")
        ttk.Radiobutton(trade_frame, text="买入", variable=self.us_direction_var, value="买入").grid(row=0, column=1, sticky=tk.W)
        ttk.Radiobutton(trade_frame, text="卖出", variable=self.us_direction_var, value="卖出").grid(row=0, column=2, sticky=tk.W)
        
        # 数量
        quantity_label = ttk.Label(trade_frame, text="数量:")
        quantity_label.grid(row=1, column=0, sticky=tk.W, pady=5)
        
        self.us_quantity_var = tk.StringVar()
        self.us_quantity_entry = ttk.Entry(trade_frame, textvariable=self.us_quantity_var, width=20)
        self.us_quantity_entry.grid(row=1, column=1, sticky=tk.W, pady=5)
        
        # 价格
        price_label = ttk.Label(trade_frame, text="价格:")
        price_label.grid(row=2, column=0, sticky=tk.W, pady=5)
        
        self.us_price_var = tk.StringVar()
        self.us_price_entry = ttk.Entry(trade_frame, textvariable=self.us_price_var, width=20)
        self.us_price_entry.grid(row=2, column=1, sticky=tk.W, pady=5)
        
        # 下单按钮
        self.us_order_button = ttk.Button(trade_frame, text="下单", command=self.place_us_order)
        self.us_order_button.grid(row=3, column=0, columnspan=3, pady=20)
        
        # 设置列权重
        self.us_trade_frame.columnconfigure(1, weight=1)
        
    def create_fund_frame(self):
        """创建资金管理标签页"""
        self.fund_frame = ttk.Frame(self.notebook, padding="10")
        self.notebook.add(self.fund_frame, text="资金管理")
        
        # 标题
        title_label = ttk.Label(self.fund_frame, text="资金管理", font=("Arial", 14, "bold"))
        title_label.grid(row=0, column=0, columnspan=2, pady=(0, 20))
        
        # 资金操作
        operation_frame = ttk.LabelFrame(self.fund_frame, text="资金操作", padding="10")
        operation_frame.grid(row=1, column=0, columnspan=2, pady=10, sticky=(tk.W, tk.E))
        
        # 操作类型
        type_label = ttk.Label(operation_frame, text="操作类型:")
        type_label.grid(row=0, column=0, sticky=tk.W, pady=5)
        
        self.fund_type_var = tk.StringVar(value="入金")
        ttk.Radiobutton(operation_frame, text="入金", variable=self.fund_type_var, value="入金").grid(row=0, column=1, sticky=tk.W)
        ttk.Radiobutton(operation_frame, text="出金", variable=self.fund_type_var, value="出金").grid(row=0, column=2, sticky=tk.W)
        
        # 金额
        amount_label = ttk.Label(operation_frame, text="金额:")
        amount_label.grid(row=1, column=0, sticky=tk.W, pady=5)
        
        self.fund_amount_var = tk.StringVar()
        self.fund_amount_entry = ttk.Entry(operation_frame, textvariable=self.fund_amount_var, width=20)
        self.fund_amount_entry.grid(row=1, column=1, sticky=tk.W, pady=5)
        
        # 银行信息
        bank_label = ttk.Label(operation_frame, text="银行:")
        bank_label.grid(row=2, column=0, sticky=tk.W, pady=5)
        
        self.bank_var = tk.StringVar()
        banks = ["工商银行", "建设银行", "农业银行", "中国银行", "招商银行"]
        self.bank_combo = ttk.Combobox(operation_frame, textvariable=self.bank_var, values=banks, state="readonly", width=20)
        self.bank_combo.grid(row=2, column=1, sticky=tk.W, pady=5)
        self.bank_combo.set(banks[0])
        
        # 确认按钮
        confirm_button = ttk.Button(operation_frame, text="确认", command=self.process_fund)
        confirm_button.grid(row=3, column=0, columnspan=3, pady=20)
        
        # 资金流水
        history_label = ttk.Label(self.fund_frame, text="资金流水:", font=("Arial", 12))
        history_label.grid(row=2, column=0, sticky=tk.W, pady=(20, 5))
        
        # 流水列表
        self.history_tree = ttk.Treeview(self.fund_frame, columns=("时间", "类型", "金额", "状态"), show="headings", height=8)
        
        # 设置列标题
        for col in self.history_tree["columns"]:
            self.history_tree.heading(col, text=col)
            self.history_tree.column(col, width=150)
            
        self.history_tree.grid(row=3, column=0, columnspan=2, pady=10, sticky=(tk.W, tk.E))
        
        # 滚动条
        history_scroll = ttk.Scrollbar(self.fund_frame, orient="vertical", command=self.history_tree.yview)
        history_scroll.grid(row=3, column=2, sticky=(tk.N, tk.S))
        self.history_tree.configure(yscrollcommand=history_scroll.set)
        
        # 设置列权重
        self.fund_frame.columnconfigure(0, weight=1)
        
    def create_ai_strategy_frame(self):
        """创建AI交易策略标签页"""
        self.ai_strategy_frame = ttk.Frame(self.notebook, padding="10")
        self.notebook.add(self.ai_strategy_frame, text="AI交易策略")
        
        # 标题
        title_label = ttk.Label(self.ai_strategy_frame, text="AI交易策略", font=("Arial", 14, "bold"))
        title_label.grid(row=0, column=0, columnspan=3, pady=(0, 20))
        
        # AI模型选择框架
        model_frame = ttk.LabelFrame(self.ai_strategy_frame, text="AI模型配置", padding="10")
        model_frame.grid(row=1, column=0, columnspan=3, pady=10, sticky=(tk.W, tk.E))
        
        # 模型提供商
        provider_label = ttk.Label(model_frame, text="模型提供商:")
        provider_label.grid(row=0, column=0, sticky=tk.W, pady=5)
        
        self.ai_provider_var = tk.StringVar(value="豆包")
        providers = ["豆包", "DeepSeek", "通义千问", "文心一言", "讯飞星火"]
        self.provider_combo = ttk.Combobox(model_frame, textvariable=self.ai_provider_var, values=providers, state="readonly", width=20)
        self.provider_combo.grid(row=0, column=1, sticky=tk.W, pady=5, padx=(10, 0))
        self.provider_combo.set(providers[0])
        
        # API密钥
        api_key_label = ttk.Label(model_frame, text="API密钥:")
        api_key_label.grid(row=1, column=0, sticky=tk.W, pady=5)
        
        self.api_key_var = tk.StringVar()
        self.api_key_entry = ttk.Entry(model_frame, textvariable=self.api_key_var, width=40, show="*")
        self.api_key_entry.grid(row=1, column=1, sticky=tk.W, pady=5, padx=(10, 0))
        
        # 模型名称
        model_name_label = ttk.Label(model_frame, text="模型名称:")
        model_name_label.grid(row=2, column=0, sticky=tk.W, pady=5)
        
        self.model_name_var = tk.StringVar()
        self.model_name_entry = ttk.Entry(model_frame, textvariable=self.model_name_var, width=40)
        self.model_name_entry.grid(row=2, column=1, sticky=tk.W, pady=5, padx=(10, 0))
        self.model_name_entry.insert(0, "default-model")  # 默认模型名称
        
        # 策略配置框架
        strategy_frame = ttk.LabelFrame(self.ai_strategy_frame, text="策略配置", padding="10")
        strategy_frame.grid(row=2, column=0, columnspan=3, pady=10, sticky=(tk.W, tk.E))
        
        # 策略名称
        strategy_name_label = ttk.Label(strategy_frame, text="策略名称:")
        strategy_name_label.grid(row=0, column=0, sticky=tk.W, pady=5)
        
        self.strategy_name_var = tk.StringVar()
        self.strategy_name_entry = ttk.Entry(strategy_frame, textvariable=self.strategy_name_var, width=30)
        self.strategy_name_entry.grid(row=0, column=1, sticky=tk.W, pady=5, padx=(10, 0))
        
        # 交易市场
        market_label = ttk.Label(strategy_frame, text="交易市场:")
        market_label.grid(row=1, column=0, sticky=tk.W, pady=5)
        
        self.market_var = tk.StringVar(value="港股")
        ttk.Radiobutton(strategy_frame, text="港股", variable=self.market_var, value="港股").grid(row=1, column=1, sticky=tk.W, padx=(10, 0))
        ttk.Radiobutton(strategy_frame, text="美股", variable=self.market_var, value="美股").grid(row=1, column=2, sticky=tk.W)
        ttk.Radiobutton(strategy_frame, text="A股", variable=self.market_var, value="A股").grid(row=1, column=3, sticky=tk.W)
        
        # 风险等级
        risk_label = ttk.Label(strategy_frame, text="风险等级:")
        risk_label.grid(row=2, column=0, sticky=tk.W, pady=5)
        
        self.risk_var = tk.StringVar(value="中等")
        risk_levels = ["低", "中等", "高"]
        self.risk_combo = ttk.Combobox(strategy_frame, textvariable=self.risk_var, values=risk_levels, state="readonly", width=10)
        self.risk_combo.grid(row=2, column=1, sticky=tk.W, pady=5, padx=(10, 0))
        self.risk_combo.set(risk_levels[1])
        
        # 策略描述
        description_label = ttk.Label(strategy_frame, text="策略描述:")
        description_label.grid(row=3, column=0, sticky=tk.NW, pady=5)
        
        self.strategy_description_text = tk.Text(strategy_frame, height=5, width=50)
        description_scroll = ttk.Scrollbar(strategy_frame, orient="vertical", command=self.strategy_description_text.yview)
        self.strategy_description_text.configure(yscrollcommand=description_scroll.set)
        
        self.strategy_description_text.grid(row=3, column=1, columnspan=2, pady=5, padx=(10, 0), sticky=(tk.W, tk.E))
        description_scroll.grid(row=3, column=3, sticky=(tk.N, tk.S))
        
        # 操作按钮框架
        button_frame = ttk.Frame(self.ai_strategy_frame)
        button_frame.grid(row=3, column=0, columnspan=3, pady=20)
        
        # 保存策略按钮
        save_strategy_button = ttk.Button(button_frame, text="保存策略", command=self.save_ai_strategy)
        save_strategy_button.grid(row=0, column=0, padx=10)
        
        # 测试策略按钮
        test_strategy_button = ttk.Button(button_frame, text="测试策略", command=self.test_ai_strategy)
        test_strategy_button.grid(row=0, column=1, padx=10)
        
        # 启动策略按钮
        start_strategy_button = ttk.Button(button_frame, text="启动策略", command=self.start_ai_strategy)
        start_strategy_button.grid(row=0, column=2, padx=10)
        
        # 停止策略按钮
        stop_strategy_button = ttk.Button(button_frame, text="停止策略", command=self.stop_ai_strategy)
        stop_strategy_button.grid(row=0, column=3, padx=10)
        
        # 策略状态显示
        status_frame = ttk.LabelFrame(self.ai_strategy_frame, text="策略状态", padding="10")
        status_frame.grid(row=4, column=0, columnspan=3, pady=10, sticky=(tk.W, tk.E))
        
        self.strategy_status_var = tk.StringVar(value="未启动")
        status_label = ttk.Label(status_frame, text="当前状态:")
        status_label.grid(row=0, column=0, sticky=tk.W, pady=5)
        
        self.strategy_status_display = ttk.Label(status_frame, textvariable=self.strategy_status_var, foreground="red")
        self.strategy_status_display.grid(row=0, column=1, sticky=tk.W, pady=5, padx=(10, 0))
        
        # 策略日志显示
        log_frame = ttk.LabelFrame(self.ai_strategy_frame, text="策略日志", padding="10")
        log_frame.grid(row=5, column=0, columnspan=3, pady=10, sticky=(tk.W, tk.E, tk.N, tk.S))
        
        self.strategy_log_text = tk.Text(log_frame, height=10, width=80)
        log_scroll = ttk.Scrollbar(log_frame, orient="vertical", command=self.strategy_log_text.yview)
        self.strategy_log_text.configure(yscrollcommand=log_scroll.set)
        
        self.strategy_log_text.grid(row=0, column=0, sticky=(tk.W, tk.E, tk.N, tk.S))
        log_scroll.grid(row=0, column=1, sticky=(tk.N, tk.S))
        
        # 清空日志按钮
        clear_log_button = ttk.Button(log_frame, text="清空日志", command=self.clear_ai_strategy_log)
        clear_log_button.grid(row=1, column=0, pady=10)
        
        # 设置列权重
        self.ai_strategy_frame.columnconfigure(0, weight=1)
        self.ai_strategy_frame.rowconfigure(5, weight=1)
        log_frame.columnconfigure(0, weight=1)
        log_frame.rowconfigure(0, weight=1)
        
    def save_ai_strategy(self):
        """保存AI交易策略"""
        # 获取策略配置信息
        strategy_name = self.strategy_name_var.get()
        provider = self.ai_provider_var.get()
        api_key = self.api_key_var.get()
        model_name = self.model_name_var.get()
        market = self.market_var.get()
        risk_level = self.risk_var.get()
        description = self.strategy_description_text.get("1.0", tk.END).strip()
        
        # 验证必填字段
        if not strategy_name:
            messagebox.showwarning("警告", "请输入策略名称")
            return
            
        if not api_key:
            messagebox.showwarning("警告", "请输入API密钥")
            return
            
        # 显示保存成功信息
        messagebox.showinfo("成功", f"策略 '{strategy_name}' 已保存")
        self.append_ai_strategy_log(f"策略 '{strategy_name}' 已保存")
        
    def test_ai_strategy(self):
        """测试AI交易策略"""
        strategy_name = self.strategy_name_var.get()
        if not strategy_name:
            messagebox.showwarning("警告", "请输入策略名称")
            return
            
        self.append_ai_strategy_log(f"正在测试策略 '{strategy_name}'...")
        # 这里可以添加实际的测试逻辑
        self.append_ai_strategy_log("测试完成")
        
    def start_ai_strategy(self):
        """启动AI交易策略"""
        strategy_name = self.strategy_name_var.get()
        if not strategy_name:
            messagebox.showwarning("警告", "请输入策略名称")
            return
            
        self.strategy_status_var.set("运行中")
        self.strategy_status_display.config(foreground="green")
        self.append_ai_strategy_log(f"策略 '{strategy_name}' 已启动")
        
    def stop_ai_strategy(self):
        """停止AI交易策略"""
        strategy_name = self.strategy_name_var.get()
        self.strategy_status_var.set("已停止")
        self.strategy_status_display.config(foreground="red")
        self.append_ai_strategy_log(f"策略 '{strategy_name}' 已停止")
        
    def clear_ai_strategy_log(self):
        """清空AI策略日志"""
        self.strategy_log_text.delete(1.0, tk.END)
        
    def append_ai_strategy_log(self, text):
        """添加AI策略日志"""
        import datetime
        timestamp = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
        self.strategy_log_text.insert(tk.END, f"[{timestamp}] {text}\n")
        self.strategy_log_text.see(tk.END)
        
    def refresh_holdings(self):
        """刷新持仓信息"""
        # 在新线程中获取持仓信息
        thread = threading.Thread(target=self._refresh_holdings_thread)
        thread.daemon = True
        thread.start()
        
    def _refresh_holdings_thread(self):
        """刷新持仓信息线程函数"""
        try:
            # 获取港股持仓
            hk_result = self.api_client.stock_holding("0")  # 0表示港股
            # 获取美股持仓
            us_result = self.api_client.stock_holding("1")  # 1表示美股
            
            # 更新UI
            self.parent.after(0, lambda: self._update_holdings_ui(hk_result, us_result))
        except Exception as e:
            self.parent.after(0, lambda: messagebox.showerror("错误", f"获取持仓信息失败: {str(e)}"))
            
    def _update_holdings_ui(self, hk_result, us_result):
        """更新持仓信息UI"""
        # 清空现有数据
        for item in self.holdings_tree.get_children():
            self.holdings_tree.delete(item)
            
        # 添加港股持仓
        if hk_result.get("success"):
            holdings = hk_result.get("data", [])
            for holding in holdings:
                self.holdings_tree.insert("", "end", values=(
                    holding.get("stockCode", ""),
                    holding.get("stockName", ""),
                    holding.get("holdingQuantity", ""),
                    holding.get("availableQuantity", ""),
                    holding.get("costPrice", ""),
                    holding.get("currentPrice", ""),
                    holding.get("profitLoss", "")
                ))
                
        # 添加美股持仓
        if us_result.get("success"):
            holdings = us_result.get("data", [])
            for holding in holdings:
                self.holdings_tree.insert("", "end", values=(
                    holding.get("stockCode", ""),
                    holding.get("stockName", ""),
                    holding.get("holdingQuantity", ""),
                    holding.get("availableQuantity", ""),
                    holding.get("costPrice", ""),
                    holding.get("currentPrice", ""),
                    holding.get("profitLoss", "")
                ))
                
    def search_hk_stock(self):
        """搜索港股"""
        code = self.hk_code_var.get().strip()
        if not code:
            messagebox.showwarning("警告", "请输入股票代码")
            return
            
        # 模拟搜索结果
        self.hk_stock_info_var.set(f"股票代码: {code}\n股票名称: 示例港股\n当前价格: 100.50 HKD")
        
    def search_us_stock(self):
        """搜索美股"""
        code = self.us_code_var.get().strip()
        if not code:
            messagebox.showwarning("警告", "请输入股票代码")
            return
            
        # 模拟搜索结果
        self.us_stock_info_var.set(f"股票代码: {code}\n股票名称: 示例美股\n当前价格: 150.25 USD")
        
    def place_hk_order(self):
        """下单港股"""
        code = self.hk_code_var.get().strip()
        quantity = self.hk_quantity_var.get().strip()
        price = self.hk_price_var.get().strip()
        direction = self.hk_direction_var.get()
        
        if not code or not quantity or not price:
            messagebox.showwarning("警告", "请填写完整的交易信息")
            return
            
        try:
            quantity = int(quantity)
            price = float(price)
        except ValueError:
            messagebox.showwarning("警告", "数量和价格必须为有效数字")
            return
            
        # 禁用按钮并显示状态
        self.hk_order_button.config(state="disabled")
        self.hk_order_button.config(text="下单中...")
        self.parent.update()
        
        # 在新线程中下单
        thread = threading.Thread(target=self._place_hk_order_thread, args=(code, quantity, price, direction))
        thread.daemon = True
        thread.start()
        
    def _place_hk_order_thread(self, code, quantity, price, direction):
        """下单港股线程函数"""
        try:
            # 调用API下单
            entrust_type = "0" if direction == "买入" else "1"  # 0买入,1卖出
            result = self.api_client.entrust_order(
                entrust_amount=str(quantity),
                entrust_price=str(price),
                entrust_prop="0",  # 普通委托
                entrust_type=entrust_type,
                exchange_type="0",  # 港股
                stock_code=code
            )
            
            # 更新UI
            if result.get("success"):
                self.parent.after(0, lambda: messagebox.showinfo("成功", "下单成功"))
            else:
                self.parent.after(0, lambda: messagebox.showerror("错误", f"下单失败: {result.get('message')}"))
        except Exception as e:
            self.parent.after(0, lambda: messagebox.showerror("错误", f"下单异常: {str(e)}"))
        finally:
            self.parent.after(0, lambda: self.hk_order_button.config(state="normal"))
            self.parent.after(0, lambda: self.hk_order_button.config(text="下单"))
            
    def place_us_order(self):
        """下单美股"""
        code = self.us_code_var.get().strip()
        quantity = self.us_quantity_var.get().strip()
        price = self.us_price_var.get().strip()
        direction = self.us_direction_var.get()
        
        if not code or not quantity or not price:
            messagebox.showwarning("警告", "请填写完整的交易信息")
            return
            
        try:
            quantity = int(quantity)
            price = float(price)
        except ValueError:
            messagebox.showwarning("警告", "数量和价格必须为有效数字")
            return
            
        # 禁用按钮并显示状态
        self.us_order_button.config(state="disabled")
        self.us_order_button.config(text="下单中...")
        self.parent.update()
        
        # 在新线程中下单
        thread = threading.Thread(target=self._place_us_order_thread, args=(code, quantity, price, direction))
        thread.daemon = True
        thread.start()
        
    def _place_us_order_thread(self, code, quantity, price, direction):
        """下单美股线程函数"""
        try:
            # 调用API下单
            entrust_type = "0" if direction == "买入" else "1"  # 0买入,1卖出
            result = self.api_client.entrust_order(
                entrust_amount=str(quantity),
                entrust_price=str(price),
                entrust_prop="0",  # 普通委托
                entrust_type=entrust_type,
                exchange_type="1",  # 美股
                stock_code=code
            )
            
            # 更新UI
            if result.get("success"):
                self.parent.after(0, lambda: messagebox.showinfo("成功", "下单成功"))
            else:
                self.parent.after(0, lambda: messagebox.showerror("错误", f"下单失败: {result.get('message')}"))
        except Exception as e:
            self.parent.after(0, lambda: messagebox.showerror("错误", f"下单异常: {str(e)}"))
        finally:
            self.parent.after(0, lambda: self.us_order_button.config(state="normal"))
            self.parent.after(0, lambda: self.us_order_button.config(text="下单"))
            
    def process_fund(self):
        """处理资金操作"""
        amount = self.fund_amount_var.get().strip()
        fund_type = self.fund_type_var.get()
        bank = self.bank_var.get()
        
        if not amount:
            messagebox.showwarning("警告", "请输入金额")
            return
            
        try:
            amount = float(amount)
        except ValueError:
            messagebox.showwarning("警告", "金额必须为有效数字")
            return
            
        # 模拟资金操作
        messagebox.showinfo("成功", f"{fund_type}操作已提交\n金额: {amount}\n银行: {bank}\n请在银行端确认操作")
        
    def hide(self):
        """隐藏主窗口"""
        self.notebook.grid_forget()
        
    def create_demo_frame(self):
        """创建Demo功能测试标签页"""
        self.demo_frame = ttk.Frame(self.notebook, padding="10")
        self.notebook.add(self.demo_frame, text="Demo功能测试")
        
        # 标题
        title_label = ttk.Label(self.demo_frame, text="盈立证券API Demo功能测试", font=("Arial", 14, "bold"))
        title_label.grid(row=0, column=0, columnspan=3, pady=(0, 20))
        
        # 创建功能按钮框架
        button_frame = ttk.LabelFrame(self.demo_frame, text="API功能测试", padding="10")
        button_frame.grid(row=1, column=0, columnspan=3, pady=10, sticky=(tk.W, tk.E))
        
        # 第一行按钮
        ttk.Button(button_frame, text="基础信息查询", command=self.test_basicinfo).grid(row=0, column=0, pady=5, padx=5, sticky=tk.W)
        ttk.Button(button_frame, text="市场状态查询", command=self.test_marketstate).grid(row=0, column=1, pady=5, padx=5, sticky=tk.W)
        ttk.Button(button_frame, text="实时行情查询", command=self.test_realtime).grid(row=0, column=2, pady=5, padx=5, sticky=tk.W)
        
        # 第二行按钮
        ttk.Button(button_frame, text="分时数据查询", command=self.test_timeline).grid(row=1, column=0, pady=5, padx=5, sticky=tk.W)
        ttk.Button(button_frame, text="K线数据查询", command=self.test_kline).grid(row=1, column=1, pady=5, padx=5, sticky=tk.W)
        ttk.Button(button_frame, text="买卖盘查询", command=self.test_orderbook).grid(row=1, column=2, pady=5, padx=5, sticky=tk.W)
        
        # 第三行按钮
        ttk.Button(button_frame, text="逐笔成交查询", command=self.test_tick).grid(row=2, column=0, pady=5, padx=5, sticky=tk.W)
        ttk.Button(button_frame, text="今日委托查询", command=self.test_today_entrust).grid(row=2, column=1, pady=5, padx=5, sticky=tk.W)
        ttk.Button(button_frame, text="持仓查询", command=self.test_stock_holding).grid(row=2, column=2, pady=5, padx=5, sticky=tk.W)
        
        # 第四行按钮
        ttk.Button(button_frame, text="IPO列表查询", command=self.test_ipo_list).grid(row=3, column=0, pady=5, padx=5, sticky=tk.W)
        ttk.Button(button_frame, text="下单测试", command=self.test_entrust_order).grid(row=3, column=1, pady=5, padx=5, sticky=tk.W)
        ttk.Button(button_frame, text="改单测试", command=self.test_modify_order).grid(row=3, column=2, pady=5, padx=5, sticky=tk.W)
        
        # 结果显示区域
        result_frame = ttk.LabelFrame(self.demo_frame, text="测试结果", padding="10")
        result_frame.grid(row=2, column=0, columnspan=3, pady=20, sticky=(tk.W, tk.E, tk.N, tk.S))
        
        # 创建文本框和滚动条
        self.result_text = tk.Text(result_frame, height=15, width=80)
        scrollbar = ttk.Scrollbar(result_frame, orient="vertical", command=self.result_text.yview)
        self.result_text.configure(yscrollcommand=scrollbar.set)
        
        self.result_text.grid(row=0, column=0, sticky=(tk.W, tk.E, tk.N, tk.S))
        scrollbar.grid(row=0, column=1, sticky=(tk.N, tk.S))
        
        # 清空结果按钮
        ttk.Button(result_frame, text="清空结果", command=self.clear_result).grid(row=1, column=0, pady=10)
        
        # 设置列权重
        self.demo_frame.columnconfigure(0, weight=1)
        self.demo_frame.rowconfigure(2, weight=1)
        result_frame.columnconfigure(0, weight=1)
        result_frame.rowconfigure(0, weight=1)
        
    def clear_result(self):
        """清空测试结果"""
        self.result_text.delete(1.0, tk.END)
        
    def append_result(self, text):
        """添加测试结果"""
        self.result_text.insert(tk.END, text + "\n")
        self.result_text.see(tk.END)
        
    def test_basicinfo(self):
        """测试基础信息查询"""
        self.append_result("=== 基础信息查询测试 ===")
        
        # 优先使用示例API
        if self.example_api_client:
            try:
                self.append_result("使用示例API查询基础信息...")
                # 示例API不需要token也可以查询基础信息
                result = self.example_api_client.basicinfo('us')
                # 检查是否是Response对象(表示HTTP错误)
                if hasattr(result, 'status_code'):
                    if result.status_code == 200:
                        try:
                            json_result = result.json()
                            self.append_result(f"结果: {json_result}")
                        except:
                            self.append_result(f"结果: {result.text}")
                    else:
                        self.append_result(f"示例API返回HTTP错误: {result.status_code}")
                        # 回退到自定义API
                        self._fallback_to_custom_api("basicinfo", "us")
                        return
                else:
                    self.append_result(f"结果: {result}")
                return
            except Exception as e:
                self.append_result(f"示例API调用失败: {str(e)}")
                # 回退到自定义API
                self._fallback_to_custom_api("basicinfo", "us")
                return
        
        # 回退到我们自己的API客户端
        self._fallback_to_custom_api("basicinfo", "us")
    
    def _fallback_to_custom_api(self, api_name, *args):
        """回退到自定义API"""
        if not self.api_client:
            self.append_result("API客户端未初始化")
            return
            
        # 在测试模式下,我们已经有模拟数据了
        if self.api_client.token == "test_token_123456":
            self.append_result(f"测试模式:使用模拟{api_name}数据")
            if api_name == "basicinfo":
                result = self.api_client.basicinfo(args[0] if args else "us")
            elif api_name == "marketstate":
                result = self.api_client.marketstate(args[0] if args else "us")
            elif api_name == "realtime":
                result = self.api_client.realtime(args[0] if args else ["sz000001"])
            elif api_name == "timeline":
                result = self.api_client.timeline(args[0] if args else "sz000001", args[1] if len(args) > 1 else 0)
            elif api_name == "kline":
                result = self.api_client.kline(args[0] if args else "sz000001", args[1] if len(args) > 1 else 7, 
                                             args[2] if len(args) > 2 else 20240509160000000, 
                                             args[3] if len(args) > 3 else 0, 
                                             args[4] if len(args) > 4 else 100)
            elif api_name == "orderbook":
                result = self.api_client.orderbook(args[0] if args else "sz000001")
            elif api_name == "tick":
                result = self.api_client.tick(args[0] if args else "sz000001", 
                                            args[1] if len(args) > 1 else 20201221160000000, 
                                            args[2] if len(args) > 2 else 0, 
                                            args[3] if len(args) > 3 else 2, 
                                            args[4] if len(args) > 4 else 1)
            elif api_name == "today_entrust":
                result = self.api_client.today_entrust(args[0] if args else "0")
            elif api_name == "stock_holding":
                result = self.api_client.stock_holding(args[0] if args else "0")
            elif api_name == "ipo_list":
                result = self.api_client.ipo_list()
            elif api_name == "entrust_order":
                result = self.api_client.entrust_order(
                    entrust_amount='100',
                    entrust_price='250',
                    entrust_prop='0',
                    entrust_type='0',
                    exchange_type='0',
                    stock_code='03690'
                )
            elif api_name == "modify_order":
                result = self.api_client.modify_order(
                    action_type='0',
                    entrust_amount='0',
                    entrust_id="test_order_id",
                    entrust_price='0'
                )
            else:
                self.append_result(f"未知的API: {api_name}")
                return
                
            self.append_result(f"结果: {result}")
            return
            
        if not self.api_client.token:
            self.append_result("请先登录再进行测试")
            return
            
        # 调用我们自己的API
        try:
            self.append_result(f"使用自定义API查询{api_name}...")
            if api_name == "basicinfo":
                result = self.api_client.basicinfo(args[0] if args else "us")
            elif api_name == "marketstate":
                result = self.api_client.marketstate(args[0] if args else "us")
            elif api_name == "realtime":
                result = self.api_client.realtime(args[0] if args else ["sz000001"])
            elif api_name == "timeline":
                result = self.api_client.timeline(args[0] if args else "sz000001", args[1] if len(args) > 1 else 0)
            elif api_name == "kline":
                result = self.api_client.kline(args[0] if args else "sz000001", args[1] if len(args) > 1 else 7, 
                                             args[2] if len(args) > 2 else 20240509160000000, 
                                             args[3] if len(args) > 3 else 0, 
                                             args[4] if len(args) > 4 else 100)
            elif api_name == "orderbook":
                result = self.api_client.orderbook(args[0] if args else "sz000001")
            elif api_name == "tick":
                result = self.api_client.tick(args[0] if args else "sz000001", 
                                            args[1] if len(args) > 1 else 20201221160000000, 
                                            args[2] if len(args) > 2 else 0, 
                                            args[3] if len(args) > 3 else 2, 
                                            args[4] if len(args) > 4 else 1)
            elif api_name == "today_entrust":
                result = self.api_client.today_entrust(args[0] if args else "0")
            elif api_name == "stock_holding":
                result = self.api_client.stock_holding(args[0] if args else "0")
            elif api_name == "ipo_list":
                result = self.api_client.ipo_list()
            elif api_name == "entrust_order":
                result = self.api_client.entrust_order(
                    entrust_amount='100',
                    entrust_price='250',
                    entrust_prop='0',
                    entrust_type='0',
                    exchange_type='0',
                    stock_code='03690'
                )
            elif api_name == "modify_order":
                result = self.api_client.modify_order(
                    action_type='0',
                    entrust_amount='0',
                    entrust_id="test_order_id",
                    entrust_price='0'
                )
            else:
                self.append_result(f"未知的API: {api_name}")
                return
                
            self.append_result(f"结果: {result}")
        except Exception as e:
            self.append_result(f"自定义API调用失败: {str(e)}")
        
    def test_marketstate(self):
        """测试市场状态查询"""
        self.append_result("=== 市场状态查询测试 ===")
        
        # 优先使用示例API
        if self.example_api_client:
            try:
                self.append_result("使用示例API查询市场状态...")
                # 示例API不需要token也可以查询市场状态
                result = self.example_api_client.marketstate('us')
                # 检查是否是Response对象(表示HTTP错误)
                if hasattr(result, 'status_code'):
                    if result.status_code == 200:
                        try:
                            json_result = result.json()
                            self.append_result(f"结果: {json_result}")
                        except:
                            self.append_result(f"结果: {result.text}")
                    else:
                        self.append_result(f"示例API返回HTTP错误: {result.status_code}")
                        # 回退到自定义API
                        self._fallback_to_custom_api("marketstate", "us")
                        return
                else:
                    self.append_result(f"结果: {result}")
                return
            except Exception as e:
                self.append_result(f"示例API调用失败: {str(e)}")
                # 回退到自定义API
                self._fallback_to_custom_api("marketstate", "us")
                return
        
        # 回退到我们自己的API客户端
        self._fallback_to_custom_api("marketstate", "us")
        
    def test_realtime(self):
        """测试实时行情查询"""
        self.append_result("=== 实时行情查询测试 ===")
        
        # 优先使用示例API
        if self.example_api_client:
            try:
                self.append_result("使用示例API查询实时行情...")
                # 示例API不需要token也可以查询实时行情
                result = self.example_api_client.realtime(secuIds=["sz000001"])
                # 检查是否是Response对象(表示HTTP错误)
                if hasattr(result, 'status_code'):
                    if result.status_code == 200:
                        try:
                            json_result = result.json()
                            self.append_result(f"结果: {json_result}")
                        except:
                            self.append_result(f"结果: {result.text}")
                    else:
                        self.append_result(f"示例API返回HTTP错误: {result.status_code}")
                        # 回退到自定义API
                        self._fallback_to_custom_api("realtime", ["sz000001"])
                        return
                else:
                    self.append_result(f"结果: {result}")
                return
            except Exception as e:
                self.append_result(f"示例API调用失败: {str(e)}")
                # 回退到自定义API
                self._fallback_to_custom_api("realtime", ["sz000001"])
                return
        
        # 回退到我们自己的API客户端
        self._fallback_to_custom_api("realtime", ["sz000001"])
        
    def test_timeline(self):
        """测试分时数据查询"""
        self.append_result("=== 分时数据查询测试 ===")
        
        # 优先使用示例API
        if self.example_api_client:
            try:
                self.append_result("使用示例API查询分时数据...")
                # 示例API不需要token也可以查询分时数据
                result = self.example_api_client.timeline(secuId="sz000001", type=0)
                self.append_result(f"结果: {result}")
                return
            except Exception as e:
                self.append_result(f"示例API调用失败: {str(e)}")
        
        # 回退到我们自己的API客户端
        if not self.api_client:
            self.append_result("API客户端未初始化")
            return
            
        # 在测试模式下,我们已经有模拟数据了
        if self.api_client.token == "test_token_123456":
            self.append_result("测试模式:使用模拟分时数据")
            result = self.api_client.timeline(secuId="sz000001", type=0)
            self.append_result(f"结果: {result}")
            return
            
        if not self.api_client.token:
            self.append_result("请先登录再进行测试")
            return
            
        # 调用我们自己的API
        try:
            self.append_result("使用自定义API查询分时数据...")
            result = self.api_client.timeline(secuId="sz000001", type=0)
            self.append_result(f"结果: {result}")
        except Exception as e:
            self.append_result(f"自定义API调用失败: {str(e)}")
        
    def test_kline(self):
        """测试K线数据查询"""
        self.append_result("=== K线数据查询测试 ===")
        
        # 优先使用示例API
        if self.example_api_client:
            try:
                self.append_result("使用示例API查询K线数据...")
                # 注意:这里需要有效的参数
                result = self.example_api_client.kline(secuId="sz000001", type=7, start=20240509160000000, right=0, count=100)
                self.append_result(f"结果: {result}")
                return
            except Exception as e:
                self.append_result(f"示例API调用失败: {str(e)}")
        
        # 回退到我们自己的API客户端
        if not self.api_client:
            self.append_result("API客户端未初始化")
            return
            
        # 在测试模式下,我们已经有模拟数据了
        if self.api_client.token == "test_token_123456":
            self.append_result("测试模式:使用模拟K线数据")
            result = self.api_client.kline(secuId="sz000001", type=7, start=20240509160000000, right=0, count=100)
            self.append_result(f"结果: {result}")
            return
            
        if not self.api_client.token:
            self.append_result("请先登录再进行测试")
            return
            
        # 调用我们自己的API
        try:
            self.append_result("使用自定义API查询K线数据...")
            result = self.api_client.kline(secuId="sz000001", type=7, start=20240509160000000, right=0, count=100)
            self.append_result(f"结果: {result}")
        except Exception as e:
            self.append_result(f"自定义API调用失败: {str(e)}")
        
    def test_orderbook(self):
        """测试买卖盘查询"""
        self.append_result("=== 买卖盘查询测试 ===")
        
        # 优先使用示例API
        if self.example_api_client:
            try:
                self.append_result("使用示例API查询买卖盘...")
                # 示例API不需要token也可以查询买卖盘
                result = self.example_api_client.orderbook(secuId="sz000001")
                # 检查是否是Response对象(表示HTTP错误)
                if hasattr(result, 'status_code'):
                    if result.status_code == 200:
                        try:
                            json_result = result.json()
                            self.append_result(f"结果: {json_result}")
                        except:
                            self.append_result(f"结果: {result.text}")
                    else:
                        self.append_result(f"示例API返回HTTP错误: {result.status_code}")
                        # 回退到自定义API
                        self._fallback_to_custom_api("orderbook", "sz000001")
                        return
                else:
                    self.append_result(f"结果: {result}")
                return
            except Exception as e:
                self.append_result(f"示例API调用失败: {str(e)}")
                # 回退到自定义API
                self._fallback_to_custom_api("orderbook", "sz000001")
                return
        
        # 回退到我们自己的API客户端
        self._fallback_to_custom_api("orderbook", "sz000001")
        
    def test_tick(self):
        """测试逐笔成交查询"""
        self.append_result("=== 逐笔成交查询测试 ===")
        
        # 优先使用示例API
        if self.example_api_client:
            try:
                self.append_result("使用示例API查询逐笔成交...")
                # 注意:这里需要有效的参数
                result = self.example_api_client.tick(secuId="sz000001", tradeTime=20201221160000000, seq=0, count=2, sortDirection=1)
                # 检查是否是Response对象(表示HTTP错误)
                if hasattr(result, 'status_code'):
                    if result.status_code == 200:
                        try:
                            json_result = result.json()
                            self.append_result(f"结果: {json_result}")
                        except:
                            self.append_result(f"结果: {result.text}")
                    else:
                        self.append_result(f"示例API返回HTTP错误: {result.status_code}")
                        # 回退到自定义API
                        self._fallback_to_custom_api("tick", "sz000001", 20201221160000000, 0, 2, 1)
                        return
                else:
                    self.append_result(f"结果: {result}")
                return
            except Exception as e:
                self.append_result(f"示例API调用失败: {str(e)}")
                # 回退到自定义API
                self._fallback_to_custom_api("tick", "sz000001", 20201221160000000, 0, 2, 1)
                return
        
        # 回退到我们自己的API客户端
        self._fallback_to_custom_api("tick", "sz000001", 20201221160000000, 0, 2, 1)
        
    def test_today_entrust(self):
        """测试今日委托查询"""
        self.append_result("=== 今日委托查询测试 ===")
        
        # 优先使用示例API
        if self.example_api_client:
            try:
                self.append_result("使用示例API查询今日委托...")
                result = self.example_api_client.today_entrust(exchangeType='0')
                # 检查是否是Response对象(表示HTTP错误)
                if hasattr(result, 'status_code'):
                    if result.status_code == 200:
                        try:
                            json_result = result.json()
                            self.append_result(f"结果: {json_result}")
                        except:
                            self.append_result(f"结果: {result.text}")
                    else:
                        self.append_result(f"示例API返回HTTP错误: {result.status_code}")
                        # 回退到自定义API
                        self._fallback_to_custom_api("today_entrust", "0")
                        return
                else:
                    self.append_result(f"结果: {result}")
                return
            except Exception as e:
                self.append_result(f"示例API调用失败: {str(e)}")
                # 回退到自定义API
                self._fallback_to_custom_api("today_entrust", "0")
                return
        
        # 回退到我们自己的API客户端
        self._fallback_to_custom_api("today_entrust", "0")
        
    def test_stock_holding(self):
        """测试持仓查询"""
        self.append_result("=== 持仓查询测试 ===")
        
        # 优先使用示例API
        if self.example_api_client:
            try:
                self.append_result("使用示例API查询持仓...")
                result = self.example_api_client.stock_holding('0')
                # 检查是否是Response对象(表示HTTP错误)
                if hasattr(result, 'status_code'):
                    if result.status_code == 200:
                        try:
                            json_result = result.json()
                            self.append_result(f"结果: {json_result}")
                        except:
                            self.append_result(f"结果: {result.text}")
                    else:
                        self.append_result(f"示例API返回HTTP错误: {result.status_code}")
                        # 回退到自定义API
                        self._fallback_to_custom_api("stock_holding", "0")
                        return
                else:
                    self.append_result(f"结果: {result}")
                return
            except Exception as e:
                self.append_result(f"示例API调用失败: {str(e)}")
                # 回退到自定义API
                self._fallback_to_custom_api("stock_holding", "0")
                return
        
        # 在测试模式下,我们已经有模拟数据了
        if self.api_client and self.api_client.token == "test_token_123456":
            self.append_result("测试模式:使用模拟持仓数据")
            result = self.api_client.stock_holding("0")
            if result["success"]:
                for holding in result["data"]:
                    self.append_result(f"股票代码: {holding['stockCode']}, 股票名称: {holding['stockName']}, 持仓数量: {holding['holdingQuantity']}")
            return
            
        if not self.api_client or not self.api_client.token:
            self.append_result("请先登录再进行测试")
            return
            
        # 调用我们自己的API
        try:
            self.append_result("使用自定义API查询持仓...")
            result = self.api_client.stock_holding("0")
            self.append_result(f"结果: {result}")
        except Exception as e:
            self.append_result(f"自定义API调用失败: {str(e)}")
        
    def test_ipo_list(self):
        """测试IPO列表查询"""
        self.append_result("=== IPO列表查询测试 ===")
        
        # 优先使用示例API
        if self.example_api_client:
            try:
                self.append_result("使用示例API查询IPO列表...")
                result = self.example_api_client.ipo_list(status=0)
                # 检查是否是Response对象(表示HTTP错误)
                if hasattr(result, 'status_code'):
                    if result.status_code == 200:
                        try:
                            json_result = result.json()
                            self.append_result(f"结果: {json_result}")
                        except:
                            self.append_result(f"结果: {result.text}")
                    else:
                        self.append_result(f"示例API返回HTTP错误: {result.status_code}")
                        # 回退到自定义API
                        self._fallback_to_custom_api("ipo_list", 0)
                        return
                else:
                    self.append_result(f"结果: {result}")
                return
            except Exception as e:
                self.append_result(f"示例API调用失败: {str(e)}")
                # 回退到自定义API
                self._fallback_to_custom_api("ipo_list", 0)
                return
        
        # 回退到我们自己的API客户端
        self._fallback_to_custom_api("ipo_list", 0)
        
    def test_entrust_order(self):
        """测试下单功能"""
        self.append_result("=== 下单功能测试 ===")
        
        # 优先使用示例API
        if self.example_api_client:
            try:
                self.append_result("使用示例API进行下单测试...")
                # 注意:这里只是测试调用,实际下单需要谨慎
                result = self.example_api_client.entrust_order(
                    entrustAmount='100', 
                    entrustPrice='250', 
                    entrustProp='0', 
                    entrustType='0', 
                    exchangeType='0', 
                    stockCode='03690', 
                    forceEntrustFlag=True
                )
                # 检查是否是Response对象(表示HTTP错误)
                if hasattr(result, 'status_code'):
                    if result.status_code == 200:
                        try:
                            json_result = result.json()
                            self.append_result(f"结果: {json_result}")
                        except:
                            self.append_result(f"结果: {result.text}")
                    else:
                        self.append_result(f"示例API返回HTTP错误: {result.status_code}")
                        # 回退到自定义API
                        self._fallback_to_custom_api("entrust_order")
                        return
                else:
                    self.append_result(f"结果: {result}")
                return
            except Exception as e:
                self.append_result(f"示例API调用失败: {str(e)}")
                # 回退到自定义API
                self._fallback_to_custom_api("entrust_order")
                return
        
        # 回退到我们自己的API客户端
        self._fallback_to_custom_api("entrust_order")
        
    def test_modify_order(self):
        """测试改单功能"""
        self.append_result("=== 改单功能测试 ===")
        
        # 优先使用示例API
        if self.example_api_client:
            try:
                self.append_result("使用示例API进行改单测试...")
                # 注意:这里只是测试调用,实际改单需要有效的委托ID
                result = self.example_api_client.modify_order(
                    actionType='0', 
                    entrustAmount='0', 
                    entrustId="test_order_id", 
                    entrustPrice='0', 
                    forceEntrustFlag=True
                )
                # 检查是否是Response对象(表示HTTP错误)
                if hasattr(result, 'status_code'):
                    if result.status_code == 200:
                        try:
                            json_result = result.json()
                            self.append_result(f"结果: {json_result}")
                        except:
                            self.append_result(f"结果: {result.text}")
                    else:
                        self.append_result(f"示例API返回HTTP错误: {result.status_code}")
                        # 回退到自定义API
                        self._fallback_to_custom_api("modify_order")
                        return
                else:
                    self.append_result(f"结果: {result}")
                return
            except Exception as e:
                self.append_result(f"示例API调用失败: {str(e)}")
                # 回退到自定义API
                self._fallback_to_custom_api("modify_order")
                return
        
        # 回退到我们自己的API客户端
        self._fallback_to_custom_api("modify_order")
        
    def show(self):
        """显示主窗口"""
        self.notebook.grid(row=0, column=0, sticky=(tk.W, tk.E, tk.N, tk.S))
        # 刷新持仓信息
        self.refresh_holdings()

登录界面

系统启动后显示登录界面,用户可选择账号密码登录或短信验证码登录方式。测试模式允许用户跳过登录流程直接进入系统,方便功能测试和演示。

账号密码登录需要输入手机号和密码,点击登录按钮完成验证。短信验证码登录需先输入手机号获取验证码,填写正确验证码后点击验证码登录按钮。测试模式按钮位于登录界面,点击后直接进入系统主界面。

账户管理

账户管理页面展示用户的持仓信息和交易员管理功能。持仓信息板块显示港股和美股持仓详情,包括证券代码、名称、数量、成本价、当前价和盈亏等数据。点击刷新持仓按钮可更新最新持仓数据。

交易员管理功能显示已授权交易员列表,支持添加新交易员或删除现有交易员。该功能便于用户管理账户权限,确保交易安全。

港股交易

港股交易页面提供港股买卖操作功能。股票搜索栏可输入港股代码查询对应股票信息。交易操作板块可选择买入或卖出方向,输入交易数量和价格后点击下单按钮提交委托。

交易界面显示实时行情数据,帮助用户做出交易决策。委托状态区域展示当前委托的执行情况,便于用户跟踪交易进展。

美股交易

美股交易页面功能与港股交易类似,专门针对美股市场设计。用户可通过输入美股代码搜索目标股票,获取实时行情信息。交易操作支持买入和卖出两种方向,需填写交易数量和价格参数。

美股交易遵循当地市场规则,系统会自动处理交易时间限制等特殊要求。交易记录板块保存历史委托信息,方便用户回溯分析。

资金管理

资金管理页面支持入金和出金操作,并显示详细的资金流水记录。资金操作板块可选择入金或出金类型,填写操作金额并选择银行账户后确认提交。

资金流水区域按时间顺序显示历史资金操作记录,包括操作类型、金额、状态等信息。该功能帮助用户清晰掌握资金变动情况,便于财务管理。

AI交易策略

AI交易策略页面为扩展功能模块,支持接入国内主流AI大模型开发交易策略。模型配置区可选择豆包、DeepSeek等提供商,填写API密钥和模型名称完成设置。

策略配置部分需定义策略名称、描述、目标市场和风险等级。操作控制区提供保存策略、测试策略和启停策略等功能。状态监控面板实时显示策略运行状态和详细日志。

Demo功能测试

Demo功能测试页面提供对盈立证券API主要功能的测试入口。行情查询测试包含基础信息、市场状态、实时行情等多项查询功能。交易功能测试覆盖委托查询、持仓查询、IPO查询等核心交易操作。

测试结果会显示在页面日志区域,帮助开发者验证API调用流程。该功能便于系统调试和功能验证,确保交易接口稳定可靠。

系统配置

系统配置文件config.json包含交易主机、行情主机等关键参数。默认用户配置存储了登录所需的手机号、密码和密钥信息。

配置文件采用JSON格式,结构清晰易于修改。用户可根据实际需求调整服务器地址等参数,但修改密钥等安全信息需谨慎操作。

常见问题

登录失败通常由网络问题或凭证错误引起,建议检查网络连接并确认账号密码正确。无法获取行情数据时可检查token状态和股票代码格式。

测试模式使用模拟数据展示系统功能,适合演示和测试场景。AI交易策略功能需要有效API密钥和后续开发支持,当前版本仅提供基础框架。

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐