[Add] LogMonitor for cta strategy and global excepthook
This commit is contained in:
parent
4596f3a515
commit
a257b18f84
@ -2,6 +2,7 @@ from pathlib import Path
|
|||||||
|
|
||||||
from vnpy.trader.app import BaseApp
|
from vnpy.trader.app import BaseApp
|
||||||
from .engine import CtaEngine
|
from .engine import CtaEngine
|
||||||
|
from .template import CtaTemplate
|
||||||
from .base import APP_NAME
|
from .base import APP_NAME
|
||||||
|
|
||||||
|
|
||||||
|
@ -47,31 +47,32 @@ class CtaEngine(BaseEngine):
|
|||||||
event_engine,
|
event_engine,
|
||||||
"CtaStrategy")
|
"CtaStrategy")
|
||||||
|
|
||||||
self._engine_type = EngineType.LIVE # live trading engine
|
self.engine_type = EngineType.LIVE # live trading engine
|
||||||
self.setting_file = None # setting file object
|
self.setting_file = None # setting file object
|
||||||
|
|
||||||
self._strategy_classes = {} # class_name: stategy_class
|
self.classes = {} # class_name: stategy_class
|
||||||
self._strategies = {} # name: strategy
|
self.strategies = {} # strategy_name: strategy
|
||||||
|
|
||||||
self._symbol_strategy_map = defaultdict(list) # vt_symbol: strategy list
|
self.symbol_strategy_map = defaultdict(list) # vt_symbol: strategy list
|
||||||
self._orderid_strategy_map = {} # vt_orderid: strategy
|
self.orderid_strategy_map = {} # vt_orderid: strategy
|
||||||
|
self.strategy_orderid_map = defaultdict(
|
||||||
|
set
|
||||||
|
) # strategy_name: orderid list
|
||||||
|
|
||||||
self._active_orderids = defaultdict(set) # name: active orderid list
|
self.stop_order_count = 0 # for generating stop_orderid
|
||||||
|
self.stop_orders = {} # stop_orderid: stop_order
|
||||||
self._stop_order_count = 0 # for generating stop_orderid
|
|
||||||
self._stop_orders = {} # stop_orderid: stop_order
|
|
||||||
|
|
||||||
def init_engine(self):
|
def init_engine(self):
|
||||||
"""
|
"""
|
||||||
"""
|
"""
|
||||||
self.load_strategy_class()
|
self.load_strategy_class()
|
||||||
self.load_setting()
|
self.load_strategy_setting()
|
||||||
self.register_event()
|
self.register_event()
|
||||||
self.write_log("CTA策略引擎初始化成功")
|
self.write_log("CTA策略引擎初始化成功")
|
||||||
|
|
||||||
def close(self):
|
def close(self):
|
||||||
""""""
|
""""""
|
||||||
self.save_setting()
|
self.save_strategy_setting()
|
||||||
|
|
||||||
def register_event(self):
|
def register_event(self):
|
||||||
""""""
|
""""""
|
||||||
@ -83,26 +84,26 @@ class CtaEngine(BaseEngine):
|
|||||||
""""""
|
""""""
|
||||||
tick = event.data
|
tick = event.data
|
||||||
|
|
||||||
strategies = self._symbol_strategy_map[tick.vt_symbol]
|
strategies = self.symbol_strategy_map[tick.vt_symbol]
|
||||||
if not strategies:
|
if not strategies:
|
||||||
return
|
return
|
||||||
|
|
||||||
self.check_stop_order(tick)
|
self.check_stop_order(tick)
|
||||||
|
|
||||||
for strategy in strategies:
|
for strategy in strategies:
|
||||||
if strategy._inited:
|
if strategy.inited:
|
||||||
self.call_strategy_func(strategy, strategy.on_tick, tick)
|
self.call_strategy_func(strategy, strategy.on_tick, tick)
|
||||||
|
|
||||||
def process_order_event(self, event: Event):
|
def process_order_event(self, event: Event):
|
||||||
""""""
|
""""""
|
||||||
order = event.data
|
order = event.data
|
||||||
|
|
||||||
strategy = self._orderid_strategy_map.get(order.vt_orderid, None)
|
strategy = self.orderid_strategy_map.get(order.vt_orderid, None)
|
||||||
if not strategy:
|
if not strategy:
|
||||||
return
|
return
|
||||||
|
|
||||||
# Remove vt_orderid if order is no longer active.
|
# Remove vt_orderid if order is no longer active.
|
||||||
vt_orderids = self._active_orderids[strategy.name]
|
vt_orderids = self.strategy_orderid_map[strategy.name]
|
||||||
if order.vt_orderid in vt_orderids and not order.is_active():
|
if order.vt_orderid in vt_orderids and not order.is_active():
|
||||||
vt_orderids.remove(order.vt_orderid)
|
vt_orderids.remove(order.vt_orderid)
|
||||||
|
|
||||||
@ -112,20 +113,20 @@ class CtaEngine(BaseEngine):
|
|||||||
""""""
|
""""""
|
||||||
trade = event.data
|
trade = event.data
|
||||||
|
|
||||||
strategy = self._orderid_strategy_map.get(trade.vt_orderid, None)
|
strategy = self.orderid_strategy_map.get(trade.vt_orderid, None)
|
||||||
if not strategy:
|
if not strategy:
|
||||||
return
|
return
|
||||||
|
|
||||||
if trade.direction == Direction.LONG:
|
if trade.direction == Direction.LONG:
|
||||||
strategy._pos += trade.volume
|
strategy.pos += trade.volume
|
||||||
else:
|
else:
|
||||||
strategy._pos -= trade.volume
|
strategy.pos -= trade.volume
|
||||||
|
|
||||||
self.call_strategy_func(strategy, strategy.on_trade, trade)
|
self.call_strategy_func(strategy, strategy.on_trade, trade)
|
||||||
|
|
||||||
def check_stop_order(self, tick: TickData):
|
def check_stop_order(self, tick: TickData):
|
||||||
""""""
|
""""""
|
||||||
for stop_order in self._stop_orders.values():
|
for stop_order in self.stop_orders.values():
|
||||||
if stop_order.vt_symbol != tick.vt_symbol:
|
if stop_order.vt_symbol != tick.vt_symbol:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
@ -165,9 +166,9 @@ class CtaEngine(BaseEngine):
|
|||||||
# Update stop order status if placed successfully
|
# Update stop order status if placed successfully
|
||||||
if vt_orderid:
|
if vt_orderid:
|
||||||
# Remove from relation map.
|
# Remove from relation map.
|
||||||
self._stop_orders.pop(stop_order.stop_orderid)
|
self.stop_orders.pop(stop_order.stop_orderid)
|
||||||
|
|
||||||
vt_orderids = self._active_orderids[strategy.name]
|
vt_orderids = self.strategy_orderid_map[strategy.name]
|
||||||
if stop_orderid in vt_orderids:
|
if stop_orderid in vt_orderids:
|
||||||
vt_orderids.remove(stop_orderid)
|
vt_orderids.remove(stop_orderid)
|
||||||
|
|
||||||
@ -214,9 +215,9 @@ class CtaEngine(BaseEngine):
|
|||||||
)
|
)
|
||||||
|
|
||||||
# Save relationship between orderid and strategy.
|
# Save relationship between orderid and strategy.
|
||||||
self._orderid_strategy_map[vt_orderid] = strategy
|
self.orderid_strategy_map[vt_orderid] = strategy
|
||||||
|
|
||||||
vt_orderids = self._active_orderids[strategy.name]
|
vt_orderids = self.strategy_orderid_map[strategy.name]
|
||||||
vt_orderids.add(vt_orderid)
|
vt_orderids.add(vt_orderid)
|
||||||
|
|
||||||
return vt_orderid
|
return vt_orderid
|
||||||
@ -231,9 +232,9 @@ class CtaEngine(BaseEngine):
|
|||||||
"""
|
"""
|
||||||
Send a new order.
|
Send a new order.
|
||||||
"""
|
"""
|
||||||
self._stop_order_count += 1
|
self.stop_order_count += 1
|
||||||
direction, offset = ORDER_CTA2VT[order_type]
|
direction, offset = ORDER_CTA2VT[order_type]
|
||||||
stop_orderid = f"{STOPORDER_PREFIX}.{self._stop_order_count}"
|
stop_orderid = f"{STOPORDER_PREFIX}.{self.stop_order_count}"
|
||||||
|
|
||||||
stop_order = StopOrder(
|
stop_order = StopOrder(
|
||||||
vt_symbol=strategy.vt_symbol,
|
vt_symbol=strategy.vt_symbol,
|
||||||
@ -245,9 +246,9 @@ class CtaEngine(BaseEngine):
|
|||||||
strategy=strategy
|
strategy=strategy
|
||||||
)
|
)
|
||||||
|
|
||||||
self._stop_orders[stop_orderid] = stop_order
|
self.stop_orders[stop_orderid] = stop_order
|
||||||
|
|
||||||
vt_orderids = self._active_orderids[strategy.name]
|
vt_orderids = self.strategy_orderid_map[strategy.name]
|
||||||
vt_orderids.add(stop_orderid)
|
vt_orderids.add(stop_orderid)
|
||||||
|
|
||||||
self.call_strategy_func(strategy, strategy.on_stop_order, stop_order)
|
self.call_strategy_func(strategy, strategy.on_stop_order, stop_order)
|
||||||
@ -270,15 +271,15 @@ class CtaEngine(BaseEngine):
|
|||||||
"""
|
"""
|
||||||
Cancel a local stop order.
|
Cancel a local stop order.
|
||||||
"""
|
"""
|
||||||
stop_order = self._stop_orders.get(stop_orderid, None)
|
stop_order = self.stop_orders.get(stop_orderid, None)
|
||||||
if not stop_order:
|
if not stop_order:
|
||||||
return
|
return
|
||||||
strategy = stop_order.strategy
|
strategy = stop_order.strategy
|
||||||
|
|
||||||
# Remove from relation map.
|
# Remove from relation map.
|
||||||
self._stop_orders.pop(stop_orderid)
|
self.stop_orders.pop(stop_orderid)
|
||||||
|
|
||||||
vt_orderids = self._active_orderids[strategy.name]
|
vt_orderids = self.strategy_orderid_map[strategy.name]
|
||||||
if stop_orderid in vt_orderids:
|
if stop_orderid in vt_orderids:
|
||||||
vt_orderids.remove(stop_orderid)
|
vt_orderids.remove(stop_orderid)
|
||||||
|
|
||||||
@ -314,7 +315,7 @@ class CtaEngine(BaseEngine):
|
|||||||
"""
|
"""
|
||||||
Cancel all active orders of a strategy.
|
Cancel all active orders of a strategy.
|
||||||
"""
|
"""
|
||||||
vt_orderids = self._active_orderids[strategy.name]
|
vt_orderids = self.strategy_orderid_map[strategy.name]
|
||||||
if not vt_orderids:
|
if not vt_orderids:
|
||||||
return
|
return
|
||||||
|
|
||||||
@ -323,7 +324,7 @@ class CtaEngine(BaseEngine):
|
|||||||
|
|
||||||
def get_engine_type(self):
|
def get_engine_type(self):
|
||||||
""""""
|
""""""
|
||||||
return self._engine_type
|
return self.engine_type
|
||||||
|
|
||||||
def call_strategy_func(
|
def call_strategy_func(
|
||||||
self,
|
self,
|
||||||
@ -340,116 +341,120 @@ class CtaEngine(BaseEngine):
|
|||||||
else:
|
else:
|
||||||
func()
|
func()
|
||||||
except Exception:
|
except Exception:
|
||||||
strategy._trading = False
|
strategy.trading = False
|
||||||
strategy._inited = False
|
strategy.inited = False
|
||||||
|
|
||||||
msg = f"触发异常已停止\n{traceback.format_exc()}"
|
msg = f"触发异常已停止\n{traceback.format_exc()}"
|
||||||
self.write_log(msg, strategy)
|
self.write_log(msg, strategy)
|
||||||
|
|
||||||
def add_strategy(self, setting):
|
def add_strategy(
|
||||||
|
self,
|
||||||
|
class_name: str,
|
||||||
|
strategy_name: str,
|
||||||
|
vt_symbol: str,
|
||||||
|
setting: dict
|
||||||
|
):
|
||||||
"""
|
"""
|
||||||
Add a new strategy.
|
Add a new strategy.
|
||||||
"""
|
"""
|
||||||
name = setting["name"]
|
if strategy_name in self.strategies:
|
||||||
if name in self._strategies:
|
self.write_log(f"创建策略失败,存在重名{strategy_name}")
|
||||||
self.write_log(f"创建策略失败,存在重名{name}")
|
|
||||||
return
|
return
|
||||||
|
|
||||||
class_name = setting["class_name"]
|
strategy_class = self.classes[class_name]
|
||||||
strategy_class = self._strategy_classes[class_name]
|
|
||||||
|
|
||||||
strategy = strategy_class(self, setting)
|
strategy = strategy_class(self, strategy_name, vt_symbol, setting)
|
||||||
self._strategies[name] = strategy
|
self.strategies[strategy_name] = strategy
|
||||||
|
|
||||||
# Add vt_symbol to strategy map.
|
# Add vt_symbol to strategy map.
|
||||||
strategies = self._symbol_strategy_map[strategy.vt_symbol]
|
strategies = self.symbol_strategy_map[vt_symbol]
|
||||||
strategies.append(strategy)
|
strategies.append(strategy)
|
||||||
|
|
||||||
# Update to setting file.
|
# Update to setting file.
|
||||||
self.update_setting(setting)
|
self.update_strategy_setting(strategy_name, setting)
|
||||||
|
|
||||||
self.put_strategy_event()
|
self.put_strategy_event(strategy)
|
||||||
|
|
||||||
def init_strategy(self, name):
|
def init_strategy(self, strategy_name: str):
|
||||||
"""
|
"""
|
||||||
Init a strategy.
|
Init a strategy.
|
||||||
"""
|
"""
|
||||||
strategy = self._strategies[name]
|
strategy = self.strategies[strategy_name]
|
||||||
self.call_strategy_func(strategy, strategy.on_init)
|
self.call_strategy_func(strategy, strategy.on_init)
|
||||||
strategy._inited = True
|
strategy.inited = True
|
||||||
|
|
||||||
# Subscribe market data
|
# Subscribe market data
|
||||||
contract = self.main_engine.get_contract(strategy.vt_symbol)
|
contract = self.main_engine.get_contract(strategy.vt_symbol)
|
||||||
if not contract:
|
if not contract:
|
||||||
self.write_log(f"行情订阅失败,找不到合约{strategy.vt_symbol}", strategy)
|
self.write_log(f"行情订阅失败,找不到合约{strategy.vt_symbol}", strategy)
|
||||||
|
|
||||||
self.put_strategy_event()
|
self.put_strategy_event(strategy)
|
||||||
|
|
||||||
def start_strategy(self, name):
|
def start_strategy(self, strategy_name: str):
|
||||||
"""
|
"""
|
||||||
Start a strategy.
|
Start a strategy.
|
||||||
"""
|
"""
|
||||||
strategy = self._strategies[name]
|
strategy = self.strategies[strategy_name]
|
||||||
self.call_strategy_func(strategy, strategy.on_start)
|
self.call_strategy_func(strategy, strategy.on_start)
|
||||||
strategy._trading = True
|
strategy.trading = True
|
||||||
|
|
||||||
self.put_strategy_event()
|
self.put_strategy_event(strategy)
|
||||||
|
|
||||||
def stop_strategy(self, name):
|
def stop_strategy(self, strategy_name: str):
|
||||||
"""
|
"""
|
||||||
Stop a strategy.
|
Stop a strategy.
|
||||||
"""
|
"""
|
||||||
strategy = self._strategies[name]
|
strategy = self.strategies[strategy_name]
|
||||||
self.call_strategy_func(strategy, strategy.on_start)
|
self.call_strategy_func(strategy, strategy.on_start)
|
||||||
strategy._trading = False
|
strategy.trading = False
|
||||||
|
|
||||||
self.put_strategy_event()
|
self.put_strategy_event(strategy)
|
||||||
|
|
||||||
def edit_strategy(self, setting):
|
def edit_strategy(self, strategy_name: str, setting: dict):
|
||||||
"""
|
"""
|
||||||
Edit parameters of a strategy.
|
Edit parameters of a strategy.
|
||||||
"""
|
"""
|
||||||
name = setting["name"]
|
strategy = self.strategies[strategy_name]
|
||||||
strategy = self._strategies[name]
|
strategy.update_setting(setting)
|
||||||
|
|
||||||
for name in strategy.parameters:
|
self.update_strategy_setting(strategy_name, setting)
|
||||||
setattr(strategy, name, setting[name])
|
|
||||||
|
|
||||||
self.update_setting(setting)
|
|
||||||
self.put_strategy_event(strategy)
|
self.put_strategy_event(strategy)
|
||||||
|
|
||||||
def remove_strategy(self, name):
|
def remove_strategy(self, strategy_name: str):
|
||||||
"""
|
"""
|
||||||
Remove a strategy.
|
Remove a strategy.
|
||||||
"""
|
"""
|
||||||
# Remove setting
|
# Remove setting
|
||||||
self.remove_setting(name)
|
self.remove_strategy_setting(strategy_name)
|
||||||
|
|
||||||
# Remove from symbol strategy map
|
# Remove from symbol strategy map
|
||||||
strategy = self._strategies[name]
|
strategy = self.strategies[strategy_name]
|
||||||
strategies = self._symbol_strategy_map[strategy.vt_symbol]
|
strategies = self.symbol_strategy_map[strategy.vt_symbol]
|
||||||
strategies.remove(strategy)
|
strategies.remove(strategy)
|
||||||
|
|
||||||
# Remove from active orderid map
|
# Remove from active orderid map
|
||||||
if name in self._active_orderids:
|
if strategy_name in self.strategy_orderid_map:
|
||||||
vt_orderids = self._active_orderids.pop(name)
|
vt_orderids = self.strategy_orderid_map.pop(strategy_name)
|
||||||
|
|
||||||
# Remove vt_orderid strategy map
|
# Remove vt_orderid strategy map
|
||||||
for vt_orderid in vt_orderids:
|
for vt_orderid in vt_orderids:
|
||||||
self._orderid_strategy_map.pop(vt_orderid)
|
self.orderid_strategy_map.pop(vt_orderid)
|
||||||
|
|
||||||
# Remove from strategies
|
# Remove from strategies
|
||||||
self._strategies.pop(name)
|
self.strategies.pop(strategy_name)
|
||||||
|
|
||||||
def load_strategy_class(self):
|
def load_strategy_class(self):
|
||||||
"""
|
"""
|
||||||
Load strategy class from source code.
|
Load strategy class from source code.
|
||||||
"""
|
"""
|
||||||
path1 = Path(__file__).parent.joinpath("strategies")
|
path1 = Path(__file__).parent.joinpath("strategies")
|
||||||
self.load_strategy_class_from_folder(path1, __name__)
|
self.load_strategy_class_from_folder(
|
||||||
|
path1,
|
||||||
|
"vnpy.app.cta_strategy.strategies"
|
||||||
|
)
|
||||||
|
|
||||||
path2 = Path.cwd().joinpath("strategies")
|
path2 = Path.cwd().joinpath("strategies")
|
||||||
self.load_strategy_class_from_folder(path2)
|
self.load_strategy_class_from_folder(path2, "strategies")
|
||||||
|
|
||||||
def load_strategy_class_from_folder(
|
def load_strategy_class_from_folder(
|
||||||
self,
|
self,
|
||||||
@ -460,8 +465,12 @@ class CtaEngine(BaseEngine):
|
|||||||
Load strategy class from certain folder.
|
Load strategy class from certain folder.
|
||||||
"""
|
"""
|
||||||
for dirpath, dirnames, filenames in os.walk(path):
|
for dirpath, dirnames, filenames in os.walk(path):
|
||||||
for name in filenames:
|
for filename in filenames:
|
||||||
module_name = ".".join([module_name, name.replace(".py", "")])
|
module_name = ".".join(
|
||||||
|
[module_name,
|
||||||
|
filename.replace(".py",
|
||||||
|
"")]
|
||||||
|
)
|
||||||
self.load_strategy_class_from_module(module_name)
|
self.load_strategy_class_from_module(module_name)
|
||||||
|
|
||||||
def load_strategy_class_from_module(self, module_name: str):
|
def load_strategy_class_from_module(self, module_name: str):
|
||||||
@ -473,8 +482,8 @@ class CtaEngine(BaseEngine):
|
|||||||
|
|
||||||
for name in dir(module):
|
for name in dir(module):
|
||||||
value = getattr(module, name)
|
value = getattr(module, name)
|
||||||
if isinstance(value, CtaTemplate):
|
if issubclass(value, CtaTemplate) and value is not CtaTemplate:
|
||||||
self._strategy_classes[value.__name__] = value
|
self.classes[value.__name__] = value
|
||||||
except:
|
except:
|
||||||
msg = f"策略文件{module_name}加载失败,触发异常:\n{traceback.format_exc()}"
|
msg = f"策略文件{module_name}加载失败,触发异常:\n{traceback.format_exc()}"
|
||||||
self.write_log(msg)
|
self.write_log(msg)
|
||||||
@ -483,13 +492,13 @@ class CtaEngine(BaseEngine):
|
|||||||
"""
|
"""
|
||||||
Return names of strategy classes loaded.
|
Return names of strategy classes loaded.
|
||||||
"""
|
"""
|
||||||
return list(self._strategy_classes.keys())
|
return list(self.classes.keys())
|
||||||
|
|
||||||
def get_strategy_class_parameters(self, class_name: str):
|
def get_strategy_class_parameters(self, class_name: str):
|
||||||
"""
|
"""
|
||||||
Get default parameters of a strategy.
|
Get default parameters of a strategy class.
|
||||||
"""
|
"""
|
||||||
strategy_class = self._strategy_classes[class_name]
|
strategy_class = self.classes[class_name]
|
||||||
|
|
||||||
parameters = {}
|
parameters = {}
|
||||||
for name in strategy_class.parameters:
|
for name in strategy_class.parameters:
|
||||||
@ -497,51 +506,67 @@ class CtaEngine(BaseEngine):
|
|||||||
|
|
||||||
return parameters
|
return parameters
|
||||||
|
|
||||||
|
def get_strategy_parameters(self, strategy_name):
|
||||||
|
"""
|
||||||
|
Get parameters of a strategy.
|
||||||
|
"""
|
||||||
|
strategy = self.strategies[strategy_name]
|
||||||
|
return strategy.get_parameters()
|
||||||
|
|
||||||
def init_all_strategies(self):
|
def init_all_strategies(self):
|
||||||
"""
|
"""
|
||||||
"""
|
"""
|
||||||
for name in self._strategies.keys():
|
for strategy_name in self.strategies.keys():
|
||||||
self.init_strategy(name)
|
self.init_strategy(strategy_name)
|
||||||
|
|
||||||
def start_all_strategies(self):
|
def start_all_strategies(self):
|
||||||
"""
|
"""
|
||||||
"""
|
"""
|
||||||
for name in self._strategies.keys():
|
for strategy_name in self.strategies.keys():
|
||||||
self.start_strategy(name)
|
self.start_strategy(strategy_name)
|
||||||
|
|
||||||
def stop_all_strategies(self):
|
def stop_all_strategies(self):
|
||||||
"""
|
"""
|
||||||
"""
|
"""
|
||||||
for name in self._strategies.keys():
|
for strategy_name in self.strategies.keys():
|
||||||
self.stop_strategy(name)
|
self.stop_strategy(strategy_name)
|
||||||
|
|
||||||
def load_setting(self):
|
def load_strategy_setting(self):
|
||||||
"""
|
"""
|
||||||
Load setting file.
|
Load setting file.
|
||||||
"""
|
"""
|
||||||
filepath = get_temp_path(self.filename)
|
filepath = str(get_temp_path(self.filename))
|
||||||
self.setting_file = shelve.open(filename)
|
self.setting_file = shelve.open(filepath)
|
||||||
for setting in list(self.setting_file.values()):
|
|
||||||
self.add_strategy(setting)
|
|
||||||
|
|
||||||
def update_setting(self, setting: dict):
|
for tp in list(self.setting_file.values()):
|
||||||
|
class_name, strategy_name, vt_symbol, setting = tp
|
||||||
|
self.add_strategy(class_name, strategy_name, vt_symbol, setting)
|
||||||
|
|
||||||
|
def update_strategy_setting(self, strategy_name: str, setting: dict):
|
||||||
"""
|
"""
|
||||||
Update setting file.
|
Update setting file.
|
||||||
"""
|
"""
|
||||||
self.setting_file[new_setting["name"]] = new_setting
|
strategy = self.strategies[strategy_name]
|
||||||
|
|
||||||
|
self.setting_file[strategy_name] = (
|
||||||
|
strategy.__class__.__name__,
|
||||||
|
strategy_name,
|
||||||
|
strategy.vt_symbol,
|
||||||
|
setting
|
||||||
|
)
|
||||||
self.setting_file.sync()
|
self.setting_file.sync()
|
||||||
|
|
||||||
def remove_setting(self, name: str):
|
def remove_strategy_setting(self, strategy_name: str):
|
||||||
"""
|
"""
|
||||||
Update setting file.
|
Update setting file.
|
||||||
"""
|
"""
|
||||||
if name not in self.setting_file:
|
if strategy_name not in self.setting_file:
|
||||||
return
|
return
|
||||||
|
|
||||||
self.setting_file.pop(name)
|
self.setting_file.pop(strategy_name)
|
||||||
self.setting_file.sync()
|
self.setting_file.sync()
|
||||||
|
|
||||||
def save_setting(self):
|
def save_strategy_setting(self):
|
||||||
"""
|
"""
|
||||||
Save and close setting file.
|
Save and close setting file.
|
||||||
"""
|
"""
|
||||||
@ -558,25 +583,7 @@ class CtaEngine(BaseEngine):
|
|||||||
"""
|
"""
|
||||||
Put an event to update strategy status.
|
Put an event to update strategy status.
|
||||||
"""
|
"""
|
||||||
parameters = {}
|
data = strategy.get_data()
|
||||||
for name in strategy.parameters:
|
|
||||||
parameters[name] = getattr(strategy, name)
|
|
||||||
|
|
||||||
variables = {}
|
|
||||||
for name in strategy.variables:
|
|
||||||
variables[name] = getattr(strategy, name)
|
|
||||||
|
|
||||||
data = {
|
|
||||||
"name": name,
|
|
||||||
"class_name": strategy.__class__.__name__,
|
|
||||||
"inited": strategy._inited,
|
|
||||||
"trading": strategy._trading,
|
|
||||||
"pos": strategy._pos,
|
|
||||||
"author": strategy.author,
|
|
||||||
"vt_symbol": strategy.vt_symbol,
|
|
||||||
"parameters": parameters,
|
|
||||||
"variables": variables
|
|
||||||
}
|
|
||||||
event = Event(EVENT_CTA_STRATEGY, data)
|
event = Event(EVENT_CTA_STRATEGY, data)
|
||||||
self.event_engine.put(event)
|
self.event_engine.put(event)
|
||||||
|
|
||||||
@ -585,7 +592,7 @@ class CtaEngine(BaseEngine):
|
|||||||
Create cta engine log event.
|
Create cta engine log event.
|
||||||
"""
|
"""
|
||||||
if strategy:
|
if strategy:
|
||||||
msg = f"{strategy.name}: {msg}"
|
msg = f"{strategy.strategy_name}: {msg}"
|
||||||
|
|
||||||
log = LogData(msg=msg, gateway_name="CtaStrategy")
|
log = LogData(msg=msg, gateway_name="CtaStrategy")
|
||||||
event = Event(type=EVENT_CTA_LOG, data=log)
|
event = Event(type=EVENT_CTA_LOG, data=log)
|
||||||
|
23
vnpy/app/cta_strategy/strategies/double_ma_strategy.py
Normal file
23
vnpy/app/cta_strategy/strategies/double_ma_strategy.py
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
from vnpy.app.cta_strategy import CtaTemplate
|
||||||
|
|
||||||
|
|
||||||
|
class DoubleMaStrategy(CtaTemplate):
|
||||||
|
|
||||||
|
author = "用Python的交易员"
|
||||||
|
|
||||||
|
fast_window = 10
|
||||||
|
slow_window = 20.10
|
||||||
|
|
||||||
|
fast_ma = 0.0
|
||||||
|
slow_ma = 0.0
|
||||||
|
|
||||||
|
parameters = ["fast_window", "slow_window"]
|
||||||
|
variables = ["fast_ma", "slow_ma"]
|
||||||
|
|
||||||
|
def __init__(self, cta_engine, strategy_name, vt_symbol, setting):
|
||||||
|
""""""
|
||||||
|
super(DoubleMaStrategy,
|
||||||
|
self).__init__(cta_engine,
|
||||||
|
strategy_name,
|
||||||
|
vt_symbol,
|
||||||
|
setting)
|
@ -11,26 +11,82 @@ from .base import CtaOrderType, StopOrder
|
|||||||
class CtaTemplate(ABC):
|
class CtaTemplate(ABC):
|
||||||
""""""
|
""""""
|
||||||
|
|
||||||
_inited = False
|
|
||||||
_trading = False
|
|
||||||
_pos = 0
|
|
||||||
|
|
||||||
author = ""
|
author = ""
|
||||||
vt_symbol = ""
|
|
||||||
|
|
||||||
parameters = []
|
parameters = []
|
||||||
variables = []
|
variables = []
|
||||||
|
|
||||||
def __init__(self, engine: BaseEngine, setting: dict):
|
def __init__(
|
||||||
|
self,
|
||||||
|
cta_engine: BaseEngine,
|
||||||
|
strategy_name: str,
|
||||||
|
vt_symbol: str,
|
||||||
|
setting: dict
|
||||||
|
):
|
||||||
""""""
|
""""""
|
||||||
self.engine = engine
|
self.cta_engine = cta_engine
|
||||||
|
self.strategy_name = strategy_name
|
||||||
|
self.vt_symbol = vt_symbol
|
||||||
|
|
||||||
self.vt_symbol = setting["vt_symbol"]
|
self.inited = False
|
||||||
|
self.trading = False
|
||||||
|
self.pos = 0
|
||||||
|
|
||||||
|
self.variables.insert(0, "inited")
|
||||||
|
self.variables.insert(1, "trading")
|
||||||
|
self.variables.insert(2, "pos")
|
||||||
|
|
||||||
|
self.update_setting(setting)
|
||||||
|
|
||||||
|
def update_setting(self, setting: dict):
|
||||||
|
"""
|
||||||
|
Update strategy parameter wtih value in setting dict.
|
||||||
|
"""
|
||||||
for name in self.parameters:
|
for name in self.parameters:
|
||||||
if name in setting:
|
if name in setting:
|
||||||
setattr(self, name, setting[name])
|
setattr(self, name, setting[name])
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_class_parameters(cls):
|
||||||
|
"""
|
||||||
|
Get default parameters dict of strategy class.
|
||||||
|
"""
|
||||||
|
class_parameters = {}
|
||||||
|
for name in cls.parameters:
|
||||||
|
class_parameters[name] = getattr(cls, name)
|
||||||
|
return class_parameters
|
||||||
|
|
||||||
|
def get_parameters(self):
|
||||||
|
"""
|
||||||
|
Get strategy parameters dict.
|
||||||
|
"""
|
||||||
|
strategy_parameters = {}
|
||||||
|
for name in self.parameters:
|
||||||
|
strategy_parameters[name] = getattr(self, name)
|
||||||
|
return strategy_parameters
|
||||||
|
|
||||||
|
def get_variables(self):
|
||||||
|
"""
|
||||||
|
Get strategy variables dict.
|
||||||
|
"""
|
||||||
|
strategy_variables = {}
|
||||||
|
for name in self.variables:
|
||||||
|
strategy_variables[name] = getattr(self, name)
|
||||||
|
return strategy_variables
|
||||||
|
|
||||||
|
def get_data(self):
|
||||||
|
"""
|
||||||
|
Get strategy data.
|
||||||
|
"""
|
||||||
|
strategy_data = {
|
||||||
|
"strategy_name": self.strategy_name,
|
||||||
|
"vt_symbol": self.vt_symbol,
|
||||||
|
"class_name": self.__class__.__name__,
|
||||||
|
"author": self.author,
|
||||||
|
"parameters": self.get_parameters(),
|
||||||
|
"variables": self.get_variables()
|
||||||
|
}
|
||||||
|
return strategy_data
|
||||||
|
|
||||||
def on_init(self):
|
def on_init(self):
|
||||||
"""
|
"""
|
||||||
Callback when strategy is inited.
|
Callback when strategy is inited.
|
||||||
@ -107,34 +163,34 @@ class CtaTemplate(ABC):
|
|||||||
"""
|
"""
|
||||||
Send a new order.
|
Send a new order.
|
||||||
"""
|
"""
|
||||||
return self.engine.send_order(self, order_type, price, volume, stop)
|
return self.cta_engine.send_order(self, order_type, price, volume, stop)
|
||||||
|
|
||||||
def cancel_order(self, vt_orderid):
|
def cancel_order(self, vt_orderid):
|
||||||
"""
|
"""
|
||||||
Cancel an existing order.
|
Cancel an existing order.
|
||||||
"""
|
"""
|
||||||
self.engine.cancel_order(vt_orderid)
|
self.cta_engine.cancel_order(vt_orderid)
|
||||||
|
|
||||||
def cancel_all(self):
|
def cancel_all(self):
|
||||||
"""
|
"""
|
||||||
Cancel all orders sent by strategy.
|
Cancel all orders sent by strategy.
|
||||||
"""
|
"""
|
||||||
self.engine.cancel_all(self)
|
self.cta_engine.cancel_all(self)
|
||||||
|
|
||||||
def write_log(self, msg):
|
def write_log(self, msg):
|
||||||
"""
|
"""
|
||||||
Write a log message.
|
Write a log message.
|
||||||
"""
|
"""
|
||||||
self.engine.write_log(self, msg)
|
self.cta_engine.write_log(self, msg)
|
||||||
|
|
||||||
def get_engine_type(self):
|
def get_engine_type(self):
|
||||||
"""
|
"""
|
||||||
Return whether the engine is backtesting or live trading.
|
Return whether the cta_engine is backtesting or live trading.
|
||||||
"""
|
"""
|
||||||
return self.engine.get_engine_type()
|
return self.cta_engine.get_engine_type()
|
||||||
|
|
||||||
def get_pos(self):
|
def put_event(self):
|
||||||
"""
|
"""
|
||||||
Return current net position of the strategy.
|
Put an strategy data event for ui update.
|
||||||
"""
|
"""
|
||||||
return self._pos
|
self.cta_engine.put_strategy_event(self)
|
||||||
|
@ -3,7 +3,7 @@ from typing import Any
|
|||||||
from vnpy.event import EventEngine, Event
|
from vnpy.event import EventEngine, Event
|
||||||
from vnpy.trader.engine import BaseEngine, MainEngine
|
from vnpy.trader.engine import BaseEngine, MainEngine
|
||||||
from vnpy.trader.ui import QtGui, QtWidgets, QtCore
|
from vnpy.trader.ui import QtGui, QtWidgets, QtCore
|
||||||
from vnpy.trader.ui.widget import BaseMonitor, BaseCell, EnumCell, DirectionCell
|
from vnpy.trader.ui.widget import BaseMonitor, BaseCell, EnumCell, TimeCell, MsgCell
|
||||||
|
|
||||||
from ..engine import CtaEngine
|
from ..engine import CtaEngine
|
||||||
from ..base import APP_NAME, EVENT_CTA_LOG, EVENT_CTA_STOPORDER, EVENT_CTA_STRATEGY
|
from ..base import APP_NAME, EVENT_CTA_LOG, EVENT_CTA_STOPORDER, EVENT_CTA_STRATEGY
|
||||||
@ -21,12 +21,12 @@ class CtaManager(QtWidgets.QWidget):
|
|||||||
self.event_engine = event_engine
|
self.event_engine = event_engine
|
||||||
self.cta_engine = main_engine.get_engine(APP_NAME)
|
self.cta_engine = main_engine.get_engine(APP_NAME)
|
||||||
|
|
||||||
self.cta_engine.init_engine()
|
|
||||||
|
|
||||||
self.managers = {}
|
self.managers = {}
|
||||||
|
|
||||||
self.init_ui()
|
self.init_ui()
|
||||||
self.register_event()
|
self.register_event()
|
||||||
|
self.cta_engine.init_engine()
|
||||||
|
self.update_class_combo()
|
||||||
|
|
||||||
def init_ui(self):
|
def init_ui(self):
|
||||||
""""""
|
""""""
|
||||||
@ -34,9 +34,6 @@ class CtaManager(QtWidgets.QWidget):
|
|||||||
|
|
||||||
# Create widgets
|
# Create widgets
|
||||||
self.class_combo = QtWidgets.QComboBox()
|
self.class_combo = QtWidgets.QComboBox()
|
||||||
self.class_combo.addItems(
|
|
||||||
self.cta_engine.get_all_strategy_class_names()
|
|
||||||
)
|
|
||||||
|
|
||||||
add_button = QtWidgets.QPushButton("添加策略")
|
add_button = QtWidgets.QPushButton("添加策略")
|
||||||
add_button.clicked.connect(self.add_strategy)
|
add_button.clicked.connect(self.add_strategy)
|
||||||
@ -51,6 +48,7 @@ class CtaManager(QtWidgets.QWidget):
|
|||||||
stop_button.clicked.connect(self.cta_engine.stop_all_strategies)
|
stop_button.clicked.connect(self.cta_engine.stop_all_strategies)
|
||||||
|
|
||||||
self.scroll_layout = QtWidgets.QVBoxLayout()
|
self.scroll_layout = QtWidgets.QVBoxLayout()
|
||||||
|
self.scroll_layout.addStretch()
|
||||||
|
|
||||||
scroll_widget = QtWidgets.QWidget()
|
scroll_widget = QtWidgets.QWidget()
|
||||||
scroll_widget.setLayout(self.scroll_layout)
|
scroll_widget.setLayout(self.scroll_layout)
|
||||||
@ -61,15 +59,12 @@ class CtaManager(QtWidgets.QWidget):
|
|||||||
|
|
||||||
bottom_height = 300
|
bottom_height = 300
|
||||||
|
|
||||||
self.log_monitor = QtWidgets.QTextEdit()
|
self.log_monitor = LogMonitor(self.main_engine, self.event_engine)
|
||||||
self.log_monitor.setReadOnly(True)
|
|
||||||
self.log_monitor.setMaximumHeight(bottom_height)
|
|
||||||
|
|
||||||
self.stop_order_monitor = StopOrderMonitor(
|
self.stop_order_monitor = StopOrderMonitor(
|
||||||
self.main_engine,
|
self.main_engine,
|
||||||
self.event_engine
|
self.event_engine
|
||||||
)
|
)
|
||||||
self.stop_order_monitor.setMaximumHeight(bottom_height)
|
|
||||||
|
|
||||||
# Set layout
|
# Set layout
|
||||||
hbox1 = QtWidgets.QHBoxLayout()
|
hbox1 = QtWidgets.QHBoxLayout()
|
||||||
@ -80,54 +75,50 @@ class CtaManager(QtWidgets.QWidget):
|
|||||||
hbox1.addWidget(start_button)
|
hbox1.addWidget(start_button)
|
||||||
hbox1.addWidget(stop_button)
|
hbox1.addWidget(stop_button)
|
||||||
|
|
||||||
hbox2 = QtWidgets.QHBoxLayout()
|
grid = QtWidgets.QGridLayout()
|
||||||
hbox2.addWidget(self.log_monitor)
|
grid.addWidget(scroll_area, 0, 0, 2, 1)
|
||||||
hbox2.addWidget(self.stop_order_monitor)
|
grid.addWidget(self.stop_order_monitor, 0, 1)
|
||||||
|
grid.addWidget(self.log_monitor, 1, 1)
|
||||||
|
|
||||||
vbox = QtWidgets.QVBoxLayout()
|
vbox = QtWidgets.QVBoxLayout()
|
||||||
vbox.addLayout(hbox1)
|
vbox.addLayout(hbox1)
|
||||||
vbox.addWidget(scroll_area)
|
vbox.addLayout(grid)
|
||||||
vbox.addLayout(hbox2)
|
|
||||||
|
|
||||||
self.setLayout(vbox)
|
self.setLayout(vbox)
|
||||||
|
|
||||||
|
def update_class_combo(self):
|
||||||
|
""""""
|
||||||
|
self.class_combo.addItems(
|
||||||
|
self.cta_engine.get_all_strategy_class_names()
|
||||||
|
)
|
||||||
|
|
||||||
def register_event(self):
|
def register_event(self):
|
||||||
""""""
|
""""""
|
||||||
self.signal_log.connect(self.process_log_event)
|
|
||||||
self.signal_strategy.connect(self.process_strategy_event)
|
self.signal_strategy.connect(self.process_strategy_event)
|
||||||
|
|
||||||
self.event_engine.register(EVENT_CTA_LOG, self.signal_log.emit)
|
|
||||||
self.event_engine.register(
|
self.event_engine.register(
|
||||||
EVENT_CTA_STRATEGY,
|
EVENT_CTA_STRATEGY,
|
||||||
self.signal_strategy.emit
|
self.signal_strategy.emit
|
||||||
)
|
)
|
||||||
|
|
||||||
def process_log_event(self, event):
|
|
||||||
"""
|
|
||||||
Update log output.
|
|
||||||
"""
|
|
||||||
log = event.data
|
|
||||||
time = log.time.strftime("%H:%M:S")
|
|
||||||
msg = f"{time}:\t{log.msg}"
|
|
||||||
self.log_monitor.append(msg)
|
|
||||||
|
|
||||||
def process_strategy_event(self, event):
|
def process_strategy_event(self, event):
|
||||||
"""
|
"""
|
||||||
Update strategy status onto its monitor.
|
Update strategy status onto its monitor.
|
||||||
"""
|
"""
|
||||||
data = event.data
|
data = event.data
|
||||||
name = data["name"]
|
strategy_name = data["strategy_name"]
|
||||||
|
|
||||||
if name in self.managers:
|
if strategy_name in self.managers:
|
||||||
manager = self.managers[name]
|
manager = self.managers[strategy_name]
|
||||||
manager.update_data(data)
|
manager.update_data(data)
|
||||||
else:
|
else:
|
||||||
manager = StrategyManager(self, self.cta_engine, data)
|
manager = StrategyManager(self, self.cta_engine, data)
|
||||||
self.scroll_layout.insertWidget(0, manager)
|
self.scroll_layout.insertWidget(0, manager)
|
||||||
|
self.managers[strategy_name] = manager
|
||||||
|
|
||||||
def remove_strategy(self, name):
|
def remove_strategy(self, strategy_name):
|
||||||
""""""
|
""""""
|
||||||
manager = self.managers[name]
|
manager = self.managers[strategy_name]
|
||||||
manager.deleteLater()
|
manager.deleteLater()
|
||||||
|
|
||||||
def add_strategy(self):
|
def add_strategy(self):
|
||||||
@ -137,20 +128,27 @@ class CtaManager(QtWidgets.QWidget):
|
|||||||
return
|
return
|
||||||
|
|
||||||
parameters = self.cta_engine.get_strategy_class_parameters(class_name)
|
parameters = self.cta_engine.get_strategy_class_parameters(class_name)
|
||||||
|
|
||||||
editor = SettingEditor(parameters, class_name=class_name)
|
editor = SettingEditor(parameters, class_name=class_name)
|
||||||
n = editor.exec_()
|
n = editor.exec_()
|
||||||
|
|
||||||
if n == editor.Accepted:
|
if n == editor.Accepted:
|
||||||
setting = editor.get_setting()
|
setting = editor.get_setting()
|
||||||
self.cta_engine.add_strategy(setting)
|
vt_symbol = setting.pop("vt_symbol")
|
||||||
|
strategy_name = setting.pop("strategy_name")
|
||||||
|
|
||||||
|
self.cta_engine.add_strategy(
|
||||||
|
class_name,
|
||||||
|
strategy_name,
|
||||||
|
vt_symbol,
|
||||||
|
setting
|
||||||
|
)
|
||||||
|
|
||||||
def show(self):
|
def show(self):
|
||||||
""""""
|
""""""
|
||||||
self.showMaximized()
|
self.showMaximized()
|
||||||
|
|
||||||
|
|
||||||
class StrategyManager(QtWidgets.QWidget):
|
class StrategyManager(QtWidgets.QFrame):
|
||||||
"""
|
"""
|
||||||
Manager for a strategy
|
Manager for a strategy
|
||||||
"""
|
"""
|
||||||
@ -162,16 +160,22 @@ class StrategyManager(QtWidgets.QWidget):
|
|||||||
data: dict
|
data: dict
|
||||||
):
|
):
|
||||||
""""""
|
""""""
|
||||||
|
super(StrategyManager, self).__init__()
|
||||||
|
|
||||||
self.cta_manager = cta_manager
|
self.cta_manager = cta_manager
|
||||||
self.cta_engine = cta_engine
|
self.cta_engine = cta_engine
|
||||||
|
|
||||||
self.name = data["name"]
|
self.strategy_name = data["strategy_name"]
|
||||||
self._data = data
|
self._data = data
|
||||||
|
|
||||||
self.init_ui()
|
self.init_ui()
|
||||||
|
|
||||||
def init_ui(self):
|
def init_ui(self):
|
||||||
""""""
|
""""""
|
||||||
|
self.setMaximumHeight(200)
|
||||||
|
self.setFrameShape(self.Box)
|
||||||
|
self.setLineWidth(1)
|
||||||
|
|
||||||
init_button = QtWidgets.QPushButton("初始化")
|
init_button = QtWidgets.QPushButton("初始化")
|
||||||
init_button.clicked.connect(self.init_strategy)
|
init_button.clicked.connect(self.init_strategy)
|
||||||
|
|
||||||
@ -187,27 +191,19 @@ class StrategyManager(QtWidgets.QWidget):
|
|||||||
remove_button = QtWidgets.QPushButton("移除")
|
remove_button = QtWidgets.QPushButton("移除")
|
||||||
remove_button.clicked.connect(self.remove_strategy)
|
remove_button.clicked.connect(self.remove_strategy)
|
||||||
|
|
||||||
self.name_label = QtWidgets.QLabel(f"策略名:{self._data['name']}")
|
strategy_name = self._data["strategy_name"]
|
||||||
self.class_label = QtWidgets.QLabel(f"策略类:{self._data['class_name']}")
|
vt_symbol = self._data["vt_symbol"]
|
||||||
self.symbol_label = QtWidgets.QLabel(f"代码:{self._data['vt_symbol']}")
|
class_name = self._data["class_name"]
|
||||||
self.author_label = QtWidgets.QLabel(f"作者:{self._data['author']}")
|
author = self._data["author"]
|
||||||
self.inited_label = QtWidgets.QLabel(f"inited:{self._data['inited']}")
|
|
||||||
self.trading_label = QtWidgets.QLabel(
|
label_text = f"{strategy_name} - {vt_symbol} ({class_name} by {author})"
|
||||||
f"trading:{self._data['trading']}"
|
label = QtWidgets.QLabel(label_text)
|
||||||
)
|
label.setAlignment(QtCore.Qt.AlignCenter)
|
||||||
self.pos_label = QtWidgets.QLabel(f"pos:{self._data['pos']}")
|
|
||||||
|
|
||||||
self.parameters_monitor = DataMonitor(self._data["parameters"])
|
self.parameters_monitor = DataMonitor(self._data["parameters"])
|
||||||
self.variables_monitor = DataMonitor(self._data["variables"])
|
self.variables_monitor = DataMonitor(self._data["variables"])
|
||||||
|
|
||||||
hbox = QtWidgets.QHBoxLayout()
|
hbox = QtWidgets.QHBoxLayout()
|
||||||
hbox.addWidget(self.name_label)
|
|
||||||
hbox.addWidget(self.class_label)
|
|
||||||
hbox.addWidget(self.symbol_label)
|
|
||||||
hbox.addWidget(self.author_label)
|
|
||||||
hbox.addWidget(self.inited_label)
|
|
||||||
hbox.addWidget(self.trading_label)
|
|
||||||
hbox.addWidget(self.pos_label)
|
|
||||||
hbox.addWidget(init_button)
|
hbox.addWidget(init_button)
|
||||||
hbox.addWidget(start_button)
|
hbox.addWidget(start_button)
|
||||||
hbox.addWidget(stop_button)
|
hbox.addWidget(stop_button)
|
||||||
@ -215,6 +211,7 @@ class StrategyManager(QtWidgets.QWidget):
|
|||||||
hbox.addWidget(remove_button)
|
hbox.addWidget(remove_button)
|
||||||
|
|
||||||
vbox = QtWidgets.QVBoxLayout()
|
vbox = QtWidgets.QVBoxLayout()
|
||||||
|
vbox.addWidget(label)
|
||||||
vbox.addLayout(hbox)
|
vbox.addLayout(hbox)
|
||||||
vbox.addWidget(self.parameters_monitor)
|
vbox.addWidget(self.parameters_monitor)
|
||||||
vbox.addWidget(self.variables_monitor)
|
vbox.addWidget(self.variables_monitor)
|
||||||
@ -224,33 +221,39 @@ class StrategyManager(QtWidgets.QWidget):
|
|||||||
""""""
|
""""""
|
||||||
self._data = data
|
self._data = data
|
||||||
|
|
||||||
self.inited_label.setText(f"inited:{data['inited']}")
|
|
||||||
self.trading_label.setText(f"trading:{data['trading']}")
|
|
||||||
self.pos_label.setText(f"pos:{data['pos']}")
|
|
||||||
|
|
||||||
self.parameters_monitor.update_data(data["parameters"])
|
self.parameters_monitor.update_data(data["parameters"])
|
||||||
self.variables_monitor.update_data(data["variables"])
|
self.variables_monitor.update_data(data["variables"])
|
||||||
|
|
||||||
def init_strategy(self):
|
def init_strategy(self):
|
||||||
""""""
|
""""""
|
||||||
self.cta_engine.init_strategy(self.name)
|
self.cta_engine.init_strategy(self.strategy_name)
|
||||||
|
|
||||||
def start_strategy(self):
|
def start_strategy(self):
|
||||||
""""""
|
""""""
|
||||||
self.cta_engine.start_strategy(self.name)
|
self.cta_engine.start_strategy(self.strategy_name)
|
||||||
|
|
||||||
def stop_strategy(self):
|
def stop_strategy(self):
|
||||||
""""""
|
""""""
|
||||||
self.cta_engine.stop_strategy(self.name)
|
self.cta_engine.stop_strategy(self.strategy_name)
|
||||||
|
|
||||||
def edit_strategy(self):
|
def edit_strategy(self):
|
||||||
""""""
|
""""""
|
||||||
pass
|
vt_symbol = self._data["vt_symbol"]
|
||||||
|
class_name = self._data["class_name"]
|
||||||
|
strategy_name = self._data["strategy_name"]
|
||||||
|
|
||||||
|
parameters = self.cta_engine.get_strategy_parameters(strategy_name)
|
||||||
|
editor = SettingEditor(parameters, strategy_name=strategy_name)
|
||||||
|
n = editor.exec_()
|
||||||
|
|
||||||
|
if n == editor.Accepted:
|
||||||
|
setting = editor.get_setting()
|
||||||
|
self.cta_engine.edit_strategy(strategy_name, setting)
|
||||||
|
|
||||||
def remove_strategy(self):
|
def remove_strategy(self):
|
||||||
""""""
|
""""""
|
||||||
self.cta_engine.remove_strategy(self.name)
|
self.cta_engine.remove_strategy(self.strategy_name)
|
||||||
self.cta_manager.remove_strategy(self.name)
|
self.cta_manager.remove_strategy(self.strategy_name)
|
||||||
|
|
||||||
|
|
||||||
class DataMonitor(QtWidgets.QTableWidget):
|
class DataMonitor(QtWidgets.QTableWidget):
|
||||||
@ -270,16 +273,22 @@ class DataMonitor(QtWidgets.QTableWidget):
|
|||||||
def init_ui(self):
|
def init_ui(self):
|
||||||
""""""
|
""""""
|
||||||
labels = list(self._data.keys())
|
labels = list(self._data.keys())
|
||||||
self.setColumnCount(labels)
|
self.setColumnCount(len(labels))
|
||||||
self.setHorizontalHeaderLabels(labels)
|
self.setHorizontalHeaderLabels(labels)
|
||||||
|
|
||||||
self.setRowCount(1)
|
self.setRowCount(1)
|
||||||
|
self.verticalHeader().setSectionResizeMode(
|
||||||
|
QtWidgets.QHeaderView.Stretch
|
||||||
|
)
|
||||||
self.verticalHeader().setVisible(False)
|
self.verticalHeader().setVisible(False)
|
||||||
self.setEditTriggers(self.NoEditTriggers)
|
self.setEditTriggers(self.NoEditTriggers)
|
||||||
|
|
||||||
for column, name in enumerate(self._data.items()):
|
for column, name in enumerate(self._data.keys()):
|
||||||
value = self._data[name]
|
value = self._data[name]
|
||||||
|
|
||||||
cell = QtWidgets.QTableWidgetItem(str(value))
|
cell = QtWidgets.QTableWidgetItem(str(value))
|
||||||
|
cell.setTextAlignment(QtCore.Qt.AlignCenter)
|
||||||
|
|
||||||
self.setItem(0, column, cell)
|
self.setItem(0, column, cell)
|
||||||
self.cells[name] = cell
|
self.cells[name] = cell
|
||||||
|
|
||||||
@ -304,7 +313,7 @@ class StrategyCell(BaseCell):
|
|||||||
Set text using enum.constant.value.
|
Set text using enum.constant.value.
|
||||||
"""
|
"""
|
||||||
if content:
|
if content:
|
||||||
super(StrategyCell, self).set_content(content.name, data)
|
super(StrategyCell, self).set_content(content.strategy_name, data)
|
||||||
|
|
||||||
|
|
||||||
class StopOrderMonitor(BaseMonitor):
|
class StopOrderMonitor(BaseMonitor):
|
||||||
@ -358,6 +367,56 @@ class StopOrderMonitor(BaseMonitor):
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def init_ui(self):
|
||||||
|
"""
|
||||||
|
Stretch columns.
|
||||||
|
"""
|
||||||
|
super(StopOrderMonitor, self).init_ui()
|
||||||
|
|
||||||
|
self.horizontalHeader().setSectionResizeMode(
|
||||||
|
QtWidgets.QHeaderView.Stretch
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class LogMonitor(BaseMonitor):
|
||||||
|
"""
|
||||||
|
Monitor for log data.
|
||||||
|
"""
|
||||||
|
event_type = EVENT_CTA_LOG
|
||||||
|
data_key = ""
|
||||||
|
sorting = False
|
||||||
|
|
||||||
|
headers = {
|
||||||
|
"time": {
|
||||||
|
"display": "时间",
|
||||||
|
"cell": TimeCell,
|
||||||
|
"update": False
|
||||||
|
},
|
||||||
|
"msg": {
|
||||||
|
"display": "信息",
|
||||||
|
"cell": MsgCell,
|
||||||
|
"update": False
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def init_ui(self):
|
||||||
|
"""
|
||||||
|
Stretch last column.
|
||||||
|
"""
|
||||||
|
super(LogMonitor, self).init_ui()
|
||||||
|
|
||||||
|
self.horizontalHeader().setSectionResizeMode(
|
||||||
|
1,
|
||||||
|
QtWidgets.QHeaderView.Stretch
|
||||||
|
)
|
||||||
|
|
||||||
|
def insert_new_row(self, data):
|
||||||
|
"""
|
||||||
|
Insert a new row at the top of table.
|
||||||
|
"""
|
||||||
|
super(LogMonitor, self).insert_new_row(data)
|
||||||
|
self.resizeRowToContents(0)
|
||||||
|
|
||||||
|
|
||||||
class SettingEditor(QtWidgets.QDialog):
|
class SettingEditor(QtWidgets.QDialog):
|
||||||
"""
|
"""
|
||||||
@ -400,12 +459,19 @@ class SettingEditor(QtWidgets.QDialog):
|
|||||||
type_ = type(value)
|
type_ = type(value)
|
||||||
|
|
||||||
edit = QtWidgets.QLineEdit(str(value))
|
edit = QtWidgets.QLineEdit(str(value))
|
||||||
|
if type_ is int:
|
||||||
|
validator = QtGui.QIntValidator()
|
||||||
|
edit.setValidator(validator)
|
||||||
|
elif type_ is float:
|
||||||
|
validator = QtGui.QDoubleValidator()
|
||||||
|
edit.setValidator(validator)
|
||||||
|
|
||||||
form.addRow(f"{name} {type_}", edit)
|
form.addRow(f"{name} {type_}", edit)
|
||||||
|
|
||||||
self.edits[name] = (edit, type_)
|
self.edits[name] = (edit, type_)
|
||||||
|
|
||||||
button = QtWidgets.QPushButton(button_text)
|
button = QtWidgets.QPushButton(button_text)
|
||||||
button.clicked.connect(self.accpet)
|
button.clicked.connect(self.accept)
|
||||||
form.addRow(button)
|
form.addRow(button)
|
||||||
|
|
||||||
self.setLayout(form)
|
self.setLayout(form)
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
import platform
|
import platform
|
||||||
import ctypes
|
import ctypes
|
||||||
|
import traceback
|
||||||
|
import sys
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
import qdarkstyle
|
import qdarkstyle
|
||||||
@ -10,10 +12,23 @@ from ..setting import SETTINGS
|
|||||||
from ..utility import get_icon_path
|
from ..utility import get_icon_path
|
||||||
|
|
||||||
|
|
||||||
|
def excepthook(exctype, value, tb):
|
||||||
|
"""异常捕捉钩子"""
|
||||||
|
msg = ''.join(traceback.format_exception(exctype, value, tb))
|
||||||
|
QtWidgets.QMessageBox.critical(
|
||||||
|
None,
|
||||||
|
u'Exception',
|
||||||
|
msg,
|
||||||
|
QtWidgets.QMessageBox.Ok
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def create_qapp():
|
def create_qapp():
|
||||||
"""
|
"""
|
||||||
Create Qt Application.
|
Create Qt Application.
|
||||||
"""
|
"""
|
||||||
|
sys.excepthook = excepthook
|
||||||
|
|
||||||
qapp = QtWidgets.QApplication([])
|
qapp = QtWidgets.QApplication([])
|
||||||
qapp.setStyleSheet(qdarkstyle.load_stylesheet_pyqt5())
|
qapp.setStyleSheet(qdarkstyle.load_stylesheet_pyqt5())
|
||||||
|
|
||||||
|
@ -164,6 +164,17 @@ class TimeCell(BaseCell):
|
|||||||
self._data = data
|
self._data = data
|
||||||
|
|
||||||
|
|
||||||
|
class MsgCell(BaseCell):
|
||||||
|
"""
|
||||||
|
Cell used for showing msg data.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, content: str, data: Any):
|
||||||
|
""""""
|
||||||
|
super(MsgCell, self).__init__(content, data)
|
||||||
|
self.setTextAlignment(QtCore.Qt.AlignLeft|QtCore.Qt.AlignVCenter)
|
||||||
|
|
||||||
|
|
||||||
class BaseMonitor(QtWidgets.QTableWidget):
|
class BaseMonitor(QtWidgets.QTableWidget):
|
||||||
"""
|
"""
|
||||||
Monitor data update in VN Trader.
|
Monitor data update in VN Trader.
|
||||||
@ -422,7 +433,7 @@ class LogMonitor(BaseMonitor):
|
|||||||
},
|
},
|
||||||
"msg": {
|
"msg": {
|
||||||
"display": "信息",
|
"display": "信息",
|
||||||
"cell": BaseCell,
|
"cell": MsgCell,
|
||||||
"update": False
|
"update": False
|
||||||
},
|
},
|
||||||
"gateway_name": {
|
"gateway_name": {
|
||||||
|
Loading…
Reference in New Issue
Block a user