[Add] BasicSpreadStrategy for demo
This commit is contained in:
parent
80d89d1cb8
commit
6a5d04e61f
@ -75,7 +75,7 @@ def main():
|
|||||||
# main_engine.add_gateway(DaGateway)
|
# main_engine.add_gateway(DaGateway)
|
||||||
main_engine.add_gateway(CoinbaseGateway)
|
main_engine.add_gateway(CoinbaseGateway)
|
||||||
|
|
||||||
# main_engine.add_app(CtaStrategyApp)
|
main_engine.add_app(CtaStrategyApp)
|
||||||
# main_engine.add_app(CtaBacktesterApp)
|
# main_engine.add_app(CtaBacktesterApp)
|
||||||
# main_engine.add_app(CsvLoaderApp)
|
# main_engine.add_app(CsvLoaderApp)
|
||||||
# main_engine.add_app(AlgoTradingApp)
|
# main_engine.add_app(AlgoTradingApp)
|
||||||
|
@ -1,8 +1,19 @@
|
|||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
from vnpy.trader.app import BaseApp
|
from vnpy.trader.app import BaseApp
|
||||||
|
from vnpy.trader.object import (
|
||||||
|
OrderData,
|
||||||
|
TradeData
|
||||||
|
)
|
||||||
|
|
||||||
from .engine import SpreadEngine, APP_NAME
|
from .engine import (
|
||||||
|
SpreadEngine,
|
||||||
|
APP_NAME,
|
||||||
|
SpreadData,
|
||||||
|
LegData,
|
||||||
|
SpreadStrategyTemplate,
|
||||||
|
SpreadAlgoTemplate
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class SpreadTradingApp(BaseApp):
|
class SpreadTradingApp(BaseApp):
|
||||||
|
@ -48,6 +48,8 @@ class SpreadEngine(BaseEngine):
|
|||||||
|
|
||||||
self.add_spread = self.data_engine.add_spread
|
self.add_spread = self.data_engine.add_spread
|
||||||
self.remove_spread = self.data_engine.remove_spread
|
self.remove_spread = self.data_engine.remove_spread
|
||||||
|
self.get_spread = self.data_engine.get_spread
|
||||||
|
self.get_all_spreads = self.data_engine.get_all_spreads
|
||||||
|
|
||||||
self.start_algo = self.algo_engine.start_algo
|
self.start_algo = self.algo_engine.start_algo
|
||||||
self.stop_algo = self.algo_engine.stop_algo
|
self.stop_algo = self.algo_engine.stop_algo
|
||||||
@ -60,6 +62,13 @@ class SpreadEngine(BaseEngine):
|
|||||||
|
|
||||||
self.data_engine.start()
|
self.data_engine.start()
|
||||||
self.algo_engine.start()
|
self.algo_engine.start()
|
||||||
|
self.strategy_engine.start()
|
||||||
|
|
||||||
|
def stop(self):
|
||||||
|
""""""
|
||||||
|
self.data_engine.stop()
|
||||||
|
self.algo_engine.stop()
|
||||||
|
self.strategy_engine.stop()
|
||||||
|
|
||||||
def write_log(self, msg: str):
|
def write_log(self, msg: str):
|
||||||
""""""
|
""""""
|
||||||
@ -94,6 +103,10 @@ class SpreadDataEngine:
|
|||||||
|
|
||||||
self.write_log("价差数据引擎启动成功")
|
self.write_log("价差数据引擎启动成功")
|
||||||
|
|
||||||
|
def stop(self):
|
||||||
|
""""""
|
||||||
|
pass
|
||||||
|
|
||||||
def load_setting(self) -> None:
|
def load_setting(self) -> None:
|
||||||
""""""
|
""""""
|
||||||
setting = load_json(self.setting_filename)
|
setting = load_json(self.setting_filename)
|
||||||
@ -251,11 +264,20 @@ class SpreadDataEngine:
|
|||||||
|
|
||||||
spread = self.spreads.pop(name)
|
spread = self.spreads.pop(name)
|
||||||
|
|
||||||
for leg in spread.legs:
|
for leg in spread.legs.values():
|
||||||
self.symbol_spread_map[leg.vt_symbol].remove(spread)
|
self.symbol_spread_map[leg.vt_symbol].remove(spread)
|
||||||
|
|
||||||
self.save_setting()
|
self.save_setting()
|
||||||
self.write_log("价差删除成功:{}".format(name))
|
self.write_log("价差移除成功:{},重启后生效".format(name))
|
||||||
|
|
||||||
|
def get_spread(self, name: str) -> SpreadData:
|
||||||
|
""""""
|
||||||
|
spread = self.spreads.get(name, None)
|
||||||
|
return spread
|
||||||
|
|
||||||
|
def get_all_spreads(self) -> List[SpreadData]:
|
||||||
|
""""""
|
||||||
|
return list(self.spreads.values())
|
||||||
|
|
||||||
|
|
||||||
class SpreadAlgoEngine:
|
class SpreadAlgoEngine:
|
||||||
@ -289,6 +311,11 @@ class SpreadAlgoEngine:
|
|||||||
|
|
||||||
self.write_log("价差算法引擎启动成功")
|
self.write_log("价差算法引擎启动成功")
|
||||||
|
|
||||||
|
def stop(self):
|
||||||
|
""""""
|
||||||
|
for algo in self.algos.values():
|
||||||
|
self.stop_algo(algo)
|
||||||
|
|
||||||
def register_event(self):
|
def register_event(self):
|
||||||
""""""
|
""""""
|
||||||
self.event_engine.register(EVENT_TICK, self.process_tick_event)
|
self.event_engine.register(EVENT_TICK, self.process_tick_event)
|
||||||
@ -533,9 +560,10 @@ class SpreadStrategyEngine:
|
|||||||
|
|
||||||
self.vt_tradeids: Set = set()
|
self.vt_tradeids: Set = set()
|
||||||
|
|
||||||
|
self.load_strategy_class()
|
||||||
|
|
||||||
def start(self):
|
def start(self):
|
||||||
""""""
|
""""""
|
||||||
self.load_strategy_class()
|
|
||||||
self.load_strategy_setting()
|
self.load_strategy_setting()
|
||||||
self.register_event()
|
self.register_event()
|
||||||
|
|
||||||
@ -551,7 +579,7 @@ class SpreadStrategyEngine:
|
|||||||
"""
|
"""
|
||||||
path1 = Path(__file__).parent.joinpath("strategies")
|
path1 = Path(__file__).parent.joinpath("strategies")
|
||||||
self.load_strategy_class_from_folder(
|
self.load_strategy_class_from_folder(
|
||||||
path1, "vnpy.app.cta_strategy.strategies")
|
path1, "vnpy.app.spread_trading.strategies")
|
||||||
|
|
||||||
path2 = Path.cwd().joinpath("strategies")
|
path2 = Path.cwd().joinpath("strategies")
|
||||||
self.load_strategy_class_from_folder(path2, "strategies")
|
self.load_strategy_class_from_folder(path2, "strategies")
|
||||||
@ -642,6 +670,7 @@ class SpreadStrategyEngine:
|
|||||||
strategies = self.spread_strategy_map[spread.name]
|
strategies = self.spread_strategy_map[spread.name]
|
||||||
|
|
||||||
for strategy in strategies:
|
for strategy in strategies:
|
||||||
|
if strategy.inited:
|
||||||
self.call_strategy_func(strategy, strategy.on_spread_data)
|
self.call_strategy_func(strategy, strategy.on_spread_data)
|
||||||
|
|
||||||
def process_spread_pos_event(self, event: Event):
|
def process_spread_pos_event(self, event: Event):
|
||||||
@ -650,6 +679,7 @@ class SpreadStrategyEngine:
|
|||||||
strategies = self.spread_strategy_map[spread.name]
|
strategies = self.spread_strategy_map[spread.name]
|
||||||
|
|
||||||
for strategy in strategies:
|
for strategy in strategies:
|
||||||
|
if strategy.inited:
|
||||||
self.call_strategy_func(strategy, strategy.on_spread_pos)
|
self.call_strategy_func(strategy, strategy.on_spread_pos)
|
||||||
|
|
||||||
def process_spread_algo_event(self, event: Event):
|
def process_spread_algo_event(self, event: Event):
|
||||||
@ -671,7 +701,7 @@ class SpreadStrategyEngine:
|
|||||||
def process_trade_event(self, event: Event):
|
def process_trade_event(self, event: Event):
|
||||||
""""""
|
""""""
|
||||||
trade = event.data
|
trade = event.data
|
||||||
strategy = self.trade_strategy_map.get(trade.vt_orderid, None)
|
strategy = self.order_strategy_map.get(trade.vt_orderid, None)
|
||||||
|
|
||||||
if strategy:
|
if strategy:
|
||||||
self.call_strategy_func(strategy, strategy.on_trade, trade)
|
self.call_strategy_func(strategy, strategy.on_trade, trade)
|
||||||
@ -692,7 +722,7 @@ class SpreadStrategyEngine:
|
|||||||
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_strategy_log(strategy, msg)
|
||||||
|
|
||||||
def add_strategy(
|
def add_strategy(
|
||||||
self, class_name: str, strategy_name: str, spread_name: str, setting: dict
|
self, class_name: str, strategy_name: str, spread_name: str, setting: dict
|
||||||
@ -709,7 +739,12 @@ class SpreadStrategyEngine:
|
|||||||
self.write_log(f"创建策略失败,找不到策略类{class_name}")
|
self.write_log(f"创建策略失败,找不到策略类{class_name}")
|
||||||
return
|
return
|
||||||
|
|
||||||
strategy = strategy_class(self, strategy_name, spread_name, setting)
|
spread = self.spread_engine.get_spread(spread_name)
|
||||||
|
if not spread:
|
||||||
|
self.write_log(f"创建策略失败,找不到价差{spread_name}")
|
||||||
|
return
|
||||||
|
|
||||||
|
strategy = strategy_class(self, strategy_name, spread, setting)
|
||||||
self.strategies[strategy_name] = strategy
|
self.strategies[strategy_name] = strategy
|
||||||
|
|
||||||
# Add vt_symbol to strategy map.
|
# Add vt_symbol to strategy map.
|
||||||
@ -721,6 +756,37 @@ class SpreadStrategyEngine:
|
|||||||
|
|
||||||
self.put_strategy_event(strategy)
|
self.put_strategy_event(strategy)
|
||||||
|
|
||||||
|
def edit_strategy(self, strategy_name: str, setting: dict):
|
||||||
|
"""
|
||||||
|
Edit parameters of a strategy.
|
||||||
|
"""
|
||||||
|
strategy = self.strategies[strategy_name]
|
||||||
|
strategy.update_setting(setting)
|
||||||
|
|
||||||
|
self.update_strategy_setting(strategy_name, setting)
|
||||||
|
self.put_strategy_event(strategy)
|
||||||
|
|
||||||
|
def remove_strategy(self, strategy_name: str):
|
||||||
|
"""
|
||||||
|
Remove a strategy.
|
||||||
|
"""
|
||||||
|
strategy = self.strategies[strategy_name]
|
||||||
|
if strategy.trading:
|
||||||
|
self.write_log(f"策略{strategy.strategy_name}移除失败,请先停止")
|
||||||
|
return
|
||||||
|
|
||||||
|
# Remove setting
|
||||||
|
self.remove_strategy_setting(strategy_name)
|
||||||
|
|
||||||
|
# Remove from symbol strategy map
|
||||||
|
strategies = self.spread_strategy_map[strategy.spread_name]
|
||||||
|
strategies.remove(strategy)
|
||||||
|
|
||||||
|
# Remove from strategies
|
||||||
|
self.strategies.pop(strategy_name)
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
def init_strategy(self, strategy_name: str):
|
def init_strategy(self, strategy_name: str):
|
||||||
""""""
|
""""""
|
||||||
strategy = self.strategies[strategy_name]
|
strategy = self.strategies[strategy_name]
|
||||||
@ -758,28 +824,48 @@ class SpreadStrategyEngine:
|
|||||||
return
|
return
|
||||||
|
|
||||||
self.call_strategy_func(strategy, strategy.on_stop)
|
self.call_strategy_func(strategy, strategy.on_stop)
|
||||||
strategy.trading = False
|
|
||||||
|
|
||||||
strategy.stop_all_algos()
|
strategy.stop_all_algos()
|
||||||
strategy.cancel_all_orders()
|
strategy.cancel_all_orders()
|
||||||
|
|
||||||
|
strategy.trading = False
|
||||||
|
|
||||||
self.put_strategy_event(strategy)
|
self.put_strategy_event(strategy)
|
||||||
|
|
||||||
def init_all_strategies(self):
|
def init_all_strategies(self):
|
||||||
""""""
|
""""""
|
||||||
for strategy in self.strategies.values():
|
for strategy in self.strategies.keys():
|
||||||
self.init_strategy(strategy)
|
self.init_strategy(strategy)
|
||||||
|
|
||||||
def start_all_strategies(self):
|
def start_all_strategies(self):
|
||||||
""""""
|
""""""
|
||||||
for strategy in self.strategies.values():
|
for strategy in self.strategies.keys():
|
||||||
self.start_strategy(strategy)
|
self.start_strategy(strategy)
|
||||||
|
|
||||||
def stop_all_strategies(self):
|
def stop_all_strategies(self):
|
||||||
""""""
|
""""""
|
||||||
for strategy in self.strategies.values():
|
for strategy in self.strategies.keys():
|
||||||
self.stop_strategy(strategy)
|
self.stop_strategy(strategy)
|
||||||
|
|
||||||
|
def get_strategy_class_parameters(self, class_name: str):
|
||||||
|
"""
|
||||||
|
Get default parameters of a strategy class.
|
||||||
|
"""
|
||||||
|
strategy_class = self.classes[class_name]
|
||||||
|
|
||||||
|
parameters = {}
|
||||||
|
for name in strategy_class.parameters:
|
||||||
|
parameters[name] = getattr(strategy_class, name)
|
||||||
|
|
||||||
|
return parameters
|
||||||
|
|
||||||
|
def get_strategy_parameters(self, strategy_name):
|
||||||
|
"""
|
||||||
|
Get parameters of a strategy.
|
||||||
|
"""
|
||||||
|
strategy = self.strategies[strategy_name]
|
||||||
|
return strategy.get_parameters()
|
||||||
|
|
||||||
def start_algo(
|
def start_algo(
|
||||||
self,
|
self,
|
||||||
strategy: SpreadStrategyTemplate,
|
strategy: SpreadStrategyTemplate,
|
||||||
@ -864,7 +950,8 @@ class SpreadStrategyEngine:
|
|||||||
""""""
|
""""""
|
||||||
order = self.main_engine.get_order(vt_orderid)
|
order = self.main_engine.get_order(vt_orderid)
|
||||||
if not order:
|
if not order:
|
||||||
self.write_strategy_log(strategy, "撤单失败,找不到委托{}".format(vt_orderid))
|
self.write_strategy_log(
|
||||||
|
strategy, "撤单失败,找不到委托{}".format(vt_orderid))
|
||||||
return
|
return
|
||||||
|
|
||||||
req = order.create_cancel_request()
|
req = order.create_cancel_request()
|
||||||
@ -876,7 +963,8 @@ class SpreadStrategyEngine:
|
|||||||
|
|
||||||
def put_strategy_event(self, strategy: SpreadStrategyTemplate):
|
def put_strategy_event(self, strategy: SpreadStrategyTemplate):
|
||||||
""""""
|
""""""
|
||||||
event = Event(EVENT_SPREAD_STRATEGY, strategy)
|
data = strategy.get_data()
|
||||||
|
event = Event(EVENT_SPREAD_STRATEGY, data)
|
||||||
self.event_engine.put(event)
|
self.event_engine.put(event)
|
||||||
|
|
||||||
def write_strategy_log(self, strategy: SpreadStrategyTemplate, msg: str):
|
def write_strategy_log(self, strategy: SpreadStrategyTemplate, msg: str):
|
||||||
|
0
vnpy/app/spread_trading/strategies/__init__.py
Normal file
0
vnpy/app/spread_trading/strategies/__init__.py
Normal file
168
vnpy/app/spread_trading/strategies/basic_spread_strategy.py
Normal file
168
vnpy/app/spread_trading/strategies/basic_spread_strategy.py
Normal file
@ -0,0 +1,168 @@
|
|||||||
|
from vnpy.app.spread_trading import (
|
||||||
|
SpreadStrategyTemplate,
|
||||||
|
SpreadAlgoTemplate,
|
||||||
|
SpreadData,
|
||||||
|
OrderData,
|
||||||
|
TradeData
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class BasicSpreadStrategy(SpreadStrategyTemplate):
|
||||||
|
""""""
|
||||||
|
|
||||||
|
author = "用Python的交易员"
|
||||||
|
|
||||||
|
buy_price = 0.0
|
||||||
|
sell_price = 0.0
|
||||||
|
cover_price = 0.0
|
||||||
|
short_price = 0.0
|
||||||
|
max_pos = 0.0
|
||||||
|
payup = 10
|
||||||
|
interval = 5
|
||||||
|
|
||||||
|
spread_pos = 0.0
|
||||||
|
buy_algoid = ""
|
||||||
|
sell_algoid = ""
|
||||||
|
short_algoid = ""
|
||||||
|
cover_algoid = ""
|
||||||
|
|
||||||
|
parameters = [
|
||||||
|
"buy_price",
|
||||||
|
"sell_price",
|
||||||
|
"cover_price",
|
||||||
|
"short_price",
|
||||||
|
"max_pos",
|
||||||
|
"payup",
|
||||||
|
"interval"
|
||||||
|
]
|
||||||
|
variables = [
|
||||||
|
"spread_pos",
|
||||||
|
"buy_algoid",
|
||||||
|
"sell_algoid",
|
||||||
|
"short_algoid",
|
||||||
|
"cover_algoid",
|
||||||
|
]
|
||||||
|
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
strategy_engine,
|
||||||
|
strategy_name: str,
|
||||||
|
spread: SpreadData,
|
||||||
|
setting: dict
|
||||||
|
):
|
||||||
|
""""""
|
||||||
|
super().__init__(
|
||||||
|
strategy_engine, strategy_name, spread, setting
|
||||||
|
)
|
||||||
|
|
||||||
|
def on_init(self):
|
||||||
|
"""
|
||||||
|
Callback when strategy is inited.
|
||||||
|
"""
|
||||||
|
self.write_log("策略初始化")
|
||||||
|
|
||||||
|
def on_start(self):
|
||||||
|
"""
|
||||||
|
Callback when strategy is started.
|
||||||
|
"""
|
||||||
|
self.write_log("策略启动")
|
||||||
|
|
||||||
|
def on_stop(self):
|
||||||
|
"""
|
||||||
|
Callback when strategy is stopped.
|
||||||
|
"""
|
||||||
|
self.write_log("策略停止")
|
||||||
|
|
||||||
|
self.buy_algoid = ""
|
||||||
|
self.sell_algoid = ""
|
||||||
|
self.short_algoid = ""
|
||||||
|
self.cover_algoid = ""
|
||||||
|
self.put_event()
|
||||||
|
|
||||||
|
def on_spread_data(self):
|
||||||
|
"""
|
||||||
|
Callback when spread price is updated.
|
||||||
|
"""
|
||||||
|
self.spread_pos = self.get_spread_pos()
|
||||||
|
|
||||||
|
# No position
|
||||||
|
if not self.spread_pos:
|
||||||
|
# Start open algos
|
||||||
|
if not self.buy_algoid:
|
||||||
|
self.buy_algoid = self.start_long_algo(
|
||||||
|
self.buy_price, self.max_pos, self.payup, self.interval
|
||||||
|
)
|
||||||
|
|
||||||
|
if not self.short_algoid:
|
||||||
|
self.short_algoid = self.start_short_algo(
|
||||||
|
self.short_price, self.max_pos, self.payup, self.interval
|
||||||
|
)
|
||||||
|
|
||||||
|
# Stop close algos
|
||||||
|
if self.sell_algoid:
|
||||||
|
self.stop_algo(self.sell_algoid)
|
||||||
|
|
||||||
|
if self.cover_algoid:
|
||||||
|
self.stop_algo(self.cover_algoid)
|
||||||
|
|
||||||
|
# Long position
|
||||||
|
elif self.spread_pos > 0:
|
||||||
|
# Start sell close algo
|
||||||
|
if not self.sell_algoid:
|
||||||
|
self.sell_algoid = self.start_short_algo(
|
||||||
|
self.sell_price, self.spread_pos, self.payup, self.interval
|
||||||
|
)
|
||||||
|
|
||||||
|
# Stop buy open algo
|
||||||
|
if self.buy_algoid:
|
||||||
|
self.stop_algo(self.buy_algoid)
|
||||||
|
|
||||||
|
# Short position
|
||||||
|
elif self.spread_pos < 0:
|
||||||
|
# Start cover close algo
|
||||||
|
if not self.cover_algoid:
|
||||||
|
self.cover_algoid = self.start_long_algo(
|
||||||
|
self.cover_price, abs(
|
||||||
|
self.spread_pos), self.payup, self.interval
|
||||||
|
)
|
||||||
|
|
||||||
|
# Stop short open algo
|
||||||
|
if self.short_algoid:
|
||||||
|
self.stop_algo(self.short_algoid)
|
||||||
|
|
||||||
|
self.put_event()
|
||||||
|
|
||||||
|
def on_spread_pos(self):
|
||||||
|
"""
|
||||||
|
Callback when spread position is updated.
|
||||||
|
"""
|
||||||
|
self.spread_pos = self.get_spread_pos()
|
||||||
|
self.put_event()
|
||||||
|
|
||||||
|
def on_spread_algo(self, algo: SpreadAlgoTemplate):
|
||||||
|
"""
|
||||||
|
Callback when algo status is updated.
|
||||||
|
"""
|
||||||
|
if not algo.is_active():
|
||||||
|
if self.buy_algoid == algo.algoid:
|
||||||
|
self.buy_algoid = ""
|
||||||
|
elif self.sell_algoid == algo.algoid:
|
||||||
|
self.sell_algoid = ""
|
||||||
|
elif self.short_algoid == algo.algoid:
|
||||||
|
self.short_algoid = ""
|
||||||
|
else:
|
||||||
|
self.cover_algoid = ""
|
||||||
|
|
||||||
|
self.put_event()
|
||||||
|
|
||||||
|
def on_order(self, order: OrderData):
|
||||||
|
"""
|
||||||
|
Callback when order status is updated.
|
||||||
|
"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
def on_trade(self, trade: TradeData):
|
||||||
|
"""
|
||||||
|
Callback when new trade data is received.
|
||||||
|
"""
|
||||||
|
pass
|
@ -147,12 +147,12 @@ class SpreadAlgoTemplate:
|
|||||||
def update_timer(self):
|
def update_timer(self):
|
||||||
""""""
|
""""""
|
||||||
self.count += 1
|
self.count += 1
|
||||||
if self.count < self.interval:
|
if self.count > self.interval:
|
||||||
return
|
|
||||||
self.count = 0
|
self.count = 0
|
||||||
|
|
||||||
self.on_interval()
|
self.on_interval()
|
||||||
|
|
||||||
|
self.put_event()
|
||||||
|
|
||||||
def put_event(self):
|
def put_event(self):
|
||||||
""""""
|
""""""
|
||||||
self.algo_engine.put_algo_event(self)
|
self.algo_engine.put_algo_event(self)
|
||||||
@ -358,7 +358,7 @@ class SpreadStrategyTemplate:
|
|||||||
Callback when algo status is updated.
|
Callback when algo status is updated.
|
||||||
"""
|
"""
|
||||||
if not algo.is_active() and algo.algoid in self.algoids:
|
if not algo.is_active() and algo.algoid in self.algoids:
|
||||||
self.algoids.pop(algo.algoid)
|
self.algoids.remove(algo.algoid)
|
||||||
|
|
||||||
self.on_spread_algo(algo)
|
self.on_spread_algo(algo)
|
||||||
|
|
||||||
@ -367,7 +367,7 @@ class SpreadStrategyTemplate:
|
|||||||
Callback when order status is updated.
|
Callback when order status is updated.
|
||||||
"""
|
"""
|
||||||
if not order.is_active() and order.vt_orderid in self.vt_orderids:
|
if not order.is_active() and order.vt_orderid in self.vt_orderids:
|
||||||
self.vt_orderids.pop(order.vt_orderid)
|
self.vt_orderids.remove(order.vt_orderid)
|
||||||
|
|
||||||
self.on_order(order)
|
self.on_order(order)
|
||||||
|
|
||||||
@ -461,7 +461,7 @@ class SpreadStrategyTemplate:
|
|||||||
volume: float,
|
volume: float,
|
||||||
payup: int,
|
payup: int,
|
||||||
interval: int,
|
interval: int,
|
||||||
lock: bool
|
lock: bool = False
|
||||||
) -> str:
|
) -> str:
|
||||||
""""""
|
""""""
|
||||||
return self.start_algo(Direction.LONG, price, volume, payup, interval, lock)
|
return self.start_algo(Direction.LONG, price, volume, payup, interval, lock)
|
||||||
@ -472,7 +472,7 @@ class SpreadStrategyTemplate:
|
|||||||
volume: float,
|
volume: float,
|
||||||
payup: int,
|
payup: int,
|
||||||
interval: int,
|
interval: int,
|
||||||
lock: bool
|
lock: bool = False
|
||||||
) -> str:
|
) -> str:
|
||||||
""""""
|
""""""
|
||||||
return self.start_algo(Direction.SHORT, price, volume, payup, interval, lock)
|
return self.start_algo(Direction.SHORT, price, volume, payup, interval, lock)
|
||||||
|
@ -34,6 +34,7 @@ class SpreadManager(QtWidgets.QWidget):
|
|||||||
|
|
||||||
self.main_engine = main_engine
|
self.main_engine = main_engine
|
||||||
self.event_engine = event_engine
|
self.event_engine = event_engine
|
||||||
|
|
||||||
self.spread_engine = main_engine.get_engine(APP_NAME)
|
self.spread_engine = main_engine.get_engine(APP_NAME)
|
||||||
|
|
||||||
self.init_ui()
|
self.init_ui()
|
||||||
@ -43,8 +44,8 @@ class SpreadManager(QtWidgets.QWidget):
|
|||||||
self.setWindowTitle("价差交易")
|
self.setWindowTitle("价差交易")
|
||||||
|
|
||||||
self.algo_dialog = SpreadAlgoWidget(self.spread_engine)
|
self.algo_dialog = SpreadAlgoWidget(self.spread_engine)
|
||||||
algo_tab = self.create_tab("交易", self.algo_dialog)
|
algo_group = self.create_group("交易", self.algo_dialog)
|
||||||
algo_tab.setMaximumWidth(300)
|
algo_group.setMaximumWidth(300)
|
||||||
|
|
||||||
self.data_monitor = SpreadDataMonitor(
|
self.data_monitor = SpreadDataMonitor(
|
||||||
self.main_engine,
|
self.main_engine,
|
||||||
@ -63,13 +64,13 @@ class SpreadManager(QtWidgets.QWidget):
|
|||||||
)
|
)
|
||||||
|
|
||||||
grid = QtWidgets.QGridLayout()
|
grid = QtWidgets.QGridLayout()
|
||||||
grid.addWidget(self.create_tab("价差", self.data_monitor), 0, 0)
|
grid.addWidget(self.create_group("价差", self.data_monitor), 0, 0)
|
||||||
grid.addWidget(self.create_tab("日志", self.log_monitor), 1, 0)
|
grid.addWidget(self.create_group("日志", self.log_monitor), 1, 0)
|
||||||
grid.addWidget(self.create_tab("算法", self.algo_monitor), 0, 1)
|
grid.addWidget(self.create_group("算法", self.algo_monitor), 0, 1)
|
||||||
grid.addWidget(self.create_tab("策略", self.strategy_monitor), 1, 1)
|
grid.addWidget(self.create_group("策略", self.strategy_monitor), 1, 1)
|
||||||
|
|
||||||
hbox = QtWidgets.QHBoxLayout()
|
hbox = QtWidgets.QHBoxLayout()
|
||||||
hbox.addWidget(algo_tab)
|
hbox.addWidget(algo_group)
|
||||||
hbox.addLayout(grid)
|
hbox.addLayout(grid)
|
||||||
|
|
||||||
self.setLayout(hbox)
|
self.setLayout(hbox)
|
||||||
@ -77,14 +78,20 @@ class SpreadManager(QtWidgets.QWidget):
|
|||||||
def show(self):
|
def show(self):
|
||||||
""""""
|
""""""
|
||||||
self.spread_engine.start()
|
self.spread_engine.start()
|
||||||
|
self.algo_dialog.update_class_combo()
|
||||||
self.showMaximized()
|
self.showMaximized()
|
||||||
|
|
||||||
def create_tab(self, title: str, widget: QtWidgets.QWidget):
|
def create_group(self, title: str, widget: QtWidgets.QWidget):
|
||||||
""""""
|
""""""
|
||||||
tab = QtWidgets.QTabWidget()
|
group = QtWidgets.QGroupBox()
|
||||||
tab.addTab(widget, title)
|
|
||||||
return tab
|
vbox = QtWidgets.QVBoxLayout()
|
||||||
|
vbox.addWidget(widget)
|
||||||
|
|
||||||
|
group.setLayout(vbox)
|
||||||
|
group.setTitle(title)
|
||||||
|
|
||||||
|
return group
|
||||||
|
|
||||||
|
|
||||||
class SpreadDataMonitor(BaseMonitor):
|
class SpreadDataMonitor(BaseMonitor):
|
||||||
@ -145,7 +152,7 @@ class SpreadLogMonitor(QtWidgets.QTextEdit):
|
|||||||
def process_log_event(self, event: Event):
|
def process_log_event(self, event: Event):
|
||||||
""""""
|
""""""
|
||||||
log = event.data
|
log = event.data
|
||||||
msg = f"{log.time.strftime('%H:%M:%S')}:{log.msg}"
|
msg = f"{log.time.strftime('%H:%M:%S')}\t{log.msg}"
|
||||||
self.append(msg)
|
self.append(msg)
|
||||||
|
|
||||||
|
|
||||||
@ -205,7 +212,6 @@ class SpreadAlgoWidget(QtWidgets.QFrame):
|
|||||||
self.strategy_engine: SpreadStrategyEngine = spread_engine.strategy_engine
|
self.strategy_engine: SpreadStrategyEngine = spread_engine.strategy_engine
|
||||||
|
|
||||||
self.init_ui()
|
self.init_ui()
|
||||||
self.update_class_combo()
|
|
||||||
|
|
||||||
def init_ui(self):
|
def init_ui(self):
|
||||||
""""""
|
""""""
|
||||||
@ -314,7 +320,8 @@ class SpreadAlgoWidget(QtWidgets.QFrame):
|
|||||||
|
|
||||||
def remove_spread(self):
|
def remove_spread(self):
|
||||||
""""""
|
""""""
|
||||||
pass
|
dialog = SpreadRemoveDialog(self.spread_engine)
|
||||||
|
dialog.exec_()
|
||||||
|
|
||||||
def update_class_combo(self):
|
def update_class_combo(self):
|
||||||
""""""
|
""""""
|
||||||
@ -470,7 +477,44 @@ class SpreadDataDialog(QtWidgets.QDialog):
|
|||||||
self.accept()
|
self.accept()
|
||||||
|
|
||||||
|
|
||||||
class SpreadStrategyMonitor(QtWidgets.QScrollArea):
|
class SpreadRemoveDialog(QtWidgets.QDialog):
|
||||||
|
""""""
|
||||||
|
|
||||||
|
def __init__(self, spread_engine: SpreadEngine):
|
||||||
|
""""""
|
||||||
|
super().__init__()
|
||||||
|
|
||||||
|
self.spread_engine: SpreadEngine = spread_engine
|
||||||
|
|
||||||
|
self.init_ui()
|
||||||
|
|
||||||
|
def init_ui(self):
|
||||||
|
""""""
|
||||||
|
self.setWindowTitle("移除价差")
|
||||||
|
self.setMinimumWidth(300)
|
||||||
|
|
||||||
|
self.name_combo = QtWidgets.QComboBox()
|
||||||
|
spreads = self.spread_engine.get_all_spreads()
|
||||||
|
for spread in spreads:
|
||||||
|
self.name_combo.addItem(spread.name)
|
||||||
|
|
||||||
|
button_remove = QtWidgets.QPushButton("移除")
|
||||||
|
button_remove.clicked.connect(self.remove_spread)
|
||||||
|
|
||||||
|
hbox = QtWidgets.QHBoxLayout()
|
||||||
|
hbox.addWidget(self.name_combo)
|
||||||
|
hbox.addWidget(button_remove)
|
||||||
|
|
||||||
|
self.setLayout(hbox)
|
||||||
|
|
||||||
|
def remove_spread(self):
|
||||||
|
""""""
|
||||||
|
spread_name = self.name_combo.currentText()
|
||||||
|
self.spread_engine.remove_spread(spread_name)
|
||||||
|
self.accept()
|
||||||
|
|
||||||
|
|
||||||
|
class SpreadStrategyMonitor(QtWidgets.QWidget):
|
||||||
""""""
|
""""""
|
||||||
|
|
||||||
signal_strategy = QtCore.pyqtSignal(Event)
|
signal_strategy = QtCore.pyqtSignal(Event)
|
||||||
@ -495,8 +539,13 @@ class SpreadStrategyMonitor(QtWidgets.QScrollArea):
|
|||||||
scroll_widget = QtWidgets.QWidget()
|
scroll_widget = QtWidgets.QWidget()
|
||||||
scroll_widget.setLayout(self.scroll_layout)
|
scroll_widget.setLayout(self.scroll_layout)
|
||||||
|
|
||||||
self.setWidgetResizable(True)
|
scroll_area = QtWidgets.QScrollArea()
|
||||||
self.setWidget(scroll_widget)
|
scroll_area.setWidgetResizable(True)
|
||||||
|
scroll_area.setWidget(scroll_widget)
|
||||||
|
|
||||||
|
vbox = QtWidgets.QVBoxLayout()
|
||||||
|
vbox.addWidget(scroll_area)
|
||||||
|
self.setLayout(vbox)
|
||||||
|
|
||||||
def register_event(self):
|
def register_event(self):
|
||||||
""""""
|
""""""
|
||||||
@ -517,10 +566,15 @@ class SpreadStrategyMonitor(QtWidgets.QScrollArea):
|
|||||||
manager = self.managers[strategy_name]
|
manager = self.managers[strategy_name]
|
||||||
manager.update_data(data)
|
manager.update_data(data)
|
||||||
else:
|
else:
|
||||||
manager = SpreadStrategyWidget(self.strategy_engine, data)
|
manager = SpreadStrategyWidget(self, self.strategy_engine, data)
|
||||||
self.scroll_layout.insertWidget(0, manager)
|
self.scroll_layout.insertWidget(0, manager)
|
||||||
self.managers[strategy_name] = manager
|
self.managers[strategy_name] = manager
|
||||||
|
|
||||||
|
def remove_strategy(self, strategy_name):
|
||||||
|
""""""
|
||||||
|
manager = self.managers.pop(strategy_name)
|
||||||
|
manager.deleteLater()
|
||||||
|
|
||||||
|
|
||||||
class SpreadStrategyWidget(QtWidgets.QFrame):
|
class SpreadStrategyWidget(QtWidgets.QFrame):
|
||||||
"""
|
"""
|
||||||
@ -529,12 +583,14 @@ class SpreadStrategyWidget(QtWidgets.QFrame):
|
|||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
|
strategy_monitor: SpreadStrategyMonitor,
|
||||||
strategy_engine: SpreadStrategyEngine,
|
strategy_engine: SpreadStrategyEngine,
|
||||||
data: dict
|
data: dict
|
||||||
):
|
):
|
||||||
""""""
|
""""""
|
||||||
super().__init__()
|
super().__init__()
|
||||||
|
|
||||||
|
self.strategy_monitor = strategy_monitor
|
||||||
self.strategy_engine = strategy_engine
|
self.strategy_engine = strategy_engine
|
||||||
|
|
||||||
self.strategy_name = data["strategy_name"]
|
self.strategy_name = data["strategy_name"]
|
||||||
@ -629,7 +685,7 @@ class SpreadStrategyWidget(QtWidgets.QFrame):
|
|||||||
|
|
||||||
# Only remove strategy gui manager if it has been removed from engine
|
# Only remove strategy gui manager if it has been removed from engine
|
||||||
if result:
|
if result:
|
||||||
self.spread_manager.remove_strategy(self.strategy_name)
|
self.strategy_monitor.remove_strategy(self.strategy_name)
|
||||||
|
|
||||||
|
|
||||||
class StrategyDataMonitor(QtWidgets.QTableWidget):
|
class StrategyDataMonitor(QtWidgets.QTableWidget):
|
||||||
@ -698,11 +754,11 @@ class SettingEditor(QtWidgets.QDialog):
|
|||||||
""""""
|
""""""
|
||||||
form = QtWidgets.QFormLayout()
|
form = QtWidgets.QFormLayout()
|
||||||
|
|
||||||
# Add vt_symbol and name edit if add new strategy
|
# Add spread_name and name edit if add new strategy
|
||||||
if self.class_name:
|
if self.class_name:
|
||||||
self.setWindowTitle(f"添加策略:{self.class_name}")
|
self.setWindowTitle(f"添加策略:{self.class_name}")
|
||||||
button_text = "添加"
|
button_text = "添加"
|
||||||
parameters = {"strategy_name": "", "vt_symbol": ""}
|
parameters = {"strategy_name": "", "spread_name": ""}
|
||||||
parameters.update(self.parameters)
|
parameters.update(self.parameters)
|
||||||
else:
|
else:
|
||||||
self.setWindowTitle(f"参数编辑:{self.strategy_name}")
|
self.setWindowTitle(f"参数编辑:{self.strategy_name}")
|
||||||
|
Loading…
Reference in New Issue
Block a user