diff --git a/docs/gateway.md b/docs/gateway.md index 714ca42b..1f183ab5 100644 --- a/docs/gateway.md +++ b/docs/gateway.md @@ -71,23 +71,23 @@ def main(): ## 接口分类 -| 接口 |类型 | -| ------ | :------: | -| CTP | 期货 | -| FEMAS | 期货 | -| OES | 国内股票 | -| XTP | 国内股票、指数、基金、债券、期权、融资融券 | -| IB | 外盘股票、期货、期权 | -| TAP | 外盘股票、期货、期权 | -| FUTU | 国内股票、港股、美股 | -| TIGER | 国内股票、港股、美股 | -| BITFINEX | 数字货币 | -| BITMEX | 数字货币 | -| OKEX | 数字货币 | -| OKEXF | 数字货币 | -| HUOBI | 数字货币 | -| HBDM | 数字货币 | -| ONETOKEN | 数字货币 | +| 接口 | 类型 | +| -------- | :----------------------------------------: | +| CTP | 期货 | +| FEMAS | 期货 | +| OES | 国内股票 | +| XTP | 国内股票、指数、基金、债券、期权、融资融券 | +| IB | 外盘股票、期货、期权 | +| TAP | 外盘股票、期货、期权 | +| FUTU | 国内股票、港股、美股 | +| TIGER | 国内股票、港股、美股 | +| BITFINEX | 数字货币 | +| BITMEX | 数字货币 | +| OKEX | 数字货币 | +| OKEXF | 数字货币 | +| HUOBI | 数字货币 | +| HBDM | 数字货币 | +| ONETOKEN | 数字货币 | @@ -270,8 +270,11 @@ main_engine.add_gateway(IbGateway)   #### 其他特点 + 可交易品种几乎覆盖全球的股票、期权、期权;手续费相对较低。 +注意IB接口的合约代码较为特殊,请前往官网的产品查询板块查询,VN Trader中使用的是盈透证券对于每个合约在某一交易所的唯一标识符ConId来作为合约代码,而非Symbol或者LocalName。 +   diff --git a/docs/risk_manager.md b/docs/risk_manager.md new file mode 100644 index 00000000..15e0a7ea --- /dev/null +++ b/docs/risk_manager.md @@ -0,0 +1,39 @@ +# 交易风控 + +交易风控模块属于事前风控,即在委托在通过交易API接口发出去前,需要检查其状态不能超过风控限制,其中包括: +- 委托数量必须大于0 +- 单笔委托的数量上限 +- 当日总成交数量上限 +- 委托流数量上限 +- 当前活动委托次数上限 +- 当日撤单次数上限 + +  + +## 加载启动 + +进入VN Trader后,首先登陆接口,如连接CTP;然后在菜单栏中点击“功能”->"交易风控“后,会弹出交易风控窗口,如图。 +![](https://vnpy-community.oss-cn-shanghai.aliyuncs.com/forum_experience/yazhang/risk_manager/risk_manager.png) + +窗口中显示的参数,对应的是C:\Users\Administrator\.vntrader里面risk_manager_setting.json的参数字典,如图。 +![](https://vnpy-community.oss-cn-shanghai.aliyuncs.com/forum_experience/yazhang/risk_manager/data_setting.png) + +在“风控运行状态”的选择框中点击“启动”后 +- 立刻调用RiskManagerEngine类的update_setting()函数读取risk_manager_setting.json的参数字典并且绑定类的属性。 +- 在日志中输出"交易风控功能启动"。 +- 运行check_risk()函数,去检查每一笔发出去的委托是否符合各种风控要求,若全部满足后,流控计数+1,委托真正通过API接口发送出去。 + +  + +## 修改参数 + +交易风控组件允许用户修改风控参数。由于GUI界面的各参数栏是基于PyQt5的QSpinBox,用户可以用鼠标点击上下箭头来修改,也可以直接键盘输入来修改。 + +最后点击窗口下方的“保存”按钮,对调用RiskManagerEngine类的save_setting()函数去更新到risk_manager_setting.json的参数字典中,最后通过update_setting()函数把参数字典绑定到类的属性。 + +  + +## 停止风控 + +在“风控运行状态”的选择框中点击“停止后”后,RiskManagerEngine类的active变成False,check_risk()函数不再检查委托的风控流控状态,同时在日志中输出"交易风控功能停止"。 + diff --git a/tests/trader/run.py b/tests/trader/run.py index 099d7a55..b4e1db91 100644 --- a/tests/trader/run.py +++ b/tests/trader/run.py @@ -17,8 +17,8 @@ from vnpy.trader.ui import MainWindow, create_qapp # from vnpy.gateway.onetoken import OnetokenGateway # from vnpy.gateway.okexf import OkexfGateway # from vnpy.gateway.xtp import XtpGateway -# from vnpy.gateway.hbdm import HbdmGateway -from vnpy.gateway.tap import TapGateway +from vnpy.gateway.hbdm import HbdmGateway +# from vnpy.gateway.tap import TapGateway # from vnpy.app.cta_strategy import CtaStrategyApp # from vnpy.app.csv_loader import CsvLoaderApp @@ -49,8 +49,8 @@ def main(): # main_engine.add_gateway(BitfinexGateway) # main_engine.add_gateway(OnetokenGateway) # main_engine.add_gateway(OkexfGateway) - # main_engine.add_gateway(HbdmGateway) - main_engine.add_gateway(TapGateway) + main_engine.add_gateway(HbdmGateway) + # main_engine.add_gateway(TapGateway) # main_engine.add_app(CtaStrategyApp) # main_engine.add_app(CtaBacktesterApp) diff --git a/vnpy/app/cta_strategy/backtesting.py b/vnpy/app/cta_strategy/backtesting.py index c63fda23..22ebd22e 100644 --- a/vnpy/app/cta_strategy/backtesting.py +++ b/vnpy/app/cta_strategy/backtesting.py @@ -214,6 +214,8 @@ class BacktestingEngine: if not self.end: self.end = datetime.now() + self.history_data.clear() # Clear previously loaded history data + # Load 30 days of data each time and allow for progress update progress_delta = timedelta(days=30) total_delta = self.end - self.start diff --git a/vnpy/app/cta_strategy/engine.py b/vnpy/app/cta_strategy/engine.py index e17f49ec..ff2e8ef9 100644 --- a/vnpy/app/cta_strategy/engine.py +++ b/vnpy/app/cta_strategy/engine.py @@ -36,7 +36,7 @@ from vnpy.trader.constant import ( Offset, Status ) -from vnpy.trader.utility import load_json, save_json, extract_vt_symbol +from vnpy.trader.utility import load_json, save_json, extract_vt_symbol, round_to from vnpy.trader.database import database_manager from vnpy.trader.rqdata import rqdata_client @@ -464,7 +464,11 @@ class CtaEngine(BaseEngine): if not contract: self.write_log(f"委托失败,找不到合约:{strategy.vt_symbol}", strategy) return "" - + + # Round order price and volume to nearest incremental value + price = round_to(price, contract.pricetick) + volume = round_to(volume, contract.min_volume) + if stop: if contract.stop_supported: return self.send_server_stop_order(strategy, contract, direction, offset, price, volume, lock) diff --git a/vnpy/gateway/hbdm/hbdm_gateway.py b/vnpy/gateway/hbdm/hbdm_gateway.py index fe0d93dc..9c786ec8 100644 --- a/vnpy/gateway/hbdm/hbdm_gateway.py +++ b/vnpy/gateway/hbdm/hbdm_gateway.py @@ -957,6 +957,9 @@ class HbdmDataWebsocketApi(HbdmWebsocketApiBase): def on_connected(self): """""" self.gateway.write_log("行情Websocket API连接成功") + + for ws_symbol in self.ticks.keys(): + self.subscribe_data(ws_symbol) def subscribe(self, req: SubscribeRequest): """""" @@ -979,7 +982,11 @@ class HbdmDataWebsocketApi(HbdmWebsocketApiBase): gateway_name=self.gateway_name, ) self.ticks[ws_symbol] = tick - + + self.subscribe_data(ws_symbol) + + def subscribe_data(self, ws_symbol: str): + """""" # Subscribe to market depth update self.req_id += 1 req = { diff --git a/vnpy/gateway/ib/ib_gateway.py b/vnpy/gateway/ib/ib_gateway.py index 0a7d0fb8..19a84774 100644 --- a/vnpy/gateway/ib/ib_gateway.py +++ b/vnpy/gateway/ib/ib_gateway.py @@ -416,6 +416,9 @@ class IbApi(EWrapper): accountName, ) + if not contract.exchange: + return + ib_size = contract.multiplier if not ib_size: ib_size = 1 diff --git a/vnpy/trader/engine.py b/vnpy/trader/engine.py index 9b60bae0..9a65e90d 100644 --- a/vnpy/trader/engine.py +++ b/vnpy/trader/engine.py @@ -299,7 +299,7 @@ class LogEngine(BaseEngine): file_path = log_path.joinpath(filename) file_handler = logging.FileHandler( - file_path, mode="w", encoding="utf8" + file_path, mode="a", encoding="utf8" ) file_handler.setLevel(self.level) file_handler.setFormatter(self.formatter)