2011/12/25

パターン認識の精度を向上させる。■■■

今回は、前回の内容を用いて認証精度の向上を図ってみました。
実は、ウェーブレットの事を調べていて、別階級のウェーブレット係数は、そのままでは比較できない事、もし比較する場合には、変換作業が必要であることがわかりました。その変換作業を用いることで認証制度の向上に取り組んだわけです。

スケール係数の比較は不要

スケール係数の数値を変更して確認してみました。以下がその画像です。
※白線:無加工 ※黄線:スケール係数+0.05 ※赤線:スケール係数+0.1
スケール
この画像でわかるとおり、波形の形状には変化がなく、位置が変化したにすぎません。その為、パターン認証では不要な要素であることがわかります。

ウェーブレット係数の変換作業

まず、変換作業に使用する重みを作成しました。
これは、ウェーブレット変換する際に乗算されるsqr(1/√2=0.70710678)を各階級に応じて除算するものです。
重み
変換作業を画像で見てみると、以下の図のとおりとなります。
wbr
実際に使用するのは、黄線のように高周波成分を削除した形の物を使用するわけです。

認識精度の確認

前回のコードに上記コードを追加し、以下のコードを修正します。赤線が変更箇所です。
ちなみに、y=0から1に変更したのは、g[0]に格納されているスケール係数を排除するためです。
追加
結果を見ると、上図が、変更前で下図が、変更後のチャートです。
※赤線:基本波形 ※黄色:一番近い過去の波形 ※白線:2・3番目に近い過去の線 です。
【変更前】
変更前

【変更後】
変更
使用した結果、1番近い過去の波形及び2番目と同じ波形を導いていますが、3番目の波形が異なることがわかります。(用いるデータが悪く変化がわかりづらい。。。orz)数値的には、悪くなっていますが、パターン認識の精度は、向上した、、、はずです。^^;

その他

3か月にわたり開催されたATC2011が修了しました。参加されたみなさん、お疲れ様でした。そして、応援して頂いた皆様、期待に応えられず申し訳ありません。今年は、第1週目にほぼ敗北宣言をするような結果になってしまいました。私の力量不足が招いた結果だと思っています。しかし、ATCへの参加は、面白いですよ^^;来年は、みなさんも参加されてはいかがでしょう?世界を相手に勝負できますよ(^o^)丿それでは、良いお年を!

2011/12/06

ウェーブレットを用いたパターン認識■■■

※2011/12/9追記(コードのバグ修正) しました。
ウェーブレットの勉強をしている際に、ふと思いついたことを形にしてみました。


パターン認識とは

今回ここで挙げるパターン認識とは、過去のチャートの形から、現在のチャートの形に近いものを選択し、その後の動きを元に、近未来のチャートの動きを予測しようというものです。

ここで問題になったのが、2点。
1.どのような形を用いるか。
※今回は、ウェーブレット変換した形を採用しました。
2.どのように予測するか。
※最も近い形3ヶ所をピックアップし、その2時間後までの高値、安値を導く。その線を表示させて、検証する。(実は、まだ検討中。)


ウェーブレット

今回使用したウェーブレットは、前に作ったHarrのウェーブレットをウェーブレット変換のみ使用しています。
前作のウェーブレット変換を完了させるとg[]配列に以下の様に変換された数値が、格納される。
(L=2^N:N=5の場合)
g[0]=レベルNのスケーリング係数
g[1]=レベルNのウェーブレット係数
g[2~3]=レベルN-1のウェーブレット係数
g[4~7]=レベルN-2のウェーブレット係数
g[8~15]=レベルN-3のウェーブレット係数
g[16~31]=レベルN-4のウェーブレット係数
・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・
ここで、最下層レベルN-4(高周波領域)をフィルタリングによりのウェーブレット係数を0にすると、格納されているデータは、半分の量になります。画像で見てみると、上がg[]配列のフィルタ前、下がフィルタ後です。さらに、レベルN-2までフィルタリングするとデータ量は、さらに半減します。
N0
このように圧縮(加工)されたデータをパターン認識の形として採用しました。
ちなみに、レベルN-4でフィルタリングしたデータを再変換をすると、以下の様な画像となります。
N2
圧縮(加工)したデータを用いることで、パターン認識する測点が減り、ノイズの削除効果もあるためウェーブレット変換を採用しました。


その他もろもろ

照合するパターンの抽出間隔を1日(1440分=86400秒)にしてあります。これは、抽出作業の際に特異な期間(短期間)に抽出箇所が集中するのを防ぐ役割と、前回のブログの話で出てきた時間単位の平均値(期待値)の差を低減させるためです。また、夏時間の影響をカバーするために夏時間の変換コードも追加しておきました。
※5分足様に作成されています。
採用した値は、すべてOpenを採用しています。これは、演算負荷を低減させるために採用した値です。お好みで調整ください。


コード

//+------------------------------------------------------------------+
//|                                                         DWTP.mq4 |
//|                                        Copyright ゥ 2011, bighope |
//|                       http://expertadviser-bighope.blogspot.com/ |
//+------------------------------------------------------------------+
#property copyright "Copyright ゥ 2011, bighope"
#property link      "http://expertadviser-bighope.blogspot.com/"

#property indicator_chart_window
#property indicator_buffers 6
#property indicator_color1 Red
#property indicator_color2 Red
#property indicator_color3 Orange
#property indicator_color4 Orange
#property indicator_color5 Yellow
#property indicator_color6 Yellow

#define sqr 0.70710678

//---- input parameters
extern int       N      =   7;//対象データ数(2のN乗)
extern int       HBs    =   5;//高周波カット位置
extern int       LBs    =   7;//低周波カット位置
extern int       Shift  =   0;//データのシフト
extern int       loop   = 500;//検索回数
int    DWTPeriod ;
//---- buffers
double Hi0Band[];
double Lw0Band[];
double Hi1Band[];
double Lw1Band[];
double Hi2Band[];
double Lw2Band[];
double g[];
double gs[];
double now[];
int CusPeriod;
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int init()
  {
//---- indicators
   SetIndexStyle(0,DRAW_LINE);
   SetIndexStyle(1,DRAW_LINE);
   SetIndexStyle(2,DRAW_LINE);
   SetIndexStyle(3,DRAW_LINE);
   SetIndexStyle(4,DRAW_LINE);
   SetIndexStyle(5,DRAW_LINE);
   SetIndexShift(0,24);
   SetIndexShift(1,24);
   SetIndexShift(2,24);
   SetIndexShift(3,24);
   SetIndexShift(4,24);
   SetIndexShift(5,24);
   SetIndexBuffer(0,Hi0Band);
   SetIndexBuffer(1,Lw0Band);
   SetIndexBuffer(2,Hi1Band);
   SetIndexBuffer(3,Lw1Band);
   SetIndexBuffer(4,Hi2Band);
   SetIndexBuffer(5,Lw2Band);
   
   CusPeriod = MathPow(2,N-HBs+1);
   DWTPeriod = MathPow(2,N);
   ArrayResize(g,DWTPeriod);
   ArrayResize(gs,DWTPeriod);
   ArrayResize(now,CusPeriod);
//----
   return(0);
  }
//+------------------------------------------------------------------+
//| Custom indicator deinitialization function                       |
//+------------------------------------------------------------------+
int deinit()
  {
//----
   Comment("");
//----
   return(0);
  }
  
//+------------------------------------------------------------------+
//|  function                                                        |
//+------------------------------------------------------------------+ 
bool str(int index,double B,int &No[],double &BL[]){
   int Hindex;
   Hindex=ArrayMaximum(BL);
   
   if(BL[Hindex]>B){
      BL[Hindex] = B;
      No[Hindex]  = index;
      return(true);
   }
   return(false);
}

//+------------------------------------------------------------------+
//| ウェーブレット変換                                               |
//+------------------------------------------------------------------+ 
 void DWT(double &input[],double &out[],int Ns,int DWTf,int Hibs,int Lwbs){
   int z,k;
    double difference;
   for(z=1 ; z<=Ns ;z++){
      DWTf =DWTf/2;
      for(k = 0; k < DWTf; k++){
         out[k]         = (input[k*2]+input[k*2+1])*sqr;
         difference = (input[k*2]-input[k*2+1])*sqr;
         if((Lwbs>=z)&&(z>=Hibs)){out[DWTf+k] = difference;}else{out[DWTf+k] = 0;}//フィルタリング作業
       }
      if(Ns>z)ArrayCopy(input,out);  
   }
 }

//+------------------------------------------------------------------+
//|夏時間関数                                                        |
//+------------------------------------------------------------------+ 
bool  DST(datetime Now)//夏時間にtrue
{
 bool Check = false;
 int Start_Month    =              3;//開始月
 int Start_Week     =              2;//第○週
 int Start_DayofWeek=              0;//0:日曜日
 int End_Month      =             11;//終了月
 int End_Week       =              1;//第○週
 int End_DayofWeek  =              0;//0:日曜日
 int Year_Now       =  TimeYear(Now);
 datetime DST_Start,DST_End ;
 string MakeTime;
 int Day_S,Day_E;
 
 if(Year_Now < 2000)return(0);
 switch(Year_Now)
 {
  case 2000:
            DST_Start = D'02.04.2000';
            DST_End   = D'29.10.2000';
            break;
  case 2001:
            DST_Start = D'01.04.2001';
            DST_End   = D'28.10.2001';
            break;
  case 2002:
            DST_Start = D'07.04.2002';
            DST_End   = D'27.10.2002';
            break;
  case 2003:
            DST_Start = D'06.04.2003';
            DST_End   = D'26.10.2003';
            break;
  case 2004:
            DST_Start = D'04.04.2004';
            DST_End   = D'31.10.2004';
            break;
  case 2005:
            DST_Start = D'03.04.2005';
            DST_End   = D'30.10.2005';
            break;
  case 2006:
            DST_Start = D'02.04.2006';
            DST_End   = D'29.10.2006';
            break;
  default:
            MakeTime =Year_Now + "."+Start_Month + ".01"; 
            DST_Start = StrToTime(MakeTime) - 86400.0;
            Day_S = Start_Week*7 - TimeDayOfWeek(DST_Start) + Start_DayofWeek;
            MakeTime = Year_Now + "."+ Start_Month  + "." + Day_S;
            DST_Start = StrToTime(MakeTime);
            
            MakeTime =Year_Now + "."+End_Month + ".01"; 
            DST_End = StrToTime(MakeTime) - 86400.0;
            Day_E = End_Week*7 - TimeDayOfWeek(DST_End) + End_DayofWeek;
            MakeTime = Year_Now + "."+ End_Month  + "." + Day_E;
            DST_End = StrToTime(MakeTime);
            break;
 }
 
 if(DST_Start < Now &&  Now < DST_End)Check = true;
 
 return(Check);
 }
 
//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+

int start()
  {

   int counted_bars=IndicatorCounted();
   if(counted_bars>0&&Volume[0]>1)return(0);
   int y=0,k=0,index=0;
   datetime day=0;
   int    BarNo[3]={0,0,0};
   double     L[3]={1000.0,1000.0,1000.0};
   double    R=1000.0;
   double    Hi[3]={0,0,0};
   double    Lw[3]={0,0,0};
   
   for(int i=0;i<loop;i++){
      ArrayInitialize(g,0);
      ArrayInitialize(gs,0); 
//※修正箇所
      day= Time[Shift]-84400*i;
   //day=Time[Shift]-1440*i;訂正前
      if(DST(day))day-=3600;
  //if(DST(day))day--;訂正前
//※訂正箇所ここまで 
      if(i!=0)index = iBarShift(NULL,0,day,true);
      if(index<0){ Print("Orver data",i); break;}
      for(k=0;k<DWTPeriod;k++) g[k]=(Open[k+Shift+index]-Open[Shift+DWTPeriod+index])*MathPow(10,Digits-2);
      DWT(g,gs,N,DWTPeriod,HBs,LBs);
      
      if(i==0){
         ArrayCopy(now,gs,0,0,CusPeriod);
      }else{
             R=0;
             for(y=0;y<CusPeriod;y++) R += MathPow(now[y]-gs[y],2);
             str(Shift+index,R,BarNo,L);
           }
   }
    R=1000.0;
    for(k=0;k<3;k++){
      Hi[k] = High[iHighest(NULL,0,MODE_HIGH,24,BarNo[k]-24)]-Open[BarNo[k]];
      Lw[k] = Low[iLowest(NULL,0,MODE_LOW,24,BarNo[k]-24)]-Open[BarNo[k]];
      if(R>L[k]){R=L[k];index=k;}
    }

    for(k=0;k<24;k++){
      switch(index){
         case 0:
               Hi0Band[Shift+k] = Hi[0]+Open[Shift];
               Lw0Band[Shift+k] = Lw[0]+Open[Shift];
               Hi1Band[Shift+k] = Hi[1]+Open[Shift];
               Lw1Band[Shift+k] = Lw[1]+Open[Shift];
               Hi2Band[Shift+k] = Hi[2]+Open[Shift];
               Lw2Band[Shift+k] = Lw[2]+Open[Shift];
               break;
         case 1:
               Hi0Band[Shift+k] = Hi[1]+Open[Shift];
               Lw0Band[Shift+k] = Lw[1]+Open[Shift];
               Hi1Band[Shift+k] = Hi[0]+Open[Shift];
               Lw1Band[Shift+k] = Lw[0]+Open[Shift];
               Hi2Band[Shift+k] = Hi[2]+Open[Shift];
               Lw2Band[Shift+k] = Lw[2]+Open[Shift];
               break;
         case 2:
               Hi0Band[Shift+k] = Hi[2]+Open[Shift];
               Lw0Band[Shift+k] = Lw[2]+Open[Shift];
               Hi1Band[Shift+k] = Hi[0]+Open[Shift];
               Lw1Band[Shift+k] = Lw[0]+Open[Shift];
               Hi2Band[Shift+k] = Hi[1]+Open[Shift];
               Lw2Band[Shift+k] = Lw[1]+Open[Shift];
               break;
         default:
               Print("Err Buffer select");
               break;
      }
 
    }
   Comment(" R = ",L[index]," : ",L[0]," : ",L[1]," : ",L[2], "   No= ",BarNo[index]," : ",BarNo[0]," : ",BarNo[1]," : ",BarNo[2]);
  
//----
   return(0);
  }
//+------------------------------------------------------------------+

使いかた

パラメータは、ほぼ前回のウェーブレットの時に用いた物と同じですので省略して、追加したパラメータの説明をすると、【loop】は、検索するデータ量を設定するものです。デフォルトの500とは、過去500日分のデータを照合しなさいと言うことになります。(※設定したデータ量がない場合は、Printでお知らせし、そこでbreakします。)

表示内容の説明
インジケータを表示すると以下の様になると思います。
y0
各水平ランは、色ごとのペア(3種類のペア)で2時間後までの高値と安値を表示しています。ちなみに赤色のラインが最も近い形の予測値となります。
コメント欄(画像左上)の【R】は、検索された物がどれだけ近い形を示しているかを表す数値です。(小さい方が良い)【R=最も近かった数値:R1:R2:R3(3種類のR値)】を表示しています。【No】は、検索された値の日数を表します。【No=最も近かった数値の日数(●日前):R1の日数:R2の日数:R3の日数】
しばらく作動させると履歴が残りますのでどんな動きだったか検証することもできますが、パラメータ【Shift】の数値を変更しても確認できます。

まとめ

いろいろテストしてみましたが、完全に予測するというものではありません。ただし、Rの数値は小さく各3組の線がほぼ同じ状態になった時に、予測できているかな?と言う程度です。では!

2011/11/23

ボリンジャーバンドを作ってみました。■■■

ATC参戦用のEAを作るのに時間を取られ、後回しにしてきたことをコツコツと行っています。その中の一つがRの使い方の習得でした。今回は、Rの学習の一環としてボリンジャーバンドもどきを作ってみました。

ヒストグラムの作成

今回は、MQL4のスクリプトでUSDJPYH1をヒストグラム化してみました。Rの勉強になってない。。
以下がコードです。
//+------------------------------------------------------------------+
//|                                                    Copyprice.mq4 |
//|                                        Copyright ゥ 2009, bighope |
//|                       http://expertadviser-bighope.blogspot.com/ |
//+------------------------------------------------------------------+
#property copyright "Copyright ゥ 2009, bighope"
#property link      "http://expertadviser-bighope.blogspot.com/"
#property show_inputs
extern string Filename  = "USDJPYH1"; 

int bufindex(){
   int hiindex,lowindex,sd;
   double st;
   hiindex  = iHighest(NULL,0,MODE_HIGH);
   lowindex = iLowest(NULL,0,MODE_LOW);
   st = High[hiindex] - Low[lowindex];
   sd = st/Point*0.1;
   return(sd);
}

//+------------------------------------------------------------------+
//| script program start function                                    |
//+------------------------------------------------------------------+
int start()
  {
//----
   int handle,index;
   bool ret;
   int HL;
   double Ds[];
   index = bufindex();
   
   ArrayResize(Ds,index);
   handle=FileOpen(Filename+".csv",FILE_CSV|FILE_WRITE,',');
   if(handle<1) return(false);
  
   for(int i=0;i<Bars;i++){
      HL=MathRound((High[i]-Low[i])*MathPow(10,Digits)) ;
      Ds[HL]++;
   }

   for(i=0;i<index;i++){
      ret = FileWrite(handle,i,Ds[i]/Bars);
      if(ret==false)return(0);
   }
   FileClose(handle);
   Comment("Get Data OK");
//----
   return(0);
  }
//+------------------------------------------------------------------+

スクリプトを作動させると、・・・//experts/filesにCSVファイルが作られます。
※これをRに読み取らせる訳ですが、Rのアイコンを右クリック→プロパティを選択し、作業フォルダーのアドレスを変更しておくと、ひと手間省けて便利です。
syo-to
Rを起動し以下のコードでヒストグラムが表示されます。
#データの読み込み(リスト形式)
 d<-read.csv("UJH1.csv") #データの代入
 x<-d[[1]]
y<-d[[2]]
#表示
plot(x,y,main="USDJPU1時間足(Hi-Low)",xlab="pips",ylab="頻度%",xlim=c(0,80), ylim=c(0,0.06),col=1)
r
※Rはデータの種類がいろいろあって、はじめは、ここでつまずきました。 リストとは


確立密度関数の推定

当初は、ガンマ分布を当てはめようと考えていましたが、ある方から、対数正規分布を教えて頂いたので今回は、対数正規分布を当てはめてみました。回帰方法は、nls() 関数を使用しましたが、初期値設定を導くために以下のコードを追加しています。
rt
結果をグラフ化したものが以下の通りです。
r
対数正規分布の性質から平均と分散(偏差)が求まります。
平均=EXP(meanlog+(sdlog^2)/2)=19.01149(pips)
分散=EXP(2×meanlog+sdlog^2)×(EXP(sdlog^2)-1)=148.6416
偏差=√分散=12.19187

時間単位での変化

時間単位で調べてみると以下の表のようになりました。
時間帯 meanlog sdlog 平均 偏差
0 2.875508 0.508818 20.18533 10.9727
1 2.706802 0.567246 17.59625 10.84084
2 2.462878 0.565203 13.77155 8.448786
3 2.356058 0.561678 12.35177 7.522623
4 2.440356 0.562824 13.4468 8.209028
5 2.593056 0.522776 15.32834 8.593275
6 2.947423 0.468463 21.2669 10.53519
7 3.016413 0.479638 22.90693 11.65029
8 2.948864 0.466359 21.27663 10.48733
9 2.849121 0.495672 19.53029 10.30681
10 2.80227 0.487687 18.56335 9.619049
11 2.857566 0.47229 19.47429 9.735056
12 3.191692 0.516832 27.80594 15.38629
13 3.113179 0.503577 25.53306 13.71777
14 3.242793 0.51251 29.19876 16.00329
15 3.034412 0.475586 23.27787 11.72715
16 2.822379 0.50759 19.12895 10.36999
17 2.655229 0.517096 16.2635 9.004569
18 2.662298 0.519839 16.40218 9.136312
19 2.436341 0.53617 13.1982 7.616876
20 2.371655 0.582975 12.69978 8.079605
21 2.4068 0.499943 12.57576 6.701269
22 2.522685 0.492323 14.06762 7.367471
23 2.745907 0.502226 17.67272 9.465938
※時間は、GMT時間を採用
平均値(期待値)が、時間帯によって倍以上の違いがあることがわかります。


ボリンジャーバンドもどき

平均と偏差と聞いて思い出すのがボリンジャーバンド!と言うことで、上記の内容を踏まえて指標の作成です。
tty
//+----------------------------------------------------------------------------+
//|                                                              BBands.mq4|
//|                                                  Copyright ゥ 2009, bighope | 
//|                                 http://expertadviser-bighope.blogspot.com/ |
//+----------------------------------------------------------------------------+ 
#property copyright "Copyright ゥ 2011, bighope" 
#property link http://expertadviser-bighope.blogspot.com/ 
#property indicator_chart_window
#property indicator_buffers 2
#property indicator_color1 Yellow
#property indicator_color2 Yellow
extern int    GMT      =   1;
extern double Multiple = 1.0;
double Average[24]   = {0.202,0.176,0.138,0.124,0.134,0.153,0.213,0.229,0.213,0.195,0.186,0.195,0.278,0.255,0.292,0.233,0.191,0.163,0.164,0.132,0.127,0.126,0.141,0.177};
double Deviation[24] = {0.110,0.108,0.084,0.075,0.082,0.086,0.105,0.117,0.105,0.103,0.096,0.097,0.154,0.137,0.160,0.117,0.104,0.090,0.091,0.076,0.081,0.067,0.074,0.095}; 

double  Hibands[];
double  Lowbands[];
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int init()
  {
//---- indicators
   IndicatorBuffers(2);
//---- indicator line
   SetIndexStyle(0,DRAW_LINE);
   SetIndexStyle(1,DRAW_LINE);
   SetIndexBuffer(0,Hibands);
   SetIndexBuffer(1,Lowbands);
//----
   return(0);
  }
//+------------------------------------------------------------------+
//| Custom indicator deinitialization function                       |
//+------------------------------------------------------------------+
int deinit()
  {
//----
   
//----
   return(0);
  }
//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
int start()
  {
   int i,h,counted_bars=IndicatorCounted();
   double hig,lowg,cg;
//----
   if(Multiple<0)return(0);
   if(counted_bars>0) counted_bars--;
   int limit=Bars-counted_bars;
   
   for(i=0; i<limit; i++){
      h    = TimeHour(Time[i]);
      hig  = High[iHighest(NULL,0,MODE_HIGH,12,i)];
      lowg = Low[iLowest(NULL,0,MODE_LOW,12,i)];
      h = h-GMT;
      if(h<0)h=24+h;
      cg=(hig+lowg)/2;
      Hibands[i]  = cg + (Average[h]/2) + (Deviation[h] * Multiple);
      Lowbands[i] = cg  - (Average[h]/2) - (Deviation[h] * Multiple);  
   }
//----
   return(0);
  }
//+------------------------------------------------------------------+


※USDJPY M5用に作成しています。
 

まとめ

かなり飛ばしてまとめてしまいました。^^;
 

2011/10/21

前回のコメントの内容を確認しました。■■■

前回の記事で、筆者がATC2011に提出したEAのコードを掲示し、貴重なコメントを頂いたので今回は、そのコメントの精査を行いたいと思います。



はじめに

今回のEAで考慮した点の一つが、メモリの使用量の削減です。その為に、バッファを固定し再利用する方法を模索しました。以下が仕様です。ちなみにバッファ固定の取り組み方法は、こちら ですが、記載されているバグは、バージョンアップで改善されたみたい?

使用したDATE
指標名 値(time,open,hi,low,close) 平均足 DeMaker EMA×4本 一定期間の値(高値、中値、安値)
バッファ数 10 6 50 30 80

ちなみに、EAを稼働した時のメモリ増加量は、1300kBほどです。(タスクマネージャー調べ)多いのか少ないのかは、不明?ホントに削減されているのかな?CopyBuffer()と比べてどうなのか確認していません。。orz

今回、iMA()やiCustom()などの関数を使用せずにEAを作成した結果、前処理(事前計算)が必要となりました。

※前処理とは、初期状態で空のバッファに過去のデータを入れる事。

今回使用した方法は、現在のbarからバッファ分過去の値(time,open,…)を取得するために、バッファ分過去のbarのtimeを取得し、そこから値を取得する方法を取りました。以下がそのtimeの取得コードです。

+---------------------------------------------------------------------------------------------------------+
datetime Cindibox_h::Shiftime(datetime time){ 
   datetime startime;
   int rates,i=0;
   startime=time-frametime(timeframes)*60*(range-1);
   datetime getbars[];
   do{
      do{
         if(i>0)Sleep(500);//一度以上取得に失敗したら一時停止
         i++;
         rates = CopyTime(symbl,timeframes,(datetime)startime,(datetime)time,getbars);
         if(rates==range)break;
         }while(i<5);
      if(rates!=range){startime-=(datetime)frametime(timeframes)*60; i=1;}
     }while(rates < range);
return(startime);
+---------------------------------------------------------------------------------------------------------+

この関数で留意した点
1.CopyRates(),CopyTIme()などの関数は、取得に失敗することがあるので対応する。
(特に、異なるペア、異なるタイムフレームを取得する場合、失敗するとこが多かった。)
データを呼び出す前に、関数を抜けている感じがする?ので、sleep(500)を含めて5回試みるようにした。
2.必ず、バッファ数のbarが取得できるtimeを取得する。
barの抜けがある場合の処理を追加してあります。

この関数を元に以下の関数を実行し、バッファに値を取得させています。
ちなみに、Rates以外の値は、各関数内で処理させています。

+---------------------------------------------------------------------------------------------------------+
int Cindibox_h::Run(const datetime nowtime){
   MqlRates Sprice[1];
   int zero=0,befo=0,hlzero=0;
   int rates;
   datetime startime=nowtime;
   //バッファが空の時
   if(bufindex==0)startime=Shiftime(nowtime);
   do{
      rates = CopyRates(symbl,timeframes,(datetime)startime,(int)1,Sprice);
      if(rates>0){
         if(Sprice[0].time != bartimenow){
            bartimenow = Sprice[0].time;
            bufindex++;
         }
         zero=ZeroIndex(bufindex,range);
         hlzero = ZeroIndex(bufindex,HLrange);
         price[zero] = Sprice[0];
         phi[hlzero] = price[zero].high;
         plw[hlzero] = price[zero].low;
        if(MLalfa>0 && MSalfa>0 && ON_MA==true)Run_Ma(bufindex);
        if(ON_Heiken==true) Run_HeikenAshi(bufindex);
        if(ON_DeMark==true) Run_DeMarker(bufindex);
         startime=Shiftimeon(startime);                    
         befo = ZeroIndex(bufindex+1,range);
         }
    } while(price[befo].tick_volume<=0);//バッファが埋まったら脱出
   return(bufindex);
+---------------------------------------------------------------------------------------------------------+





前回のコメント

前回頂いたコメントを確認していきます。

>>datetime Cindibox_h::frametime(ENUM_TIMEFRAMES timef)にPERIOD_M6とかPERIOD_M20とかPERIOD_M12がないような..。時間の計算が人間業とは思えないトリッキーさでよくわかりませんでした..。なぜSleep()が..。この関数のdatetimeという戻り値の型も変ですよね。


そうなんです。CATCtradeクラスの各インスタンスのCATCtrade::InputdateでPERIOD_M6、PERIOD_M20、PERIOD_M12を使用しているにも関わらず、datetime Cindibox_h::frametime(ENUM_TIMEFRAMES timef)に対応するコードを記載していませんでした。以下コード

+---------------------------------------------------------------------------------------------------------+
datetime Cindibox_h::frametime(ENUM_TIMEFRAMES timef){
 switch(timef){
      case PERIOD_M1: return(1);
      case PERIOD_M5: return(5);
      case PERIOD_M10: return(10);
      case PERIOD_M15: return(15);
      case PERIOD_M30: return(30);
      case PERIOD_H1: return(60);
      case PERIOD_H4: return(240);      
      default : return(15);  
   }
}
+---------------------------------------------------------------------------------------------------------+

うん~!初期計画から変更するのを忘れてました。。orz しかし、defaultがなぜ15なの@@?
後でコードを変更しENUM_TIMEFRAMES の値をそのまま使おうと思っていましたが、忘れていました。
以下がENUM_TIMEFRAMESの値 一覧です。なぜ、H1から16385+時間になるんだろう?

PERIOD_M1 M3 M5 M6 M10 M30 H1 H2 H3 H12 D1
1 3 5 6 10 30 16385 16386 16387 16396 16408

そして、以下のコードが、修正版

+---------------------------------------------------------------------------------------------------------+
int Cindibox_h::frametime(ENUM_TIMEFRAMES timef){
   int t;
  t=timef;
  if(t>=16385)t=(t-16384)*60;
  return(t);
}
+----------------------------------------------------------------------------------------------------------+

トリッキーと評されたコードは、上記に記載しました。やっぱりこんなコードは、スタンダードではないんだろうな(・・?

datetime Cindibox_h::frametime(ENUM_TIMEFRAMES timef)
の戻り値もおかしいですね。 int型に変更して、datetime Cindibox_h::Shiftime(datetime time)の以下のコードを変更するようにした方が良いのかな?
startime=time - (datetime)frametime(timeframes)*60*(range-1);






>>if(--retry_count!=0) continue;
リトライが動作しない。
partial_closeがfalseだとwhile(partial_close);でループを抜けてしまいます。


指摘されたコードが以下のコードです。
標準ライブラリー(bool CTrade::PositionClose(const string symbol,ulong deviation))より抜粋し、余分?なところを削除したものです。

+----------------------------------------------------------------------------------------------------------+
bool CATCtrade::PositionClose(void){
   bool   partial_close=false;
   int    retry_count  =10;
   uint   retcode      =TRADE_RETCODE_REJECT;
//--- check stopped
   if(IsStopped()) return(false);
//--- variables
   string action,result;
//--- clean
   ClearStructures();
   do
     {
      //--- checking
      if(PositionSelect(symbl))
        {
         if((ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE)==POSITION_TYPE_BUY)
           {
            //--- prepare request for close BUY position
            m_request.type =ORDER_TYPE_SELL;
            m_request.price=SymbolInfoDouble(symbl,SYMBOL_BID);
           }
         else
           {
            //--- prepare request for close SELL position
            m_request.type =ORDER_TYPE_BUY;
            m_request.price=SymbolInfoDouble(symbl,SYMBOL_ASK);
           }
        }
        else
        {
         //--- position not found
         m_result.retcode=retcode;
         return(false);
        }
      //--- setting request
      m_request.action      =TRADE_ACTION_DEAL;
      m_request.symbol      =symbl;
      m_request.deviation   =deviation;
      m_request.type_filling=ORDER_FILLING_AON;
      m_request.volume      =PositionGetDouble(POSITION_VOLUME);
      //--- check volume
      double max_volume=SymbolInfoDouble(symbl,SYMBOL_VOLUME_MAX);
      if(m_request.volume>max_volume)
        {
         m_request.volume=max_volume;
         partial_close=true;
        }
      else
         partial_close=false;
      //--- order check
      if(!OrderCheck(m_request,m_check_result))return(false);
      
      //--- order send
      if(!OrderSend(m_request,m_result)){
         if(--retry_count!=0) continue;
         return(false);
      }
        
      retcode=TRADE_RETCODE_DONE_PARTIAL;
      if(partial_close) Sleep(1000);
     }
   while(partial_close);
return(true);
}
+----------------------------------------------------------------------------------------------------------+

確認するんだった。。orz デフォルトだとループしないじゃん。勉強になりました。
ループさせる場合は、bool partial_close=true;ですね。。




>>ENUM_ORDER_TYPE CATCtrade::creattype(const int typec)
return(ORDER_TYPE_BUY)とreturn(NULL)を返していますが、どちらも0で同値です。ただ動作には影響ないです。
ENUM_ORDER_TYPEにORDER_TYPE_FLATを作成しなかったMetaQuotes社の仕様決めのいい加減さが原因だと思います。
ポジションの状態を調べるのにPositionSelect()とPositionGetInteger()の2つの関数の組み合わせが必要になりますし。


まず、対象コードの確認
+----------------------------------------------------------------------------------------------------------+
ENUM_ORDER_TYPE CATCtrade::creattype(const int typec){
   switch(typec){
      case  2: return(ORDER_TYPE_BUY);
      case -2: return(ORDER_TYPE_SELL);
      default: return(NULL);
   }
} 
+----------------------------------------------------------------------------------------------------------+

そして、ENUM_ORDER_TYPEの値の確認
_BUY _SELL _BUY_LIMIT _SELL_LIMIT _BUY_STOP _SELL_STOP _BUY_STOP_LIMIT _SELL_STOP_LIMIT
0 1 2 3 4 5 6 7

あらら、指摘の通り_BUYの値が0でした。
さて、どうするか?int型?char型の方が良いかな?にしてdefalt値に-1を入れる手段をとるか?選択に迷います。
それにしても、TYPE_FLATがほしいですね。



>>deviation =10;1pipsは狭すぎではないですか?
とほほです。デフォルトのコードを確認せずに使っちゃダメですね。反省します。




まとめ

情けないほどのバグが発見されました。ご指摘くださった@ahaha_fxtraderさんと匿名さんありがとうございました。
今後に生かしたいと思います。