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;
| |
}
| |
//+------------------------------------------------------------------+
| |
//+------------------------------------------------------------------+
|