おはようございます。キリンです。
今日も7bitさんのライブラリーの解析をしていきます。
誰得路線まっしぐら。でも僕は楽しいのですw
何してるの?という方はpart1をどうぞ。
7bit氏作成 MQLライブラリー解析 part1
さて、今日はこれです。
ついに来ました。発注関数。
こいつの勉強が一番必要だと思ってたんですよね。
MT4で一番しっかりと管理しなければいけないのがこの発注関数です。
何も制御せずに発注を行うと、
MT4で業者側で約定拒否などざらで、さらに他のEAと同タイミングで別のEAが発注していた場合、
どちらかの注文が通らなくなってしまいます。
それを防ぐためにつくるのがこのような発注関数です。
さぁ、見ていきましょう。
int orderSendReliable( string symbol, int cmd, double volume, double price, int slippage, double stoploss, double takeprofit, string comment="", int magic=0, datetime expiration=0, color arrow_color=CLR_NONE){ int ticket; int err; Print("orderSendReliable(" + symbol + "," + cmd + "," + volume + "," + price + "," + slippage + "," + stoploss + "," + takeprofit + "," + comment + "," + magic + "," + expiration + "," + arrow_color + ")"); while(true){ if (IsStopped()){ Print("orderSendReliable(): Trading is stopped!"); return(-1); } RefreshRates(); if (cmd == OP_BUY){ price = Ask; } if (cmd == OP_SELL){ price = Bid; } if (!IsTradeContextBusy()){ ticket = OrderSend( symbol, cmd, volume, NormalizeDouble(price, MarketInfo(symbol, MODE_DIGITS)), slippage, NormalizeDouble(stoploss, MarketInfo(symbol, MODE_DIGITS)), NormalizeDouble(takeprofit, MarketInfo(symbol, MODE_DIGITS)), comment, magic, expiration, arrow_color ); if (ticket > 0){ Print("orderSendReliable(): Success! Ticket: " + ticket); return(ticket); // the normal exit } err = GetLastError(); if (isTemporaryError(err)){ Print("orderSendReliable(): Temporary Error: " + err + " " + ErrorDescription(err) + ". waiting."); }else{ Print("orderSendReliable(): Permanent Error: " + err + " " + ErrorDescription(err) + ". giving up."); return(-1); } }else{ Print("orderSendReliable(): Must wait for trade context"); } Sleep(MathRand()/10); }}
また結構なボリュームですw
上からの流れを説明していきます。
最初に「発注しますよ」というのをPrintで表しています。
これは特に説明不要です。
IsStoped()関数では、「EAが止まっていないか?」を判別できます。
リファレンスから言えば、
「チャートからプログラムを取り外すと、通貨ペアの変更や、チャート期間の変更、アカウントの変更、チャートが閉
じられる、クライアント ターミナルのシャットダウンと同様に、プログラムの実行が中断されます。もし、処理停止コマンドが与えられた時、この時点で start() 関数が実行されていた場合は、その処理の残り時間は 2.5秒に制限されます。プログラムは、IsStopped() の組み込み関数でシャットダウンして、正しく処理が終了される事を知ることができます。」
だそうです。要は、手動でEAを取り外すときは、start()が起動していれば2.5秒間だけ処理を継続して、処理を続けるってことですね。
あれ?でも、deinit()も2.5秒間だったような・・・
start()の残処理で2.5秒間使ってしまったら処理がdeinit()は起動するのでしょうか。
これについては明日書きます。
さて、次。
RefreshRates()は言わずと知れた、「チャートの表示中の価格にAskとBidを更新する」というもの。
発注リトライが5秒間続いたりすると、RefreshRates()をしなければ5秒前の価格でずっと発注をチャレンジしてしまうんですよね。
そして、注文の種類によって、priceを更新します。
次のIsTradeContexBusy()ですが、IsTradeAllowed()と機能がさほど変わりません・・・。
どちらがいいのでしょう。僕はIsTradeAllowed()派ですね。
違いは、IsTradeContexBusdy()は「他のEAが発注を行っているか」を見ます。
IsTradeAllowe()は、「他のEAが発注を行っていなくて、さらにAllow live tradingにチェックが入っているか」を
見ています。
次に、OrderSend()で実際に発注を行います。
priceやtp,slがNormalizeDoubleされているのは、4桁業者でたまーにバックデータに5桁のものが混入されているバグがあって、それを避けるためです。
正常に発注されると、OrderSend()はチケット番号を返します。
今回はそれをticketに値を置いています。
0より大きければ発注が正常終了したってことですね。
逆に、0以下の場合はエラーが起こっています。
そのエラーをGetLastError()でerrに格納。
面白いのが、isTemporaryError()という関数を用いている点ですね。
コイツの中身はこれ。
bool isTemporaryError(int error){ return( error == ERR_NO_ERROR || error == ERR_COMMON_ERROR || error == ERR_SERVER_BUSY || error == ERR_NO_CONNECTION || error == ERR_MARKET_CLOSED || error == ERR_PRICE_CHANGED || error == ERR_INVALID_PRICE || //happens sometimes error == ERR_OFF_QUOTES || error == ERR_BROKER_BUSY || error == ERR_REQUOTE || error == ERR_TRADE_TIMEOUT || error == ERR_TRADE_CONTEXT_BUSY );}
それぞれのエラーについてはこちらで確認してください。
上記のエラーだったら発注をリトライさせます。
逆に、上記エラー以外だったら発注をやめてしまいます。
滑った場合を考慮して、INVALID_STOPSをリトライの中に含めてもいいかなぁと思う僕。
最後が謎の、Sleep(MathRand()/10) で待機しています。
MathRand()とは、0 から 32767 の範囲内の擬似乱数の整数を返します。
なんでMathRand()なんでしょう?
長い時で3秒も待つのは結構辛い気がするんですが><
僕個人としては、一定間隔でいいのじゃないかなと思います。
豊嶋先生のMyOrderSend()と比較しても甲乙つけ難い関数でした。
MyOrderSend()の優秀さを表していますね。
ざくっと関数の説明をさせてもらいました。
ご参考になりましたら幸いです・・・。
今日もお読み下さり、ありがとうございます^^
コメント