股票量化交易軟件:跳空缺口是能夠獲利的策略還是五五開?

在這里赫茲股票量化將會在股票市場上檢驗 D1 上的跳空缺口,市場繼續(xù)按照缺口方向變化會有多么頻繁呢?市場在出現(xiàn)跳空缺口后會反轉(zhuǎn)嗎?我將會在這篇文章中嘗試回答這些問題, 同時會使用自定義的 CGraphic 圖表來顯示結(jié)果。交易品種的文件是使用系統(tǒng)的 GetOpenFileName DLL 函數(shù)來選擇的。

選擇哪一個市場?
我只對D1時段中的跳空缺口有興趣,
很明顯,與商品交易品種相比, 股票中發(fā)現(xiàn)的跳空缺口要多得多, 因為股票是從早上到晚上交易的, 而不是連續(xù)的。我對股票特別有興趣,因為它們有相對長的歷史,而期貨從另一方面看就不是非常適合,因為它們的生命周期經(jīng)常只有三或六個月,這對于在D1時段上對歷史做研究就不夠。
在文檔"數(shù)據(jù)訪問處理"部分中的 TestLoadHistory.mq5 腳本可以定義當(dāng)前交易品種的數(shù)量和服務(wù)其上存在的D1時段的柱數(shù)。下面是一個用于檢查 ABBV 交易品種D1時段柱數(shù)的例子:

編輯
圖 1. ABBV 交易品種
過程如下:
首先,保存在文檔中所描述的腳本,為此,要在 MetaEditor 5 ("創(chuàng)建一個腳本") 中創(chuàng)建一個新的腳本,讓赫茲股票量化把它命名為 TestLoadHistory.mq5?,F(xiàn)在,赫茲股票量化需要從文檔中復(fù)制腳本文本,然后粘貼到 TestLoadHistory.mq5 腳本中 (所粘貼的文字應(yīng)當(dāng)替換掉腳本中的全部文字)。
編譯得到的腳本 (在編譯之后,腳本在終端的導(dǎo)航器窗口中就可以看到了),
在 MetaTrader 5 中運行腳本。因為檢查是為 ABBV 交易品種進行的, 我們需要準(zhǔn)備圖表: 打開 ABBV 交易品種的圖表并把時段設(shè)為 D1,從導(dǎo)航器窗口選擇腳本并且在 ABBV 圖表上運行它,在腳本參數(shù)中,把交易品種名稱設(shè)為 ABBV,選擇 D1 時段并把1970年設(shè)為日期:

編輯切換為居中
圖 2. 運行 TestLoadHistory.mq5 腳本
腳本運行結(jié)果:
TestLoadHistory (ABBV,D1) ? ? ? Start loadABBV,Dailyfrom1970.03.16 00:00:00 TestLoadHistory (ABBV,D1) ? ? ? Loaded OK TestLoadHistory (ABBV,D1) ? ? ? First date 2015.09.18 00:00:00 - 758 bars
— 歷史從 2015 年開始并且含有 758 個 D1 柱。這個數(shù)字對于分析是足夠了。
操作一組交易品種
為了分析和計算任何標(biāo)準(zhǔn),赫茲股票量化都需要比較一個交易品種組中的交易品種。按照規(guī)則,MetaTrader 5 終端中的交易品種已經(jīng)分組 (在市場報價窗口中用鼠標(biāo)右鍵點擊和選擇交易品種,或者按下 Ctrl + U):

編輯
圖 3. NASDAQ (SnP100) 組的交易品種
在圖中NASDAQ(SnP100)組就被選中了,這個組中就包括 ABBV 交易品種。操作一組交易品種的最方便的方法就是確保腳本是從這個組的交易品種中運行的,為了在每個組中做迭代,赫茲股票量化需要從每個組中手動打開一個交易品種圖表并運行 Symbols on symbol tree.mq5 工具腳本 — 這個腳本會把所有組里的交易品種 (交易品種名稱) 收集到一個單獨的文件中。
Symbols on symbol tree.mq5 腳本是根據(jù)下面的算法來工作的: 在 SYMBOL_PATH 交易品種樹中取得路徑;從取得的路徑中讀取最終的交易品種組 (這里就是 NASDAQ(SnP100) 組); 從這個組中選擇所有的交易品種并把選中的交易品種保存到一個文件中。在交易品種樹中,路徑中的文件名稱里面,所有的 "/" 和 "\" 字符都使用 "_" 代替(代替過程是在腳本中自動進行的,文件名稱也是自動生成的)。在替換了字符之后,為 NASDAQ(SnP100) 交易品種組生成的名稱如下: "Stock Markets_USA_NYSE_NASDAQ(SnP100)_.txt".
為什么赫茲股票量化需要把每個組放到單獨的文件中呢?因為這樣我們就能夠從組文件中直接簡單讀取交易品種名稱了,而不用迭代所有的交易品種再進行缺口的分析。也就是說,Symbols on symbol tree.mq5 工具腳本可以去掉從指定的交易品種組中選擇交易品種的過程。
Symbols on symbol tree.mq5 script
讓我們研究一下腳本的運行。
請注意: 只有在專家頁面中出現(xiàn) "Everything is fine. There are no errors" 的文字信息才能保證腳本的工作已經(jīng)成功,并且所得到的文件可以用于將來的工作!
為了縮短文件操作的代碼, 包含了 CFileTxt 類, 而對文本文件的操作是由 m_file_txt — CFileTxt 類對象來完成的。腳本的工作可以分成七步:
//+------------------------------------------------------------------+ //| ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? Symbols on symbol tree.mq5 | //| ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?Copyright ? 2018, Vladimir Karputov | //| ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? http://wmua.ru/slesar/ | //+------------------------------------------------------------------+ #property copyright "Copyright ? 2018, Vladimir Karputov" #property link ? ? ?"http://wmua.ru/slesar/" #property version ? "1.000" //--- #include <Files\FileTxt.mqh> CFileTxt ? ? ? m_file_txt; ? ? ? // 文本文件對象 //--- string ? m_file_name=""; ? ? ? ? // 文件名 //+------------------------------------------------------------------+ //| 腳本程序起始函數(shù) ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?| //+------------------------------------------------------------------+ void OnStart() ?{ //--- 第一步 ? string current_path=""; ? if(!SymbolInfoString(Symbol(),SYMBOL_PATH,current_path)) ? ? { ? ? ?Print("ERROR: SYMBOL_PATH"); ? ? ?return; ? ? } //--- 第二步 ? string sep_="\\"; ? ? ? ? ? ? ? ? // 分隔符字符 ? ushort u_sep_; ? ? ? ? ? ? ? ? ? ?// 用于分隔字符的代碼 ? string result_[]; ? ? ? ? ? ? ? ? // 用于取得字符串的數(shù)組 //--- 取得分隔符代碼 ? u_sep_=StringGetCharacter(sep_,0); //--- 把字符串分成子字符串 ? int k_=StringSplit(current_path,u_sep_,result_); //--- 第三步 //--- 現(xiàn)在輸出所有取得的字符串 ? if(k_>0) ? ? { ? ? ?current_path=""; ? ? ?for(int i=0;i<k_-1;i++) ? ? ? ? current_path=current_path+result_[i]+sep_; ? ? } //--- 第四步 ? string symbols_array[]; ? int symbols_total=SymbolsTotal(false); ? for(int i=0;i<symbols_total;i++) ? ? { ? ? ?string symbol_name=SymbolName(i,false); ? ? ?string symbol_path=""; ? ? ?if(!SymbolInfoString(symbol_name,SYMBOL_PATH,symbol_path)) ? ? ? ? continue; ? ? ?if(StringFind(symbol_path,current_path,0)==-1) ? ? ? ? continue; ? ? ?int size=ArraySize(symbols_array); ? ? ?ArrayResize(symbols_array,size+1,10); ? ? ?symbols_array[size]=symbol_name; ? ? } //--- 第五步 ? int size=ArraySize(symbols_array); ? if(size==0) ? ? { ? ? ?PrintFormat("ERROR: On path \"%s\" %d symbols",current_path,size); ? ? ?return; ? ? } ? PrintFormat("On path \"%s\" %d symbols",current_path,size); //--- 第六步 ? m_file_name=current_path; ? StringReplace(m_file_name,"\\","_"); ? StringReplace(m_file_name,"/","_"); ? if(m_file_txt.Open("5220\\"+m_file_name+".txt",FILE_WRITE|FILE_COMMON)==INVALID_HANDLE) ? ? { ? ? ?PrintFormat("ERROR: \"%s\" 文件沒有在通用數(shù)據(jù)文件夾中創(chuàng)建",m_file_name); ? ? ?return; ? ? } //--- 第七步 ? for(int i=0;i<size;i++) ? ? ?m_file_txt.WriteString(symbols_array[i]+"\r\n"); ? m_file_txt.Close(); ? Print("Everything is fine. There are no errors"); //--- ?} //+------------------------------------------------------------------+
腳本運行的算法:
第一步: 為當(dāng)前交易品種定義 SYMBOL_PATH (交易品種樹中的路徑);
第二步: 取得的路徑使用"\"分隔符分成子字符串;
第三步: 重新組裝當(dāng)前路徑,不包括最后的子字符串,因為它包含著交易品種名稱;
第四步: 在所有可用交易品種中循環(huán);如果交易品種的路徑與當(dāng)前路徑匹配,就選擇交易品種名稱并把它加到偵測到的交易品種數(shù)組中;
第五步: 檢查偵測到的交易品種數(shù)組的大小;
第六步: 生成文件名 (從名字中刪除 "/" 和 "\" 字符,生成文件);
第七步: 把偵測到的交易品種數(shù)組寫到文件中并關(guān)閉它。
注意第六步: 文件是在通用文件目錄(使用了FILE_COMMON標(biāo)志)創(chuàng)建的。
另外,要確保腳本的運行沒有錯誤,應(yīng)該在專家頁面的記錄中出現(xiàn)下面的信息: "Everything is fine. There are no errors. Create file:". 文件的名稱在下一行顯示 — 復(fù)制它并把它粘貼到 "Getting gap statistics ..." 腳本中。成功生成的 文件在下面顯示:
On path "Stock Markets\USA\NYSE/NASDAQ(SnP100)\" 100 symbols Everything is fine. There are no errors. Create file: Stock Markets_USA_NYSE_NASDAQ(SnP100)_
這樣,我們就取得了文件 (這里它是 Stock Markets_USA_NYSE_NASDAQ(SnP100)_) 每行一個交易品種。文件的前五行:
AAPL ABBV ABT ACN AGN
收集數(shù)據(jù)
根據(jù)交易品種的 OHLC 歷史數(shù)據(jù)和統(tǒng)計計算是在主腳本 Getting gap statistics.mq5 中進行的,為每個交易品種都要填充 SGapStatistics 結(jié)構(gòu): struct SGapStatistics ? ? ?{ ? ? ? string ? ? ? ? ? ?name; ? ? ? ? ? ? ? ?// 交易品種名稱 int ? ? ? ? ? ? ? d1_total; ? ? ? ? ? ?// D1 柱的總數(shù) int ? ? ? ? ? ? ? gap_total; ? ? ? ? ? // 缺口的總數(shù) int ? ? ? ? ? ? ? gap_confirmed; ? ? ? // 確認(rèn)的缺口數(shù)量 ? ? ?}; name — 交易品種名稱d1_total — 根據(jù)交易品種的D1柱的數(shù)量gap_total — 偵測到的缺口數(shù)量gap_confirmed — 確認(rèn)過的缺口數(shù)量 (例如,一天是以向上的缺口開始,而收盤是上升的柱) 最適合用于為每個交易品種取得 OHLC 價格的函數(shù)就是 CopyRates. 赫茲股票量化將會使用它的第三種形式 — 根據(jù)所需時間段的起始和結(jié)束日期。對于開始時間,我們會使用 TimeTradeServer 交易服務(wù)器的當(dāng)前時間加上一天,而結(jié)束日期是1970年1月1日。 現(xiàn)在,赫茲股票量化所要做的就是定義如何處理錯誤 (請求結(jié)果返回了 "-1" ) 或者如何判斷是否所有的根據(jù)請求的數(shù)據(jù)都已返回 (例如,并不是所有數(shù)據(jù)都已經(jīng)從服務(wù)器上下載了)。我們可以用簡單的方法來做 (請求 — 暫停 N — 秒 — 新的請求),或者使用正確的方法。正確的方案是基于從文檔的"數(shù)據(jù)訪問處理" 部分中的TestLoadHistory.mq5腳本改進而得到的。