393 lines
12 KiB
MQL5
393 lines
12 KiB
MQL5
//+------------------------------------------------------------------+
| |||
//| CBarsbydate.mqh |
| |||
//| Based on Price.mqh (Andrew Young) |
| |||
//+------------------------------------------------------------------+
| |||
#property strict
| |||
| |||
#property copyright "Andrew Young"
| |||
#property link "http://www.expertadvisorbook.com"
| |||
| |||
//+------------------------------------------------------------------+
| |||
//| |
| |||
//+------------------------------------------------------------------+
| |||
class CBarsbydate
| |||
{
| |||
private:
| |||
int BarCount;
| |||
string symbol;
| |||
| |||
public:
| |||
MqlRates bar[];
| |||
| |||
CBarsbydate(void);
| |||
| |||
// --- Range loading ---
| |||
// Loads bars from [fromTime .. toTime] inclusive-ish (broker availability rules apply)
| |||
int UpdateRange(string pSymbol, ENUM_TIMEFRAMES pPeriod, datetime fromTime, datetime toTime);
| |||
| |||
// Convenience:
| |||
// useMonths=true -> monthsCount means months back
| |||
// useMonths=false -> monthsCount means candle count
| |||
int UpdateFromMonthsBack(string pSymbol, ENUM_TIMEFRAMES pPeriod, int monthsCount, bool useMonths = true);
| |||
| |||
// --- Accessors ---
| |||
double Close(int pShift);
| |||
double High(int pShift);
| |||
double Low(int pShift);
| |||
double Open(int pShift);
| |||
datetime Time(int pShift);
| |||
long TickVolume(int pShift);
| |||
long Volume(int pShift);
| |||
| |||
// --- Extract arrays ---
| |||
void GetCloses(double &closes[]);
| |||
void GetOpens(double &opens[]);
| |||
void GetHighs(double &highs[]);
| |||
void GetLows(double &lows[]);
| |||
void GetTimes(datetime ×[]);
| |||
void GetVolumes(long &volumes[]);
| |||
| |||
int GetBarCount();
| |||
int IndexByTime(datetime t);
| |||
double Point();
| |||
| |||
int Size()
| |||
{
| |||
return ArraySize(bar);
| |||
}
| |||
| |||
bool UpdateLastBar(const MqlRates &rate);
| |||
bool AppendBar(const MqlRates &rate);
| |||
| |||
private:
| |||
datetime FirstOfPreviousMonths(datetime currentTime, int monthsBack);
| |||
};
| |||
| |||
//+------------------------------------------------------------------+
| |||
//| |
| |||
//+------------------------------------------------------------------+
| |||
CBarsbydate::CBarsbydate(void)
| |||
{
| |||
BarCount = 0;
| |||
| |||
// IMPORTANT:
| |||
// index 0 = oldest, index BarCount - 1 = newest.
| |||
// DO NOT ArraySetAsSeries(bar, true).
| |||
}
| |||
| |||
//+------------------------------------------------------------------+
| |||
//| |
| |||
//+------------------------------------------------------------------+
| |||
datetime CBarsbydate::FirstOfPreviousMonths(datetime currentTime, int monthsBack)
| |||
{
| |||
MqlDateTime dt;
| |||
TimeToStruct(currentTime, dt);
| |||
| |||
dt.mon -= monthsBack;
| |||
while(dt.mon <= 0)
| |||
{
| |||
dt.mon += 12;
| |||
dt.year--;
| |||
}
| |||
| |||
dt.day = 1;
| |||
dt.hour = 0;
| |||
dt.min = 0;
| |||
dt.sec = 0;
| |||
| |||
return StructToTime(dt);
| |||
}
| |||
| |||
//+------------------------------------------------------------------+
| |||
//| Load bars by time range |
| |||
//| bar[0] oldest, bar[count-1] newest |
| |||
//+------------------------------------------------------------------+
| |||
int CBarsbydate::UpdateRange(string pSymbol, ENUM_TIMEFRAMES pPeriod, datetime fromTime, datetime toTime)
| |||
{
| |||
ArrayResize(bar, 0);
| |||
BarCount = 0;
| |||
symbol = pSymbol;
| |||
| |||
if(fromTime <= 0 || toTime <= 0 || toTime <= fromTime)
| |||
{
| |||
Print("CBarsbydate::UpdateRange invalid times. from=", TimeToString(fromTime),
| |||
" to=", TimeToString(toTime));
| |||
return 0;
| |||
}
| |||
| |||
MqlRates temp[];
| |||
ArraySetAsSeries(temp, false);
| |||
| |||
int copied = CopyRates(pSymbol, pPeriod, fromTime, toTime, temp);
| |||
if(copied <= 0)
| |||
{
| |||
Print("CBarsbydate::UpdateRange CopyRates failed. err=", GetLastError(),
| |||
" from=", TimeToString(fromTime), " to=", TimeToString(toTime));
| |||
return 0;
| |||
}
| |||
| |||
ArrayResize(bar, copied);
| |||
for(int i = 0; i < copied; i++)
| |||
bar[i] = temp[i];
| |||
| |||
BarCount = copied;
| |||
return copied;
| |||
}
| |||
| |||
//+------------------------------------------------------------------+
| |||
//| Convenience: |
| |||
//| useMonths=true -> monthsCount means months back |
| |||
//| useMonths=false -> monthsCount means candle count |
| |||
//+------------------------------------------------------------------+
| |||
int CBarsbydate::UpdateFromMonthsBack(string pSymbol, ENUM_TIMEFRAMES pPeriod, int monthsCount, bool useMonths = true)
| |||
{
| |||
symbol = pSymbol;
| |||
| |||
if(monthsCount <= 0)
| |||
{
| |||
Print("CBarsbydate::UpdateFromMonthsBack invalid monthsCount=", monthsCount);
| |||
ArrayResize(bar, 0);
| |||
BarCount = 0;
| |||
return 0;
| |||
}
| |||
| |||
ArrayResize(bar, 0);
| |||
BarCount = 0;
| |||
| |||
if(useMonths)
| |||
{
| |||
datetime toTime = TimeCurrent();
| |||
datetime fromTime = FirstOfPreviousMonths(toTime, monthsCount);
| |||
return UpdateRange(pSymbol, pPeriod, fromTime, toTime);
| |||
}
| |||
| |||
MqlRates temp[];
| |||
ArraySetAsSeries(temp, false);
| |||
| |||
int copied = CopyRates(pSymbol, pPeriod, 0, monthsCount, temp);
| |||
if(copied <= 0)
| |||
{
| |||
Print("CBarsbydate::UpdateFromMonthsBack CopyRates by count failed. err=", GetLastError(),
| |||
" count=", monthsCount);
| |||
return 0;
| |||
}
| |||
| |||
ArrayResize(bar, copied);
| |||
for(int i = 0; i < copied; i++)
| |||
bar[i] = temp[i];
| |||
| |||
BarCount = copied;
| |||
return copied;
| |||
}
| |||
| |||
//+------------------------------------------------------------------+
| |||
//| |
| |||
//+------------------------------------------------------------------+
| |||
double CBarsbydate::Point()
| |||
{
| |||
return SymbolInfoDouble(symbol, SYMBOL_POINT);
| |||
}
| |||
| |||
//+------------------------------------------------------------------+
| |||
//| |
| |||
//+------------------------------------------------------------------+
| |||
int CBarsbydate::GetBarCount(void)
| |||
{
| |||
return BarCount;
| |||
}
| |||
| |||
//+------------------------------------------------------------------+
| |||
//| |
| |||
//+------------------------------------------------------------------+
| |||
double CBarsbydate::Close(int pShift)
| |||
{
| |||
if(pShift < 0 || pShift >= BarCount)
| |||
return 0.0;
| |||
return bar[pShift].close;
| |||
}
| |||
| |||
//+------------------------------------------------------------------+
| |||
//| |
| |||
//+------------------------------------------------------------------+
| |||
double CBarsbydate::High(int pShift)
| |||
{
| |||
if(pShift < 0 || pShift >= BarCount)
| |||
return 0.0;
| |||
return bar[pShift].high;
| |||
}
| |||
| |||
//+------------------------------------------------------------------+
| |||
//| |
| |||
//+------------------------------------------------------------------+
| |||
double CBarsbydate::Low(int pShift)
| |||
{
| |||
if(pShift < 0 || pShift >= BarCount)
| |||
return 0.0;
| |||
return bar[pShift].low;
| |||
}
| |||
| |||
//+------------------------------------------------------------------+
| |||
//| |
| |||
//+------------------------------------------------------------------+
| |||
double CBarsbydate::Open(int pShift)
| |||
{
| |||
if(pShift < 0 || pShift >= BarCount)
| |||
return 0.0;
| |||
return bar[pShift].open;
| |||
}
| |||
| |||
//+------------------------------------------------------------------+
| |||
//| |
| |||
//+------------------------------------------------------------------+
| |||
datetime CBarsbydate::Time(int pShift)
| |||
{
| |||
if(pShift < 0 || pShift >= BarCount)
| |||
return 0;
| |||
return bar[pShift].time;
| |||
}
| |||
| |||
//+------------------------------------------------------------------+
| |||
//| |
| |||
//+------------------------------------------------------------------+
| |||
long CBarsbydate::TickVolume(int pShift)
| |||
{
| |||
if(pShift < 0 || pShift >= BarCount)
| |||
return 0;
| |||
return bar[pShift].tick_volume;
| |||
}
| |||
| |||
//+------------------------------------------------------------------+
| |||
//| |
| |||
//+------------------------------------------------------------------+
| |||
long CBarsbydate::Volume(int pShift)
| |||
{
| |||
if(pShift < 0 || pShift >= BarCount)
| |||
return 0;
| |||
return bar[pShift].real_volume;
| |||
}
| |||
| |||
//+------------------------------------------------------------------+
| |||
//| |
| |||
//+------------------------------------------------------------------+
| |||
void CBarsbydate::GetCloses(double &closes[])
| |||
{
| |||
ArrayResize(closes, BarCount);
| |||
for(int i = 0; i < BarCount; i++)
| |||
closes[i] = bar[i].close;
| |||
}
| |||
| |||
//+------------------------------------------------------------------+
| |||
//| |
| |||
//+------------------------------------------------------------------+
| |||
void CBarsbydate::GetOpens(double &opens[])
| |||
{
| |||
ArrayResize(opens, BarCount);
| |||
for(int i = 0; i < BarCount; i++)
| |||
opens[i] = bar[i].open;
| |||
}
| |||
| |||
//+------------------------------------------------------------------+
| |||
//| |
| |||
//+------------------------------------------------------------------+
| |||
void CBarsbydate::GetHighs(double &highs[])
| |||
{
| |||
ArrayResize(highs, BarCount);
| |||
for(int i = 0; i < BarCount; i++)
| |||
highs[i] = bar[i].high;
| |||
}
| |||
| |||
//+------------------------------------------------------------------+
| |||
//| |
| |||
//+------------------------------------------------------------------+
| |||
void CBarsbydate::GetLows(double &lows[])
| |||
{
| |||
ArrayResize(lows, BarCount);
| |||
for(int i = 0; i < BarCount; i++)
| |||
lows[i] = bar[i].low;
| |||
}
| |||
| |||
//+------------------------------------------------------------------+
| |||
//| |
| |||
//+------------------------------------------------------------------+
| |||
void CBarsbydate::GetTimes(datetime ×[])
| |||
{
| |||
ArrayResize(times, BarCount);
| |||
for(int i = 0; i < BarCount; i++)
| |||
times[i] = bar[i].time;
| |||
}
| |||
| |||
//+------------------------------------------------------------------+
| |||
//| |
| |||
//+------------------------------------------------------------------+
| |||
void CBarsbydate::GetVolumes(long &volumes[])
| |||
{
| |||
ArrayResize(volumes, BarCount);
| |||
for(int i = 0; i < BarCount; i++)
| |||
volumes[i] = bar[i].tick_volume;
| |||
}
| |||
| |||
//+------------------------------------------------------------------+
| |||
//| Index by exact time match |
| |||
//| Returns index in bar[] (0 oldest) or -1 |
| |||
//+------------------------------------------------------------------+
| |||
int CBarsbydate::IndexByTime(datetime t)
| |||
{
| |||
if(t == 0 || BarCount == 0)
| |||
return -1;
| |||
| |||
for(int i = 0; i < BarCount; i++)
| |||
{
| |||
if(bar[i].time == t)
| |||
return i;
| |||
}
| |||
| |||
return -1;
| |||
}
| |||
| |||
//+------------------------------------------------------------------+
| |||
//| Replace current newest bar if time matches |
| |||
//+------------------------------------------------------------------+
| |||
bool CBarsbydate::UpdateLastBar(const MqlRates &rate)
| |||
{
| |||
if(BarCount <= 0)
| |||
return false;
| |||
| |||
int last = BarCount - 1;
| |||
| |||
if(bar[last].time != rate.time)
| |||
return false;
| |||
| |||
bar[last] = rate;
| |||
return true;
| |||
}
| |||
| |||
//+------------------------------------------------------------------+
| |||
//| Append a newer bar |
| |||
//+------------------------------------------------------------------+
| |||
bool CBarsbydate::AppendBar(const MqlRates &rate)
| |||
{
| |||
if(BarCount > 0)
| |||
{
| |||
int last = BarCount - 1;
| |||
| |||
if(rate.time < bar[last].time)
| |||
return false;
| |||
| |||
if(rate.time == bar[last].time)
| |||
{
| |||
bar[last] = rate;
| |||
return true;
| |||
}
| |||
}
| |||
| |||
int newSize = BarCount + 1;
| |||
int resized = ArrayResize(bar, newSize);
| |||
if(resized != newSize)
| |||
return false;
| |||
| |||
bar[newSize - 1] = rate;
| |||
BarCount = newSize;
| |||
return true;
| |||
}
| |||
//+------------------------------------------------------------------+
| |||
//+------------------------------------------------------------------+
|