vnpy/vnpy/trader/gateway.py

230 lines
5.8 KiB
Python

"""
"""
from abc import ABC, abstractmethod
from typing import Any
from vnpy.event import Event, EventEngine
from .event import (
EVENT_TICK,
EVENT_ORDER,
EVENT_TRADE,
EVENT_POSITION,
EVENT_ACCOUNT,
EVENT_CONTRACT,
EVENT_LOG,
)
from .object import (
TickData,
OrderData,
TradeData,
PositionData,
AccountData,
ContractData,
LogData,
OrderRequest,
CancelRequest,
SubscribeRequest,
)
class BaseGateway(ABC):
"""
Abstract gateway class for creating gateways connection
to different trading systems.
# How to implement a gateway:
---
## Basics
A gateway should satisfies:
* this class should be thread-safe:
* all methods should be thread-safe
* no mutable shared properties between objects.
* all methods should be non-blocked
* satisfies all requirements written in docstring for every method and callbacks.
* automatically reconnect if connection lost.
---
## methods must implements:
all @abstractmethod
---
## callbacks must response manually:
* on_tick
* on_trade
* on_order
* on_position
* on_account
* on_contract
All the XxxData passed to callback should be constant, which means that
the object should not be modified after passing to on_xxxx.
So if you use a cache to store reference of data, use copy.copy to create a new object
before passing that data into on_xxxx
"""
# Fields required in setting dict for connect function.
default_setting = {}
def __init__(self, event_engine: EventEngine, gateway_name: str):
""""""
self.event_engine = event_engine
self.gateway_name = gateway_name
def on_event(self, type: str, data: Any = None):
"""
General event push.
"""
event = Event(type, data)
self.event_engine.put(event)
def on_tick(self, tick: TickData):
"""
Tick event push.
Tick event of a specific vt_symbol is also pushed.
"""
self.on_event(EVENT_TICK, tick)
self.on_event(EVENT_TICK + tick.vt_symbol, tick)
def on_trade(self, trade: TradeData):
"""
Trade event push.
Trade event of a specific vt_symbol is also pushed.
"""
self.on_event(EVENT_TRADE, trade)
self.on_event(EVENT_TRADE + trade.vt_symbol, trade)
def on_order(self, order: OrderData):
"""
Order event push.
Order event of a specific vt_orderid is also pushed.
"""
self.on_event(EVENT_ORDER, order)
self.on_event(EVENT_ORDER + order.vt_orderid, order)
def on_position(self, position: PositionData):
"""
Position event push.
Position event of a specific vt_symbol is also pushed.
"""
self.on_event(EVENT_POSITION, position)
self.on_event(EVENT_POSITION + position.vt_symbol, position)
def on_account(self, account: AccountData):
"""
Account event push.
Account event of a specific vt_accountid is also pushed.
"""
self.on_event(EVENT_ACCOUNT, account)
self.on_event(EVENT_ACCOUNT + account.vt_accountid, account)
def on_log(self, log: LogData):
"""
Log event push.
"""
self.on_event(EVENT_LOG, log)
def on_contract(self, contract: ContractData):
"""
Contract event push.
"""
self.on_event(EVENT_CONTRACT, contract)
def write_log(self, msg: str):
"""
Write a log event from gateway.
"""
log = LogData(msg=msg, gateway_name=self.gateway_name)
self.on_log(log)
@abstractmethod
def connect(self, setting: dict):
"""
Start gateway connection.
to implement this method, you must:
* connect to server if necessary
* log connected if all necessary connection is established
* do the following query and response corresponding on_xxxx and write_log
* contracts : on_contract
* account asset : on_account
* account holding: on_position
* orders of account: on_order
* trades of account: on_trade
* if any of query above is failed, write log.
future plan:
response callback/change status instead of write_log
"""
pass
@abstractmethod
def close(self):
"""
Close gateway connection.
"""
pass
@abstractmethod
def subscribe(self, req: SubscribeRequest):
"""
Subscribe tick data update.
"""
pass
@abstractmethod
def send_order(self, req: OrderRequest) -> str:
"""
Send a new order to server.
implementation should finish the tasks blow:
* create an OrderData from req using OrderRequest.create_order_data
* assign a unique(gateway instance scope) id to OrderData.orderid
* send request to server
* if request is sent, OrderData.status should be set to Status.SUBMITTING
* if request is failed to sent, OrderData.status should be set to Status.REJECTED
* response on_order:
* return OrderData.vt_orderid
:return str vt_orderid for created OrderData
"""
pass
@abstractmethod
def cancel_order(self, req: CancelRequest):
"""
Cancel an existing order.
implementation should finish the tasks blow:
* send request to server
"""
pass
@abstractmethod
def query_account(self):
"""
Query account balance.
"""
pass
@abstractmethod
def query_position(self):
"""
Query holding positions.
"""
pass
def get_default_setting(self):
"""
Return default setting dict.
"""
return self.default_setting