[增强功能] 股票迅投(pb)远程接口
This commit is contained in:
parent
c5a46e49a1
commit
c7d0af81ee
1
vnpy/gateway/stockrpc/__init__.py
Normal file
1
vnpy/gateway/stockrpc/__init__.py
Normal file
@ -0,0 +1 @@
|
|||||||
|
from .stock_rpc_gateway import StockRpcGateway
|
4
vnpy/gateway/stockrpc/readme.md
Normal file
4
vnpy/gateway/stockrpc/readme.md
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
pb迅投rpc交易接口
|
||||||
|
|
||||||
|
- 使用vnpy rpc gateway方式,访问 主进程(使用pb gateway).
|
||||||
|
- 使用了rabbit mq 进行行情订阅
|
306
vnpy/gateway/stockrpc/stock_rpc_gateway.py
Normal file
306
vnpy/gateway/stockrpc/stock_rpc_gateway.py
Normal file
@ -0,0 +1,306 @@
|
|||||||
|
import traceback
|
||||||
|
import json
|
||||||
|
from uuid import uuid1
|
||||||
|
from datetime import datetime, timedelta
|
||||||
|
from threading import Thread
|
||||||
|
from vnpy.event import Event
|
||||||
|
from vnpy.rpc import RpcClient
|
||||||
|
from vnpy.trader.gateway import BaseGateway
|
||||||
|
from vnpy.trader.object import (
|
||||||
|
TickData,
|
||||||
|
SubscribeRequest,
|
||||||
|
CancelRequest,
|
||||||
|
OrderRequest
|
||||||
|
)
|
||||||
|
from vnpy.trader.event import (
|
||||||
|
EVENT_TICK,
|
||||||
|
EVENT_TRADE,
|
||||||
|
EVENT_ORDER,
|
||||||
|
EVENT_POSITION,
|
||||||
|
EVENT_ACCOUNT,
|
||||||
|
EVENT_CONTRACT,
|
||||||
|
EVENT_LOG)
|
||||||
|
from vnpy.trader.constant import Exchange
|
||||||
|
from vnpy.amqp.consumer import subscriber
|
||||||
|
from vnpy.amqp.producer import task_creator
|
||||||
|
|
||||||
|
|
||||||
|
class StockRpcGateway(BaseGateway):
|
||||||
|
"""
|
||||||
|
股票交易得RPC接口
|
||||||
|
交易使用RPC实现,
|
||||||
|
行情使用RabbitMQ订阅获取
|
||||||
|
需要启动单独得进程运行stock_tick_publisher
|
||||||
|
Cta_Stock => 行情订阅 =》StockRpcGateway =》RabbitMQ (task)=》 stock_tick_publisher =》订阅(worker)
|
||||||
|
stock_tick_publisher => restful接口获取股票行情 =》RabbitMQ(pub) => StockRpcGateway =>on_tick event
|
||||||
|
"""
|
||||||
|
|
||||||
|
default_setting = {
|
||||||
|
"主动请求地址": "tcp://127.0.0.1:2014",
|
||||||
|
"推送订阅地址": "tcp://127.0.0.1:4102",
|
||||||
|
"远程接口名称": "pb01"
|
||||||
|
}
|
||||||
|
|
||||||
|
exchanges = list(Exchange)
|
||||||
|
|
||||||
|
def __init__(self, event_engine, gateway_name='StockRPC'):
|
||||||
|
"""Constructor"""
|
||||||
|
super().__init__(event_engine, gateway_name)
|
||||||
|
|
||||||
|
self.symbol_gateway_map = {}
|
||||||
|
|
||||||
|
self.client = RpcClient()
|
||||||
|
self.client.callback = self.client_callback
|
||||||
|
self.rabbit_api = None
|
||||||
|
self.rabbit_dict = {}
|
||||||
|
# 远程RPC端,gateway_name
|
||||||
|
self.remote_gw_name = gateway_name
|
||||||
|
|
||||||
|
def connect(self, setting: dict):
|
||||||
|
""""""
|
||||||
|
req_address = setting["主动请求地址"]
|
||||||
|
pub_address = setting["推送订阅地址"]
|
||||||
|
self.remote_gw_name = setting['远程接口名称']
|
||||||
|
|
||||||
|
self.write_log(f'请求地址:{req_address},订阅地址:{pub_address},远程接口:{self.remote_gw_name}')
|
||||||
|
|
||||||
|
# 订阅事件
|
||||||
|
self.client.subscribe_topic("")
|
||||||
|
# self.client.subscribe_topic(EVENT_TRADE)
|
||||||
|
# self.client.subscribe_topic(EVENT_ORDER)
|
||||||
|
# self.client.subscribe_topic(EVENT_POSITION)
|
||||||
|
# self.client.subscribe_topic(EVENT_ACCOUNT)
|
||||||
|
# self.client.subscribe_topic(EVENT_CONTRACT)
|
||||||
|
# self.client.subscribe_topic(EVENT_LOG)
|
||||||
|
|
||||||
|
self.client.start(req_address, pub_address)
|
||||||
|
|
||||||
|
self.rabbit_dict = setting.get('rabbit', {})
|
||||||
|
self.write_log(f'激活RabbitMQ行情接口.配置:\n{self.rabbit_dict}')
|
||||||
|
self.rabbit_api = SubMdApi(gateway=self)
|
||||||
|
self.rabbit_api.connect(self.rabbit_dict)
|
||||||
|
|
||||||
|
self.write_log("服务器连接成功,开始初始化查询")
|
||||||
|
|
||||||
|
self.query_all()
|
||||||
|
|
||||||
|
def subscribe(self, req: SubscribeRequest):
|
||||||
|
"""行情订阅"""
|
||||||
|
self.write_log(f'创建订阅任务=> rabbitMQ')
|
||||||
|
host = self.rabbit_dict.get('host', 'localhost')
|
||||||
|
port = self.rabbit_dict.get('port', 5672)
|
||||||
|
user = self.rabbit_dict.get('user', 'admin')
|
||||||
|
password = self.rabbit_dict.get('password', 'admin')
|
||||||
|
exchange = 'x_work_queue'
|
||||||
|
queue_name = 'subscribe_task_queue'
|
||||||
|
routing_key = 'stock_subscribe'
|
||||||
|
task = task_creator(
|
||||||
|
host=host,
|
||||||
|
port=port,
|
||||||
|
user=user,
|
||||||
|
password=password,
|
||||||
|
exchange=exchange,
|
||||||
|
queue_name=queue_name,
|
||||||
|
routing_key=routing_key)
|
||||||
|
|
||||||
|
mission = {}
|
||||||
|
mission.update({'id': str(uuid1())})
|
||||||
|
mission.update({'action': "subscribe"})
|
||||||
|
mission.update({'vt_symbol': req.vt_symbol})
|
||||||
|
mission.update({'is_stock': True})
|
||||||
|
msg = json.dumps(mission)
|
||||||
|
self.write_log(f'[=>{host}:{port}/{exchange}/{queue_name}/{routing_key}] create task :{msg}')
|
||||||
|
task.pub(msg)
|
||||||
|
task.close()
|
||||||
|
# gateway_name = self.symbol_gateway_map.get(req.vt_symbol, "")
|
||||||
|
# self.client.subscribe(req, gateway_name)
|
||||||
|
|
||||||
|
def send_order(self, req: OrderRequest):
|
||||||
|
"""
|
||||||
|
RPC远程发单
|
||||||
|
:param req:
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
ref = self.client.send_order(req, self.remote_gw_name)
|
||||||
|
|
||||||
|
local_ref = ref.replace(f'{self.remote_gw_name}.', f'{self.gateway_name}.')
|
||||||
|
self.write_log(f'委托返回:{ref}=> {local_ref}')
|
||||||
|
return local_ref
|
||||||
|
|
||||||
|
def cancel_order(self, req: CancelRequest):
|
||||||
|
""""""
|
||||||
|
self.write_log(f'委托撤单:{req.__dict__}')
|
||||||
|
# gateway_name = self.symbol_gateway_map.get(req.vt_symbol, "")
|
||||||
|
self.client.cancel_order(req, self.remote_gw_name)
|
||||||
|
|
||||||
|
def query_account(self):
|
||||||
|
""""""
|
||||||
|
pass
|
||||||
|
|
||||||
|
def query_position(self):
|
||||||
|
""""""
|
||||||
|
pass
|
||||||
|
|
||||||
|
def query_all(self):
|
||||||
|
""""""
|
||||||
|
contracts = self.client.get_all_contracts()
|
||||||
|
for contract in contracts:
|
||||||
|
self.symbol_gateway_map[contract.vt_symbol] = contract.gateway_name
|
||||||
|
contract.gateway_name = self.gateway_name
|
||||||
|
self.on_contract(contract)
|
||||||
|
self.write_log("合约信息查询成功")
|
||||||
|
|
||||||
|
accounts = self.client.get_all_accounts()
|
||||||
|
for account in accounts:
|
||||||
|
account.gateway_name = self.gateway_name
|
||||||
|
self.on_account(account)
|
||||||
|
self.write_log("资金信息查询成功")
|
||||||
|
|
||||||
|
positions = self.client.get_all_positions()
|
||||||
|
for position in positions:
|
||||||
|
position.gateway_name = self.gateway_name
|
||||||
|
# 更换 vt_positionid得gateway前缀
|
||||||
|
position.vt_positionid.replace(f'{position.gateway_name}.', f'{self.gateway_name}.')
|
||||||
|
# 更换 vt_accountid得gateway前缀
|
||||||
|
position.vt_accountid.replace(f'{position.gateway_name}.', f'{self.gateway_name}.')
|
||||||
|
|
||||||
|
self.on_position(position)
|
||||||
|
self.write_log("持仓信息查询成功")
|
||||||
|
|
||||||
|
orders = self.client.get_all_orders()
|
||||||
|
for order in orders:
|
||||||
|
# 更换gateway
|
||||||
|
order.gateway_name = self.gateway_name
|
||||||
|
# 更换 vt_orderid得gateway前缀
|
||||||
|
order.vt_orderid.replace(f'{order.gateway_name}.', f'{self.gateway_name}.')
|
||||||
|
# 更换 vt_accountid得gateway前缀
|
||||||
|
order.vt_accountid.replace(f'{order.gateway_name}.', f'{self.gateway_name}.')
|
||||||
|
|
||||||
|
self.on_order(order)
|
||||||
|
self.write_log("委托信息查询成功")
|
||||||
|
|
||||||
|
trades = self.client.get_all_trades()
|
||||||
|
for trade in trades:
|
||||||
|
trade.gateway_name = self.gateway_name
|
||||||
|
# 更换 vt_orderid得gateway前缀
|
||||||
|
trade.vt_orderid.replace(f'{trade.gateway_name}.', f'{self.gateway_name}.')
|
||||||
|
# 更换 vt_orderid得gateway前缀
|
||||||
|
trade.vt_orderid.replace(f'{trade.gateway_name}.', f'{self.gateway_name}.')
|
||||||
|
# 更换 vt_accountid得gateway前缀
|
||||||
|
trade.vt_accountid.replace(f'{trade.gateway_name}.', f'{self.gateway_name}.')
|
||||||
|
self.on_trade(trade)
|
||||||
|
self.write_log("成交信息查询成功")
|
||||||
|
|
||||||
|
def close(self):
|
||||||
|
""""""
|
||||||
|
self.client.stop()
|
||||||
|
self.client.join()
|
||||||
|
|
||||||
|
def client_callback(self, topic: str, event: Event):
|
||||||
|
""""""
|
||||||
|
if event is None:
|
||||||
|
print("none event", topic, event)
|
||||||
|
return
|
||||||
|
if event.type == EVENT_TICK:
|
||||||
|
return
|
||||||
|
|
||||||
|
data = event.data
|
||||||
|
|
||||||
|
if hasattr(data, "gateway_name"):
|
||||||
|
data.gateway_name = self.gateway_name
|
||||||
|
if hasattr(data, 'vt_orderid'):
|
||||||
|
data.vt_orderid = data.vt_orderid.replace(f'{data.gateway_name}.', f'{self.gateway_name}.')
|
||||||
|
if hasattr(data, 'vt_tradeid'):
|
||||||
|
data.vt_tradeid = data.vt_tradeid.replace(f'{data.gateway_name}.', f'{self.gateway_name}.')
|
||||||
|
if hasattr(data, 'vt_accountid'):
|
||||||
|
data.vt_accountid = data.vt_accountid.replace(f'{data.gateway_name}.', f'{self.gateway_name}.')
|
||||||
|
if hasattr(data, 'vt_positionid'):
|
||||||
|
data.vt_positionid = data.vt_positionid.replace(f'{data.gateway_name}.', f'{self.gateway_name}.')
|
||||||
|
|
||||||
|
self.event_engine.put(event)
|
||||||
|
|
||||||
|
|
||||||
|
class SubMdApi():
|
||||||
|
"""
|
||||||
|
RabbitMQ Subscriber 数据行情接收API
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, gateway):
|
||||||
|
self.gateway = gateway
|
||||||
|
self.gateway_name = gateway.gateway_name
|
||||||
|
|
||||||
|
self.symbol_tick_dict = {} # 合约与最后一个Tick得字典
|
||||||
|
self.registed_symbol_set = set() # 订阅的合约记录集
|
||||||
|
|
||||||
|
self.sub = None
|
||||||
|
self.setting = {}
|
||||||
|
self.connect_status = False
|
||||||
|
self.thread = None # 用线程运行所有行情接收
|
||||||
|
|
||||||
|
def connect(self, setting={}):
|
||||||
|
"""连接"""
|
||||||
|
self.setting = setting
|
||||||
|
try:
|
||||||
|
self.sub = subscriber(
|
||||||
|
host=self.setting.get('host', 'localhost'),
|
||||||
|
port=self.setting.get('port', 5672),
|
||||||
|
user=self.setting.get('user', 'admin'),
|
||||||
|
password=self.setting.get('password', 'admin'),
|
||||||
|
exchange=self.setting.get('exchange', 'x_fanout_stock_tick'))
|
||||||
|
|
||||||
|
self.sub.set_callback(self.on_message)
|
||||||
|
self.thread = Thread(target=self.sub.start)
|
||||||
|
self.thread.start()
|
||||||
|
self.connect_status = True
|
||||||
|
self.gateway.status.update({'sub_con': True, 'sub_con_time': datetime.now().strftime('%Y-%m-%d %H:%M:%S')})
|
||||||
|
except Exception as ex:
|
||||||
|
self.gateway.write_error(u'连接RabbitMQ {} 异常:{}'.format(self.setting, str(ex)))
|
||||||
|
self.gateway.write_error(traceback.format_exc())
|
||||||
|
self.connect_status = False
|
||||||
|
|
||||||
|
def on_message(self, chan, method_frame, _header_frame, body, userdata=None):
|
||||||
|
# print(" [x] %r" % body)
|
||||||
|
try:
|
||||||
|
str_tick = body.decode('utf-8')
|
||||||
|
d = json.loads(str_tick)
|
||||||
|
d.pop('rawData', None)
|
||||||
|
|
||||||
|
symbol = d.pop('symbol', None)
|
||||||
|
str_datetime = d.pop('datetime', None)
|
||||||
|
|
||||||
|
if '.' in str_datetime:
|
||||||
|
dt = datetime.strptime(str_datetime, '%Y-%m-%d %H:%M:%S.%f')
|
||||||
|
else:
|
||||||
|
dt = datetime.strptime(str_datetime, '%Y-%m-%d %H:%M:%S')
|
||||||
|
|
||||||
|
tick = TickData(gateway_name=self.gateway_name,
|
||||||
|
exchange=Exchange(d.get('exchange')),
|
||||||
|
symbol=symbol,
|
||||||
|
datetime=dt)
|
||||||
|
d.pop('gateway_name', None)
|
||||||
|
d.pop('exchange', None)
|
||||||
|
d.pop('symbol', None)
|
||||||
|
tick.__dict__.update(d)
|
||||||
|
|
||||||
|
self.symbol_tick_dict[symbol] = tick
|
||||||
|
self.gateway.on_tick(tick)
|
||||||
|
|
||||||
|
except Exception as ex:
|
||||||
|
self.gateway.write_error(u'RabbitMQ on_message 异常:{}'.format(str(ex)))
|
||||||
|
self.gateway.write_error(traceback.format_exc())
|
||||||
|
|
||||||
|
def close(self):
|
||||||
|
"""退出API"""
|
||||||
|
self.gateway.write_log(u'退出rabbit行情订阅API')
|
||||||
|
self.connection_status = False
|
||||||
|
|
||||||
|
try:
|
||||||
|
if self.sub:
|
||||||
|
self.gateway.write_log(u'关闭订阅器')
|
||||||
|
self.sub.close()
|
||||||
|
|
||||||
|
if self.thread is not None:
|
||||||
|
self.gateway.write_log(u'关闭订阅器接收线程')
|
||||||
|
self.thread.join()
|
||||||
|
except Exception as ex:
|
||||||
|
self.gateway.write_error(u'退出rabbitMQ行情api异常:{}'.format(str(ex)))
|
Loading…
Reference in New Issue
Block a user