//+------------------------------------------------------------------+
//|                                                      OptimMA.mq4 |
//+------------------------------------------------------------------+
#property copyright "Copyright © 2008, Сергеев Алексей"

#define MaxI 125000
#define MaxTP 20
#define MaxSL 20
#define MaxK 40
double Ma[MaxK]; // абсолютные значения веера МА
double Ma.Sub[MaxK][MaxI]; // относительные значения (разность) веера МА
int Ma.Ident[MaxI];// номера баров идентичных вееров j для i веера
int BuyTP[MaxSL][MaxTP][MaxI];// номер бара на котором сработал профит или лось. >0 - профит, <0 - лось 
double op, ExpValue;
int SL, TP, nSL, nTP, _sl, _tp, _ma, spread, Sum;
double LossPrice, ProfitPrice, OpenPrice;
int i, j, k, ErrorID;
bool find;
string FileName;
int hFile;
// параметры для расчета веера МА
int Price=PRICE_MEDIAN, Mode=MODE_EMA;

//----------------------------------------------------------CreatTPSLData
int CreatTPSLData()
{
	Comment("Создаем TP/SL данные");
	FileName = Symbol()+"_"+Period()+"_ts.buy";	hFile = FileOpen(FileName, FILE_WRITE|FILE_BIN);
	FileSeek(hFile, 0, SEEK_END);
	// составляем массив - исторически достижимые профит и лось
	for (_sl=0; _sl<MaxSL; _sl++)
	{
		SL=25+_sl*5;
		for (_tp=0; _tp<MaxTP; _tp++)
		{
			TP=25+_tp*5;
			for (i=0; i<MaxI; i++)//проходим по всем барам и проверяем условия
			{
				//цены открытия, уровни профита и лоса
				OpenPrice = Open[i]+spread*Point; LossPrice=OpenPrice-SL*Point; ProfitPrice=OpenPrice+TP*Point; 
				k=i; find= false;
				// ищем номер бара, на котором сработал ТП или СЛ
				while (k>=0 && !find) 
				{
					if (Low[k]<=LossPrice) { find = true; FileWriteInteger(hFile, -k); }//если нашли бар СЛ
					else if (High[k]>=ProfitPrice) { find=true; FileWriteInteger(hFile, k); }//если нашли бар ТП
					k--;
					// контроль возможных ошибок
					ErrorID=GetLastError(); if (ErrorID>0)	{ Alert("CreatTPSL= ", ErrorID); return(ErrorID); }
				}
				if (!find) FileWriteInteger(hFile, 0);

				// нижний блок закоментарен. он нужен для составления аналогичного массива для сигналов продажи
				/*
				OpenPrice = Open[i]; LossPrice=OpenPrice+(SL+spread)*Point; ProfitPrice=OpenPrice-(TP+spread)*Point;
				k=i; find= false;
				while (k>=0 && !find) 
				{
					if (High[k]>=LossPrice) { find = true; FileWriteInteger(hFile, -k); }//если нашли бар СЛ
					else if (Low[k]<=ProfitPrice) { find=true; FileWriteInteger(hFile, k); }//если нашли бар ТП
					k--;
					ErrorID=GetLastError(); if (ErrorID>0)	{ Alert("CreatTPSL= ", ErrorID); return(ErrorID); }
				}
				if (!find) FileWriteInteger(hFile, 0);
				*/
			}
			Comment("Завершено SL= "+SL+" | TP= "+TP);
		}
	}
	Comment("Завершено!!!"); FileClose(hFile);	
	return(0);
}
//----------------------------------------------------------ReadTpSlData
int ReadTpSlData()
{
	Comment("2. Берем данные по TP/SL.");
	FileName = Symbol()+"_"+Period()+"_ts.buy";
	hFile=FileOpen(FileName,FILE_BIN|FILE_READ);
	for (_sl=0; _sl<MaxSL; _sl++)
	{
		for (_tp=0; _tp<MaxTP; _tp++)
			for (i=0; i<MaxI; i++) 
				BuyTP[_sl][_tp][i] = FileReadInteger(hFile); 
		Comment("2. Берем данные по TP/SL. Завершено: "+DoubleToStr(_sl*100.0/MaxSL, 1)+"%");
	}
	Comment("Завершено TP/SL");	FileClose(hFile);
	return(0);
}
//----------------------------------------------------------CreatDataArray
int CreatDataArray()
{
	datetime LastFan;
	Comment("1. Расчитываем данные Ma.Sub");
	for (i=0; i<MaxI; i++) // проходим по барам и собираем значения веера МА 
	{
		op=(Open[i]+Close[i])/2.0; 
		for (_ma=0; _ma<MaxK; _ma++) Ma[_ma] = iMA(NULL, 0, 2+_ma*3, 0, Mode, Price, i);
		Ma.Sub[0][i]=op-Ma[1];
		for (_ma=1; _ma<MaxK; _ma++) Ma.Sub[_ma][i]=Ma[_ma-1]-Ma[_ma];
		if (MathMod(i,2500.0)<=0.0) { op = i/1250.0; Comment("Расчитываем данные Ma. Завершено: "+DoubleToStr(op, 1)+"%"); }
	}
	//Взяли данные по TP/SL
	if (ReadTpSlData()>0) return;
	//теперь прогоняем и классифицируем веера
	Comment("3. Поиск идентичных вееров");
	int nFile=1, nFan=0;
	FileName = Symbol()+"_"+Period()+"_fan"+nFile+".csv";
	hFile=FileOpen(FileName,FILE_CSV|FILE_WRITE);	FileSeek(hFile, 0, SEEK_END);
	FileWrite(hFile, "Бар;Время;Прибыль;TP;nTP;SL;nSL;МатОжид;Вееров;ЭтоПрофитный;ПрибыльБара;Последний");
	for (i=1; i<MaxI; i++)// 
	{
		if (MathMod(i,12.5)<=0.0) 
		{ op = i/1250.0; Comment("Поиск идентичных вееров. Завершено: "+DoubleToStr(op, 2)+"% | nFan="+nFan+" | nFile="+nFile); }
		// Проанализиуем каждый веер Ma.Sub. Установим допустимый диапазон попадания в X%.
		// То есть для каждого веера находим такие, которые отличаются от него на +/- X%.
		// Сохраняем совпадения в массив Ma.Ident
		k=1;
		for (j=i+1; j<MaxI; j++)
		{
			find=true; _ma=0; 
			while (_ma<MaxK && find && k<MaxI) // проходим по вееру и классифицируем его
			{
				if (Sign(Ma.Sub[_ma][j])!=Sign(Ma.Sub[_ma][i])) find=false;// если не совпало направление каждой МА
				else 
					if (MathAbs(Ma.Sub[_ma][j])>=MathAbs(Ma.Sub[_ma][i])*1.4 || MathAbs(Ma.Sub[_ma][j])<=MathAbs(Ma.Sub[_ma][i])*0.714) 
						find=false;// или если расстояния между ними не попадают в диапазон
				_ma++;
			}
			if (find) { Ma.Ident[k]=j; k++; LastFan=Time[j]; }
		}
		Ma.Ident[0]=k-1; 
		// первый этап отсеивания вееров, не удовлетворяющие условию МатОжидания
		if (Ma.Ident[0]<11) continue;
		
		for (_sl=0; _sl<MaxSL; _sl++)
		{
			SL=25+_sl*5;// расчетный убыток
			for (_tp=0; _tp<MaxTP; _tp++)
			{
				TP=25+_tp*5; //расчетный профит
				Sum=0;	nSL=0; nTP=0; // обнулили начальные данные
				for (k=1; k<=Ma.Ident[0]; k++)//проходим по всем найденым идентичным веерам и расчитываем убытки и профит
				{
					if (BuyTP[_sl][_tp][Ma.Ident[k]-1]>i) { Sum+=TP; nTP++; }//если попали на профитный бар, то плюсуем
					else { Sum-=SL; nSL++; }//а если на убыточный, то отнимаем лося
				}
				// Веер, у которого количество профитных совпадений будет максимальным - наш искомый победитель.
				ExpValue=nTP*100.0/Ma.Ident[0];
				if (Sum>0 && ExpValue>83.0 && ExpValue<100.0 && nTP>=11) // второй этап отсеивания вееров
				{
					k=IsProfitBar(i-1, 0, TP, SL, OP_BUY); 
					if (k>0) FileWrite(hFile, i+";"+TimeToStr(Time[i])+";"+Sum+";"+TP+";"+nTP+";"+SL+";"+nSL+";"+DoubleToStr(ExpValue, 2)+";"+Ma.Ident[0]+";"+k+";"+TP+";"+Ma.Ident[Ma.Ident[0]]);
					else FileWrite(hFile, i+";"+TimeToStr(Time[i])+";"+Sum+";"+TP+";"+nTP+";"+SL+";"+nSL+";"+DoubleToStr(ExpValue, 2)+";"+Ma.Ident[0]+";"+k+";"+SL+";"+Ma.Ident[Ma.Ident[0]]);
					nFan++;//увеличиваем счетчик записи в файл
					if (nFan>=65500) //если в файл записали больше 65500
					{
						nFan=0; nFile++; FileClose(hFile); //закрываем предыдущий файл
						FileName = Symbol()+"_"+Period()+"_fan"+nFile+".csv";//и открываем новый
						hFile=FileOpen(FileName,FILE_CSV|FILE_WRITE); FileSeek(hFile, 0, SEEK_END);
						FileWrite(hFile, "Бар;Время;Прибыль;TP;nTP;SL;nSL;МатОжид;Вееров;ЭтоПрофитный;ПрибыльБара;Последний");
					}
				}
			}
		}
	}
	FileClose(hFile); Comment("Завершено!");
	return;
}
//-----------------------------------------------------------------------------------IsProfitBar
int IsProfitBar(int iB, int iE, int iTP, int iSL, int dir)
{
	if (dir==OP_BUY)
	{
		//цены открытия, уровни профита и лоса
		OpenPrice = Open[iB]+spread*Point; LossPrice=OpenPrice-iSL*Point; ProfitPrice=OpenPrice+iTP*Point;
		// ищем номер бара, на котором сработал ТП или СЛ для покупки
		for (k=iB; k>=iE; k--) 
			if (Low[k]<=LossPrice) return(-1); //если нашли убыточный бар
			else if (High[k]>=ProfitPrice) return(1); //если нашли профитный бар
	}
	if (dir==OP_SELL)
	{
		OpenPrice = Open[iB]; LossPrice=OpenPrice+(iSL+spread)*Point; ProfitPrice=OpenPrice-(iTP+spread)*Point;
		for (k=iB; k>=0; k--) 
			if (High[k]>=LossPrice) return(0); else if (Low[k]<=ProfitPrice) return(1);
	}
	return (-1);// цена закрытия не определена
}
//-----------------------------------------------------------------------------------IsProfitFan
int IsProfitFan(int iB, int iE, int dir)
{
	double MaTest.Sub[MaxK]; // относительные значения (разность) веера МА
	double MaCur.Sub[MaxK]; // относительные значения (разность) веера МА
	// определили веер для тестируемого бара
	double OpenPrice=(Open[iB]+Close[iB])/2.0; 
	for (_ma=0; _ma<MaxK; _ma++) Ma[_ma] = iMA(NULL, 0, 2+_ma*3, 0, Mode, Price, iB);
	MaTest.Sub[0]=OpenPrice-Ma[1]; for (_ma=1; _ma<MaxK; _ma++) MaTest.Sub[_ma]=Ma[_ma-1]-Ma[_ma];
	// ------------------------------------
	bool find;
	int j, k=1;
	ErrorID=GetLastError(); if (ErrorID>0)	{ Alert("ErrorID1= ", ErrorID); return(-1); }
	// теперь проходим по всем предыдущим барам и находим похожие веера
	for (j=iB+1; j<Bars-1; j++)
	{
		// расчитали j веер
		OpenPrice=(Open[j]+Close[j])/2.0; for (_ma=0; _ma<MaxK; _ma++) Ma[_ma] = iMA(NULL, 0, 2+_ma*3, 0, Mode, Price, j);
		MaCur.Sub[0]=OpenPrice-Ma[1]; for (_ma=1; _ma<MaxK; _ma++) MaCur.Sub[_ma]=Ma[_ma-1]-Ma[_ma];
		find=true; _ma=0; 
		while (_ma<MaxK && find && k<MaxI) // проходим по вееру и классифицируем его
		{
 			if (Sign(MaCur.Sub[_ma])!=Sign(MaTest.Sub[_ma])) find=false;// если не совпало направление каждой МА
			else 
				if (MathAbs(MaCur.Sub[_ma])>=MathAbs(MaTest.Sub[_ma])*1.4 || MathAbs(MaCur.Sub[_ma])<=MathAbs(MaTest.Sub[_ma])*0.714) 
					find=false;// или если расстояния между ними не попадают в диапазон
			_ma++;
		}
		if (find) { Ma.Ident[k]=j; k++; Print(j);}
	}
	return;
	Ma.Ident[0]=k-1;	
	// первый этап отсеивания вееров, не удовлетворяющие условию МатОжидания
	if (Ma.Ident[0]<11) return(-1);

	// Расчет прибыли/убытка бара
	int _tp, _sl;
	for (_sl=0; _sl<MaxSL; _sl++)
	{
		SL=25+_sl*5;// расчетный убыток
		for (_tp=0; _tp<MaxTP; _tp++)
		{
			TP=25+_tp*5; //расчетный профит
			Sum=0; nTP=0; nSL=0; // обнулили начальные данные
			for (j=1; j<=Ma.Ident[0]; j++)//проходим по всем найденым идентичным веерам и расчитываем сумму пунктов
				if (IsProfitBar(Ma.Ident[j]-1, iB, TP, SL, dir)==1) { Sum+=TP; nTP++; }//если попали на профитный бар, то добавляем
				else { Sum-=SL; nSL++; }//а если на убыточный, то отнимам лося
			
			ExpValue=nTP*100.0/Ma.Ident[0]; // матожидание выигрыша
			// определяем систему вероятного положительного исхода
			if (Sum>0 && ExpValue>83.0 && ExpValue<100 && nTP>=11) return (dir);
		}
	}
	ErrorID=GetLastError(); if (ErrorID>0)	{ Alert("ErrorID3= ", ErrorID); return(-1); }
	return(-1);
}
//-----------------------------------------------------------------------------------Sign
int Sign(double n) { if (n>=0.0)	return (1); else return (-1); }

//-----------------------------------------------------------------------------------start
int start()
{
	spread = MarketInfo(Symbol(), MODE_SPREAD);// получили спред инструмента
	// 1. Составляем массив достижимости профита и убытка
	// CreatTPSLData();
	// 2. Проходим по всем барам и создаем файл для анализа
	// CreatDataArray();
}

