2009/02/04
Mizutori_EAの説明(カスタムユーザー向け①)
表示にバグがありましたので修正しました。
Mizutori_EAの内部で何を行っているか、順に説明していきます。
(※本職の方が見たら、ホントでそれでいいのか?と問いかけたくなるところがあると思います。気になりましたコメントください。)
では、初期化関数から見ていきます。
※この初期化関数『init()』は、EAを作動した時に1度だけ作動する場所です。
一度だけ処理すれば、解決する内容を記載します。
int init()
{①
◆マジックナンバーの取得 ◆
Mc1Number = MYMAGIC + MagicfromSymbol();
【MagicfromSymbol()関数で処理した数値にMYMAGICを加えMc1Number(大域変数)に格納する。】
◆Profitの確認 ◆
TPf = Take_Profit();
【Take_Profit()関数で処理した数値をTPf(大域変数)に格納する。】
return(0);
}①
※後処理関数です。(省略可能)
int deinit()
{
return(0);
}
※ティックが更新するたびにスタート関数『start()』が呼び出されます。
◆ expert start function◆
int start() {
int Order = SIGNAL_NONE;
int pos1=0,pos2=0;
bool OderStop = false;
bool OderClose = false;
bool fbp = false;
bool fsp = false;
//double Profit =0;
int Now_Time = TimeCurrent();
【現在のサーバータイムをNow_Timeに格納】
//int NowDay = TimeDay(Now_Time);
int NowHour = TimeHour(Now_Time);
【現在のサーバータイムを時間軸(時)に変更し、NowHourに格納】
int NowMin = TimeMinute(Now_Time);
【現在のサーバータイムを時間軸(分)に変更して、NowMinに格納】
if(!IsTradeAllowed())return(0);
【もし取引が可能でなければ、start()関数終了】
◆オーダーの凍結 ◆
int NT,FrT,ExT;
if(Trade_Freeze)【もしTrade_Freezeが真(true)なら{から}までを実行する。】
{①
NT = (60*NowHour)+NowMin;
【(60*NowHour)+NowMin『現在のサーバータイム』をNTに格納】
※●時▽分を■×◎分に変換しています。
FrT = (60*Freeze_SH)+Freeze_SM;
【設定したオーダー凍結開始時間を分に変換してFrTに格納】
ExT = (60*Freeze_EH)+Freeze_EM;
【設定したオーダー凍結終了時間を分に変換してExTに格納】
if((FrT<ExT)&&(FrT<NT)&&(NT<ExT))OderStop = true;
【もし( )内の条件が真(true)ならOderStop に真を格納】
if((FrT>ExT)&&((FrT<NT)||(NT<ExT)))OderStop = true;
もし( )内の条件が真(true)ならOderStop に真を格納】
}①
◆週末制限 および制限 ◆
if(Weekend_Stop==true && DayOfWeek()== Stop_Day_Of_Week && NowHour>=Stop_Hours)OderStop = true;//週末のオーダーストップ
【もし( )内の条件が真(true)ならOderStop に真を格納】※DayOfWeek()は、現在のサーバータイムの曜日(日~土)を0から6の数値で表す関数です。
if(Weekend_Stop==true && DayOfWeek()>Stop_Day_Of_Week)OderStop = true;
【もし( )内の条件が真(true)ならOderStop に真を格納】
if(Weekend_Close==true && DayOfWeek()==Close_Day_Of_Week && NowHour>=Close_Hours)OderClose = true;//週末のオーダー強制決済
【もし( )内の条件が真(true)ならOderClose に真を格納】
if(Weekend_Close==true && DayOfWeek()>Close_Day_Of_Week)OderStop = true;
【もし( )内の条件が真(true)ならOderStop に真を格納】
◆最後に決済したオーダーの抽出 ◆
※1時間の間最後に決済されてから金額よりも悪い条件で取引することを防止するための仕様です。
int ht = OrdersHistoryTotal( )-1;
【過去のオーダー数 -1をhtに格納】
int ODT = 0;
for(int Z = ht ; Z>=0 ;Z--)
【過去のオーダー数回①{~}①内を繰り返す。Zは、過去のオーダー数からの引き算】
※過去のオーダーは、古いものから新しいもの(最後に決済したもの)の順に並んでいます。①一番古いもの・・・・・・・・・・⑩一番新しいもの
{①
if(OrderSelect(Z, SELECT_BY_POS, MODE_HISTORY) == true)//口座履歴の選択
【もし過去のデータファイルからデータを抜き出せたら{②~}②内を処理する。】
{ ②
if(OrderMagicNumber() != Mc1Number) continue;//マジックナンバー
【もしマジックナンバーが異なっていたらこの処理をスキップする。】
datetime HistoryLastTime = OrderCloseTime( ) ;//決済した時間
【決済した時間をHistoryLastTimeに格納する。】
double HistoryLastPrice = OrderOpenPrice( ) ;
【注文した時の価格をHistoryLastPriceに格納】
ODT = ODT+1;
【ODTに1を加える】
}②
if(HistoryLastPrice>0)break;
【HistoryLastPriceが0以上ならループから脱出する。】
}①
//ポジション取得の許可
int now =TimeHour(Now_Time-HistoryLastTime) ;
【現在の時間から最後に決済された時間を引いてnowに時間単位(時)で格納】
if((now>=1)||(ODT==0)||(Ask<=(HistoryLastPrice-(PipStep*Point))))fbp = true;
【もし(最後に決済されてから1時間以上経過した)または(過去のオーダーがない)または(最後に決済した価格よりもASKが下回ったら)fbpに真を格納する。】
if((now>=1)||(ODT==0)||(Bid>=(HistoryLastPrice+(PipStep*Point))))fsp = true;//
【もし(最後に決済されてから1時間以上経過した)または(過去のオーダーがない)または(最後に決済した価格よりもBidが上回ったら)fbpに真を格納する。】
if(!Sort_Order){fbp = true;fsp = true;}
【もしSort_Orderが真でなければ{ }を処理】
◆ オープンポジションの抽出◆
//ポジション数の確認およびラストオーダーの金額の抽出
※ポジションは、①古いオーダー・・・・⑤新しいオーダーの順で格納されています。
double LastPrice = 0;
for(int i=0;i<OrdersTotal();i++)【注文分繰り返す】
{①
if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES) == true){② //注文ポジションの選択
【もしデータファイルからデータを抜き出せたら{②~}②内を処理する。】
if(OrderMagicNumber() != Mc1Number) continue;//マジックナンバー
【マジックナンバーが異なればスキップ】
if(OrderType()==OP_BUY)pos1++;
【BUY注文があればpos1に1を追加する】
if(OrderType()==OP_SELL)pos2++;
【SELL注文があればpos2に1を追加する】
LastPrice=OrderOpenPrice();
【約定金額をLastPriceに格納】
}②
}①
int posX = pos1+pos2;
if((posX==0)||(posX > NumPos))
【もし( )内の条件のどちらかが真から{①}内を繰り返す。】
{①
NumPos=posX;
if(NumPos>1 && UseStopLoss )Changes_Stoploss(Mc1Number,NumPos);
【もしナンピン回数(オーダー数の合計)が更新されたら、Changes_Stoploss()関数にMc1Number,NumPosの条件を与えて処理させる。】
}①
◆ 時間軸による変更(サーバータイム[GTM+0] ◆
int NH = NowHour+ServerTime_GMT;
MaShift = MaShift_Custom(NH);
【MaShift_Custom( )にNHを与えて、その結果をMaShiftに格納】
Xox = Xox_Custom(NH);
【Xox_Custom( )にNHを与えて、その結果をXoxに格納】
※今回はここまでにしておきます。
2009/02/03
Mizutori_EAの説明(カスタムユーザー向け④)
前回の続きです。
※ご指示頂きましたので修正しました。(2009/2/11)
ここからは、注文・決済・注文の変更になりますが、汎用性を高くするために多くの無駄な作業が含まれています。
※不具合が見つかりました。不具合の場所を赤字で書いておきます。
◆ ポジションの決済 ◆
void ClosePositions(int Close_Type ,int Oder_Type ,int MagicNumber)
【void型の関数は、処理後の値がない関数(処理値を返さない関数です。)】
【ClosePositionsという名前の自作関数で、決済タイプ(0:1つだけ決済する、1;すべて決済する)決済する注文の種別、マジックナンバー、を受けて処理を行います。】
{【①まで有効】
int Error ;
RefreshRates();
【値を最新のものにする。】
for(int i=OrdersTotal()-1;i>=0;i--)【注文がある分繰り返す】
{【②まで有効】
if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES) == false) break ; //注文ポジションの選択
【注文が、なければ処理を脱出する。】
if(OrderMagicNumber() != MagicNumber) continue; //マジックナンバー
【マジックナンバーが異なれば処理をスキップする。】
{ 【③まで有効】※不要かもしれません。
int type = OrderType();
【その注文のタイプを確認する。BUY or SELL】
if((type == OP_BUY && Oder_Type==SIGNAL_CLOSEBUY)||(type==OP_SELL && Oder_Type==SIGNAL_CLOSESELL))
【決済指示が来ている注文のタイプとその注文が同じタイプか確認し、同じタイプであるなら④内の処理を行う。】
{【④まで有効】
switch(type)【注文のタイプ別分儀】
{【⑤まで有効】
買ポジションに対する処理
case OP_BUY:【BUY注文の場合】
OrderClose(OrderTicket(), OrderLots(), Bid, Slippage, MediumSeaGreen);
【決済注文を行う(この注文のチケットナンバー、この注文のロット数、売値、スリペ、チャート上の決済位置の印の色)】
Error = GetLastError();
【上記処理のエラーをErrorに格納】
if(Error!=0){Print("Close Positions Error OrderTicket = ", OrderTicket());}else{【⑥まで有効】
【もし、処理時にエラーがあれば、エラー報告しなければ以下の処理を行う。】
if (SignalMail) SendMail("[Signal Alert]", "[" + Symbol() + "] " + DoubleToStr(Bid, Digits) + " Close Buy");
【メールを送るようになっていれば、( )内の文面でメールを送る。】
if(SignalAlert)Alert("[Signal Alert]", "[" + Symbol() + "] " + DoubleToStr(Bid, Digits) + " Close Buy");
【アラート設定がなされていれば、( )内の文面でアラートを発生させる。】
}⑥
if(Close_Type==0){return(0);}
【1つだけ決済する場合は、この関数を終了する。】
break;【swithchからの脱出】
売りポジションに対する処理
case OP_SELL: 【SLL注文の場合】
OrderClose(OrderTicket(), OrderLots(), Ask, Slippage, DarkOrange);
【決済注文を行う(この注文のチケットナンバー、この注文のロット数、買値、スリペ、チャート上の決済位置の印の色)】
Error = GetLastError();
【上記処理のエラーをErrorに格納】
if(Error!=0){Print("Close Positions Error OrderTicket = ", OrderTicket());}else{【⑦まで有効】
【もし、処理時にエラーがあれば、エラー報告しなければ以下の処理を行う。】
if (SignalMail) SendMail("[Signal Alert]", "[" + Symbol() + "] " + DoubleToStr(Ask, Digits) + " Close Sell");
【メールを送るようになっていれば、( )内の文面でメールを送る。】
if(SignalAlert)Alert("[Signal Alert]", "[" + Symbol() + "] " + DoubleToStr(Ask, Digits) + " Close Sell");
【アラート設定がなされていれば、( )内の文面でアラートを発生させる。】
}⑦
if(Close_Type==0){return(0);}
【1つだけ決済する場合は、この関数を終了する。】
break; 【swithchからの脱出】
}⑤
}④
}③
}②
}①
【処理値を返さなくていいので、return()がありません。】
◆ポジションの注文 ◆
void OrderPositions(int Order,int pok1,int pok2,int MagicNumber)
【戻り値のないOrderPositionsという名前の自作関数で、注文の種別、現在のBUY注文の数、現在のSELL注文数、マジックナンバーを受けて処理する。】
{ 【①まで有効】
//-------ロット数の計算
double StopLossLevel =0;
double Stp=0;
int pos = MathAbs(pok1 - pok2);
【現在の注文数をposに格納】
double Lots = 0;
if(Lot_Management){Lots=lotSizeCalc(pos);}else{Lots=Fixed_Lots;}
【ロット調整を行う場合は、lotSizeCalc自作関数を実行し、Lotsに格納。ロット調整をしない場合は、Fixed_Lots(指示値)をLotsに格納】
if(Order==SIGNAL_BUY)
【BUY注文の場合{②}内の処理を行う】
{【②まで有効】
Ticket=0;
if(AccountFreeMarginCheck(Symbol(),OP_BUY,Lots)<=0 || GetLastError()==134){【③まで有効】
【余剰証拠金を確認し、不足している場合{③}内を処理】
Print("We have no money. Free Margin = ", AccountFreeMargin());
【残高不足であることを記載する。】
return(0);【自作関数の終了】}③
if (UseStopLoss){Stp= Ask-StopLoss*Point ;}else Stp = 0.0;
【損切り値を設定する場合、損切り値をstpに格納、設定しない場合は、stpに0を格納】
if (UseTakeProfit) TakeProfitLevel = Ask + (TPf*Point) ; else TakeProfitLevel = 0.0;
【利食い値を設定する場合、利食い値をTakeProfitLevelに格納、設定しない場合は、TakeProfitLevelに0を格納】
for(int bt=1;bt<= Order_Challenge ;bt++)【Order_Challenge(指示値)分{④}内を繰り返す】
{【④まで有効】
Ticket = OrderSend(Symbol(), OP_BUY, Lots, Ask, Slippage*Point, Stp, TakeProfitLevel, "Buy(#" + MagicNumber + ")", MagicNumber, 0, DodgerBlue);
【現在の通貨ペア、BUY注文、注文数、買値、スリペ、損切り値、利食い値、履歴に(Buy(#マジックナンバー))と記入、マジックナンバー、現在の時間、チャート上に記載される色を指示し、注文する。また、注文状況をTicketに格納】
if(Ticket > 0) 【注文が処理されたら】{【⑤まで有効】
if (OrderSelect(Ticket, SELECT_BY_TICKET, MODE_TRADES)) {【⑥まで有効】
【注文がされているか再度確認するために、注文を確認し、注文がされていれば】
Print("BUY order opened : ", OrderOpenPrice());
【(BUY order open 約定金額)と履歴に残す】
if (SignalMail) SendMail("[Signal Alert]", "[" + Symbol() + "] " + DoubleToStr(Ask, Digits) + "@"+DoubleToStr(Lots,2)+"@ Open Buy");
【メール設定されていれば、( )内の文面でメールを送る。】
if(SignalAlert) Alert ("[Signal Alert]", "[" + Symbol() + "] " + DoubleToStr(Ask, Digits) + "@"+DoubleToStr(Lots,2)+"@ Open Buy");
【アラート設定されていれば、( )内の文面でアラートを表示する。】
break ;【処理を抜け出す。】
⑥} else { ⇒ ⑥}⑤}else{⑦ 【不具合発見です。既設(赤部)だと1度目の注文確認で真、2回目の確認で偽にならないと、エラー報告が発生しないようになっています。変更が必要です。】
【変更内容は、1度目の確認が偽ならエラー処理をする。というものです。】
【2回目の確認は、本来注文の呼び出しがメインのため、エラー処理なしとしてみました。】 if(SignalAlert) Alert("Error opening BUY order : ", GetLastError());
【アラート設定がなされている場合、( )内を表示(エラー報告)】
Sleep(5000);//5秒間停止
【5秒間停止】
}【上記不具合のため、削除】
}⑦
}④
}③
if(Order==SIGNAL_SELL)
【SELL注文の場合{⑦}内の処理を行う】
{【⑦まで有効】
Ticket=0;
if(AccountFreeMarginCheck(Symbol(),OP_SELL,Lots)<=0 || GetLastError()==134){【⑧まで有効】
【余剰証拠金を確認し、不足している場合{⑧}内を処理】
Print("We have no money. Free Margin = ", AccountFreeMargin());
【残高不足であることを記載する。】
return(0); 【自作関数の終了】}⑧
if (UseStopLoss){Stp= Bid+StopLoss*Point ;}else Stp = 0.0;
【損切り値を設定する場合、損切り値をstpに格納、設定しない場合は、stpに0を格納】
if (UseTakeProfit) TakeProfitLevel = Bid - (TPf*Point) ; else TakeProfitLevel = 0.0;
【利食い値を設定する場合、利食い値をTakeProfitLevelに格納、設定しない場合は、TakeProfitLevelに0を格納】
for(int sc = 1;sc<= Order_Challenge ;sc++)【Order_Challenge(指示値)分{⑨}内を繰り返す】
{【⑨まで有効】
Ticket = OrderSend(Symbol(), OP_SELL, Lots, Bid, Slippage*Point, Stp, TakeProfitLevel, "Sell(#" + MagicNumber + ")", MagicNumber, 0, DeepPink);
【現在の通貨ペア、SELL注文、注文数、売値、スリペ、損切り値、利食い値、履歴に(Buy(#マジックナンバー))と記入、マジックナンバー、現在の時間、チャート上に記載される色を指示し、注文する。また、注文状況をTicketに格納】
if(Ticket > 0) 【注文が処理されたら】{【⑩まで有効】
if (OrderSelect(Ticket, SELECT_BY_TICKET, MODE_TRADES)) {【⑪まで有効】
【注文がされているか再度確認するために、注文を確認し、注文がされていれば】
Print("SELL order opened : ", OrderOpenPrice());
【(SELL order open 約定金額)と履歴に残す】
if (SignalMail) SendMail("[Signal Alert]", "[" + Symbol() + "] " + DoubleToStr(Bid, Digits) + "@"+Lots+"@ Open Sell");
【メール設定されていれば、( )内の文面でメールを送る。】
if(SignalAlert) Alert ("[Signal Alert]", "[" + Symbol() + "] " + DoubleToStr(Bid, Digits) + "@"+Lots+"@ Open Sell");
【アラート設定されていれば、( )内の文面でアラートを表示する。】
break ; 【return(0);の方がいいかもしれません。】
⑪} else { ⇒ ⑪}⑩}else{⑫ 【不具合発見です。既設(赤部)だと1度目の注文確認で真、2回目の確認で偽にならないと、エラー報告が発生しないようになっています。変更が必要です。】
【変更内容は、1度目の確認が偽ならエラー処理をする。というものです。】
【2回目の確認は、本来注文の呼び出しがメインのため、エラー処理なしとしてみました。】if(SignalAlert) Alert("Error opening SELL order : ", GetLastError());
【アラート設定がなされている場合、( )内を表示(エラー報告)】
Sleep(5000);//5秒間停止
【5秒間停止】
} 【上記不具合のため、削除】
}⑫
}⑨
}②
}①
◆ Stoplossの変更(注文の変更)◆
void Changes_Stoploss(int MagicNumber,int pos)
【戻り値のないChanges_Stoplossという自作関数で、マジックナンバー、ナンピン回数を受けて処理します。】
{【①まで有効】
int Error ;
int Total = OrdersTotal()-1;
【注文数の合計をTotalに格納】
int K = Total-pos+1;※不具合処理のため削除
for(int i=Total;i>=K;i--) ⇒ for(int i=0;i> Total;i++) ※不具合発生のため変更
{【②まで有効】
if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES) == false) break ; //注文ポジションの選択
【注文の呼び出し、及び 注文がなければ、処理を脱出】
if(OrderMagicNumber() != MagicNumber) continue; //マジックナンバー
【マジックナンバーが異なればスキップ】
{ 【③まで有効】※たぶん要らない
int type = OrderType();
【その注文タイプをtypeに格納】
switch(type)【注文タイプの分儀】
{【④まで有効】
//買ポジションに対する処理
case OP_BUY:【BUY注文の場合】
OrderModify(OrderTicket(),OrderOpenPrice(),OrderStopLoss( )-Point*StopStep,OrderTakeProfit(),0,Yellow);
【注文の変更(注文番号、注文値、損切り値、利食い値、時刻、黄色)で変更を行う】
Error = GetLastError();
【エラーをErrorに格納】
if(Error!=0){Print("Changes Stoploss Error OrderTicket = ", OrderTicket());}
【エラーがあるなら、履歴に残す】
break;【処理を脱出】
//売りポジションに対する処理
case OP_SELL:【SELL注文の場合】
OrderModify(OrderTicket(),OrderOpenPrice(),OrderStopLoss( )+Point*StopStep,OrderTakeProfit(),0,Yellow);
【注文の変更(注文番号、注文値、損切り値、利食い値、時刻、黄色)で変更を行う】
Error = GetLastError();
【エラーをErrorに格納】
if(Error!=0){Print("Changes Stoploss Error OrderTicket = ", OrderTicket());}
【エラーがあるなら、履歴に残す】
break; 【SELL注文の場合】
}④
}③
}②
} ①
//+---------------------------------------------------------------- END ------------------------------------------------------------------+
登録:
投稿
(
Atom
)