CTP賬戶持倉和資金的維護(干貨滿滿)

對于很多CTP開發(fā)者而言,持倉和資金的維護都是比較頭疼的事情,這里給大家講一些維護持倉和資金的一些方法。注意哦,全篇全是干貨,記得做筆記~
先聲明一下,Up主這里講的是一個通用的錢和倉的計算規(guī)則,適用于大部分交易系統(tǒng),up主也合理推測CTP柜臺內(nèi)部也是使用類似的更新方法。寫得不對的地方,歡迎大家指正。
首先列出幾個資金的計算式(本文以逐日盯市而非逐筆對沖的規(guī)則來計算,逐日盯市的含義up主不再贅述,讀者可通過其他方式了解):
靜態(tài)權(quán)益 =?上次結(jié)算準備金(PreBalance,就是昨天結(jié)算后的賬戶權(quán)益)+ 入金(Deposit) - 出金(Withdraw)
動態(tài)權(quán)益(Balance) =?靜態(tài)權(quán)益?+?持倉盈虧(PositionProfit)?+?平倉盈虧(CloseProfit)+ 資金差額(CashIn,即權(quán)利金收支,期權(quán)才會用到)- 手續(xù)費?(Commission)
可用資金(Available) =?動態(tài)權(quán)益(Balance)-?保證金(CurrMargin)- 凍結(jié)的保證金(FrozenMargin) - 凍結(jié)的手續(xù)費(FrozenCommission) - 凍結(jié)的資金(FrozenCash,即凍結(jié)的權(quán)利金,期權(quán)才會用到) - 交割保證金(DeliveryMargin)
持倉盈虧 =?∑持倉的持倉盈虧
平倉盈虧?=?∑持倉的平倉盈虧
單個持倉的平倉盈虧 =?∑此持倉各筆平倉成交的平倉盈虧
資金差額?=?∑持倉的資金差額
手續(xù)費?=?∑持倉的手續(xù)費
保證金?=?∑持倉的占用保證金
凍結(jié)的保證金=?∑持倉的凍結(jié)的保證金
凍結(jié)的手續(xù)費=?∑持倉的凍結(jié)的手續(xù)費
凍結(jié)的資金=?∑持倉的凍結(jié)的資金
這些按持倉匯總求和的字段,都是表示當天這個交易日的數(shù)據(jù),結(jié)算后會清空置零。例如,持倉盈虧表示今日的持倉盈虧,手續(xù)費表示今日的手續(xù)費。
從上面的式子可以看出,賬戶資金的數(shù)據(jù)的很多字段都是持倉的相關(guān)數(shù)據(jù)的匯總求和,當持倉的該字段數(shù)據(jù)發(fā)生變化時,賬戶資金的對應(yīng)數(shù)據(jù)也會發(fā)生變化。因此,下面的內(nèi)容主要是關(guān)于持倉中各數(shù)據(jù)的維護,而資金的數(shù)據(jù)的變動可根據(jù)新的持倉數(shù)據(jù)計算更新,所以一般不再贅述。另外,也不涉及期權(quán)的相關(guān)計算。
TIPS:期權(quán)交易涉及到的資金差額(CashIn,即權(quán)利金收支)的更新,參加up主的文章:(傳送門)CTP期權(quán)交易。本文剩余內(nèi)容對于期貨和期權(quán)都是通用的,但不再單獨涉及期權(quán)的權(quán)利金收支的更新。

1.收到行情快照時資金和持倉的更新
接收到合約行情快照時,需要更新這個快照的合約對應(yīng)的持倉(匯總)的持倉盈虧,然后更新賬戶的動態(tài)權(quán)益等資金數(shù)據(jù)。
多頭持倉的持倉盈虧 =?(最新價 - 持倉均價) * 合約數(shù)量乘數(shù) * 持倉數(shù)量
空頭持倉的持倉盈虧 =?(持倉均價 - 最新價) * 合約數(shù)量乘數(shù)?* 持倉數(shù)量

2. 報單時資金和持倉的更新
報單時,區(qū)分開倉和平倉兩種類型來更新數(shù)據(jù)。
開倉報單:
需要凍結(jié)一部分保證金和凍結(jié)一部分手續(xù)費,以及持倉中增加等同于報單數(shù)量的多(或空)頭凍結(jié)。
買入開倉則增加多頭持倉的多頭凍結(jié)(LongFrozen)數(shù)量,賣出開倉則增加空頭持倉的空頭凍結(jié)(ShortFrozen)數(shù)量。
由于凍結(jié)手續(xù)費計算較為復(fù)雜,而且金額較少,因此本文中忽略不計,下同。
不同期貨公司的凍結(jié)保證金算法不一(可以參見 TThostFtdcMarginPriceTypeType 類型取值說明),有的按報單價格計算,有的按昨結(jié)算價計算,有的按最新價計算......為方便管理,開發(fā)者可自行選擇其中一種價格的類型來統(tǒng)一計算凍結(jié)保證金(此處以昨結(jié)算價為例進行計算):
增加的凍結(jié)保證金?= 昨結(jié)算價 * 合約數(shù)量乘數(shù) * 合約保證金率 * 報單數(shù)量 + 合約保證金(按手數(shù)) * 報單數(shù)量
注1:目前國內(nèi)期貨的合約保證金(按手數(shù))暫時都為0,多頭和空頭保證金率二者也是相等的,但有消息稱,交易所未來將上線"多頭和空頭獨立設(shè)置保證金率"的改動。
注2:期貨公司具體使用哪種方式計算凍結(jié)資金,可通過查詢經(jīng)紀公司交易參數(shù)獲得,查詢接口是函數(shù)ReqQryBrokerTradingParams, 響應(yīng)函數(shù)是OnRspQryBrokerTradingParams。
注3:期權(quán)買入開倉時,由于多頭持倉無需支付保證金,因此也無需占用凍結(jié)保證金。下方同理,對期權(quán)買入開倉的報單錯誤相應(yīng)和成交、報單回報等的處理中,也無需更改保證金或凍結(jié)保證金。作為代價,期權(quán)買入開倉需要支付權(quán)利金(資金差額),權(quán)利金的計算方式類似于保證金,計算方式:
權(quán)利金增加或減少的數(shù)量,等于此次成交的(預(yù)期的)成交額,即 成交數(shù)量 * 成交價格 * 期權(quán)合約乘數(shù)。?
當然對于買入下單計算凍結(jié)權(quán)利金時,這里的成交數(shù)量即可替換為報單數(shù)量,成交價格即可替換為合約昨結(jié)算價,替換方式類似于凍結(jié)保證金。其他場景的更新權(quán)利金和凍結(jié)權(quán)利金同理,下方不再贅述。
平倉報單:
需要凍結(jié)一部分持倉,就是說,未成交的平倉的掛單會凍結(jié)一部分持倉,這部分持倉暫時無法平倉。
增加的凍結(jié)的持倉的數(shù)量等于報單數(shù)量。
買入平倉則增加空頭持倉的多頭凍結(jié)(LongFrozen)數(shù)量,賣出平倉則增加多頭持倉的空頭凍結(jié)數(shù)量(ShortFrozen)數(shù)量。
這里給大家講一下,為啥在平倉的委托在下單時就要更新凍結(jié)的持倉等數(shù)據(jù)呢?因為從委托到收到報單通知是有一個時間差的,如果不在報單時更新而是在收到報單通知中更新,則有一定的延時,這段時間內(nèi)持倉等數(shù)據(jù)就會不準確。例如,小明有1手ag2106多頭持倉,他報單賣出平倉1手,如果他不在報單時更新凍結(jié)持倉數(shù)量,則程序會誤認為報單后(還沒收到報單通知時),自己仍有1手可平的持倉(見下面的式子),從而程序可能會再次下單平倉,產(chǎn)生錯誤。
持倉可用(即可平)數(shù)量計算式:
可用數(shù)量(對于多頭持倉) =?Position -?ShortFrozen?-?CombShortFrozen
可用數(shù)量(對于空頭持倉)?=?Position - LongFrozen?-?CombLongFrozen

3. 報單錯誤響應(yīng)時資金和持倉的更新
如果報單有錯誤,即收到了OnRspOrderInsert響應(yīng),說明報單失敗,需要將此前凍結(jié)的持倉等數(shù)據(jù)進行解凍。
報單錯誤響應(yīng)時,也區(qū)分開倉和平倉兩種類型來更新數(shù)據(jù)。
開倉報單的錯誤響應(yīng):
解凍(即減少)一部分保證金和一部分手續(xù)費,并持倉中減少等同于報單數(shù)量的多(或空)頭凍結(jié)。
買入開倉錯誤響應(yīng)則減少多頭持倉的多頭凍結(jié)(LongFrozen)數(shù)量,賣出開倉錯誤響應(yīng)則減少空頭持倉的空頭凍結(jié)(ShortFrozen)數(shù)量。
減少的凍結(jié)保證金?= 昨結(jié)算價 * 合約數(shù)量乘數(shù) * 合約保證金率 * 報單數(shù)量 + 合約保證金(按手數(shù)) * 報單數(shù)量
平倉報單的錯誤響應(yīng):
需要解凍一部分持倉,減少的凍結(jié)的持倉的數(shù)量等于報單數(shù)量。
買入平倉錯誤響應(yīng)則減少空頭持倉的多頭凍結(jié)(LongFrozen)數(shù)量,賣出平倉則減少多頭持倉的空頭凍結(jié)數(shù)量(ShortFrozen)數(shù)量。

4. 報單通知(OnRtnOrder)中的更新
收到報單通知時,先判斷報單是否是已撤單。如果報單通知中的訂單狀態(tài)不是已撤單,則無需根據(jù)這個報單通知來更新持倉或資金。
當一個報單被撤單時,無論是被動撤單(被交易所自動撤單,如FAK單)還是主動撤單(主動發(fā)起撤單請求導(dǎo)致),都需要更新持倉和資金數(shù)據(jù)。更新的方法與報單錯誤響應(yīng)時的更新類似。二者主要區(qū)別在于,報單錯誤響應(yīng)時的更新中,計算使用的數(shù)量是報單數(shù)量,而(已撤單的)報單通知的更新,計算使用的數(shù)量是報單的未成交數(shù)量,即報單通知數(shù)據(jù)結(jié)構(gòu)的剩余數(shù)量(VolumeTotal)字段。具體更新計算方法不再贅述。而如果報單沒有達到被撤單的最終狀態(tài),則無需更新持倉和資金數(shù)據(jù)。
有一點需要注意,如果你的賬戶可能在多端同時登錄且報單,由于私有流OnRtnOrder報單通知會推送給所有登錄了同一賬戶的API,所以API會收到其他API終端報單生的報單通知,這就會有數(shù)據(jù)同步的問題。因為,在非本端的報單,是沒有在報單時更新本端的持倉等數(shù)據(jù)的,而根據(jù)其他端的報單產(chǎn)生的報單通知去更新,就會有解凍還沒有凍結(jié)(但本應(yīng)凍結(jié))的持倉等錯誤。如何解決這個問題,這里有兩種方案供參考:
在你的多個程序間,建立同步機制,一端的報單能同步到其他端上面,從而保證各個端的數(shù)據(jù)是統(tǒng)一的,例如使用分布式服務(wù)。
收到報單通知時,判斷是否是本端的報單(例如根據(jù)FrontID和SessionID判斷),如果不是,而且是第一次收到這個報單的報單通知,則更新凍結(jié)的持倉等數(shù)據(jù),更新方法類似于報單時的更新,即將本端漏掉的報單時的更新操作給補上。

5.成交通知(OnRtnTrade)中的更新
收到成交通知時,需要更新對應(yīng)的持倉明細和持倉,以及解凍數(shù)量等同于成交數(shù)量的持倉,還需要解凍一定數(shù)量的凍結(jié)保證金和凍結(jié)手續(xù)費。
成交也區(qū)分開倉和平倉兩種類型來更新數(shù)據(jù)。

開倉成交:
先增加一條持倉明細:
持倉明細的開倉日期(OpenDate)是成交的交易日(TradingDay),
持倉明細的成交編號(TradeID)等于成交的成交編號(TradeID),
持倉明細的成交類型(TradeType)等于成交的成交類型(TradeType),
持倉明細的買賣方向(Direction)等于成交的買賣方向(Direction),
持倉明細的開倉價格(OpenPrice)等于成交的成交價格(Price),
持倉明細的數(shù)量等于成交的成交數(shù)量(Volume),
持倉明細的投機套保標志(HedgeFlag)等于成交的投機套保標志(HedgeFlag)。
此筆持倉明細是今倉,因此持倉價格等于開倉成交價格。
持倉明細的保證金(Margin)由以下式子計算得出:
Margin =?Volume?*?Price?*?合約數(shù)量乘數(shù) * 合約保證金率 +?Volume?*?合約保證金(按手數(shù))
然后,查找到對應(yīng)的持倉,并做修改:
持倉的持倉數(shù)量(PositionNum)和開倉量(OpenVolume)和今倉量(TodayPosition)增加,其增加量等于成交數(shù)量。
持倉的保證金(UseMargin)增加,增加量等于上述計算出的持倉明細的保證金。
持倉的多頭凍結(jié)(對于多頭持倉)或空頭凍結(jié)(對于空頭持倉)減少,其減少量等于成交數(shù)量。
持倉的凍結(jié)保證金減少,減少量為按成交數(shù)量計算。
持倉的持倉成本(PositionCost)和開倉成本(OpenCost)增加,增加量都等于成交的成交額,即Volume?*?Price?*?合約數(shù)量乘數(shù),并根據(jù)持倉成本和開倉成本重新計算持倉均價和開倉均價:
持倉均價 = 持倉成本 / (持倉數(shù)量 *?合約數(shù)量乘數(shù))
開倉均價 =?開倉成本 / (持倉數(shù)量 *?合約數(shù)量乘數(shù))
持倉的手續(xù)費增加,增加數(shù)量即為此筆成交的手續(xù)費:
此筆開倉成交的手續(xù)費 =?成交價 * 成交數(shù)量?*?合約數(shù)量乘數(shù)?* 合約開倉手續(xù)費率 +?成交數(shù)量?*?合約開倉手續(xù)費(按手數(shù))

平倉成交:
首先,按照一定的規(guī)則來確定,該合約對應(yīng)方向的各筆持倉明細的分別平倉的數(shù)量。平倉規(guī)則詳見此前介紹組合合約的文章。
部分交易所不區(qū)分今倉和昨倉,例如大商所,但平倉一般是按先開先平來處理,即先平昨倉再平今倉,而上期所和能源中心等交易所,區(qū)分平今和平昨,因此,這些交易所根據(jù)成交的開平類型(平今還是平倉即平昨),即可判斷要更新哪一些持倉明細。搞清楚持倉明細的平倉順序,才能正確更新持倉明細(主要是為了計算準確手續(xù)費和平倉盈虧)。
對于單筆持倉明細,按上述規(guī)則確定其在成交中的平倉數(shù)量(設(shè)為N),再進行更新。更新方法如下:
這筆持倉明細的數(shù)量減少,減少量等于N。
按新的數(shù)量重新計算這筆持倉明細的保證金。
這筆持倉明細的平倉量(CloseVolume)增加,增加量等于N。
這筆持倉明細的平倉盈虧(CloseProfit)增加,增加量等于此筆持倉明細在此成交中的平倉盈虧:
對于多頭持倉明細:此筆持倉明細在此成交中的平倉盈虧 =?(成交價 - 持倉價格)* N * 合約數(shù)量乘數(shù)
對于空頭持倉明細:此筆持倉明細在此成交中的平倉盈虧 =?(持倉價格?-?成交價)* N * 合約數(shù)量乘數(shù)
其中,持倉價格是多少:
歷史持倉明倉(開倉日期不等于今日交易日)的持倉價格 = 昨結(jié)算價
今日持倉明細(開倉日期等于今日交易日)的持倉價格 = 開倉價格
可以看到,今倉和昨倉的持倉價格不一樣,因此算出來的持倉盈虧也是不一樣的,所以持倉明細的更新需要按正確的平倉順序來算,如果順序錯了,那么算出來的平倉盈虧也就會和實際值不相符了,下面的平倉成交的的手續(xù)費也是同理。
更新持倉明細時,順便將此筆持倉明細平倉產(chǎn)生的手續(xù)費計算出來:
此筆持倉明細平倉產(chǎn)生的手續(xù)費 =?成交價 *?N *?合約數(shù)量乘數(shù)?* 合約平倉手續(xù)費率 +?N *?合約平倉手續(xù)費(按手數(shù))
注意:即使是對于大商所等不區(qū)分今倉和昨倉的交易所,合約平倉手續(xù)費率和合約平倉手續(xù)費(按手數(shù)),也是區(qū)分平今和平昨進行計算的,即分為平今手續(xù)費率和平昨手續(xù)費率。所以,上面的計算手續(xù)費的式子中的費率是需要取用交易對應(yīng)的實際費率的,而不能為了簡單方便而對大商所等交易所的平倉交易統(tǒng)一都用單一的費率(例如,只取用平昨的費率),這樣算出來的手續(xù)費就會和實際的手續(xù)費有較大的偏差。
然后,根據(jù)以上數(shù)據(jù),可以計算出此筆成交的平倉盈虧和手續(xù)費:
此筆平倉成交的平倉盈虧 =?∑各筆持倉明細在此平倉成交中的平倉盈虧
此筆平倉成交的手續(xù)費?=?∑各筆持倉明細在此平倉成交中產(chǎn)生的手續(xù)費
持倉明細更新完后,以持倉明細匯總更新持倉,更新持倉的持倉數(shù)量,保證金,平倉盈虧,今倉數(shù)量,持倉成本,開倉成本等數(shù)據(jù),具體更新方法如下。
持倉的持倉數(shù)量 =?∑持倉明細的數(shù)量
持倉的保證金?=?∑持倉明細的保證金
持倉的平倉量?=?∑持倉明細的平倉量
持倉的平倉盈虧?=?∑持倉明細的平倉盈虧
持倉的今倉量?=?∑開倉日期等于今日交易日的持倉明細的數(shù)量
持倉的開倉成本 =?∑?(持倉明細的開倉價格 * 數(shù)量 * 合約數(shù)量乘數(shù))
根據(jù)開倉的開倉成本即可算出開倉均價,注意哦,是均價,即開倉平均價格
持倉的持倉成本 =?∑?(持倉明細的持倉價格 * 數(shù)量 * 合約數(shù)量乘數(shù))
根據(jù)持倉的持倉成本即可算出持倉均價,注意哦,是均價,即持倉平均價格
持倉的手續(xù)費?+=?此筆平倉成交的手續(xù)費
更新后,持倉中再做進一步改動:
持倉的空頭凍結(jié)(對于多頭持倉)或多頭凍結(jié)(對于空頭持倉)減少,其減少量等于成交數(shù)量。
注1:期權(quán)交易的賣出成交時(無論是開倉或平倉),還額外會有一筆權(quán)利金的收入,即權(quán)利金收支(資金差額)會增加,計算方式見上文。
至此,根據(jù)平倉成交來更新持倉明細和持倉的流程宣告完成。相信看到這里,你已經(jīng)是對CTP的錢和倉該怎么算,有了一個基礎(chǔ)的認識了。
這里舉一個平倉的例子,幫助大家理解:
小明有4手c2101多頭持倉,分為兩筆持倉明細:
第一筆,是2手昨倉,開倉價格3006元;
第二筆,是2手今倉,開倉價格3000元。
假設(shè)c2101昨結(jié)算價是3005元,合約數(shù)量乘數(shù)是10噸/手,多頭保證金率是5%,平昨手續(xù)費是每手1.2元,平今免手續(xù)費。他下單賣出平倉3手c2101,全部成交,成交價是3004元。則按平倉順序可知,平倉的是2手昨倉和1手今倉,交易后剩余1手今倉。交易數(shù)據(jù)如下:
第一筆持倉明細(昨倉)在本次成交中的平倉盈虧 =?(3004?- 3005) *?10 * 2 = -20元
第一筆持倉明細(昨倉)在本次成交中產(chǎn)生的手續(xù)費?= 2 * 1.2 =?2.4元
第二筆持倉明細(今倉)在本次成交中的平倉盈虧 =?(3004?-?3000) *?10 * 1?= 40元
第二筆持倉明細(今倉)在本次成交中產(chǎn)生的手續(xù)費?= 1?* 0?=?0元
此次成交的平倉盈虧?=?(-20)+ 40 = 20元
此次成交的手續(xù)費?= 2.4 + 0 = 2.4元
成交后,新的c2101多頭持倉的部分數(shù)據(jù)如下:
持倉數(shù)量 1手,其中今倉量 1手,即持倉全部都是今倉。
平倉量相比此次成交前增加3手,
手續(xù)費相比此次成交前增加2.4元,
平倉盈虧相比此次成交前增加20元。
新的開倉成本為30000元,開倉均價為3000元,
新的持倉成本為30000元,持倉均價為3000元。
新的持倉保證金為1500元。
