股票量化軟件:信息的存儲和閱覽
2. EA交易自己的記錄文件
就像我說的那樣, Print()函數(shù)在記錄EA交易運行時生成的信息時并不總是那么方便. 特別是當有幾個EA交易同時在一個相同終端上運行時就更加明顯. 每個EA交易都把它自己的信息寫到記錄文件中, 這樣就很難在其中找東西了. 這種情況下, 對此類信息的分析就不用提了:這非常費力和麻煩.赫茲量化軟件
這個問題可以用比較簡單的方法解決. 每個EA交易必須有它自己的記錄文件. 信息都會被寫進這些獨立的記錄文件, 而不是寫進一個通用的文件中. 為了盡可能簡單地使用此方式, 讓我們把代碼寫成一個函數(shù).赫茲量化軟件
以下就是描述這個函數(shù)必須做到的:
使用唯一名稱來創(chuàng)建文件di
當有需要時在其中寫入信息
當EA交易結(jié)束運行時關(guān)閉文件, 以便其他應(yīng)用程序可以使用該文件
清晰明了. 唯一有爭議的一點是是否有必要在寫完每個記錄時關(guān)閉文件. 一方面, 這樣就可以在EA交易運行過程中使用其他應(yīng)用程序打開此文件了. 但是, 另一方面, 這樣對EA交易進行下一條記錄可能是不利的, 因為文件可能被其他應(yīng)用程序使用了. 如果出現(xiàn)這種情況, 信息可能就直接丟掉了. 這是不能允許的, 特別是有些程序打開文件只是為了讀取, 而不愿影響 赫茲量化軟件 的運行.赫茲量化軟件
因為打開和關(guān)閉文件只進行一次, 對應(yīng)的代碼可以分別放到 init() 和 deinit() 函數(shù)中. 為了讓它只占用最小的空間, 讓我們把它們也做成函數(shù):赫茲量化軟件
int log_handle = -1; //+------------------------------------------------------------------+ // void log_open( string ExpertName = "Expert" ) // // 用于打開EA交易獨立記錄文件的函數(shù). // 創(chuàng)建文件的目錄: // "...\MetaTrader 4\experts\files\logs\ExpertName\" // 文件名就是文件的記錄日期, 格式為 "YYYY.MM.DD" //+------------------------------------------------------------------+ void log_open( string ExpertName = "Expert" ) { ???? string log_name = "logs\\" + ExpertName + " (" + Symbol() + ", " + ?????????????????? strPeriod( Period() ) + ")\\" + TimeToStr( LocalTime(), ?????????????????? TIME_DATE ) + ".txt"; ??log_handle = FileOpen ( log_name, FILE_READ | FILE_WRITE, " " ); ???? ??if ( log_handle < 0 ) ???? { ???????? int _GetLastError = GetLastError(); ????Print( "FileOpen( ", log_name, ", FILE_READ | FILE_WRITE, \" \" ) - 錯誤 #", ???????????????????? _GetLastError ); ????return(-1); ?? } } string strPeriod( int intPeriod ) { ???? switch ( intPeriod ) ???? { ??????????case PERIOD_MN1: return("Monthly"); ????case PERIOD_W1:??return("Weekly"); ????case PERIOD_D1:??return("Daily"); ????case PERIOD_H4:??return("H4"); ????case PERIOD_H1:??return("H1"); ????case PERIOD_M30: return("M30"); ????case PERIOD_M15: return("M15"); ????case PERIOD_M5:??return("M5"); ????case PERIOD_M1:??return("M1"); ????default:????????return("UnknownPeriod"); ?? } } //+------------------------------------------------------------------+ // log_close() // // 用于關(guān)閉EA交易自身記錄文件的函數(shù). //+------------------------------------------------------------------+ void log_close() { ???? if ( log_handle > 0 ) FileClose( log_handle ); }
現(xiàn)在我們有了一個打開的文件, 可以在里面寫信息了. 為此:
把光標移動到文件末尾, 這樣不會丟失信息;
把記錄時間寫在每行開頭, 這將有助于分析;
把文字寫到文件中;
把文件存儲在磁盤上;如果EA交易意外出錯退出, 數(shù)據(jù)也不會丟失
以下就是滿足上面需求的函數(shù):赫茲量化軟件
//+------------------------------------------------------------------+ // log( string text ) // // 把文本行寫入EA交易自身記錄文件的函數(shù). //+------------------------------------------------------------------+ void log( string text ) { ???? int _GetLastError = 0; ??if ( log_handle < 0 ) ???? { ???????? Print( "寫入記錄錯誤!文本: ", text ); ????return(-1); ?? } ???? ???? //---- 把文件指針移動到文件末尾 ????if ( !FileSeek ( log_handle, 0, SEEK_END ) ) ??????{ ???????? _GetLastError = GetLastError(); ????Print( "FileSeek ( " + log_handle + ", 0, SEEK_END ) - 錯誤 #", ??????????_GetLastError ); ????return(-1); ??} ????//---- 如果EA要寫的一行內(nèi)容不包含換行符, ????//---- 在一行的開始部分增加記錄時間 ????if( text != "\n" && text != "\r\n" ) ???????? text = StringConcatenate( TimeToStr( LocalTime(), TIME_SECONDS ), ???????????????????????????? " - - - ", text ); ????if( FileWrite ( log_handle, text ) < 0 ) ??????????{ ???????????? _GetLastError = GetLastError(); ???? Print( "FileWrite ( ", log_handle, ", ", text, " ) - Error #", ?????????? _GetLastError ); ???? return(-1); ????} ???? ????//---- 把寫下的文字寫到磁盤上 ????FileFlush( log_handle ); }
現(xiàn)在, Print 這個詞可以在所有的EA交易中使用log來替換了, 另外不要忘記調(diào)用 log_open 和 log_close 函數(shù).赫茲量化軟件
這是一個使用log.mq4包含文件的非常簡單的EA交易:
#include <log.mq4> int init() ??{ ????log_open( "log_test" ); ????log( "記錄文件已經(jīng)被成功打開, EA交易開始工作..." ); ????return(0); ??} int deinit() ??{ ????log( "關(guān)閉記錄文件, EA交易結(jié)束工作..." ); ????log_close(); ????return(0); ??} int start() ??{ ????log( "新訂單: Bid = " + DoubleToStr( Bid, Digits ) ); ????return(0); ??}
3. 信息的顯示
現(xiàn)在, 當我們解決了記錄文件的問題之后, 我們可以開始"裝飾"顯示的信息了.
首先, 讓我們考慮實現(xiàn)這個任務(wù)的所有可能方法. 在 MQL4 中, Comment() 函數(shù)是用于顯示信息的, 但是它不適合以上描述的需求. 所以我們必須找到其他的解決方案. 一個很好的例子是含有文本的對象. 有兩類這樣的對象: "文本(Text)" 和 "文本標簽(Text Label)". 它們之間的基本區(qū)別就是, "文本"綁定于圖表的坐標(價格和時間), 而"文本標簽"綁定的是窗口坐標. 因為我們需要信息在圖表移動或者縮放改變的時候依然停留在原點上, 所以我們會使用"文本標簽".赫茲量化軟件
在MQL5中有一些函數(shù)用于創(chuàng)建和控制對象, 所有的名字都以O(shè)bject開頭. 讓我們看看它們?nèi)绾畏?wù)于我們的目標:
bool ObjectCreate(...) – 創(chuàng)建一個對象;
bool ObjectDelete(...) – 使用過后刪除對象;
bool ObjectSet(...) – 修改對象屬性, 例如錨點 (x,y);
bool ObjectSetText(...) – 顯示文字;
void ObjectsRedraw() – 在文本改變之后重繪對象.
這就是我們要做的:
在EA交易的 init() 函數(shù)中, 創(chuàng)建用于顯示信息的對象;
在EA交易的 deinit() 函數(shù)中, 刪除所有創(chuàng)建的對象;
在 start() 函數(shù)里, 可以修改文字, 字體顏色和所創(chuàng)建對象的大小.
我們將會再一次得到3個函數(shù), 每個都完成自己的任務(wù).
在寫代碼之前, 我想先說一下"文本標簽"使用中的一個令人不愉快的局限. 它只能是一行, 也就是說, 它不能包含任何換行字符. 但是如果信息能夠分成幾行顯示會更好. 這就是為什么我們會創(chuàng)建多個對象, 然后在其中分配數(shù)據(jù). 我制作了5"行", 但是您可以使用任何其他的行數(shù).赫茲量化軟件
另外, 顯示文字的長度也有一個限制. 所以我增加了第二"列", 也就是說, 右側(cè)又多了5行.
這就是用于創(chuàng)建對象的 info_init() 函數(shù)看起來的樣子: