Navigation:Home > Content >

+Index.mq4

Time: 2015-03-03 | Download file:+Index.mq4

#property copyright "Индекс. +Index.mq4 4.1.3. © 2008-2012 Plus."
#property link "http://fxcoder.ru"

#property indicator_separate_window
#property indicator_buffers 1
#property indicator_color1 LimeGreen
#property indicator_width1 1

// [/|-]Index [BaseCurr] [CalcCurrs] [AppliedPrice] [Dirty] [Log] [Reverse]
// Если не заполнено, используется раздельное указание параметров
extern string Params = "";

// Имя валюты индекса
extern string Index = "USD";

// Реверс (1/x)
extern bool Reverse = false;

// Базовая валюта для получения котировок (кроссы будут рассчитаны через кроссы этой валюты)
extern string BaseCurr = "USD";

// Набор валют, по которым рассчитывается индекс
// Мажоры: "AUD,CAD,CHF,EUR,GBP,JPY,NZD,USD";
// Добавочные: SGD,DKK,MXN,NOK,SEK,ZAR
// Некоторые CFD: "usd,#aa,#aapl,#amzn,#axp,#ba,#bac,#cat,#csco,#cvx,#dd,#dis,#ebay,#ek,#fcx,#fdx,#ge,#goog,#gs,#hal,#hd,#hon,#hpq,#ibm,#intc,#ip,#jnj,#jpm,#kft,#ko,#mcd,#mmm,#mo,#mrk,#msft,#orcl,#pep,#pfe"
extern string CalcCurrs = "AUD,CAD,CHF,EUR,GBP,JPY,NZD,USD";

// Используемая для вычислений цена
extern int AppliedPrice = PRICE_CLOSE;

// Грязный режим без проверки наличия баров, годится только для больших тф, где не бывает дыр.
extern bool Dirty = false;

// Массив линии
double I[];

// Параметры индекса
string syms[];
int dirs[];
bool indexInitialized = false;
int crossCount;

bool doCalcBar;
string mainSym;

int start()
{
	// проверить, инициализированы ли параметры расчета индекса
	if (!indexInitialized)
		return(0);
	
	// бары для расчета
	int counted_bars = IndicatorCounted();
	if (counted_bars > 0)
		counted_bars--;
	int barsCount = Bars - counted_bars;

	int bar;
	for (int i = barsCount - 1; i >= 0; i--)
	{
		if (doCalcBar)
		{
			datetime time = Time[i];                             // 1. время, для которого нужно найти значение формулы
			int barShift = iBarShift(mainSym, 0, time);          // 2. ближайший бар основного символа для этого времени
			datetime mainSymTime = iTime(mainSym, 0, barShift);  // 3. точное время для определенного бара
			if (mainSymTime > time)                              // 4. коррекция временя найденного бара, если iBarShift 
				mainSymTime -= Period() * 60;                    //    налажал (сдвинул вправо)
			bar = iBarShiftX(Symbol(), 0, mainSymTime);          // 5. точный бар текущего символа для времени значения формулы
		}
		else
		{
			bar = i;
		}

		/*if (i == 0)
			Comment(mainSym + ": " + bar + ", " + TimeToStr(mainSymTime));
		else
			Comment("");*/

		// значение индекса
		double value = Index(syms, dirs, crossCount, AppliedPrice, Dirty, bar);

		// проверка результата и реверс
		if (value > 0)
		{
			if (Reverse)
				I[i] = 1.0 / value;
			else
				I[i] = value;
		}
		else
		{
			I[i] = EMPTY_VALUE;
		}
	}

	return(0);
}

int init()
{
	// Если параметры заданые одной строкой в Params, попробовать расшифровать
	if (StringLen(Params) != 0)
	{
		if (!ParseIndexParams(Params, Index, Reverse, BaseCurr, CalcCurrs, AppliedPrice, Dirty))
		{
			IndicatorShortName(WindowExpertName() + ": неверные входные параметры.");
			return(0);
		}
	}
	else
	{
		// Иначе подправляем прочие параметры
		CalcCurrs = UpperString(CalcCurrs);
		Index = UpperString(Index);
	}

	// Заменить специальные обозначения, если текущий символ для этого подходит (нужна валюта, 6 знаков)
	if (StringLen(Symbol()) == 6)
	{
		if (Index == "1")
			Index = StringSubstr(Symbol(), 0, 3);
		else if (Index == "2")
			Index = StringSubstr(Symbol(), 3, 3);
	}
	
	// Инициализация индекса (поиск составляющих формулы)
	indexInitialized = InitIndex(Index, BaseCurr, CalcCurrs, syms, dirs, crossCount);
	mainSym = syms[0];
	doCalcBar = !Dirty && (mainSym != Symbol());
 
	//Comment(GetIndexFormula(syms, dirs, crossCount));

	string name = "+Index: " + If2s(Reverse, "/") + Index + "," + AppliedPriceToString(AppliedPrice) + If2s(Dirty, ",dirty");
	SetIndexLabel(0, name);
	IndicatorShortName(StringSubstr(name, 0, 63));
	SetIndexStyle(0, DRAW_LINE);
	SetIndexBuffer(0, I);

	return(0);
}

int deinit()
{
	return(0);
}

// xlib\convert.mqh
// Библиотека XLib. © 2011 Plus (FXcoder.ru).
// Функции преобразования. convert.mqh 1.9.0

// Тип цены в строку
string AppliedPriceToString(int ap, bool verbose = false)
{
	if (verbose)
	{
		switch (ap)
		{
			case 0: return("Close");
			case 1: return("Open");
			case 2: return("High");
			case 3: return("Low");
			case 4: return("Median");
			case 5: return("Typical");
			case 6: return("Weighted");
			default: return("Unknown");
		}
	}
	else
	{
		switch (ap)
		{
			case 0: return("C");
			case 1: return("O");
			case 2: return("H");
			case 3: return("L");
			case 4: return("HL");
			case 5: return("HLC");
			case 6: return("HLCC");
			default: return("?");
		}
	}
}

// xlib\strings.mqh
// Библиотека XLib. © 2011 Plus (FXcoder.ru).
// Работа со строками. strings.mqh 1.3.2

// Убирает указанные символы в начале строки
string TrimLeft(string s, int char = 0)
{
	if (char == 0)
	{	
		s = StringTrimLeft(s);
	}
	else
	{
		int len = StringLen(s);
		
		// слева
		int cut = 0;
		for (int i = 0; i < len; i++)
		{
			if (StringGetChar(s, i) == char)
				cut++;
			else
				break;
		}
		
		if (cut > 0)
		{
			if (cut > len - 1)
				s = "";
			else
				s = StringSubstr(s, cut);
		}
	}
	return(s);
}

// Убирает указанные символы в конце строки
string TrimRight(string s, int char = 0)
{
	if (char == 0)
	{	
		s = StringTrimLeft(s);
	}
	else
	{
		int len = StringLen(s);
		
		// справа
		int cut = len;
		for (int i = len - 1; i >= 0; i--)
		{
			if (StringGetChar(s, i) == char)
				cut--;
			else
				break;
		}
		
		if (cut != len)
		{
			if (cut == 0)
				s = "";
			else
				s = StringSubstr(s, 0, cut);
		}		
	}
	return(s);
}

// Убрать пустые символы в начале и конце строки
string Trim(string s, int char = 0)
{
	if (char == 0)
		return(StringTrimLeft(StringTrimRight(s)));
	else
		return(TrimLeft(TrimRight(s, char), char));
}

// Разбить строку
int SplitString(string s, string sep, string& parts[], bool removeEmpty = false)
{
	int count = 0;
	int sepLen = StringLen(sep);
	//ArrayResize(parts, count);

	string part;
	while (true)
	{
		int p = StringFind(s, sep);
		if (p >= 0)
		{
			if (p == 0)
				part = "";
			else
				part = StringSubstr(s, 0, p);
			//Print("part: [" + part + "], p+sepLen: " + (p + sepLen));

			if (!removeEmpty || (Trim(part) != ""))
			{
				count++;
				ArrayResize(parts, count);
				parts[count - 1] = part;
			}

			s = StringSubstr(s, p + sepLen);
			//Print("s: [" + s + "]");
		}
		else
		{
			// Последний кусок
			if (!removeEmpty || (Trim(s) != ""))
			{
				count++;
				ArrayResize(parts, count);
				parts[count - 1] = s;
			}
			break;
		}		
	}
	
	// удалить последнюю пустую строку
	if ((count > 0) && (parts[count - 1] == ""))
	{
		count--;
		ArrayResize(parts, count);
	}
	
	return(count);
}

// Перевести строку в верхний регистр
string UpperString(string s)
{
	int c = StringLen(s);
	int ch;
	for (int i = 0; i < c; i++)
	{
		// Upper char
		ch = StringGetChar(s, i);
		if ((ch > 96 && ch < 123) || (ch > 223 && ch < 256))
			ch -= 32;

		s = StringSetChar(s, i, ch);
	}
	return(s);
}

// xlib\logic.mqh
// Библиотека XLib. © 2011 Plus (FXcoder.ru).
// Функции логики. logic.mqh 1.0.1

// Если условие верно, вернуть s1, иначе s2
string If2s(bool c, string s1, string s2 = "")
{
	if (c)
		return(s1);
	else
		return(s2);
}

// +indicators\index.mqh
// Библиотека +Indicators. © 2011 Plus. http://fxcoder.ru
// Индекс валюты. +index.mqh 4.1.3

// Инициализировать индекс (получить компоненты формулы)
bool InitIndex(string index, string baseCurr, string calcCurrs, string& syms[], int& dirs[], int& crossCount)
{
	ArrayResize(syms, 0);
	ArrayResize(dirs, 0);

	string currs[];	
	crossCount = SplitString(calcCurrs, ",", currs, true);
	if (StringArrayIndexOf(currs, index) == -1)
		crossCount++;
	
	bool ok = crossCount > 0;
	ok = ok && index__getSymbols(index, baseCurr, currs, syms, dirs);
	
	return(ok);
}

// Получить значение индекса
double Index(string& syms[], int& dirs[], int crossCount, int ap, bool dirty, int bar)
{
	int c = 0;
	double value, q;
	
	// перебираем все символы
	value = 1.0;

	int sc = ArraySize(syms);
	
	for (int j = 0; j < sc; j++)
	{
		q = index__price(syms[j], ap, dirty, bar);
		if (q > 0)
		{
			value *= MathPow(q, 1.0 * dirs[j] / crossCount);
			c++;
		}
		else
		{
			value = 0;
			break;
		}
	}

	if (value == 0 || sc == 0)
		value = 0.0;
		
	return(value);
}

// Разобрать параметры индекса, указанные одной строкой, формат:
//     [/|-]index [baseCurr] [calcCurrs] [appliedPrice] [dirty] [log] [reverse]
bool ParseIndexParams(string indexParams, string &index, bool &reverse, string &baseCurr, string &calcCurrs, 
	int &ap, bool &dirty)
{
	// Параметры по умолчанию
	index = "";
	reverse = false;
	baseCurr = "USD";
	calcCurrs = "AUD,CAD,CHF,EUR,GBP,JPY,NZD,USD";
	ap = PRICE_CLOSE;
	dirty = false;
	
	string params[];
	int count = SplitString(UpperString(indexParams), " ", params, true);

	// распознавание параметров, кроме первого
	for (int i = 1; i < count; i++)
	{
		string param = params[i];
		if (param == "DIRTY")
			dirty = true;
		else if ((param == "REVERSE") || (param == "REV"))
			reverse = true;
		else if (param == "CLOSE")
			ap = PRICE_CLOSE;
		else if (param == "OPEN")
			ap = PRICE_OPEN;
		else if (param == "HIGH")
			ap = PRICE_HIGH;
		else if (param == "LOW")
			ap = PRICE_LOW;
		else if (param == "HL")
			ap = PRICE_MEDIAN;
		else if (param == "HLC")
			ap = PRICE_TYPICAL;
		else if (param == "HLCC")
			ap = PRICE_WEIGHTED;
		else if (param == "0")
			ap = PRICE_CLOSE;
		else if (param == "1")
			ap = PRICE_OPEN;
		else if (param == "2")
			ap = PRICE_HIGH;
		else if (param == "3")
			ap = PRICE_LOW;
		else if (param == "4")
			ap = PRICE_MEDIAN;
		else if (param == "5")
			ap = PRICE_TYPICAL;
		else if (param == "6")
			ap = PRICE_WEIGHTED;
		else if (StringFind(param, ",") != -1)
			calcCurrs = param;
		else if (StringLen(param) == 3)
			baseCurr = param;
	}

	if (count > 0)
	{
		// реверс?
		index = params[0];
		if (StringLen(index) != 0)
		{
			int ch = StringGetChar(index, 0);
			if (ch == '/' || ch == '-')
			{
				reverse = true;
				index = StringSubstr(index, 1);
			}
		}
	}
	else
	{
		return(false);
	}
			
	return(index != "");
}

// Получить список символов и их степени в формуле для расчета индекса
bool index__getSymbols(string index, string baseCurr, string& currs[], string& syms[], int& dirs[])
{
	bool ok = true;
	
	// количество валют для расчета
	int cc = ArraySize(currs);

	for (int i = 0; i < cc; i++)
	{
		string curr2 = currs[i];
		if (index != curr2)
		{
			if (index == baseCurr)
				index__addSymbol(baseCurr, curr2, syms, dirs);
			else if (curr2 == baseCurr)
				index__addSymbol(index, baseCurr, syms, dirs);
			else
			{
				if (!(index__addSymbol(index, baseCurr, syms, dirs) 
						&& index__addSymbol(baseCurr, curr2, syms, dirs)))
				{
					ok = false;
					break;
				}
			}
		}
	}

	if (ok)
	{
		ok = ok && (ArraySize(syms) != 0);
	}
	else
	{
		ArrayResize(syms, 0);
		ArrayResize(dirs, 0);
	}
	
	return(ok);
}

// Добавить символ в формулу расчета индекса
// Варианты curr1/curr2: EUR/USD, #AA/USD, USD/_SP500, USD/AUD.
bool index__addSymbol(string curr1, string curr2, string& syms[], int& dirs[])
{
	// Получить правильное название символа на основе двух составляющих
	string sym = "";
	bool isCross = true;
	
	// CFD и индексы
	if (curr2 == "USD" && (StringGetChar(curr1, 0) == '#' || StringGetChar(curr1, 0) == '_'))
	{
		sym = curr1;
		isCross = false;
	}
	else if (curr1 == "USD" && (StringGetChar(curr2, 0) == '#' || StringGetChar(curr2, 0) == '_'))
	{
		sym = curr2;
		isCross = false;
	}
	else
	{
		sym = curr1 + curr2;
	}
	
	// проверить наличие символа в обзоре рынка
	if (MarketInfo(sym, MODE_BID) <= 0 && isCross)
	{
		sym = curr2 + curr1;
		if (MarketInfo(sym, MODE_BID) <= 0)
			sym = "";
	}
	
	// Определить направление
	if (sym != "")
	{
		int si = StringArrayIndexOf(syms, sym);
		if (isCross)
		{
			if (si >= 0)
			{
				// Если такой символ уже есть в наборе, то изменить его степень
				if (curr1 == StringSubstr(sym, 0, 3))
					dirs[si]++;
				else
					dirs[si]--;
			}
			else
			{
				// Добавить новый символ в набор
				StringArrayAdd(syms, sym);
		
				if (curr1 == StringSubstr(sym, 0, 3))
					IntArrayAdd(dirs, 1);
				else
					IntArrayAdd(dirs, -1);
			}
		}
		else
		{
			if (si >= 0)
			{
				// Если такой символ уже есть в наборе, то изменить его степень
				if (curr1 == sym)
					dirs[si]++;
				else
					dirs[si]--;
			}
			else
			{
				// Добавить новый символ в набор
				StringArrayAdd(syms, sym);
		
				if (curr1 == sym)
					IntArrayAdd(dirs, 1);
				else
					IntArrayAdd(dirs, -1);
			}
		}
				
		return(true);
	}
	
	return(false);
}

double index__price(string symbol, int ap, bool dirty, int bar)
{
	double p = 0.0;
	double o = 1;
	double h = 1;
	double l = 1;
	double c = 1;

	if (!dirty && (symbol != Symbol()))
		bar = iBarShiftX(symbol, Period(), Time[bar]);
	
	switch(ap)
	{
		case 0:
			c = iClose(symbol, 0, bar);
			if (c != 0)
				p = c;
			break;
	
		case 1:
			o = iOpen(symbol, 0, bar);
			if (o != 0)
				p = o;
			break;
	
		case 2:
			h = iHigh(symbol, 0, bar);
			if (h != 0)
				p = h;
			break;
	
		case 3:
			l = iLow(symbol, 0, bar);
			if (l != 0)
				p = l;
			break;
	
		case 4:
			h = iHigh(symbol, 0, bar);
			l = iLow(symbol, 0, bar);
			if (h != 0 && l != 0)
				p = (h + l) / 2.0;
			break;
	
		case 5:
			h = iHigh(symbol, 0, bar);
			l = iLow(symbol, 0, bar);
			c = iClose(symbol, 0, bar);
			if (h != 0 && l != 0 && c != 0)
				p = (h + l + c) / 3.0;
			break;
	
		case 6:
			h = iHigh(symbol, 0, bar);
			l = iLow(symbol, 0, bar);
			c = iClose(symbol, 0, bar);
			if (h != 0 && l != 0 && c != 0)
				p = (h + l + 2.0 * c) / 4.0;
			break;
			
		default:
			c = iClose(symbol, 0, bar);
			if (c != 0)
				p = c;
	}

	
	return(p);
}

// xlib\array.mqh
// Библиотека XLib. © 2011 Plus (FXcoder.ru).
// Работа с массивами. array.mqh 1.6.0

// Найти элемент строкового массива по значению, начиная с элемента startingFrom, и вернуть индекс
//TODO: протестировать
int StringArrayIndexOf(string& array[], string value, int startingFrom = 0)
{
	int index = - 1;
	int count = ArraySize(array);
	for (int i = startingFrom; i < count; i++)
	{
		if (array[i] == value)
		{
			index = i;
			break;
		}
	}
	
	return(index);
}

// Добавить в массив (string) значение и вернуть его индекс
int StringArrayAdd(string& sa[], string s)
{
	int c = ArraySize(sa);
	ArrayResize(sa, c + 1);
	sa[c] = s;
	return(c);
}

// Добавить в массив (int) значение и вернуть его индекс
int IntArrayAdd(int& ia[], int i)
{
	int c = ArraySize(ia);
	ArrayResize(ia, c + 1);
	ia[c] = i;
	return(c);
}

// xlib\math.mqh
// Библиотека XLib. © 2011 Plus (FXcoder.ru).
// Математические функции. math.mqh 1.3.3

// +fix.mqh
// © 2011 Plus. http://fxcoder.ru
// Исправление стандартных функций. +fix.mqh 1.0.0

// Определить бар по времени с возможным сдвигом влево, если для указанного времени бара нет
int iBarShiftX(string symbol, int timeframe, datetime time, bool exact = false)
{
	int barShift = iBarShift(symbol, timeframe, time, exact);
	
	// проверить, чтобы бар был не справа по времени
	if (!exact && iTime(symbol, timeframe, barShift) > time)
		barShift++;
	
	return(barShift);	
}

Recommend