[Mod] strategy trading widget

This commit is contained in:
vn.py 2019-11-13 21:13:51 +08:00
parent 6643d8157e
commit 9ee00b0a58
2 changed files with 259 additions and 15 deletions

View File

@ -5,11 +5,11 @@ from copy import copy
from vnpy.event import Event, EventEngine from vnpy.event import Event, EventEngine
from vnpy.trader.engine import BaseEngine, MainEngine 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.constant import Direction, Offset, OrderType
from vnpy.trader.object import ( from vnpy.trader.object import (
OrderRequest, CancelRequest, SubscribeRequest, OrderRequest, CancelRequest, SubscribeRequest,
OrderData, TradeData, TickData OrderData, TradeData, TickData, ContractData
) )
from vnpy.trader.utility import load_json, save_json 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" APP_NAME = "PortfolioManager"
EVENT_PORTFOLIO_UPDATE = "ePortfioUpdate" EVENT_PORTFOLIO_UPDATE = "ePortfioUpdate"
EVENT_PORTFOLIO_ORDER = "ePortfioUpdate" EVENT_PORTFOLIO_ORDER = "ePortfioOrder"
EVENT_PORTFOLIO_TRADE = "ePortfioUpdate" EVENT_PORTFOLIO_TRADE = "ePortfioTrade"
class PortfolioEngine(BaseEngine): class PortfolioEngine(BaseEngine):
@ -35,7 +35,6 @@ class PortfolioEngine(BaseEngine):
self.active_orders: Set[str] = set() self.active_orders: Set[str] = set()
self.register_event() self.register_event()
self.load_setting()
def load_setting(self): def load_setting(self):
"""""" """"""
@ -57,7 +56,7 @@ class PortfolioEngine(BaseEngine):
"""""" """"""
setting: dict = {} setting: dict = {}
for strategy in self.strategies: for strategy in self.strategies.values():
setting[strategy.name] = { setting[strategy.name] = {
"name": strategy.name, "name": strategy.name,
"vt_symbol": strategy.vt_symbol, "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_ORDER, self.process_order_event)
self.event_engine.register(EVENT_TRADE, self.process_trade_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_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): def process_order_event(self, event: Event):
"""""" """"""
@ -102,9 +109,9 @@ class PortfolioEngine(BaseEngine):
trade.vt_orderid) trade.vt_orderid)
if strategy: if strategy:
strategy.update_trade( strategy.update_trade(
trade.trade_direction, trade.direction,
trade.trade_volume, trade.volume,
trade.trade_price trade.price
) )
self.put_strategy_event(strategy.name) self.put_strategy_event(strategy.name)
@ -128,7 +135,7 @@ class PortfolioEngine(BaseEngine):
self, self,
name: str, name: str,
vt_symbol: str, vt_symbol: str,
size: int, size: int = 0,
net_pos: int = 0, net_pos: int = 0,
open_price: float = 0, open_price: float = 0,
last_price: float = 0, last_price: float = 0,
@ -139,6 +146,12 @@ class PortfolioEngine(BaseEngine):
if name in self.strategies: if name in self.strategies:
return False return False
if not size:
contract = self.main_engine.get_contract(vt_symbol)
if not contract:
return False
size = contract.size
strategy = PortfolioStrategy( strategy = PortfolioStrategy(
name, name,
vt_symbol, vt_symbol,
@ -152,8 +165,12 @@ class PortfolioEngine(BaseEngine):
self.strategies[strategy.name] = strategy self.strategies[strategy.name] = strategy
self.symbol_strategy_map[strategy.vt_symbol].append(strategy) self.symbol_strategy_map[strategy.vt_symbol].append(strategy)
self.save_setting()
self.subscribe_data(vt_symbol) self.subscribe_data(vt_symbol)
self.put_strategy_event(name)
return True
def remove_strategy(self, name: str): def remove_strategy(self, name: str):
"""""" """"""
@ -238,6 +255,10 @@ class PortfolioEngine(BaseEngine):
event = Event(EVENT_PORTFOLIO_UPDATE, strategy) event = Event(EVENT_PORTFOLIO_UPDATE, strategy)
self.event_engine.put(event) self.event_engine.put(event)
def stop(self):
""""""
self.save_setting()
class PortfolioStrategy: class PortfolioStrategy:
"""""" """"""

View File

@ -1,12 +1,10 @@
from vnpy.event import EventEngine, Event from vnpy.event import EventEngine
from vnpy.trader.engine import MainEngine from vnpy.trader.engine import MainEngine
from vnpy.trader.constant import Direction, Offset 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 ( from vnpy.trader.ui.widget import (
BaseMonitor, BaseCell, BaseMonitor, BaseCell,
BidCell, AskCell, PnlCell, DirectionCell, EnumCell,
TimeCell, PnlCell,
DirectionCell, EnumCell,
) )
from ..engine import ( from ..engine import (
@ -43,10 +41,18 @@ class PortfolioManager(QtWidgets.QWidget):
trade_monitor = PortfolioTradeMonitor( trade_monitor = PortfolioTradeMonitor(
self.main_engine, self.event_engine) self.main_engine, self.event_engine)
trading_widget = StrategyTradingWidget(self.portfolio_engine)
management_widget = StrategyManagementWidget(
self.portfolio_engine,
trading_widget,
)
vbox = QtWidgets.QVBoxLayout() vbox = QtWidgets.QVBoxLayout()
vbox.addWidget(management_widget)
vbox.addWidget(self.create_group("策略", strategy_monitor)) vbox.addWidget(self.create_group("策略", strategy_monitor))
vbox.addWidget(self.create_group("委托", order_monitor)) vbox.addWidget(self.create_group("委托", order_monitor))
vbox.addWidget(self.create_group("成交", trade_monitor)) vbox.addWidget(self.create_group("成交", trade_monitor))
vbox.addWidget(trading_widget)
self.setLayout(vbox) self.setLayout(vbox)
@ -151,3 +157,220 @@ class PortfolioOrderMonitor(BaseMonitor):
order = cell.get_data() order = cell.get_data()
req = order.create_cancel_request() req = order.create_cancel_request()
self.main_engine.cancel_order(req, order.gateway_name) 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()