[增强功能] 风控增加成交持仓比阈值

This commit is contained in:
msincenselee 2020-09-01 16:56:07 +08:00
parent 5cd7edd3dc
commit 739b075045
2 changed files with 88 additions and 25 deletions

View File

@ -3,11 +3,11 @@ import logging
from copy import copy from copy import copy
from collections import defaultdict from collections import defaultdict
from datetime import datetime from datetime import datetime
from vnpy.trader.constant import Offset from vnpy.trader.constant import Offset, Direction
from vnpy.trader.object import OrderRequest, LogData from vnpy.trader.object import OrderRequest, LogData
from vnpy.event import Event, EventEngine, EVENT_TIMER from vnpy.event import Event, EventEngine, EVENT_TIMER
from vnpy.trader.engine import BaseEngine, MainEngine from vnpy.trader.engine import BaseEngine, MainEngine
from vnpy.trader.event import EVENT_TRADE, EVENT_ORDER, EVENT_LOG, EVENT_ACCOUNT from vnpy.trader.event import EVENT_TRADE, EVENT_ORDER, EVENT_LOG, EVENT_ACCOUNT, EVENT_POSITION
from vnpy.trader.constant import Status from vnpy.trader.constant import Status
from vnpy.trader.utility import load_json, save_json from vnpy.trader.utility import load_json, save_json
@ -20,6 +20,7 @@ APP_NAME = "RiskManager"
-系统需具备成交持仓比控制功能对当日客户账户成交持仓比例进行控制当账户成交量大于1000张时启用各期权标的合约成交持仓比=成交张数/max昨日净持仓张数今日净持仓张数 -系统需具备成交持仓比控制功能对当日客户账户成交持仓比例进行控制当账户成交量大于1000张时启用各期权标的合约成交持仓比=成交张数/max昨日净持仓张数今日净持仓张数
""" """
class RiskManagerEngine(BaseEngine): class RiskManagerEngine(BaseEngine):
"""""" """"""
setting_filename = "risk_manager_setting.json" setting_filename = "risk_manager_setting.json"
@ -30,29 +31,34 @@ 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.order_volumes = 0 # 累计委托数量
self.trade_volumes = 0 # 累计成交数量 self.trade_volumes = 0 # 累计成交数量
self.trade_limit = 10000 # 成交数量上限 self.trade_limit = 10000 # 成交数量上限
self.order_cancel_limit = 5000 # 撤单数量限制 self.order_cancel_limit = 5000 # 撤单数量限制
self.order_cancel_counts = defaultdict(int) # 撤单次数 {合约:撤单次数} self.order_cancel_counts = defaultdict(int) # 撤单次数 {合约:撤单次数}
self.order_cancel_volumes = 0 # 累计撤单笔数 self.pos_yd_counts = {} # {vt_symbol: {'long':x, 'short':y} } 合约多单昨持仓数,# 合约空单昨持仓数
self.order_reject_volumes = 0 # 累计废单笔数 self.pos_td_counts = {} # {vt_symbol: {'long':x, 'short':y} } 合约多单今持仓数, # 合约空单今持仓数
self.order_cancel_volumes = 0 # 累计撤单笔数
self.order_reject_volumes = 0 # 累计废单笔数
self.ratio_active_order_limit = 500 # 激活撤单比、废单比得订单总数量阈值 self.ratio_active_order_limit = 500 # 激活撤单比、废单比得订单总数量阈值
self.trade_hold_active_limit = 1000 # 激活“成交持仓比例”的阈值
self.cancel_ratio_percent_limit = 99 # 撤单比阈值 self.cancel_ratio_percent_limit = 99 # 撤单比风控阈值
self.reject_ratio_percent_limit = 99 # 废单比阈值 self.reject_ratio_percent_limit = 99 # 废单比风控阈值
self.trade_hold_percent_limit = 300 # 成交/持仓比例风控阈值
self.active_order_limit = 500 # 未完成订单数量 self.active_order_limit = 500 # 未完成订单数量
# 总仓位相关(0~100+) # 总仓位相关(0~100+)
self.percent_limit = 100 # 仓位比例限制 self.percent_limit = 100 # 仓位比例限制
@ -94,6 +100,8 @@ class RiskManagerEngine(BaseEngine):
self.ratio_active_order_limit = setting.get('ratio_active_order_limit', 500) 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.cancel_ratio_percent_limit = setting.get('cancel_ratio_percent_limit', 99)
self.reject_ratio_percent_limit = setting.get('reject_ratio_percent_limit', 99) self.reject_ratio_percent_limit = setting.get('reject_ratio_percent_limit', 99)
self.trade_hold_active_limit = setting.get('trade_hold_active_limit', 1000)
self.trade_hold_percent_limit = setting.get('trade_hold_percent_limit', 300)
if self.active: if self.active:
self.write_log("交易风控功能启动") self.write_log("交易风控功能启动")
@ -110,7 +118,12 @@ class RiskManagerEngine(BaseEngine):
"trade_limit": self.trade_limit, "trade_limit": self.trade_limit,
"active_order_limit": self.active_order_limit, "active_order_limit": self.active_order_limit,
"order_cancel_limit": self.order_cancel_limit, "order_cancel_limit": self.order_cancel_limit,
"percent_limit": self.percent_limit "percent_limit": self.percent_limit,
"ratio_active_order_limit": self.ratio_active_order_limit,
"cancel_ratio_percent_limit": self.cancel_ratio_percent_limit,
"reject_ratio_percent_limit": self.reject_ratio_percent_limit,
"trade_hold_active_limit": self.trade_hold_active_limit,
"trade_hold_percent_limit": self.trade_hold_percent_limit
} }
return setting return setting
@ -132,10 +145,11 @@ class RiskManagerEngine(BaseEngine):
self.event_engine.register(EVENT_TRADE, self.process_trade_event) self.event_engine.register(EVENT_TRADE, self.process_trade_event)
self.event_engine.register(EVENT_TIMER, self.process_timer_event) self.event_engine.register(EVENT_TIMER, self.process_timer_event)
self.event_engine.register(EVENT_ORDER, self.process_order_event) self.event_engine.register(EVENT_ORDER, self.process_order_event)
self.event_engine.register(EVENT_POSITION, self.process_position_event)
self.event_engine.register(EVENT_ACCOUNT, self.process_account_event) self.event_engine.register(EVENT_ACCOUNT, self.process_account_event)
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]: if order.status in [Status.ALLTRADED, Status.REJECTED, Status.CANCELLED]:
self.order_volumes += order.volume self.order_volumes += order.volume
@ -149,10 +163,29 @@ class RiskManagerEngine(BaseEngine):
self.order_cancel_volumes += order.volume 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_volumes += trade.volume self.trade_volumes += trade.volume
def process_position_event(self, event: Event):
"""持仓更新"""
pos = event.data
if pos.direction in [Direction.LONG, Direction.NET]:
yd = self.pos_yd_counts.get(pos.vt_symbol, {})
td = self.pos_td_counts.get(pos.vt_symbol, {})
yd.update({'long': pos.yd_volume})
td.update({'long': pos.volume - pos.yd_volume})
self.pos_yd_counts[pos.vt_symbol] = yd
self.pos_td_counts[pos.vt_symbol] = td
if pos.direction in [Direction.SHORT]:
yd = self.pos_yd_counts.get(pos.vt_symbol, {})
td = self.pos_td_counts.get(pos.vt_symbol, {})
yd.update({'short': pos.yd_volume})
td.update({'short': pos.volume - pos.yd_volume})
self.pos_yd_counts[pos.vt_symbol] = yd
self.pos_td_counts[pos.vt_symbol] = td
def process_timer_event(self, event: Event): def process_timer_event(self, event: Event):
"""""" """"""
self.order_flow_timer += 1 self.order_flow_timer += 1
@ -277,13 +310,33 @@ class RiskManagerEngine(BaseEngine):
# 激活撤单比,废单比 # 激活撤单比,废单比
if self.order_volumes > self.ratio_active_order_limit: 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: if self.order_reject_volumes > 0 and (
self.write_log(f'当前订单总数:{self.order_volumes}, 废单总数:{self.order_reject_volumes}, 超过阈值{self.reject_ratio_percent_limit}%') 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 return False
if self.order_cancel_volumes > 0 and (self.order_cancel_volumes/self.order_volumes) * 100 > self.cancel_ratio_percent_limit: if self.order_cancel_volumes > 0 and (
self.write_log(f'当前订单总数:{self.order_volumes}, 撤单总数:{self.order_reject_volumes}, 超过阈值{self.cancel_ratio_percent_limit}%') 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 return False
# 激活成交持仓风控
if self.trade_volumes > self.trade_hold_active_limit:
# 昨仓持仓总数
yd_volumes = sum([max(yd.get('long', 0), yd.get('short', 0)) for yd in self.pos_yd_counts.values()])
# 今仓持仓总数
td_volumes = sum([max(td.get('long', 0), td.get('short', 0)) for td in self.pos_td_counts.values()])
hold_volumes = max(yd_volumes, td_volumes)
if hold_volumes > 0:
if (self.trade_volumes / hold_volumes) * 100 > self.trade_hold_percent_limit:
self.write_log(
f'当前成交总数:{self.trade_volumes}, 昨仓净持仓总数:{yd_volumes},今仓净持仓总数{td_volumes}: '
f'max净持仓数:{hold_volumes}, 成交/持仓比, 超过阈值{self.trade_hold_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

@ -37,6 +37,10 @@ class RiskManager(QtWidgets.QDialog):
self.reject_limit_percent_spin = RiskManagerSpinBox() self.reject_limit_percent_spin = RiskManagerSpinBox()
self.cancel_limit_percent_spin = RiskManagerSpinBox() self.cancel_limit_percent_spin = RiskManagerSpinBox()
self.trade_hold_active_limit_spin = RiskManagerSpinBox()
self.trade_hold_percent_limit_spin = RiskManagerSpinBox()
save_button = QtWidgets.QPushButton("保存") save_button = QtWidgets.QPushButton("保存")
save_button.clicked.connect(self.save_setting) save_button.clicked.connect(self.save_setting)
@ -53,6 +57,9 @@ class RiskManager(QtWidgets.QDialog):
form.addRow("激活废单/撤单(笔)", self.ratio_active_limit_spin) form.addRow("激活废单/撤单(笔)", self.ratio_active_limit_spin)
form.addRow("废单比上限(%)", self.reject_limit_percent_spin) form.addRow("废单比上限(%)", self.reject_limit_percent_spin)
form.addRow("撤单比上限(%)", self.cancel_limit_percent_spin) form.addRow("撤单比上限(%)", self.cancel_limit_percent_spin)
form.addRow("激活成交/持仓比阈值(笔)" ,self.trade_hold_active_limit_spin)
form.addRow("成交/持仓比上限(%)", self.trade_hold_percent_limit_spin)
form.addRow(save_button) form.addRow(save_button)
self.setLayout(form) self.setLayout(form)
@ -80,7 +87,9 @@ class RiskManager(QtWidgets.QDialog):
"percent_limit": self.percent_limit_spin.value(), "percent_limit": self.percent_limit_spin.value(),
"ratio_active_order_limit": self.ratio_active_limit_spin.value(), "ratio_active_order_limit": self.ratio_active_limit_spin.value(),
"cancel_ratio_percent_limit": self.cancel_limit_percent_spin.value(), "cancel_ratio_percent_limit": self.cancel_limit_percent_spin.value(),
"reject_ratio_percent_limit": self.reject_limit_percent_spin.value() "reject_ratio_percent_limit": self.reject_limit_percent_spin.value(),
"trade_hold_active_limit": self.trade_hold_active_limit_spin.value(),
"trade_hold_percent_limit": self.trade_hold_percent_limit_spin.value()
} }
self.rm_engine.update_setting(setting) self.rm_engine.update_setting(setting)
@ -106,7 +115,8 @@ class RiskManager(QtWidgets.QDialog):
self.ratio_active_limit_spin.setValue(setting.get('ratio_active_order_limit', 500)) 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.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)) self.reject_limit_percent_spin.setValue(setting.get('reject_ratio_percent_limit', 90))
self.trade_hold_active_limit_spin.setValue(setting.get('trade_hold_active_limit', 1000))
self.trade_hold_percent_limit_spin.setValue(setting.get("trade_hold_percent_limit", 300))
def exec_(self): def exec_(self):
"""""" """"""