Equilibrium/Include/MultiSymbolIndicator.mqh

640 lines
67 KiB
MQL5
Raw Permalink Normal View History

2025-05-30 14:53:03 +02:00
<EFBFBD><EFBFBD>//+------------------------------------------------------------------+
//| 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
//--- 5@5<5==K5/<0AA82K 4;O :>?8@>20=8O 40==KE 87 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; // 07<5@ 2E>4=KE B09<A5@89
int m_prev_calculated; // 1@01>B0=> 10@>2 =0 ?@54K4CI5< 2K7>25
datetime m_time[]; // @5<O >B:@KB8O
double m_open[]; // &5=K >B:@KB8O
double m_high[]; // 0:A8<0;L=K5 F5=K
double m_low[]; // 8=8<0;L=K5 F5=K
double m_close[]; // &5=K 70:@KB8O
long m_tick_volume[]; // "8:>2K5 >1JQ<K
long m_volume[]; // 50;L=K5 >1JQ<K
int m_spread[]; // !?@54
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()
{
//--- @>25@:0 ?CABKE 7=0G5=89
// TODO: uncomment checking for empty value
//if(!CheckEmptyValues())
// m_prev_calculated=0;
//--- A;8 1K;0 703@C65=0 1>;55 3;C1>:0O 8AB>@8O
// TODO: uncomment checking for the need to download the history
//if(!CheckEventLoadHistory())
// m_prev_calculated=0;
//--- 1=>2;O5< 7=0G5=8O 8=48:0B>@0 :064CN A5:C=4C
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);
//--- @>25@:0 7=0G5=89 2 8=48:0B>@=KE 1CD5@0E
//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[])
{
//--- !45;05< :>?8N ?0@0<5B@>2 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.
//--- 1=C;8< 8=48:0B>@=K5 1CD5@K
// Zero indicator buffers
// ZeroIndicatorBuffers(); // SYMBOL SPECIFIC!!!
//--- ATR_MS: // initialisiert ausschlie<EFBFBD>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<EFBFBD>t verm<EFBFBD>ge MqlRates auch
// datetime time, int spread, und long *_volume mit ein!!!
//--- <EFBFBD><EFBFBD><EFBFBD>_<EFBFBD>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!!!
//--- >;CG8< A2>9AB20 ?>4>:=0 - Get the properties of the subwindow
SetSubwindowProperties();
//--- #AB0=>28< :0=2C - Install the canvas
SetCanvas();
//--- 03@C78< 8 AD>@<8@C5< =5>1E>48<>5/8<5NI55AO :>;8G5AB2> 40==KE
// 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();
//--- @>25@O5B :>;8G5AB2> 4>ABC?=KE 40==KE C 2A5E A8<2>;>2
// Checks the amount of data available for all symbols.
// TODO: make CheckAvailableData() a method of CSymbolWatcher
if(!CheckAvailableData())
return(RESET);
//--- A;8 703@C65=0 1>;55 3;C1>:0O 8AB>@8O
// If a deeper hisstory is loaded
// TODO: make CheckAvailableData() a method of CSymbolWatcher
if(!CheckEventLoadHistory())
return(RESET);
//--- @>25@8< A8=E@>=878@>20==>ABL 40==KE ?> A8<2>;C/?5@8>4C =0 40==K9 <><5=B
// Check the synchronization of data on the symbol / period at the moment
// TODO: make CheckAvailableData() a method of CSymbolWatcher
if(!CheckSymbolIsSynchronized())
return(RESET);
//--- ?@545;8< 4;O :064>3> A8<2>;0, A :0:>3> 10@0 =0G8=0BL >B@8A>2:C
// For each symbol find the bar at which to start drawing
// TODO: make CheckAvailableData() a method of CSymbolWatcher
if(!DetermineBeginForCalculate())
return(RESET);
//--- A;8 4>H;8 4> MB>3> <><5=B0, B>
// 7=0G8B OnCalculate() 25@=QB =5=C;52>5 7=0G5=85 8 MB> =C6=> 70?><=8BL
//--- 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);
// --- 064K5 2000 10@>2 ?@>25@O5< @07<5@K >:=0
// 8 5A;8 @07<5@ 87<5=8;AO ?>43>=8< ?>4 =53> @07<5@ :0=2K
// 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;
//---
}
//+------------------------------------------------------------------+
//| >?8@C5B 40==K5 87 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);
}
//+------------------------------------------------------------------+