CTP期货程序化交易开发讲解C++版 2024 五

文章详细指导如何在C++中编写代码,涉及登录、退出功能的代码实现,包括设置服务器地址、账号密码以及MDApi和Spi对象的创建与初始化过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

第六节  代码的编写(1

从这一节开始,进入到代码的编写,有了上面的基础,我们只需要一个个的把里面的按钮双击,进入到对应的代码编写区域,把相应功能的代码写上去就可以了。

还是按上面的顺序,首先,我们来编写登入、退出 部分的代码。需要查看原文件的读者,欢迎前往 :https://ipacel.cc/ctp

一、上期模拟、上期7X24:这两个Radio Button 用来切换两个CTP服务器的地址,为了方便,读者也可以把账号密码写进去,程序调试好了,记得把账号密码不要显示出来。双击这两个按钮,把以下代码分别复制到相应的响应事件中去:

  1. void CMyCtpDlg::OnBnClickedR1()      //上期模拟
  2. {
  3. // TODO: 在此添加控件通知处理程序代码
  4. GetDlgItem(IDC_EDIT_MDadd)->SetWindowTextW(_T("tcp://218.202.237.33:10213"));
  5. GetDlgItem(IDC_EDIT_TRadd)->SetWindowTextW(_T("tcp://218.202.237.33:10203"));
  6. GetDlgItem(IDC_EDIT_BrID)->SetWindowTextW(_T("9999"));
  7. GetDlgItem(IDC_EDIT_INVid)->SetWindowTextW(_T(""));
  8. GetDlgItem(IDC_EDIT_Pass)->SetWindowTextW(_T(""));
  9. GetDlgItem(IDC_EDIT_appid)->SetWindowTextW(_T("simnow_client_test"));
  10. GetDlgItem(IDC_EDIT_auID)->SetWindowTextW(_T("0000000000000000"));
  11. }
  12. void CMyCtpDlg::OnBnClickedR2()         //上期7X24
  13. {
  14.          // TODO: 在此添加控件通知处理程序代码
  15.          GetDlgItem(IDC_EDIT_MDadd)->SetWindowTextW(_T("tcp://180.168.146.187:10131"));
  16.          GetDlgItem(IDC_EDIT_TRadd)->SetWindowTextW(_T("tcp://180.168.146.187:10130"));
  17.          GetDlgItem(IDC_EDIT_BrID)->SetWindowTextW(_T("9999"));
  18.          GetDlgItem(IDC_EDIT_INVid)->SetWindowTextW(_T(""));
  19.          GetDlgItem(IDC_EDIT_Pass)->SetWindowTextW(_T(""));
  20.          GetDlgItem(IDC_EDIT_appid)->SetWindowTextW(_T("simnow_client_test"));
  21.          GetDlgItem(IDC_EDIT_auID)->SetWindowTextW(_T("0000000000000000"));
  22. }
  • 关闭:我们先把简单的讲了,双击这个按钮控件,代码如下:

void CMyCtpDlg::OnBnClickedCancel()  // 关闭

{      

         if (MessageBox(TEXT("               确定要退出吗?"), TEXT("退出提示"), MB_YESNO | MB_DEFBUTTON1) == IDNO)

         {

                  return;

         }

         CMyCtpDlg::OnBnClickedButton11();      

         PostQuitMessage(0);//最常用

}

  • 登入:

代码如下:

void CMyCtpDlg::OnBnClickedOk()

{

         // TODO: 在此添加控件通知处理程序代码

           ///取得登陆信息

         CString STRTEMP = _T("");

         GetDlgItem(IDC_EDIT_MDadd)->GetWindowTextW(STRTEMP);

         STRTEMP.Trim();     ///trimleft

         if (STRTEMP != "")

         {

                  CStringToChar(STRTEMP, FRONT_MD_ADDR);             // 前置地址  

         }

         else

         {               

                  return;

         }

         STRTEMP = _T("");

         GetDlgItem(IDC_EDIT_TRadd)->GetWindowTextW(STRTEMP);

         STRTEMP.Trim();     ///trimleft

         if (STRTEMP != "")

         {

                  CStringToChar(STRTEMP, FRONT_TR_ADDR);                       // 前置地址  

         }

         else

         {               

                  return;

         }

         STRTEMP = _T("");

         GetDlgItem(IDC_EDIT_BrID)->GetWindowTextW(STRTEMP);

         STRTEMP.Trim();     ///trimleft

         if (STRTEMP != "")

         {

                  CStringToChar(STRTEMP, BROKER_ID);

         }

         else

         {               

                  return;

         }

         STRTEMP = _T("");

         GetDlgItem(IDC_EDIT_INVid)->GetWindowTextW(STRTEMP);

         STRTEMP.Trim();     ///trimleft

         if (STRTEMP != "")

         {

                  CStringToChar(STRTEMP, INVESTOR_ID);                   // 投资者代码

         }

         else

         {               

                  return;

         }

         STRTEMP = _T("");

         GetDlgItem(IDC_EDIT_Pass)->GetWindowTextW(STRTEMP);

         /// STRTEMP.Trim();     ///trimleft   ///密码前后可以有空格,不能删除这些信息

         if (STRTEMP != _T(""))

         {

                  CStringToChar(STRTEMP, PASSWORD);  ///TThostFtdcPasswordType  PASSWORD = "";                      // 用户密码

         }

         else

         {               

                  return;

         }

         STRTEMP = _T("");

         GetDlgItem(IDC_EDIT_appid)->GetWindowTextW(STRTEMP);

         STRTEMP.Trim();

         if (STRTEMP != _T(""))

         {

                  CStringToChar(STRTEMP, APPID);  ///                     APPID不能为 空

         }

         else

         {               

                  return;

         }

         STRTEMP = _T("");

         GetDlgItem(IDC_EDIT_auID)->GetWindowTextW(STRTEMP);

         STRTEMP.Trim();

         if (STRTEMP != _T(""))

         {

                  CStringToChar(STRTEMP, AuthCode);  ///                         认证码不能为 空

         }

         else

         {               

                  return;

         }               

         将以上登陆信息写入到相应的结构中去///

         memset(&reqUserInFo, 0, sizeof(reqUserInFo));

         strcpy_s(reqUserInFo.BrokerID, BROKER_ID);

         strcpy_s(reqUserInFo.UserID, INVESTOR_ID);

         strcpy_s(reqUserInFo.Password, PASSWORD);

         //CThostFtdcReqAuthenticateField Auth_login_field;  ///穿透式认证信息

         memset(&Auth_login_field, 0, sizeof(Auth_login_field));

         strcpy_s(Auth_login_field.BrokerID, BROKER_ID);

         strcpy_s(Auth_login_field.UserID, INVESTOR_ID);

         strcpy_s(Auth_login_field.AppID, APPID);

         strcpy_s(Auth_login_field.AuthCode, AuthCode);

         /// //

         if (!LOGIN_MD_FLAG)

         {

                  CMyCtpDlg::MsgDis(888, _T("正在连接行情服务器,请稍等..."));

                  //判断保存本地数据的目录是否存在,如果不存在,建一个  (".\\flow\\")

                  STRTEMP = _T(".\\flow\\");

                  if (!PathIsDirectory(STRTEMP))

                  {

                          BOOL dirok = CreateDirectory(STRTEMP, NULL);

                  }

                  CThostFtdcMdSpi* pUserMdSpi = new MdSpi//创建spi对象

                  pUserMdApi = CThostFtdcMdApi::CreateFtdcMdApi(".\\flow\\", true);                //创建API对象 //使用udp的通讯模式接收行情 true

                  //pUserMdApi = CThostFtdcMdApi::CreateFtdcMdApi(".\\flow\\", false, false);

                  //其中第一个参数是本地流文件生成的目录。流文

                  //件是行情接口或交易接口在本地生成的流文件,后缀名为.con。流文件中记录着客户端收到的所有的数据流

                  //的数量。第二个参数描述是否使用 UDP 传输模式,true 表示使用 UDP 模式,false 表示使用 TCP 模式。

                  pUserMdApi->RegisterSpi(pUserMdSpi);                                 spi注册给api,注册回调函数

                  pUserMdApi->RegisterFront(FRONT_MD_ADDR);                            注册前置服务器地址   行情地址

                  pUserMdApi->Init();                                                   //自动创建线程,创建后调用spi中的OnFrontConnect函数  pUserTrApi

                if (WAIT_TIMEOUT == WaitForSingleObject(MdXc, 5000)) { MsgDis(888, _T("连接行情服务器失败,连接超时")); }

         }

}

//

这段代码比较长,需要说明一下:

这段代码分成三部分

  • 把参数从各个控件中取出来,再存到相应的数据变量中去。比如,行情前置地址,交易前置地址等,这里只有账号和密码这两个控件在运行时是可以看见的,其它的控件在运行时是看不到,这些看不到的控件,是由旁边两个切换CTP服务器地址等的 Radio Buuton 在点击的时候赋了值的,我们在操作中,只需要手工把账号密码填写进去就可以了。
  • 在正确获取到参数后,开始创建CTP的行情SPI对象:

CThostFtdcMdSpi* pUserMdSpi = new MdSpi//创建spi对象

pUserMdApi = CThostFtdcMdApi::CreateFtdcMdApi(".\\flow\\", true);                 //创建API对象

就是这两句,这个是个重点内容,CTP的API接口除了分行情、交易两个线程外,还分请求与响应函数。行情有请求和响应,交易也有自己的请求和响应。所以,下面就有这一句,将SPI注册回调函数:

pUserMdApi->RegisterSpi(pUserMdSpi);    spi注册给api,注册回调函数

创建这两个对象的时候,有一些参数,请参看源码部分给出的说明,源码上写得比较清楚,有不明白的地方,可以与作者联系沟通交流。

  • 初始化:

pUserMdApi->Init();   //自动创建线程,创建后调用spi中的OnFrontConnect函数  pUserTrApi

通过这个 Init() 函数,程序正确运行时,就会有不同的信息通过回调函数返回相应的信息。

到止,行情的代码就在CTP接口里的回调函数里去写了,我们先不去研究那部分,先把主窗口界面的代码讲解完,回过来再讲解行情,交易API接口提供的回调函数。

### P1007 独木桥问题的Python实现 对于独木桥问题,目标是在给定条件下计算部队撤离独木桥所需的最小时间和最大时间。该问题可以通过模拟士兵过桥的过程来解决。 #### 计算最小时间 为了使所有士兵尽快通过桥梁,可以让速度较慢的士兵先走,这样可以减少快速士兵等待的时间。因此,按照士兵的速度升序排列后依次过桥即可得到最短时间[^1]。 ```python def min_time_to_cross_bridge(soldiers_speeds): soldiers_speeds.sort() n = len(soldiers_speeds) if n == 0: return 0 total_min_time = sum(soldiers_speeds[:n//2]) * 2 + soldiers_speeds[n-1] + (soldiers_speeds[n//2] if n % 2 != 0 else 0) return total_min_time ``` #### 计算最大时间 为了让整个队伍花费尽可能多的时间才能完全离开独木桥,则应让最快的两个士兵最后才一起出发。其余士兵按任意顺序前进均可达到此目的。所以只需考虑最快两人的情况并加上其他所有人单独所需的最大可能耗时即为最终答案。 ```python def max_time_to_cross_bridge(soldiers_speeds): soldiers_speeds.sort(reverse=True) n = len(soldiers_speeds) if n == 0: return 0 total_max_time = sum([max(2*s, soldiers_speeds[i]) for i,s in enumerate(soldiers_speeds[:-2], start=2)]) \ + soldiers_speeds[-2]*2 + soldiers_speeds[-1] return total_max_time ``` 将上述两部分组合起来形成完整的解决方案: ```python def solve_p1007(): import sys input_data = list(map(int, sys.stdin.readline().strip().split())) print(f"{min_time_to_cross_bridge(input_data)} {max_time_to_cross_bridge(input_data)}") if __name__ == "__main__": solve_p1007() ```
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值