日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程语言 > c/c++ >内容正文

c/c++

C++连接CTP接口实现简单量化交易(行情、交易、k线、策略)

發(fā)布時(shí)間:2024/1/1 c/c++ 58 豆豆
生活随笔 收集整理的這篇文章主要介紹了 C++连接CTP接口实现简单量化交易(行情、交易、k线、策略) 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

對(duì)于量化交易來(lái)說(shuō),量化策略和技術(shù)系統(tǒng)缺一不可,為了知其所以然,本文實(shí)現(xiàn)了一個(gè)C++連接CTP接口進(jìn)行仿真交易的demo,從接收行情、下訂單、數(shù)據(jù)處理到添加策略、掛載運(yùn)行交易等多個(gè)環(huán)節(jié)來(lái)看一下量化交易的最簡(jiǎn)單流程,管中窺豹,一探究竟。

?

準(zhǔn)備工作

交易所接口

這里使用上期所提供的CTP接口API,通過(guò)CTP可以連接交易所進(jìn)行行情接收交易。下載地址:CTP下載

本文使用的win32版本的,linux版本用法類似。

CTP接口包含以下內(nèi)容:

?

  • ThostFtdcTraderApi.h:C++頭文件,包含交易相關(guān)的指令,如報(bào)單。
  • ThostFtdcMdApi.h:C++頭文件,包含獲取行情相關(guān)的指令。
  • ThostFtdcUserApiStruct.h:包含了所有用到的數(shù)據(jù)結(jié)構(gòu)。
  • ThostFtdcUserApiDataType.h:包含了所有用到的數(shù)據(jù)類型。
  • thosttraderapi.lib、thosttraderapi.dll:交易部分的動(dòng)態(tài)鏈接庫(kù)和靜態(tài)鏈接庫(kù)。
  • thostmduserapi.lib、thostmduserapi.dll:行情部分的動(dòng)態(tài)鏈接庫(kù)和靜態(tài)鏈接庫(kù)。
  • error.dtd、error.xml:包含所有可能的錯(cuò)誤信息。

?

?

整個(gè)開發(fā)包有2個(gè)核心頭文件包括4個(gè)核心接口
CThostFtdcMdApi接口和CThostFtdcTraderApi兩個(gè)頭文件,一個(gè)處理行情,一個(gè)處理交易

(1)處理行情的CThostFtdcMdApi接口有兩個(gè)類,分別是CThostFtdcMdApi和CThostFtdcMdSpi,以Api結(jié)尾的是用來(lái)下命令的,以Spi結(jié)尾的是用來(lái)響應(yīng)命令的回調(diào)。

(2)處理交易的CThostFtdcTraderApi接口也有兩個(gè)類,分別是CThostFtdcTraderApi和CThostFtdcTraderSpi, ?通過(guò)CThostFtdcTraderApi向CTP發(fā)送操作請(qǐng)求,通過(guò)CThostFtdcTraderSpi接收CTP的操作響應(yīng)。

?

期貨賬戶

要連接期貨交易所交易,需要開設(shè)自己的賬戶,實(shí)現(xiàn)期貨交易、銀期轉(zhuǎn)賬、保證金等功能,由于小白一般不會(huì)用實(shí)盤資金交易,所以此處推薦用上期所提供的simnow虛擬交易平臺(tái)simnow申請(qǐng)一個(gè)虛擬賬戶。

SIMNOW提供兩類數(shù)據(jù)前置地址:

(1)交易時(shí)段的地址,如09:00-15:00和21:00-02:30,使用第一套地址,這些數(shù)據(jù)是真實(shí)的行情數(shù)據(jù),只是時(shí)間上比真實(shí)的行情會(huì)有延遲30秒左右(SIMNOW從交易所接收后轉(zhuǎn)發(fā)出來(lái)的)。

(2)非交易時(shí)段地址,這時(shí)的數(shù)據(jù)是歷史行情的播放,比如昨天的數(shù)據(jù)之類的,可以用來(lái)做程序調(diào)試。

?

建議選擇申請(qǐng)那個(gè)7x24行情的賬戶,便于開發(fā)調(diào)試。

?

開發(fā)步驟

工程總覽

?

其中,

?

  • CTP的API文件配置到工程
  • CustomMdSpi.h,CustomMdSpi.cpp是派生的行情回調(diào)類
  • CustomTradeSpi.h,CustomTradeSpi.cpp是派生的交易回調(diào)類
  • TickToKlineHelper.h,TickToKlineHelper.cpp是處理時(shí)序數(shù)據(jù),轉(zhuǎn)換成K線的類
  • StrategyTrade.h,StrategyTrade.cpp是策略類
  • main.cpp是程序的入口

一個(gè)簡(jiǎn)單的程序化交易系統(tǒng)需要完成的業(yè)務(wù)可以劃分為:
1.基本操作,比如登錄,訂閱等;
2.行情操作,比如對(duì)行情數(shù)據(jù)的接收,存儲(chǔ)等
3.訂單操作,比如報(bào)單;對(duì)報(bào)單,成交狀況的查詢;報(bào)單,成交狀況的私有回報(bào)等。
4.數(shù)據(jù)監(jiān)聽和處理操作,比如接收到新數(shù)據(jù)之后的統(tǒng)計(jì)處理,滿足統(tǒng)計(jì)條件后的報(bào)單處理(其實(shí)這里就是我們的策略所在)

?

導(dǎo)入CTP接口庫(kù)

visual studio創(chuàng)建工程后,首先需要將ctp的頭文件以及鏈接庫(kù)(lib和dll)目錄配置到工程

?

?

?

  • // 鏈接庫(kù)
  • #pragma comment (lib, "thostmduserapi.lib")
  • #pragma comment (lib, "thosttraderapi.lib")
  • ?

    ?

    全局參數(shù)

    連接到交易所,需要配置經(jīng)紀(jì)商代碼、帳戶名、密碼以及訂閱合約和買賣合約的相關(guān)參數(shù)

  • // ---- 全局變量 ---- //
  • // 公共參數(shù)
  • TThostFtdcBrokerIDType gBrokerID = "9999"; // 模擬經(jīng)紀(jì)商代碼
  • TThostFtdcInvestorIDType gInvesterID = ""; // 投資者賬戶名
  • TThostFtdcPasswordType gInvesterPassword = ""; // 投資者密碼
  • // 行情參數(shù)
  • CThostFtdcMdApi *g_pMdUserApi = nullptr; // 行情指針
  • char gMdFrontAddr[] = "tcp://180.168.146.187:10010"; // 模擬行情前置地址
  • char *g_pInstrumentID[] = {"TF1706", "zn1705", "cs1801", "CF705"}; // 行情合約代碼列表,中、上、大、鄭交易所各選一種
  • int instrumentNum = 4; // 行情合約訂閱數(shù)量
  • unordered_map<string, TickToKlineHelper> g_KlineHash; // 不同合約的k線存儲(chǔ)表
  • // 交易參數(shù)
  • CThostFtdcTraderApi *g_pTradeUserApi = nullptr; // 交易指針
  • char gTradeFrontAddr[] = "tcp://180.168.146.187:10001"; // 模擬交易前置地址
  • TThostFtdcInstrumentIDType g_pTradeInstrumentID = "m1709"; // 所交易的合約代碼
  • TThostFtdcDirectionType gTradeDirection = THOST_FTDC_D_Sell; // 買賣方向
  • TThostFtdcPriceType gLimitPrice = 2818; // 交易價(jià)格

  • 這里只是簡(jiǎn)單的寫一下,真實(shí)完整的交易系統(tǒng)中,一般用配置文件,有用戶去定制

    ?

    行情回調(diào)類

    繼承CThostFtdcMdSpi實(shí)現(xiàn)自己的行情回調(diào)類CustomMdSpi,在系統(tǒng)運(yùn)行時(shí)這些重寫的函數(shù)會(huì)被CTP的系統(tǒng)api回調(diào)從而實(shí)現(xiàn)個(gè)性化行情

    CustomMdSpi頭文件

    ?

  • #pragma once
  • // ---- 派生的行情類 ---- //
  • #include <vector>
  • #include "CTP_API/ThostFtdcMdApi.h"
  • class CustomMdSpi: public CThostFtdcMdSpi
  • {
  • // ---- 繼承自CTP父類的回調(diào)接口并實(shí)現(xiàn) ---- //
  • public:
  • ///當(dāng)客戶端與交易后臺(tái)建立起通信連接時(shí)(還未登錄前),該方法被調(diào)用。
  • void OnFrontConnected();
  • ///當(dāng)客戶端與交易后臺(tái)通信連接斷開時(shí),該方法被調(diào)用。當(dāng)發(fā)生這個(gè)情況后,API會(huì)自動(dòng)重新連接,客戶端可不做處理。
  • ///@param nReason 錯(cuò)誤原因
  • /// 0x1001 網(wǎng)絡(luò)讀失敗
  • /// 0x1002 網(wǎng)絡(luò)寫失敗
  • /// 0x2001 接收心跳超時(shí)
  • /// 0x2002 發(fā)送心跳失敗
  • /// 0x2003 收到錯(cuò)誤報(bào)文
  • void OnFrontDisconnected(int nReason);
  • ///心跳超時(shí)警告。當(dāng)長(zhǎng)時(shí)間未收到報(bào)文時(shí),該方法被調(diào)用。
  • ///@param nTimeLapse 距離上次接收?qǐng)?bào)文的時(shí)間
  • void OnHeartBeatWarning(int nTimeLapse);
  • ///登錄請(qǐng)求響應(yīng)
  • void OnRspUserLogin(CThostFtdcRspUserLoginField *pRspUserLogin, CThostFtdcRspInfoField *pRspInfo, int nRequestID, bool bIsLast);
  • ///登出請(qǐng)求響應(yīng)
  • void OnRspUserLogout(CThostFtdcUserLogoutField *pUserLogout, CThostFtdcRspInfoField *pRspInfo, int nRequestID, bool bIsLast);
  • ///錯(cuò)誤應(yīng)答
  • void OnRspError(CThostFtdcRspInfoField *pRspInfo, int nRequestID, bool bIsLast);
  • ///訂閱行情應(yīng)答
  • void OnRspSubMarketData(CThostFtdcSpecificInstrumentField *pSpecificInstrument, CThostFtdcRspInfoField *pRspInfo, int nRequestID, bool bIsLast);
  • ///取消訂閱行情應(yīng)答
  • void OnRspUnSubMarketData(CThostFtdcSpecificInstrumentField *pSpecificInstrument, CThostFtdcRspInfoField *pRspInfo, int nRequestID, bool bIsLast);
  • ///訂閱詢價(jià)應(yīng)答
  • void OnRspSubForQuoteRsp(CThostFtdcSpecificInstrumentField *pSpecificInstrument, CThostFtdcRspInfoField *pRspInfo, int nRequestID, bool bIsLast);
  • ///取消訂閱詢價(jià)應(yīng)答
  • void OnRspUnSubForQuoteRsp(CThostFtdcSpecificInstrumentField *pSpecificInstrument, CThostFtdcRspInfoField *pRspInfo, int nRequestID, bool bIsLast);
  • ///深度行情通知
  • void OnRtnDepthMarketData(CThostFtdcDepthMarketDataField *pDepthMarketData);
  • ///詢價(jià)通知
  • void OnRtnForQuoteRsp(CThostFtdcForQuoteRspField *pForQuoteRsp);
  • };
  • ?

    都是重寫回調(diào)函數(shù)

    連接應(yīng)答

    ?

  • // 連接成功應(yīng)答
  • void CustomMdSpi::OnFrontConnected()
  • {
  • std::cout << "=====建立網(wǎng)絡(luò)連接成功=====" << std::endl;
  • // 開始登錄
  • CThostFtdcReqUserLoginField loginReq;
  • memset(&loginReq, 0, sizeof(loginReq));
  • strcpy(loginReq.BrokerID, gBrokerID);
  • strcpy(loginReq.UserID, gInvesterID);
  • strcpy(loginReq.Password, gInvesterPassword);
  • static int requestID = 0; // 請(qǐng)求編號(hào)
  • int rt = g_pMdUserApi->ReqUserLogin(&loginReq, requestID);
  • if (!rt)
  • std::cout << ">>>>>>發(fā)送登錄請(qǐng)求成功" << std::endl;
  • else
  • std::cerr << "--->>>發(fā)送登錄請(qǐng)求失敗" << std::endl;
  • }
  • ?

    登錄應(yīng)答

    ?

  • // 登錄應(yīng)答
  • void CustomMdSpi::OnRspUserLogin(
  • CThostFtdcRspUserLoginField *pRspUserLogin,
  • CThostFtdcRspInfoField *pRspInfo,
  • int nRequestID,
  • bool bIsLast)
  • {
  • bool bResult = pRspInfo && (pRspInfo->ErrorID != 0);
  • if (!bResult)
  • {
  • std::cout << "=====賬戶登錄成功=====" << std::endl;
  • std::cout << "交易日: " << pRspUserLogin->TradingDay << std::endl;
  • std::cout << "登錄時(shí)間: " << pRspUserLogin->LoginTime << std::endl;
  • std::cout << "經(jīng)紀(jì)商: " << pRspUserLogin->BrokerID << std::endl;
  • std::cout << "帳戶名: " << pRspUserLogin->UserID << std::endl;
  • // 開始訂閱行情
  • int rt = g_pMdUserApi->SubscribeMarketData(g_pInstrumentID, instrumentNum);
  • if (!rt)
  • std::cout << ">>>>>>發(fā)送訂閱行情請(qǐng)求成功" << std::endl;
  • else
  • std::cerr << "--->>>發(fā)送訂閱行情請(qǐng)求失敗" << std::endl;
  • }
  • else
  • std::cerr << "返回錯(cuò)誤--->>> ErrorID=" << pRspInfo->ErrorID << ", ErrorMsg=" << pRspInfo->ErrorMsg << std::endl;
  • }
  • ?

    訂閱行情應(yīng)答

    ?

  • // 訂閱行情應(yīng)答
  • void CustomMdSpi::OnRspSubMarketData(
  • CThostFtdcSpecificInstrumentField *pSpecificInstrument,
  • CThostFtdcRspInfoField *pRspInfo,
  • int nRequestID,
  • bool bIsLast)
  • {
  • bool bResult = pRspInfo && (pRspInfo->ErrorID != 0);
  • if (!bResult)
  • {
  • std::cout << "=====訂閱行情成功=====" << std::endl;
  • std::cout << "合約代碼: " << pSpecificInstrument->InstrumentID << std::endl;
  • // 如果需要存入文件或者數(shù)據(jù)庫(kù),在這里創(chuàng)建表頭,不同的合約單獨(dú)存儲(chǔ)
  • char filePath[100] = {'\0'};
  • sprintf(filePath, "%s_market_data.csv", pSpecificInstrument->InstrumentID);
  • std::ofstream outFile;
  • outFile.open(filePath, std::ios::out); // 新開文件
  • outFile << "合約代碼" << ","
  • << "更新時(shí)間" << ","
  • << "最新價(jià)" << ","
  • << "成交量" << ","
  • << "買價(jià)一" << ","
  • << "買量一" << ","
  • << "賣價(jià)一" << ","
  • << "賣量一" << ","
  • << "持倉(cāng)量" << ","
  • << "換手率"
  • << std::endl;
  • outFile.close();
  • }
  • else
  • std::cerr << "返回錯(cuò)誤--->>> ErrorID=" << pRspInfo->ErrorID << ", ErrorMsg=" << pRspInfo->ErrorMsg << std::endl;
  • }
  • ?

    • 因?yàn)槭钱惒浇涌?#xff0c;這里連接、登錄、訂閱行情是一步套一步來(lái)調(diào)用的,在運(yùn)行過(guò)程中,會(huì)啟動(dòng)一個(gè)行情線程,交易所每500ms會(huì)推送一個(gè)訂閱的行情tick數(shù)據(jù),因此,某些接口會(huì)被連續(xù)間隔調(diào)用,直到連接關(guān)閉
    • 收到行情后除了存在內(nèi)存,也可以用文本文件或者數(shù)據(jù)庫(kù)等形式存儲(chǔ)起來(lái),在這里創(chuàng)建初始文件或者建庫(kù)

    深度行情通知

  • // 行情詳情通知
  • void CustomMdSpi::OnRtnDepthMarketData(CThostFtdcDepthMarketDataField *pDepthMarketData)
  • {
  • // 打印行情,字段較多,截取部分
  • std::cout << "=====獲得深度行情=====" << std::endl;
  • std::cout << "交易日: " << pDepthMarketData->TradingDay << std::endl;
  • std::cout << "交易所代碼: " << pDepthMarketData->ExchangeID << std::endl;
  • std::cout << "合約代碼: " << pDepthMarketData->InstrumentID << std::endl;
  • std::cout << "合約在交易所的代碼: " << pDepthMarketData->ExchangeInstID << std::endl;
  • std::cout << "最新價(jià): " << pDepthMarketData->LastPrice << std::endl;
  • std::cout << "數(shù)量: " << pDepthMarketData->Volume << std::endl;
  • // 如果只獲取某一個(gè)合約行情,可以逐tick地存入文件或數(shù)據(jù)庫(kù)
  • char filePath[100] = {'\0'};
  • sprintf(filePath, "%s_market_data.csv", pDepthMarketData->InstrumentID);
  • std::ofstream outFile;
  • outFile.open(filePath, std::ios::app); // 文件追加寫入
  • outFile << pDepthMarketData->InstrumentID << ","
  • << pDepthMarketData->UpdateTime << "." << pDepthMarketData->UpdateMillisec << ","
  • << pDepthMarketData->LastPrice << ","
  • << pDepthMarketData->Volume << ","
  • << pDepthMarketData->BidPrice1 << ","
  • << pDepthMarketData->BidVolume1 << ","
  • << pDepthMarketData->AskPrice1 << ","
  • << pDepthMarketData->AskVolume1 << ","
  • << pDepthMarketData->OpenInterest << ","
  • << pDepthMarketData->Turnover << std::endl;
  • outFile.close();
  • // 計(jì)算實(shí)時(shí)k線
  • std::string instrumentKey = std::string(pDepthMarketData->InstrumentID);
  • if (g_KlineHash.find(instrumentKey) == g_KlineHash.end())
  • g_KlineHash[instrumentKey] = TickToKlineHelper();
  • g_KlineHash[instrumentKey].KLineFromRealtimeData(pDepthMarketData);
  • // 取消訂閱行情
  • //int rt = g_pMdUserApi->UnSubscribeMarketData(g_pInstrumentID, instrumentNum);
  • //if (!rt)
  • // std::cout << ">>>>>>發(fā)送取消訂閱行情請(qǐng)求成功" << std::endl;
  • //else
  • // std::cerr << "--->>>發(fā)送取消訂閱行情請(qǐng)求失敗" << std::endl;
  • }
    • 每個(gè)tick世間節(jié)點(diǎn)系統(tǒng)都會(huì)調(diào)用這個(gè)函數(shù),推送具體的行情截面數(shù)據(jù)
    • 可以在此處將行情寫到本地,或者做一些數(shù)據(jù)處理(例如實(shí)時(shí)K線計(jì)算,判斷是否觸發(fā)策略等)

    ?

    交易回調(diào)類

    同理,也需要繼承CThostFtdcTraderSpi來(lái)實(shí)現(xiàn)自己的CustomTradeSpi類,用于交易下單、報(bào)單等操作的回調(diào)

    CustomTradeSpi頭文件

    ?

  • #pragma once
  • // ---- 派生的交易類 ---- //
  • #include "CTP_API/ThostFtdcTraderApi.h"
  • class CustomTradeSpi : public CThostFtdcTraderSpi
  • {
  • // ---- ctp_api部分回調(diào)接口 ---- //
  • public:
  • ///當(dāng)客戶端與交易后臺(tái)建立起通信連接時(shí)(還未登錄前),該方法被調(diào)用。
  • void OnFrontConnected();
  • ///登錄請(qǐng)求響應(yīng)
  • void OnRspUserLogin(CThostFtdcRspUserLoginField *pRspUserLogin, CThostFtdcRspInfoField *pRspInfo, int nRequestID, bool bIsLast);
  • ///錯(cuò)誤應(yīng)答
  • void OnRspError(CThostFtdcRspInfoField *pRspInfo, int nRequestID, bool bIsLast);
  • ///當(dāng)客戶端與交易后臺(tái)通信連接斷開時(shí),該方法被調(diào)用。當(dāng)發(fā)生這個(gè)情況后,API會(huì)自動(dòng)重新連接,客戶端可不做處理。
  • void OnFrontDisconnected(int nReason);
  • ///心跳超時(shí)警告。當(dāng)長(zhǎng)時(shí)間未收到報(bào)文時(shí),該方法被調(diào)用。
  • void OnHeartBeatWarning(int nTimeLapse);
  • ///登出請(qǐng)求響應(yīng)
  • void OnRspUserLogout(CThostFtdcUserLogoutField *pUserLogout, CThostFtdcRspInfoField *pRspInfo, int nRequestID, bool bIsLast);
  • ///投資者結(jié)算結(jié)果確認(rèn)響應(yīng)
  • void OnRspSettlementInfoConfirm(CThostFtdcSettlementInfoConfirmField *pSettlementInfoConfirm, CThostFtdcRspInfoField *pRspInfo, int nRequestID, bool bIsLast);
  • ///請(qǐng)求查詢合約響應(yīng)
  • void OnRspQryInstrument(CThostFtdcInstrumentField *pInstrument, CThostFtdcRspInfoField *pRspInfo, int nRequestID, bool bIsLast);
  • ///請(qǐng)求查詢資金賬戶響應(yīng)
  • void OnRspQryTradingAccount(CThostFtdcTradingAccountField *pTradingAccount, CThostFtdcRspInfoField *pRspInfo, int nRequestID, bool bIsLast);
  • ///請(qǐng)求查詢投資者持倉(cāng)響應(yīng)
  • void OnRspQryInvestorPosition(CThostFtdcInvestorPositionField *pInvestorPosition, CThostFtdcRspInfoField *pRspInfo, int nRequestID, bool bIsLast);
  • ///報(bào)單錄入請(qǐng)求響應(yīng)
  • void OnRspOrderInsert(CThostFtdcInputOrderField *pInputOrder, CThostFtdcRspInfoField *pRspInfo, int nRequestID, bool bIsLast);
  • ///報(bào)單操作請(qǐng)求響應(yīng)
  • void OnRspOrderAction(CThostFtdcInputOrderActionField *pInputOrderAction, CThostFtdcRspInfoField *pRspInfo, int nRequestID, bool bIsLast);
  • ///報(bào)單通知
  • void OnRtnOrder(CThostFtdcOrderField *pOrder);
  • ///成交通知
  • void OnRtnTrade(CThostFtdcTradeField *pTrade);
  • // ---- 自定義函數(shù) ---- //
  • public:
  • bool loginFlag; // 登陸成功的標(biāo)識(shí)
  • void reqOrderInsert(
  • TThostFtdcInstrumentIDType instrumentID,
  • TThostFtdcPriceType price,
  • TThostFtdcVolumeType volume,
  • TThostFtdcDirectionType direction); // 個(gè)性化報(bào)單錄入,外部調(diào)用
  • private:
  • void reqUserLogin(); // 登錄請(qǐng)求
  • void reqUserLogout(); // 登出請(qǐng)求
  • void reqSettlementInfoConfirm(); // 投資者結(jié)果確認(rèn)
  • void reqQueryInstrument(); // 請(qǐng)求查詢合約
  • void reqQueryTradingAccount(); // 請(qǐng)求查詢資金帳戶
  • void reqQueryInvestorPosition(); // 請(qǐng)求查詢投資者持倉(cāng)
  • void reqOrderInsert(); // 請(qǐng)求報(bào)單錄入
  • void reqOrderAction(CThostFtdcOrderField *pOrder); // 請(qǐng)求報(bào)單操作
  • bool isErrorRspInfo(CThostFtdcRspInfoField *pRspInfo); // 是否收到錯(cuò)誤信息
  • bool isMyOrder(CThostFtdcOrderField *pOrder); // 是否我的報(bào)單回報(bào)
  • bool isTradingOrder(CThostFtdcOrderField *pOrder); // 是否正在交易的報(bào)單
  • };
  • ?

    ?

    除了重寫的基類函數(shù),還自己封裝一些主動(dòng)調(diào)用的操作函數(shù),比如登入登出、下單報(bào)單、查詢報(bào)單等

    ?

    ?

    ?

    登錄應(yīng)答

    ?

  • void CustomTradeSpi::OnRspUserLogin(
  • CThostFtdcRspUserLoginField *pRspUserLogin,
  • CThostFtdcRspInfoField *pRspInfo,
  • int nRequestID,
  • bool bIsLast)
  • {
  • if (!isErrorRspInfo(pRspInfo))
  • {
  • std::cout << "=====賬戶登錄成功=====" << std::endl;
  • loginFlag = true;
  • std::cout << "交易日: " << pRspUserLogin->TradingDay << std::endl;
  • std::cout << "登錄時(shí)間: " << pRspUserLogin->LoginTime << std::endl;
  • std::cout << "經(jīng)紀(jì)商: " << pRspUserLogin->BrokerID << std::endl;
  • std::cout << "帳戶名: " << pRspUserLogin->UserID << std::endl;
  • // 保存會(huì)話參數(shù)
  • trade_front_id = pRspUserLogin->FrontID;
  • session_id = pRspUserLogin->SessionID;
  • strcpy(order_ref, pRspUserLogin->MaxOrderRef);
  • // 投資者結(jié)算結(jié)果確認(rèn)
  • reqSettlementInfoConfirm();
  • }
  • }
  • 查詢投資者結(jié)算結(jié)果應(yīng)答

    ?

    ?

  • void CustomTradeSpi::OnRspSettlementInfoConfirm(
  • CThostFtdcSettlementInfoConfirmField *pSettlementInfoConfirm,
  • CThostFtdcRspInfoField *pRspInfo,
  • int nRequestID,
  • bool bIsLast)
  • {
  • if (!isErrorRspInfo(pRspInfo))
  • {
  • std::cout << "=====投資者結(jié)算結(jié)果確認(rèn)成功=====" << std::endl;
  • std::cout << "確認(rèn)日期: " << pSettlementInfoConfirm->ConfirmDate << std::endl;
  • std::cout << "確認(rèn)時(shí)間: " << pSettlementInfoConfirm->ConfirmTime << std::endl;
  • // 請(qǐng)求查詢合約
  • reqQueryInstrument();
  • }
  • }
  • 查詢合約應(yīng)答

    ?

    ?

  • void CustomTradeSpi::OnRspQryInstrument(
  • CThostFtdcInstrumentField *pInstrument,
  • CThostFtdcRspInfoField *pRspInfo,
  • int nRequestID,
  • bool bIsLast)
  • {
  • if (!isErrorRspInfo(pRspInfo))
  • {
  • std::cout << "=====查詢合約結(jié)果成功=====" << std::endl;
  • std::cout << "交易所代碼: " << pInstrument->ExchangeID << std::endl;
  • std::cout << "合約代碼: " << pInstrument->InstrumentID << std::endl;
  • std::cout << "合約在交易所的代碼: " << pInstrument->ExchangeInstID << std::endl;
  • std::cout << "執(zhí)行價(jià): " << pInstrument->StrikePrice << std::endl;
  • std::cout << "到期日: " << pInstrument->EndDelivDate << std::endl;
  • std::cout << "當(dāng)前交易狀態(tài): " << pInstrument->IsTrading << std::endl;
  • // 請(qǐng)求查詢投資者資金賬戶
  • reqQueryTradingAccount();
  • }
  • }
  • 查詢投資者資金帳戶應(yīng)答

    ?

    ?

  • void CustomTradeSpi::OnRspQryTradingAccount(
  • CThostFtdcTradingAccountField *pTradingAccount,
  • CThostFtdcRspInfoField *pRspInfo,
  • int nRequestID,
  • bool bIsLast)
  • {
  • if (!isErrorRspInfo(pRspInfo))
  • {
  • std::cout << "=====查詢投資者資金賬戶成功=====" << std::endl;
  • std::cout << "投資者賬號(hào): " << pTradingAccount->AccountID << std::endl;
  • std::cout << "可用資金: " << pTradingAccount->Available << std::endl;
  • std::cout << "可取資金: " << pTradingAccount->WithdrawQuota << std::endl;
  • std::cout << "當(dāng)前保證金: " << pTradingAccount->CurrMargin << std::endl;
  • std::cout << "平倉(cāng)盈虧: " << pTradingAccount->CloseProfit << std::endl;
  • // 請(qǐng)求查詢投資者持倉(cāng)
  • reqQueryInvestorPosition();
  • }
  • }
  • 查詢投資者持倉(cāng)應(yīng)答

    ?

    ?

  • void CustomTradeSpi::OnRspQryInvestorPosition(
  • CThostFtdcInvestorPositionField *pInvestorPosition,
  • CThostFtdcRspInfoField *pRspInfo,
  • int nRequestID,
  • bool bIsLast)
  • {
  • if (!isErrorRspInfo(pRspInfo))
  • {
  • std::cout << "=====查詢投資者持倉(cāng)成功=====" << std::endl;
  • if (pInvestorPosition)
  • {
  • std::cout << "合約代碼: " << pInvestorPosition->InstrumentID << std::endl;
  • std::cout << "開倉(cāng)價(jià)格: " << pInvestorPosition->OpenAmount << std::endl;
  • std::cout << "開倉(cāng)量: " << pInvestorPosition->OpenVolume << std::endl;
  • std::cout << "開倉(cāng)方向: " << pInvestorPosition->PosiDirection << std::endl;
  • std::cout << "占用保證金:" << pInvestorPosition->UseMargin << std::endl;
  • }
  • else
  • std::cout << "----->該合約未持倉(cāng)" << std::endl;
  • // 報(bào)單錄入請(qǐng)求(這里是一部接口,此處是按順序執(zhí)行)
  • /*if (loginFlag)
  • reqOrderInsert();*/
  • if (loginFlag)
  • reqOrderInsert(g_pTradeInstrumentID, gLimitPrice, 1, gTradeDirection); // 自定義一筆交易
  • // 策略交易
  • /*std::cout << "=====開始進(jìn)入策略交易=====" << std::endl;
  • while (loginFlag)
  • StrategyCheckAndTrade(g_pTradeInstrumentID, this);*/
  • }
  • }
  • 這里把下單錄入的操作放在了持倉(cāng)結(jié)果出來(lái)之后的回調(diào)里面,策略交易也簡(jiǎn)單的放在了這里,真實(shí)的情況下,應(yīng)該是由行情觸發(fā)某個(gè)策略條件開一個(gè)線程進(jìn)行策略交易

    ?

    下單操作

    ?

    ?

  • void CustomTradeSpi::reqOrderInsert(
  • TThostFtdcInstrumentIDType instrumentID,
  • TThostFtdcPriceType price,
  • TThostFtdcVolumeType volume,
  • TThostFtdcDirectionType direction)
  • {
  • CThostFtdcInputOrderField orderInsertReq;
  • memset(&orderInsertReq, 0, sizeof(orderInsertReq));
  • ///經(jīng)紀(jì)公司代碼
  • strcpy(orderInsertReq.BrokerID, gBrokerID);
  • ///投資者代碼
  • strcpy(orderInsertReq.InvestorID, gInvesterID);
  • ///合約代碼
  • strcpy(orderInsertReq.InstrumentID, instrumentID);
  • ///報(bào)單引用
  • strcpy(orderInsertReq.OrderRef, order_ref);
  • ///報(bào)單價(jià)格條件: 限價(jià)
  • orderInsertReq.OrderPriceType = THOST_FTDC_OPT_LimitPrice;
  • ///買賣方向:
  • orderInsertReq.Direction = direction;
  • ///組合開平標(biāo)志: 開倉(cāng)
  • orderInsertReq.CombOffsetFlag[0] = THOST_FTDC_OF_Open;
  • ///組合投機(jī)套保標(biāo)志
  • orderInsertReq.CombHedgeFlag[0] = THOST_FTDC_HF_Speculation;
  • ///價(jià)格
  • orderInsertReq.LimitPrice = price;
  • ///數(shù)量:1
  • orderInsertReq.VolumeTotalOriginal = volume;
  • ///有效期類型: 當(dāng)日有效
  • orderInsertReq.TimeCondition = THOST_FTDC_TC_GFD;
  • ///成交量類型: 任何數(shù)量
  • orderInsertReq.VolumeCondition = THOST_FTDC_VC_AV;
  • ///最小成交量: 1
  • orderInsertReq.MinVolume = 1;
  • ///觸發(fā)條件: 立即
  • orderInsertReq.ContingentCondition = THOST_FTDC_CC_Immediately;
  • ///強(qiáng)平原因: 非強(qiáng)平
  • orderInsertReq.ForceCloseReason = THOST_FTDC_FCC_NotForceClose;
  • ///自動(dòng)掛起標(biāo)志: 否
  • orderInsertReq.IsAutoSuspend = 0;
  • ///用戶強(qiáng)評(píng)標(biāo)志: 否
  • orderInsertReq.UserForceClose = 0;
  • static int requestID = 0; // 請(qǐng)求編號(hào)
  • int rt = g_pTradeUserApi->ReqOrderInsert(&orderInsertReq, ++requestID);
  • if (!rt)
  • std::cout << ">>>>>>發(fā)送報(bào)單錄入請(qǐng)求成功" << std::endl;
  • else
  • std::cerr << "--->>>發(fā)送報(bào)單錄入請(qǐng)求失敗" << std::endl;
  • }
  • 通過(guò)重載寫了兩個(gè)函數(shù),一個(gè)是用默認(rèn)參數(shù)下單,一個(gè)可以傳參下單,比如設(shè)定合約代碼、價(jià)格、數(shù)量等

    ?

    報(bào)單操作

    ?

  • void CustomTradeSpi::reqOrderAction(CThostFtdcOrderField *pOrder)
  • {
  • static bool orderActionSentFlag = false; // 是否發(fā)送了報(bào)單
  • if (orderActionSentFlag)
  • return;
  • CThostFtdcInputOrderActionField orderActionReq;
  • memset(&orderActionReq, 0, sizeof(orderActionReq));
  • ///經(jīng)紀(jì)公司代碼
  • strcpy(orderActionReq.BrokerID, pOrder->BrokerID);
  • ///投資者代碼
  • strcpy(orderActionReq.InvestorID, pOrder->InvestorID);
  • ///報(bào)單操作引用
  • // TThostFtdcOrderActionRefType OrderActionRef;
  • ///報(bào)單引用
  • strcpy(orderActionReq.OrderRef, pOrder->OrderRef);
  • ///請(qǐng)求編號(hào)
  • // TThostFtdcRequestIDType RequestID;
  • ///前置編號(hào)
  • orderActionReq.FrontID = trade_front_id;
  • ///會(huì)話編號(hào)
  • orderActionReq.SessionID = session_id;
  • ///交易所代碼
  • // TThostFtdcExchangeIDType ExchangeID;
  • ///報(bào)單編號(hào)
  • // TThostFtdcOrderSysIDType OrderSysID;
  • ///操作標(biāo)志
  • orderActionReq.ActionFlag = THOST_FTDC_AF_Delete;
  • ///價(jià)格
  • // TThostFtdcPriceType LimitPrice;
  • ///數(shù)量變化
  • // TThostFtdcVolumeType VolumeChange;
  • ///用戶代碼
  • // TThostFtdcUserIDType UserID;
  • ///合約代碼
  • strcpy(orderActionReq.InstrumentID, pOrder->InstrumentID);
  • static int requestID = 0; // 請(qǐng)求編號(hào)
  • int rt = g_pTradeUserApi->ReqOrderAction(&orderActionReq, ++requestID);
  • if (!rt)
  • std::cout << ">>>>>>發(fā)送報(bào)單操作請(qǐng)求成功" << std::endl;
  • else
  • std::cerr << "--->>>發(fā)送報(bào)單操作請(qǐng)求失敗" << std::endl;
  • orderActionSentFlag = true;
  • }
  • ?

    主要是對(duì)于未成交的訂單進(jìn)行編輯或者撤銷操作

    ?

    ?

    報(bào)單應(yīng)答

    ?

  • void CustomTradeSpi::OnRtnOrder(CThostFtdcOrderField *pOrder)
  • {
  • char str[10];
  • sprintf(str, "%d", pOrder->OrderSubmitStatus);
  • int orderState = atoi(str) - 48; //報(bào)單狀態(tài)0=已經(jīng)提交,3=已經(jīng)接受
  • std::cout << "=====收到報(bào)單應(yīng)答=====" << std::endl;
  • if (isMyOrder(pOrder))
  • {
  • if (isTradingOrder(pOrder))
  • {
  • std::cout << "--->>> 等待成交中!" << std::endl;
  • //reqOrderAction(pOrder); // 這里可以撤單
  • //reqUserLogout(); // 登出測(cè)試
  • }
  • else if (pOrder->OrderStatus == THOST_FTDC_OST_Canceled)
  • std::cout << "--->>> 撤單成功!" << std::endl;
  • }
  • }
  • void CustomTradeSpi::OnRtnTrade(CThostFtdcTradeField *pTrade)
  • {
  • std::cout << "=====報(bào)單成功成交=====" << std::endl;
  • std::cout << "成交時(shí)間: " << pTrade->TradeTime << std::endl;
  • std::cout << "合約代碼: " << pTrade->InstrumentID << std::endl;
  • std::cout << "成交價(jià)格: " << pTrade->Price << std::endl;
  • std::cout << "成交量: " << pTrade->Volume << std::endl;
  • std::cout << "開平倉(cāng)方向: " << pTrade->Direction << std::endl;
  • }
  • 等待成交進(jìn)行輪詢可以選擇報(bào)單操作,成交完成后的應(yīng)答

    ?

    時(shí)間序列轉(zhuǎn)K線

    從交易拿到的tick數(shù)據(jù)是時(shí)間序列數(shù)據(jù),在證券交易中其實(shí)還需要根據(jù)時(shí)間序列算出一些技術(shù)指標(biāo)數(shù)據(jù),例如MACD,KDJ、K線等,這里簡(jiǎn)單地對(duì)數(shù)據(jù)做一下處理,寫一個(gè)TickToKlineHelper將時(shí)間序列專程K線

    ?

    ?

    K線數(shù)據(jù)結(jié)構(gòu)

    ?

  • // k線數(shù)據(jù)結(jié)構(gòu)
  • struct KLineDataType
  • {
  • double open_price; // 開
  • double high_price; // 高
  • double low_price; // 低
  • double close_price; // 收
  • int volume; // 量
  • };

  • 轉(zhuǎn)換函數(shù)

    ?

    ?

  • void TickToKlineHelper::KLineFromLocalData(const std::string &sFilePath, const std::string &dFilePath)
  • {
  • // 先清理殘留數(shù)據(jù)
  • m_priceVec.clear();
  • m_volumeVec.clear();
  • m_KLineDataArray.clear();
  • std::cout << "開始轉(zhuǎn)換tick到k線..." << std::endl;
  • // 默認(rèn)讀取的tick數(shù)據(jù)表有4個(gè)字段:合約代碼、更新時(shí)間、最新價(jià)、成交量
  • std::ifstream srcInFile;
  • std::ofstream dstOutFile;
  • srcInFile.open(sFilePath, std::ios::in);
  • dstOutFile.open(dFilePath, std::ios::out);
  • dstOutFile << "開盤價(jià)" << ','
  • << "最高價(jià)" << ','
  • << "最低價(jià)" << ','
  • << "收盤價(jià)" << ','
  • << "成交量" << std::endl;
  • // 一遍解析文件一邊計(jì)算k線數(shù)據(jù),1分鐘k線每次讀取60 * 2 = 120行數(shù)據(jù)
  • std::string lineStr;
  • bool isFirstLine = true;
  • while (std::getline(srcInFile, lineStr))
  • {
  • if (isFirstLine)
  • {
  • // 跳過(guò)第一行表頭
  • isFirstLine = false;
  • continue;
  • }
  • std::istringstream ss(lineStr);
  • std::string fieldStr;
  • int count = 4;
  • while (std::getline(ss, fieldStr, ','))
  • {
  • count--;
  • if (count == 1)
  • m_priceVec.push_back(std::atof(fieldStr.c_str()));
  • else if (count == 0)
  • {
  • m_volumeVec.push_back(std::atoi(fieldStr.c_str()));
  • break;
  • }
  • }
  • // 計(jì)算k線
  • if (m_priceVec.size() == kDataLineNum)
  • {
  • KLineDataType k_line_data;
  • k_line_data.open_price = m_priceVec.front();
  • k_line_data.high_price = *std::max_element(m_priceVec.cbegin(), m_priceVec.cend());
  • k_line_data.low_price = *std::min_element(m_priceVec.cbegin(), m_priceVec.cend());
  • k_line_data.close_price = m_priceVec.back();
  • // 成交量的真實(shí)的算法是當(dāng)前區(qū)間最后一個(gè)成交量減去上去一個(gè)區(qū)間最后一個(gè)成交量
  • k_line_data.volume = m_volumeVec.back() - m_volumeVec.front();
  • //m_KLineDataArray.push_back(k_line_data); // 此處可以存到內(nèi)存
  • dstOutFile << k_line_data.open_price << ','
  • << k_line_data.high_price << ','
  • << k_line_data.low_price << ','
  • << k_line_data.close_price << ','
  • << k_line_data.volume << std::endl;
  • m_priceVec.clear();
  • m_volumeVec.clear();
  • }
  • }
  • srcInFile.close();
  • dstOutFile.close();
  • std::cout << "k線生成成功" << std::endl;
  • }
  • void TickToKlineHelper::KLineFromRealtimeData(CThostFtdcDepthMarketDataField *pDepthMarketData)
  • {
  • m_priceVec.push_back(pDepthMarketData->LastPrice);
  • m_volumeVec.push_back(pDepthMarketData->Volume);
  • if (m_priceVec.size() == kDataLineNum)
  • {
  • KLineDataType k_line_data;
  • k_line_data.open_price = m_priceVec.front();
  • k_line_data.high_price = *std::max_element(m_priceVec.cbegin(), m_priceVec.cend());
  • k_line_data.low_price = *std::min_element(m_priceVec.cbegin(), m_priceVec.cend());
  • k_line_data.close_price = m_priceVec.back();
  • // 成交量的真實(shí)的算法是當(dāng)前區(qū)間最后一個(gè)成交量減去上去一個(gè)區(qū)間最后一個(gè)成交量
  • k_line_data.volume = m_volumeVec.back() - m_volumeVec.front();
  • m_KLineDataArray.push_back(k_line_data); // 此處可以存到內(nèi)存
  • m_priceVec.clear();
  • m_volumeVec.clear();
  • }
  • }
  • ?

    • 可以從本地文件中讀取行情數(shù)據(jù),進(jìn)行離線轉(zhuǎn)換,也可以在接受到行情時(shí)進(jìn)行實(shí)時(shí)計(jì)算
    • 基本思想是,針對(duì)每個(gè)合約代碼,建立字典,維持一個(gè)行情數(shù)組,當(dāng)時(shí)間間隔達(dá)到要求(例如分鐘、分時(shí)、分日)時(shí)計(jì)算該時(shí)段的開、高、低、收、成交量等數(shù)據(jù)存入K線數(shù)組
    • 最低時(shí)間單位的K線計(jì)算出來(lái)之后,高時(shí)間間隔的K線數(shù)據(jù)可以根據(jù)低時(shí)間間隔的K線計(jì)算出來(lái)(例如,算出了分鐘K,那么分時(shí)K就根據(jù)分鐘K來(lái)算)
    • 本例子中只是實(shí)現(xiàn)了一個(gè)大概的原理,非常不精確,僅供參考

    策略交易

    量化交易系統(tǒng)最終是需要將編寫的策略代碼掛載到系統(tǒng)中進(jìn)行策略交易的,這里做了一個(gè)簡(jiǎn)單的實(shí)現(xiàn)

    StrategyTrade.h

  • #pragma once
  • // ---- 簡(jiǎn)單策略交易的類 ---- //
  • #include <functional>
  • #include "CTP_API/ThostFtdcUserApiStruct.h"
  • #include "TickToKlineHelper.h"
  • #include "CustomTradeSpi.h"
  • typedef void(*reqOrderInsertFun)(
  • TThostFtdcInstrumentIDType instrumentID,
  • TThostFtdcPriceType price,
  • TThostFtdcVolumeType volume,
  • TThostFtdcDirectionType direction);
  • using ReqOrderInsertFunctionType = std::function<
  • void(TThostFtdcInstrumentIDType instrumentID,
  • TThostFtdcPriceType price,
  • TThostFtdcVolumeType volume,
  • TThostFtdcDirectionType direction)>;
  • void StrategyCheckAndTrade(TThostFtdcInstrumentIDType instrumentID, CustomTradeSpi *customTradeSpi);

  • StrategyTrade.cpp

  • #include <vector>
  • #include <string>
  • #include <unordered_map>
  • #include <thread>
  • #include <mutex>
  • #include "StrategyTrade.h"
  • #include "CustomTradeSpi.h"
  • extern std::unordered_map<std::string, TickToKlineHelper> g_KlineHash;
  • // 線程互斥量
  • std::mutex marketDataMutex;
  • void StrategyCheckAndTrade(TThostFtdcInstrumentIDType instrumentID, CustomTradeSpi *customTradeSpi)
  • {
  • // 加鎖
  • std::lock_guard<std::mutex> lk(marketDataMutex);
  • TickToKlineHelper tickToKlineObject = g_KlineHash.at(std::string(instrumentID));
  • // 策略
  • std::vector<double> priceVec = tickToKlineObject.m_priceVec;
  • if (priceVec.size() >= 3)
  • {
  • int len = priceVec.size();
  • // 最后連續(xù)三個(gè)上漲就買開倉(cāng),反之就賣開倉(cāng),這里暫時(shí)用最后一個(gè)價(jià)格下單
  • if (priceVec[len - 1] > priceVec[len - 2] && priceVec[len - 2] > priceVec[len - 3])
  • customTradeSpi->reqOrderInsert(instrumentID, priceVec[len - 1], 1, THOST_FTDC_D_Buy);
  • else if (priceVec[len - 1] < priceVec[len - 2] && priceVec[len - 2] < priceVec[len - 3])
  • customTradeSpi->reqOrderInsert(instrumentID, priceVec[len - 1], 1, THOST_FTDC_D_Buy);
  • }
  • }
    • 基本思想,針對(duì)指定合約,判斷如果連續(xù)三個(gè)上漲就買開倉(cāng),連續(xù)三個(gè)下跌就賣開倉(cāng),價(jià)格都是用最新價(jià)
    • 因?yàn)樾星楹徒灰资欠珠_的線程,涉及到線程競(jìng)爭(zhēng),所以在實(shí)際下單時(shí)需要加入互斥鎖,線程同步
    • 策略如何被行情觸發(fā)然后交易其實(shí)需要用事件驅(qū)動(dòng)來(lái)做的,這里沒(méi)有實(shí)現(xiàn)T_T

    入口

    main.cpp

  • int main()
  • {
  • // 賬號(hào)密碼
  • cout << "請(qǐng)輸入賬號(hào): ";
  • scanf("%s", gInvesterID);
  • cout << "請(qǐng)輸入密碼: ";
  • scanf("%s", gInvesterPassword);
  • // 初始化行情線程
  • cout << "初始化行情..." << endl;
  • g_pMdUserApi = CThostFtdcMdApi::CreateFtdcMdApi(); // 創(chuàng)建行情實(shí)例
  • CThostFtdcMdSpi *pMdUserSpi = new CustomMdSpi; // 創(chuàng)建行情回調(diào)實(shí)例
  • g_pMdUserApi->RegisterSpi(pMdUserSpi); // 注冊(cè)事件類
  • g_pMdUserApi->RegisterFront(gMdFrontAddr); // 設(shè)置行情前置地址
  • g_pMdUserApi->Init(); // 連接運(yùn)行
  • // 初始化交易線程
  • cout << "初始化交易..." << endl;
  • g_pTradeUserApi = CThostFtdcTraderApi::CreateFtdcTraderApi(); // 創(chuàng)建交易實(shí)例
  • //CThostFtdcTraderSpi *pTradeSpi = new CustomTradeSpi;
  • CustomTradeSpi *pTradeSpi = new CustomTradeSpi; // 創(chuàng)建交易回調(diào)實(shí)例
  • g_pTradeUserApi->RegisterSpi(pTradeSpi); // 注冊(cè)事件類
  • g_pTradeUserApi->SubscribePublicTopic(THOST_TERT_RESTART); // 訂閱公共流
  • g_pTradeUserApi->SubscribePrivateTopic(THOST_TERT_RESTART); // 訂閱私有流
  • g_pTradeUserApi->RegisterFront(gTradeFrontAddr); // 設(shè)置交易前置地址
  • g_pTradeUserApi->Init(); // 連接運(yùn)行
  • // 等到線程退出
  • g_pMdUserApi->Join();
  • delete pMdUserSpi;
  • g_pMdUserApi->Release();
  • g_pTradeUserApi->Join();
  • delete pTradeSpi;
  • g_pTradeUserApi->Release();
  • // 轉(zhuǎn)換本地k線數(shù)據(jù)
  • //TickToKlineHelper tickToKlineHelper;
  • //tickToKlineHelper.KLineFromLocalData("market_data.csv", "K_line_data.csv");
  • getchar();
  • return 0;
  • }
    • CThostFtdcMdApi跟CustomMdSpi要建立關(guān)聯(lián),CThostFtdcTraderApi跟CustomTradeSpi建立關(guān)聯(lián),其實(shí)就是類似于函數(shù)注冊(cè)
    • 配置行情和交易地址
    • 行情和交易分別是不同的線程,注意線程同步
    • 記得內(nèi)存回收

    運(yùn)行結(jié)果

    行情

    應(yīng)答日志

    ?

    存成csv表格

    ?

    交易

    應(yīng)答日志

    ?

    ?

    K線數(shù)據(jù)

    ?

    ?

    ?

    ?

    報(bào)單情況

    用上期所的快期軟件,登錄上自己的賬號(hào)之后,從過(guò)程序下單,在這個(gè)界面里能看到實(shí)時(shí)的報(bào)單成交狀況

    ?

    ?

    源碼下載

    ?

    csdn:demo

    ?

    github:demo

    ?

    結(jié)語(yǔ)

    ?

    本文旨在為剛接觸CTP的小白們拋磚引玉,各交易接口的深度運(yùn)用還需要看官方開發(fā)文檔。

    另外,對(duì)于完整的量化交易系統(tǒng)來(lái)說(shuō),不僅要具備行情、交易、策略模塊,事件驅(qū)動(dòng)、風(fēng)控、回測(cè)模塊以及底層的數(shù)據(jù)存儲(chǔ)、網(wǎng)絡(luò)并發(fā)都是需要深入鉆研的方面,金融工程的Quant Researcher可以只專注于數(shù)據(jù)的分析、策略的研發(fā),但是對(duì)于程序員Quant Developer來(lái)說(shuō),如何設(shè)計(jì)和開發(fā)一個(gè)高并發(fā)、低延遲、功能完善與策略結(jié)合緊密的量化交易系統(tǒng)的確是一項(xiàng)需要不斷完善的工程。

    ?

    ps:如果需要更高級(jí)和細(xì)致甚至可以用于實(shí)盤的功能,比如完整的開源交易系統(tǒng),數(shù)據(jù)系統(tǒng),算法交易,數(shù)據(jù)和交易接口等完備的解決方案,由于博客回復(fù)不現(xiàn)實(shí),只能私信聯(lián)系啦~

    支持是知識(shí)分享的動(dòng)力,有問(wèn)題可掃碼哦

    ?

    總結(jié)

    以上是生活随笔為你收集整理的C++连接CTP接口实现简单量化交易(行情、交易、k线、策略)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

    如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。