增加:
1、自动根据持仓合约,订阅tick消息。 2、风控增加亏损比例监控(暂时还没有确定的强制平仓处理)
This commit is contained in:
parent
f37440e6bb
commit
c7f6e1e9a5
@ -11,6 +11,8 @@ import os
|
|||||||
import copy
|
import copy
|
||||||
from collections import OrderedDict
|
from collections import OrderedDict
|
||||||
from datetime import datetime, timedelta
|
from datetime import datetime, timedelta
|
||||||
|
from Queue import Queue
|
||||||
|
from threading import Thread
|
||||||
|
|
||||||
from eventEngine import *
|
from eventEngine import *
|
||||||
from vtGateway import VtSubscribeReq, VtLogData
|
from vtGateway import VtSubscribeReq, VtLogData
|
||||||
@ -43,6 +45,11 @@ class DrEngine(object):
|
|||||||
# K线对象字典
|
# K线对象字典
|
||||||
self.barDict = {}
|
self.barDict = {}
|
||||||
|
|
||||||
|
# 负责执行数据库插入的单独线程相关
|
||||||
|
self.active = False # 工作状态
|
||||||
|
self.queue = Queue() # 队列
|
||||||
|
self.thread = Thread(target=self.run) # 线程
|
||||||
|
|
||||||
# 载入设置,订阅行情
|
# 载入设置,订阅行情
|
||||||
self.loadSetting()
|
self.loadSetting()
|
||||||
|
|
||||||
@ -112,6 +119,9 @@ class DrEngine(object):
|
|||||||
for activeSymbol, vtSymbol in d.items():
|
for activeSymbol, vtSymbol in d.items():
|
||||||
self.activeSymbolDict[vtSymbol] = activeSymbol
|
self.activeSymbolDict[vtSymbol] = activeSymbol
|
||||||
|
|
||||||
|
# 启动数据插入线程
|
||||||
|
self.start()
|
||||||
|
|
||||||
# 注册事件监听
|
# 注册事件监听
|
||||||
self.registerEvent()
|
self.registerEvent()
|
||||||
|
|
||||||
@ -187,7 +197,29 @@ class DrEngine(object):
|
|||||||
#----------------------------------------------------------------------
|
#----------------------------------------------------------------------
|
||||||
def insertData(self, dbName, collectionName, data):
|
def insertData(self, dbName, collectionName, data):
|
||||||
"""插入数据到数据库(这里的data可以是CtaTickData或者CtaBarData)"""
|
"""插入数据到数据库(这里的data可以是CtaTickData或者CtaBarData)"""
|
||||||
self.mainEngine.dbInsert(dbName, collectionName, data.__dict__)
|
self.queue.put((dbName, collectionName, data.__dict__))
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
def run(self):
|
||||||
|
"""运行插入线程"""
|
||||||
|
while self.active:
|
||||||
|
try:
|
||||||
|
dbName, collectionName, d = self.queue.get(block=True, timeout=1)
|
||||||
|
self.mainEngine.dbInsert(dbName, collectionName, d)
|
||||||
|
except Empty:
|
||||||
|
pass
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
def start(self):
|
||||||
|
"""启动"""
|
||||||
|
self.active = True
|
||||||
|
self.thread.start()
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
def stop(self):
|
||||||
|
"""退出"""
|
||||||
|
if self.active:
|
||||||
|
self.active = False
|
||||||
|
self.thread.join()
|
||||||
|
|
||||||
#----------------------------------------------------------------------
|
#----------------------------------------------------------------------
|
||||||
def writeDrLog(self, content):
|
def writeDrLog(self, content):
|
||||||
|
@ -19,9 +19,9 @@ EVENT_LOG = 'eLog' # 日志事件,全局通用
|
|||||||
EVENT_TICK = 'eTick.' # TICK行情事件,可后接具体的vtSymbol
|
EVENT_TICK = 'eTick.' # TICK行情事件,可后接具体的vtSymbol
|
||||||
EVENT_TRADE = 'eTrade.' # 成交回报事件
|
EVENT_TRADE = 'eTrade.' # 成交回报事件
|
||||||
EVENT_ORDER = 'eOrder.' # 报单回报事件
|
EVENT_ORDER = 'eOrder.' # 报单回报事件
|
||||||
EVENT_ERRRTNORDERINSERT = 'eErrRtnOrderInsert' # 报单录入错误回报事件
|
|
||||||
EVENT_POSITION = 'ePosition.' # 持仓回报事件
|
EVENT_POSITION = 'ePosition.' # 持仓回报事件
|
||||||
EVENT_ACCOUNT = 'eAccount.' # 账户回报事件
|
EVENT_ACCOUNT = 'eAccount.' # 账户回报事件
|
||||||
|
EVENT_ACCOUNT_LOSS = 'eAccountLoss' # 账户亏损事件
|
||||||
EVENT_CONTRACT = 'eContract.' # 合约基础信息回报事件
|
EVENT_CONTRACT = 'eContract.' # 合约基础信息回报事件
|
||||||
EVENT_ERROR = 'eError.' # 错误回报事件
|
EVENT_ERROR = 'eError.' # 错误回报事件
|
||||||
|
|
||||||
|
@ -1,9 +1,10 @@
|
|||||||
{
|
{
|
||||||
"orderFlowClear": 10,
|
"orderFlowClear": 10,
|
||||||
"percentLimit": 90,
|
"percentLimit": 80,
|
||||||
"workingOrderLimit": 200,
|
"workingOrderLimit": 200,
|
||||||
"tradeLimit": 1000,
|
"tradeLimit": 20000,
|
||||||
"orderSizeLimit": 100,
|
"orderSizeLimit": 100,
|
||||||
"active": true,
|
"active": true,
|
||||||
"orderFlowLimit": 1000
|
"lossPercentLimit": 11,
|
||||||
|
"orderFlowLimit": 20000
|
||||||
}
|
}
|
@ -23,9 +23,6 @@ class RmSpinBox(QtGui.QSpinBox):
|
|||||||
|
|
||||||
self.setValue(value)
|
self.setValue(value)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
########################################################################
|
########################################################################
|
||||||
class RmLine(QtGui.QFrame):
|
class RmLine(QtGui.QFrame):
|
||||||
"""水平分割线"""
|
"""水平分割线"""
|
||||||
@ -38,8 +35,6 @@ class RmLine(QtGui.QFrame):
|
|||||||
self.setFrameShadow(self.Sunken)
|
self.setFrameShadow(self.Sunken)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
########################################################################
|
########################################################################
|
||||||
class RmEngineManager(QtGui.QWidget):
|
class RmEngineManager(QtGui.QWidget):
|
||||||
"""风控引擎的管理组件"""
|
"""风控引擎的管理组件"""
|
||||||
@ -72,6 +67,9 @@ class RmEngineManager(QtGui.QWidget):
|
|||||||
# 最大开仓比例
|
# 最大开仓比例
|
||||||
self.spinPercentLimit = RmSpinBox(self.rmEngine.percentLimit)
|
self.spinPercentLimit = RmSpinBox(self.rmEngine.percentLimit)
|
||||||
|
|
||||||
|
# 最大净值止损比例,满足后强制止损
|
||||||
|
self.spinLossPercentLimit = RmSpinBox(self.rmEngine.lossPercentLimit)
|
||||||
|
|
||||||
buttonClearOrderFlowCount = QtGui.QPushButton(u'清空流控计数')
|
buttonClearOrderFlowCount = QtGui.QPushButton(u'清空流控计数')
|
||||||
buttonClearTradeCount = QtGui.QPushButton(u'清空总成交计数')
|
buttonClearTradeCount = QtGui.QPushButton(u'清空总成交计数')
|
||||||
buttonSaveSetting = QtGui.QPushButton(u'保存设置')
|
buttonSaveSetting = QtGui.QPushButton(u'保存设置')
|
||||||
@ -98,6 +96,8 @@ class RmEngineManager(QtGui.QWidget):
|
|||||||
grid.addWidget(RmLine(), 10, 0, 1, 2)
|
grid.addWidget(RmLine(), 10, 0, 1, 2)
|
||||||
grid.addWidget(Label(u'仓位上限(1~100)'), 11, 0)
|
grid.addWidget(Label(u'仓位上限(1~100)'), 11, 0)
|
||||||
grid.addWidget(self.spinPercentLimit, 11, 1)
|
grid.addWidget(self.spinPercentLimit, 11, 1)
|
||||||
|
grid.addWidget(Label(u'强制止损比例'), 12, 0)
|
||||||
|
grid.addWidget(self.spinLossPercentLimit, 12, 1)
|
||||||
|
|
||||||
hbox = QtGui.QHBoxLayout()
|
hbox = QtGui.QHBoxLayout()
|
||||||
hbox.addWidget(buttonClearOrderFlowCount)
|
hbox.addWidget(buttonClearOrderFlowCount)
|
||||||
@ -117,6 +117,7 @@ class RmEngineManager(QtGui.QWidget):
|
|||||||
self.spinTradeLimit.valueChanged.connect(self.rmEngine.setTradeLimit)
|
self.spinTradeLimit.valueChanged.connect(self.rmEngine.setTradeLimit)
|
||||||
self.spinWorkingOrderLimit.valueChanged.connect(self.rmEngine.setWorkingOrderLimit)
|
self.spinWorkingOrderLimit.valueChanged.connect(self.rmEngine.setWorkingOrderLimit)
|
||||||
self.spinPercentLimit.valueChanged.connect(self.rmEngine.setAccountPercentLimit)
|
self.spinPercentLimit.valueChanged.connect(self.rmEngine.setAccountPercentLimit)
|
||||||
|
self.spinLossPercentLimit.valueChanged.connect(self.rmEngine.setLossPercentLimit)
|
||||||
|
|
||||||
self.buttonSwitchEngineStatus.clicked.connect(self.switchEngineSatus)
|
self.buttonSwitchEngineStatus.clicked.connect(self.switchEngineSatus)
|
||||||
buttonClearOrderFlowCount.clicked.connect(self.rmEngine.clearOrderFlowCount)
|
buttonClearOrderFlowCount.clicked.connect(self.rmEngine.clearOrderFlowCount)
|
||||||
|
@ -610,8 +610,6 @@ class PositionMonitor(BasicMonitor):
|
|||||||
self.initTable()
|
self.initTable()
|
||||||
self.registerEvent()
|
self.registerEvent()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
########################################################################
|
########################################################################
|
||||||
class AccountMonitor(BasicMonitor):
|
class AccountMonitor(BasicMonitor):
|
||||||
"""账户监控"""
|
"""账户监控"""
|
||||||
@ -639,7 +637,6 @@ class AccountMonitor(BasicMonitor):
|
|||||||
self.initTable()
|
self.initTable()
|
||||||
self.registerEvent()
|
self.registerEvent()
|
||||||
|
|
||||||
|
|
||||||
########################################################################
|
########################################################################
|
||||||
class TradingWidget(QtGui.QFrame):
|
class TradingWidget(QtGui.QFrame):
|
||||||
"""简单交易组件"""
|
"""简单交易组件"""
|
||||||
@ -745,7 +742,6 @@ class TradingWidget(QtGui.QFrame):
|
|||||||
self.comboPriceType.addItems(self.priceTypeList)
|
self.comboPriceType.addItems(self.priceTypeList)
|
||||||
|
|
||||||
self.comboExchange = QtGui.QComboBox()
|
self.comboExchange = QtGui.QComboBox()
|
||||||
|
|
||||||
self.comboExchange.addItems(self.exchangeList)
|
self.comboExchange.addItems(self.exchangeList)
|
||||||
|
|
||||||
self.comboCurrency = QtGui.QComboBox()
|
self.comboCurrency = QtGui.QComboBox()
|
||||||
|
@ -23,8 +23,10 @@ class MainWindow(QtGui.QMainWindow):
|
|||||||
|
|
||||||
self.widgetDict = {} # 用来保存子窗口的字典
|
self.widgetDict = {} # 用来保存子窗口的字典
|
||||||
|
|
||||||
|
self.connectGatewayDict = {}
|
||||||
|
|
||||||
self.initUi()
|
self.initUi()
|
||||||
self.loadWindowSettings()
|
#self.loadWindowSettings()
|
||||||
|
|
||||||
self.connected = False
|
self.connected = False
|
||||||
self.autoDisConnect = False
|
self.autoDisConnect = False
|
||||||
@ -32,11 +34,13 @@ class MainWindow(QtGui.QMainWindow):
|
|||||||
self.orderSaveDate = EMPTY_STRING
|
self.orderSaveDate = EMPTY_STRING
|
||||||
self.barSaveDate = EMPTY_STRING
|
self.barSaveDate = EMPTY_STRING
|
||||||
|
|
||||||
self.connectGatewayDict = {}
|
|
||||||
# ----------------------------------------------------------------------
|
# ----------------------------------------------------------------------
|
||||||
def initUi(self):
|
def initUi(self):
|
||||||
"""初始化界面"""
|
"""初始化界面"""
|
||||||
self.setWindowTitle('VnTrader')
|
path = os.getcwd().rsplit('\\')[-1]
|
||||||
|
|
||||||
|
self.setWindowTitle(path)
|
||||||
self.initCentral()
|
self.initCentral()
|
||||||
self.initMenu()
|
self.initMenu()
|
||||||
self.initStatusBar()
|
self.initStatusBar()
|
||||||
@ -196,9 +200,15 @@ class MainWindow(QtGui.QMainWindow):
|
|||||||
self.sbTrigger = 10 # 10秒刷新一次
|
self.sbTrigger = 10 # 10秒刷新一次
|
||||||
self.eventEngine.register(EVENT_TIMER, self.updateStatusBar)
|
self.eventEngine.register(EVENT_TIMER, self.updateStatusBar)
|
||||||
|
|
||||||
|
|
||||||
# ----------------------------------------------------------------------
|
# ----------------------------------------------------------------------
|
||||||
def updateStatusBar(self, event):
|
def updateStatusBar(self, event):
|
||||||
"""在状态栏更新CPU和内存信息"""
|
"""1、在状态栏更新CPU和内存信息"""
|
||||||
|
# 2、定时断开服务器连接
|
||||||
|
# 3、定时重连服务器
|
||||||
|
# 4、定时保存每日的委托单
|
||||||
|
# 5、定时执行策略的保存事件
|
||||||
|
|
||||||
self.sbCount += 1
|
self.sbCount += 1
|
||||||
|
|
||||||
# 更新任务栏
|
# 更新任务栏
|
||||||
@ -211,7 +221,7 @@ class MainWindow(QtGui.QMainWindow):
|
|||||||
|
|
||||||
self.statusLabel.setText(info)
|
self.statusLabel.setText(info)
|
||||||
|
|
||||||
if len(self.connectGatewayDict) > 0:
|
if self.connectGatewayDict:
|
||||||
s = u''.join(str(e) for e in self.connectGatewayDict.values())
|
s = u''.join(str(e) for e in self.connectGatewayDict.values())
|
||||||
|
|
||||||
if not self.connected:
|
if not self.connected:
|
||||||
@ -266,7 +276,8 @@ class MainWindow(QtGui.QMainWindow):
|
|||||||
# 调用各策略保存数据
|
# 调用各策略保存数据
|
||||||
if ((dt.hour == 15 and dt.minute == 1) or (dt.hour == 2 and dt.minute == 31)) \
|
if ((dt.hour == 15 and dt.minute == 1) or (dt.hour == 2 and dt.minute == 31)) \
|
||||||
and len(self.connectGatewayDict) > 0 \
|
and len(self.connectGatewayDict) > 0 \
|
||||||
and today != self.barSaveDate:
|
and today != self.barSaveDate \
|
||||||
|
and self.connected:
|
||||||
self.barSaveDate = today
|
self.barSaveDate = today
|
||||||
self.mainEngine.writeLog(u'调用各策略保存数据')
|
self.mainEngine.writeLog(u'调用各策略保存数据')
|
||||||
self.mainEngine.saveData()
|
self.mainEngine.saveData()
|
||||||
@ -491,7 +502,6 @@ class MainWindow(QtGui.QMainWindow):
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def disconnect(self):
|
def disconnect(self):
|
||||||
""""断开底层gateway的连接"""
|
""""断开底层gateway的连接"""
|
||||||
self.mainEngine.disconnect()
|
self.mainEngine.disconnect()
|
||||||
|
@ -78,6 +78,7 @@ EXCHANGE_GLOBEX = 'GLOBEX' # CME电子交易平台
|
|||||||
EXCHANGE_IDEALPRO = 'IDEALPRO' # IB外汇ECN
|
EXCHANGE_IDEALPRO = 'IDEALPRO' # IB外汇ECN
|
||||||
|
|
||||||
EXCHANGE_OANDA = 'OANDA' # OANDA外汇做市商
|
EXCHANGE_OANDA = 'OANDA' # OANDA外汇做市商
|
||||||
|
EXCHANGE_OKCOIN = 'OKCOIN' # OKCOIN比特币交易所
|
||||||
|
|
||||||
# 货币类型
|
# 货币类型
|
||||||
CURRENCY_USD = 'USD' # 美元
|
CURRENCY_USD = 'USD' # 美元
|
||||||
|
@ -28,7 +28,7 @@ class MainEngine(object):
|
|||||||
self.eventEngine.start()
|
self.eventEngine.start()
|
||||||
|
|
||||||
# 创建数据引擎
|
# 创建数据引擎
|
||||||
self.dataEngine = DataEngine(self.eventEngine)
|
self.dataEngine = DataEngine(self, self.eventEngine)
|
||||||
|
|
||||||
# MongoDB数据库相关
|
# MongoDB数据库相关
|
||||||
self.dbClient = None # MongoDB客户端对象
|
self.dbClient = None # MongoDB客户端对象
|
||||||
@ -61,7 +61,7 @@ class MainEngine(object):
|
|||||||
|
|
||||||
self.addGateway(CtpGateway, 'CTP_EBF')
|
self.addGateway(CtpGateway, 'CTP_EBF')
|
||||||
self.gatewayDict['CTP_EBF'].setQryEnabled(True)
|
self.gatewayDict['CTP_EBF'].setQryEnabled(True)
|
||||||
except Exception, e:
|
except Exception as e:
|
||||||
print e
|
print e
|
||||||
|
|
||||||
"""
|
"""
|
||||||
@ -125,7 +125,15 @@ class MainEngine(object):
|
|||||||
self.gatewayDict['OANDA'].setQryEnabled(True)
|
self.gatewayDict['OANDA'].setQryEnabled(True)
|
||||||
except Exception, e:
|
except Exception, e:
|
||||||
print e
|
print e
|
||||||
|
|
||||||
|
try:
|
||||||
|
from okcoinGateway.okcoinGateway import OkcoinGateway
|
||||||
|
self.addGateway(OkcoinGateway, 'OKCOIN')
|
||||||
|
self.gatewayDict['OKCOIN'].setQryEnabled(True)
|
||||||
|
except Exception, e:
|
||||||
|
print e
|
||||||
"""
|
"""
|
||||||
|
|
||||||
#----------------------------------------------------------------------
|
#----------------------------------------------------------------------
|
||||||
def addGateway(self, gateway, gatewayName=None):
|
def addGateway(self, gateway, gatewayName=None):
|
||||||
"""创建接口"""
|
"""创建接口"""
|
||||||
@ -208,6 +216,9 @@ class MainEngine(object):
|
|||||||
# 停止事件引擎
|
# 停止事件引擎
|
||||||
self.eventEngine.stop()
|
self.eventEngine.stop()
|
||||||
|
|
||||||
|
# 停止数据记录引擎
|
||||||
|
self.drEngine.stop()
|
||||||
|
|
||||||
# 保存数据引擎里的合约数据到硬盘
|
# 保存数据引擎里的合约数据到硬盘
|
||||||
self.dataEngine.saveContracts()
|
self.dataEngine.saveContracts()
|
||||||
|
|
||||||
@ -288,6 +299,7 @@ class MainEngine(object):
|
|||||||
def clearData(self):
|
def clearData(self):
|
||||||
"""清空数据引擎的数据"""
|
"""清空数据引擎的数据"""
|
||||||
self.dataEngine.clearData()
|
self.dataEngine.clearData()
|
||||||
|
self.ctaEngine.clearData()
|
||||||
|
|
||||||
def saveData(self):
|
def saveData(self):
|
||||||
self.ctaEngine.saveStrategyData()
|
self.ctaEngine.saveStrategyData()
|
||||||
@ -298,8 +310,9 @@ class DataEngine(object):
|
|||||||
contractFileName = 'ContractData.vt'
|
contractFileName = 'ContractData.vt'
|
||||||
|
|
||||||
# ----------------------------------------------------------------------
|
# ----------------------------------------------------------------------
|
||||||
def __init__(self, eventEngine):
|
def __init__(self, mainEngine, eventEngine):
|
||||||
"""Constructor"""
|
"""Constructor"""
|
||||||
|
self.mainEngine = mainEngine
|
||||||
self.eventEngine = eventEngine
|
self.eventEngine = eventEngine
|
||||||
|
|
||||||
# 保存合约详细信息的字典
|
# 保存合约详细信息的字典
|
||||||
@ -317,6 +330,9 @@ class DataEngine(object):
|
|||||||
# 注册事件监听
|
# 注册事件监听
|
||||||
self.registerEvent()
|
self.registerEvent()
|
||||||
|
|
||||||
|
# 已订阅合约代码
|
||||||
|
self.subscribedSymbols = set()
|
||||||
|
|
||||||
# ----------------------------------------------------------------------
|
# ----------------------------------------------------------------------
|
||||||
def updateContract(self, event):
|
def updateContract(self, event):
|
||||||
"""更新合约数据"""
|
"""更新合约数据"""
|
||||||
@ -386,10 +402,45 @@ class DataEngine(object):
|
|||||||
"""注册事件监听"""
|
"""注册事件监听"""
|
||||||
self.eventEngine.register(EVENT_CONTRACT, self.updateContract)
|
self.eventEngine.register(EVENT_CONTRACT, self.updateContract)
|
||||||
self.eventEngine.register(EVENT_ORDER, self.updateOrder)
|
self.eventEngine.register(EVENT_ORDER, self.updateOrder)
|
||||||
|
self.eventEngine.register(EVENT_POSITION, self.updatePosition)
|
||||||
|
|
||||||
def clearData(self):
|
def clearData(self):
|
||||||
"""清空数据"""
|
"""清空数据"""
|
||||||
|
|
||||||
self.orderDict = {}
|
self.orderDict = {}
|
||||||
self.workingOrderDict = {}
|
self.workingOrderDict = {}
|
||||||
|
self.subscribedSymbols.clear()
|
||||||
|
|
||||||
|
def updatePosition(self,event):
|
||||||
|
"""更新持仓信息"""
|
||||||
|
# 在获取更新持仓信息时,自动订阅这个symbol
|
||||||
|
# 目的:1、
|
||||||
|
|
||||||
|
position = event.dict_['data']
|
||||||
|
|
||||||
|
symbol = position.symbol
|
||||||
|
|
||||||
|
# 已存在,不做更新
|
||||||
|
if symbol in self.subscribedSymbols:
|
||||||
|
return
|
||||||
|
|
||||||
|
self.subscribedSymbols.add(symbol)
|
||||||
|
|
||||||
|
gatewayName = position.gatewayName
|
||||||
|
contract = self.mainEngine.getContract(symbol)
|
||||||
|
|
||||||
|
if not contract:
|
||||||
|
self.mainEngine.writeLog(u'找不到合约{0}信息'.format(symbol))
|
||||||
|
return
|
||||||
|
|
||||||
|
# 订阅合约
|
||||||
|
req = VtSubscribeReq()
|
||||||
|
req.symbol = symbol
|
||||||
|
req.exchange = contract.exchange
|
||||||
|
req.currency = ''
|
||||||
|
req.productClass = ''
|
||||||
|
|
||||||
|
self.mainEngine.subscribe(req, gatewayName)
|
||||||
|
|
||||||
|
self.mainEngine.writeLog(u'自动订阅合约{0}'.format(symbol))
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user