引子
我是一個碼農(nóng),一個程序員,一個開發(fā)者。1998年上大學(xué),計算機(jī)科學(xué)與技術(shù)專業(yè),畢業(yè)后一直工作在軟件開發(fā)行業(yè)一線。十幾年之后的2016年,陰差陽錯開始接觸外匯交易行業(yè),嘗試使用碼農(nóng)的方法開始追求財務(wù)自由。
市場上幾乎所有的外匯交易書籍都會強(qiáng)調(diào)“交易系統(tǒng)”的重要性。想實現(xiàn)穩(wěn)定收益,必須要遵守交易紀(jì)律,完全按照事先制定好的交易系統(tǒng)執(zhí)行。在交易中不要思考,不能臨時改變主意,越是機(jī)械,越是死板越好。但是建立這個“系統(tǒng)”卻需要交易者常年累月的經(jīng)驗積累和對系統(tǒng)的不停改進(jìn)。我是外行,沒有經(jīng)驗;也沒有那么多時間和精力去操作1年以上的模擬盤來犯那些該犯得錯誤。而且,我現(xiàn)在還有一份全職的工作,沒法每天看盤幾個小時。所以,只能走另外的路徑。
我用工具,我寫程序,我把從別人書里學(xué)到的系統(tǒng)寫成EA,跑歷史數(shù)據(jù)驗證。從驗證中,我找到入市信號、途中頭寸管理(加減倉)、出場點;學(xué)習(xí)、分析、理解各個系統(tǒng)原型的原理、優(yōu)缺點,適應(yīng)狀況。
學(xué)習(xí)MT4和MQL4時,我參考了兩本書。一本是 《MetaTrader4 外匯自動交易圣經(jīng)》Dave C 王彤 劉斌 編著,中國經(jīng)濟(jì)出版社出版。另一本是《Expert Advisor Programming -- Creating Automated Trading Systems in MQL for MetaTrader 4》 Andrew R. Young , EDGEHILL PUBLISHING。
中文的那一本看起來很像是英文版的翻譯和改編,目錄章節(jié)都是基本一模一樣??赡苓@也是作者特意表明 “編著”的原因。
關(guān)于MQL4 和 MQL5
從MQL4 build 600 之后,MetaQuest對MQL4做了巨大修改,(也許應(yīng)該叫MQL4.5?)引入了很多MQL5的內(nèi)容(Python3在一邊看著,不說話),并且把MetaEditor也就是MQL的IDE進(jìn)行了統(tǒng)一。
我上手晚,用的是MetaEditor version 5.0 build 1351, 04 Jul 2016。在實際中發(fā)現(xiàn)build 600之后的與上面書里中一些內(nèi)容對不上號,比如那四個事件觸發(fā)函數(shù)。本文全文使用的都是build600之后的版本,在2016年以后應(yīng)該可以算是開箱可用。
MT4基本介紹
外匯散戶使用最廣泛的是MetaTrader4 軟件平臺。這個平臺上有自己的MQL4語言來于系統(tǒng)交互,執(zhí)行用戶制定的邏輯判斷、分析算法和交易動作。
MT4其實和各種“專業(yè)”軟件很相似,如果你使用過工程軟件(比如AutoCAD、IC Designer等等),并且為其寫過擴(kuò)展程序,就更容易掌握這種思想。這些軟件都是在系統(tǒng)平臺里集成了一門語言、解釋器,依賴該語言的能力處理邏輯、計算以及文件讀寫、網(wǎng)絡(luò)通信等通用功能,再把自己平臺的功能細(xì)化并封裝成各個函數(shù)“命令”供用戶調(diào)用,給用戶二次開發(fā)和實現(xiàn)復(fù)雜功能的能力。
MetaTrader4 是windows下的軟件,在Mac OS X下使用PlayOnMac和Wine來模擬運行環(huán)境,已經(jīng)很成熟,官方網(wǎng)站上有安裝說明,可以放心使用。
MT4主要有幾個模塊:(可以再Menu View里打開和關(guān)閉)
- 導(dǎo)航欄 -- Navigator
- 圖表窗口 -- Chart
- 數(shù)據(jù)窗口 -- Data Window
- 控制終端窗口 -- Terminal
- EA測試器 -- Strategy Tester
在開發(fā)時,用的最多的是 Navigator和 Tester, 很多時候基本不看其他窗口。
除此之外,還有一個MQL4的IDE -- MetaEditor。
和市場上的大部分IDE相同,MetaEditor也把屏幕切分成上有Menu和Toolbar,左有Navigator,中有Editor,下有Console(Toolbox)四部分。Editor支持語法高亮,自動補全等等功能。
MQL4是一門類似C的語言,或是說是一種擴(kuò)展了的C語言,有基礎(chǔ)的同行很容易上手。但是對于專業(yè)碼農(nóng),這MQL卻在空格縮進(jìn)、變量、函數(shù)名大小寫這種代碼風(fēng)格上很值得吐槽。我忍,誰叫這是為了賺錢做生意而不是追求碼農(nóng)的自我修養(yǎng)呢。
在Editor里編寫完成EA程序后,需要compile成可執(zhí)行文件,系統(tǒng)后綴為.ex4。屏幕下方Console里的Errors Tab會顯示編譯結(jié)果,有沒有error或warning。之后就可以在MT4中使用這個EA了,不論是應(yīng)用在圖表交易上還是進(jìn)行歷史數(shù)據(jù)測試。
MT4 MQL 文件目錄
作為約定MT4會把所有的開發(fā)EA相關(guān)文件放在它自己安裝目錄(以下用MT4_HOME代替)下的mql4目錄下。如果你的EA有讀寫文件操作,請在MT4_HOME/tester/files下尋找。
MQL 文件類型
- EA
可以附在圖表上進(jìn)行,監(jiān)聽系統(tǒng)產(chǎn)生的Tick事件,被調(diào)用而進(jìn)行交易。 - Indicator 指標(biāo)
附在圖標(biāo)上,監(jiān)聽系統(tǒng)Tick,但是不能下單?TODO - Script
一次性執(zhí)行的腳本程序,由OnStart() 觸發(fā)。
再看看,還不會 TODO
MQL4 簡單文件結(jié)構(gòu)
- 頭部變量定義
-- #property
-- #include
-- #input
EA的各個輸入?yún)?shù),在MQL中是全局變量。在之前的版本中使用extern 關(guān)鍵字定義 - 函數(shù)
-- int OnInit() 構(gòu)造函數(shù)?
-- void OnTick() 事件循環(huán)?
-- void OnDeinit() 析構(gòu)函數(shù)?
-- void OnTimer() 時間觸發(fā)?
-- double OnTester() Tester最后匯總用?
-- void OnChartEvent() ?
-- void OnStart() 不是給EA用的,而是給一次性運行的script使用。
對于經(jīng)驗豐富的碼農(nóng)來說,這幾個函數(shù)全是callback,或是說系統(tǒng)里定義好的interface,留給我們自己實現(xiàn)。對應(yīng)的事件觸發(fā)時,會執(zhí)行相應(yīng)的函數(shù)。
void OnStart() 函數(shù)
Script啟動時調(diào)用,如果你的EA里含有這個函數(shù),在新版的MT4中,會提示 “xx” is not expert and cannot be executed.
int OnInit() 函數(shù)
在程序初始時執(zhí)行,可以進(jìn)行全局變量的初始化等動作。在老版本的MQL4中,函數(shù)名為 int init(),現(xiàn)在為了和MQL5兼容,把幾個主要函數(shù)名都加入了On打頭。
下面例子里顯示了一些市場信息內(nèi)部變量,這是我們的交易中都必須使用的,具體會在后面介紹。
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
//--- create timer
EventSetTimer(60);
Print("Balance: ",AccountBalance());
Print("Equity: ",AccountEquity());
Print("TickValue: ",MarketInfo(Symbol(),MODE_TICKVALUE));
Print("Lot Size: ",GetSize());
Print("MINLOT: ",MarketInfo(Symbol(),MODE_MINLOT));
Print("MAXLOT: ",MarketInfo(Symbol(),MODE_MAXLOT));
Print("Symbol name of the current chart=",_Symbol);
Print("Timeframe of the current chart=",_Period);
Print("The latest known seller's price (ask price) for the current symbol=",Ask);
Print("The latest known buyer's price (bid price) of the current symbol=",Bid);
Print("Number of decimal places=",Digits);
Print("Number of decimal places=",_Digits);
Print("Size of the current symbol point in the quote currency=",_Point);
Print("Size of the current symbol point in the quote currency=",Point);
Print("Number of bars in the current chart=",Bars);
Print("Open price of the current bar of the current chart=",Open[0]);
Print("Close price of the current bar of the current chart=",Close[0]);
Print("High price of the current bar of the current chart=",High[0]);
Print("Low price of the current bar of the current chart=",Low[0]);
Print("Time of the current bar of the current chart=",Time[0]);
Print("Tick volume of the current bar of the current chart=",Volume[0]);
Print("Last error code=",_LastError);
Print("Random seed=",_RandomSeed);
Print("Stop flag=",_StopFlag);
Print("Uninitialization reason code=",_UninitReason);
//---
return(INIT_SUCCEEDED);
}
void OnTick()
這是MT4 事件循環(huán)觸發(fā)的最主要函數(shù),市場中的每個Tick事件,都會觸發(fā)該函數(shù)。我們的所有市場交易邏輯都在該函數(shù)中執(zhí)行。
基本上的邏輯是,每個Tick時,相應(yīng)的市場信息比如Bid,Ask,過去的bar數(shù)據(jù),各種指標(biāo)都會有相應(yīng)更新。我們的邏輯會按照“交易系統(tǒng)”的邏輯去分析現(xiàn)在市場情況,分析自己持倉情況,做出下列決定:1)買n手;2)賣n手;3)修改頭寸的Stop、Limit價;4)不動。
這里需要注意的是,每個Tick的時間很短,一個tick之后馬上就是下一個tick。我們的函數(shù)運行時間有很嚴(yán)格的限制,如果運行過慢,在下一個tick進(jìn)來的時候還沒有結(jié)束,會出現(xiàn)跳過該tick的后果。
對于單張圖表,MT4“看起來”是串行工作。處理完OnTick后,才會觸發(fā)下一個Tick。
這種串行工作方式乍看起來會損失很多精度,但是從模擬人類的角度看起來也沒什么問題。只要不是高頻交易,這點時間比起人類的判斷反應(yīng)時間上要快的多。只是不能對相鄰兩個Tick做假設(shè),因為它們的時間間隔是不固定,不保證的。
對于多個圖表上同時運行的EA,很遺憾他們也是非并行運行。而是輪換的方法搶奪運行時的權(quán)限。
最好把OnTick函數(shù)想象成HTTP的stateless 模型。每次只從DB中拿出狀態(tài)變量,重新判斷局勢然后做出反應(yīng)。
void OnDeinit()
這個函數(shù)是EA結(jié)束時被執(zhí)行,可以近似成析構(gòu)函數(shù),進(jìn)行內(nèi)存釋放、關(guān)閉文件句柄等clean up 任務(wù)。
識別市場情況
一個系統(tǒng)主要由三部分組成,入市,頭寸,出場。在市場的每個Tick到來時,都要首先分析市場的現(xiàn)狀。在手工分析和交易時,交易者會把主要精力放到觀察圖表上,根據(jù)圖表形狀,技術(shù)指標(biāo)來確定交易行為。
對于一個自動化交易的EA,第一步也是要取得市場上的所有信息,MQL4提供了MaketInfo()函數(shù)和一組預(yù)定義內(nèi)部變量供我們使用。
MarketInfo()
double MarketInfo(string symbol, int type)
type 包括
MODE_POINT
MODE_DIGITS
MODE_SPREAD
MODE_STOPLEVEL
MODE_BID
MODE_ASK
MODE_LOW
MODE_HIGH
MODE_TIME
MODE_TICKSIZE
MODE_TICKVALUE
MODE_EXPIRATION
MODE_FREEZELEVEL
MODE_STARTING
MODE_STOPLEVEL
MODE_SWAPLONG
MODE_SWAPSHORT
MODE_SWAPTYPE
MODE_LOTSIZE
MODE_LOTSTEP
MODE_MAXLOT
MODE_MINLOT
MODE_CLOSEBY_ALLOWED
寫個函數(shù)把它們都打出來看看
void report_marketinfo()
{
Print("START");
Print(MarketInfo(_Symbol,MODE_ASK)); // ask
Print(MarketInfo(_Symbol,MODE_BID)); // bid
Print(MarketInfo(_Symbol,MODE_CLOSEBY_ALLOWED)); // 0
Print(MarketInfo(_Symbol,MODE_DIGITS)); // 3 for USDJPY
Print(MarketInfo(_Symbol,MODE_EXPIRATION)); // 0
Print(MarketInfo(_Symbol,MODE_FREEZELEVEL)); // 0
Print(MarketInfo(_Symbol,MODE_HIGH)); // 0
Print(MarketInfo(_Symbol,MODE_LOTSIZE)); // 100000
Print(MarketInfo(_Symbol,MODE_LOTSTEP)); // 0.1
Print(MarketInfo(_Symbol,MODE_LOW)); // 0
Print(MarketInfo(_Symbol,MODE_MARGINCALCMODE)); // 0
Print(MarketInfo(_Symbol,MODE_MARGINHEDGED)); // 10000
Print(MarketInfo(_Symbol,MODE_MARGININIT)); // 0
Print(MarketInfo(_Symbol,MODE_MARGINMAINTENANCE)); //0
Print(MarketInfo(_Symbol,MODE_MARGINREQUIRED)); // 1553.84
Print(MarketInfo(_Symbol,MODE_MAXLOT)); // 50
Print(MarketInfo(_Symbol,MODE_MINLOT)); // 0.1
Print(MarketInfo(_Symbol,MODE_POINT)); // 0.001
Print(MarketInfo(_Symbol,MODE_PROFITCALCMODE)); // 1
Print(MarketInfo(_Symbol,MODE_SPREAD)); // 7
Print(MarketInfo(_Symbol,MODE_STARTING)); // 0
Print(MarketInfo(_Symbol,MODE_SWAPLONG)); // 0
Print(MarketInfo(_Symbol,MODE_SWAPSHORT)); // 0
Print(MarketInfo(_Symbol,MODE_SWAPTYPE)); // 0
Print(MarketInfo(_Symbol,MODE_TICKSIZE)); // 0.001
Print(MarketInfo(_Symbol,MODE_TICKVALUE)); // 0.9980836
Print(MarketInfo(_Symbol,MODE_TIME)); // looks like cpu time, in
Print(MarketInfo(_Symbol,MODE_TIME)); // 1470182399 system epoch time, in second, use http://www.epochconverter.com/ to convert
Print("END PRINT");
//
}
預(yù)定義變量
https://docs.mql4.com/cn/predefined
_Digits
_Point
_LastError
_Period
_RandomSeed
_StopFlag
_Symbol
_UninitReason
Ask
Bars
Bid
Close (array)
Digits
High (array)
Low (array)
Open (array)
Point
Time (array)
Volume (array)
其他函數(shù)
AccountBalance()
AccountEquity()
如何使用MQL4分析現(xiàn)在的圖形
識別單根K線
在交易上我是純外行,對K線戰(zhàn)法只有書本上的認(rèn)識。下面爭取用MQL來識別《外匯交易實戰(zhàn)全典》書中提到的幾種K線形態(tài)。
正常性
大陰線、陽線 (光頭光腳)
OCHL