commit
d7577f6b54
@ -398,3 +398,7 @@ class BacktesterEngine(BaseEngine):
|
||||
def get_all_orders(self):
|
||||
""""""
|
||||
return self.backtesting_engine.get_all_orders()
|
||||
|
||||
def get_all_daily_results(self):
|
||||
""""""
|
||||
return self.backtesting_engine.get_all_daily_results()
|
||||
|
@ -12,6 +12,7 @@ from ..engine import (
|
||||
from vnpy.trader.constant import Interval
|
||||
from vnpy.trader.engine import MainEngine
|
||||
from vnpy.trader.ui import QtCore, QtWidgets, QtGui
|
||||
from vnpy.trader.ui.widget import BaseMonitor, BaseCell, DirectionCell, EnumCell
|
||||
from vnpy.event import Event, EventEngine
|
||||
|
||||
|
||||
@ -95,11 +96,26 @@ class BacktesterManager(QtWidgets.QWidget):
|
||||
downloading_button = QtWidgets.QPushButton("下载数据")
|
||||
downloading_button.clicked.connect(self.start_downloading)
|
||||
|
||||
self.order_button = QtWidgets.QPushButton("委托记录")
|
||||
self.order_button.clicked.connect(self.show_backtesting_orders)
|
||||
self.order_button.setEnabled(False)
|
||||
|
||||
self.trade_button = QtWidgets.QPushButton("成交记录")
|
||||
self.trade_button.clicked.connect(self.show_backtesting_trades)
|
||||
self.trade_button.setEnabled(False)
|
||||
|
||||
self.daily_button = QtWidgets.QPushButton("每日盈亏")
|
||||
self.daily_button.clicked.connect(self.show_daily_results)
|
||||
self.daily_button.setEnabled(False)
|
||||
|
||||
for button in [
|
||||
backtesting_button,
|
||||
optimization_button,
|
||||
downloading_button,
|
||||
self.result_button
|
||||
self.result_button,
|
||||
self.order_button,
|
||||
self.trade_button,
|
||||
self.daily_button
|
||||
]:
|
||||
button.setFixedHeight(button.sizeHint().height() * 2)
|
||||
|
||||
@ -114,12 +130,16 @@ class BacktesterManager(QtWidgets.QWidget):
|
||||
form.addRow("合约乘数", self.size_line)
|
||||
form.addRow("价格跳动", self.pricetick_line)
|
||||
form.addRow("回测资金", self.capital_line)
|
||||
form.addRow(backtesting_button)
|
||||
|
||||
left_vbox = QtWidgets.QVBoxLayout()
|
||||
left_vbox.addLayout(form)
|
||||
left_vbox.addWidget(backtesting_button)
|
||||
left_vbox.addWidget(downloading_button)
|
||||
left_vbox.addStretch()
|
||||
left_vbox.addWidget(self.trade_button)
|
||||
left_vbox.addWidget(self.order_button)
|
||||
left_vbox.addWidget(self.daily_button)
|
||||
left_vbox.addStretch()
|
||||
left_vbox.addWidget(optimization_button)
|
||||
left_vbox.addWidget(self.result_button)
|
||||
|
||||
@ -132,6 +152,25 @@ class BacktesterManager(QtWidgets.QWidget):
|
||||
self.chart = BacktesterChart()
|
||||
self.chart.setMinimumWidth(1000)
|
||||
|
||||
self.trade_dialog = BacktestingResultDialog(
|
||||
self.main_engine,
|
||||
self.event_engine,
|
||||
"回测成交记录",
|
||||
BacktestingTradeMonitor
|
||||
)
|
||||
self.order_dialog = BacktestingResultDialog(
|
||||
self.main_engine,
|
||||
self.event_engine,
|
||||
"回测委托记录",
|
||||
BacktestingOrderMonitor
|
||||
)
|
||||
self.daily_dialog = BacktestingResultDialog(
|
||||
self.main_engine,
|
||||
self.event_engine,
|
||||
"回测每日盈亏",
|
||||
DailyResultMonitor
|
||||
)
|
||||
|
||||
# Layout
|
||||
vbox = QtWidgets.QVBoxLayout()
|
||||
vbox.addWidget(self.statistics_monitor)
|
||||
@ -176,6 +215,10 @@ class BacktesterManager(QtWidgets.QWidget):
|
||||
df = self.backtester_engine.get_result_df()
|
||||
self.chart.set_data(df)
|
||||
|
||||
self.trade_button.setEnabled(True)
|
||||
self.order_button.setEnabled(True)
|
||||
self.daily_button.setEnabled(True)
|
||||
|
||||
def process_optimization_finished_event(self, event: Event):
|
||||
""""""
|
||||
self.write_log("请点击[优化结果]按钮查看")
|
||||
@ -221,6 +264,14 @@ class BacktesterManager(QtWidgets.QWidget):
|
||||
self.statistics_monitor.clear_data()
|
||||
self.chart.clear_data()
|
||||
|
||||
self.trade_button.setEnabled(False)
|
||||
self.order_button.setEnabled(False)
|
||||
self.daily_button.setEnabled(False)
|
||||
|
||||
self.trade_dialog.clear_data()
|
||||
self.order_dialog.clear_data()
|
||||
self.daily_dialog.clear_data()
|
||||
|
||||
def start_optimization(self):
|
||||
""""""
|
||||
class_name = self.class_combo.currentText()
|
||||
@ -284,6 +335,30 @@ class BacktesterManager(QtWidgets.QWidget):
|
||||
)
|
||||
dialog.exec_()
|
||||
|
||||
def show_backtesting_trades(self):
|
||||
""""""
|
||||
if not self.trade_dialog.is_updated():
|
||||
trades = self.backtester_engine.get_all_trades()
|
||||
self.trade_dialog.update_data(trades)
|
||||
|
||||
self.trade_dialog.exec_()
|
||||
|
||||
def show_backtesting_orders(self):
|
||||
""""""
|
||||
if not self.order_dialog.is_updated():
|
||||
orders = self.backtester_engine.get_all_orders()
|
||||
self.order_dialog.update_data(orders)
|
||||
|
||||
self.order_dialog.exec_()
|
||||
|
||||
def show_daily_results(self):
|
||||
""""""
|
||||
if not self.daily_dialog.is_updated():
|
||||
results = self.backtester_engine.get_all_daily_results()
|
||||
self.daily_dialog.update_data(results)
|
||||
|
||||
self.daily_dialog.exec_()
|
||||
|
||||
def show(self):
|
||||
""""""
|
||||
self.showMaximized()
|
||||
@ -750,3 +825,117 @@ class OptimizationResultMonitor(QtWidgets.QDialog):
|
||||
vbox.addWidget(table)
|
||||
|
||||
self.setLayout(vbox)
|
||||
|
||||
|
||||
class BacktestingTradeMonitor(BaseMonitor):
|
||||
"""
|
||||
Monitor for backtesting trade data.
|
||||
"""
|
||||
|
||||
headers = {
|
||||
"tradeid": {"display": "成交号 ", "cell": BaseCell, "update": False},
|
||||
"orderid": {"display": "委托号", "cell": BaseCell, "update": False},
|
||||
"symbol": {"display": "代码", "cell": BaseCell, "update": False},
|
||||
"exchange": {"display": "交易所", "cell": EnumCell, "update": False},
|
||||
"direction": {"display": "方向", "cell": DirectionCell, "update": False},
|
||||
"offset": {"display": "开平", "cell": EnumCell, "update": False},
|
||||
"price": {"display": "价格", "cell": BaseCell, "update": False},
|
||||
"volume": {"display": "数量", "cell": BaseCell, "update": False},
|
||||
"datetime": {"display": "时间", "cell": BaseCell, "update": False},
|
||||
"gateway_name": {"display": "接口", "cell": BaseCell, "update": False},
|
||||
}
|
||||
|
||||
|
||||
class BacktestingOrderMonitor(BaseMonitor):
|
||||
"""
|
||||
Monitor for backtesting order data.
|
||||
"""
|
||||
|
||||
headers = {
|
||||
"orderid": {"display": "委托号", "cell": BaseCell, "update": False},
|
||||
"symbol": {"display": "代码", "cell": BaseCell, "update": False},
|
||||
"exchange": {"display": "交易所", "cell": EnumCell, "update": False},
|
||||
"type": {"display": "类型", "cell": EnumCell, "update": False},
|
||||
"direction": {"display": "方向", "cell": DirectionCell, "update": False},
|
||||
"offset": {"display": "开平", "cell": EnumCell, "update": False},
|
||||
"price": {"display": "价格", "cell": BaseCell, "update": False},
|
||||
"volume": {"display": "总数量", "cell": BaseCell, "update": False},
|
||||
"traded": {"display": "已成交", "cell": BaseCell, "update": False},
|
||||
"status": {"display": "状态", "cell": EnumCell, "update": False},
|
||||
"datetime": {"display": "时间", "cell": BaseCell, "update": False},
|
||||
"gateway_name": {"display": "接口", "cell": BaseCell, "update": False},
|
||||
}
|
||||
|
||||
|
||||
class DailyResultMonitor(BaseMonitor):
|
||||
"""
|
||||
Monitor for backtesting daily result.
|
||||
"""
|
||||
|
||||
headers = {
|
||||
"date": {"display": "日期", "cell": BaseCell, "update": False},
|
||||
"trade_count": {"display": "成交笔数", "cell": BaseCell, "update": False},
|
||||
"start_pos": {"display": "开盘持仓", "cell": BaseCell, "update": False},
|
||||
"end_pos": {"display": "收盘持仓", "cell": BaseCell, "update": False},
|
||||
"turnover": {"display": "成交额", "cell": BaseCell, "update": False},
|
||||
"commission": {"display": "手续费", "cell": BaseCell, "update": False},
|
||||
"slippage": {"display": "滑点", "cell": BaseCell, "update": False},
|
||||
"trading_pnl": {"display": "交易盈亏", "cell": BaseCell, "update": False},
|
||||
"holding_pnl": {"display": "持仓盈亏", "cell": BaseCell, "update": False},
|
||||
"total_pnl": {"display": "总盈亏", "cell": BaseCell, "update": False},
|
||||
"net_pnl": {"display": "净盈亏", "cell": BaseCell, "update": False},
|
||||
}
|
||||
|
||||
|
||||
class BacktestingResultDialog(QtWidgets.QDialog):
|
||||
"""
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
main_engine: MainEngine,
|
||||
event_engine: EventEngine,
|
||||
title: str,
|
||||
table_class: QtWidgets.QTableWidget
|
||||
):
|
||||
""""""
|
||||
super().__init__()
|
||||
|
||||
self.main_engine = main_engine
|
||||
self.event_engine = event_engine
|
||||
self.title = title
|
||||
self.table_class = table_class
|
||||
|
||||
self.updated = False
|
||||
|
||||
self.init_ui()
|
||||
|
||||
def init_ui(self):
|
||||
""""""
|
||||
self.setWindowTitle(self.title)
|
||||
self.resize(1100, 600)
|
||||
|
||||
self.table = self.table_class(self.main_engine, self.event_engine)
|
||||
|
||||
vbox = QtWidgets.QVBoxLayout()
|
||||
vbox.addWidget(self.table)
|
||||
|
||||
self.setLayout(vbox)
|
||||
|
||||
def clear_data(self):
|
||||
""""""
|
||||
self.updated = False
|
||||
self.table.setRowCount(0)
|
||||
|
||||
def update_data(self, data: list):
|
||||
""""""
|
||||
self.updated = True
|
||||
|
||||
data.reverse()
|
||||
for obj in data:
|
||||
self.table.insert_new_row(obj)
|
||||
|
||||
def is_updated(self):
|
||||
""""""
|
||||
return self.updated
|
||||
|
||||
|
@ -825,6 +825,7 @@ class BacktestingEngine:
|
||||
status=Status.ALLTRADED,
|
||||
gateway_name=self.gateway_name,
|
||||
)
|
||||
order.datetime = self.datetime
|
||||
|
||||
self.limit_orders[order.vt_orderid] = order
|
||||
|
||||
@ -943,6 +944,7 @@ class BacktestingEngine:
|
||||
status=Status.NOTTRADED,
|
||||
gateway_name=self.gateway_name,
|
||||
)
|
||||
order.datetime = self.datetime
|
||||
|
||||
self.active_limit_orders[order.vt_orderid] = order
|
||||
self.limit_orders[order.vt_orderid] = order
|
||||
@ -1023,14 +1025,19 @@ class BacktestingEngine:
|
||||
"""
|
||||
Return all trade data of current backtesting result.
|
||||
"""
|
||||
return self.trades.values()
|
||||
return list(self.trades.values())
|
||||
|
||||
def get_all_orders(self):
|
||||
"""
|
||||
Return all limit order data of current backtesting result.
|
||||
"""
|
||||
return self.limit_orders.values()
|
||||
return list(self.limit_orders.values())
|
||||
|
||||
def get_all_daily_results(self):
|
||||
"""
|
||||
Return all daily result data.
|
||||
"""
|
||||
return list(self.daily_results.values())
|
||||
|
||||
class DailyResult:
|
||||
""""""
|
||||
|
@ -237,8 +237,9 @@ class BaseMonitor(QtWidgets.QTableWidget):
|
||||
"""
|
||||
Register event handler into event engine.
|
||||
"""
|
||||
self.signal.connect(self.process_event)
|
||||
self.event_engine.register(self.event_type, self.signal.emit)
|
||||
if self.event_type:
|
||||
self.signal.connect(self.process_event)
|
||||
self.event_engine.register(self.event_type, self.signal.emit)
|
||||
|
||||
def process_event(self, event):
|
||||
"""
|
||||
|
Loading…
Reference in New Issue
Block a user