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