[Add] SpreadStrategyEngine for managing spread trading strategies
This commit is contained in:
parent
68090e4552
commit
3b9f1c3148
@ -1,6 +1,10 @@
|
|||||||
from typing import List, Dict, Set
|
import traceback
|
||||||
|
import importlib
|
||||||
|
import os
|
||||||
|
from typing import List, Dict, Set, Callable, Any, Type
|
||||||
from collections import defaultdict
|
from collections import defaultdict
|
||||||
from copy import copy
|
from copy import copy
|
||||||
|
from path import Path
|
||||||
|
|
||||||
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
|
||||||
@ -40,6 +44,7 @@ class SpreadEngine(BaseEngine):
|
|||||||
|
|
||||||
self.data_engine: SpreadDataEngine = SpreadDataEngine(self)
|
self.data_engine: SpreadDataEngine = SpreadDataEngine(self)
|
||||||
self.algo_engine: SpreadAlgoEngine = SpreadAlgoEngine(self)
|
self.algo_engine: SpreadAlgoEngine = SpreadAlgoEngine(self)
|
||||||
|
self.strategy_engine: SpreadStrategyEngine = SpreadStrategyEngine(self)
|
||||||
|
|
||||||
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
|
||||||
@ -506,6 +511,8 @@ class SpreadAlgoEngine:
|
|||||||
class SpreadStrategyEngine:
|
class SpreadStrategyEngine:
|
||||||
""""""
|
""""""
|
||||||
|
|
||||||
|
setting_filename = "spraed_trading_strategy.json"
|
||||||
|
|
||||||
def __init__(self, spread_engine: SpreadEngine):
|
def __init__(self, spread_engine: SpreadEngine):
|
||||||
""""""
|
""""""
|
||||||
self.spread_engine: SpreadEngine = spread_engine
|
self.spread_engine: SpreadEngine = spread_engine
|
||||||
@ -514,28 +521,107 @@ class SpreadStrategyEngine:
|
|||||||
|
|
||||||
self.write_log = spread_engine.write_log
|
self.write_log = spread_engine.write_log
|
||||||
|
|
||||||
|
self.strategy_setting: Dict[str: Dict] = {}
|
||||||
|
|
||||||
|
self.classes: Dict[str: Type[SpreadStrategyTemplate]] = {}
|
||||||
self.strategies: Dict[str: SpreadStrategyTemplate] = {}
|
self.strategies: Dict[str: SpreadStrategyTemplate] = {}
|
||||||
|
|
||||||
self.order_strategy_map: dict[str: SpreadStrategyTemplate] = {}
|
self.order_strategy_map: dict[str: SpreadStrategyTemplate] = {}
|
||||||
self.name_strategy_map: dict[str: SpreadStrategyTemplate] = defaultdict(
|
self.algo_strategy_map: dict[str: SpreadStrategyTemplate] = {}
|
||||||
|
self.spread_strategy_map: dict[str: SpreadStrategyTemplate] = defaultdict(
|
||||||
list)
|
list)
|
||||||
|
|
||||||
self.vt_tradeids: Set = set()
|
self.vt_tradeids: Set = set()
|
||||||
|
|
||||||
def start(self):
|
def start(self):
|
||||||
""""""
|
""""""
|
||||||
self.load_setting()
|
self.load_strategy_class()
|
||||||
|
self.load_strategy_setting()
|
||||||
self.register_event()
|
self.register_event()
|
||||||
|
|
||||||
self.write_log("价差策略引擎启动成功")
|
self.write_log("价差策略引擎启动成功")
|
||||||
|
|
||||||
def load_setting(self):
|
def close(self):
|
||||||
""""""
|
""""""
|
||||||
pass
|
self.stop_all_strategies()
|
||||||
|
|
||||||
def save_setting(self):
|
def load_strategy_class(self):
|
||||||
""""""
|
"""
|
||||||
pass
|
Load strategy class from source code.
|
||||||
|
"""
|
||||||
|
path1 = Path(__file__).parent.joinpath("strategies")
|
||||||
|
self.load_strategy_class_from_folder(
|
||||||
|
path1, "vnpy.app.cta_strategy.strategies")
|
||||||
|
|
||||||
|
path2 = Path.cwd().joinpath("strategies")
|
||||||
|
self.load_strategy_class_from_folder(path2, "strategies")
|
||||||
|
|
||||||
|
def load_strategy_class_from_folder(self, path: Path, module_name: str = ""):
|
||||||
|
"""
|
||||||
|
Load strategy class from certain folder.
|
||||||
|
"""
|
||||||
|
for dirpath, dirnames, filenames in os.walk(str(path)):
|
||||||
|
for filename in filenames:
|
||||||
|
if filename.endswith(".py"):
|
||||||
|
strategy_module_name = ".".join(
|
||||||
|
[module_name, filename.replace(".py", "")])
|
||||||
|
elif filename.endswith(".pyd"):
|
||||||
|
strategy_module_name = ".".join(
|
||||||
|
[module_name, filename.split(".")[0]])
|
||||||
|
|
||||||
|
self.load_strategy_class_from_module(strategy_module_name)
|
||||||
|
|
||||||
|
def load_strategy_class_from_module(self, module_name: str):
|
||||||
|
"""
|
||||||
|
Load strategy class from module file.
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
module = importlib.import_module(module_name)
|
||||||
|
|
||||||
|
for name in dir(module):
|
||||||
|
value = getattr(module, name)
|
||||||
|
if (isinstance(value, type) and issubclass(value, SpreadStrategyTemplate) and value is not SpreadStrategyTemplate):
|
||||||
|
self.classes[value.__name__] = value
|
||||||
|
except: # noqa
|
||||||
|
msg = f"策略文件{module_name}加载失败,触发异常:\n{traceback.format_exc()}"
|
||||||
|
self.write_log(msg)
|
||||||
|
|
||||||
|
def load_strategy_setting(self):
|
||||||
|
"""
|
||||||
|
Load setting file.
|
||||||
|
"""
|
||||||
|
self.strategy_setting = load_json(self.setting_filename)
|
||||||
|
|
||||||
|
for strategy_name, strategy_config in self.strategy_setting.items():
|
||||||
|
self.add_strategy(
|
||||||
|
strategy_config["class_name"],
|
||||||
|
strategy_name,
|
||||||
|
strategy_config["spread_name"],
|
||||||
|
strategy_config["setting"]
|
||||||
|
)
|
||||||
|
|
||||||
|
def update_strategy_setting(self, strategy_name: str, setting: dict):
|
||||||
|
"""
|
||||||
|
Update setting file.
|
||||||
|
"""
|
||||||
|
strategy = self.strategies[strategy_name]
|
||||||
|
|
||||||
|
self.strategy_setting[strategy_name] = {
|
||||||
|
"class_name": strategy.__class__.__name__,
|
||||||
|
"spread_name": strategy.spread_name,
|
||||||
|
"setting": setting,
|
||||||
|
}
|
||||||
|
save_json(self.setting_filename, self.strategy_setting)
|
||||||
|
|
||||||
|
def remove_strategy_setting(self, strategy_name: str):
|
||||||
|
"""
|
||||||
|
Update setting file.
|
||||||
|
"""
|
||||||
|
if strategy_name not in self.strategy_setting:
|
||||||
|
return
|
||||||
|
|
||||||
|
self.strategy_setting.pop(strategy_name)
|
||||||
|
save_json(self.setting_filename, self.strategy_setting)
|
||||||
|
|
||||||
def register_event(self):
|
def register_event(self):
|
||||||
""""""
|
""""""
|
||||||
@ -548,27 +634,152 @@ class SpreadStrategyEngine:
|
|||||||
|
|
||||||
def process_spread_data_event(self, event: Event):
|
def process_spread_data_event(self, event: Event):
|
||||||
""""""
|
""""""
|
||||||
pass
|
spread = event.data
|
||||||
|
strategies = self.spread_strategy_map[spread.name]
|
||||||
|
|
||||||
|
for strategy in strategies:
|
||||||
|
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):
|
||||||
""""""
|
""""""
|
||||||
pass
|
spread = event.data
|
||||||
|
strategies = self.spread_strategy_map[spread.name]
|
||||||
|
|
||||||
|
for strategy in strategies:
|
||||||
|
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):
|
||||||
""""""
|
""""""
|
||||||
pass
|
algo = event.data
|
||||||
|
strategy = self.algo_strategy_map.get(algo.algoid, None)
|
||||||
|
|
||||||
|
if strategy:
|
||||||
|
self.call_strategy_func(strategy, strategy.update_spread_algo, algo)
|
||||||
|
|
||||||
def process_order_event(self, event: Event):
|
def process_order_event(self, event: Event):
|
||||||
""""""
|
""""""
|
||||||
pass
|
order = event.data
|
||||||
|
strategy = self.order_strategy_map.get(order.vt_orderid, None)
|
||||||
|
|
||||||
|
if strategy:
|
||||||
|
self.call_strategy_func(strategy, strategy.update_order, order)
|
||||||
|
|
||||||
def process_trade_event(self, event: Event):
|
def process_trade_event(self, event: Event):
|
||||||
""""""
|
""""""
|
||||||
pass
|
trade = event.data
|
||||||
|
strategy = self.trade_strategy_map.get(trade.vt_orderid, None)
|
||||||
|
|
||||||
|
if strategy:
|
||||||
|
self.call_strategy_func(strategy, strategy.on_trade, trade)
|
||||||
|
|
||||||
|
def call_strategy_func(
|
||||||
|
self, strategy: SpreadStrategyTemplate, func: Callable, params: Any = None
|
||||||
|
):
|
||||||
|
"""
|
||||||
|
Call function of a strategy and catch any exception raised.
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
if params:
|
||||||
|
func(params)
|
||||||
|
else:
|
||||||
|
func()
|
||||||
|
except Exception:
|
||||||
|
strategy.trading = False
|
||||||
|
strategy.inited = False
|
||||||
|
|
||||||
|
msg = f"触发异常已停止\n{traceback.format_exc()}"
|
||||||
|
self.write_log(msg, strategy)
|
||||||
|
|
||||||
|
def add_strategy(
|
||||||
|
self, class_name: str, strategy_name: str, spread_name: str, setting: dict
|
||||||
|
):
|
||||||
|
"""
|
||||||
|
Add a new strategy.
|
||||||
|
"""
|
||||||
|
if strategy_name in self.strategies:
|
||||||
|
self.write_log(f"创建策略失败,存在重名{strategy_name}")
|
||||||
|
return
|
||||||
|
|
||||||
|
strategy_class = self.classes.get(class_name, None)
|
||||||
|
if not strategy_class:
|
||||||
|
self.write_log(f"创建策略失败,找不到策略类{class_name}")
|
||||||
|
return
|
||||||
|
|
||||||
|
strategy = strategy_class(self, strategy_name, spread_name, setting)
|
||||||
|
self.strategies[strategy_name] = strategy
|
||||||
|
|
||||||
|
# Add vt_symbol to strategy map.
|
||||||
|
strategies = self.spread_strategy_map[spread_name]
|
||||||
|
strategies.append(strategy)
|
||||||
|
|
||||||
|
# Update to setting file.
|
||||||
|
self.update_strategy_setting(strategy_name, setting)
|
||||||
|
|
||||||
|
self.put_strategy_event(strategy)
|
||||||
|
|
||||||
|
def init_strategy(self, strategy_name: str):
|
||||||
|
""""""
|
||||||
|
strategy = self.strategies[strategy_name]
|
||||||
|
|
||||||
|
if strategy.inited:
|
||||||
|
self.write_log(f"{strategy_name}已经完成初始化,禁止重复操作")
|
||||||
|
return
|
||||||
|
|
||||||
|
self.call_strategy_func(strategy, strategy.on_init)
|
||||||
|
strategy.inited = True
|
||||||
|
|
||||||
|
self.put_strategy_event(strategy)
|
||||||
|
self.write_log(f"{strategy_name}初始化完成")
|
||||||
|
|
||||||
|
def start_strategy(self, strategy_name: str):
|
||||||
|
""""""
|
||||||
|
strategy = self.strategies[strategy_name]
|
||||||
|
if not strategy.inited:
|
||||||
|
self.write_log(f"策略{strategy.strategy_name}启动失败,请先初始化")
|
||||||
|
return
|
||||||
|
|
||||||
|
if strategy.trading:
|
||||||
|
self.write_log(f"{strategy_name}已经启动,请勿重复操作")
|
||||||
|
return
|
||||||
|
|
||||||
|
self.call_strategy_func(strategy, strategy.on_start)
|
||||||
|
strategy.trading = True
|
||||||
|
|
||||||
|
self.put_strategy_event(strategy)
|
||||||
|
|
||||||
|
def stop_strategy(self, strategy_name: str):
|
||||||
|
""""""
|
||||||
|
strategy = self.strategies[strategy_name]
|
||||||
|
if not strategy.trading:
|
||||||
|
return
|
||||||
|
|
||||||
|
self.call_strategy_func(strategy, strategy.on_stop)
|
||||||
|
strategy.trading = False
|
||||||
|
|
||||||
|
strategy.stop_all_algos()
|
||||||
|
strategy.cancel_all_orders()
|
||||||
|
|
||||||
|
self.put_strategy_event(strategy)
|
||||||
|
|
||||||
|
def init_all_strategies(self):
|
||||||
|
""""""
|
||||||
|
for strategy in self.strategies.values():
|
||||||
|
self.init_strategy(strategy)
|
||||||
|
|
||||||
|
def start_all_strategies(self):
|
||||||
|
""""""
|
||||||
|
for strategy in self.strategies.values():
|
||||||
|
self.start_strategy(strategy)
|
||||||
|
|
||||||
|
def stop_all_strategies(self):
|
||||||
|
""""""
|
||||||
|
for strategy in self.strategies.values():
|
||||||
|
self.stop_strategy(strategy)
|
||||||
|
|
||||||
def start_algo(
|
def start_algo(
|
||||||
self,
|
self,
|
||||||
strategy: SpreadStrategyTemplate,
|
strategy: SpreadStrategyTemplate,
|
||||||
|
spread_name: str,
|
||||||
direction: Direction,
|
direction: Direction,
|
||||||
price: float,
|
price: float,
|
||||||
volume: float,
|
volume: float,
|
||||||
@ -577,9 +788,25 @@ class SpreadStrategyEngine:
|
|||||||
lock: bool
|
lock: bool
|
||||||
) -> str:
|
) -> str:
|
||||||
""""""
|
""""""
|
||||||
pass
|
algoid = self.spread_engine.start_algo(
|
||||||
|
spread_name,
|
||||||
|
direction,
|
||||||
|
price,
|
||||||
|
volume,
|
||||||
|
payup,
|
||||||
|
interval,
|
||||||
|
lock
|
||||||
|
)
|
||||||
|
|
||||||
def stop_algo(self, algoid: str):
|
self.algo_strategy_map[algoid] = strategy
|
||||||
|
|
||||||
|
return algoid
|
||||||
|
|
||||||
|
def stop_algo(self, strategy: SpreadStrategyTemplate, algoid: str):
|
||||||
|
""""""
|
||||||
|
self.spread_engine.stop_algo(algoid)
|
||||||
|
|
||||||
|
def stop_all_algos(self, strategy: SpreadStrategyTemplate):
|
||||||
""""""
|
""""""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@ -590,19 +817,74 @@ class SpreadStrategyEngine:
|
|||||||
price: float,
|
price: float,
|
||||||
volume: float,
|
volume: float,
|
||||||
direction: Direction,
|
direction: Direction,
|
||||||
offset: Offset
|
offset: Offset,
|
||||||
) -> str:
|
lock: bool
|
||||||
pass
|
) -> List[str]:
|
||||||
|
contract = self.main_engine.get_contract(vt_symbol)
|
||||||
|
|
||||||
def cancel_order(self, vt_orderid: str):
|
original_req = OrderRequest(
|
||||||
|
symbol=contract.symbol,
|
||||||
|
exchange=contract.exchange,
|
||||||
|
direction=direction,
|
||||||
|
offset=offset,
|
||||||
|
type=OrderType.LIMIT,
|
||||||
|
price=price,
|
||||||
|
volume=volume
|
||||||
|
)
|
||||||
|
|
||||||
|
# Convert with offset converter
|
||||||
|
req_list = self.offset_converter.convert_order_request(
|
||||||
|
original_req, lock)
|
||||||
|
|
||||||
|
# Send Orders
|
||||||
|
vt_orderids = []
|
||||||
|
|
||||||
|
for req in req_list:
|
||||||
|
vt_orderid = self.main_engine.send_order(
|
||||||
|
req, contract.gateway_name)
|
||||||
|
|
||||||
|
# Check if sending order successful
|
||||||
|
if not vt_orderid:
|
||||||
|
continue
|
||||||
|
|
||||||
|
vt_orderids.append(vt_orderid)
|
||||||
|
|
||||||
|
self.offset_converter.update_order_request(req, vt_orderid)
|
||||||
|
|
||||||
|
# Save relationship between orderid and strategy.
|
||||||
|
self.order_strategy_map[vt_orderid] = strategy
|
||||||
|
|
||||||
|
return vt_orderids
|
||||||
|
|
||||||
|
def cancel_order(self, strategy: SpreadStrategyTemplate, vt_orderid: str):
|
||||||
|
""""""
|
||||||
|
order = self.main_engine.get_order(vt_orderid)
|
||||||
|
if not order:
|
||||||
|
self.write_strategy_log(strategy, "撤单失败,找不到委托{}".format(vt_orderid))
|
||||||
|
return
|
||||||
|
|
||||||
|
req = order.create_cancel_request()
|
||||||
|
self.main_engine.cancel_order(req, order.gateway_name)
|
||||||
|
|
||||||
|
def cancel_all_orders(self, strategy: SpreadStrategyTemplate):
|
||||||
""""""
|
""""""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def put_strategy_event(self, strategy: SpreadStrategyTemplate):
|
def put_strategy_event(self, strategy: SpreadStrategyTemplate):
|
||||||
""""""
|
""""""
|
||||||
pass
|
event = Event(EVENT_SPREAD_STRATEGY, strategy)
|
||||||
|
self.event_engine.put(event)
|
||||||
|
|
||||||
def write_strategy_log(self, strategy: SpreadStrategyTemplate, msg: str):
|
def write_strategy_log(self, strategy: SpreadStrategyTemplate, msg: str):
|
||||||
""""""
|
""""""
|
||||||
pass
|
msg = f"{strategy.strategy_name}:{msg}"
|
||||||
|
self.write_log(msg)
|
||||||
|
|
||||||
|
def send_strategy_email(self, strategy: SpreadStrategyTemplate, msg: str):
|
||||||
|
""""""
|
||||||
|
if strategy:
|
||||||
|
subject = f"{strategy.strategy_name}"
|
||||||
|
else:
|
||||||
|
subject = "价差策略引擎"
|
||||||
|
|
||||||
|
self.main_engine.send_email(subject, msg)
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
|
|
||||||
from collections import defaultdict
|
from collections import defaultdict
|
||||||
from typing import Dict, List
|
from typing import Dict, List, Set
|
||||||
from math import floor, ceil
|
from math import floor, ceil
|
||||||
|
from copy import copy
|
||||||
|
|
||||||
from vnpy.trader.object import TickData, TradeData, OrderData, ContractData
|
from vnpy.trader.object import TickData, TradeData, OrderData, ContractData
|
||||||
from vnpy.trader.constant import Direction, Status, Offset
|
from vnpy.trader.constant import Direction, Status, Offset
|
||||||
@ -272,42 +273,158 @@ class SpreadStrategyTemplate:
|
|||||||
"""
|
"""
|
||||||
Template for implementing spread trading strategies.
|
Template for implementing spread trading strategies.
|
||||||
"""
|
"""
|
||||||
strategy_name = "StrategyTemplate"
|
|
||||||
|
author: str = ""
|
||||||
|
parameters: List[str] = []
|
||||||
|
variables: List[str] = []
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
strategy_engine,
|
strategy_engine,
|
||||||
strategy_id: str,
|
strategy_name: str,
|
||||||
spread: SpreadData
|
spread: SpreadData,
|
||||||
|
setting: dict
|
||||||
):
|
):
|
||||||
""""""
|
""""""
|
||||||
self.strategy_engine = strategy_engine
|
self.strategy_engine = strategy_engine
|
||||||
self.strategy_id = strategy_id
|
self.strategy_name = strategy_name
|
||||||
self.spread = spread
|
self.spread = spread
|
||||||
|
self.spread_name = spread.name
|
||||||
|
|
||||||
|
self.inited = False
|
||||||
|
self.trading = False
|
||||||
|
|
||||||
|
self.variables = copy(self.variables)
|
||||||
|
self.variables.insert(0, "inited")
|
||||||
|
self.variables.insert(1, "trading")
|
||||||
|
|
||||||
|
self.vt_orderids: Set[str] = set()
|
||||||
|
self.algoids: Set[str] = set()
|
||||||
|
|
||||||
|
self.update_setting(setting)
|
||||||
|
|
||||||
|
def update_setting(self, setting: dict):
|
||||||
|
"""
|
||||||
|
Update strategy parameter wtih value in setting dict.
|
||||||
|
"""
|
||||||
|
for name in self.parameters:
|
||||||
|
if name in setting:
|
||||||
|
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,
|
||||||
|
"spread_name": self.spread_name,
|
||||||
|
"class_name": self.__class__.__name__,
|
||||||
|
"author": self.author,
|
||||||
|
"parameters": self.get_parameters(),
|
||||||
|
"variables": self.get_variables(),
|
||||||
|
}
|
||||||
|
return strategy_data
|
||||||
|
|
||||||
|
def update_spread_algo(self, algo: SpreadAlgoTemplate):
|
||||||
|
"""
|
||||||
|
Callback when algo status is updated.
|
||||||
|
"""
|
||||||
|
if not algo.is_active() and algo.algoid in self.algoids:
|
||||||
|
self.algoids.pop(algo.algoid)
|
||||||
|
|
||||||
|
self.on_spread_algo(algo)
|
||||||
|
|
||||||
|
def update_order(self, order: OrderData):
|
||||||
|
"""
|
||||||
|
Callback when order status is updated.
|
||||||
|
"""
|
||||||
|
if not order.is_active() and order.vt_orderid in self.vt_orderids:
|
||||||
|
self.vt_orderids.pop(order.vt_orderid)
|
||||||
|
|
||||||
|
self.on_order(order)
|
||||||
|
|
||||||
|
@virtual
|
||||||
|
def on_init(self):
|
||||||
|
"""
|
||||||
|
Callback when strategy is inited.
|
||||||
|
"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
@virtual
|
||||||
|
def on_start(self):
|
||||||
|
"""
|
||||||
|
Callback when strategy is started.
|
||||||
|
"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
@virtual
|
||||||
|
def on_stop(self):
|
||||||
|
"""
|
||||||
|
Callback when strategy is stopped.
|
||||||
|
"""
|
||||||
|
pass
|
||||||
|
|
||||||
@virtual
|
@virtual
|
||||||
def on_spread_data(self):
|
def on_spread_data(self):
|
||||||
""""""
|
"""
|
||||||
|
Callback when spread price is updated.
|
||||||
|
"""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@virtual
|
@virtual
|
||||||
def on_spread_pos(self):
|
def on_spread_pos(self):
|
||||||
""""""
|
"""
|
||||||
|
Callback when spread position is updated.
|
||||||
|
"""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@virtual
|
@virtual
|
||||||
def on_spread_algo(self, algo: SpreadAlgoTemplate):
|
def on_spread_algo(self, algo: SpreadAlgoTemplate):
|
||||||
""""""
|
"""
|
||||||
|
Callback when algo status is updated.
|
||||||
|
"""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@virtual
|
@virtual
|
||||||
def on_order(self, order: OrderData):
|
def on_order(self, order: OrderData):
|
||||||
""""""
|
"""
|
||||||
|
Callback when order status is updated.
|
||||||
|
"""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@virtual
|
@virtual
|
||||||
def on_trade(self, trade: TradeData):
|
def on_trade(self, trade: TradeData):
|
||||||
""""""
|
"""
|
||||||
|
Callback when new trade data is received.
|
||||||
|
"""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def start_algo(
|
def start_algo(
|
||||||
@ -320,7 +437,23 @@ class SpreadStrategyTemplate:
|
|||||||
lock: bool
|
lock: bool
|
||||||
) -> str:
|
) -> str:
|
||||||
""""""
|
""""""
|
||||||
pass
|
if not self.trading:
|
||||||
|
return ""
|
||||||
|
|
||||||
|
algoid: str = self.strategy_engine.start_algo(
|
||||||
|
self,
|
||||||
|
self.spread_name,
|
||||||
|
direction,
|
||||||
|
price,
|
||||||
|
volume,
|
||||||
|
payup,
|
||||||
|
interval,
|
||||||
|
lock
|
||||||
|
)
|
||||||
|
|
||||||
|
self.algoids.add(algoid)
|
||||||
|
|
||||||
|
return algoid
|
||||||
|
|
||||||
def start_long_algo(
|
def start_long_algo(
|
||||||
self,
|
self,
|
||||||
@ -346,23 +479,31 @@ class SpreadStrategyTemplate:
|
|||||||
|
|
||||||
def stop_algo(self, algoid: str):
|
def stop_algo(self, algoid: str):
|
||||||
""""""
|
""""""
|
||||||
pass
|
if not self.trading:
|
||||||
|
return
|
||||||
|
|
||||||
def buy(self, vt_symbol: str, price: float, volume: float):
|
self.strategy_engine.stop_algo(self, algoid)
|
||||||
""""""
|
|
||||||
return self.send_order(vt_symbol, price, volume, Direction.LONG, Offset.OPEN)
|
|
||||||
|
|
||||||
def sell(self, vt_symbol: str, price: float, volume: float):
|
def stop_all_algos(self):
|
||||||
""""""
|
""""""
|
||||||
return self.send_order(vt_symbol, price, volume, Direction.SHORT, Offset.CLOSE)
|
for algoid in self.algoids:
|
||||||
|
self.stop_algo(algoid)
|
||||||
|
|
||||||
def short(self, vt_symbol: str, price: float, volume: float):
|
def buy(self, vt_symbol: str, price: float, volume: float, lock: bool = False) -> List[str]:
|
||||||
""""""
|
""""""
|
||||||
return self.send_order(vt_symbol, price, volume, Direction.SHORT, Offset.OPEN)
|
return self.send_order(vt_symbol, price, volume, Direction.LONG, Offset.OPEN, lock)
|
||||||
|
|
||||||
def cover(self, vt_symbol: str, price: float, volume: float):
|
def sell(self, vt_symbol: str, price: float, volume: float, lock: bool = False) -> List[str]:
|
||||||
""""""
|
""""""
|
||||||
return self.send_order(vt_symbol, price, volume, Direction.LONG, Offset.CLOSE)
|
return self.send_order(vt_symbol, price, volume, Direction.SHORT, Offset.CLOSE, lock)
|
||||||
|
|
||||||
|
def short(self, vt_symbol: str, price: float, volume: float, lock: bool = False) -> List[str]:
|
||||||
|
""""""
|
||||||
|
return self.send_order(vt_symbol, price, volume, Direction.SHORT, Offset.OPEN, lock)
|
||||||
|
|
||||||
|
def cover(self, vt_symbol: str, price: float, volume: float, lock: bool = False) -> List[str]:
|
||||||
|
""""""
|
||||||
|
return self.send_order(vt_symbol, price, volume, Direction.LONG, Offset.CLOSE, lock)
|
||||||
|
|
||||||
def send_order(
|
def send_order(
|
||||||
self,
|
self,
|
||||||
@ -370,22 +511,47 @@ class SpreadStrategyTemplate:
|
|||||||
price: float,
|
price: float,
|
||||||
volume: float,
|
volume: float,
|
||||||
direction: Direction,
|
direction: Direction,
|
||||||
offset: Offset
|
offset: Offset,
|
||||||
):
|
lock: bool
|
||||||
|
) -> List[str]:
|
||||||
""""""
|
""""""
|
||||||
pass
|
if not self.trading:
|
||||||
|
return []
|
||||||
|
|
||||||
|
vt_orderids: List[str] = self.strategy_engine.send_order(
|
||||||
|
self,
|
||||||
|
vt_symbol,
|
||||||
|
price,
|
||||||
|
volume,
|
||||||
|
direction,
|
||||||
|
offset,
|
||||||
|
lock
|
||||||
|
)
|
||||||
|
|
||||||
|
for vt_orderid in vt_orderids:
|
||||||
|
self.vt_orderids.add(vt_orderid)
|
||||||
|
|
||||||
|
return vt_orderids
|
||||||
|
|
||||||
def cancel_order(self, vt_orderid: str):
|
def cancel_order(self, vt_orderid: str):
|
||||||
""""""
|
""""""
|
||||||
pass
|
if not self.trading:
|
||||||
|
return
|
||||||
|
|
||||||
|
self.strategy_engine.cancel_order(self, vt_orderid)
|
||||||
|
|
||||||
|
def cancel_all_orders(self):
|
||||||
|
""""""
|
||||||
|
for vt_orderid in self.vt_orderids:
|
||||||
|
self.cancel_order(vt_orderid)
|
||||||
|
|
||||||
def put_event(self):
|
def put_event(self):
|
||||||
""""""
|
""""""
|
||||||
pass
|
self.strategy_engine.put_strategy_event(self)
|
||||||
|
|
||||||
def write_log(self, msg: str):
|
def write_log(self, msg: str):
|
||||||
""""""
|
""""""
|
||||||
pass
|
self.strategy_engine.write_strategy_log(self, msg)
|
||||||
|
|
||||||
def get_spread_tick(self) -> TickData:
|
def get_spread_tick(self) -> TickData:
|
||||||
""""""
|
""""""
|
||||||
@ -417,3 +583,10 @@ class SpreadStrategyTemplate:
|
|||||||
return leg.long_pos
|
return leg.long_pos
|
||||||
else:
|
else:
|
||||||
return leg.short_pos
|
return leg.short_pos
|
||||||
|
|
||||||
|
def send_email(self, msg: str):
|
||||||
|
"""
|
||||||
|
Send email to default receiver.
|
||||||
|
"""
|
||||||
|
if self.inited:
|
||||||
|
self.strategy_engine.send_email(msg, self)
|
||||||
|
Loading…
Reference in New Issue
Block a user