639 lines
67 KiB
MQL5
639 lines
67 KiB
MQL5
//+------------------------------------------------------------------+
|
|
//| MultiSymbolIndicator.mqh |
|
|
//| Copyright 2019, Thomas Schwabhaeuser |
|
|
//| schwabhaeuser@icloud.com |
|
|
//+------------------------------------------------------------------+
|
|
#property copyright "Copyright 2019, Thomas Schwabhaeuser"
|
|
#property link "schwabhaeuser@icloud.com"
|
|
#property version "1.00"
|
|
//--- Trade direction type
|
|
enum ENUM_DIRECTION
|
|
{
|
|
BUY =0,
|
|
SELL =1
|
|
};
|
|
//---
|
|
#include <Arrays\ArrayObj.mqh>
|
|
#include <Indicators\Series.mqh>
|
|
#include <Trade\SymbolInfo.mqh>
|
|
#include "SymbolWatcher.mqh"
|
|
//+------------------------------------------------------------------+
|
|
//| CSeries objects are arrays of buffers associated with a |
|
|
//| pair of a SYMBOL and a TIMEFRAME. They have a protected |
|
|
//| bool CheckLoadHistory (const int size); |
|
|
//| bool CheckTerminalHistory (const int size) |
|
|
//| bool CheckServerHistory (const int size) |
|
|
//| to force building timeseries and data loading. |
|
|
//| CiRealVolume, CiSpread, CiTickVolume, CiTime, and CPriceSeries |
|
|
//| objects are in particular CSeries objects by means of |
|
|
//| inheritance. They are all arrays with 1 buffer object, |
|
|
//| respectively of type: |
|
|
//| class CRealVolumeBuffer : public CArrayLong |
|
|
//| class CSpreadBuffer : public CArrayInt |
|
|
//| class CTickVolumeBuffer : public CArrayLong |
|
|
//| class CTimeBuffer : public CArrayLong |
|
|
//+------------------------------------------------------------------+
|
|
//| CIndicator objects are arrays of one or more buffer objects of |
|
|
//| class CIndicatorBuffer : public CDoubleBuffer |
|
|
//| Purpose: Class for access to data of buffers of technical |
|
|
//| indicators. |
|
|
//| Encapsulates: m_offset (in bars), m_name (name of buffer) |
|
|
//| class CIndicator : public CSeries |
|
|
//| Purpose: Base class of technical indicators. |
|
|
//| Encapsulates: m_handle, m_status, m_full_release, m_redrawer |
|
|
//| m_status is "" unless given a meaning by subclasses. |
|
|
//+------------------------------------------------------------------+
|
|
//| The buffer objects used by CPriceSeries objects |
|
|
//| class CiClose : public CPriceSeries : public CSeries |
|
|
//| class CiHigh : public CPriceSeries : public CSeries |
|
|
//| class CiLow : public CPriceSeries : public CSeries |
|
|
//| class CiOpen : public CPriceSeries : public CSeries |
|
|
//| Purpose: Class of close/high/low/open series. |
|
|
//| Derives from class CPriceSeries. |
|
|
//| are |
|
|
//| class CCloseBuffer : public CDoubleBuffer |
|
|
//| class CHighBuffer : public CDoubleBuffer |
|
|
//| class CLowBuffer : public CDoubleBuffer |
|
|
//| class COpenBuffer : public CDoubleBuffer |
|
|
//| Purpose: Class of close/high/low/open price series buffer. |
|
|
//| Derives from class CDoubleBuffer. |
|
|
//+------------------------------------------------------------------+
|
|
//| All of the above are desinged for usage in expert advisors. |
|
|
//| The class CiMSI derived from CiCustom will be needed |
|
|
//| for this purpose, too. |
|
|
//| CiMSI::AddWatcher(symbol,direction) |
|
|
//| CiMSI::FillerFactory(composition) -> filler(CIndicators) |
|
|
//| CiMSI::AddBuffer(&buffer[],type,&filler) |
|
|
//| BUT WE NEED CLASSES DESINGED FOR PROVIDING INDICATOR |
|
|
//| CALCULATIONS AND FILLING OF BUFFERS. |
|
|
//+------------------------------------------------------------------+
|
|
//| This amount to a template for OnCalculate(): |
|
|
//| to_copy=limit+1; |
|
|
//| if(CopyBuffer(ATR_Handle,0,0,to_copy,ATR)<=0) return(0); |
|
|
//| ... |
|
|
//| int limit=0; |
|
|
//| if(prev_calculated==0) |
|
|
//| { |
|
|
//| } |
|
|
//| else |
|
|
//| limit=prev_calculated-1; |
|
|
//| for(int i=limit; i<rates_total; i++) |
|
|
//| { |
|
|
//| PreparationData(i,time); |
|
|
//| FillIndicatorBuffers(i,time); |
|
|
//| } |
|
|
//+------------------------------------------------------------------+
|
|
//| The base of this development will be the new |
|
|
//| class CIndicatorBase : public CExpertBase |
|
|
//| encapsulating |
|
|
//| CIndicators m_indicators; // array of CSeries objects |
|
|
//| |
|
|
//| CIndicatorBase::AddPriceSeries(symbol,direction) |
|
|
//| |
|
|
//| CMultiSymbolIndicator::FillerFactory(composition) |
|
|
//| -> filler(CIndicatore) |
|
|
//| CMultiSymbolIndicator::AddBuffer(&buffer[],type,&filler) |
|
|
//| |
|
|
//| |
|
|
//| virtual DecrementLoopIteration(); |
|
|
//| |
|
|
//| |
|
|
//| |
|
|
//| OnCalculate() |
|
|
//| // update all REGISTERED series and indicators we want to use |
|
|
//| m_indicators.Refresh(); |
|
|
//| int limit=0; |
|
|
//| if(prev_calculated==0) |
|
|
//| { |
|
|
//| } |
|
|
//| else |
|
|
//| limit=prev_calculated-1; |
|
|
//| for(int i=limit; i<rates_total; i++) |
|
|
//| { |
|
|
//| DecrementLoopIteration(i,time); |
|
|
//| FillIndicatorBuffer(i,time); |
|
|
//| } |
|
|
//| |
|
|
//| |
|
|
//| |
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
//--- FIXME: 'BufferType' - declaration without type MultiSymbolIndicator.mqh 20 9
|
|
//typedef BufferType *(double &buffer[]);
|
|
//+------------------------------------------------------------------+
|
|
//| Class CMultiSymbolIndicator. |
|
|
//| Purpose: Base class of custom indicators evaluating 2+ symbols. |
|
|
//| Derives from class CArrayObj. |
|
|
//| |
|
|
//| Note: Rather than accessing indicator data in EXPERT ADVISORS |
|
|
//| we want to provide a class providing methods that perform |
|
|
//| indicator calculations so it must not be derived from |
|
|
//| CIndicator which copies indicator buffers to local arrays. |
|
|
//| THE CLASS IS FOR USAGE IN MQL5 INDICATORS AND THUS NEEDS |
|
|
//| TO PROVIDE METHODS FOR FILLING BUFFERS ARE TO BE PASSED |
|
|
//| FROM THE MAIN FILE BY REFERENCE. |
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//| class CIndicator : public CSeries |
|
|
//| is an array of buffers intended to be accessed by experts. |
|
|
//| |
|
|
//| class CMultiSymbolIndicator : public CArrayObj |
|
|
//| below is an array of CSymbolWatcher objects |
|
|
//| without an obvious reason! |
|
|
//| BASICALLY IT IS A LIST OF CSymbolWatcher OBJECTS ENDOWED WITH |
|
|
//| METHODS FOR FILLING EXTERNAL BUFFERS! |
|
|
//| MORE PRECISELY IT SHOULD BE DECLARED AS |
|
|
//| class CMultiSymbolIndicator : public CIndicators |
|
|
//| because we have class CIndicators : public CArrayObj |
|
|
//| |
|
|
//| A general class CiMSI : public CIndicators may not make sense. |
|
|
//| CiMSI::AddWatcher(symbol,direction) |
|
|
//| CiMSI::FillerFactory(composition) -> filler(CIndicatore) |
|
|
//| CiMSI::AddBuffer(&buffer[],type,&filler) |
|
|
//| are not to be called by experts but rather by subclasses |
|
|
//| of CMultiSymbolIndicator! Access to indicators implemented by |
|
|
//| such subclasses will be given by |
|
|
//| class CiMSI : public CIndicator |
|
|
//| as usual. |
|
|
//| |
|
|
//| class CMultiSymbolIndicator : public CIndicators |
|
|
//| still needs to have this functionality so it needs to implement |
|
|
//| protected: |
|
|
//| CMultiSymbolIndicator::AddWatcher(symbol,direction) |
|
|
//| -> m_indicators.Add() |
|
|
//| CMultiSymbolIndicator::FillerFactory(double &buffer[]) |
|
|
//| -> for subclasses |
|
|
//| CMultiSymbolIndicator::AddBuffer(&buffer[],type,&filler) |
|
|
//| CProduct may have a member m_filler_array and |
|
|
//| CProduct::OnCalculate() may finish with a loop |
|
|
//| |
|
|
//| for(int i=0;i<m_filler_array.Total();i++) |
|
|
//| { |
|
|
//| CMSIFiller *filler=m_filler_array.At(i); |
|
|
//| ("CIndicatorBuffer") *buffer=m_buffer_array.At(i); |
|
|
//| int value=filler.OnCalculate(rates_total,prev_calculated |
|
|
//| m_indicators,buffer.ref()); |
|
|
//| } |
|
|
//| |
|
|
//| Check what indicators really need to do for providing values! |
|
|
//| HOW CAN WE CREATE CObject OBJECTS, THAT CAN RETURN REFERENCES |
|
|
//| TO DOUBLE-ARRAYS??? |
|
|
//| |
|
|
//| TRY THIS WITH A SIMPLE SINGLE SYMBOL BUT MULTI BUFFER INDICATOR! |
|
|
//| | |
|
|
//+------------------------------------------------------------------+
|
|
class CMultiSymbolIndicator : public CSeries // public CArrayObj
|
|
{
|
|
private:
|
|
CArrayObj m_watcher_array; // CArrayObj object
|
|
CArrayObj m_buffer_array; // CArrayObj object
|
|
|
|
//--- Переменные/массивы для копирования данных из OnCalculate()
|
|
// Aren't these variables needed per Symbol? I.e. in CSymbolWatcher?
|
|
// No! They are for storing the values for the symbol chart
|
|
// the indicator was applied to. This is needed for being able to call
|
|
// OnCalculate() in case of other events.
|
|
int m_rates_total; // Размер входных таймсерий
|
|
int m_prev_calculated; // Обработано баров на предыдущем вызове
|
|
datetime m_time[]; // Время открытия
|
|
double m_open[]; // Цены открытия
|
|
double m_high[]; // Максимальные цены
|
|
double m_low[]; // Минимальные цены
|
|
double m_close[]; // Цены закрытия
|
|
long m_tick_volume[]; // Тиковые объёмы
|
|
long m_volume[]; // Реальные объёмы
|
|
int m_spread[]; // Спред
|
|
|
|
void CopyOnCalculate(const int rates_total,
|
|
const int prev_calculated,
|
|
const datetime &time[],
|
|
const double &open[],
|
|
const double &high[],
|
|
const double &low[],
|
|
const double &close[],
|
|
const long &tick_volume[],
|
|
const long &volume[],
|
|
const int &spread[]);
|
|
//--- TODO: remove FillBuffers()
|
|
void FillBuffers(int i,datetime const &time[]);
|
|
|
|
//--- TODO: implement
|
|
bool AddBuffer(double &buffer[],ENUM_INDEXBUFFER_TYPE buffer_mode);
|
|
|
|
public:
|
|
CMultiSymbolIndicator();
|
|
~CMultiSymbolIndicator();
|
|
|
|
int OnInit();
|
|
void OnDeinit(const int reason);
|
|
int OnCalculate(const int rates_total,
|
|
const int prev_calculated,
|
|
const datetime &time[],
|
|
const double &open[],
|
|
const double &high[],
|
|
const double &low[],
|
|
const double &close[],
|
|
const long &tick_volume[],
|
|
const long &volume[],
|
|
const int &spread[]);
|
|
void OnTimer();
|
|
bool AddWatcher(string symbol,ENUM_DIRECTION direction);
|
|
//--- TODO: implement by invoking
|
|
// AddBuffer(double &buffer[],ENUM_INDEXBUFFER_TYPE buffer_mode)
|
|
bool AddEnterBuffer(double &buffer[]) { return(AddBuffer(buffer,INDICATOR_DATA)); }
|
|
bool AddLeaveBuffer(double &buffer[]) { return(AddBuffer(buffer,INDICATOR_DATA)); }
|
|
bool AddBidBuffer(double &buffer[]) { return(AddBuffer(buffer,INDICATOR_DATA)); }
|
|
bool AddAskBuffer(double &buffer[]) { return(AddBuffer(buffer,INDICATOR_DATA)); }
|
|
bool AddMarginBuffer(double &buffer[]) { return(AddBuffer(buffer,INDICATOR_DATA)); }
|
|
//---
|
|
void FillEnterBuffer(const int rates_total,
|
|
const int prev_calculated,
|
|
double &buffer[]);
|
|
void FillLeaveBuffer(const int rates_total,
|
|
const int prev_calculated,
|
|
double &buffer[]);
|
|
void FillBidBuffer(const int rates_total,
|
|
const int prev_calculated,
|
|
double &buffer[]);
|
|
void FillAskBuffer(const int rates_total,
|
|
const int prev_calculated,
|
|
double &buffer[]);
|
|
void FillMarginBuffer(const int rates_total,
|
|
const int prev_calculated,
|
|
double &margin_buffer[]);
|
|
};
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
CMultiSymbolIndicator::CMultiSymbolIndicator() : m_rates_total(0),m_prev_calculated(0)
|
|
{
|
|
Print(__FUNCTION__);
|
|
ArrayInitialize(m_time,EMPTY_VALUE);
|
|
ArrayInitialize(m_open,EMPTY_VALUE);
|
|
ArrayInitialize(m_high,EMPTY_VALUE);
|
|
ArrayInitialize(m_low,EMPTY_VALUE);
|
|
ArrayInitialize(m_close,EMPTY_VALUE);
|
|
ArrayInitialize(m_tick_volume,EMPTY_VALUE);
|
|
ArrayInitialize(m_volume,EMPTY_VALUE);
|
|
ArrayInitialize(m_spread,EMPTY_VALUE);
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
CMultiSymbolIndicator::~CMultiSymbolIndicator()
|
|
{
|
|
Print(__FUNCTION__);
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Custom indicator initialization function |
|
|
//+------------------------------------------------------------------+
|
|
int CMultiSymbolIndicator::OnInit()
|
|
{
|
|
Print(__FUNCTION__+": m_watcher_array.Total()="+m_watcher_array.Total());
|
|
//---
|
|
return(INIT_SUCCEEDED);
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Custom indicator deinitialization function |
|
|
//+------------------------------------------------------------------+
|
|
void CMultiSymbolIndicator::OnDeinit(const int reason)
|
|
{
|
|
Print(__FUNCTION__+": deleting m_watcher_array.Total()="+m_watcher_array.Total()+" watchers");
|
|
for(int i=0;i<m_watcher_array.Total();i++)
|
|
{
|
|
CSymbolWatcher *watcher=m_watcher_array.At(i);
|
|
delete watcher;
|
|
}
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
bool CMultiSymbolIndicator::AddWatcher(string symbol,ENUM_DIRECTION direction)
|
|
{
|
|
CSymbolWatcher *watcher=new CSymbolWatcher;
|
|
if(watcher==NULL)
|
|
{
|
|
Print(__FUNCTION__+"Object CSymbolWatcher create error");
|
|
return(false);
|
|
}
|
|
if(watcher.OnInit(symbol,direction)!=INIT_SUCCEEDED)
|
|
{
|
|
Print(__FUNCTION__+"Object CSymbolWatcher initialization error");
|
|
return(false);
|
|
}
|
|
m_watcher_array.Add(watcher);
|
|
Print(__FUNCTION__+": Added watcher for symbol "+watcher.GetSymbol()+" to "+
|
|
EnumToString(watcher.GetDirection()));
|
|
return(true);
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| AddBuffer |
|
|
//| PURPOSE: Declare another buffer for writing varlues to. |
|
|
//| TODO: We do not only need its mode/type but also a rule for |
|
|
//| determining which values are to be returned. |
|
|
//| Such rules have to read the array of symbols and write to |
|
|
//| the array of buffers declared here. |
|
|
//+------------------------------------------------------------------+
|
|
bool CMultiSymbolIndicator::AddBuffer(double &buffer[],ENUM_INDEXBUFFER_TYPE buffer_mode,CMSIFiller *filler)
|
|
{
|
|
//--- FIXME: Unknown type BufferType!!!
|
|
SetIndexBuffer(m_buffer_array.Total()-1,buffer,buffer_mode);
|
|
CDoubleBuffer *buffer_pointer=GetPointer(buffer);
|
|
m_buffer_array.Add(buffer_pointer);
|
|
m_filler_array.Add(filler);
|
|
//---
|
|
return(true);
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Timer function |
|
|
//+------------------------------------------------------------------+
|
|
void CMultiSymbolIndicator::OnTimer()
|
|
{
|
|
//--- Проверка пустых значений
|
|
// TODO: uncomment checking for empty value
|
|
//if(!CheckEmptyValues())
|
|
// m_prev_calculated=0;
|
|
//--- Если была загружена более глубокая история
|
|
// TODO: uncomment checking for the need to download the history
|
|
//if(!CheckEventLoadHistory())
|
|
// m_prev_calculated=0;
|
|
//--- Обновляем значения индикатора каждую секунду
|
|
this.OnCalculate(m_rates_total,m_prev_calculated,
|
|
m_time,m_open,m_high,m_low,m_close,
|
|
m_tick_volume,m_volume,m_spread);
|
|
|
|
//--- Проверка значений в индикаторных буферах
|
|
//CheckLastEmptyValues(10);
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Custom indicator iteration function |
|
|
//+------------------------------------------------------------------+
|
|
int CMultiSymbolIndicator::OnCalculate(const int rates_total,
|
|
const int prev_calculated,
|
|
const datetime &time[],
|
|
const double &open[],
|
|
const double &high[],
|
|
const double &low[],
|
|
const double &close[],
|
|
const long &tick_volume[],
|
|
const long &volume[],
|
|
const int &spread[])
|
|
{
|
|
//--- Сделаем копию параметров OnCalculate()
|
|
// store in member variables
|
|
CopyOnCalculate(rates_total,prev_calculated,
|
|
time,open,high,low,close,
|
|
tick_volume,volume,spread);
|
|
//--- DOING:
|
|
//--- detect start position
|
|
int start=0;
|
|
if(prev_calculated>0) start=prev_calculated-1;
|
|
else
|
|
{
|
|
start=0;
|
|
//--- TODO: Check if all of the following can already be done in OnInit()???
|
|
// Regardless of the fact that it is to be extacted to CSymbolWatcher.
|
|
// In the end it turns out that all this preparation cannot be moved to OnInit()
|
|
// because it is needed for each recalculation triggered by new tick or timer events.
|
|
|
|
//--- Обнулим индикаторные буферы
|
|
// Zero indicator buffers
|
|
// ZeroIndicatorBuffers(); // SYMBOL SPECIFIC!!!
|
|
//--- ATR_MS: // initialisiert ausschließlich den Datenpuffer, weitere hat buffer_atr nicht!
|
|
// for(int s=0; s<SYMBOLS; s++)
|
|
// ArrayInitialize(buffer_atr[s(ymbol)].data,EMPTY_VALUE);
|
|
for(int i=0;i<m_watcher_array.Total();i++)
|
|
{
|
|
CSymbolWatcher *watcher=m_watcher_array.At(i);
|
|
//--- schließt vermöge MqlRates auch
|
|
// datetime time, int spread, und long *_volume mit ein!!!
|
|
//--- ΑΤΡ_ΜS.mq5
|
|
// ArrayInitialize(temp_symbol_time[s].time,NULL);
|
|
// ArrayInitialize(temp_atr_values[s].value,EMPTY_VALUE);
|
|
watcher.PrepareOnCalculate();
|
|
//--- TODO: NOT invoke ArrayInitialize() from CSymbolWatcher::OnCalculate()
|
|
// Here we rather need to invoke
|
|
// CSymbolWatcher::PrepareOnCalculate()
|
|
// {
|
|
// this.ArrayInitialize();
|
|
// this.LoadFormationData();
|
|
// this.CheckAvailableData();
|
|
// this.CheckEventLoadHistory();
|
|
// this.CheckSymbolIsSynchronized();
|
|
// this.DetermineBeginForCalculate();
|
|
// }
|
|
}
|
|
// CANVAS AND SUBWINDOW PROPERTIES ARE NOT SYMBOL SPECIFIC!!!
|
|
//--- Получим свойства подокна - Get the properties of the subwindow
|
|
SetSubwindowProperties();
|
|
//--- Установим канву - Install the canvas
|
|
SetCanvas();
|
|
//--- Загрузим и сформируем необходимое/имеющееся количество данных
|
|
// Load and generate the necessary / available amount of data.
|
|
// TODO: make LoadFormationData() a method of CSymbolWatcher
|
|
LoadFormationData();
|
|
//--- TODO: Do we really need this NON SYMBOL SPECIFIC function
|
|
// from MultiSymbolPriceDivergence???
|
|
LoadFormationDataHighTF();
|
|
//--- Проверяет количество доступных данных у всех символов
|
|
// Checks the amount of data available for all symbols.
|
|
// TODO: make CheckAvailableData() a method of CSymbolWatcher
|
|
if(!CheckAvailableData())
|
|
return(RESET);
|
|
//--- Если загружена более глубокая история
|
|
// If a deeper hisstory is loaded
|
|
// TODO: make CheckAvailableData() a method of CSymbolWatcher
|
|
if(!CheckEventLoadHistory())
|
|
return(RESET);
|
|
//--- Проверим синхронизированность данных по символу/периоду на данный момент
|
|
// Check the synchronization of data on the symbol / period at the moment
|
|
// TODO: make CheckAvailableData() a method of CSymbolWatcher
|
|
if(!CheckSymbolIsSynchronized())
|
|
return(RESET);
|
|
//--- Определим для каждого символа, с какого бара начинать отрисовку
|
|
// For each symbol find the bar at which to start drawing
|
|
// TODO: make CheckAvailableData() a method of CSymbolWatcher
|
|
if(!DetermineBeginForCalculate())
|
|
return(RESET);
|
|
//--- Если дошли до этого момента, то
|
|
// значит OnCalculate() вернёт ненулевое значение и это нужно запомнить
|
|
//--- If you have reached this point, then OnCalculate() returns a nonzero value and
|
|
// it needs to be remembered to allow for calling OnCalculate() from OnTimer().
|
|
m_prev_calculated=rates_total;
|
|
}
|
|
|
|
Print(__FUNCTION__+
|
|
"("+rates_total+","+prev_calculated+",...): start ="+start+", "+
|
|
"updating "+m_watcher_array.Total()+" watchers...");
|
|
|
|
// Tell each watcher to make the data we need available
|
|
//--- DONE: Extract symbol specific code and data to CSymbolWatcher
|
|
int result=rates_total;
|
|
for(int i=0;i<m_watcher_array.Total();i++)
|
|
{
|
|
if(CheckPointer(m_watcher_array.At(i))!=POINTER_DYNAMIC)
|
|
continue;
|
|
CSymbolWatcher *watcher=m_watcher_array.At(i);
|
|
// Make sure that the data from i=limit while i<rates_total is available
|
|
int value=watcher.OnCalculate(rates_total,prev_calculated,time,open,high,low,close,
|
|
tick_volume,volume,spread);
|
|
if(value<result)
|
|
result=value;
|
|
}
|
|
|
|
string s="watchers prepared with data from i=start="+start+" while i<"+result;
|
|
if(result<rates_total) s+="<"+rates_total+". INCOMPLETE!"; else s+="...";
|
|
Print(__FUNCTION__+": "+s);
|
|
|
|
// for(int i=limit; i<rates_total; i++)
|
|
// {
|
|
// FillBuffers(i,time);
|
|
// --- Каждые 2000 баров проверяем размеры окна
|
|
// и если размер изменился подгоним под него размер канвы
|
|
// if(!(i%2000))
|
|
// EventChartChange();
|
|
// }
|
|
|
|
//--- return value of prev_calculated for next call
|
|
return(result);
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
void CMultiSymbolIndicator::FillBuffers(int i,datetime const &time[])
|
|
{
|
|
//--- TODO: Define which buffers are to be provided Buffer1[], Buffer2[], ... BufferN[],
|
|
// e.g. for Enter, Leave, Margin, Bid, Ask
|
|
//--- TODO: Calculate these values for period starting at time time[i]
|
|
//--- TODO: Store the values in indicator buffers Buffer1[i], Buffer2[i], ... BufferN[i].
|
|
}
|
|
//--- DOING: Implement
|
|
void CMultiSymbolIndicator::FillEnterBuffer(const int rates_total,
|
|
const int prev_calculated,
|
|
double &buffer[])
|
|
{
|
|
//--- detect start position
|
|
int start=0;
|
|
if(prev_calculated>0) start=prev_calculated-1;
|
|
//---
|
|
for(int i=start; i<rates_total; i++)
|
|
{
|
|
// FIXME Array out of range in 'MultiSymbolIndicator.mqh' (279,13)
|
|
// TODO: Buffers need to be initialised before they can be used by indicators
|
|
buffer[i]=1.0;
|
|
for(int index=0;index<m_watcher_array.Total();index++)
|
|
{
|
|
if(CheckPointer(m_watcher_array.At(index))!=POINTER_DYNAMIC)
|
|
continue;
|
|
CSymbolWatcher *watcher=m_watcher_array.At(index);
|
|
buffer[i]*=watcher.Enter(i);
|
|
}
|
|
}
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
void CMultiSymbolIndicator::FillLeaveBuffer(const int rates_total,
|
|
const int prev_calculated,
|
|
double &buffer[])
|
|
{
|
|
//--- detect start position
|
|
int start=0;
|
|
if(prev_calculated>0) start=prev_calculated-1;
|
|
//---
|
|
for(int i=start; i<rates_total; i++)
|
|
{
|
|
buffer[i]=1.0;
|
|
for(int index=0;index<m_watcher_array.Total();index++)
|
|
{
|
|
if(CheckPointer(m_watcher_array.At(index))!=POINTER_DYNAMIC)
|
|
continue;
|
|
CSymbolWatcher *watcher=m_watcher_array.At(index);
|
|
buffer[i]*=watcher.Leave(i);
|
|
}
|
|
}
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
void CMultiSymbolIndicator::FillBidBuffer(const int rates_total,
|
|
const int prev_calculated,
|
|
double &buffer[])
|
|
{
|
|
//--- detect start position
|
|
int start=0;
|
|
if(prev_calculated>0) start=prev_calculated-1;
|
|
//---
|
|
for(int i=start; i<rates_total; i++)
|
|
{
|
|
buffer[i]=1.0;
|
|
for(int index=0;index<m_watcher_array.Total();index++)
|
|
{
|
|
if(CheckPointer(m_watcher_array.At(index))!=POINTER_DYNAMIC)
|
|
continue;
|
|
CSymbolWatcher *watcher=m_watcher_array.At(index);
|
|
buffer[i]*=watcher.CloseBid(i);
|
|
}
|
|
}
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
void CMultiSymbolIndicator::FillAskBuffer(const int rates_total,
|
|
const int prev_calculated,
|
|
double &buffer[])
|
|
{
|
|
//--- detect start position
|
|
int start=0;
|
|
if(prev_calculated>0) start=prev_calculated-1;
|
|
//---
|
|
for(int i=start; i<rates_total; i++)
|
|
{
|
|
buffer[i]=1.0;
|
|
for(int index=0;index<m_watcher_array.Total();index++)
|
|
{
|
|
if(CheckPointer(m_watcher_array.At(index))!=POINTER_DYNAMIC)
|
|
continue;
|
|
CSymbolWatcher *watcher=m_watcher_array.At(index);
|
|
buffer[i]*=watcher.CloseAsk(i);
|
|
}
|
|
}
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
void CMultiSymbolIndicator::FillMarginBuffer(const int rates_total,
|
|
const int prev_calculated,
|
|
double &margin_buffer[])
|
|
{
|
|
//--- detect start position
|
|
int start=0;
|
|
if(prev_calculated>0) start=prev_calculated-1;
|
|
//---
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Копирует данные из OnCalculate |
|
|
//+------------------------------------------------------------------+
|
|
void CMultiSymbolIndicator::CopyOnCalculate(const int rates_total,
|
|
const int prev_calculated,
|
|
const datetime &time[],
|
|
const double &open[],
|
|
const double &high[],
|
|
const double &low[],
|
|
const double &close[],
|
|
const long &tick_volume[],
|
|
const long &volume[],
|
|
const int &spread[])
|
|
{
|
|
m_rates_total=rates_total;
|
|
m_prev_calculated=prev_calculated;
|
|
ArrayCopy(m_time,time);
|
|
ArrayCopy(m_open,open);
|
|
ArrayCopy(m_high,high);
|
|
ArrayCopy(m_low,low);
|
|
ArrayCopy(m_close,close);
|
|
ArrayCopy(m_tick_volume,tick_volume);
|
|
ArrayCopy(m_volume,volume);
|
|
ArrayCopy(m_spread,spread);
|
|
}
|
|
//+------------------------------------------------------------------+
|