305 lines
22 KiB
MQL5
305 lines
22 KiB
MQL5
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
#include <Arrays\ArrayDouble.mqh>
|
|
class Ranger
|
|
{
|
|
private:
|
|
int counter;
|
|
datetime start, vWapStart;
|
|
string symbol;
|
|
ENUM_TIMEFRAMES tf;
|
|
CArrayDouble pr, md, rs;
|
|
double vWap, stopLoss, takeProfit, close[];
|
|
|
|
//Определение диапазонов используя макд
|
|
int RangeCheck()
|
|
{
|
|
//Хэндлы и подготовка
|
|
int macd_handle = iMACD(symbol,tf,12,26,9,PRICE_CLOSE);
|
|
double macd[], sig[];
|
|
ArraySetAsSeries(macd, true);
|
|
ArraySetAsSeries(sig, true);
|
|
//UPD 3 значения в буфере необходимы что бы избежать перерисовки, путем сдвига на 2-1 индекс вместо 1-0
|
|
CopyBuffer(macd_handle,0,0,3,macd);
|
|
CopyBuffer(macd_handle,1,0,3,sig);
|
|
if((macd[2] > 0 && macd[1] < 0) || (macd[2] < 0 && macd[1] > 0))
|
|
{
|
|
start = TimeCurrent();
|
|
}
|
|
else
|
|
if
|
|
(start != TimeCurrent() && ((macd[1] > 0 && sig[2] < macd[2] && sig[1] > macd[1]) || (macd[1] < 0 && sig[2] > macd[2] && sig[1] < macd[1])))
|
|
{
|
|
counter = Bars(symbol,tf,start,TimeCurrent());
|
|
start = TimeCurrent();
|
|
}
|
|
return ((counter > 2 && macd[1] < 0) ? counter+1 : (counter > 2 && macd[1] > 0) ? -counter-1 : NULL);
|
|
};
|
|
|
|
//Заполнение массивов экстремумами
|
|
//Разобраться с заполнением данными, косяки со сдвигами присутствуют//done for now??
|
|
void Arranger()//Сбор и упорядочивание данных для последующих процедур
|
|
{
|
|
int range = MathAbs(RangeCheck());
|
|
if(range-2 > 0 && range < 10000)
|
|
{
|
|
//Volume tests
|
|
MqlRates candle[];
|
|
MqlRates daily[];
|
|
long volArray[];
|
|
vector volume;
|
|
ArraySetAsSeries(volArray, true);
|
|
ArraySetAsSeries(candle, true);
|
|
ArraySetAsSeries(daily,true);
|
|
CopyRates(symbol,tf,1,range,candle);
|
|
CopyRates(symbol,PERIOD_D1,0,1,daily);
|
|
int totalBars = Bars(symbol,tf,daily[0].time,TimeCurrent());
|
|
double avgVol = (double)daily[0].tick_volume/totalBars;
|
|
//Print("Daily Avg Vol: ", avgVol);
|
|
//CopyTickVolume(symbol,tf,candle[range-1].time,candle[1].time,volArray);
|
|
ArrayResize(volArray,range);
|
|
for(int i=0; i<ArraySize(candle); i++)
|
|
{
|
|
volArray[i] = candle[i].tick_volume;
|
|
}
|
|
//ArrayReverse(volArray,0,WHOLE_ARRAY);//что бы объемы соответствовали свече, тики которой скопированы
|
|
volume.Assign(volArray);
|
|
if((volume.Sum()/volume.Size())/avgVol < 1.5)
|
|
{
|
|
pr.Shutdown();
|
|
md.Shutdown();
|
|
rs.Shutdown();
|
|
vWapStart = NULL;
|
|
return;
|
|
}
|
|
//Print("Volume Test OK: ", (volume.Sum()/volume.Size())/avgVol);
|
|
|
|
//If tests OK -> Хэндлы и подготовка
|
|
int macd_handle = iMACD(symbol,tf,12,26,9,PRICE_CLOSE);
|
|
int rsi_handle = iRSI(symbol,tf,14,PRICE_CLOSE);
|
|
double price[], macd[], rsi[];
|
|
|
|
ArraySetAsSeries(price, true);
|
|
ArraySetAsSeries(macd, true);
|
|
ArraySetAsSeries(rsi, true);
|
|
|
|
//Получение последней клозины
|
|
CopyClose(symbol,tf,0,1,close);
|
|
|
|
//Заполнение массивов индикаторов
|
|
CopyBuffer(macd_handle,0,0,range,macd);
|
|
CopyBuffer(rsi_handle,0,0,range,rsi);
|
|
|
|
//Проверка какой из экстремумов использовать, заполнение массива price
|
|
if(macd[0] < 0)
|
|
{
|
|
ArrayResize(price,range);
|
|
for(int i=0; i<ArraySize(candle); i++)
|
|
{
|
|
price[i] = candle[i].low;
|
|
}
|
|
vWapStart = vWapStart == NULL ? candle[ArraySize(candle)-1].time : vWapStart;
|
|
pr.Add(price[ArrayMinimum(price,0,WHOLE_ARRAY)]);
|
|
md.Add(macd[ArrayMinimum(macd,0,WHOLE_ARRAY)]);
|
|
rs.Add(rsi[ArrayMinimum(rsi,0,WHOLE_ARRAY)]);
|
|
counter = 0;
|
|
start = TimeCurrent();
|
|
}
|
|
else
|
|
{
|
|
ArrayResize(price,range);
|
|
for(int i=0; i<ArraySize(candle); i++)
|
|
{
|
|
price[i] = candle[i].high;
|
|
}
|
|
vWapStart = vWapStart == NULL ? candle[ArraySize(candle)-1].time : vWapStart;
|
|
pr.Add(price[ArrayMaximum(price,0,WHOLE_ARRAY)]);
|
|
md.Add(macd[ArrayMaximum(macd,0,WHOLE_ARRAY)]);
|
|
rs.Add(rsi[ArrayMaximum(rsi,0,WHOLE_ARRAY)]);
|
|
counter = 0;
|
|
start = TimeCurrent();
|
|
}
|
|
|
|
//Фильтр последовательности добавлений значений(- за -, + за +)
|
|
if(md.Total() > 0 && ((md.At(0) > 0 && md.At(md.Total()-1) < 0) || (md.At(0) < 0 && md.At(md.Total()-1) > 0)))
|
|
{
|
|
pr.Shutdown();
|
|
md.Shutdown();
|
|
rs.Shutdown();
|
|
vWapStart = NULL;
|
|
return;
|
|
}
|
|
}
|
|
};
|
|
|
|
public:
|
|
double Rrange(string currentSymbol, ENUM_TIMEFRAMES currentTF, int rangesToSignal)
|
|
{
|
|
//Конструктор для дальнейшей передачи в Arranger
|
|
//Доработать проверку на спред. При большом среднем(?) спреде(?) игнорить вход целиком
|
|
symbol = currentSymbol;
|
|
tf = currentTF;
|
|
double signal = 0;
|
|
|
|
Arranger();
|
|
|
|
//Формирование векторов при условии достаточного количества значений, иначе выход
|
|
if(pr.Total() == rangesToSignal && md.Total() == rangesToSignal && rs.Total() == rangesToSignal)
|
|
{
|
|
if((md.At(rangesToSignal-2) > 0 && md.At(rangesToSignal-1) > 0) || (md.At(rangesToSignal-2) < 0 && md.At(rangesToSignal-1) < 0))
|
|
{
|
|
int bb_handle = iBands(symbol,PERIOD_M30,20,0,2,PRICE_CLOSE);
|
|
double upper[], mid[], lower[];
|
|
ArraySetAsSeries(upper,true);
|
|
ArraySetAsSeries(mid,true);
|
|
ArraySetAsSeries(lower,true);
|
|
|
|
CopyBuffer(bb_handle,1,0,3,upper);
|
|
CopyBuffer(bb_handle,0,0,3,mid);
|
|
CopyBuffer(bb_handle,2,0,3,lower);
|
|
|
|
if(md.At(rangesToSignal-1) > 0 && (close[0] > upper[0] || close[0] < mid[0]))
|
|
{
|
|
pr.Shutdown();
|
|
md.Shutdown();
|
|
rs.Shutdown();
|
|
vWapStart = NULL;
|
|
//Print("BB range check false");
|
|
return 0;
|
|
}
|
|
else
|
|
if(md.At(rangesToSignal-1) < 0 && (close[0] < lower[0] || close[0] > mid[0]))
|
|
{
|
|
pr.Shutdown();
|
|
md.Shutdown();
|
|
rs.Shutdown();
|
|
vWapStart = NULL;
|
|
//Print("BB range check false");
|
|
return 0;
|
|
}
|
|
|
|
vector priceRange, mdRange, rsRange;
|
|
priceRange.Init(rangesToSignal);
|
|
mdRange.Init(rangesToSignal);
|
|
rsRange.Init(rangesToSignal);
|
|
|
|
for(int i=0; i<rangesToSignal; i++)
|
|
{
|
|
priceRange[i] = pr.At(i);
|
|
mdRange[i] = md.At(i);
|
|
rsRange[i] = rs.At(i);
|
|
}
|
|
double mdCorr = priceRange.CorrCoef(mdRange);
|
|
double rsCorr = priceRange.CorrCoef(rsRange);
|
|
|
|
signal = (MathAbs(mdCorr)+MathAbs(rsCorr))/2;
|
|
|
|
//Очистка не нужных уже листов, с этого момента начинается работа с векторами
|
|
pr.Shutdown();
|
|
md.Shutdown();
|
|
rs.Shutdown();
|
|
|
|
//Блок работы с данными
|
|
if(mdRange[rangesToSignal-1] < 0 && mdCorr*rsCorr > 0 && (mdCorr < 0 || rsCorr < 0))
|
|
{
|
|
//Подключаем VWAP
|
|
int vWapBars = Bars(symbol,tf,vWapStart,TimeCurrent());
|
|
MqlRates candle[];
|
|
double price[];
|
|
long volumeArray[];
|
|
vector wap, volume;
|
|
|
|
ArraySetAsSeries(candle, true);
|
|
ArraySetAsSeries(price, true);
|
|
ArraySetAsSeries(volumeArray, true);
|
|
ArrayResize(volumeArray,vWapBars);
|
|
ArrayResize(price,vWapBars);
|
|
|
|
CopyRates(symbol,tf,0,vWapBars,candle);
|
|
for(int i=0; i<ArraySize(candle); i++)
|
|
{
|
|
volumeArray[i] = candle[i].tick_volume;
|
|
}
|
|
for(int i=0; i<ArraySize(candle); i++)
|
|
{
|
|
price[i] = candle[i].low;
|
|
}
|
|
|
|
wap.Assign(price);
|
|
volume.Assign(volumeArray);
|
|
|
|
for(ulong i=0; i<wap.Size(); i++)
|
|
{
|
|
wap[i] = wap[i]*volume[i];
|
|
}
|
|
vWap = wap.Sum()/volume.Sum();
|
|
Print(vWap);
|
|
stopLoss = priceRange.Min()*0.9985;
|
|
//Print("StopLoss: ", stopLoss);
|
|
takeProfit = close[0]*1.001;// + (close[0] - stopLoss)*1.5;
|
|
//Print("TakeProfit: ", takeProfit);
|
|
return signal;
|
|
}
|
|
else
|
|
if(mdRange[rangesToSignal-1] > 0 && mdCorr*rsCorr > 0 && (mdCorr < 0 || rsCorr < 0))
|
|
{
|
|
//Подключаем VWAP
|
|
int vWapBars = Bars(symbol,tf,vWapStart,TimeCurrent());
|
|
MqlRates candle[];
|
|
double price[];
|
|
long volumeArray[];
|
|
vector wap, volume;
|
|
|
|
ArraySetAsSeries(candle, true);
|
|
ArraySetAsSeries(price, true);
|
|
ArraySetAsSeries(volumeArray, true);
|
|
ArrayResize(volumeArray,vWapBars);
|
|
ArrayResize(price,vWapBars);
|
|
|
|
CopyRates(symbol,tf,0,vWapBars,candle);
|
|
for(int i=0; i<ArraySize(candle); i++)
|
|
{
|
|
volumeArray[i] = candle[i].tick_volume;
|
|
}
|
|
for(int i=0; i<ArraySize(candle); i++)
|
|
{
|
|
price[i] = candle[i].high;
|
|
}
|
|
|
|
wap.Assign(price);
|
|
volume.Assign(volumeArray);
|
|
|
|
for(ulong i=0; i<wap.Size(); i++)
|
|
{
|
|
wap[i] = wap[i]*volume[i];
|
|
}
|
|
vWap = wap.Sum()/volume.Sum();
|
|
Print(vWap);
|
|
stopLoss = priceRange.Max()*1.0015;
|
|
//Print("StopLoss: ", stopLoss);
|
|
takeProfit = close[0]*0.999;// - (stopLoss - close[0])*1.5;
|
|
//Print("TakeProfit: ", takeProfit);
|
|
return -signal;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
pr.Shutdown();
|
|
md.Shutdown();
|
|
rs.Shutdown();
|
|
vWapStart = NULL;
|
|
return 0;
|
|
}
|
|
}
|
|
return 0;
|
|
};
|
|
|
|
double getSL() {return stopLoss;}
|
|
double getTP() {return takeProfit;}
|
|
double getVWAP() {return vWap;}
|
|
|
|
};
|
|
//+------------------------------------------------------------------+
|
|
|
|
//+------------------------------------------------------------------+
|