diff --git a/vnpy/app/spread_trading/engine.py b/vnpy/app/spread_trading/engine.py index 71be653b..deb7e801 100644 --- a/vnpy/app/spread_trading/engine.py +++ b/vnpy/app/spread_trading/engine.py @@ -18,10 +18,11 @@ from vnpy.trader.converter import OffsetConverter from .base import ( LegData, SpreadData, - EVENT_SPREAD_DATA, EVENT_SPREAD_ALGO, - EVENT_SPREAD_LOG + EVENT_SPREAD_DATA, EVENT_SPREAD_POS, + EVENT_SPREAD_ALGO, EVENT_SPREAD_LOG, + EVENT_SPREAD_STRATEGY ) -from .template import SpreadAlgoTemplate +from .template import SpreadAlgoTemplate, SpreadStrategyTemplate from .algo import SpreadTakerAlgo @@ -129,6 +130,7 @@ class SpreadDataEngine: def register_event(self) -> None: """""" self.event_engine.register(EVENT_TICK, self.process_tick_event) + self.event_engine.register(EVENT_TRADE, self.process_trade_event) self.event_engine.register(EVENT_POSITION, self.process_position_event) self.event_engine.register(EVENT_CONTRACT, self.process_contract_event) @@ -143,8 +145,7 @@ class SpreadDataEngine: for spread in self.symbol_spread_map[tick.vt_symbol]: spread.calculate_price() - - self.put_data_event(spread) + self.put_data_event(spread) def process_position_event(self, event: Event) -> None: """""" @@ -157,8 +158,20 @@ class SpreadDataEngine: for spread in self.symbol_spread_map[position.vt_symbol]: spread.calculate_pos() + self.put_pos_event(spread) - self.put_data_event(spread) + def process_trade_event(self, event: Event) -> None: + """""" + trade = event.data + + leg = self.legs.get(trade.vt_symbol, None) + if not leg: + return + leg.update_trade(trade) + + for spread in self.symbol_spread_map[trade.vt_symbol]: + spread.calculate_pos() + self.put_pos_event(spread) def process_contract_event(self, event: Event) -> None: """""" @@ -175,6 +188,11 @@ class SpreadDataEngine: event = Event(EVENT_SPREAD_DATA, spread) self.event_engine.put(event) + def put_pos_event(self, spread: SpreadData) -> None: + """""" + event = Event(EVENT_SPREAD_POS, spread) + self.event_engine.put(event) + def add_spread( self, name: str, @@ -483,3 +501,108 @@ class SpreadAlgoEngine: def get_contract(self, vt_symbol: str) -> ContractData: """""" return self.main_engine.get_contract(vt_symbol) + + +class SpreadStrategyEngine: + """""" + + def __init__(self, spread_engine: SpreadEngine): + """""" + self.spread_engine: SpreadEngine = spread_engine + self.main_engine: MainEngine = spread_engine.main_engine + self.event_engine: EventEngine = spread_engine.event_engine + + self.write_log = spread_engine.write_log + + self.strategies: Dict[str: SpreadStrategyTemplate] = {} + + self.order_strategy_map: dict[str: SpreadStrategyTemplate] = {} + self.name_strategy_map: dict[str: SpreadStrategyTemplate] = defaultdict( + list) + + self.vt_tradeids: Set = set() + + def start(self): + """""" + self.load_setting() + self.register_event() + + self.write_log("价差策略引擎启动成功") + + def load_setting(self): + """""" + pass + + def save_setting(self): + """""" + pass + + def register_event(self): + """""" + ee = self.event_engine + ee.register(EVENT_ORDER, self.process_order_event) + ee.register(EVENT_TRADE, self.process_trade_event) + ee.register(EVENT_SPREAD_DATA, self.process_spread_data_event) + ee.register(EVENT_SPREAD_POS, self.process_spread_pos_event) + ee.register(EVENT_SPREAD_ALGO, self.process_spread_algo_event) + + def process_spread_data_event(self, event: Event): + """""" + pass + + def process_spread_pos_event(self, event: Event): + """""" + pass + + def process_spread_algo_event(self, event: Event): + """""" + pass + + def process_order_event(self, event: Event): + """""" + pass + + def process_trade_event(self, event: Event): + """""" + pass + + def start_algo( + self, + strategy: SpreadStrategyTemplate, + direction: Direction, + price: float, + volume: float, + payup: int, + interval: int, + lock: bool + ) -> str: + """""" + pass + + def stop_algo(self, algoid: str): + """""" + pass + + def send_order( + self, + strategy: SpreadStrategyTemplate, + vt_symbol: str, + price: float, + volume: float, + direction: Direction, + offset: Offset + ) -> str: + pass + + def cancel_order(self, vt_orderid: str): + """""" + pass + + def put_strategy_event(self, strategy: SpreadStrategyTemplate): + """""" + pass + + def write_strategy_log(self, strategy: SpreadStrategyTemplate, msg: str): + """""" + pass + diff --git a/vnpy/app/spread_trading/template.py b/vnpy/app/spread_trading/template.py index c723010c..8f428d4b 100644 --- a/vnpy/app/spread_trading/template.py +++ b/vnpy/app/spread_trading/template.py @@ -4,7 +4,7 @@ from typing import Dict, List from math import floor, ceil from vnpy.trader.object import TickData, TradeData, OrderData, ContractData -from vnpy.trader.constant import Direction, Status +from vnpy.trader.constant import Direction, Status, Offset from vnpy.trader.utility import virtual from .base import SpreadData @@ -12,7 +12,7 @@ from .base import SpreadData class SpreadAlgoTemplate: """ - Template for writing spread trading algos. + Template for implementing spread trading algos. """ algo_name = "AlgoTemplate" @@ -266,3 +266,154 @@ class SpreadAlgoTemplate: def on_interval(self): """""" pass + + +class SpreadStrategyTemplate: + """ + Template for implementing spread trading strategies. + """ + strategy_name = "StrategyTemplate" + + def __init__( + self, + strategy_engine, + strategy_id: str, + spread: SpreadData + ): + """""" + self.strategy_engine = strategy_engine + self.strategy_id = strategy_id + self.spread = spread + + @virtual + def on_spread_data(self): + """""" + pass + + @virtual + def on_spread_pos(self): + """""" + pass + + @virtual + def on_spread_algo(self, algo: SpreadAlgoTemplate): + """""" + pass + + @virtual + def on_order(self, order: OrderData): + """""" + pass + + @virtual + def on_trade(self, trade: TradeData): + """""" + pass + + def start_algo( + self, + direction: Direction, + price: float, + volume: float, + payup: int, + interval: int, + lock: bool + ) -> str: + """""" + pass + + def start_long_algo( + self, + price: float, + volume: float, + payup: int, + interval: int, + lock: bool + ) -> str: + """""" + return self.start_algo(Direction.LONG, price, volume, payup, interval, lock) + + def start_short_algo( + self, + price: float, + volume: float, + payup: int, + interval: int, + lock: bool + ) -> str: + """""" + return self.start_algo(Direction.SHORT, price, volume, payup, interval, lock) + + def stop_algo(self, algoid: str): + """""" + pass + + def buy(self, vt_symbol: str, price: float, volume: float): + """""" + return self.send_order(vt_symbol, price, volume, Direction.LONG, Offset.OPEN) + + def sell(self, vt_symbol: str, price: float, volume: float): + """""" + return self.send_order(vt_symbol, price, volume, Direction.SHORT, Offset.CLOSE) + + def short(self, vt_symbol: str, price: float, volume: float): + """""" + return self.send_order(vt_symbol, price, volume, Direction.SHORT, Offset.OPEN) + + def cover(self, vt_symbol: str, price: float, volume: float): + """""" + return self.send_order(vt_symbol, price, volume, Direction.LONG, Offset.CLOSE) + + def send_order( + self, + vt_symbol: str, + price: float, + volume: float, + direction: Direction, + offset: Offset + ): + """""" + pass + + def cancel_order(self, vt_orderid: str): + """""" + pass + + def put_event(self): + """""" + pass + + def write_log(self, msg: str): + """""" + pass + + def get_spread_tick(self) -> TickData: + """""" + return self.spread.to_tick() + + def get_spread_pos(self) -> float: + """""" + return self.spread.net_pos + + def get_leg_tick(self, vt_symbol: str) -> TickData: + """""" + leg = self.spread.legs.get(vt_symbol, None) + + if not leg: + return None + + return leg.tick + + def get_leg_pos(self, vt_symbol: str, direction: Direction = Direction.NET) -> float: + """""" + leg = self.spread.legs.get(vt_symbol, None) + + if not leg: + return None + + if direction == Direction.NET: + return leg.net_pos + elif direction == Direction.LONG: + return leg.long_pos + else: + return leg.short_pos diff --git a/vnpy/trader/constant.py b/vnpy/trader/constant.py index 72aea310..1ebb2aa8 100644 --- a/vnpy/trader/constant.py +++ b/vnpy/trader/constant.py @@ -117,6 +117,9 @@ class Exchange(Enum): BINANCE = "BINANCE" COINBASE = "COINBASE" + # Special Function + LOCAL = "LOCAL" # For local generated data + class Currency(Enum): """