[Mod] strategy trading widget
This commit is contained in:
parent
6643d8157e
commit
9ee00b0a58
@ -5,11 +5,11 @@ from copy import copy
|
||||
|
||||
from vnpy.event import Event, EventEngine
|
||||
from vnpy.trader.engine import BaseEngine, MainEngine
|
||||
from vnpy.trader.event import EVENT_TRADE, EVENT_ORDER, EVENT_TICK
|
||||
from vnpy.trader.event import EVENT_TRADE, EVENT_ORDER, EVENT_TICK, EVENT_CONTRACT
|
||||
from vnpy.trader.constant import Direction, Offset, OrderType
|
||||
from vnpy.trader.object import (
|
||||
OrderRequest, CancelRequest, SubscribeRequest,
|
||||
OrderData, TradeData, TickData
|
||||
OrderData, TradeData, TickData, ContractData
|
||||
)
|
||||
from vnpy.trader.utility import load_json, save_json
|
||||
|
||||
@ -17,8 +17,8 @@ from vnpy.trader.utility import load_json, save_json
|
||||
APP_NAME = "PortfolioManager"
|
||||
|
||||
EVENT_PORTFOLIO_UPDATE = "ePortfioUpdate"
|
||||
EVENT_PORTFOLIO_ORDER = "ePortfioUpdate"
|
||||
EVENT_PORTFOLIO_TRADE = "ePortfioUpdate"
|
||||
EVENT_PORTFOLIO_ORDER = "ePortfioOrder"
|
||||
EVENT_PORTFOLIO_TRADE = "ePortfioTrade"
|
||||
|
||||
|
||||
class PortfolioEngine(BaseEngine):
|
||||
@ -35,7 +35,6 @@ class PortfolioEngine(BaseEngine):
|
||||
self.active_orders: Set[str] = set()
|
||||
|
||||
self.register_event()
|
||||
self.load_setting()
|
||||
|
||||
def load_setting(self):
|
||||
""""""
|
||||
@ -57,7 +56,7 @@ class PortfolioEngine(BaseEngine):
|
||||
""""""
|
||||
setting: dict = {}
|
||||
|
||||
for strategy in self.strategies:
|
||||
for strategy in self.strategies.values():
|
||||
setting[strategy.name] = {
|
||||
"name": strategy.name,
|
||||
"vt_symbol": strategy.vt_symbol,
|
||||
@ -76,6 +75,14 @@ class PortfolioEngine(BaseEngine):
|
||||
self.event_engine.register(EVENT_ORDER, self.process_order_event)
|
||||
self.event_engine.register(EVENT_TRADE, self.process_trade_event)
|
||||
self.event_engine.register(EVENT_TICK, self.process_tick_event)
|
||||
self.event_engine.register(EVENT_CONTRACT, self.process_contract_event)
|
||||
|
||||
def process_contract_event(self, event: Event):
|
||||
""""""
|
||||
contract: ContractData = event.data
|
||||
|
||||
if contract.vt_symbol in self.symbol_strategy_map:
|
||||
self.subscribe_data(contract.vt_symbol)
|
||||
|
||||
def process_order_event(self, event: Event):
|
||||
""""""
|
||||
@ -102,9 +109,9 @@ class PortfolioEngine(BaseEngine):
|
||||
trade.vt_orderid)
|
||||
if strategy:
|
||||
strategy.update_trade(
|
||||
trade.trade_direction,
|
||||
trade.trade_volume,
|
||||
trade.trade_price
|
||||
trade.direction,
|
||||
trade.volume,
|
||||
trade.price
|
||||
)
|
||||
|
||||
self.put_strategy_event(strategy.name)
|
||||
@ -128,7 +135,7 @@ class PortfolioEngine(BaseEngine):
|
||||
self,
|
||||
name: str,
|
||||
vt_symbol: str,
|
||||
size: int,
|
||||
size: int = 0,
|
||||
net_pos: int = 0,
|
||||
open_price: float = 0,
|
||||
last_price: float = 0,
|
||||
@ -139,6 +146,12 @@ class PortfolioEngine(BaseEngine):
|
||||
if name in self.strategies:
|
||||
return False
|
||||
|
||||
if not size:
|
||||
contract = self.main_engine.get_contract(vt_symbol)
|
||||
if not contract:
|
||||
return False
|
||||
size = contract.size
|
||||
|
||||
strategy = PortfolioStrategy(
|
||||
name,
|
||||
vt_symbol,
|
||||
@ -152,8 +165,12 @@ class PortfolioEngine(BaseEngine):
|
||||
|
||||
self.strategies[strategy.name] = strategy
|
||||
self.symbol_strategy_map[strategy.vt_symbol].append(strategy)
|
||||
self.save_setting()
|
||||
|
||||
self.subscribe_data(vt_symbol)
|
||||
self.put_strategy_event(name)
|
||||
|
||||
return True
|
||||
|
||||
def remove_strategy(self, name: str):
|
||||
""""""
|
||||
@ -238,6 +255,10 @@ class PortfolioEngine(BaseEngine):
|
||||
event = Event(EVENT_PORTFOLIO_UPDATE, strategy)
|
||||
self.event_engine.put(event)
|
||||
|
||||
def stop(self):
|
||||
""""""
|
||||
self.save_setting()
|
||||
|
||||
|
||||
class PortfolioStrategy:
|
||||
""""""
|
||||
|
@ -1,12 +1,10 @@
|
||||
from vnpy.event import EventEngine, Event
|
||||
from vnpy.event import EventEngine
|
||||
from vnpy.trader.engine import MainEngine
|
||||
from vnpy.trader.constant import Direction, Offset
|
||||
from vnpy.trader.ui import QtWidgets, QtCore, QtGui
|
||||
from vnpy.trader.ui import QtWidgets, QtGui
|
||||
from vnpy.trader.ui.widget import (
|
||||
BaseMonitor, BaseCell,
|
||||
BidCell, AskCell,
|
||||
TimeCell, PnlCell,
|
||||
DirectionCell, EnumCell,
|
||||
PnlCell, DirectionCell, EnumCell,
|
||||
)
|
||||
|
||||
from ..engine import (
|
||||
@ -43,10 +41,18 @@ class PortfolioManager(QtWidgets.QWidget):
|
||||
trade_monitor = PortfolioTradeMonitor(
|
||||
self.main_engine, self.event_engine)
|
||||
|
||||
trading_widget = StrategyTradingWidget(self.portfolio_engine)
|
||||
management_widget = StrategyManagementWidget(
|
||||
self.portfolio_engine,
|
||||
trading_widget,
|
||||
)
|
||||
|
||||
vbox = QtWidgets.QVBoxLayout()
|
||||
vbox.addWidget(management_widget)
|
||||
vbox.addWidget(self.create_group("策略", strategy_monitor))
|
||||
vbox.addWidget(self.create_group("委托", order_monitor))
|
||||
vbox.addWidget(self.create_group("成交", trade_monitor))
|
||||
vbox.addWidget(trading_widget)
|
||||
|
||||
self.setLayout(vbox)
|
||||
|
||||
@ -151,3 +157,220 @@ class PortfolioOrderMonitor(BaseMonitor):
|
||||
order = cell.get_data()
|
||||
req = order.create_cancel_request()
|
||||
self.main_engine.cancel_order(req, order.gateway_name)
|
||||
|
||||
|
||||
class StrategyTradingWidget(QtWidgets.QWidget):
|
||||
""""""
|
||||
|
||||
def __init__(self, portfolio_engine: PortfolioEngine):
|
||||
""""""
|
||||
super().__init__()
|
||||
|
||||
self.portfolio_engine = portfolio_engine
|
||||
self.init_ui()
|
||||
self.update_combo()
|
||||
|
||||
def init_ui(self):
|
||||
""""""
|
||||
self.name_combo = QtWidgets.QComboBox()
|
||||
|
||||
self.direction_combo = QtWidgets.QComboBox()
|
||||
self.direction_combo.addItems(
|
||||
[Direction.LONG.value, Direction.SHORT.value])
|
||||
|
||||
self.offset_combo = QtWidgets.QComboBox()
|
||||
self.offset_combo.addItems([offset.value for offset in Offset])
|
||||
|
||||
double_validator = QtGui.QDoubleValidator()
|
||||
double_validator.setBottom(0)
|
||||
|
||||
self.price_line = QtWidgets.QLineEdit()
|
||||
self.price_line.setValidator(double_validator)
|
||||
|
||||
self.volume_line = QtWidgets.QLineEdit()
|
||||
self.volume_line.setValidator(double_validator)
|
||||
|
||||
for w in [
|
||||
self.name_combo,
|
||||
self.price_line,
|
||||
self.volume_line,
|
||||
self.direction_combo,
|
||||
self.offset_combo
|
||||
]:
|
||||
w.setFixedWidth(150)
|
||||
|
||||
send_button = QtWidgets.QPushButton("委托")
|
||||
send_button.clicked.connect(self.send_order)
|
||||
send_button.setFixedWidth(70)
|
||||
|
||||
cancel_button = QtWidgets.QPushButton("全撤")
|
||||
cancel_button.clicked.connect(self.cancel_all)
|
||||
cancel_button.setFixedWidth(70)
|
||||
|
||||
hbox = QtWidgets.QHBoxLayout()
|
||||
hbox.addWidget(QtWidgets.QLabel("策略名称"))
|
||||
hbox.addWidget(self.name_combo)
|
||||
hbox.addWidget(QtWidgets.QLabel("方向"))
|
||||
hbox.addWidget(self.direction_combo)
|
||||
hbox.addWidget(QtWidgets.QLabel("开平"))
|
||||
hbox.addWidget(self.offset_combo)
|
||||
hbox.addWidget(QtWidgets.QLabel("价格"))
|
||||
hbox.addWidget(self.price_line)
|
||||
hbox.addWidget(QtWidgets.QLabel("数量"))
|
||||
hbox.addWidget(self.volume_line)
|
||||
hbox.addWidget(send_button)
|
||||
hbox.addWidget(cancel_button)
|
||||
hbox.addStretch()
|
||||
|
||||
self.setLayout(hbox)
|
||||
|
||||
def send_order(self):
|
||||
""""""
|
||||
name = self.name_combo.currentText()
|
||||
|
||||
price_text = self.price_line.text()
|
||||
volume_text = self.volume_line.text()
|
||||
|
||||
if not price_text or not volume_text:
|
||||
return
|
||||
|
||||
price = float(price_text)
|
||||
volume = float(volume_text)
|
||||
direction = Direction(self.direction_combo.currentText())
|
||||
offset = Offset(self.offset_combo.currentText())
|
||||
|
||||
self.portfolio_engine.send_order(
|
||||
name,
|
||||
price,
|
||||
volume,
|
||||
direction,
|
||||
offset
|
||||
)
|
||||
|
||||
def cancel_all(self):
|
||||
""""""
|
||||
name = self.name_line.text()
|
||||
self.portfolio_engine.cancel_all(name)
|
||||
|
||||
def update_combo(self):
|
||||
""""""
|
||||
strategy_names = list(self.portfolio_engine.strategies.keys())
|
||||
|
||||
self.name_combo.clear()
|
||||
self.name_combo.addItems(strategy_names)
|
||||
|
||||
|
||||
class StrategyManagementWidget(QtWidgets.QWidget):
|
||||
""""""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
portfolio_engine: PortfolioEngine,
|
||||
trading_widget: StrategyTradingWidget
|
||||
):
|
||||
""""""
|
||||
super().__init__()
|
||||
|
||||
self.portfolio_engine = portfolio_engine
|
||||
self.trading_widget = trading_widget
|
||||
|
||||
self.init_ui()
|
||||
self.update_combo()
|
||||
|
||||
def init_ui(self):
|
||||
""""""
|
||||
self.name_line = QtWidgets.QLineEdit()
|
||||
self.symbol_line = QtWidgets.QLineEdit()
|
||||
self.remove_combo = QtWidgets.QComboBox()
|
||||
|
||||
for w in [
|
||||
self.name_line,
|
||||
self.symbol_line,
|
||||
self.remove_combo
|
||||
]:
|
||||
w.setFixedWidth(150)
|
||||
|
||||
add_button = QtWidgets.QPushButton("创建策略")
|
||||
add_button.clicked.connect(self.add_strategy)
|
||||
|
||||
remove_button = QtWidgets.QPushButton("移除策略")
|
||||
remove_button.clicked.connect(self.remove_strategy)
|
||||
|
||||
hbox = QtWidgets.QHBoxLayout()
|
||||
hbox.addWidget(QtWidgets.QLabel("策略名称"))
|
||||
hbox.addWidget(self.name_line)
|
||||
hbox.addWidget(QtWidgets.QLabel("交易合约"))
|
||||
hbox.addWidget(self.symbol_line)
|
||||
hbox.addWidget(add_button)
|
||||
hbox.addStretch()
|
||||
hbox.addWidget(self.remove_combo)
|
||||
hbox.addWidget(remove_button)
|
||||
|
||||
self.setLayout(hbox)
|
||||
|
||||
def add_strategy(self):
|
||||
""""""
|
||||
name = self.name_line.text()
|
||||
vt_symbol = self.symbol_line.text()
|
||||
|
||||
if not name or not vt_symbol:
|
||||
QtWidgets.QMessageBox.information(
|
||||
self,
|
||||
"提示",
|
||||
"请输入策略名称和交易合约",
|
||||
QtWidgets.QMessageBox.Ok
|
||||
)
|
||||
|
||||
result = self.portfolio_engine.add_strategy(name, vt_symbol)
|
||||
|
||||
if result:
|
||||
QtWidgets.QMessageBox.information(
|
||||
self,
|
||||
"提示",
|
||||
"策略创建成功",
|
||||
QtWidgets.QMessageBox.Ok
|
||||
)
|
||||
|
||||
self.update_combo()
|
||||
else:
|
||||
QtWidgets.QMessageBox.warning(
|
||||
self,
|
||||
"提示",
|
||||
"策略创建失败,存在重名或找不到合约",
|
||||
QtWidgets.QMessageBox.Ok
|
||||
)
|
||||
|
||||
def remove_strategy(self):
|
||||
""""""
|
||||
name = self.remove_combo.currentText()
|
||||
|
||||
if not name:
|
||||
return
|
||||
|
||||
result = self.portfolio_engine.remove_strategy(name)
|
||||
|
||||
if result:
|
||||
QtWidgets.QMessageBox.information(
|
||||
self,
|
||||
"提示",
|
||||
"策略移除成功",
|
||||
QtWidgets.QMessageBox.Ok
|
||||
)
|
||||
|
||||
self.update_combo()
|
||||
else:
|
||||
QtWidgets.QMessageBox.warning(
|
||||
self,
|
||||
"提示",
|
||||
"策略移除失败,不存在该策略",
|
||||
QtWidgets.QMessageBox.Ok
|
||||
)
|
||||
|
||||
def update_combo(self):
|
||||
""""""
|
||||
strategy_names = list(self.portfolio_engine.strategies.keys())
|
||||
|
||||
self.remove_combo.clear()
|
||||
self.remove_combo.addItems(strategy_names)
|
||||
|
||||
self.trading_widget.update_combo()
|
||||
|
Loading…
Reference in New Issue
Block a user