Пока мой пост не замечают решил ответить на свой второй вопрос - взять пример "не кривого" кода (по образному выражению Мегаквотов ;) и добавить одну странную на мой взгляд проверку...
//+------------------------------------------------------------------+ //| Momentum.mq5 | //| Copyright 2009, MetaQuotes Software Corp. | //| http://www.mql5.com | //+------------------------------------------------------------------+ #property copyright "2009, MetaQuotes Software Corp." #property link "http://www.mql5.com" //---- indicator settings #property indicator_separate_window #property indicator_buffers 1 #property indicator_plots 1 #property indicator_type1 DRAW_LINE #property indicator_color1 DodgerBlue //---- input parameters input int InpMomentumPeriod=14; // Period //---- indicator buffers double ExtMomentumBuffer[]; //--- global variable int ExtMomentumPeriod; //+------------------------------------------------------------------+ //| Custom indicator initialization function | //+------------------------------------------------------------------+ void OnInit() { //--- check for input value if(InpMomentumPeriod<0) { ExtMomentumPeriod=14; Print("Input parameter InpMomentumPeriod has wrong value. Indicator will use value ",ExtMomentumPeriod); } else ExtMomentumPeriod=InpMomentumPeriod; //---- buffers SetIndexBuffer(0,ExtMomentumBuffer,INDICATOR_DATA); //---- name for DataWindow and indicator subwindow label IndicatorSetString(INDICATOR_SHORTNAME,"Momentum"+"("+string(ExtMomentumPeriod)+")"); //--- sets first bar from what index will be drawn PlotIndexSetInteger(0,PLOT_DRAW_BEGIN,ExtMomentumPeriod-1); //--- sets drawing line empty value PlotIndexSetDouble(0,PLOT_EMPTY_VALUE,0.0); //--- digits IndicatorSetInteger(INDICATOR_DIGITS,2); } //+------------------------------------------------------------------+ //| Momentum | //+------------------------------------------------------------------+ int OnCalculate(const int rates_total, const int prev_calculated, const int begin, const double &price[]) { //--- start calculation int StartCalcPosition=(ExtMomentumPeriod-1)+begin; //---- insufficient data if(rates_total<StartCalcPosition) return(0); //--- correct draw begin if(begin>0) PlotIndexSetInteger(0,PLOT_DRAW_BEGIN,StartCalcPosition+(ExtMomentumPeriod-1)); //--- start working, detect position int pos=prev_calculated-1; if(pos<StartCalcPosition) pos=begin+ExtMomentumPeriod; if(!ArrayGetAsSeries(price)) // ------ Проверка очевидного !!!!!! ArraySetAsSeries(price,true);// но не для всех... //--- main cycle for(int i=pos;i<rates_total;i++) { ExtMomentumBuffer[i]=price[i]*100/price[i-ExtMomentumPeriod]; } Print (price[0]); //--- OnCalculate done. Return new prev_calculated. return(rates_total); } //+------------------------------------------------------------------+
Естественно получилась небольшая разница в результатах..
А в справке написано
В качестве массива price[] может быть передана одна из ценовых таймсерий либо рассчитанный буфер какого-либо индикатора. Чтобы определить направление индексации в массиве price[], необходимо вызывать функцию ArrayGetAsSeries(). Чтобы не зависеть от умолчаний, необходимо безусловно вызывать функцию ArraySetAsSeries() для тех массивов, с которыми предполагается работать.
Пока мой пост не замечают решил ответить на свой второй вопрос - взять пример "не кривого" кода (по образному выражению Мегаквотов ;) и добавить одну странную на мой взгляд проверку...
Естественно получилась небольшая разница в результатах..
А в справке написано
Чудно..
долго изучал справку, примеры, свелось все к тому, что при доступе к буферам индикаторов, к параметрам oncalculate - нет простого ответа, откуда ж считать - от 0 или нет, где же этот последний элемент? постоянно нужно чето проверять и помнить.
сейчас тело oncalculate выглядит так:
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[]){ ArraySetAsSeries(TDBuffer, true ); ArraySetAsSeries(TDDemand, true ); ArraySetAsSeries(TDSupport, true ); ArraySetAsSeries(high, true ); ArraySetAsSeries(TDBreakOutQualifier1, true ); ArraySetAsSeries(TDBreakOutQualifier2, true ); ArraySetAsSeries(TDBreakOutQualifier3, true ); ArraySetAsSeries(BuyStopBuffer, true ); ArraySetAsSeries(SellStopBuffer, true );
на каждый индикаторный буфер пишу ArraySetAsSeries(, true ), чтоб наверняка, а time[], open[], high[], low[], close[] вообще не использую, т.к. они доступны только в OnCalculate, и для того чтобы их использовать, предположим внутри объектов или фнукций, вызываемых далее (а если алогоритмы сложные, то уровень вложенности вызываемых функции может быть не один и не два), то нужно передавать их в качестве параметров на каждый уровень вложенности, либо копировать специальным образом содержимое этих массивов в глобальные, чтоли переменные, поэтому пришлось написать свои функции Open(), High(), Low(), Close(), Time(). Может быть я мыслю слишком шаблонно и топорно? может разработчики подскажут, как организовать доступ к таймсериям при использовании сложных алогритмов с использованием ооп и большой вложенности вызовов функций?
я лично ждал платформу с ооп, в которой можно было реализовывавать действительно сложные вещи кодируя торговые идей, ооп получилось хорошее, устраивает, а вот кодирование идей- утомляет, погрязаешь в бесконечных проверках, нехватке решений непосредственно поддерживаемых платформой - к примеру я о том же Open[] - почему я должен программировать эту функцию, почему в специализированной торговой платформе ее нет? раз нет этого функционала, может разработчики сами его реализуют уже средствами языка? а то пытаешься сам запрограммирвоать, не получается - и ооказывается, если по простому: я это еще не разу не делал, и опять не получилось.
долго изучал справку, примеры, свелось все к тому, что при доступе к буферам индикаторов, к параметрам oncalculate - нет простого ответа, откуда ж считать - от 0 или нет, где же этот последний элемент? постоянно нужно чето проверять и помнить.
Зато не криво получится может...
;)
А пример Моментума и цитату из справки привел для иллюстрации, что проверки не обязательны...
Правда не всем.
И еще одна хохма -. последняя цена на графике 83.689/05!!
что в price[0] - если в параметрах выбрана цена Close?
Не всегда получается отвечать вовремя. Но ведь можно проверить самостоятельно и убедиться, что самая последняя цена передается в функцию OnCalculate() под индексом rates_total-1. То есть, переданный в функцию массив price[] имеет индексацию из прошлого в будущее.
Вот простой пример индикатора для проверки.
//+------------------------------------------------------------------+ //| CheckDirection.mq5 | //| Copyright 2009, MetaQuotes Software Corp. | //| http://www.mql5.com | //+------------------------------------------------------------------+ #property copyright "2009, MetaQuotes Software Corp." #property link "http://www.mql5.com" #property version "1.00" #property indicator_chart_window #property indicator_buffers 1 #property indicator_plots 1 //---- plot close #property indicator_label1 "close" #property indicator_type1 DRAW_LINE #property indicator_color1 Red #property indicator_style1 STYLE_SOLID #property indicator_width1 1 //--- indicator buffers double closeBuffer[]; bool firstCalc=true; //+------------------------------------------------------------------+ //| Custom indicator initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- indicator buffers mapping SetIndexBuffer(0,closeBuffer,INDICATOR_DATA); //--- return(0); } //+------------------------------------------------------------------+ //| Custom indicator iteration function | //+------------------------------------------------------------------+ int OnCalculate (const int rates_total, // размер массива price[] const int prev_calculated, // обработано баров на предыдущем вызове const int begin, // откуда начинаются значимые данные const double& price[] // массив для расчета ) { if(firstCalc) { ArrayInitialize(closeBuffer,EMPTY_VALUE); firstCalc=false; } //--- MqlTick last_tick; string com="\r\n"; if(SymbolInfoTick(Symbol(),last_tick)) { com=com+" Last Bid = "+DoubleToString(last_tick.bid,_Digits); } com=com+" price[0]= "+DoubleToString(price[0],_Digits)+ " price[rates_total-1]= "+DoubleToString(price[rates_total-1],_Digits); Comment(com); //--- return value of prev_calculated for next call return(rates_total); } //+------------------------------------------------------------------+
Результат:
Пока мой пост не замечают решил ответить на свой второй вопрос - взять пример "не кривого" кода (по образному выражению Мегаквотов ;) и добавить одну странную на мой взгляд проверку...
Естественно получилась небольшая разница в результатах..
//+------------------------------------------------------------------+ //| Momentum | //+------------------------------------------------------------------+ int OnCalculate(const int rates_total, const int prev_calculated, const int begin, const double &price[]) { //--- start calculation int StartCalcPosition=(ExtMomentumPeriod-1)+begin; //---- insufficient data if(rates_total<StartCalcPosition) return(0); //--- correct draw begin if(begin>0) PlotIndexSetInteger(0,PLOT_DRAW_BEGIN,StartCalcPosition+(ExtMomentumPeriod-1)); //--- start working, detect position int pos=prev_calculated-1; if(pos<StartCalcPosition) pos=begin+ExtMomentumPeriod; if(!ArrayGetAsSeries(price)) // ------ Проверка очевидного !!!!!! ArraySetAsSeries(price,true);// но не для всех...
А в справке написано
Чудно..Дело в том, что массив price[] не обязательно является таймсерией. В справке есть ArrayGetAsSeries() примечание:
Примечание
Для проверки массива на принадлежность к таймсерии следует применять функцию ArrayIsSeries(). Массивы ценовых данных, переданных в качестве входных параметров в функцию OnCalculate(), не обязательно имеют направление индексации как у таймсерий. Нужное направление индексации можно установить функцией ArraySetAsSeries().
Не всегда получается отвечать вовремя. Но ведь можно проверить самостоятельно и убедиться, что самая последняя цена передается в функцию OnCalculate() под индексом rates_total-1. То есть, переданный в функцию массив price[] имеет индексацию из прошлого в будущее.
Вот простой пример индикатора для проверки.
Результат:
Спасибо что нашли время ответить!
Вопрос этот был второстепенным и скорее... хм. - провокационным.
Таймсерия принимается и она не таймсерия. Странно знаете.
Нужно не зависеть от умолчаний и проверять - иначе криво!
Смотрим творения мастеров-создателей - никаких проверок.
"Что позволено Юпитеру..."
;)
А вопрос остался! С сложением или делением логарифма.
Может быть я мыслю слишком шаблонно и топорно? может разработчики подскажут, как организовать доступ к таймсериям при использовании сложных алогритмов с использованием ооп и большой вложенности вызовов функций?
Спасибо что нашли время ответить!
Вопрос этот был второстепенным и скорее... хм. - провокационным.
Таймсерия принимается и она не таймсерия. Странно знаете.
Нужно не зависеть от умолчаний и проверять - иначе криво!
Смотрим творения мастеров-создателей - никаких проверок.
Но ведь разработчики не пишут для индикатора Momentum в OnInit как у Вас
void OnInit() { //--- check for input value if(pPeriod<0) { iPeriod=14; Print ("Input parameter Period has wrong value.", " Indicator will use value ",pPeriod); } else iPeriod=pPeriod; //---- buffers SetIndexBuffer(0,ExtBuffer,INDICATOR_DATA); //---- name for DataWindow and indicator subwindow label sName+="("+string(iPeriod)+ ")"; IndicatorSetString(INDICATOR_SHORTNAME,sName); //--- sets first bar from what index will be drawn PlotIndexSetInteger(0,PLOT_DRAW_BEGIN,iPeriod-1); //--- sets drawing line empty value PlotIndexSetDouble(0,PLOT_EMPTY_VALUE,0); //--- digits IndicatorSetInteger(INDICATOR_DIGITS,5); PlotIndexSetString(0,PLOT_LABEL,sName); ArraySetAsSeries(ExtBuffer,true); Print("Init Dvar...."); }
Вы же писали это сознательно, значит понимали что делаете.
Но ведь разработчики не пишут для индикатора Momentum в OnInit как у Вас
Вы же писали это сознательно, значит понимали что делаете.
Это затронуло ExtBuffer[i]=std*MathLog(sred)/(MathLog(price[0])*Means);?
:o)))
Буду осмотрительней...
Спасибо.
PS.
SetIndexBuffer
Связывает указанный индикаторный буфер с одномерным динамическим массивом типа double, объявленном на глобальном уровне.
bool SetIndexBuffer( |
Примечание
После связывания динамический массив buffer[] будет иметь индексацию как в обычных массивах, даже если для связываемого массива будет предварительно установлена индексация как в таймсериях. Если необходимо изменить порядок доступа к элементам индикаторного массива, необходимо применить функцию ArraySetAsSeries() после связывания массива функцией SetIndexBuffer().
А вопрос остался! С сложением или делением логарифма.
Логарифм здесь не причем. Компилятор указывает на выход за пределы индексации при доступе к массиву ExtBuffer[]. Вы его объявили на глобальном уровне, но он так и остался нулевого размера. Если бы Вы его привязали к индикаторному буферу, то все было бы нормально.
SetIndexBuffer(0,ExtBuffer,INDICATOR_CALCULATIONS);
- Бесплатные приложения для трейдинга
- 8 000+ сигналов для копирования
- Экономические новости для анализа финансовых рынков
Вы принимаете политику сайта и условия использования
#property indicator_separate_window
#property indicator_buffers 1
#property indicator_plots 1
//---- plot
#property indicator_label1 "D_1"
#property indicator_type1 DRAW_LINE
#property indicator_color1 RoyalBlue
#property indicator_style1 STYLE_SOLID
#property indicator_width1 1
//---- input parameters
input int pPeriod=200; // Period
double P=0.00001;
//---- indicator buffers
double ExtBuffer[],std,sred,Means;
//--- global variable
int iPeriod;
string sName="D_Vars";
//+------------------------------------------------------------------+
//| Custom indicator initialization function |
//+------------------------------------------------------------------+
void OnInit()
{
//--- check for input value
if(pPeriod<0)
{
iPeriod=14;
Print ("Input parameter Period has wrong value.",
" Indicator will use value ",pPeriod);
}
else iPeriod=pPeriod;
//---- buffers
SetIndexBuffer(0,ExtBuffer,INDICATOR_DATA);
//---- name for DataWindow and indicator subwindow label
sName+="("+string(iPeriod)+ ")";
IndicatorSetString(INDICATOR_SHORTNAME,sName);
//--- sets first bar from what index will be drawn
PlotIndexSetInteger(0,PLOT_DRAW_BEGIN,iPeriod-1);
//--- sets drawing line empty value
PlotIndexSetDouble(0,PLOT_EMPTY_VALUE,0);
//--- digits
IndicatorSetInteger(INDICATOR_DIGITS,5);
PlotIndexSetString(0,PLOT_LABEL,sName);
ArraySetAsSeries(ExtBuffer,true);
Print("Init Dvar....");
}
//+------------------------------------------------------------------+
//| Momentu |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total,
const int prev_calculated,
const int begin,
const double &price[])
{
//--- start calculation
int StartCalcPosition=(iPeriod+1)+begin;
//---- insufficient data
if(rates_total<StartCalcPosition)
return(0);
//--- correct draw begin
std=0.1;
sred=0.001;
Means=0.001;
Print(".... start ....iPeriod=",iPeriod);
for(int i=0;i<iPeriod;i++)
{
ExtBuffer[i]=std*MathLog(sred)/(MathLog(price[0])*Means);
Print (i,"=",ExtBuffer[i]," price[0]=",price[0]);
}
Print(".... end....");
//--- OnCalculate done. Return new prev_calculated.
return(rates_total);
}
результат
2010.02.13 05:05:55 Access (CHFJPY,M15) Access violation read to 0x00000007 in 'E:\Program Files\MetaTrader 5\MQL5\Indicators\MyMSQL5\errors\Access.ex5
2010.02.13 05:05:55 Access (CHFJPY,M15) 2 = 0.9559295868397006 price[0]= 87.119
2010.02.13 05:05:55 Access (CHFJPY,M15) 1 = 1.131892665130701 price[0]= 87.119
2010.02.13 05:05:55 Access (CHFJPY,M15) 0 = 1.201220169277647 price[0]= 87.119
2010.02.13 05:05:55 Access (CHFJPY,M15) .... start ....iPeriod= 200
2010.02.13 05:05:55 Access (CHFJPY,M15) Init Dvar....
Получается, что в цикле меняются результаты, или оптимизация кода напартачила?
В чём ошибка?
И еще одна хохма -. последняя цена на графике 83.689/05!!
что в price[0] - если в параметрах выбрана цена Close?