[增强功能] 风控模块,增加废单比,撤单比控制

This commit is contained in:
msincenselee 2020-09-01 15:47:10 +08:00
parent c890b931b7
commit 5cd7edd3dc
2 changed files with 61 additions and 13 deletions

View File

@ -13,6 +13,12 @@ from vnpy.trader.utility import load_json, save_json
APP_NAME = "RiskManager" APP_NAME = "RiskManager"
"""
中信证券期权新要求
-系统须具备撤单比控制控能对单日客户账户委托撤单比例进行控制当委托笔数大于预定阀值时启用撤单比=撤单笔数/(总委托笔数-废单笔数)*100%
-交易系统须具备废单比控制功能对单日客户账户委托废单比例进行控制当委托笔数大于预定阀值时启用废单比=废单委托笔数/总委托笔数*100%
-系统需具备成交持仓比控制功能对当日客户账户成交持仓比例进行控制当账户成交量大于1000张时启用各期权标的合约成交持仓比=成交张数/max昨日净持仓张数今日净持仓张数
"""
class RiskManagerEngine(BaseEngine): class RiskManagerEngine(BaseEngine):
"""""" """"""
@ -24,21 +30,29 @@ class RiskManagerEngine(BaseEngine):
self.active = False self.active = False
self.order_flow_count = 0 self.order_flow_count = 0 # 单位时间内,委托数量计数器
self.order_flow_limit = 500 self.order_flow_limit = 500 # 单位时间内,委托数量上限。
self.order_flow_clear = 1 self.order_flow_clear = 1 # 单位时间,即清空委托数量计数器得秒数
self.order_flow_timer = 0 self.order_flow_timer = 0 # 计时秒
self.order_size_limit = 1000 self.order_size_limit = 1000 # 单笔委托数量限制
self.order_volumes = 0 # 累计委托数量
self.trade_volumes = 0 # 累计成交数量
self.trade_limit = 10000 # 成交数量上限
self.trade_count = 0 self.order_cancel_limit = 5000 # 撤单数量限制
self.trade_limit = 10000 self.order_cancel_counts = defaultdict(int) # 撤单次数 {合约:撤单次数}
self.order_cancel_limit = 5000 self.order_cancel_volumes = 0 # 累计撤单笔数
self.order_cancel_counts = defaultdict(int) self.order_reject_volumes = 0 # 累计废单笔数
self.active_order_limit = 500 self.ratio_active_order_limit = 500 # 激活撤单比、废单比得订单总数量阈值
self.cancel_ratio_percent_limit = 99 # 撤单比阈值
self.reject_ratio_percent_limit = 99 # 废单比阈值
self.active_order_limit = 500 # 未完成订单数量
# 总仓位相关(0~100+) # 总仓位相关(0~100+)
self.percent_limit = 100 # 仓位比例限制 self.percent_limit = 100 # 仓位比例限制
@ -77,6 +91,10 @@ class RiskManagerEngine(BaseEngine):
self.active_order_limit = setting["active_order_limit"] self.active_order_limit = setting["active_order_limit"]
self.order_cancel_limit = setting["order_cancel_limit"] self.order_cancel_limit = setting["order_cancel_limit"]
self.percent_limit = setting.get('percent_limit', 100) self.percent_limit = setting.get('percent_limit', 100)
self.ratio_active_order_limit = setting.get('ratio_active_order_limit', 500)
self.cancel_ratio_percent_limit = setting.get('cancel_ratio_percent_limit', 99)
self.reject_ratio_percent_limit = setting.get('reject_ratio_percent_limit', 99)
if self.active: if self.active:
self.write_log("交易风控功能启动") self.write_log("交易风控功能启动")
else: else:
@ -119,14 +137,21 @@ class RiskManagerEngine(BaseEngine):
def process_order_event(self, event: Event): def process_order_event(self, event: Event):
"""""" """"""
order = event.data order = event.data
if order.status in [Status.ALLTRADED, Status.REJECTED, Status.CANCELLED]:
self.order_volumes += order.volume
if order.status == Status.REJECTED:
self.order_reject_volumes += order.volume
if order.status != Status.CANCELLED: if order.status != Status.CANCELLED:
return return
self.order_cancel_counts[order.symbol] += 1 self.order_cancel_counts[order.symbol] += 1
self.order_cancel_volumes += order.volume
def process_trade_event(self, event: Event): def process_trade_event(self, event: Event):
"""""" """"""
trade = event.data trade = event.data
self.trade_count += trade.volume self.trade_volumes += trade.volume
def process_timer_event(self, event: Event): def process_timer_event(self, event: Event):
"""""" """"""
@ -221,9 +246,9 @@ class RiskManagerEngine(BaseEngine):
return False return False
# Check trade volume # Check trade volume
if self.trade_count >= self.trade_limit: if self.trade_volumes >= self.trade_limit:
self.write_log( self.write_log(
f"今日总成交合约数量{self.trade_count},超过限制{self.trade_limit}") f"今日总成交合约数量{self.trade_volumes},超过限制{self.trade_limit}")
return False return False
# Check flow count # Check flow count
@ -250,6 +275,15 @@ class RiskManagerEngine(BaseEngine):
self.write_log(f'当前资金仓位{self.gateway_dict[gateway_name]}超过仓位限制:{self.percent_limit}') self.write_log(f'当前资金仓位{self.gateway_dict[gateway_name]}超过仓位限制:{self.percent_limit}')
return False return False
# 激活撤单比,废单比
if self.order_volumes > self.ratio_active_order_limit:
if self.order_reject_volumes > 0 and (self.order_reject_volumes/self.order_volumes) * 100 > self.reject_ratio_percent_limit:
self.write_log(f'当前订单总数:{self.order_volumes}, 废单总数:{self.order_reject_volumes}, 超过阈值{self.reject_ratio_percent_limit}%')
return False
if self.order_cancel_volumes > 0 and (self.order_cancel_volumes/self.order_volumes) * 100 > self.cancel_ratio_percent_limit:
self.write_log(f'当前订单总数:{self.order_volumes}, 撤单总数:{self.order_reject_volumes}, 超过阈值{self.cancel_ratio_percent_limit}%')
return False
# Add flow count if pass all checks # Add flow count if pass all checks
self.order_flow_count += 1 self.order_flow_count += 1
return True return True

View File

@ -33,6 +33,10 @@ class RiskManager(QtWidgets.QDialog):
self.cancel_limit_spin = RiskManagerSpinBox() self.cancel_limit_spin = RiskManagerSpinBox()
self.percent_limit_spin = RiskManagerSpinBox() self.percent_limit_spin = RiskManagerSpinBox()
self.ratio_active_limit_spin = RiskManagerSpinBox()
self.reject_limit_percent_spin = RiskManagerSpinBox()
self.cancel_limit_percent_spin = RiskManagerSpinBox()
save_button = QtWidgets.QPushButton("保存") save_button = QtWidgets.QPushButton("保存")
save_button.clicked.connect(self.save_setting) save_button.clicked.connect(self.save_setting)
@ -46,6 +50,9 @@ class RiskManager(QtWidgets.QDialog):
form.addRow("活动委托上限(笔)", self.active_limit_spin) form.addRow("活动委托上限(笔)", self.active_limit_spin)
form.addRow("合约撤单上限(笔)", self.cancel_limit_spin) form.addRow("合约撤单上限(笔)", self.cancel_limit_spin)
form.addRow("资金仓位上限(%)", self.percent_limit_spin) form.addRow("资金仓位上限(%)", self.percent_limit_spin)
form.addRow("激活废单/撤单(笔)", self.ratio_active_limit_spin)
form.addRow("废单比上限(%)", self.reject_limit_percent_spin)
form.addRow("撤单比上限(%)", self.cancel_limit_percent_spin)
form.addRow(save_button) form.addRow(save_button)
self.setLayout(form) self.setLayout(form)
@ -71,6 +78,9 @@ class RiskManager(QtWidgets.QDialog):
"active_order_limit": self.active_limit_spin.value(), "active_order_limit": self.active_limit_spin.value(),
"order_cancel_limit": self.cancel_limit_spin.value(), "order_cancel_limit": self.cancel_limit_spin.value(),
"percent_limit": self.percent_limit_spin.value(), "percent_limit": self.percent_limit_spin.value(),
"ratio_active_order_limit": self.ratio_active_limit_spin.value(),
"cancel_ratio_percent_limit": self.cancel_limit_percent_spin.value(),
"reject_ratio_percent_limit": self.reject_limit_percent_spin.value()
} }
self.rm_engine.update_setting(setting) self.rm_engine.update_setting(setting)
@ -93,6 +103,10 @@ class RiskManager(QtWidgets.QDialog):
self.active_limit_spin.setValue(setting["active_order_limit"]) self.active_limit_spin.setValue(setting["active_order_limit"])
self.cancel_limit_spin.setValue(setting["order_cancel_limit"]) self.cancel_limit_spin.setValue(setting["order_cancel_limit"])
self.percent_limit_spin.setValue(setting.get('percent_limit', 100)) self.percent_limit_spin.setValue(setting.get('percent_limit', 100))
self.ratio_active_limit_spin.setValue(setting.get('ratio_active_order_limit', 500))
self.cancel_limit_percent_spin.setValue(setting.get('cancel_ratio_percent_limit', 90))
self.reject_limit_percent_spin.setValue(setting.get('reject_ratio_percent_limit', 90))
def exec_(self): def exec_(self):
"""""" """"""