[增强功能] 风控模块,增加废单比,撤单比控制
This commit is contained in:
parent
c890b931b7
commit
5cd7edd3dc
@ -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
|
||||||
|
@ -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):
|
||||||
""""""
|
""""""
|
||||||
|
Loading…
Reference in New Issue
Block a user