# CtpPlus-master **Repository Path**: syealfalfa/CtpPlus-master ## Basic Information - **Project Name**: CtpPlus-master - **Description**: 期货CTP接口封装,释放GIL锁 - **Primary Language**: Python - **License**: GPL-3.0 - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 17 - **Forks**: 18 - **Created**: 2024-03-07 - **Last Updated**: 2025-08-28 ## Categories & Tags **Categories**: stocks **Tags**: None ## README ``` 提示:投资有风险,入市需谨慎! ``` # 简介 ### 1. CtpPlus是上期技术CTP API的Python封装,具有以下特点 * **易使用**:Python语言,结构清晰,注释完整,文档详尽。 * **低延时**:基于Cython释放GIL;支持多路行情源;无需主事件引擎,实现去中心化。 * **忠实于CTP官方特性**:充分利用CTP的异步、多线程特性。 ### 2. v6.7.9及之前版本需手动修改 FutureAccount.py 中模拟交易环境为如下地址(旧地址已弃用) #### 2.1 第一套环境(SimNow): 182.254.243.31:30001 第一组交易前置 182.254.243.31:30011 第一组行情前置 182.254.243.31:30002 第二组交易前置 182.254.243.31:30012 第二组行情前置 182.254.243.31:30003 第三组交易前置 182.254.243.31:30013 第三组行情前置 #### 2.2 第二套环境:7x24环境(SimNow, 仅在盘后开放) 182.254.243.31:40001 交易前置 182.254.243.31:40011 行情前置 # 一、API下载 ### 1.API接口和chm开发文档下载地址 [https://www.simnow.com.cn/static/apiDownload.action # 二、量化交易投研平台 ### 1.项目简介 **该项目包含数据接口lhxtApi、回测系统backtest、客户端lhxt_client等,提供回测、数据分析、模拟交易、实盘交易等一站式服务。** ### 2.gitee地址 [https://gitee.com/syealfalfa/lhxt_version](https://gitee.com/syealfalfa/lhxt_version) # 三、Windows环境下项目目录如下: ![Image text](img/windows_project.jpg) ​ **说明:打包时将 .dll 文件放入项目目录下** ### 1.打包方法 ​ **windows环境打包:双击 install_ctp_win.bat** # 四、Linux环境下项目目录如下: ![Image text](img/linux_project.jpg) ​ **说明:打包时将 .so 文件放入项目目录下** ### 1.打包方法一: 说明:该方式打包的安装包只能在当前linux环境下安装(如Ubuntu或Centos),不能通用 **linux环境打包:sh install_ctp_linux.sh** ### 2.打包方法二: 说明:该方式打包的安装包可以在任意linux环境下安装(如Ubuntu和Centos) #### 2.1拉取官方 manylinux2014 镜像 ```p # 拉取官方 manylinux2014 镜像 docker pull quay.io/pypa/manylinux2014_x86_64 ``` #### 2.2启动 manylinux2014 容器 ``` # 启动 manylinux2014 容器 docker run -it --rm quay.io/pypa/manylinux2014_x86_64 bash ``` #### 2.3查看已安装的 Python 版本 ``` # 查看已安装的 Python 版本 ls /opt/python/ ``` #### 2.4特定python(如python3.9)安装Cython ``` # 使用特定 Python 版本安装Cython(如python3.9) /opt/python/cp39-cp39/bin/pip install Cython -i https://pypi.tuna.tsinghua.edu.cn/simple/ ``` #### 2.5文件挂载 ``` # 挂载本地jao文件夹至manylinux2014容器的home目录(jao文件中存放CtpPlus项目源码) docker run -it -v /home/jao:/home quay.io/pypa/manylinux2014_x86_64 /bin/bash ``` #### 2.6项目打包 ``` 打包成特定版本的安装包(例如python3.10) /opt/python/cp310-cp310/bin/python setup.py sdist bdist_wheel ``` #### 2.7修复 Wheel 为 manylinux 兼容 ``` # 安装 auditwheel /opt/python/cp310-cp310/bin/pip install auditwheel # 修复 Wheel /opt/python/cp310-cp310/bin/auditwheel repair dist/*.whl --plat manylinux2014_x86_64 # 修复后的Wheel在wheelhouse文件内 ``` #### 2.8上传至pypi官网 ``` # 不能重复上传同一个版本的包 twine upload wheelhouse/* ``` # 五、Linux下打包注意事项(ubuntu) **1.在打包前先重命名linux64文件中的 .so 链接库文件:** ``` thostmduserapi_se.so -> libthostmduserapi_se.so thosttraderapi_se.so -> libthosttraderapi_se.so ``` **2.如不重命名链接库文件,在打包过程中则会出现如下错误:** /usr/bin/ld: cannot find -lthostmduserapi_se: No such file or directory # 六、Linux环境下安装(ubuntu) ## 1.安装自己打包的安装包 ```python #1.python3.10环境安装自己打包的CtpPlus安装包: # 进入到 CtpPlus-6.7.2-cp310-cp310-linux_x86_64.whl 所在的文件执行以下命令 pip install CtpPlus-6.7.2-cp310-cp310-linux_x86_64.whl ``` ## 2.安装官方提供的安装包 ``` pip install CtpPlus ``` # 七、windows安装 首先配置[Anaconda环境](http://algo.plus/algoplus/getting-started/installation.html) 或 python环境 以下为安装方法: ![Image text](img/install.jpg) ## 1.安装自己打包的安装包 项目中已提供了python3.10的window安装包,cd到对应的安装包路径即可,然后使用pip命令安装: ``` pip install CtpPlus-1.0-cp38-cp38-win_amd64.whl ``` ## 2.安装官方提供的安装包 ``` pip install CtpPlus ``` # 八、CtpPlus文件介绍: - **api:存放的是Linux和windows版本CTP链接库** - **c2cython:实现CTP回调函数功能** - **cython2c:使用cython调用CTP接口** - **MdApiBase.pyx:封装后的CTP行情接口** - **TraderApiBase.pyx:封装后的CTP交易接口** - **MdApi.py和TraderApi.py:接口案例文件** - **ApiConst.py:对应CTP的ThostFtdcUserApiDataType.h中的数据类型** - **ApiStruct.py:对应CTP的ThostFtdcUserApiStruct.h中的数据结构** - **FutureAccount.py:配置文件** ## 1.ApiStruct.py对应ThostFtdcUserApiStruch.h ![Image text](img/file1.png) **左侧CtpPlus文件名命规则:去掉了右侧CTP文件结构体名中的"CthostFtdc"** ## 2.ApiConst.py对应ThostFtdcUserApiDataType.h ![Image text](img/file2.png) **左侧CtpPlus文件名命规则:由右侧CTP文件红色框中的单词拼接** 用法如下: ```python from CtpPlus.CTP.TraderApiBase import HedgeFlag_Speculation # 请求查询合约保证金率(投机) pInstrumentMarginRate = QryInstrumentMarginRateField(BrokerID=self.broker_id, InvestorID=self.investor_id, HedgeFlag=HedgeFlag_Speculation, InstrumentID=b'ag2510') self.ReqQryInstrumentMarginRate(pInstrumentMarginRate) ``` # 九、CTP API文档及资料链接 * [CTP API的工作原理](https://www.zhihu.com/zvideo/1288267321451081728) * [景色的CTPAPI系列文章](https://mp.weixin.qq.com/mp/appmsgalbum?__biz=Mzg5MjEwNDEwMQ==&action=getalbum&album_id=1545992091560968194) * [秋水的CTPAPI系列文章](https://mp.weixin.qq.com/mp/appmsgalbum?__biz=MzAxOTQ2ODA3OA==&action=getalbum&album_id=1501810151681523713) * [CTPAPI接口开发“葵花宝典”](https://mp.weixin.qq.com/mp/appmsgalbum?__biz=MzAxOTQ2ODA3OA==&action=getalbum&album_id=1501810151681523713) * [CTPAPI接口量化交易资料汇总](https://mp.weixin.qq.com/mp/appmsgalbum?__biz=MzAxOTQ2ODA3OA==&action=getalbum&album_id=1501810151681523713) * [CTP客户端开发指南.pdf](https://mp.weixin.qq.com/mp/appmsgalbum?__biz=MzAxOTQ2ODA3OA==&action=getalbum&album_id=1501810151681523713) * [综合交易平台API技术开发指南.pdf](https://mp.weixin.qq.com/mp/appmsgalbum?__biz=MzAxOTQ2ODA3OA==&action=getalbum&album_id=1501810151681523713) * [综合交易平台API开发常见问题列表.pdf](https://mp.weixin.qq.com/mp/appmsgalbum?__biz=MzAxOTQ2ODA3OA==&action=getalbum&album_id=1501810151681523713) * [综合交易平台交易API特别说明.pdf](https://mp.weixin.qq.com/mp/appmsgalbum?__biz=MzAxOTQ2ODA3OA==&action=getalbum&album_id=1501810151681523713) * [CTP期权保证金手续费算法说明.pdf](https://mp.weixin.qq.com/mp/appmsgalbum?__biz=MzAxOTQ2ODA3OA==&action=getalbum&album_id=1501810151681523713) * [FTD期货交易数据交换协议.pdf](https://mp.weixin.qq.com/mp/appmsgalbum?__biz=MzAxOTQ2ODA3OA==&action=getalbum&album_id=1501810151681523713) # 十、应用范例 这里就给大家介绍介个基于CtpPlus实现的应用范例,供大家参考。 **配置文件:FutureAccount.py** ```python # encoding:utf-8 import os BASE_LOCATION = "./log" MD_LOCATION = BASE_LOCATION TD_LOCATION = BASE_LOCATION SIMULATE_SERVER = { '电信1': {'BrokerID': 9999, 'TDServer': "180.168.146.187:10201", 'MDServer': '180.168.146.187:10211', 'AppID': 'simnow_client_test', 'AuthCode': '0000000000000000'}, '电信2': {'BrokerID': 9999, 'TDServer': "180.168.146.187:10202", 'MDServer': '180.168.146.187:10212', 'AppID': 'simnow_client_test', 'AuthCode': '0000000000000000'}, '移动': {'BrokerID': 9999, 'TDServer': "218.202.237.33:10203", 'MDServer': '218.202.237.33:10213', 'AppID': 'simnow_client_test', 'AuthCode': '0000000000000000'}, 'TEST': {'BrokerID': 9999, 'TDServer': "180.168.146.187:10130", 'MDServer': '180.168.146.187:10131', 'AppID': 'simnow_client_test', 'AuthCode': '0000000000000000'}, 'N视界': {'BrokerID': 10010, 'TDServer': "210.14.72.12:4600", 'MDServer': '210.14.72.12:4602', 'AppID': '', 'AuthCode': ''}, } class FutureAccount: def __init__(self, broker_id, server_dict, reserve_server_dict, investor_id, password, app_id, auth_code, subscribe_list, md_flow_path=MD_LOCATION, td_flow_path=TD_LOCATION): self.broker_id = broker_id # 期货公司BrokerID self.server_dict = server_dict # 登录的服务器地址 self.reserve_server_dict = reserve_server_dict # 备用服务器地址 self.investor_id = investor_id # 账户 self.password = password # 密码 self.app_id = app_id # 认证使用AppID self.auth_code = auth_code # 认证使用授权码 self.subscribe_list = subscribe_list # 订阅合约列表[] self.md_flow_path = md_flow_path # MdApi流文件存储地址,默认MD_LOCATION self.td_flow_path = td_flow_path # TraderApi流文件存储地址,默认TD_LOCATION def get_simulate_account(investor_id, password, subscribe_list=None, server_name='电信1', md_flow_path=MD_LOCATION, td_flow_path=TD_LOCATION): if server_name not in SIMULATE_SERVER.keys(): print(f'{server_name}不在可选列表[电信1, 电信2, 移动, TEST]中,默认使用电信1。') server_name = '电信1' if subscribe_list is None: subscribe_list = [] investor_id = investor_id if isinstance(investor_id, bytes) else investor_id.encode(encoding='utf-8') password = password if isinstance(password, bytes) else password.encode(encoding='utf-8') return FutureAccount( broker_id=SIMULATE_SERVER[server_name]['BrokerID'], # 期货公司BrokerID server_dict=SIMULATE_SERVER[server_name], # TDServer为交易服务器,MDServer为行情服务器。服务器地址格式为"ip:port。" reserve_server_dict={}, investor_id=investor_id, # 账户 password=password, # 密码 app_id=SIMULATE_SERVER[server_name]['AppID'], # 认证使用AppID auth_code=SIMULATE_SERVER[server_name]['AuthCode'], # 认证使用授权码 subscribe_list=subscribe_list, # 订阅合约列表 md_flow_path=md_flow_path, # MdApi流文件存储地址,默认MD_LOCATION td_flow_path=td_flow_path # TraderApi流文件存储地址,默认TD_LOCATION ) ``` ## 1、CTP API文档中的接口在python中的使用示例 ### 1.1请求接口:CTP API中的请求查询投资者持仓接口: ```c++ // 原生接口 virtual int ReqQryInvestorPosition(CThostFtdcQryInvestorPositionField *pQryInvestorPosition, int nRequestID) = 0; ``` 该接口在python中的用法: ```python # CThostFtdcQryInvestorPositionField 对应 QryInvestorPositionField # 原生接口中传入的结构体在封装后名字中少了CThostFtdc from CtpPlus.CTP.ApiStruct import QryInvestorPositionField qry_investor_position_field = QryInvestorPositionField(BrokerID=self.broker_id, InvestorID=self.investor_id) result = self.ReqQryInvestorPosition(qry_investor_position_field) ``` ### 1.2响应接口:CTP API中的请求查询投资者持仓响应接口 ```c++ // 原生接口 virtual void OnRspQryInvestorPosition(CThostFtdcInvestorPositionField *pInvestorPosition, CThostFtdcRspInfoField *pRspInfo, int nRequestID, bool bIsLast) {}; ``` 该接口在python中重写: ```python # 去掉数据类型即可 def OnRspQryInvestorPosition(pInvestorPosition, pRspInfo, nRequestID, bIsLast): print(pInvestorPosition) ``` **其他接口的使用方法类似,可见源文件: TraderApiBase.pyx** ## 2、获取实时行情和交易接口测试 #### 期货合约规范: - 上期/能源所:小写+4个数字 - 大商所:小写+4个数字 - 中金所:大写+4个数字 - 郑商所:大写+3个数字 - 广期所:小写+4个数字 #### 期权合约规范: - 上期所/能源所:小写+4个数字+C(或者P)+行权价 - 郑商所:大写+3个数字+C(或者P)+行权价 - 中金所:大写+4个数字+-C-(或者-P-)+行权价 - 大商所:小写+4个数字+-C-(或者-P-)+行权价 - 广期所:小写+4个数字+-C-(或者-P-)+行权价 #### 期货交易所ID: - 上期所:SHFE - 能源所:INE - 大商所:DCE - 中金所:CFFEX - 郑商所:CZCE - 广期所:GFEX #### 2.1获取实时行情 发布实时行情是交易所实现价值发现职能的重要工作,而且是交易决策的重要依据。 CTP通过一个独立的MdApi接口发布行情。MdApi功能比较单一,只需要在与服务器建立连接后订阅相关合约,就可以自动接收到到实时行情。 AlgoPlus对MdApi进行了封装,我们只需要将账户信息及合约名称作为参数传进去,就可以接收到字典形式的实时行情数据。 演示这个功能的例子是`examples/test_MdApi.py`,运行之后可以看到如下的输出结果: ```python # -*- codeing:utf-8 -*- ''' @author: syealfalfa @datetime: 2024/2/22 11:00 @Blog: 获取tick数据 ''' from CtpPlus.CTP.ApiStruct import ReqUserLoginField, QryMulticastInstrumentField from CtpPlus.CTP.FutureAccount import get_simulate_account, FutureAccount from CtpPlus.CTP.MdApi import run_api from CtpPlus.CTP.MdApiBase import MdApiBase class TickEngine(MdApiBase): def __init__(self, broker_id, md_server, investor_id, password, app_id, auth_code, instrument_id_list, md_queue_list=None, page_dir='', using_udp=False, multicast=False, *args, **kwargs): super(TickEngine, self).__init__() def OnRtnDepthMarketData(self, pDepthMarketData): print(pDepthMarketData) def OnRspUserLogin(self, pRspUserLogin, pRspInfo, nRequestID, bIsLast): self.write_log('OnRspUserLogin', pRspUserLogin) def OnRspQryMulticastInstrument(self, pMulticastInstrument, pRspInfo, nRequestID, bIsLast): print(f'OnRspQryMulticastInstrument: {pMulticastInstrument}') if __name__ == '__main__': subscribe_list = [b'rb2410'] future_account = get_simulate_account( investor_id='', # SimNow账户 password='', # SimNow账户密码 subscribe_list=subscribe_list, # 合约列表 server_name='TEST' # 电信1、电信2、移动、TEST ) run_api(TickEngine, future_account) ``` ![Image text](img/git_tick.jpg) 从输出日志可以看到,CtpPlus第一步连接服务器,第二步登陆账户,第三步订阅行情,最后就是接收行情数据。 #### 2.2交易接口测试 ```python # -*- codeing:utf-8 -*- ''' @author: syealfalfa @datetime: 2024/3/4 9:56 @Blog: ''' import time from CtpPlus.CTP.ApiStruct import QryRULEIntraParameterField, QryProductGroupField, QryExchangeField, QryInstrumentField from CtpPlus.CTP.FutureAccount import get_simulate_account, FutureAccount from CtpPlus.CTP.TraderApiBase import TraderApiBase from CtpPlus.utils.base_field import to_str class TraderEngine(TraderApiBase): def __init__(self, broker_id, td_server, investor_id, password, app_id, auth_code, md_queue=None, flow_path='', private_resume_type=2, public_resume_type=2): super(TraderEngine, self).__init__() def OnRspSettlementInfoConfirm(self, pSettlementInfoConfirm, pRspInfo, nRequestID, bIsLast): """投资者结算结果确认响应""" self.write_log('pSettlementInfoConfirm', pSettlementInfoConfirm) def OnRspUserLogin(self, pRspUserLogin, pRspInfo, nRequestID, bIsLast): """登录请求响应""" self.write_log('OnRspUserLogin', pRspUserLogin) # 请求RULE品种内对锁仓折扣参数查询 # pQryRULEIntraParameter = QryRULEIntraParameterField(ExchangeID=b'9080', ProdFamilyCode=b'MA') # ret = self.ReqQryRULEIntraParameter(pQryRULEIntraParameter) # print(f'ReqQryRULEIntraParameter: ret = {ret}') # 请求查询产品组 # pQryProductGroup = QryProductGroupField(ProductID=b'ag', ExchangeID=b'SHFE') # ret = self.ReqQryProductGroup(pQryProductGroup) # print(f'ReqQryProductGroup: ret = {ret}') # 买开仓 ret = self.buy_open(b'SHFE', b'rb2405', 3720, 1) if not ret: self.write_log("ReqOrderInsert", "买入开仓成功") """查询持仓明细""" # self.query_position_detail() """请求查询交易所""" # pQryExchange = QryExchangeField(ExchangeID=b'SHFE') # self.ReqQryExchange(pQryExchange) """请求查询合约,填空可以查询到所有合约""" # pQryInstrument = QryInstrumentField() # self.ReqQryInstrument(pQryInstrument) # self.query_instrument() def OnRspQryInstrument(self, pInstrument, pRspInfo, nRequestID, bIsLast): """请求查询合约响应""" pInstrument['InstrumentName'] = to_str(pInstrument['InstrumentName']) self.write_log("OnRspQryInstrument", pInstrument, pRspInfo) def OnRspQryRULEIntraParameter(self, pRULEIntraParameter, pRspInfo, nRequestID, bIsLast): self.write_log('OnRspQryRULEIntraParameter', pRULEIntraParameter) def OnRspQryProductGroup(self, pProductGroup, pRspInfo, nRequestID, bIsLast): self.write_log('OnRspQryProductGroup', pProductGroup, pRspInfo, nRequestID, bIsLast) def OnRspQryExchange(self, pExchange, pRspInfo, nRequestID, bIsLast): pExchange['ExchangeName'] = to_str(pExchange['ExchangeName']) self.write_log('OnRspQryExchange', pExchange) def run_api(api_cls, account): if isinstance(account, FutureAccount): trader_engine = api_cls( account.broker_id, account.server_dict['TDServer'], account.investor_id, account.password, account.app_id, account.auth_code, None, account.td_flow_path ) trader_engine.Join() if __name__ == '__main__': subscribe_list = [b'rb2410'] future_account = get_simulate_account( investor_id='******', # SimNow账户 password='******', # SimNow账户密码 subscribe_list=subscribe_list, # 合约列表 server_name='TEST' # 电信1、电信2、移动、TEST、实盘 ) run_api(TraderEngine, future_account) ``` 测试结果如下: ![Image text](img/trade.jpg) ## 3、将行情存为CSV文件 因为MdApi只推送实时行情,所以存储数据是量化交易至关重要的一项工作。虽然有多种数据库可以选择,但是简单起见,`examples/tick_to_csv.py`使用了csv文件。运行这个例子后,实时行情数据自动被存入`MarketData`文件夹下的csv文件中。 ## 4、合成K线 MdApi推送的实时行情是固定时间间隔(一般间隔是500ms)的快照,也就是我们常说Tick数据。 而交易决策的逻辑基础往往是K线数据,所谓的K线就是用固定时间间隔内开盘价、最高价、最低价、收盘价代理此间所有Tick。 K线自诞生以来就被二级市场所广泛使用。合理的选择K线周期,可以帮助我们抓住主线趋势,避免陷于短期波动。 `examples/get_bar.py`为大家演示了如何将Tick数据合成1分钟K线数据,字段内容如下: ```python { 'UpdateTime': b'00:46:00', # K线开始时间 'LastPrice': 3454.0, # 收盘价 'HighPrice': 3454.0, # 最高价 'LowPrice': 3454.0, # 最低价 'OpenPrice': 3454.0, # 开盘价 'BarVolume': 7, # 成交量 'BarTurnover': 24178.0, # 成交额 'BarSettlement': 3454.0, # K线成交均价 'BVolume': 0, # 主动买量 'SVolume': 7, # 主动卖量 'FVolume': 0, # 非主动买卖量 'DayVolume': 1381157, # 全天成交量 'DayTurnover': 4771897578.0, # 全天成交额 'DaySettlement': 3455.000103536383, # 全天成交均价 'OpenInterest': 1577415.0, # 持仓量 'LastVolume': 1381157, # 全天成交量 'TradingDay': b'20200508' # 交易日 } ``` 除了1分钟K线之外,大家也可以参考如下条件合成其他周期K线: ```python # 1分钟K线条件 is_new_1minute = (pDepthMarketData['UpdateTime'][:-2] != last_update_time[:-2]) and pDepthMarketData['UpdateTime'] != b'21:00:00' # 5分钟K线条件 is_new_5minute = is_new_1minute and int(pDepthMarketData['UpdateTime'][-4]) % 5 == 0 # 10分钟K线条件 is_new_10minute = is_new_1minute and pDepthMarketData['UpdateTime'][-4] == b"0" # 15分钟K线条件 is_new_10minute = is_new_1minute and int(pDepthMarketData['UpdateTime'][-5:-3]) % 15 == 0 # 30分钟K线条件 is_new_30minute = is_new_1minute and int(pDepthMarketData['UpdateTime'][-5:-3]) % 30 == 0 # 60分钟K线条件 is_new_hour = is_new_1minute and int(pDepthMarketData['UpdateTime'][-5:-3]) % 60 == 0 ``` 运行结果如下: ![Image text](img/get_bar.jpg) ## 5、看穿式认证 由于监管要求,接入期货公司的交易程序必须经过看穿式认证。简单的说,就是用交易程序在期货公司提供的仿真环境中完成指定的交易、查询任务就可以了。完成后,期货公司会提供用于生产环境的授权码。所谓的直连模式和中继模式,只要是自己用的都属于直连模式。 `examples/trade_demo.py`这个例子虽然是为了方便大家做认证,但是其中的基础操作对熟悉交易接口是很有帮助的,例如: ```python # 交易接口请查看TraderApiBase.py文件 # 行情接口请查看MdApiBase.py文件 # 为了使用方便,对以下功能的接口进行了二次封装 # 买开仓 self.buy_open(...) # 卖平仓 self.sell_close(...) # 卖开仓 self.sell_open(...) # 买平仓 self.buy_close(...) # 撤单 self.cancel_order(...) # 查询订单 self.ReqQryOrder(...) # 查询成交 self.ReqQryTrade() # 查询持仓 self.ReqQryInvestorPosition() # 查询持仓明细 self.query_position_detail() # 查询资金 self.ReqQryTradingAccount() # 查询所有合约 self.query_instrument() # 查询版本号 self.GetApiVersion(self) ``` 需要注意的是交易接口的查询功能是有流控限制的,每秒限制只能查询1次。买卖报单以及撤单不受流控限制。 ## 6、滚动交易 延时是很多量化交易会关注的问题,但是这又是一个很复杂的问题。 为了简单起见,我们设计了`examples/rolling_trade.py`这个滚动交易策略:收到前次报单成交回报时发起新的交易请求。完成300次交易之后,我们统计一下1秒内的交易次数,就可以计算出交易环境的延时,包括网络、交易程序、期货公司系统、交易所系统总的用时。 我使用simnow的7*24测试环境在阿里云服务器上运行该例子,1s内完成110笔成交。但是,需要说明的是,这个数据并不真实,因为7*24测试环境负载非常低。建议大家在正常的交易时间使用simnow仿真环境测试,可以获得相对更有价值的数据。 ## 7、盈损管理 `examples/profit_loss_manager.py`是一个相对复杂的例子,启动后可以监控账户的所有的成交,包括从快期或者其他终端软件报的单,当达到止盈止损条件时,就会自动平仓。启动前需要设置好止盈止损参数: ```python pl_parameter = { 'StrategyID': 9, # 盈损参数,'0'代表止盈, '1'代表止损,绝对价差 'ProfitLossParameter': { b'rb2010': {'0': [2], '1': [2]}, b'ni2007': {'0': [20], '1': [20]}, }, } ``` 简单起见,这里只实现了固定止盈止损,大家可以参考实现更复杂、有效的止损策略。这篇文章为大家提供一些关于止盈止损的思路:[http://algo.plus/researches/0002.html](http://algo.plus/researches/0002.html) 另外,我们也可以将这个策略部署到服务器上,成为属于自己的云端条件单系统。 因为目的是为了让大家快速熟悉CtpPlus,所以很多问题都浅尝辄止,以后有机会我们再进行深入探讨,也欢迎大家在后台留言讨论。 ## 8、订阅行情并落地为csv文件 期货合约都是有期限的,订阅全市场行情需要先使用`CtpPlus.CTP.TraderApi.req_instrument`查询当前挂牌交易的所有合约。 `examp/test_to_csv.py`演示了具体如何将bar数据保存成csv文件。 # 十二、开源地址及联系方式 ## https://gitee.com/syealfalfa/CtpPlus-master ## 微信号:**syealfalfa**