ところどころ、コードが切れている。
//+------------------------------------------------------------------+ | 名前のタイムフレームを返す| //+------------------------------------------------------------------+ string NameTimeframe(int timeframe=PERIOD_CURRENT) { if(timeframe==PERIOD_CURRENT) timeframe=Period(); switch(timeframe) { case 1 : return "M1"; case 2 : return "M2"; case 3 : return "M3"; case 4 : return "M4"; case 5 : return "M5"; case 6 : return "M6"; case 10 : return "M10"; case 12 : return "M12"; case 15 : return "M15"; case 20 : return "M20"; case 30 : return "M30"; case 16385 : return "H1"; case 16386 : return "H2"; case 16387 : return "H3"; case 16388 : return "H4"; case 16390 : return "H6"; case 16392 : return "H8"; case 16396 : return "H12"; case 16408 : return "D1"; case 32769 : return "W1"; case 49153 : return "MN1"; default : return (string)(int)Period(); } }
string NameTimeframe( const ENUM_TIMEFRAMES timeframe = PERIOD_CURRENT ) { return(StringSubstr(EnumToString(timeframe == PERIOD_CURRENT ? Period() : timeframe), 7)); }
//+------------------------------------------------------------------+ ||ポジション・チケット・アレイを埋める| //+------------------------------------------------------------------+ void FillingListTickets(void) { list_tickets_buy.Clear(); list_tickets_sell.Clear(); total_volume_buy=0; total_volume_sell=0; //--- int total=PositionsTotal(); for(int i=total-1; i>=0; i--) { ulong ticket=PositionGetTicket(i); ENUM_POSITION_TYPE type=(ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE); if(PositionGetInteger(POSITION_MAGIC)!=InpMagic) continue; if(PositionGetString(POSITION_SYMBOL)!=symb) continue; double volume=PositionGetDouble(POSITION_VOLUME); if(type==POSITION_TYPE_BUY) { list_tickets_buy.Add(ticket); total_volume_buy+=volume; } else if(type==POSITION_TYPE_SELL) { list_tickets_sell.Add(ticket); total_volume_sell+=volume; } } }
PositionGetTicketチェックなし。
「else if」は「else」だけでもよい。
タイプはcontinueの後では取られない。
そのため、この条件は POSITION_TYPE_BUY に対してのみ有効です。
double price=(order_type==ORDER_TYPE_BUY ? symbol_info.Ask() : symbol_info.Bid());
この条件はPOSITION_TYPE_BUY に対してのみ正しい。
なぜでしょうか?
この関数の呼び出しはコード内に2箇所存在します:
//--- シグナルによるオープニングポジション if(open_long) { if(num_s>0) CloseSell(); if(num_b==0) { double sl=(InpStopLoss==0 ? 0 : CorrectStopLoss(ORDER_TYPE_BUY,InpStopLoss)); double tp=(InpTakeProfit==0 ? 0 : CorrectTakeProfit(ORDER_TYPE_BUY,InpTakeProfit)); double ll=trade.CheckVolume(symb,lot,symbol_info.Ask(),ORDER_TYPE_BUY); if(ll>0 && CheckLotForLimitAccount(POSITION_TYPE_BUY,ll)) { if(trade.Buy(ll,symb,0,sl,tp)) FillingListTickets(); } } } if(open_short) { if(num_b>0) CloseBuy(); if(num_s==0) { double sl=(InpStopLoss==0 ? 0 : CorrectStopLoss(ORDER_TYPE_SELL,InpStopLoss)); double tp=(InpTakeProfit==0 ? 0 : CorrectTakeProfit(ORDER_TYPE_SELL,InpTakeProfit)); double ll=trade.CheckVolume(symb,lot,symbol_info.Ask(),ORDER_TYPE_SELL); if(ll>0 && CheckLotForLimitAccount(POSITION_TYPE_SELL,ll)) { if(trade.Sell(ll,symb,0,sl,tp)) FillingListTickets(); } } }
従って、このコードを書いたプログラマーだけが愚かにも間違った注文タイプを関数に送ってしまった場合、そう、エラーになります。このコードの場合、エラーは発生しない。
なぜですか?
この関数の呼び出しは、コードの2カ所に存在する:
したがって、このコードを書いたプログラマーだけが愚かにも間違ったオーダー・タイプを関数に送ってしまったとしたら、そう、エラーになる。このコードの場合、エラーは発生しない。
なぜなら、KBには異なる見解があり得るからです。
この特定のケースでエラーが発生するとは主張されていません。しかし、関数はあるコードから別のコードに移行する。移行する関数における潜在的なエラーは、壁に掛けられた銃のようなものだ。
もちろん、それを指に通しておくこともできる。しかし、私はここで警告したほうがいいと思う。
なぜなら、QBには異なる視点があり得るからだ。
この特別なケースでバグがあるとは主張していない。しかし、関数はあるコードから別のコードへと移行する。移行する関数における潜在的なエラーは、壁に掛けられた銃のようなものだ。
もちろん、指の間を通り過ぎてしまっても構わない。しかし、私はここで、警告を発したほうがいいと考えている。
その通り、警告は正しい。
作者はおそらく、不必要な不要なチェックを削除することを意図したのだろう--場合によっては、汎用性は不要だ。ENUM_ORDER_TYPEの列挙に惑わされたのでしょう。もしENUM_POSITION_TYPEが あれば、疑問は生じなかっただろう。
テキストをカットするというあなたの提案もないだろう。switchの方が早くないか?
作者はおそらく、不必要な不要なチェックを削除することを意図しているのだろう。場合によっては、普遍性は不要なのだ。ここであなたはENUM_ORDER_TYPEの列挙に惑わされたに違いない。もしENUM_POSITION_TYPEが あれば疑問は生じなかっただろう。
ここでは、関数そのものとその呼び出しを修正すべきだった。作者はMT4以降、このことに完全には気づいていない。
テキストをカットするというあなたの提案のように。switchの方が速いのでは?
このようなスイッチの構文はまさにやってはいけないことだ。スピードに関しては、この機能にはまったく必要ありません。しかし、この例は実に分かりやすい。少なくとも面白いでしょう。
関数そのものとその呼び出しは、ここで修正されるべきであった。作者はMT4以降、このことに最後まで気づいていない。
しかし、このようなスイッチ構成はまさにやってはいけないことだ。スピードに関しては、この関数にはまったく必要ない。しかし、この例は実に分かりやすい。少なくとも面白いだろう。
興味深い。また、あなたの意見では、逆指値注文を設定するための最短距離の標準的な計算のアプローチの何が間違っているのでしょうか?
//+------------------------------------------------------------------+ //| StopLevelに対する正しいStopLossを返します。 //+------------------------------------------------------------------+ double CorrectStopLoss(const ENUM_ORDER_TYPE order_type,const int stop_loss) { if(stop_loss==0) return 0; double pt=symbol_info.Point(); double price=(order_type==ORDER_TYPE_BUY ? symbol_info.Ask() : symbol_info.Bid()); int lv=StopLevel(),dg=symbol_info.Digits(); return (order_type==ORDER_TYPE_BUY ? NormalizeDouble(fmin(price-lv*pt,price-stop_loss*pt),dg) : NormalizeDouble(fmax(price+lv*pt,price+stop_loss*pt),dg) ); } //+------------------------------------------------------------------+
//+------------------------------------------------------------------+ //| 計算された StopLevel を返します。| //+------------------------------------------------------------------+ int StopLevel(void) { int sp=symbol_info.Spread(); int lv=symbol_info.StopsLevel(); return(lv==0 ? sp*size_spread : lv); } //+------------------------------------------------------------------+
特に間違いはないと思うのですが。説明してください。また、MT4とMT5の最小距離の計算の違いは何ですか?
実際には、このコードにはもっと多くの誤りがある。たとえば、SBスタイルのためだけにCsymbolInfoを使うのは邪道であることがよく示されている。
以前に収集したチケットのリストを通じてポジションをクローズすることは悪である。これは非常によくあるエラーです。
fxsaber, 2018.01.23 09:39.
これは間違ったロジックです。OrderSendが失敗し、成功した後、現在の取引環境を再度完全に読み込む必要があります。このルールは常に適用されるべきです。
リターンコードについて。私は自分のExpert Advisorでは一切分析していません。私の意見では、取引ロジックはリターンコードに依存すべきではありません。
興味深い。逆指値注文の最短距離の標準的な計算方法の何が問題だと思いますか?
私はここに間違いはないと思います。説明してください。また、MT4 と MT5 の最小距離の計算の違いは何ですか?
エラーは最小距離ではなく、列挙入力と呼び出しにあります。しかし、計算も間違っています。
取引、自動取引システム、取引戦略のテストに関するフォーラム。
fxsaber, 2018.02.01 21:38
SBスタイルのためだけにCsymbolInfoを使うのは悪であることはよく示されている。
- 無料取引アプリ
- 8千を超えるシグナルをコピー
- 金融ニュースで金融マーケットを探索
Diff_TF_MA_EA:
Diff_TF_MA指標に基づいたエキスパートアドバイザーです。
作者: Scriptor