diff --git a/examples/VnTrader/RM_setting.json b/examples/VnTrader/RM_setting.json index 25c98921..3cd23168 100644 --- a/examples/VnTrader/RM_setting.json +++ b/examples/VnTrader/RM_setting.json @@ -1,6 +1,7 @@ { "orderFlowClear": 1, "orderCancelLimit": 10, + "marginRatioLimit": 0.85, "workingOrderLimit": 20, "tradeLimit": 1000, "orderSizeLimit": 100, diff --git a/vnpy/trader/app/riskManager/RM_setting.json b/vnpy/trader/app/riskManager/RM_setting.json index 25c98921..20625b38 100644 --- a/vnpy/trader/app/riskManager/RM_setting.json +++ b/vnpy/trader/app/riskManager/RM_setting.json @@ -5,5 +5,6 @@ "tradeLimit": 1000, "orderSizeLimit": 100, "active": true, - "orderFlowLimit": 50 + "orderFlowLimit": 50, + "marginRatioLimit": 0.95 } \ No newline at end of file diff --git a/vnpy/trader/app/riskManager/language/chinese/text.py b/vnpy/trader/app/riskManager/language/chinese/text.py index 6884d48e..98ab24ca 100644 --- a/vnpy/trader/app/riskManager/language/chinese/text.py +++ b/vnpy/trader/app/riskManager/language/chinese/text.py @@ -14,4 +14,5 @@ ORDER_FLOW_CLEAR = u'流控清空(秒)' ORDER_SIZE_LIMIT = u'单笔委托上限' TOTAL_TRADE_LIMIT = u'总成交上限' WORKING_ORDER_LIMIT = u'活动订单上限' -CONTRACT_CANCEL_LIMIT = u'单合约撤单上限' \ No newline at end of file +CONTRACT_CANCEL_LIMIT = u'单合约撤单上限' +MARGIN_RATIO_LIMIT = u'保证金占比上限' \ No newline at end of file diff --git a/vnpy/trader/app/riskManager/language/english/text.py b/vnpy/trader/app/riskManager/language/english/text.py index 3355c722..c145808a 100644 --- a/vnpy/trader/app/riskManager/language/english/text.py +++ b/vnpy/trader/app/riskManager/language/english/text.py @@ -14,4 +14,5 @@ ORDER_FLOW_CLEAR = u'Flow Clear(s)' ORDER_SIZE_LIMIT = u'Order Size Limit' TOTAL_TRADE_LIMIT = u'Total Fill Limit' WORKING_ORDER_LIMIT = u'Working Order Limit' -CONTRACT_CANCEL_LIMIT = u'Contract Cancel Limit' \ No newline at end of file +CONTRACT_CANCEL_LIMIT = u'Contract Cancel Limit' +MARGIN_RATIO_LIMIT = u'Margin Ratio Limit' \ No newline at end of file diff --git a/vnpy/trader/app/riskManager/rmEngine.py b/vnpy/trader/app/riskManager/rmEngine.py index a77dc1e9..337f6294 100644 --- a/vnpy/trader/app/riskManager/rmEngine.py +++ b/vnpy/trader/app/riskManager/rmEngine.py @@ -7,6 +7,8 @@ 3. 单笔委托的委托数量控制 ''' +from __future__ import division + import json import os import platform @@ -57,6 +59,10 @@ class RmEngine(object): # 活动合约相关 self.workingOrderLimit = EMPTY_INT # 活动合约最大限制 + + # 保证金相关 + self.marginRatioDict = {} # 保证金占账户净值比例字典 + self.marginRatioLimit = EMPTY_FLOAT # 最大比例限制 self.loadSetting() self.registerEvent() @@ -80,6 +86,8 @@ class RmEngine(object): self.workingOrderLimit = d['workingOrderLimit'] self.orderCancelLimit = d['orderCancelLimit'] + + self.marginRatioLimit = d['marginRatioLimit'] #---------------------------------------------------------------------- def saveSetting(self): @@ -100,6 +108,8 @@ class RmEngine(object): d['workingOrderLimit'] = self.workingOrderLimit d['orderCancelLimit'] = self.orderCancelLimit + + d['marginRatioLimit'] = self.marginRatioLimit # 写入json jsonD = json.dumps(d, indent=4) @@ -111,6 +121,7 @@ class RmEngine(object): self.eventEngine.register(EVENT_TRADE, self.updateTrade) self.eventEngine.register(EVENT_TIMER, self.updateTimer) self.eventEngine.register(EVENT_ORDER, self.updateOrder) + self.eventEngine.register(EVENT_ACCOUNT, self.updateAccount) #---------------------------------------------------------------------- def updateOrder(self, event): @@ -141,6 +152,19 @@ class RmEngine(object): self.orderFlowCount = 0 self.orderFlowTimer = 0 + #---------------------------------------------------------------------- + def updateAccount(self, event): + """账户资金更新""" + account = event.dict_['data'] + + # 计算保证金占比 + ratio = 0 + if account.balance: + ratio = account.margin / account.balance + + # 更新到字典中 + self.marginRatioDict[account.gatewayName] = ratio + #---------------------------------------------------------------------- def writeRiskLog(self, content): """快速发出日志事件""" @@ -159,7 +183,7 @@ class RmEngine(object): self.eventEngine.put(event) #---------------------------------------------------------------------- - def checkRisk(self, orderReq): + def checkRisk(self, orderReq, gatewayName): """检查风险""" # 如果没有启动风控检查,则直接返回成功 if not self.active: @@ -200,6 +224,12 @@ class RmEngine(object): %(orderReq.symbol, self.orderCancelDict[orderReq.symbol], self.orderCancelLimit)) return False + # 检查保证金比例 + if gatewayName in self.marginRatioDict and self.marginRatioDict[gatewayName] >= self.marginRatioLimit: + self.writeRiskLog(u'%s接口保证金占比%S,超过限制%s' + %(gatewayName, self.marginRatioDict[gatewayName], self.marginRatioLimit)) + return False + # 对于通过风控的委托,增加流控计数 self.orderFlowCount += 1 @@ -247,6 +277,11 @@ class RmEngine(object): """设置单合约撤单次数上限""" self.orderCancelLimit = n + #---------------------------------------------------------------------- + def setMarginRatioLimit(self, n): + """设置保证金比例限制""" + self.marginRatioLimit = n/100 # n为百分数,需要除以100 + #---------------------------------------------------------------------- def switchEngineStatus(self): """开关风控引擎""" diff --git a/vnpy/trader/app/riskManager/uiRmWidget.py b/vnpy/trader/app/riskManager/uiRmWidget.py index 6cffbecf..ce858a37 100644 --- a/vnpy/trader/app/riskManager/uiRmWidget.py +++ b/vnpy/trader/app/riskManager/uiRmWidget.py @@ -68,6 +68,10 @@ class RmEngineManager(QtWidgets.QWidget): self.spinWorkingOrderLimit = RmSpinBox(self.rmEngine.workingOrderLimit) self.spinOrderCancelLimit = RmSpinBox(self.rmEngine.orderCancelLimit) + self.spinMarginRatioLimit = RmSpinBox(self.rmEngine.marginRatioLimit * 100) # 百分比显示配置 + self.spinMarginRatioLimit.setMaximum(100) + self.spinMarginRatioLimit.setSuffix('%') + buttonClearOrderFlowCount = QtWidgets.QPushButton(text.CLEAR_ORDER_FLOW_COUNT) buttonClearTradeCount = QtWidgets.QPushButton(text.CLEAR_TOTAL_FILL_COUNT) buttonSaveSetting = QtWidgets.QPushButton(text.SAVE_SETTING) @@ -93,6 +97,9 @@ class RmEngineManager(QtWidgets.QWidget): grid.addWidget(RmLine(), 10, 0, 1, 2) grid.addWidget(Label(text.CONTRACT_CANCEL_LIMIT), 11, 0) grid.addWidget(self.spinOrderCancelLimit, 11, 1) + grid.addWidget(RmLine(), 12, 0, 1, 2) + grid.addWidget(Label(text.MARGIN_RATIO_LIMIT), 13, 0) + grid.addWidget(self.spinMarginRatioLimit, 13, 1) hbox = QtWidgets.QHBoxLayout() hbox.addWidget(buttonClearOrderFlowCount) @@ -112,6 +119,7 @@ class RmEngineManager(QtWidgets.QWidget): self.spinTradeLimit.valueChanged.connect(self.rmEngine.setTradeLimit) self.spinWorkingOrderLimit.valueChanged.connect(self.rmEngine.setWorkingOrderLimit) self.spinOrderCancelLimit.valueChanged.connect(self.rmEngine.setOrderCancelLimit) + self.spinMarginRatioLimit.valueChanged.connect(self.rmEngine.setMarginRatioLimit) self.buttonSwitchEngineStatus.clicked.connect(self.switchEngineSatus) buttonClearOrderFlowCount.clicked.connect(self.rmEngine.clearOrderFlowCount) diff --git a/vnpy/trader/vtEngine.py b/vnpy/trader/vtEngine.py index f9841926..cf99ec4e 100644 --- a/vnpy/trader/vtEngine.py +++ b/vnpy/trader/vtEngine.py @@ -122,7 +122,7 @@ class MainEngine(object): def sendOrder(self, orderReq, gatewayName): """对特定接口发单""" # 如果创建了风控引擎,且风控检查失败则不发单 - if self.rmEngine and not self.rmEngine.checkRisk(orderReq): + if self.rmEngine and not self.rmEngine.checkRisk(orderReq, gatewayName): return '' gateway = self.getGateway(gatewayName)