量化交易軟件:三角套利
開(kāi)發(fā)可靠規(guī)律的三角套利話題經(jīng)常出現(xiàn)在論壇上。那么它究竟是什么呢?
"套利" 意味著有些偏向行情的中立性。"三角" 是指投資組合由三個(gè)金融工具組成。
我們舉一個(gè)最流行的例子: "歐元 — 英鎊 — 美元" 三角。就貨幣對(duì)而言, 可以描述如下: EURUSD + GBPUSD + EURGBP。所需的中立性包括嘗試同時(shí)買(mǎi)入和賣(mài)出相同的金融工具, 從而賺取利潤(rùn)。

這看起來(lái)如下。這個(gè)例子中的任何一個(gè)貨幣對(duì)都可通過(guò)另外兩個(gè)貨幣對(duì)來(lái)表示:
EURUSD=GBPUSD*EURGBP,
或 GBPUSD=EURUSD/EURGBP,
或 EURGBP=EURUSD/GBPUSD。
所有這些變體是相同的, 下面會(huì)更詳細(xì)地討論它們中的所有選擇。同時(shí), 我們來(lái)研究第一個(gè)選項(xiàng)。
首先, 我們需要看出競(jìng)買(mǎi)價(jià)和競(jìng)賣(mài)價(jià)。流程如下:
買(mǎi)入 EURUSD, 即使用 競(jìng)賣(mài) 價(jià)。這意味著, 我們?cè)谟囝~中增加 EUR 占比, 并消減 USD。
我們來(lái)通過(guò)其它兩個(gè)貨幣對(duì)評(píng)估 EURUSD。
GBPUSD: 這里面沒(méi)有 EUR。代之, 我們需要拋售這里面的 USD。為了拋售 GBPUSD 當(dāng)中的 USD, 我們需要買(mǎi)入這個(gè)貨幣對(duì)。意即, 我們使用 競(jìng)賣(mài)價(jià)。當(dāng)買(mǎi)入時(shí), 我們?cè)谟囝~中增加 GBP 占比, 同時(shí)消減 USD。
EURGBP: 我們需要買(mǎi)入 EUR, 拋售我們不需要的 GBP。買(mǎi)入 EURGBP, 使用 競(jìng)賣(mài)價(jià)。我們?cè)谟囝~中增加 EUR 占比, 并消減 GBP。
總計(jì)我們擁有: (競(jìng)買(mǎi)價(jià)) EURUSD = (競(jìng)買(mǎi)價(jià)) GBPUSD * (競(jìng)買(mǎi)價(jià)) EURGBP。我們已獲得了必要的等價(jià)。為了令其盈利, 我們應(yīng)該一邊買(mǎi)入一邊賣(mài)出。這里有兩種可能的選項(xiàng):
比我們拋售 EURUSD 更便宜地買(mǎi)入, 但以不同的方式展現(xiàn): (競(jìng)賣(mài)價(jià)) EURUSD < (競(jìng)買(mǎi)價(jià)) GBPUSD * (競(jìng)買(mǎi)價(jià)) EURGBP
比我們買(mǎi)入 EURUSD 的更高價(jià)格拋售, 但以不同的方式展現(xiàn): (競(jìng)買(mǎi)價(jià)) EURUSD > (競(jìng)賣(mài)價(jià)) GBPUSD * (競(jìng)賣(mài)價(jià)) EURGBP
現(xiàn)在, 赫茲量化所要做的就是檢測(cè)這種情況, 并從中獲利。
注意, 三角可以用另一種方式來(lái)移動(dòng), 這三個(gè)貨幣對(duì)在一個(gè)方向上移動(dòng), 并與 1 比較。所有變體都相同, 但我相信, 上面描述的變體更容易理解和解釋。
通過(guò)形勢(shì)跟蹤, 赫茲量化可以尋找一個(gè)同時(shí)買(mǎi)入和賣(mài)出的時(shí)刻。在這種情況下, 會(huì)即時(shí)盈利, 但這樣的時(shí)刻是罕見(jiàn)的。 更常見(jiàn)的情況是, 當(dāng)我們能夠更便宜地買(mǎi)入一方時(shí), 卻無(wú)法在拋售另一方時(shí)盈利。那么我們只得等待這種不平衡消失。交易對(duì)我們來(lái)說(shuō)是安全的, 因?yàn)槲覀兊某謧}(cāng)相互抵消近乎為零, 意即我們游離于市場(chǎng)之外。雖然, 此處請(qǐng)注意 "近乎" 這個(gè)詞。為了交易量的完美程度, 我們所需的精確度并未得到。交易量往往四舍五入到小數(shù)點(diǎn)后兩位, 對(duì)于我們的策略來(lái)說(shuō)這太粗糙了。
現(xiàn)在赫茲量化已經(jīng)研究了這個(gè)理論, 現(xiàn)在是編寫(xiě) EA 的時(shí)候了。EA 是以面向過(guò)程的風(fēng)格開(kāi)發(fā)的, 所以新入行的程序員, 以及那些因?yàn)槟撤N原因不喜歡 OOP 的人都可以理解。
簡(jiǎn)要的 EA 描述
首先, 赫茲量化創(chuàng)建所有可能的三角, 將它們正確放置, 并獲得每個(gè)貨幣對(duì)的所有必要數(shù)據(jù)。
所有這些信息都存儲(chǔ)在 MxThree 結(jié)構(gòu)數(shù)組中。每個(gè)三角都有 status (狀態(tài)) 字段。它的初始值是 0。如果需要三角開(kāi)單, 狀態(tài)設(shè)置為 1。確認(rèn)三角完全開(kāi)單后, 狀態(tài)變?yōu)?2。如果三角形部分開(kāi)單, 或者平單時(shí)間已到, 則狀態(tài)變?yōu)?3。一旦三角成功平單, 狀態(tài)將返回到 0。
三角開(kāi)單和平單均被保存到一個(gè)日志文件, 令我們能夠檢查動(dòng)作的正確性并重溫歷史。日志文件名稱(chēng)為 Three Point Arbitrage Control YYYY.DD.MM.csv。
為了執(zhí)行測(cè)試, 請(qǐng)將所有必要的貨幣對(duì)載入到測(cè)試器。為此, 在運(yùn)行測(cè)試器之前, 在 "創(chuàng)建品種文件" 模式中啟動(dòng) EA。如果不存在這樣的文件, EA 將在默認(rèn)的 EUR + GBP + USD 三角上運(yùn)行測(cè)試。
使用的變量
在我的開(kāi)發(fā)過(guò)程中, 任何機(jī)器人的代碼都是從包含頭文件開(kāi)始的。它會(huì)列出所有包含內(nèi)容, 函數(shù)庫(kù), 等等。這個(gè)機(jī)器人也不例外: 說(shuō)明模塊之后緊隨 #include "head.mqh" 等等:
#include <Trade\Trade.mqh> #include <Trade\SymbolInfo.mqh> ? #include <Trade\TerminalInfo.mqh> #include "var.mqh" #include "fnWarning.mqh" #include "fnSetThree.mqh" #include "fnSmbCheck.mqh" #include "fnChangeThree.mqh" #include "fnSmbLoad.mqh" #include "fnCalcDelta.mqh" #include "fnMagicGet.mqh" #include "fnOpenCheck.mqh" #include "fnCalcPL.mqh" #include "fnCreateFileSymbols.mqh" #include "fnControlFile.mqh" #include "fnCloseThree.mqh" #include "fnCloseCheck.mqh" #include "fnCmnt.mqh" #include "fnRestart.mqh" #include "fnOpen.mqh"
此列表目前對(duì)您來(lái)說(shuō)也許無(wú)法完全理解, 但本文會(huì)遵循這些代碼, 因此程序結(jié)構(gòu)在此并未被違反。往下一切都將變得清晰。所有函數(shù), 類(lèi)和代碼單元都放在單獨(dú)的文件中, 以方便使用。就我而言, 除了標(biāo)準(zhǔn)庫(kù)之外, 每個(gè)包含文件也以 #include "head.mqh" 開(kāi)頭。允許在包含文件中使用 IntelliSense (智能感知), 因此不必在內(nèi)存中保存所有必要實(shí)體的名稱(chēng)。
之后, 為測(cè)試器連接文件。赫茲量化不能在任意地方進(jìn)行這一步, 所以我們要在此聲明。這個(gè)字符串是多幣種測(cè)試器加載品種所需的:
#property tester_file FILENAME
接下來(lái), 赫茲量化描述程序中使用的變量。描述可以在單獨(dú)的 var.mqh 文件中找到:
// 宏定義 #define DEVIATION ? ? ? 3 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? // 最大可能的滑點(diǎn) #define FILENAME ? ? ? ?"Three Point Arbitrage.csv" ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? // 操作品種存儲(chǔ)在這里 #define FILELOG ? ? ? ? "Three Point Arbitrage Control " ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?// 日志文件名稱(chēng)部分 #define FILEOPENWRITE(nm) ?FileOpen(nm,FILE_UNICODE|FILE_WRITE|FILE_SHARE_READ|FILE_CSV) ?// 打開(kāi)文件寫(xiě)入 #define FILEOPENREAD(nm) ? FileOpen(nm,FILE_UNICODE|FILE_READ|FILE_SHARE_READ|FILE_CSV) ? // 打開(kāi)文件讀取 #define CF ? ? ? ? ? ? ?1.2 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? // 提高保證金比例 #define MAGIC ? ? ? ? ? 200 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? // 應(yīng)用的魔幻數(shù)字范圍 #define MAXTIMEWAIT ? ? 3 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? // 三角開(kāi)單后的最長(zhǎng)等待時(shí)間, 以秒為單位 // 貨幣對(duì)結(jié)構(gòu) struct stSmb ? { ? ? ?string ? ? ? ? ? ?name; ? ? ? ? ? ?// 貨幣對(duì) ? ? ?int ? ? ? ? ? ? ? digits; ? ? ? ? ?// 報(bào)價(jià)中的小數(shù)位數(shù) ? ? ?uchar ? ? ? ? ? ? digits_lot; ? ? ?// 手?jǐn)?shù)的四舍五入小數(shù)位數(shù) ? ? ?int ? ? ? ? ? ? ? Rpoint; ? ? ? ? ?// 1/point, 以便在方程中乘以 (而不是除以) ?該值 ? ? ?double ? ? ? ? ? ?dev; ? ? ? ? ? ? // 可能的滑點(diǎn)。一次性轉(zhuǎn)換成點(diǎn)數(shù) ? ? ?double ? ? ? ? ? ?lot; ? ? ? ? ? ? // 貨幣對(duì)的交易量 ? ? ?double ? ? ? ? ? ?lot_min; ? ? ? ? // 最小交易量 ? ? ?double ? ? ? ? ? ?lot_max; ? ? ? ? // 最大交易量 ? ? ?double ? ? ? ? ? ?lot_step; ? ? ? ?// 手?jǐn)?shù)增量 ? ? ?double ? ? ? ? ? ?contract; ? ? ? ?// 合約大小 ? ? ?double ? ? ? ? ? ?price; ? ? ? ? ? // 在三角中的貨幣對(duì)開(kāi)單價(jià)。凈持模式需要 ? ? ?ulong ? ? ? ? ? ? tkt; ? ? ? ? ? ? // 交易開(kāi)單所用的訂單票號(hào)。對(duì)沖賬戶(hù)所需 ? ? ?MqlTick ? ? ? ? ? tick; ? ? ? ? ? ?// 當(dāng)前貨幣對(duì)價(jià)格 ? ? ?double ? ? ? ? ? ?tv; ? ? ? ? ? ? ?// 當(dāng)前分筆報(bào)價(jià) ? ? ?double ? ? ? ? ? ?mrg; ? ? ? ? ? ? // 當(dāng)前用于開(kāi)單的保證金 ? ? ?double ? ? ? ? ? ?sppoint; ? ? ? ? // 點(diǎn)差, 單位為點(diǎn)數(shù)的整數(shù)值 ? ? ?double ? ? ? ? ? ?spcost; ? ? ? ? ?// 當(dāng)前開(kāi)單的每手點(diǎn)差, 以資金為單位 ? ? ?stSmb(){price=0;tkt=0;mrg=0;} ? ? }; // 三角結(jié)構(gòu) struct stThree ? { ? ? ?stSmb ? ? ? ? ? ? smb1; ? ? ?stSmb ? ? ? ? ? ? smb2; ? ? ?stSmb ? ? ? ? ? ? smb3; ? ? ?double ? ? ? ? ? ?lot_min; ? ? ? ? ?// 整個(gè)三角的最小交易量 ? ? ?double ? ? ? ? ? ?lot_max; ? ? ? ? ?// 整個(gè)三角的最大交易量 ? ? ?ulong ? ? ? ? ? ? magic; ? ? ? ? ? ?// 三角的魔幻數(shù)字 ? ? ?uchar ? ? ? ? ? ? status; ? ? ? ? ? // 三角狀態(tài)。0 - 未使用。1 - 發(fā)送開(kāi)單。2 - 成功開(kāi)單。3 - 發(fā)送平單 ? ? ?double ? ? ? ? ? ?pl; ? ? ? ? ? ? ? // 三角盈利 ? ? ?datetime ? ? ? ? ?timeopen; ? ? ? ? // 發(fā)送三角開(kāi)單的時(shí)間 ? ? ?double ? ? ? ? ? ?PLBuy; ? ? ? ? ? ?// 買(mǎi)入三角時(shí)的潛在利潤(rùn) ? ? ?double ? ? ? ? ? ?PLSell; ? ? ? ? ? // 拋售三角時(shí)的潛在利潤(rùn) ? ? ?double ? ? ? ? ? ?spread; ? ? ? ? ? // 所有三個(gè)點(diǎn)差的總價(jià) (含傭金!) ? ? ?stThree(){status=0;magic=0;} ? }; ? // EA 操作模式 ? enum enMode ? { ? ? ?STANDART_MODE ?= ?0, /*Symbols from Market Watch*/ ? ? ? ? ? ? ? ? ?// 標(biāo)準(zhǔn)操作模式。市場(chǎng)觀察品種 ? ? ?USE_FILE ? ? ? = ?1, /*Symbols from file*/ ? ? ? ? ? ? ? ? ? ? ? ? ?// 使用品種文件 ? ? ?CREATE_FILE ? ?= ?2, /*Create file with symbols*/ ? ? ? ? ? ? ? ? ? // 為測(cè)試器或操作創(chuàng)建文件 ? ? ?//END_ADN_CLOSE ?= ?3, /*Not open, wait profit, close & exit*/ ? ? ?// 您的所有交易平單并結(jié)束操作 ? ? ?//CLOSE_ONLY ? ? = ?4 ?/*Not open, not wait profit, close & exit*/ ? }; stThree ?MxThree[]; ? ? ? ? ? // 主數(shù)組存儲(chǔ)正在操作的三角和所有必要的附加數(shù)據(jù) CTrade ? ? ? ? ctrade; ? ? ? ?// 標(biāo)準(zhǔn)庫(kù)的 CTrade 類(lèi) CSymbolInfo ? ?csmb; ? ? ? ? ?// 標(biāo)準(zhǔn)庫(kù)的 CSymbolInfo 類(lèi) CTerminalInfo ?cterm; ? ? ? ? // 標(biāo)準(zhǔn)庫(kù)的 CTerminalInfo 類(lèi) int ? ? ? ? glAccountsType=0; // 賬戶(hù)類(lèi)型: 對(duì)沖或凈持 int ? ? ? ? glFileLog=0; ? ? ?// 日志文件句柄 // 輸入 sinput ? ? ?enMode ? ? ?inMode= ? ? 0; ? ? ? ? ?// 操作模式 input ? ? ? double ? ? ?inProfit= ? 0; ? ? ? ? ?// 傭金 input ? ? ? double ? ? ?inLot= ? ? ?1; ? ? ? ? ?// 交易量 input ? ? ? ushort inMaxThree= 0; ? ? ? ? ?// 三角已開(kāi)單 sinput ? ? ?ulong ? ? ? inMagic= ? ?300; ? ? ? ?// EA 魔幻數(shù)字 sinput ? ? ?string ? ? ?inCmnt= ? ? "R "; ? ? ? // 注釋
由于它們很簡(jiǎn)單并附有注釋, 故先行定義。我相信, 它們很容易理解。