diff --git a/vn.trader/riskManager/RM_setting.json b/vn.trader/riskManager/RM_setting.json index ab0453d9..70eacac5 100644 --- a/vn.trader/riskManager/RM_setting.json +++ b/vn.trader/riskManager/RM_setting.json @@ -4,5 +4,6 @@ "tradeLimit": 100, "orderSizeLimit": 10, "active": true, - "orderFlowLimit": 10 + "orderCountLimit": 400, + "orderFlowLimit": 50 } \ No newline at end of file diff --git a/vn.trader/riskManager/rmEngine.py b/vn.trader/riskManager/rmEngine.py index d90e2a23..50f7c1de 100644 --- a/vn.trader/riskManager/rmEngine.py +++ b/vn.trader/riskManager/rmEngine.py @@ -21,8 +21,8 @@ class RmEngine(object): """风控引擎""" settingFileName = 'RM_setting.json' path = os.path.abspath(os.path.dirname(__file__)) - settingFileName = os.path.join(path, settingFileName) - + settingFileName = os.path.join(path, settingFileName) + name = u'风控模块' #---------------------------------------------------------------------- @@ -30,47 +30,53 @@ class RmEngine(object): """Constructor""" self.mainEngine = mainEngine self.eventEngine = eventEngine - + # 是否启动风控 self.active = False - + # 流控相关 self.orderFlowCount = EMPTY_INT # 单位时间内委托计数 self.orderFlowLimit = EMPTY_INT # 委托限制 self.orderFlowClear = EMPTY_INT # 计数清空时间(秒) self.orderFlowTimer = EMPTY_INT # 计数清空时间计时 - + # 单笔委托相关 self.orderSizeLimit = EMPTY_INT # 单笔委托最大限制 - + # 成交统计相关 self.tradeCount = EMPTY_INT # 当日成交合约数量统计 self.tradeLimit = EMPTY_INT # 当日成交合约数量限制 - + + # 单品种报撤 + self.orderCountLimit = 450 + self.orderCount = {} + # 活动合约相关 self.workingOrderLimit = EMPTY_INT # 活动合约最大限制 - + self.loadSetting() self.registerEvent() - + #---------------------------------------------------------------------- def loadSetting(self): """读取配置""" with open(self.settingFileName) as f: d = json.load(f) - + # 设置风控参数 self.active = d['active'] - + self.orderFlowLimit = d['orderFlowLimit'] self.orderFlowClear = d['orderFlowClear'] - + self.orderSizeLimit = d['orderSizeLimit'] - + self.tradeLimit = d['tradeLimit'] - + self.workingOrderLimit = d['workingOrderLimit'] - + + self.orderCountLimit = d['orderCountLimit'] + #---------------------------------------------------------------------- def saveSetting(self): """保存风控参数""" @@ -79,42 +85,55 @@ class RmEngine(object): d = {} d['active'] = self.active - + d['orderFlowLimit'] = self.orderFlowLimit d['orderFlowClear'] = self.orderFlowClear - + d['orderSizeLimit'] = self.orderSizeLimit - + d['tradeLimit'] = self.tradeLimit - + d['workingOrderLimit'] = self.workingOrderLimit - + + d['orderCountLimit'] = self.orderCountLimit + # 写入json jsonD = json.dumps(d, indent=4) f.write(jsonD) - + #---------------------------------------------------------------------- def registerEvent(self): """注册事件监听""" self.eventEngine.register(EVENT_TRADE, self.updateTrade) self.eventEngine.register(EVENT_TIMER, self.updateTimer) - + self.eventEngine.register(EVENT_ORDER, self.updateOrder) + + def updateOrder(self, event): + """更新成交数据""" + order = event.dict_['data'] + if not self.orderCount.has_key(order.symbol): + self.orderCount[order.symbol] = 0 + if order.status in [STATUS_NOTTRADED, STATUS_PARTTRADED, STATUS_ALLTRADED, STATUS_UNKNOWN]: + self.orderCount[order.symbol] += 1 + elif order.status == STATUS_CANCELLED: + self.orderCount[order.symbol] += 2 + #---------------------------------------------------------------------- def updateTrade(self, event): """更新成交数据""" trade = event.dict_['data'] self.tradeCount += trade.volume - + #---------------------------------------------------------------------- def updateTimer(self, event): """更新定时器""" self.orderFlowTimer += 1 - + # 如果计时超过了流控清空的时间间隔,则执行清空 if self.orderFlowTimer >= self.orderFlowClear: self.orderFlowCount = 0 self.orderFlowTimer = 0 - + #---------------------------------------------------------------------- def writeRiskLog(self, content): """快速发出日志事件""" @@ -122,95 +141,105 @@ class RmEngine(object): if platform.uname() == 'Windows': import winsound - winsound.PlaySound("SystemHand", winsound.SND_ASYNC) - + winsound.PlaySound("SystemHand", winsound.SND_ASYNC) + # 发出日志事件 log = VtLogData() log.logContent = content log.gatewayName = self.name event = Event(type_=EVENT_LOG) event.dict_['data'] = log - self.eventEngine.put(event) - + self.eventEngine.put(event) + #---------------------------------------------------------------------- def checkRisk(self, orderReq): """检查风险""" # 如果没有启动风控检查,则直接返回成功 if not self.active: - return True - + return RISK_OK + # 检查委托数量 if orderReq.volume > self.orderSizeLimit: - self.writeRiskLog(u'单笔委托数量%s,超过限制%s' + self.writeRiskLog(u'单笔委托数量%s,超过限制%s' %(orderReq.volume, self.orderSizeLimit)) - return False - + return RISK_ERROR_ORDER_SIZE + # 检查成交合约量 if self.tradeCount >= self.tradeLimit: - self.writeRiskLog(u'今日总成交合约数量%s,超过限制%s' + self.writeRiskLog(u'今日总成交合约数量%s,超过限制%s' %(self.tradeCount, self.tradeLimit)) - return False - + return RISK_ERROR_TRADE_COUNT + # 检查流控 if self.orderFlowCount >= self.orderFlowLimit: - self.writeRiskLog(u'委托流数量%s,超过限制每%s秒%s' + self.writeRiskLog(u'委托流数量%s,超过限制每%s秒%s' %(self.orderFlowCount, self.orderFlowClear, self.orderFlowLimit)) - return False - + return RISK_ERROR_ORDER_FLOW_COUNT + # 检查总活动合约 workingOrderCount = len(self.mainEngine.getAllWorkingOrders()) if workingOrderCount >= self.workingOrderLimit: self.writeRiskLog(u'当前活动委托数量%s,超过限制%s' %(workingOrderCount, self.workingOrderLimit)) - return False - + return RISK_ERROR_WORKING_ORDER + + if self.orderCount.has_key(orderReq.symbol) and self.orderCount[orderReq.symbol] > self.orderCountLimit: + self.writeRiskLog(u'%s当日报撤%s,超过限制%s' + % (orderReq.symbol, self.orderCount[orderReq.symbol], self.orderCountLimit)) + return RISK_ERROR_ORDER_SEND + # 对于通过风控的委托,增加流控计数 self.orderFlowCount += 1 - - return True - + + return RISK_OK + #---------------------------------------------------------------------- def clearOrderFlowCount(self): """清空流控计数""" self.orderFlowCount = 0 self.writeRiskLog(u'清空流控计数') - + #---------------------------------------------------------------------- def clearTradeCount(self): """清空成交数量计数""" self.tradeCount = 0 self.writeRiskLog(u'清空总成交计数') - + #---------------------------------------------------------------------- def setOrderFlowLimit(self, n): """设置流控限制""" self.orderFlowLimit = n - + #---------------------------------------------------------------------- def setOrderFlowClear(self, n): """设置流控清空时间""" self.orderFlowClear = n - + #---------------------------------------------------------------------- def setOrderSizeLimit(self, n): """设置委托最大限制""" self.orderSizeLimit = n - + #---------------------------------------------------------------------- def setTradeLimit(self, n): """设置成交限制""" self.tradeLimit = n - + #---------------------------------------------------------------------- def setWorkingOrderLimit(self, n): """设置活动合约限制""" self.workingOrderLimit = n - + + #---------------------------------------------------------------------- + def setOrderCountLimit(self, n): + """设置单品种报撤次数上限""" + self.orderCountLimit = n + #---------------------------------------------------------------------- def switchEngineStatus(self): """开关风控引擎""" self.active = not self.active - + if self.active: self.writeRiskLog(u'风险管理功能启动') else: diff --git a/vn.trader/riskManager/uiRmWidget.py b/vn.trader/riskManager/uiRmWidget.py index 66708b6e..74eff945 100644 --- a/vn.trader/riskManager/uiRmWidget.py +++ b/vn.trader/riskManager/uiRmWidget.py @@ -68,6 +68,7 @@ class RmEngineManager(QtGui.QWidget): self.spinOrderSizeLimit = RmSpinBox(self.rmEngine.orderSizeLimit) self.spinTradeLimit = RmSpinBox(self.rmEngine.tradeLimit) self.spinWorkingOrderLimit = RmSpinBox(self.rmEngine.workingOrderLimit) + self.spinOrderCountLimit = RmSpinBox(self.rmEngine.orderCountLimit) buttonClearOrderFlowCount = QtGui.QPushButton(u'清空流控计数') buttonClearTradeCount = QtGui.QPushButton(u'清空总成交计数') @@ -91,6 +92,8 @@ class RmEngineManager(QtGui.QWidget): grid.addWidget(RmLine(), 8, 0, 1, 2) grid.addWidget(Label(u'活动订单上限'), 9, 0) grid.addWidget(self.spinWorkingOrderLimit, 9, 1) + grid.addWidget(Label(u'单品种报撤次数上限'), 10, 0) + grid.addWidget(self.spinOrderCountLimit, 10, 1) hbox = QtGui.QHBoxLayout() hbox.addWidget(buttonClearOrderFlowCount) @@ -109,7 +112,8 @@ class RmEngineManager(QtGui.QWidget): self.spinOrderSizeLimit.valueChanged.connect(self.rmEngine.setOrderSizeLimit) self.spinTradeLimit.valueChanged.connect(self.rmEngine.setTradeLimit) self.spinWorkingOrderLimit.valueChanged.connect(self.rmEngine.setWorkingOrderLimit) - + self.spinOrderCountLimit.valueChanged.connect(self.rmEngine.setOrderCountLimit) + self.buttonSwitchEngineStatus.clicked.connect(self.switchEngineSatus) buttonClearOrderFlowCount.clicked.connect(self.rmEngine.clearOrderFlowCount) buttonClearTradeCount.clicked.connect(self.rmEngine.clearTradeCount) diff --git a/vn.trader/vtConstant.py b/vn.trader/vtConstant.py index fc3efce7..66488ab2 100644 --- a/vn.trader/vtConstant.py +++ b/vn.trader/vtConstant.py @@ -6,6 +6,18 @@ EMPTY_UNICODE = u'' EMPTY_INT = 0 EMPTY_FLOAT = 0.0 +# 风控常量 +RISK_OK = 0 # 风控正常 +RISK_ERROR_ORDER_SIZE = 1 # 单笔委托数量超限 +RISK_ERROR_TRADE_COUNT = 2 # 今日总成交合约数量超限 +RISK_ERROR_ORDER_FLOW_COUNT = 3 # 委托流数量超限 +RISK_ERROR_WORKING_ORDER = 4 # 当前活动委托数量超限 +RISK_ERROR_ORDER_SEND = 5 # 当日单品种报撤次数超限 + +RISK_MESSAGE = {RISK_ERROR_ORDER_SIZE: u'单笔委托数量超限', RISK_ERROR_TRADE_COUNT: u'今日总成交合约数量超限', + RISK_ERROR_ORDER_FLOW_COUNT: u'委托流数量超限', RISK_ERROR_WORKING_ORDER: u'当前活动委托数量超限', + RISK_ERROR_ORDER_SEND: u'当日单品种报撤次数超限'} + # 方向常量 DIRECTION_NONE = u'无方向' DIRECTION_LONG = u'多' diff --git a/vn.trader/vtEngine.py b/vn.trader/vtEngine.py index edcaabae..6a517ffd 100644 --- a/vn.trader/vtEngine.py +++ b/vn.trader/vtEngine.py @@ -188,9 +188,10 @@ class MainEngine(object): def sendOrder(self, orderReq, gatewayName): """对特定接口发单""" # 如果风控检查失败则不发单 - if not self.rmEngine.checkRisk(orderReq): - return '' - + riskResult = self.rmEngine.checkRisk(orderReq) + if riskResult != RISK_OK: + return riskResult + if gatewayName in self.gatewayDict: gateway = self.gatewayDict[gatewayName] return gateway.sendOrder(orderReq)