The interface of futures CTP C + + source code and C application program

Keywords: less Database REST network

As you know, the CTP interface of futures is provided by the technology company of the previous period. The source code and examples it provides are written in C + + language, which is not convenient to use. For example, I need a database, a program, a K-line chart, and functions like this. I need to do a lot of things before I place an order Writing in C + + can be cumbersome. But C ා is not afraid to do these troublesome things. C ා is used to do dirty work. You give C ා the interface and application logic. C + + only needs to manage one thing of its own - how to talk with the exchange. In this way, the workload will be much smaller.

In fact, for most people, without a high-level language like C Chen, they can't do any work at all. For example, if I want to place an order, how can I place an order in C + +, in the black window, enter the contract code, price, number of hands You can't finish a list until you hit the keyboard, right? But in the C interface, you only need to click a button:


It's the "hang buy" button. I click it. In a flash, the purchase is finished. In this moment, the program did a series of things for me:

● see which contract I want to buy;
● read the latest interface of the contract, read the preset offset value of the hanging order, and calculate the price of the hanging order;
● read the default number of hands;
● prepare the declaration, update the serial number of the declaration and record the information of the declaration;
● pre check this order (whether there is self closing risk, whether the application serial number is compliant, whether the funds are sufficient, whether it is compliant in transaction time and other aspects);
● whether there is an old order to be withdrawn (sometimes it is necessary to withdraw the old order and then issue a new one, such as when closing positions);
● whether there is reverse order in the account to be hedged, and if so, whether to open or close the position;
● issue order to transaction module;
● issue order to C + + module;
● report to exchange.

In this series of things, all C + + has to do is to report to the exchange, that is, ReqOrderInsert.
All the long winded matters in front are arranged by C Chen.
If it's written in C + +, the workload can be imagined (in fact, it's not feasible for most programmers).
Although it seems that there are many things, the series just happened in about ten milliseconds.
This ten millisecond event, that is, it's written in C ා language, and it's also very long. Let's simplify it. First, we don't think about the report record, report verification and so on. Suppose that we click the button to directly report, so that we can see the relationship between C ා and C + +, then——

The code in C is:

        ///Location of dll output by C + +
        const string dllPath = @"CTP_se.dll";
        ///Reference the single function in C + + (in C + +, the entry of the single is the function "﹣ ReqOrderInsert"
        [DllImport(dllPath, EntryPoint = "_ReqOrderInsert")]
        ///The single function of C ා, and the "extern" label determines that it should refer to the function "ReqOrderInsert" in C + + as specified in the previous sentence
        static extern void ReqOrderInsert(
        char[] BrokerID, //Brokerage company code (string, required)
        char[] InvestorID, //Investor code (string, required)
        char[] InstrumentID, //Contract code (string, required)
        char[] ExchangeID, //Exchange code (string, required)
        char[] OrderRef, //Entry reference (string, required)
        char[] UserID, //User code (string, no need to fill in "null")
        int OrderPriceType, //Entry price condition (required, 1 is any price, 2 is limit price, 3 is the best price, 4 is the latest price,
            //5 is the latest price floating up 1 tick, 6 is the latest price floating up 2 ticks, 7 is the latest price floating up 3 ticks, 8 is the selling price,
            //9 is one tick for selling one price floating upward, 10 is two ticks for selling one price floating upward, 11 is three ticks for selling one price floating upward, 12 is buying one price,
            //13 is one tick for the floating of buy one price, 14 is two ticks for the floating of buy one price, 15 is three ticks for the floating of buy one price, 16 is the fifth price)
        int Direction, //Buying and selling direction (1 for buying, - 1 for selling)
        int CombOffsetFlag, //Combined open flat sign (required, 1 is open, 0 is flat, - 1 is flat now, - 2 is flat yesterday, - 3 is strong flat, - 4 is strong minus, - 5 is local strong flat)
        int CombHedgeFlag, //Combination speculative hedging flag (required, 0 is speculation, 1 is arbitrage, 2 is hedging)
        double LimitPrice, //Price (real, required)
        int VolumeTotalOriginal, //Number of hands (required)
        int TimeCondition, //Validity type (required, 1 is to be completed immediately, otherwise it will be cancelled, 2 is to be valid in this section, 3 is to be valid on that day, generally fill in 3
            //4 is valid before the specified date, 5 is valid before cancellation, 6 is valid for call auction)
        char[] GTDDate, //GTD date (string, no need to fill in "null")
        int VolumeCondition, //Volume type (required, 1 for any quantity, 2 for minimum quantity, 3 for all quantity, generally 1)
        int MinVolume, //Minimum volume (required)
        int ContingentCondition, //Trigger conditions (required, 1 is immediate, 2 is stop loss, 3 is win until win, 4 is embedded form, generally fill in 1
            //5 is the latest price greater than the conditional price, 6 is the latest price greater than or equal to the conditional price, 7 is the latest price less than the conditional price, 8 is the latest price less than or equal to the conditional price,
            //9 is the selling price greater than the conditional price, 10 is the selling price greater than or equal to the conditional price, 11 is the selling price less than the conditional price, 12 is the selling price less than or equal to the conditional price,
            //13 is that the buy price is greater than the condition price, 14 is that the buy price is greater than or equal to the condition price, 15 is that the buy price is less than the condition price, 16 is that the buy price is less than or equal to the condition price)
        double StopPrice, //Stop loss price (real number, no need to fill in "0")
        int ForceCloseReason, //Strong flat reason (required, 0 is not strong flat, 1 is insufficient funds, 2 is customer over position, generally fill in 0
            //3 is over position of members, 4 is non integral multiple of position, 5 is violation, 6 is other, 7 is close to delivery of natural person)
        int IsAutoSuspend, //Auto suspend flag (integer, required, generally 0, indicating no auto suspend)
        char[] BusinessUnit, //Business unit (string, no need to fill in "null")
        int RequestID, //Request number (integer, no need to fill in "Int32.MinValue")
        int UserForceClose, //User strong rating mark (integer, required, generally 0, no)
        int IsSwapOrder, //Swap list flag (integer, no need to fill in "Int32.MinValue")
        int tdClientI //Transaction communication thread No
        );
        private void Hang on button_Click(object sender, EventArgs e)
        {
            string brokerID = "9999";
            string userID = "071988";
            string insID = "ni2003";
            string exchangeID = "SHFE";
            string ordID = "10000";
            int direction = 1;
            int oc = 1;
            double price = 108590;
            int lot = 1;
            int tdClientI = 0;
            ReqOrderInsert(brokerID.ToCharArray(), userID.ToCharArray(), insID.ToCharArray(), exchangeID.ToCharArray(), ordID.ToCharArray(), null,
                            2, direction, oc, 0, price, lot, 3, null, 1, 1, 1, 0, 0, 0, null, Int32.MinValue, 0, Int32.MinValue, tdClientI);
        }

In C + +, the function that interfaces with the above C ා function is called "ReqOrderInsert":

///Declaration function in C + +
int ReqOrderInsert(CThostFtdcInputOrderField* pInputOrder, int tdClientI) {
	string str_ref(pInputOrder->OrderRef);
	string insID(pInputOrder->InstrumentID);
	logWithTimeBUI(tdClientI, insID, "Trial report ordID." + str_ref);
	tdApiList::iterator i = tdAPIs.begin();
	advance(i, tdClientI);
	int r = (*i)->ReqOrderInsert(pInputOrder, ++nRequestID); //Enter the network communication module officially provided in the previous issue and report to the exchange
	logBUI(tdClientI, insID, "Return" + toStr(r));
	return r;
}
///The ticket function of C + + and C ා docking
CTP_API void __stdcall _ReqOrderInsert(char* BrokerID, char* InvestorID, char* InstrumentID, char* ExchangeID, char* OrderRef, char* UserID, 
int OrderPriceType, int Direction, int CombOffsetFlag, int CombHedgeFlag, double LimitPrice, int VolumeTotalOriginal, 
int TimeCondition, char* GTDDate, int VolumeCondition, int MinVolume, int ContingentCondition, double StopPrice, 
int ForceCloseReason, int IsAutoSuspend, char* BusinessUnit, int RequestID, int UserForceClose, int IsSwapOrder, int tdClientI)
{
	CThostFtdcInputOrderField req;
	memset(&req, 0, sizeof(req));
	if (BrokerID != NULL) strcpy(req.BrokerID, BrokerID);//Brokerage company code
	if (InvestorID != NULL) strcpy(req.InvestorID, InvestorID);//Investor code
	if (InstrumentID != NULL) strcpy(req.InstrumentID, InstrumentID);//Contract code
	if (ExchangeID != NULL) strcpy(req.ExchangeID, ExchangeID);//Affiliated exchange
	if (OrderRef != NULL) strcpy(req.OrderRef, OrderRef);//Invoice reference
	if (UserID != NULL) strcpy(req.UserID, UserID);//user designation codes
	if (OrderPriceType == 1) req.OrderPriceType = THOST_FTDC_OPT_AnyPrice;//Arbitrary price
	else if (OrderPriceType == 2) req.OrderPriceType = THOST_FTDC_OPT_LimitPrice;//Fixed price
	else if (OrderPriceType == 3) req.OrderPriceType = THOST_FTDC_OPT_BestPrice;//Best price
	else if (OrderPriceType == 4) req.OrderPriceType = THOST_FTDC_OPT_LastPrice;//Latest price
	else if (OrderPriceType == 5) req.OrderPriceType = THOST_FTDC_OPT_LastPricePlusOneTicks;//Latest price floating up 1 tick
	else if (OrderPriceType == 6) req.OrderPriceType = THOST_FTDC_OPT_LastPricePlusTwoTicks;//Latest price floating up 2 ticks
	else if (OrderPriceType == 7) req.OrderPriceType = THOST_FTDC_OPT_LastPricePlusThreeTicks;//Latest price floating up 3 ticks
	else if (OrderPriceType == 8) req.OrderPriceType = THOST_FTDC_OPT_AskPrice1;//Selling price
	else if (OrderPriceType == 9) req.OrderPriceType = THOST_FTDC_OPT_AskPrice1PlusOneTicks;//Sell one price floating up one tick
	else if (OrderPriceType == 10) req.OrderPriceType = THOST_FTDC_OPT_AskPrice1PlusTwoTicks;//Sell one price floating up 2 tickets
	else if (OrderPriceType == 11) req.OrderPriceType = THOST_FTDC_OPT_AskPrice1PlusThreeTicks;//Selling one price floating up three tickets
	else if (OrderPriceType == 12) req.OrderPriceType = THOST_FTDC_OPT_BidPrice1;//Buy one price
	else if (OrderPriceType == 13) req.OrderPriceType = THOST_FTDC_OPT_BidPrice1PlusOneTicks;//Buy one price float up one tick
	else if (OrderPriceType == 14) req.OrderPriceType = THOST_FTDC_OPT_BidPrice1PlusTwoTicks;//Buy one price floating up 2 tickets
	else if (OrderPriceType == 15) req.OrderPriceType = THOST_FTDC_OPT_BidPrice1PlusThreeTicks;//Buy one price floating up three tickets
	else if (OrderPriceType == 16) req.OrderPriceType = THOST_FTDC_OPT_FiveLevelPrice;//Five price
	else return;//Entry price conditions
	if (Direction > 0) req.Direction = THOST_FTDC_D_Buy;//buy 
	else if (Direction < 0) req.Direction = THOST_FTDC_D_Sell;//sell 
	else return;//Direction of business
	if (CombOffsetFlag == 1) req.CombOffsetFlag[0] = THOST_FTDC_OF_Open;//open
	else if (CombOffsetFlag == 0) req.CombOffsetFlag[0] = THOST_FTDC_OF_Close;//flat
	else if (CombOffsetFlag == -1) req.CombOffsetFlag[0] = THOST_FTDC_OF_CloseToday;//Ping Jin
	else if (CombOffsetFlag == -2) req.CombOffsetFlag[0] = THOST_FTDC_OF_CloseYesterday;//Ping yesterday
	else if (CombOffsetFlag == -3) req.CombOffsetFlag[0] = THOST_FTDC_OF_ForceClose;//Qiang Ping
	else if (CombOffsetFlag == -4) req.CombOffsetFlag[0] = THOST_FTDC_OF_ForceOff;//Strong reduction
	else if (CombOffsetFlag == -5) req.CombOffsetFlag[0] = THOST_FTDC_OF_LocalForceClose;//Local strengthening
	else return;//Combined Kaiping logo
	if (CombHedgeFlag == 0) req.CombHedgeFlag[0] = THOST_FTDC_HF_Speculation;//Speculation
	else if (CombHedgeFlag == 1) req.CombHedgeFlag[0] = THOST_FTDC_HF_Arbitrage;//Interest arbitrage
	else if (CombHedgeFlag == 2) req.CombHedgeFlag[0] = THOST_FTDC_HF_Hedge;//Hedging
	else return;//Portfolio speculative hedging mark
	if (LimitPrice > 0) req.LimitPrice = LimitPrice;//Price
	req.VolumeTotalOriginal = VolumeTotalOriginal;//Number
	if (TimeCondition == 1) req.TimeCondition = THOST_FTDC_TC_IOC;//Complete immediately, otherwise cancel 
	else if (TimeCondition == 2) req.TimeCondition = THOST_FTDC_TC_GFS;//This section is valid. 
	else if (TimeCondition == 3) req.TimeCondition = THOST_FTDC_TC_GFD;//good for the date of issue only 
	else if (TimeCondition == 4) req.TimeCondition = THOST_FTDC_TC_GTD;//Valid before specified date 
	else if (TimeCondition == 5) req.TimeCondition = THOST_FTDC_TC_GTC;//Effective before cancellation 
	else if (TimeCondition == 6) req.TimeCondition = THOST_FTDC_TC_GFA;//Effective call auction 
	else return;//Validity type
	if (GTDDate != NULL) strcpy(req.GTDDate, GTDDate);//GTD date
	if (VolumeCondition == 1) req.VolumeCondition = THOST_FTDC_VC_AV;//Any quantity 
	else if (VolumeCondition == 2) req.VolumeCondition = THOST_FTDC_VC_MV;//Minimum quantity 
	else if (VolumeCondition == 3) req.VolumeCondition = THOST_FTDC_VC_CV;//Total quantity 
	else return;//Volume type
	req.MinVolume = MinVolume;//Minimum volume
	if (ContingentCondition == 1) req.ContingentCondition = THOST_FTDC_CC_Immediately;//immediately
	else if (ContingentCondition == 2) req.ContingentCondition = THOST_FTDC_CC_Touch;//Stop loss
	else if (ContingentCondition == 3) req.ContingentCondition = THOST_FTDC_CC_TouchProfit;//Stop win
	else if (ContingentCondition == 4) req.ContingentCondition = THOST_FTDC_CC_ParkedOrder;//Prepaid bill
	else if (ContingentCondition == 5) req.ContingentCondition = THOST_FTDC_CC_LastPriceGreaterThanStopPrice;//Latest price is greater than conditional price
	else if (ContingentCondition == 6) req.ContingentCondition = THOST_FTDC_CC_LastPriceGreaterEqualStopPrice;//Latest price is greater than or equal to conditional price
	else if (ContingentCondition == 7) req.ContingentCondition = THOST_FTDC_CC_LastPriceLesserThanStopPrice;//Latest price is less than conditional price
	else if (ContingentCondition == 8) req.ContingentCondition = THOST_FTDC_CC_LastPriceLesserEqualStopPrice;//Latest price is less than or equal to conditional price
	else if (ContingentCondition == 9) req.ContingentCondition = THOST_FTDC_CC_AskPriceGreaterThanStopPrice;//Selling price is higher than conditional price
	else if (ContingentCondition == 10) req.ContingentCondition = THOST_FTDC_CC_AskPriceGreaterEqualStopPrice;//Selling price is greater than or equal to the conditional price
	else if (ContingentCondition == 11) req.ContingentCondition = THOST_FTDC_CC_AskPriceLesserThanStopPrice;//Selling price less than conditional price
	else if (ContingentCondition == 12) req.ContingentCondition = THOST_FTDC_CC_AskPriceLesserEqualStopPrice;//Selling price less than or equal to conditional price
	else if (ContingentCondition == 13) req.ContingentCondition = THOST_FTDC_CC_BidPriceGreaterThanStopPrice;//Buy price is higher than condition price
	else if (ContingentCondition == 14) req.ContingentCondition = THOST_FTDC_CC_BidPriceGreaterEqualStopPrice;//Buy price is greater than or equal to the conditional price
	else if (ContingentCondition == 15) req.ContingentCondition = THOST_FTDC_CC_BidPriceLesserThanStopPrice;//Buy price less than conditional price
	else if (ContingentCondition == 16) req.ContingentCondition = THOST_FTDC_CC_BidPriceLesserEqualStopPrice;//Buy price less than or equal to conditional price
	else return;//Trigger condition
	if (StopPrice > 0) req.StopPrice = StopPrice;//Stop loss price
	if (ForceCloseReason == 0) req.ForceCloseReason = THOST_FTDC_FCC_NotForceClose;//Non strong flat 
	else if (ForceCloseReason == 1) req.ForceCloseReason = THOST_FTDC_FCC_LackDeposit;//Insufficient funds 
	else if (ForceCloseReason == 2) req.ForceCloseReason = THOST_FTDC_FCC_ClientOverPositionLimit;//Customer exceed warehouse 
	else if (ForceCloseReason == 3) req.ForceCloseReason = THOST_FTDC_FCC_MemberOverPositionLimit;//Member super warehouse 
	else if (ForceCloseReason == 4) req.ForceCloseReason = THOST_FTDC_FCC_NotMultiple;//Position is not an integral multiple 
	else if (ForceCloseReason == 5) req.ForceCloseReason = THOST_FTDC_FCC_Violation;//Violation 
	else if (ForceCloseReason == 6) req.ForceCloseReason = THOST_FTDC_FCC_Other;//Other 
	else if (ForceCloseReason == 7) req.ForceCloseReason = THOST_FTDC_FCC_PersonDeliv;//Natural person close to delivery 
	else return;//Cause of strong flat
	if (IsAutoSuspend > -2147483647) req.IsAutoSuspend = IsAutoSuspend;//Auto suspend flag
	if (BusinessUnit != NULL) strcpy(req.BusinessUnit, BusinessUnit);//Business unit
	if (RequestID > -2147483647) req.RequestID = RequestID;//Request number
	if (UserForceClose > -2147483647) req.UserForceClose = UserForceClose;//User strong evaluation mark
	if (IsSwapOrder > -2147483647) req.IsSwapOrder = IsSwapOrder;//Interchange single sign
	ReqOrderInsert(&req, tdClientI);
}

There are a lot of codes involved in this. I'm sorry that I can't completely paste them here, because there are too many, too many. If you need to know more about it, you can chat with me in private. My QQ is 791269791 and wechat is minMove.
Here, I'll talk about the main ideas. Students who are familiar with C + + may understand it directly.

The problem we need to solve is to connect the C + + interface to C ා.
This is because:
1. We have to have C + +, because the interface officially provided in the last issue is C + +;
2. But C + + is troublesome. We don't want to write application logic with it;
3. It's easy to write with C ා, so we choose C ා;
4. But C ා needs to understand C + + "speaking", so it is necessary to connect the C + + interface to C ා.

What are the official interfaces in the last issue?

I'll show you the folders in my computer:

This is the final output directory of my futures software. The exe file is in it. Then there are many DLLs together with the exe file. Among them, the DLLs officially provided in the previous period are the three DLLs of "thostmduser api_se", "thostmtraderapi_se" and "WinDataCollect", which is the interface officially provided in the previous period.
"Thostmduserapi" is the market interface and "thostmtraderapi" is the transaction interface. These two DLLs have been used for ten years. I can write them down without looking at their strange names.
"WinDataCollect" is something that was only popularized in June last year. It's what the so-called "through certification" requires.

As an application, as an exe file, these DLLs are enough to talk to the exchange.
But as a developer, it's not enough. If you want to write the C + + part of the source code, what you need, which is officially from the last issue and is called "interface" in the legend, in addition to the three DLLs mentioned above, there are also some files, in general, these are:

error.dtd
error.xml
ThostFtdcMdApi.h
ThostFtdcTraderApi.h
ThostFtdcUserApiDataType.h
ThostFtdcUserApiStruct.h
thostmduserapi_se.dll
thostmduserapi_se.lib
thosttraderapi_se.dll
thosttraderapi_se.lib
DataCollect.h
WinDataCollect.dll
WinDataCollect.lib

The three dll files we just mentioned are in them. In addition, there are:
Library file: with the suffix of "lib", our C + + project can find the dll officially provided in the previous issue. A lib is paired with a dll. For example, "thosttradeapi_se. Lib" and "thosttradeapi_se. dll" are all transaction interfaces.
Header file: with "h" as the suffix, it can be opened with Notepad. You can clearly see its source code, because it is used for your reference. There are many official functions, which you can reference in C + + projects.
As for how to quote and place these documents, students who are familiar with C + + don't have to say they know them. Those who are not familiar with C + + don't understand them even if they say they don't understand them. They have to see the demonstration project to understand them. They can talk with me privately.

Instructions and returns

These are two important types of futures interface:

instructions
It's what I ask CTP to do for me or ask it.
For example, when I log in, I will tell it my user name, password, etc., which is the login instruction. For another example, I asked it for the service charge of contract ni2003, which belongs to the query instruction. All instructions are "what I said to CTP.".

Return
After I sent out the instruction, CTP replied to me, for example, if my login was successful, what is the handling fee of the contract I asked, which belongs to the return.
In addition, sometimes when I don't give instructions, CTP will also send messages to me, such as the market data of a contract and the transaction information of a list, which also belongs to return.
The reward is "what CTP said to me.".

Remember, the important thing to say three times, instruction and return, is the core content of CTP interface.
**Futures trading is full of orders and returns. **Our dialogue with the exchange is the return of orders and returns.
I told the exchange that I would buy two hands of ni2003 at the price limit, which is the order.
Then, the list is put on, and the exchange feeds back the information on the list to me, which is the return.
There's one deal, and the return is back.
I want to get rid of the rest and send the order to the exchange.
After the cancellation is successful, the exchange will send me the cancellation return.
......
And so on, again and again, this is the process of trading.
In addition, subscription, login, query It is also composed of instructions and returns.
Now you know enough about the importance of command and reward?

Common instructions and rewards

Instructions and returns are often in pairs. For example, the order connectMd connecting the market and the return onMdFrontConnected connecting the market are a pair. According to this rule, we will sort out the commonly used instructions and returns.

Type name Description

Command RegisterSpi and RegisterFront to connect to the quotation server
Return on frontconnected

Command ReqUserLogin to log in to quotation server
Return OnRspUserLogin market login return

Order SubscribeMarketData subscription Market
Return onrtndethmarketdata market push

Order UnSubscribeMarketData to unsubscribe (no return)
Return

instructions
Report error of onRspMdError (no instruction)

Order RegisterSpi and RegisterFront to connect to the transaction server
Return on frontconnected transaction connection return

Command GetTradingDay to get the current trading day (directly return the trading day value, no return)
Return

Instruction ReqAuthenticate requests client authentication
Return OnRspAuthenticate client authentication return

Instruct ReqUserLogin to log in to the transaction server
Return OnRspUserLogin transaction login return

Instruction ReqUserLogout log out of transaction server
Return OnRspUserLogout transaction logout return

Order reqsettlementifconfirm confirmation of investor settlement results
Return OnRspSettlementInfoConfirm

Instruction ReqQryInstrument query contract
Return OnRspQryInstrument query contract return

Instruction ReqQryOrder query entry
Report OnRspQryOrder query report report

Instruction ReqQryInvestorPosition query position
Return OnRspQryInvestorPosition query position return

Instruct ReqQryTradingAccount to query fund account
Return OnRspQryTradingAccount query fund account return

Instruct ReqQryInstrumentMarginRate to query the contract margin rate
Return OnRspQryInstrumentMarginRate query contract margin rate return

Order ReqQryInstrumentCommissionRate to query contract handling rate
Return onrspqryinstrument commissionrate query contract handling rate return

Command ReqQrySettlementInfo to query settlement doc
Return OnRspQrySettlementInfo query statement return

Command ReqQryProduct query product
Return OnRspQryProduct query product return

Order ReqQryTrade to query transaction
Return OnRspQryTrade query transaction return

Order ReqQryInvestorPositionDetail to query investor position details
Return OnRspQryInvestorPositionDetail query position detail return

Order ReqQryInvestor to query investors
Return OnRspQryInvestor query investor return

Instruction ReqOrderInsert, ReqOrderAction entry, cancellation
Return OnRtnOrder return or cancellation return (depending on the parameter to distinguish the return type)
Report on the rejection of OnRspOrderInsert by the front-end machine
Return return on the rejection of the OnErrRtnOrderInsert entry by the exchange
Report OnRspOrderAction return of cancellation rejected by the front-end machine
Return the return of the order cancellation rejected by the exchange
Return OnRtnTrade transaction return

instructions
Report OnRspTdError transaction error (no instruction)

It can be seen that most instruction functions start with "Req" and return functions start with "On".
Remember this "naming subterfuge", when you read C + + code, it's easy to distinguish between instructions and returns.
And then, how did the order go out? How does the return come to our computer from the exchange?
More specifically, how are instructions transferred from C to C + +? How is the return transferred from C + + to C?
Now let's look at these questions.

Instruction flow

Take the order to connect the market as an example.
The functions in C are:

///Location of dll output by C + +
const string dllPath = @"CTP_se.dll";
///Refer to the function "U connectMd" in C + +
[DllImport(dllPath, EntryPoint = "_connectMd")]
///The function in C ා, the "extern" label determines that it should refer to the function "﹖ connectMd" in C + + according to the previous sentence
static extern int ConnectMd(
char[] pszFrontAddress //Quotation server address (string, required)
);
public int connectMd(string tryingMdAdd)
{
    return ConnectMd(tryingMdAdd.ToCharArray());
}

The main functions in C + + are:

int connectMd(char *pszFrontAddress) {
	string str(pszFrontAddress);
	logWithTime("Already exist" + toStr(mdClientsN) + "When there are users, there are new users trying to connect with the market" + str);
	MDSPI* mdProxy = new MDSPI();
	mdProxy->clientI = mdClientsN;
	mdSPIs.push_back(mdProxy);
	CThostFtdcMdApi* mdApi = CThostFtdcMdApi::CreateFtdcMdApi();
	mdAPIs.push_back(mdApi);
	mdClientsN++;
	log("mdClientsN = " + toStr(mdClientsN));
	mdApi->RegisterSpi((CThostFtdcMdSpi*)mdProxy);
	log("RegisterMdSpi");
	mdApi->RegisterFront(pszFrontAddress);
	logWithTime("RegisterFront(Registered market address)" + str + "Complete");
	mdApi->Init();
	logWithTime("Init(Initialization) complete");
	logWithTime("Assign a sequence number to it" + toStr(mdClientsN - 1));
	return mdClientsN - 1;
}
CTP_API int __stdcall _connectMd(char *pszFrontAddress)
{ return connectMd(pszFrontAddress); }

Please understand that there is no relevant massive code posted here, but the students who are familiar with C + + may know the construction of this C + + project. If you really need to communicate, please contact me. Wechat has been written before.
Here is only an example of the market connection instruction. The flow of other instructions is similar to this. Please draw inferences from one example to understand.

Return process

The payoff can be more cumbersome than the instruction.
When we just wrote the instruction, it was very simple, just like a needle - C ා - find the function in C + + directly and call it.
But return can't simply call functions along the process. The process of return is to find C + + first and then C ා. We can't let C + + call C ා, because there is no such syntax.
For example, the market connection returns. When it comes, first go to thostmduserapi_se.dll, which is the official interface of the last issue. It's the "undercover agent" sent by the official to our computer. If the official news comes, of course, first look for it.
Then, it passes the message to C ා as an interface application program to do something after receiving the message.
Is it that simple? You must be dreaming.
First of all, news can't jump directly from the official dll to our C, because we can't modify the official dll.
Then it has to go through an intermediary, our self-made dll, a C + + version of dll. We usually name it "CTP.dll" (not only me, many developers name this intermediary), which is a translation, responsible for the communication between the official dll and our c program..
There is no obstacle for the official DLL to talk with CTP.dll. The rest of the problem lies in how to talk with C. His native language is C + +, he knows C Chen, so he can be the translator.
How does he know C Chen?
I'll put the conclusion here in advance and then say the reason. The conclusion is that CTP.dll can find the memory address of a function of C ා, so as to activate the function when something needs to be done. In this way, the message of C + + can remote control a certain action of C ා, which is also a translation, not that a C + + program can directly read C ා.
Memory address, which is the key word.
Hold on to this key word, let's understand the following process.
Take market linking returns for example.
Return comes to our computer, first find the official CTP provided thostmduserapi ﹣ se.dll, then find our own CTP.dll (both of which are C + +), call the return processing function "OnFrontConnected".

void CTP_API MDSPI::OnFrontConnected()
{
    if (toDoOnMdFrontConnected != NULL) toDoOnMdFrontConnected(MDSPI::clientI);
}

That is to say, when the market connection returns come to this machine, we need to do this: if the "to do on MD front connected" thing is not empty, call it.
So what is "to do on MD front connected"?
It is a function pointer.
Where does it point?
Point to a function to be executed by the interface program after receiving the quote connection return. This function is written in the interface program:

void onMdFrontConnected(int clientI)
{
    //......
}

Let's ignore what the ellipsis means (what to do after receiving the market return), first solve the problem: how to make C + + remote control the thing to be done in C ා.
To tell C + + the memory address of this function, that is, register the pointer of this function in C + +:

CTP_API void WINAPI registerOnMdFrontConnected(ToDoOnMdFrontConnected callback) 
{ toDoOnMdFrontConnected = callback; }

This is the action of registering function pointer. The "callback" in it is the function pointer from C ා and "toDoOnMdFrontConnected" is the record of C + + for this function pointer.
This "registerOnMdFrontConnected" is a C + + instruction, which is easy for C to call. C ා calling it is actually to tell C + + the function pointer, specifically:
1. First, create an agent for the above function onMdFrontConnected in C ා, because it can't transfer the memory address to C + +, only the agent can.
2.C calls the C + + function registerOnMdFrontConnected, and the parameter is the above agent. In this way, the memory address of the function onMdFrontConnected is passed to C + +.

Then, when C + + receives the exchange message, it executes OnFrontConnected. When it finds that toDoOnMdFrontConnected is not empty, it executes toDoOnMdFrontConnected, which is actually a pointer to the C ා function onMdFrontConnected, so it executes the C ා.
In this way, the scene of C + + remote control is magically realized.
Therefore, when we receive the message from the exchange, we need to record the database and correct the records. We need to withdraw the old order and open a new warehouse. We need to detect the programmed strategy. When we need to do this, we need not bother C + +, and we can write it in the familiar C language.
Therefore, our trading software is no longer a cold black DOS window, but can be——




Published 2 original articles, praised 0, visited 9
Private letter follow

Posted by Psyche on Thu, 06 Feb 2020 03:01:41 -0800