[Mod] add send/cancel order function of algo engine

This commit is contained in:
vn.py 2019-09-16 14:51:57 +08:00
parent f94144b704
commit be9142e878
4 changed files with 108 additions and 9 deletions

View File

@ -21,12 +21,13 @@ class SpreadTakerAlgo(SpreadAlgoTemplate):
price: float, price: float,
volume: float, volume: float,
payup: int, payup: int,
interval: int interval: int,
lock: bool
): ):
"""""" """"""
super().__init__( super().__init__(
algo_engine, algoid, spread, direction, algo_engine, algoid, spread, direction,
price, volume, payup, interval price, volume, payup, interval, lock
) )
self.cancel_interval: int = 2 self.cancel_interval: int = 2

View File

@ -1,4 +1,4 @@
from typing import List, Dict from typing import List, Dict, Set
from collections import defaultdict from collections import defaultdict
from copy import copy from copy import copy
@ -13,7 +13,8 @@ from vnpy.trader.object import (
TickData, ContractData, LogData, TickData, ContractData, LogData,
SubscribeRequest, OrderRequest, CancelRequest SubscribeRequest, OrderRequest, CancelRequest
) )
from vnpy.trader.constant import Direction from vnpy.trader.constant import Direction, Offset, OrderType
from vnpy.trader.converter import OffsetConverter, PositionHolding
from .base import ( from .base import (
LegData, SpreadData, LegData, SpreadData,
@ -242,6 +243,11 @@ class SpreadAlgoEngine:
self.symbol_algo_map: dict[str: SpreadAlgoTemplate] = defaultdict(list) self.symbol_algo_map: dict[str: SpreadAlgoTemplate] = defaultdict(list)
self.algo_count: int = 0 self.algo_count: int = 0
self.vt_tradeids: Set = set()
self.offset_converter: OffsetConverter = OffsetConverter(
self.main_engine
)
def start(self): def start(self):
"""""" """"""
@ -254,9 +260,11 @@ class SpreadAlgoEngine:
self.event_engine.register(EVENT_TICK, self.process_tick_event) self.event_engine.register(EVENT_TICK, self.process_tick_event)
self.event_engine.register(EVENT_ORDER, self.process_order_event) self.event_engine.register(EVENT_ORDER, self.process_order_event)
self.event_engine.register(EVENT_TRADE, self.process_trade_event) self.event_engine.register(EVENT_TRADE, self.process_trade_event)
self.event_engine.register(EVENT_POSITION, self.process_position_event)
self.event_engine.register(EVENT_TIMER, self.process_timer_event) self.event_engine.register(EVENT_TIMER, self.process_timer_event)
self.event_engine.register( self.event_engine.register(
EVENT_SPREAD_DATA, self.process_spread_event) EVENT_SPREAD_DATA, self.process_spread_event
)
def process_spread_event(self, event: Event): def process_spread_event(self, event: Event):
"""""" """"""
@ -280,6 +288,9 @@ class SpreadAlgoEngine:
def process_order_event(self, event: Event): def process_order_event(self, event: Event):
"""""" """"""
order = event.data order = event.data
self.offset_converter.update_order(order)
algo = self.order_algo_map.get(order.vt_orderid, None) algo = self.order_algo_map.get(order.vt_orderid, None)
if algo and algo.is_active(): if algo and algo.is_active():
algo.update_order(order) algo.update_order(order)
@ -287,10 +298,24 @@ class SpreadAlgoEngine:
def process_trade_event(self, event: Event): def process_trade_event(self, event: Event):
"""""" """"""
trade = event.data trade = event.data
# Filter duplicate trade push
if trade.vt_tradeid in self.vt_tradeids:
return
self.vt_tradeids.add(trade.vt_tradeid)
self.offset_converter.update_trade(trade)
algo = self.order_algo_map.get(trade.vt_orderid, None) algo = self.order_algo_map.get(trade.vt_orderid, None)
if algo and algo.is_active(): if algo and algo.is_active():
algo.update_trade(trade) algo.update_trade(trade)
def process_position_event(self, event: Event):
""""""
position = event.data
self.offset_converter.update_position(position)
def process_timer_event(self, event: Event): def process_timer_event(self, event: Event):
"""""" """"""
buf = list(self.algos.values()) buf = list(self.algos.values())
@ -372,13 +397,71 @@ class SpreadAlgoEngine:
price: float, price: float,
volume: float, volume: float,
direction: Direction, direction: Direction,
lock: bool
) -> List[str]: ) -> List[str]:
"""""" """"""
pass holding = self.offset_converter.get_position_holding(vt_symbol)
contract = self.main_engine.get_contract(vt_symbol)
if direction == Direction.LONG:
available = holding.short_pos - holding.short_pos_frozen
else:
available = holding.long_pos - holding.long_pos_frozen
# If no position to close, just open new
if not available:
offset = Offset.OPEN
# If enougth position to close, just close old
elif volume < available:
offset = Offset.CLOSE
# Otherwise, just close existing position
else:
volume = available
offset = Offset.CLOSE
original_req = OrderRequest(
contract.symbol,
contract.exchange,
direction,
offset,
OrderType.LIMIT,
price,
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 algo.
self.order_algo_map[vt_orderid] = algo
return vt_orderids
def cancel_order(self, algo: SpreadAlgoTemplate, vt_orderid: str) -> None: def cancel_order(self, algo: SpreadAlgoTemplate, vt_orderid: str) -> None:
"""""" """"""
pass order = self.main_engine.get_order(vt_orderid)
if not order:
self.write_algo_log(algo, "撤单失败,找不到委托{}".format(vt_orderid))
return
req = order.create_cancel_request()
self.main_engine.cancel_order(req, order.gateway_name)
def get_tick(self, vt_symbol: str) -> TickData: def get_tick(self, vt_symbol: str) -> TickData:
"""""" """"""

View File

@ -25,7 +25,8 @@ class SpreadAlgoTemplate:
price: float, price: float,
volume: float, volume: float,
payup: int, payup: int,
interval: int interval: int,
lock: bool
): ):
"""""" """"""
self.algo_engine = algo_engine self.algo_engine = algo_engine
@ -39,6 +40,7 @@ class SpreadAlgoTemplate:
self.volume: float = volume self.volume: float = volume
self.payup: int = payup self.payup: int = payup
self.interval = interval self.interval = interval
self.lock = lock
if direction == Direction.LONG: if direction == Direction.LONG:
self.target = volume self.target = volume
@ -166,6 +168,7 @@ class SpreadAlgoTemplate:
price, price,
volume, volume,
direction, direction,
self.lock
) )
self.leg_orders[vt_symbol].extend(vt_orderids) self.leg_orders[vt_symbol].extend(vt_orderids)

View File

@ -227,6 +227,11 @@ class SpreadAlgoDialog(QtWidgets.QDialog):
button_start = QtWidgets.QPushButton("启动") button_start = QtWidgets.QPushButton("启动")
button_start.clicked.connect(self.start_algo) button_start.clicked.connect(self.start_algo)
self.lock_combo = QtWidgets.QComboBox()
self.lock_combo.addItems(
["", ""]
)
form = QtWidgets.QFormLayout() form = QtWidgets.QFormLayout()
form.addRow("价差", self.name_line) form.addRow("价差", self.name_line)
form.addRow("方向", self.direction_combo) form.addRow("方向", self.direction_combo)
@ -234,6 +239,7 @@ class SpreadAlgoDialog(QtWidgets.QDialog):
form.addRow("数量", self.volume_line) form.addRow("数量", self.volume_line)
form.addRow("超价", self.payup_line) form.addRow("超价", self.payup_line)
form.addRow("间隔", self.interval_line) form.addRow("间隔", self.interval_line)
form.addRow("锁仓", self.lock_line)
form.addRow(button_start) form.addRow(button_start)
self.setLayout(form) self.setLayout(form)
@ -247,8 +253,14 @@ class SpreadAlgoDialog(QtWidgets.QDialog):
payup = int(self.payup_line.text()) payup = int(self.payup_line.text())
interval = int(self.interval_line.text()) interval = int(self.interval_line.text())
lock_str = self.lock_combo.currentText()
if lock_str == "":
lock = True
else:
lock = False
self.spread_engine.start_algo( self.spread_engine.start_algo(
name, direction, price, volume, payup, interval name, direction, price, volume, payup, interval, lock
) )