This commit is contained in:
msincenselee 2019-06-21 23:27:03 +08:00
parent 5bd718fa2e
commit 28152c2852
8 changed files with 228 additions and 39 deletions

View File

@ -741,6 +741,8 @@ class TradingWidget(QtWidgets.QFrame):
EXCHANGE_CZCE,
EXCHANGE_SSE,
EXCHANGE_SZSE,
EXCHANGE_XSHG,
EXCHANGE_XSHE,
EXCHANGE_INE,
EXCHANGE_SGE,
EXCHANGE_HKEX,
@ -984,22 +986,27 @@ class TradingWidget(QtWidgets.QFrame):
currency = self.comboCurrency.currentText()
productClass = self.comboProductClass.currentText()
gatewayName = self.comboGateway.currentText()
# 查询合约
if exchange:
vtSymbol = '.'.join([symbol, exchange])
contract = self.mainEngine.getContract(vtSymbol)
else:
vtSymbol = symbol
contract = self.mainEngine.getContract(symbol)
if contract:
vtSymbol = contract.vtSymbol
if len(gatewayName)==0 and len(contract.gatewayName) > 0:
gatewayName = contract.gatewayName
self.lineName.setText(contract.name)
exchange = contract.exchange # 保证有交易所代码
try:
# 查询合约
if exchange:
vtSymbol = '.'.join([symbol, exchange])
contract = self.mainEngine.getContract(vtSymbol)
else:
vtSymbol = symbol
contract = self.mainEngine.getContract(symbol)
if contract:
vtSymbol = contract.vtSymbol
if len(gatewayName)==0 and contract.gatewayName is not None and len(contract.gatewayName) > 0:
gatewayName = contract.gatewayName
self.lineName.setText(contract.name)
exchange = contract.exchange # 保证有交易所代码
except Exception as ex:
print(u'获取合约{}异常:{},{}'.format(symbol,str(ex),traceback.format_exc()),file=sys.stderr)
return
# 清空价格数量
self.spinPrice.setValue(0)
#self.spinVolume.setValue(0)
@ -1103,6 +1110,8 @@ class TradingWidget(QtWidgets.QFrame):
else:
self.labelReturn.setText('')
self.comboExchange.setCurrentText(tick.exchange)
#----------------------------------------------------------------------
def connectSignal(self):
"""连接Signal"""
@ -1244,8 +1253,15 @@ class TradingWidget(QtWidgets.QFrame):
return
if tick.vtSymbol:
# 更新交易组件的显示合约
self.lineSymbol.setText(tick.vtSymbol)
if '.' in tick.vtSymbol:
symbol_pairs = tick.vtSymbol.split('.')
if symbol_pairs[-1] != 'SPD':
self.lineSymbol.setText(symbol_pairs[0])
self.comboExchange.setCurrentText(symbol_pairs[-1])
else:
self.lineSymbol.setText(tick.vtSymbol)
self.updateSymbol()
# 自动填写信息
@ -1302,8 +1318,7 @@ class ContractMonitor(BasicMonitor):
d = {'.'.join([contract.exchange, contract.symbol]):contract for contract in l}
l2 = d.keys()
#l2.sort(reverse=True)
l2 = sorted(l2, reverse=True)
l2 = sorted(l2,reverse=True)
self.setRowCount(len(l2))
row = 0
@ -1358,7 +1373,7 @@ class ContractMonitor(BasicMonitor):
class ContractManager(QtWidgets.QWidget):
"""合约管理组件"""
# ----------------------------------------------------------------------
#----------------------------------------------------------------------
def __init__(self, mainEngine, parent=None):
"""Constructor"""
super(ContractManager, self).__init__(parent=parent)
@ -1367,7 +1382,7 @@ class ContractManager(QtWidgets.QWidget):
self.initUi()
# ----------------------------------------------------------------------
#----------------------------------------------------------------------
def initUi(self):
"""初始化界面"""
self.setWindowTitle(vtText.CONTRACT_SEARCH)
@ -1426,6 +1441,7 @@ class WorkingOrderMonitor(OrderMonitor):
row = self.row(cell)
self.hideRow(row)
########################################################################
class SettingEditor(QtWidgets.QWidget):
"""配置编辑器"""

View File

@ -348,14 +348,15 @@ class MainWindow(QtWidgets.QMainWindow):
return openAppFunction
#----------------------------------------------------------------------
# ----------------------------------------------------------------------
def test(self):
"""测试按钮用的函数"""
# 有需要使用手动触发的测试函数可以写在这里
self.mainEngine.qryStatus()
self.mainEngine.saveData()
pass
#----------------------------------------------------------------------
# ----------------------------------------------------------------------
def openAbout(self):
"""打开关于"""
try:
@ -424,7 +425,7 @@ class MainWindow(QtWidgets.QMainWindow):
except:
pass
#----------------------------------------------------------------------
# ----------------------------------------------------------------------
def closeEvent(self, event):
"""关闭事件"""
reply = QtWidgets.QMessageBox.question(self, vtText.EXIT,
@ -441,7 +442,7 @@ class MainWindow(QtWidgets.QMainWindow):
else:
event.ignore()
#----------------------------------------------------------------------
# ----------------------------------------------------------------------
def createDock(self, widgetClass, widgetName, widgetArea):
"""创建停靠组件"""
widget = widgetClass(self.mainEngine, self.eventEngine)
@ -459,7 +460,7 @@ class MainWindow(QtWidgets.QMainWindow):
settings.setValue('state', self.saveState())
settings.setValue('geometry', self.saveGeometry())
#----------------------------------------------------------------------
# ----------------------------------------------------------------------
def loadWindowSettings(self, settingName):
"""载入窗口设置"""
settings = QtCore.QSettings('vn.trader', settingName)

View File

@ -6,6 +6,9 @@ import sys
import platform
import psutil
# changelog
# 记录gpid修改为pid
run_path = os.path.abspath(os.path.join(os.getcwd(), 'logs'))
if not os.path.isdir(run_path):
os.mkdir(run_path)
@ -68,19 +71,23 @@ if _status():
print( u'another service is already running...')
exit(0)
def _save_gpid():
def _save_gpid(log=True):
plat = str(platform.system())
if plat == 'Windows':
gpid = os.getpid()
else: # unix
gpid = os.getpgrp() if USE_GPID else os.getpid()
print( 'gpid={}'.format(gpid))
if log:
print( 'gpid={}'.format(gpid))
with open(gpid_file, 'w') as f:
f.write(str(gpid))
if log:
print(u'wrote gpid file:{}'.format(gpid_file))
print(u'wrote gpid file:{}'.format(gpid_file))
def update_gpid():
_save_gpid(log=False)
_save_gpid()

View File

@ -274,6 +274,7 @@ class PositionMonitor(BasicMonitor):
d['ydPosition'] = {'chinese': u'昨持仓', 'cellType': ""}
d['frozen'] = {'chinese': u'冻结量', 'cellType': ""}
d['price'] = {'chinese': u'价格', 'cellType': ""}
d['positionProfit'] = {'chinese': u'持仓盈亏', 'cellType': ""}
d['gatewayName'] = {'chinese': u'接口', 'cellType': ""}
self.setHeaderDict(d)
self.createLogger(EVENT_POSITION)

View File

@ -176,10 +176,45 @@ class ClientEngine(object):
self.client.initStrategy(name, force=force)
def startStrategy(self,name):
self.client.startStrategy(name)
if hasattr(self.client,'startStrategy'):
self.writeLog(u'启动服务端策略:{}'.format(name))
self.client.startStrategy(name)
else:
self.writeLog(u'RPC客户端没有startStrategy得方法')
print(u'RPC客户端没有startStrategy得方法',file=sys.stderr)
def stopStrategy(self,name):
self.client.stopStrategy(name)
if hasattr(self.client,'stopStrategy'):
self.writeLog(u'停止运行服务端策略:{}'.format(name))
self.client.stopStrategy(name)
else:
self.writeLog(u'RPC客户端没有stopStrategy得方法')
print(u'RPC客户端没有stopStrategy得方法',file=sys.stderr)
def removeStrategy(self,name):
if hasattr(self.client,'removeStrategy'):
self.writeLog(u'移除服务端策略:{}'.format(name))
self.client.removeStrategy(name)
else:
self.writeLog(u'RPC客户端没有removeStrategy得方法')
print(u'RPC客户端没有removeStrategy得方法',file=sys.stderr)
def addStrategy(self,cta_setting):
if hasattr(self.client,'addStrategy'):
self.writeLog(u'添加服务端策略:{}'.format(cta_setting.get('name')))
self.client.addStrategy(cta_setting)
else:
self.writeLog(u'RPC客户端没有addStrategy的方法')
print(u'RPC客户端没有addStrategy的方法', file=sys.stderr)
def forceClosePos(self,name):
if hasattr(self.client,'forceClosePos'):
self.writeLog(u'调用服务端策略强制清除仓位:{}'.format(name))
self.client.forceClosePos(name)
else:
self.writeLog(u'RPC客户端没有forceClosePos得方法')
print(u'RPC客户端没有forceClosePos得方法', file=sys.stderr)
#----------------------------------------------------------------------
def main():
"""客户端主程序入口"""

View File

@ -101,13 +101,13 @@ def roundToVolumeTick(volumeTick,volume):
if volumeTick == 0:
return volume
# 取整
newVolume = volume - volume % volumeTick
newVolume = round(volume / volumeTick, 0) * volumeTick
if isinstance(volumeTick,float):
v_exponent = decimal.Decimal(str(newVolume))
v_exponent = decimal.Decimal(str(volume))
vt_exponent = decimal.Decimal(str(volumeTick))
if abs(v_exponent.as_tuple().exponent) > abs(vt_exponent.as_tuple().exponent):
newVolume = round(newVolume, ndigits=abs(vt_exponent.as_tuple().exponent))
newVolume = round(volume, ndigits=abs(vt_exponent.as_tuple().exponent))
newVolume = float(str(newVolume))
return newVolume

View File

@ -36,7 +36,7 @@ class VtGateway(object):
event1.dict_['data'] = tick
self.eventEngine.put(event1)
if tick.lastPrice is not None or tick.lastPrice != 0:
if tick.lastPrice is not None and tick.lastPrice != 0:
self.symbol_price_dict.update({tick.vtSymbol: tick.lastPrice})
elif tick.askPrice1 is not None and tick.bidPrice1 is not None:
self.symbol_price_dict.update({tick.vtSymbol: (tick.askPrice1 + tick.bidPrice1)/2})
@ -147,7 +147,7 @@ class VtGateway(object):
filename = os.path.abspath(os.path.join(path, 'Gateway'))
print(u'create logger:{}'.format(filename))
#print(u'create logger:{}'.format(filename))
self.logger = setup_logger(filename=filename, name='vtGateway', debug=True)
# ----------------------------------------------------------------------

View File

@ -5,7 +5,10 @@ from datetime import datetime
from vnpy.trader.vtConstant import (EMPTY_STRING, EMPTY_UNICODE,
EMPTY_FLOAT, EMPTY_INT)
EMPTY_FLOAT, EMPTY_INT, DIRECTION_LONG, DIRECTION_SHORT,
OFFSET_OPEN, OFFSET_CLOSE,
OFFSET_CLOSETODAY, OFFSET_CLOSEYESTERDAY)
from vnpy.trader.language import constant
########################################################################
@ -40,7 +43,7 @@ class VtTickData(VtBaseData):
self.preOpenInterest = EMPTY_INT # 昨持仓量
self.openInterest = EMPTY_INT # 持仓量
self.time = EMPTY_STRING # 时间 11:20:56.5
self.date = EMPTY_STRING # 日期 20151009
self.date = EMPTY_STRING # 日期 2015-10-09
self.tradingDay = EMPTY_STRING # 交易日期
# 常规行情
@ -96,7 +99,7 @@ class VtTickData(VtBaseData):
tick.lastVolume = lastVolume
tick.openInterest = openInterest
tick.datetime = datetime.now()
tick.date = tick.datetime.strftime('%Y%m%d')
tick.date = tick.datetime.strftime('%Y-%m-%d')
tick.time = tick.datetime.strftime('%H:%M:%S')
tick.openPrice = openPrice
@ -158,6 +161,9 @@ class VtTradeData(VtBaseData):
self.price = EMPTY_FLOAT # 成交价格
self.volume = EMPTY_FLOAT # 成交数量
self.tradeTime = EMPTY_STRING # 成交时间
self.dt = None # 成交时间datetime类型
self.strategy = EMPTY_STRING # 策略实例名
#----------------------------------------------------------------------
@staticmethod
@ -473,6 +479,8 @@ class VtSubscribeReq(object):
self.symbol = EMPTY_STRING # 代码
self.exchange = EMPTY_STRING # 交易所
self.is_bar = False # True订阅1分钟bar行情False:订阅tick行情
# 以下为IB相关
self.productClass = EMPTY_UNICODE # 合约类型
self.currency = EMPTY_STRING # 合约货币
@ -556,3 +564,124 @@ class VtSingleton(type):
cls._instances[cls] = super(VtSingleton, cls).__call__(*args, **kwargs)
return cls._instances[cls]
########################################################################
class PositionBuffer(object):
"""持仓缓存信息(本地维护的持仓数据)"""
# ----------------------------------------------------------------------
def __init__(self):
"""Constructor"""
self.vtSymbol = EMPTY_STRING
# 多头
self.longPosition = EMPTY_INT
self.longToday = EMPTY_INT
self.longYd = EMPTY_INT
self.longPrice = EMPTY_FLOAT
self.longProfit = EMPTY_FLOAT
self.longFrozen = EMPTY_FLOAT
# 空头
self.shortPosition = EMPTY_INT
self.shortToday = EMPTY_INT
self.shortYd = EMPTY_INT
self.shortPrice = EMPTY_FLOAT
self.shortProfit = EMPTY_FLOAT
self.shortFrozen = EMPTY_FLOAT
self.frozen = EMPTY_FLOAT
# ----------------------------------------------------------------------
def toStr(self):
"""更新显示信息"""
str = u'long:{},yd:{},td:{}, short:{},yd:{},td:{}, fz:{};' \
.format(self.longPosition, self.longYd, self.longToday,
self.shortPosition, self.shortYd, self.shortToday, self.frozen)
return str
# ----------------------------------------------------------------------
def updatePositionData(self, pos):
"""更新持仓数据"""
if pos.direction == DIRECTION_SHORT:
self.shortPosition = pos.position # >=0
self.shortYd = pos.ydPosition # >=0
self.shortToday = self.shortPosition - self.shortYd # >=0
self.shortPrice = pos.price
self.shortProfit = pos.positionProfit
self.shortFrozen = pos.frozen
else:
self.longPosition = pos.position # >=0
self.longYd = pos.ydPosition # >=0
self.longToday = self.longPosition - self.longYd # >=0
self.longPrice = pos.price
self.longProfit = pos.positionProfit
self.longFrozen = pos.frozen
self.frozen = self.shortFrozen + self.longFrozen
# ----------------------------------------------------------------------
def updateTradeData(self, trade):
"""更新成交数据"""
if trade.direction == DIRECTION_SHORT:
# 空头和多头相同
if trade.offset == OFFSET_OPEN: # 开仓
self.shortPosition += trade.volume
self.shortToday += trade.volume # 增加的是今仓
elif trade.offset == OFFSET_CLOSETODAY: # 平今
self.longPosition -= trade.volume
self.longToday -= trade.volume # 减少今仓
elif trade.offset == OFFSET_CLOSEYESTERDAY: # 平昨
self.longPosition -= trade.volume
self.longYd -= trade.volume # 减少昨仓
else: # 平仓
self.longPosition -= trade.volume
self.longToday -= trade.volume # 优先减今仓
if self.longToday < 0:
self.longYd += self.longToday
self.longToday = 0
if self.longPosition <= 0:
self.longPosition = 0
if self.longToday <= 0:
self.longToday = 0
if self.longYd <= 0:
self.longYd = 0
else:
# 多方开仓,则对应多头的持仓和今仓增加
if trade.offset == OFFSET_OPEN:
self.longPosition += trade.volume
self.longToday += trade.volume
# 多方平今,对应空头的持仓和今仓减少
elif trade.offset == OFFSET_CLOSETODAY:
self.shortPosition -= trade.volume
self.shortToday -= trade.volume
elif trade.offset == OFFSET_CLOSEYESTERDAY:
self.shortPosition -= trade.volume
self.shortYd -= trade.volume
else:
self.shortPosition -= trade.volume
self.shortToday -= trade.volume
if self.shortToday <= 0:
self.shortYd += self.shortToday
self.shortToday = 0
if self.shortPosition <= 0:
self.shortPosition = 0
if self.shortToday <= 0:
self.shortToday = 0
if self.shortYd <= 0:
self.shortYd = 0
# 多方平昨,对应空头的持仓和昨仓减少