//+------------------------------------------------------------------+//| TestCopy.mq4 |//| Copyright 2016, Artem A. Trishkin, Skype artmedia70 |//| https://login.mql5.com/ru/users/artmedia70 |//+------------------------------------------------------------------+#property copyright"Copyright 2016, Artem A. Trishkin, Skype artmedia70"#property link"https://login.mql5.com/ru/users/artmedia70"#property version"1.00"#property strict#property script_show_inputsenum enumYN
{
enYes=1, // Да
enNo=0, // Нет
};
//--- input parametersinputint Search_Period=10; // Количество копируемых свечейint searchPeriod=(Search_Period<1)?1:Search_Period;
inputint Delta=2; // Количество пунктов допускаint delta=(Delta<0)?0:Delta;
input enumYN AsSeries=enYes; // Массив array как таймсерияMqlRates array[]; // Массив структур для копирования Open, High, Low, Close, Timestruct DataCandle // Структура для хранения всех совпадений
{
int number_matched; // Количество совпаденийMqlRates reference_candle; // Данные эталонной свечиMqlRates matched_candles[]; // Массив свечей, совпадающих с эталонной по нужному критерию
};
DataCandle dataCandle[]; // Массив структур данных свечей и их совпадений//+------------------------------------------------------------------+//| Script program start function |//+------------------------------------------------------------------+voidOnStart()
{
//---int copy_bars=(int)fmin(Search_Period,Bars(Symbol(),Period())); // количество копируемых свечейint copied=CopyRates(Symbol(),PERIOD_CURRENT,1,copy_bars,array); // копируем данныеif(copied>0) { // если скопировалиArraySetAsSeries(array,AsSeries); // задаём массив как таймсерию или нетArrayResize(dataCandle,copied); // задаём размер структуры равным числу скопированных данныхZeroMemory(dataCandle); // Обнуляем данные в структуре//--- основной цикл по "эталонным" свечам в массиве array. Их параметры будем искать в доп. циклеfor(int i=0; i<copy_bars-1; i++) { // цикл по скопированным данным от начала до "на один меньше размера массива"
dataCandle[i].reference_candle.high=array[i].high; // ищем этот high
dataCandle[i].reference_candle.low=array[i].low; // запомнили low для сравнения
dataCandle[i].reference_candle.time=array[i].time; // запомнили time для вывода в журнал//--- поиск совпадений с эталонной свечой, индексируемой индексом основного цикла iint size=0; // размер массива совпадающих свечейArrayResize(dataCandle[i].matched_candles,size); // Размер массива совпадений в ноль
dataCandle[i].number_matched=size; // Инициализируем количество совпадений нулём//--- теперь ищем совпадения по high свечей в цикле j с high эталонной свечи с индексом ifor(int j=0; j<copy_bars; j++) { // в цикле от i+1 до copy_barsif(j==i) continue; // пропустим свечу "саму себя"//--- если совпадают high эталонной свечи (i) и свечи с индексом j (с допуском на величину Point)if(NormalizeDouble(delta*Point()-fabs(array[i].high-array[j].high),Digits())>=0) {
size++;
ArrayResize(dataCandle[i].matched_candles,size); // увеличим размер массива совпадающих свечей
dataCandle[i].number_matched=size; // запишем количество совпадений
dataCandle[i].matched_candles[size-1].high=array[j].high; // запишем в массив high совпадающей свечи
dataCandle[i].matched_candles[size-1].low=array[j].low; // запишем в массив low совпадающей свечи
dataCandle[i].matched_candles[size-1].time=array[j].time; // запишем в массив время совпадающей свечи//Print("Время свечи ",i," :",TimeToString(dataCandle[i].reference_candle.time=array[i].time),", high=",DoubleToString(dataCandle[i].reference_candle.high=array[i].high,Digits()),". Совпадение со свечой ",TimeToString(dataCandle[i].matched_candles[size-1].time=array[j].time),", её high ",DoubleToString(dataCandle[i].matched_candles[size-1].high=array[j].high,Digits()),". Совпадений: ",(string)dataCandle[i].number_matched);
}
}
}
}
//--- Посмотрим чего понаписали в массивыAlert("Array is series: ",ArrayIsSeries(array),
"\ntime array[0]: ",TimeToString(array[0].time,TIME_DATE|TIME_MINUTES),
"\ntime array[",string(searchPeriod-1),"]: ",TimeToString(array[ArraySize(array)-1].time,TIME_DATE|TIME_MINUTES));
for(int i=0; i<ArraySize(dataCandle)-1; i++) {
string refs_txt="";
string matched_txt="";
refs_txt="Свеча "+IntegerToString(i,2,'0')+": время "+TimeToString(dataCandle[i].reference_candle.time)+", high: "+DoubleToString(dataCandle[i].reference_candle.high,Digits())+" имеет совпадений: "+(string)dataCandle[i].number_matched+" шт. ";
if(dataCandle[i].number_matched>0) {
for(int j=0; j<ArraySize(dataCandle[i].matched_candles); j++) {
matched_txt="Совпадение "+IntegerToString(j+1)+": "+TimeToString(dataCandle[i].matched_candles[j].time)+", high: "+DoubleToString(dataCandle[i].matched_candles[j].high,Digits());
}
}
Print(refs_txt,matched_txt);
}
}
//+------------------------------------------------------------------+
DataCandlesは構造体である。ヒストリーからローソク足を書き込む配列はarray[]です。そこで、そのインデックスをチャート上のローソク足のインデックスと一致させるために、時系列として作成する必要があるのです。つまり、array[]の0番目のセルが、現在の日付に最も近いローソク足に対応することになります。
すなわち、1.ローソク足を配列array[]にコピーし、2.それを時系列にし、そこから値を構造体に読み込むのです。
あなたは、配列[]なしで行うことができます - ちょうど構造体にチャートから直接データを書き込むが、私は5との互換性のためにこれを提案 - それは唯一の高[i]、低[i]と他のデータを使用してインジケータで直接コピーすることができますが、スクリプトまたはエキスパートアドバイザーで、我々は最初の配列に必要な履歴間隔をコピーする必要があります、これは私がやったこと。
アラート(シリーズ)。
このように?
両方のアラートはまだfalseを返します
アラート(シリーズ)。
このように?
両方のアラートはまだfalseを返します
というわけで、これは「エラー、バグ、質問」に報告すべきバグです。
このスクリプトは、ローソク足がコピーされた時刻を、array[]の0番目と最後のセルに表示します。
ですから、これは「エラー、バグ、質問」に報告されるべきバグです。
このスクリプトは、ローソク足がコピーされた時刻を、array[]の0番目と最後のセルに表示します。
これを出力する。
配列が直列である:false
time array[0]: 2016.05.12 21:00
時間配列[9]:2016.05.12 12:00
こう出てきます。
配列が直列である:false
time array[0]: 2016.05.12 21:00
時間配列[9]:2016.05.12 12:00
スクリプトの開始時に時系列としてArray arrayを「Yes」と選択すると、常にfalseであるが時刻は正しい。
いいえ」を選択した場合。
配列に書き込まれたローソク足の時間が逆になっています。つまり、ArraySetAsSeriess() は 正しく動作しますが、ArrayIsSeries() は動作せず、常にfalseを出力します。これは、上記のバグスレッドに既に書きました。
ああ、このプログラミング。森の奥へ進むほど...。
配列の向きを知る必要はないことを理解する。アルゴリズムは、繰り返しを探している。だから、バーの処理順序は問わない。
が必要です。なぜなら、どのローソク足が一致したかを調べ、現在の 価格に最も近いところから安値を取る必要があるからです。
そのための仕組みとして、キャンドルタイムがあり、それによって、必要な時間に最も近いキャンドルを見つけることができます。
また、ローソク足番号は出力する必要はありません。実際のバー番号とは一致しません。なぜなら、配列を埋めて、配列の中のインデックスは、チャート上ではなく、配列の中のローソク足の番号にのみ属しているからです。
私はそれが何を与えるかをチェックしました - 常に偽ですが、時間は正しいです:スクリプトを実行するときに時系列の "はい "としてArray配列を選択した場合、その後。
いいえ」を選択した場合。
配列に書き込まれたローソク足の時間は逆になっており、ArraySetAsSeriess()は正しく動作しますが、ArrayIsSeries()は動作せず、常にfalseを出力します。これは既に上記のバグスレッドに書き込んであります。
コードを少し修正しました。
ArraySetAsSeries(array,true); //ここにtrueを入れるだけです。
を作成し、ローソク足の本数を追加してセルフチェックを行いました。
Alert("Array is series: ",ArrayIsSeries(array),
"⑯キャンドル" +IntegerToString(0,2,'0')+" 時間 array[0]: ",TimeToString(array[0].time,TIME_DATE|TIME_MINUTES)",
"ⅷ時間配列[", string(searchperiod-1),"]:",TimeToString(array[ArraySize(array)-1].time,TIME_DATE|TIME_MINUTES)");
次のように出力されます。
配列が直列である:false
キャンドル00時刻配列[0]:2016.05.12 22:00
キャンドル09時間配列[9]:2016.05.12 13:00
これを行うには、構造内にキャンドルタイムがあり、それによって必要な任意の時間に最も近いキャンドルを見つけることができます。
コードを少し変更しました。
ArraySetAsSeries(array,true); //ここにtrueを入れるだけです。
を作成し、ローソク足の本数を追加してセルフチェックを行いました。
Alert("Array is series: ",ArrayIsSeries(array),
"⑯キャンドル" +IntegerToString(0,2,'0')+" 時間 array[0]: ",TimeToString(array[0].time,TIME_DATE|TIME_MINUTES)",
"ⅷ時間配列[", string(searchperiod-1),"]:",TimeToString(array[ArraySize(array)-1].time,TIME_DATE|TIME_MINUTES)");
次のように出力されます。
配列が直列である:false
Candle 00 time array[0]: 2016.05.12 22:00
キャンドル09時間配列[9]:2016.05.12 13:00