Files
backtrader/strategy_editor_gui.py
2026-01-17 21:21:30 +08:00

268 lines
9.5 KiB
Python

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
策略编辑器 GUI 版本
使用 PyQt5 实现图形界面,功能与 strategy_editor.py 一致
"""
import os
import sys
import re
import glob
from datetime import datetime
# 导入 PyQt5 模块
from PyQt5.QtWidgets import (
QApplication, QMainWindow, QWidget, QVBoxLayout, QHBoxLayout,
QLabel, QPushButton, QListWidget, QTextEdit, QInputDialog, QMessageBox,
QGroupBox, QSplitter, QStatusBar
)
from PyQt5.QtCore import Qt
# 导入策略编辑器核心功能
from strategy_editor import StrategyEditor
class StrategyEditorGUI(QMainWindow):
"""策略编辑器 GUI 类"""
def __init__(self):
super().__init__()
# 初始化策略编辑器核心
self.editor = StrategyEditor()
# 设置窗口标题和大小
self.setWindowTitle("策略编辑器")
self.setGeometry(100, 100, 1200, 800)
# 初始化界面组件
self.init_ui()
# 加载策略列表
self.load_strategy_list()
def init_ui(self):
"""初始化界面组件"""
# 创建中心部件
central_widget = QWidget()
self.setCentralWidget(central_widget)
# 创建主布局
main_layout = QHBoxLayout(central_widget)
# 创建分割器
splitter = QSplitter(Qt.Horizontal)
main_layout.addWidget(splitter)
# 创建左侧策略列表区域
self.strategy_list_widget = self.create_strategy_list()
splitter.addWidget(self.strategy_list_widget)
# 创建右侧编辑区域
self.editor_widget = self.create_editor()
splitter.addWidget(self.editor_widget)
# 设置分割器比例
splitter.setSizes([200, 1000])
# 创建状态栏
self.status_bar = QStatusBar()
self.setStatusBar(self.status_bar)
self.status_bar.showMessage("就绪")
def create_strategy_list(self):
"""创建策略列表区域"""
group_box = QGroupBox("可用策略")
layout = QVBoxLayout(group_box)
# 创建策略列表
self.strategy_list = QListWidget()
self.strategy_list.itemClicked.connect(self.on_strategy_selected)
layout.addWidget(self.strategy_list)
# 创建操作按钮
button_layout = QVBoxLayout()
self.new_btn = QPushButton("新建策略")
self.new_btn.clicked.connect(self.on_new_strategy)
button_layout.addWidget(self.new_btn)
self.open_btn = QPushButton("打开策略")
self.open_btn.clicked.connect(self.on_open_strategy)
button_layout.addWidget(self.open_btn)
self.delete_btn = QPushButton("删除策略")
self.delete_btn.clicked.connect(self.on_delete_strategy)
button_layout.addWidget(self.delete_btn)
self.refresh_btn = QPushButton("刷新列表")
self.refresh_btn.clicked.connect(self.load_strategy_list)
button_layout.addWidget(self.refresh_btn)
layout.addLayout(button_layout)
return group_box
def create_editor(self):
"""创建代码编辑区域"""
group_box = QGroupBox("策略编辑")
layout = QVBoxLayout(group_box)
# 创建当前策略信息标签
self.current_strategy_label = QLabel("未选择策略")
self.current_strategy_label.setStyleSheet("font-weight: bold;")
layout.addWidget(self.current_strategy_label)
# 创建代码编辑器
self.code_editor = QTextEdit()
self.code_editor.setPlainText("# 请先选择或创建策略")
layout.addWidget(self.code_editor)
# 创建保存按钮
self.save_btn = QPushButton("保存策略")
self.save_btn.clicked.connect(self.on_save_strategy)
layout.addWidget(self.save_btn)
return group_box
def load_strategy_list(self):
"""加载策略列表"""
self.strategy_list.clear()
# 获取策略文件
strategy_files = glob.glob(os.path.join(self.editor.strategy_dir, '*.py'))
for file_path in strategy_files:
if os.path.basename(file_path) in ['__init__.py', 'base_strategy.py', 'market_filter.py']:
continue
file_name = os.path.basename(file_path)
# 读取文件内容,获取类定义
try:
with open(file_path, 'r', encoding='utf-8') as f:
content = f.read()
# 查找类定义
class_match = re.search(r'class\s+(\w+)\s*\(', content)
if class_match:
class_name = class_match.group(1)
self.strategy_list.addItem(f"{class_name} ({file_name})")
else:
self.strategy_list.addItem(f"{file_name.replace('.py', '')} ({file_name})")
except Exception as e:
QMessageBox.warning(self, "错误", f"读取文件 {file_name} 失败: {str(e)}")
def on_strategy_selected(self, item):
"""选择策略时的处理"""
strategy_info = item.text()
# 提取策略名称
strategy_name = strategy_info.split(' ')[0]
# 读取策略
if self.editor.read_strategy(strategy_name):
self.current_strategy_label.setText(f"当前策略: {self.editor.current_strategy_name}")
self.code_editor.setPlainText(self.editor.current_strategy_content)
self.status_bar.showMessage(f"已加载策略: {strategy_name}")
else:
QMessageBox.warning(self, "错误", f"无法加载策略: {strategy_name}")
def on_new_strategy(self):
"""新建策略"""
strategy_name, ok = QInputDialog.getText(
self, "新建策略", "请输入策略名称(首字母大写):"
)
if ok and strategy_name:
if self.editor.create_new_strategy(strategy_name):
# 更新界面
self.current_strategy_label.setText(f"当前策略: {self.editor.current_strategy_name}")
self.code_editor.setPlainText(self.editor.current_strategy_content)
self.load_strategy_list() # 刷新策略列表
self.status_bar.showMessage(f"已创建新策略: {strategy_name}")
else:
QMessageBox.warning(self, "错误", "策略创建失败,请检查策略名称是否合法或已存在")
def on_open_strategy(self):
"""打开策略"""
strategy_name, ok = QInputDialog.getText(
self, "打开策略", "请输入策略名称:"
)
if ok and strategy_name:
if self.editor.read_strategy(strategy_name):
self.current_strategy_label.setText(f"当前策略: {self.editor.current_strategy_name}")
self.code_editor.setPlainText(self.editor.current_strategy_content)
self.status_bar.showMessage(f"已加载策略: {strategy_name}")
else:
QMessageBox.warning(self, "错误", f"无法找到策略: {strategy_name}")
def on_save_strategy(self):
"""保存策略"""
if not self.editor.current_strategy_name:
QMessageBox.warning(self, "错误", "请先选择或创建策略")
return
# 获取编辑器内容
content = self.code_editor.toPlainText()
if not content:
QMessageBox.warning(self, "错误", "策略内容不能为空")
return
# 更新当前策略内容
self.editor.current_strategy_content = content
# 保存策略
if self.editor.save_strategy():
self.status_bar.showMessage(f"已保存策略: {self.editor.current_strategy_name}")
QMessageBox.information(self, "成功", f"策略 {self.editor.current_strategy_name} 保存成功")
else:
QMessageBox.warning(self, "错误", "策略保存失败")
def on_delete_strategy(self):
"""删除策略"""
# 获取当前选中的策略
current_item = self.strategy_list.currentItem()
if not current_item:
QMessageBox.warning(self, "错误", "请先选择要删除的策略")
return
strategy_info = current_item.text()
strategy_name = strategy_info.split(' ')[0]
# 确认删除
reply = QMessageBox.question(
self, "确认删除", f"确定要删除策略 {strategy_name} 吗?",
QMessageBox.Yes | QMessageBox.No, QMessageBox.No
)
if reply == QMessageBox.Yes:
if self.editor.delete_strategy(strategy_name):
# 清空当前编辑内容
self.current_strategy_label.setText("未选择策略")
self.code_editor.setPlainText("# 请先选择或创建策略")
# 刷新策略列表
self.load_strategy_list()
self.status_bar.showMessage(f"已删除策略: {strategy_name}")
else:
QMessageBox.warning(self, "错误", f"无法删除策略: {strategy_name}")
def main():
"""主函数"""
# 创建应用程序
app = QApplication(sys.argv)
# 创建主窗口
window = StrategyEditorGUI()
# 显示窗口
window.show()
# 运行应用程序
sys.exit(app.exec_())
if __name__ == "__main__":
main()