Перейти к содержанию

Советник с ручной стратегии \"Форекс Драйвер\" - Пишем код


talliy

Рекомендуемые сообщения

Советник с ручной стратегии \"Форекс Драйвер… Опубликовано

Начинающим, да и не только, программистам привет!
Хочу создать тему разработки, автоматизации, ручной стратегии "Форекс Драйвер". Познакомился с ней не давно, использует графики построения свечей ренко. В блоге - http://tradelikeapro.ru/strategiya-forex-racer/ подробное видео работы по ней, а также все доступные для работы индикаторы и советники. Отмечу что файлы в открытом коде поэтому единственной сложностью считаю создание логики для автоматической торговли по системе.

Хочу отметить что тема создается в пример описание кодом ручную торговую стратегию, а так же прошу кому интересно принимать активное участие в ее программировании...

Так как система использует несколько индикаторов, я предлагаю каждый индикатор, его код сигнала, передать в отдельные функции, а далее в основном советнике описать логику той или иной.

И так, самое первое что в "Драйвере" делается, это создается график ренко с помощью советника. Просмотрев код, видно, что этот советник создает и записывает файл котировок графика ренко. Т.к для автоматизации нам ненужно визуальное восприятие мы первым что должны сделать это передать, или прочитать, файл котировок в массив данных.
График пишется в бинарный файл который представляет из себя строчку байтов. В заголовке, в котором имя и представление о файле, 148 байт, а далее каждый бар графика по 44 байта, в них входит время - 4 байта и 5 величин бара по 8 байтов.
Признаюсь честно, я не сталкивался в программировании с записью, чтением бинарных файлов, поэтому было немного непонятно как должно происходить чтение. Но поседев подумав, гугл в помощь, да и вопросы в личку дали свои результаты.. И самая первая функция робота - это передача данных в массивы...

Функция WriteArray()

Для передачи массивам данных мы обозначим глобальные массивы -

double Openf[];
double Lowf[];
double Higef[];
double Closef[];
double Volumef[];

И передадим их функции с флагом изменения их значений:

WriteArray(Openf, Lowf, Higef, Closef, Volumef );

Сам код функции:



int WriteArray (double &Price[],double &Price1[],double &Price2[],double &Price3[],double &Volum[])
{

int Tim[]; //массив времени бара пишется в файл первым как 4 байта

//++++++ смотрим размер файла ++++++++

int SizeFile=0;
int SumBar=0;

static int Z=0; //Счетчик заполненого массива историей баров( 1-заполнен)
int SizeArray=ArraySize(Price);

//+++++++++Задаем размер массива и разворачиваем его индекс++++++++++++++++++++

int Handl=FileOpenHistory("EURUSD2.hst",FILE_BIN|FILE_READ);
SizeFile=FileSize(Handl);
FileClose(Handl);
SumBar=(SizeFile-148)/44;
if(SizeArray { // количества баров в файле. Причем мы перевернем индексацию массива
ArraySetAsSeries(Price, false); //создав таким образом эмуляцию индикаторного буфера.
ArraySetAsSeries(Price1, false); //Нулевой индекс будет соответствовать нулевому бару, т.е. самому
ArraySetAsSeries(Price2, false); //последниму на графике
ArraySetAsSeries(Price3, false);
ArraySetAsSeries(Volum, false);
ArraySetAsSeries(Tim, false);
//---- Изменить размер эмулируемых индикаторных буферов
ArrayResize(Price, SumBar);
ArrayResize(Price1,SumBar);
ArrayResize(Price2,SumBar);
ArrayResize(Price3,SumBar);
ArrayResize(Volum,SumBar);
ArrayResize(Tim,SumBar);
//---- Установить обратное направление индексирования в массиве
ArraySetAsSeries(Price, true);
ArraySetAsSeries(Price1, true);
ArraySetAsSeries(Price2, true);
ArraySetAsSeries(Price3, true);
ArraySetAsSeries(Volum, true);
ArraySetAsSeries(Tim, true);

}

//+++++++++++++Заполняем массив данными+++++++++++++++++++++++++++


Handl=FileOpenHistory("EURUSD2.hst",FILE_BIN|FILE_READ);
// Если массив пустой, то читаем файл с начала...

if(Z!=1)
{
int Size=ArraySize(Price);
int i=0;
while(i!=Size)
{
int Seek=44*i;
FileSeek(Handl,148+Seek,SEEK_SET);
int N=Size-(1+i);
Tim[N]=FileReadInteger(Handl,LONG_VALUE);
Price[N]=FileReadDouble(Handl,DOUBLE_VALUE);
Price1[N]=FileReadDouble(Handl,DOUBLE_VALUE);
Price2[N]=FileReadDouble(Handl,DOUBLE_VALUE);
Price3[N]=FileReadDouble(Handl,DOUBLE_VALUE);
Volum[N]=FileReadDouble(Handl,DOUBLE_VALUE);
i++;
}
Z=1;
}
// Если массив заполнен, то читаем с файла последний бар....
if(Z!=0)
{

int Si=FileSize(Handl);
FileSeek(Handl,Si-44,SEEK_END);
Tim[0]=FileReadInteger(Handl,LONG_VALUE);
Price[0]=FileReadDouble(Handl,DOUBLE_VALUE);
Price1[0]=FileReadDouble(Handl,DOUBLE_VALUE);
Price2[0]=FileReadDouble(Handl,DOUBLE_VALUE);
Price3[0]=FileReadDouble(Handl,DOUBLE_VALUE);
Volum[0]=FileReadDouble(Handl,DOUBLE_VALUE);
}
FileClose(Handl);

}


Таким образом у нас заполнен массив данными графика ренко..
Далее мы будем переносить коды индикаторов в функции эксперта.....

Добавлено: 05-08-2013 06:26:06

Следующим рассмотрим индикатор FR_Scanner. Он призван разбирать обычные японские свечи на периоды графика ренко, 5, 10, 15 и т.д. до 35 пунктов свечи, т.е. движения цены в одном направлении. Условия для каждого периода просты:
Зеленый и стрелочка вверх появляется в двух вариантах:
- если цена закрытия третьего бара больше чем цена закрытия второго и цена закрытия второго больше чем цена закрытия первого.
- если цена закрытия третьего бара меньше чем цена закрытия второго и цена второго больше чем цена первого.
Красный цвет и стрелочка вниз следовательно наоборот.

Сам код вычисления вот:

double lda_16[];
double lda_20[];
int li_12 = 0;
if (gi_140 == 333) {
Alert(f0_1());
return (0);
}
ArrayResize(lda_16, Bars);
ArrayResize(lda_20, Bars);
lda_16[li_12] = Close[Bars - 1];
for (int li_0 = Bars - 2; li_0 >= 0; li_0--) {
if (li_12 > ArraySize(lda_16) - 100) {
ArrayCopy(lda_20, lda_16);
ArrayResize(lda_16, ArraySize(lda_16) + Bars);
ArrayCopy(lda_16, lda_20, 0, 0, li_12 + 1);
ArrayResize(lda_20, ArraySize(lda_20) + Bars);
}
if (li_12 == 0) {
while (Close[li_0] > lda_16[li_12] + gi_140 * Point) {
li_12++;
lda_16[li_12] = lda_16[li_12 - 1] + gi_140 * Point;
}
while (Close[li_0] li_12++;
lda_16[li_12] = lda_16[li_12 - 1] - gi_140 * Point;
}
}
if (lda_16[li_12] > lda_16[li_12 - 1]) {
if (Close[li_0] > lda_16[li_12] + gi_140 * Point) {
while (Close[li_0] > lda_16[li_12] + gi_140 * Point) {
li_12++;
lda_16[li_12] = lda_16[li_12 - 1] + gi_140 * Point;
}
}
if (Close[li_0] li_12++;
for (lda_16[li_12] = lda_16[li_12 - 1] - gi_140 * 2 * Point; Close[li_0] }
}
if (lda_16[li_12] if (Close[li_0] while (Close[li_0] li_12++;
lda_16[li_12] = lda_16[li_12 - 1] - gi_140 * Point;
}
}
if (Close[li_0] > lda_16[li_12] + gi_140 * 2 * Point) {
li_12++;
for (lda_16[li_12] = lda_16[li_12 - 1] + gi_140 * 2 * Point; Close[li_0] > lda_16[li_12] + gi_140 * Point; lda_16[li_12] = lda_16[li_12 - 1] + gi_140 * Point) li_12++;
}
}
}


Далее проверка и выполнение условий сигнала:


if (li_12 > Bars - 100) {
for (li_0 = 0; li_0 li_12 = Bars - 100;
}
for (li_0 = 1; li_0 if (lda_16[li_0] > lda_16[li_0 - 1] && lda_16[li_0 - 1] > lda_16[li_0 - 2]) {
ObjectSetText("Brick3", "Brick" + DoubleToStr(gi_140,0), 10, "Trebuchet MS", BullColor);
ObjectSetText("Dir3", "/\\ ", 12, "Gill Sans Ultra Bold", BullColor);
}
if (lda_16[li_0] > lda_16[li_0 - 1] && lda_16[li_0 - 1] ObjectSetText("Brick3", "Brick" + DoubleToStr(gi_140,0), 10, "Trebuchet MS", BearColor);
ObjectSetText("Dir3", "\\/ ", 12, "Gill Sans Ultra Bold", BearColor);
}
if (lda_16[li_0] ObjectSetText("Brick3", "Brick" + DoubleToStr(gi_140,0), 10, "Trebuchet MS", BearColor);
ObjectSetText("Dir3", "\\/ ", 12, "Gill Sans Ultra Bold", BearColor);
}
if (lda_16[li_0] lda_16[li_0 - 2]) {
ObjectSetText("Brick3", "Brick" + DoubleToStr(gi_140,0), 10, "Trebuchet MS", BullColor);
ObjectSetText("Dir3", "/\\ ", 12, "Gill Sans Ultra Bold", BullColor);
}
}


Зная все что нам необходимо пишем функцию в которую мы передадим период ренко и уже заполненый массив функцией WriteArray() ценами закрытия.

int PeriodRenko(int PeriodR, double Closef[]){

Так же в самом коде произведем замену нескольким переменным.
Хочу обратить внимание на то что индексация в массивах по умолчанию с лева на права, а построение графика и массивы в индикаторах имеют индексацию противоположную, т.е. с права налево. Прошу это помнить при программировании самостоятельных систем.

И так... мы заменим в коде массив содержащий в себе цены закрытия (Close[]) на наш массив с ценами (Closef[]), а также массив содержащий количество всего баров (Bars[]) на количество элементов в массиве Closef[].

Функция PeriodRenko:


int PeriodRenko(int PeriodR, double Closef[]){
double lda_16[];
double lda_20[];
int li_12 = 0;
int Bar=ArraySize(Closef);
ArraySetAsSeries(lda_16, false);
ArraySetAsSeries(lda_20, false);
ArrayResize(lda_16, Bar);
ArrayResize(lda_20, Bar);
ArraySetAsSeries(lda_16, true);
ArraySetAsSeries(lda_20, true);
lda_16[li_12] = Closef[Bar - 1];
for (int li_0 = Bar - 2; li_0 >= 0; li_0--) {
if (li_12 > ArraySize(lda_16) - 100) {
ArraySetAsSeries(lda_16, false);
ArraySetAsSeries(lda_20, false);
ArrayCopy(lda_20, lda_16);
ArrayResize(lda_16, ArraySize(lda_16) + Bar);
ArrayCopy(lda_16, lda_20, 0, 0, li_12 + 1);
ArrayResize(lda_20, ArraySize(lda_20) + Bar);
ArraySetAsSeries(lda_16, true);
ArraySetAsSeries(lda_20, true);
}
if (li_12 == 0) {
while (Closef[li_0] > lda_16[li_12] + PeriodR * Point) {
li_12++;
lda_16[li_12] = lda_16[li_12 - 1] + PeriodR * Point;
}
while (Closef[li_0] li_12++;
lda_16[li_12] = lda_16[li_12 - 1] - PeriodR * Point;
}
}
if (lda_16[li_12] > lda_16[li_12 - 1]) {
if (Closef[li_0] > lda_16[li_12] + PeriodR * Point) {
while (Closef[li_0] > lda_16[li_12] + PeriodR * Point) {
li_12++;
lda_16[li_12] = lda_16[li_12 - 1] + PeriodR * Point;
}
}
if (Closef[li_0] li_12++;
for (lda_16[li_12] = lda_16[li_12 - 1] - PeriodR * 2 * Point; Closef[li_0] }
}
if (lda_16[li_12] if (Closef[li_0] while (Closef[li_0] li_12++;
lda_16[li_12] = lda_16[li_12 - 1] - PeriodR * Point;
}
}
if (Closef[li_0] > lda_16[li_12] + PeriodR * 2 * Point) {
li_12++;
for (lda_16[li_12] = lda_16[li_12 - 1] + PeriodR * 2 * Point; Closef[li_0] > lda_16[li_12] + PeriodR * Point; lda_16[li_12] = lda_16[li_12 - 1] + PeriodR * Point) li_12++;
}
}
}

if (li_12 > Bar - 100) {
for (li_0 = 0; li_0 li_12 = Bar - 100;
}
// если сигнал вверх вернем 1, если вниз вернем 2
for (li_0 = 1; li_0 if (lda_16[li_0] > lda_16[li_0 - 1] && lda_16[li_0 - 1] > lda_16[li_0 - 2]) {
return(1); } else {return(0);}
if (lda_16[li_0] > lda_16[li_0 - 1] && lda_16[li_0 - 1] return(2); } else {return(0);}
if (lda_16[li_0] return(2); } else {return(0);}
if (lda_16[li_0] lda_16[li_0 - 2]) {
return(1); } else {return(0);}
}

return(0);


}


Но для правильного восприятия сигнала от этого индикатора данной функции мало. Эта функция просчитывает один лишь период ренко, а у нас в условии стратегии сказано, что сигналы со всех 7 периодов должны совпадать.
Для этого мы напишем еще одну функцию дающую один сигнал со всех периодов ренко.

Функция SignalFRS:


int SignalFRS(double Closef[]){
int SignalPeriod;
int Up=0;
int Down=0;
// Создаем цикл выбора периода и получаем сигналы с периодов ренко
// Если все стрелочки вверх( а так по условиям системы) , то вернем сигнал вверх
// если все стрелочки красные, то вернем сигнал вниз
for(int i =0;i {
switch(i){
case 0:
SignalPeriod=PeriodRenko(5,Closef);
if(SignalPeriod==1) Up++;
if(SignalPeriod==2) Down++;
case 1:
SignalPeriod=PeriodRenko(10,Closef);
if(SignalPeriod==1) Up++;
if(SignalPeriod==2) Down++;
case 2:
SignalPeriod=PeriodRenko(15,Closef);
if(SignalPeriod==1) Up++;
if(SignalPeriod==2) Down++;
case 3:
SignalPeriod=PeriodRenko(20,Closef);
if(SignalPeriod==1) Up++;
if(SignalPeriod==2) Down++;
case 4:
SignalPeriod=PeriodRenko(25,Closef);
if(SignalPeriod==1) Up++;
if(SignalPeriod==2) Down++;
case 5:
SignalPeriod=PeriodRenko(30,Closef);
if(SignalPeriod==1) Up++;
if(SignalPeriod==2) Down++;
case 6:
SignalPeriod=PeriodRenko(35,Closef);
if(SignalPeriod==1) Up++;
if(SignalPeriod==2) Down++;
}
}

if(Up==7)return(1);
if(Down==7)return(2);
return(0);

}


Таким образом мы перенесли первый индикатор системы в функции... Изменено пользователем talliy
  • Лайк 2
Ссылка на сообщение
Поделиться на другие сайты

Советник с ручной стратегии \"Форекс Драйвер… Опубликовано

И так, на сегодня наша библиотека функций имеет уже кое какую базу. Функция заполнение массивов свечами ренко, а также первый индикатор
системы - FR_Scanner. Сегодня разберем следующий индикатор - FR_Trend. Напоминаю, что все файлы работы по системе можно скачать с поста в блоге по выше указанной ссылке.

Заглинув в код индикатора обратил внимание что для его расчетов требуется время бара. Но писав функцию заполнения массивов, массив времени бара я не вынес за пределы функции и как оказалось
зря. Поправить этот факт не сложно. Просто объявим и его глобальным и передадим его в функцию. Но об этом чуть позже, когда будем собирать воедино все написанные функции.

FR_Trend использует в себе 4 индикаторных буфера. Нам важны первые два. Вы их могли бы вызвать используя iCustom(). Индикатор будет синей линией тогда когда второй индикаторный буфер равен 0, а когда появляется на нем значение более или менее 0, то линия индикатора окрашивается в розовый.
Все необходимое нам мы выяснили. Предлагаю глобальным массивом обозначить всего лишь один в который мы передадим значения второго индикаторного буфера. Его мы передадим функции с флагом изменения его значений. Остальные переменные не будут выходить за предел функции, за исключением (по вкусу каждого програмера)
можно вынести параметры самого индикатора для дальнейшей оптимизации их в тестере.

вот сам код функции start():


int li_0;
int li_4 = Bars - IndicatorCounted() - 1;
if (li_4 else {
li_0 = Bars - 2;
gd_264 = 2.0 / (A + 1);
gda_96[li_0 + 1] = 0.0;
gda_100[li_0 + 1] = 0.0;
gd_208 = 0.0;
gd_200 = 0.0;
gd_224 = 0.0;
gd_216 = 0.0;
gd_240 = 0.0;
gd_232 = 0.0;
gt_280 = Time[li_0];
gi_272 = 0;
gi_276 = 0;
}
for (int li_8 = li_0; li_8 >= 0; li_8--) {
if (gt_280 != Time[li_8]) {
gd_208 = gd_200;
gd_224 = gd_216;
gd_240 = gd_232;
gt_280 = Time[li_8];
}
HighT = High[li_8];
LowT = Low[li_8];
RazHT = HighT - (High[li_8 + 1]);
RazLT = Low[li_8 + 1] - LowT;
if (RazHT if (RazLT if (RazHT == RazLT) {
RazHT = 0;
RazLT = 0;
} else {
if (RazHT else
if (RazLT }
H_L = MathAbs(HighT - LowT);
H_C = MathAbs(HighT - (Close[li_8 + 1]));
L_C = MathAbs(LowT - (Close[li_8 + 1]));
gd_128 = MathMax(MathMax(td_0, td_0), L_C);
if (gd_128 == 0.0) {
gd_176 = 0;
gd_184 = 0;
} else {
gd_176 = 100.0 * RazHT / gd_128;
gd_184 = 100.0 * RazLT / gd_128;
}
gd_200 = gd_208 + (gd_176 - gd_208) * gd_264;
gd_216 = gd_224 + (gd_184 - gd_224) * gd_264;
gd_248 = gd_200 - gd_216;
gd_192 = MathAbs(gd_200 + gd_216);
if (gd_192 == 0.0) gd_256 = 0;
else gd_256 = 100.0 * (MathAbs(gd_248) / gd_192);
if (gd_200 > gd_216) gi_272 = 1;
if (gd_200 if (gi_272 == 2) gd_256 = -gd_256;
gd_232 = gd_240 + (gd_256 - gd_240) * gd_264;
gda_96[li_8] = gd_232;
if (gda_96[li_8] > gda_96[li_8 + 1]) gi_276 = 1;
if (gda_96[li_8] if (gi_276 == 1) gda_100[li_8 + 1] = gda_96[li_8 + 1];
gi_276 = 2;
}
if (gi_276 == 2) gda_100[li_8] = gda_96[li_8];
else gda_100[li_8] = 0.0;
gda_104[li_8] = SR;
gda_108[li_8] = -SR;
}


Хочу обратить внимание на функцию IndicatorCounted() - она призвана содержать в себе количество посчитанных баров сужающую для оптимизации процессов расчета индикатора.
Т.к. мы работаем не с графиком свечей, а с предварительно переданными значениями этого графика в массивы, в эксперте будет просто ее обойти. Для тех кто не знает - не все
функции индикатора можно передать в эксперт, по этому приходится идти на симуляцию тех же процессов. В моих функциях уже был пример оптимизации расчетов. Я использовал статическую
переменную Z. В этой ситуации так же. Я обозначу статическую переменную, но уже S. Дадим ей значение равное нулю и поставим условие что если она равна нулю, то мы считаем всю
историю баров, после просчета мы меняем ее значение на единицу и опять условие если S не равна 0, то считаем всего 10 последних баров. Но вы могли бы поставить любое интересное
для вас значение. В принципе мы симулировали функцию IndicatorCounted().
Так же код расчета индикатора использует цены High, Low и Close. Поэтому в функцию мы передаем не только массив времени но и наши массивы цен бара и производим замену в коде на них.

В общем считаю что функция написана и вот ее код:

Функция SignalFRT:



int SignalFRT(double &FRT[],double Timf[],double Highf[],double Lowf[],double Closef[])
{
int A = 8;
int SR = 25;
double gda_96[];
double gda_104[];
double gda_108[];
double RazHT;
double RazLT;
double gd_128;
double HighT;
double LowT;
double L_C;
double gd_176;
double gd_184;
double gd_192;
double gd_200;
double gd_208;
double gd_216;
double gd_224;
double gd_232;
double gd_240;
double gd_248;
double gd_256;
double gd_264;
double H_L;
double H_C;
double td_0;
int gi_272;
int gi_276;
datetime gt_280;
int gi_284;
int li_0;
int Bar=ArraySize(Timf);
int RazArray=ArraySize(FRT);
static int S=0;
if( RazArray ArraySetAsSeries(gda_96, false);
ArraySetAsSeries(FRT, false);
ArraySetAsSeries(gda_104, false);
ArraySetAsSeries(gda_108, false);
ArrayResize(gda_96, Bar);
ArrayResize(FRT,Bar);
ArrayResize(gda_104,Bar);
ArrayResize(gda_108,Bar);
ArraySetAsSeries(gda_96, true);
ArraySetAsSeries(FRT, true);
ArraySetAsSeries(gda_104, true);
ArraySetAsSeries(gda_108, true);}
if (S==0){
li_0 = Bar - 2;
gd_264 = 2.0 / (A + 1);
gda_96[li_0 + 1] = 0.0;
FRT[li_0 + 1] = 0.0;
gd_208 = 0.0;
gd_200 = 0.0;
gd_224 = 0.0;
gd_216 = 0.0;
gd_240 = 0.0;
gd_232 = 0.0;
gt_280 = Timf[li_0];
gi_272 = 0;
gi_276 = 0;
for (int li_8 = li_0; li_8 >= 0; li_8--) {
if (gt_280 != Timf[li_8]) {
gd_208 = gd_200;
gd_224 = gd_216;
gd_240 = gd_232;
gt_280 = Timf[li_8];
}
HighT = Highf[li_8];
LowT = Lowf[li_8];
RazHT = HighT - (Highf[li_8 + 1]);
RazLT = Lowf[li_8 + 1] - LowT;
if (RazHT if (RazLT if (RazHT == RazLT) {
RazHT = 0;
RazLT = 0;
} else {
if (RazHT else
if (RazLT }
H_L = MathAbs(HighT - LowT);
H_C = MathAbs(HighT - (Closef[li_8 + 1]));
L_C = MathAbs(LowT - (Closef[li_8 + 1]));
gd_128 = MathMax(MathMax(td_0, td_0), L_C);
if (gd_128 == 0.0) {
gd_176 = 0;
gd_184 = 0;
} else {
gd_176 = 100.0 * RazHT / gd_128;
gd_184 = 100.0 * RazLT / gd_128;
}
gd_200 = gd_208 + (gd_176 - gd_208) * gd_264;
gd_216 = gd_224 + (gd_184 - gd_224) * gd_264;
gd_248 = gd_200 - gd_216;
gd_192 = MathAbs(gd_200 + gd_216);
if (gd_192 == 0.0) gd_256 = 0;
else gd_256 = 100.0 * (MathAbs(gd_248) / gd_192);
if (gd_200 > gd_216) gi_272 = 1;
if (gd_200 if (gi_272 == 2) gd_256 = -gd_256;
gd_232 = gd_240 + (gd_256 - gd_240) * gd_264;

gda_96[li_8] = gd_232;
if (gda_96[li_8] > gda_96[li_8 + 1]) gi_276 = 1;
if (gda_96[li_8] if (gi_276 == 1) FRT[li_8 + 1] = gda_96[li_8 + 1];
gi_276 = 2;
}
if (gi_276 == 2) FRT[li_8] = gda_96[li_8];
else FRT[li_8] = 0.0;
gda_104[li_8] = SR;
gda_108[li_8] = -SR;

}
S=1;
}
if (S!=0){
li_0 = 10;
for (int li_81 = li_0; li_81 >= 0; li_81--) {
if (gt_280 != Timf[li_81]) {
gd_208 = gd_200;
gd_224 = gd_216;
gd_240 = gd_232;
gt_280 = Timf[li_81];
}
HighT = Highf[li_81];
LowT = Lowf[li_81];
RazHT = HighT - (Highf[li_81 + 1]);
RazLT = Lowf[li_81 + 1] - LowT;
if (RazHT if (RazLT if (RazHT == RazLT) {
RazHT = 0;
RazLT = 0;
} else {
if (RazHT else
if (RazLT }
H_L = MathAbs(HighT - LowT);
H_C = MathAbs(HighT - (Closef[li_81 + 1]));
L_C = MathAbs(LowT - (Closef[li_81 + 1]));
gd_128 = MathMax(MathMax(td_0, td_0), L_C);
if (gd_128 == 0.0) {
gd_176 = 0;
gd_184 = 0;
} else {
gd_176 = 100.0 * RazHT / gd_128;
gd_184 = 100.0 * RazLT / gd_128;
}
gd_200 = gd_208 + (gd_176 - gd_208) * gd_264;
gd_216 = gd_224 + (gd_184 - gd_224) * gd_264;
gd_248 = gd_200 - gd_216;
gd_192 = MathAbs(gd_200 + gd_216);
if (gd_192 == 0.0) gd_256 = 0;
else gd_256 = 100.0 * (MathAbs(gd_248) / gd_192);
if (gd_200 > gd_216) gi_272 = 1;
if (gd_200 if (gi_272 == 2) gd_256 = -gd_256;
gd_232 = gd_240 + (gd_256 - gd_240) * gd_264;

gda_96[li_81] = gd_232;
if (gda_96[li_81] > gda_96[li_81 + 1]) gi_276 = 1;
if (gda_96[li_81] if (gi_276 == 1) FRT[li_81 + 1] = gda_96[li_81 + 1];
gi_276 = 2;
}
if (gi_276 == 2) FRT[li_81] = gda_96[li_81];
else FRT[li_81] = 0.0;
gda_104[li_81] = SR;
gda_108[li_81] = -SR;

}

}return(0);}


Добавлено: 08-08-2013 14:45:07

Вчера прочитал ветку повещенную данной стратегии. Впечатлило что многие легко решили разобрать ее по полочкам и заменить по вкусу индикаторы. Конечно как человеку который автоматизирует процесс торговли, мне интересны были предложенные индикаторы, они были скачены и отложены на случай оптимизации получившегося робота. Но первоначальная цель воссоздать в логике машинного вычисления и принятия решений на вход, выход условия, строго по правилам системы. За исключением расстановки стоп лосов и отложенных ордеров. Конечно же посидев подумав возможно и этот аспект перенести в код, но я не вижу особо критическим отклонением от правил системы использования фиксированного стопа и количества пунктов от цены для расстановки отложенных ордеров. Так же задумываюсь о системе слежения за ордерами. Использовать ли тралл либо фиксированный тейк профит. Ну да ладно, об этом чуть позже. У нас осталось всего два индикатора и мы будем формировать условие на вход.

Сегодня разберем индикатор FR-TrendLines. Он использует линейно-взвешенное скользящее среднее LWMA по ценам High. При чем если LWMA первого бара больше чем LWMA второго, то индикатор приобретает синий цвет, если же наоборот то красный, белый это пограничный цвет.

Как вы наверное знаете скользящее среднее в экспертах вызывается с помощью функции iMA(), т.к. мы работам изначально с массивами, то для расчета данных которые в них хранятся в МТ4 предусмотрена функция iMAOnArray(). Все переменные и массивы мы не будем выносить за пределы функции данного индикатора, а просто передадим ей массивы цен которые требуются для расчета индикатора и вернем единицу если цвет синий и двойку если красный линий индикатора. Ноль будет возвращаться в пограничные моменты. И напоминаю про индексацию массивов, которую мы принудительно меняем на противоположную.

И так, давайте для начала посмотрим код вычисления индикатора:


double ld_0;
double ld_8;
double ld_16;
double ld_24;
double ld_32;
double ld_40;
int li_48 = IndicatorCounted();
if (li_48 if (li_48 > 0) li_48--;
int li_52 = Bars - li_48;
for (int li_56 = 0; li_56 ld_0 = iMA(NULL, 0, TPeriod, TShift, TType, PRICE_HIGH, li_56);
ld_8 = iMA(NULL, 0, TPeriod, TShift, TType, PRICE_HIGH, li_56 + 1);
ld_16 = iMA(NULL, 0, TPeriod, TShift, TType, PRICE_LOW, li_56);
ld_24 = iMA(NULL, 0, TPeriod, TShift, TType, PRICE_LOW, li_56 + 1);
ld_32 = iMA(NULL, 0, TPeriod, TShift, TType, PRICE_MEDIAN, li_56);
ld_40 = iMA(NULL, 0, TPeriod, TShift, TType, PRICE_MEDIAN, li_56 + 1);
gda_88[li_56] = ld_0;
gda_92[li_56] = ld_0;
gda_96[li_56] = ld_0;
gda_100[li_56] = ld_16;
gda_104[li_56] = ld_16;
gda_108[li_56] = ld_16;
if (ld_0 > ld_8) {
gda_96[li_56] = 0;
gda_108[li_56] = 0;
}
if (ld_0 gda_92[li_56] = 0;
gda_104[li_56] = 0;
}
}


Обойдем функцию IndicatorCounted() и обозначим массивы. И так....

Функция SignalFRTL():



int SignalFRTL (double Lowf[],double Highf[])
{
int TPeriod = 34;
int TType = 3;
int TShift = 0;
double gda_88[];
double gda_92[];
double gda_96[];
double gda_100[];
double gda_104[];
double gda_108[];
static int Q=0;
int Bar=ArraySize(Lowf);
int indiarray=ArraySize(gda_88);
if(indiarray {
ArraySetAsSeries(gda_88, false);
ArraySetAsSeries(gda_92, false);
ArraySetAsSeries(gda_96, false);
ArraySetAsSeries(gda_100, false);
ArraySetAsSeries(gda_104, false);
ArraySetAsSeries(gda_108, false);

ArrayResize(gda_88, Bar);
ArrayResize(gda_92,Bar);
ArrayResize(gda_96,Bar);
ArrayResize(gda_100,Bar);
ArrayResize(gda_104,Bar);
ArrayResize(gda_108,Bar);

ArraySetAsSeries(gda_88, true);
ArraySetAsSeries(gda_92, true);
ArraySetAsSeries(gda_96, true);
ArraySetAsSeries(gda_100, true);
ArraySetAsSeries(gda_104, true);
ArraySetAsSeries(gda_108, true);
}
double ld_0;
double ld_8;
double ld_16;
if (Q==0)
{
int li_52=Bar-1;
for (int li_56 = 0; li_56 ld_0 = iMAOnArray(Highf, 0, TPeriod, TShift, TType, li_56);
ld_8 = iMAOnArray(Highf, 0, TPeriod, TShift, TType, li_56 + 1);
ld_16 = iMAOnArray(Lowf, 0, TPeriod, TShift, TType, li_56);
gda_88[li_56] = ld_0;
gda_92[li_56] = ld_0;
gda_96[li_56] = ld_0;
gda_100[li_56] = ld_16;
gda_104[li_56] = ld_16;
gda_108[li_56] = ld_16;
if (ld_0 > ld_8) {
gda_96[li_56] = 0;
gda_108[li_56] = 0;
return(2);
}
if (ld_0 gda_92[li_56] = 0;
gda_104[li_56] = 0;
return(1);
}

}
Q=1;
}
if(Q!=0)
{
int li_5=TPeriod;
for (int li_561 = 0; li_561 ld_0 = iMAOnArray(Highf, 0, TPeriod, TShift, TType, li_561);
ld_8 = iMAOnArray(Highf, 0, TPeriod, TShift, TType, li_561 + 1);
ld_16 = iMAOnArray(Lowf, 0, TPeriod, TShift, TType, li_561);
gda_88[li_561] = ld_0;
gda_92[li_561] = ld_0;
gda_96[li_561] = ld_0;
gda_100[li_561] = ld_16;
gda_104[li_561] = ld_16;
gda_108[li_561] = ld_16;
if (ld_0 > ld_8) {
gda_96[li_561] = 0;
gda_108[li_561] = 0;
return(2);
}
if (ld_0 gda_92[li_561] = 0;
gda_104[li_561] = 0;
return(1);
}
}
}
return (0);
}
Изменено пользователем talliy
Ссылка на сообщение
Поделиться на другие сайты

Советник с ручной стратегии \"Форекс Драйвер… Опубликовано

И последний индикатор - FR-Signals. На мой взгляд самый интересный из линейки индикаторов системы с точки зрения переноса его в функцию.
Логика индикатора сводится к разнице сигнальной линии и гистограммы индикатора MACD.Это встроенный индикатор в терминал и он работает исключительно с графиком цены. Не предусмотрен расчет передачи в него массива данных. В свое время индикатор MACD в просчетах использует скользящие средние методом EMA - экспоненциальное скользящее среднее по ценам закрытия бара. Сервис mql4.com разместил на своем сайте функции встроенных индикаторов и для начала мы успешно взяв код переделаем MACD под условие работы с массивами данных.

Вот сам код расчета MACD:


//+------------------------------------------------------------------+
//| Custom MACD.mq4 |
//| Copyright © 2004, MetaQuotes Software Corp. |
//| http://www.metaquotes.net/ |
//+------------------------------------------------------------------+
#property copyright "Copyright © 2004, MetaQuotes Software Corp."
#property link "http://www.metaquotes.net/"
//---- indicator settings
#property indicator_separate_window
#property indicator_buffers 2
#property indicator_color1 Silver
#property indicator_color2 Red
#property indicator_width1 2
//---- indicator parameters
extern int FastEMA=12;
extern int SlowEMA=26;
extern int SignalSMA=9;
//---- indicator buffers
double MacdBuffer[];
double SignalBuffer[];

//+------------------------------------------------------------------+
//| Custom indicator initialization function |
//+------------------------------------------------------------------+
int init()
{
//---- drawing settings
SetIndexStyle(0,DRAW_HISTOGRAM);
SetIndexStyle(1,DRAW_LINE);
SetIndexDrawBegin(1,SignalSMA);
IndicatorDigits(Digits+1);
//---- indicator buffers mapping
SetIndexBuffer(0,MacdBuffer);
SetIndexBuffer(1,SignalBuffer);
//---- name for DataWindow and indicator subwindow label
IndicatorShortName("MACD("+FastEMA+","+SlowEMA+","+SignalSMA+")");
SetIndexLabel(0,"MACD");
SetIndexLabel(1,"Signal");
//---- initialization done
return(0);
}
//+------------------------------------------------------------------+
//| Moving Averages Convergence/Divergence |
//+------------------------------------------------------------------+
int start()
{
int limit;
int counted_bars=IndicatorCounted();
//---- last counted bar will be recounted
if(counted_bars>0) counted_bars--;
limit=Bars-counted_bars;
//---- macd counted in the 1-st buffer
for(int i=0; i MacdBuffer=iMA(NULL,0,FastEMA,0,MODE_EMA,PRICE_CLOSE,i)-iMA(NULL,0,SlowEMA,0,MODE_EMA,PRICE_CLOSE,i);
//---- signal line counted in the 2-nd buffer
for(i=0; i SignalBuffer=iMAOnArray(MacdBuffer,Bars,SignalSMA,0,MODE_SMA,i);
//---- done
return(0);
}
//+------------------------------------------------------------------+


Сама гистограмма считается разницей EMA по ценам закрытия с разными периодами, а в свое время сигнальная линия считается методом SMA - простое скользящее среднее с массива данных гистограммы. Мы напишем функцию MACD индикатора и далее в FR-Signals будем ее использовать. Мы будем изменять значение массивов переданных функции ,также передадим значения периодов быстрой, медленной и сигнальной скользящей и массив с ценами закрытия. Обойдем IndicatorCounted(), переменной W и развернем индексацию, в общем :

Функция MyMACD:


int MyMACD (double Closef[], double &Gipstogram[], double &Signalline[], int FastEMA, int SlowEMA, int SignalSMA)
{
int Bar=ArraySize(Closef);
int ICount=ArraySize(Gipstogram);
static int W=0;
if (ICount {
ArraySetAsSeries(Gipstogram, false);
ArraySetAsSeries(Signalline, false);

ArrayResize(Gipstogram, Bar);
ArrayResize(Signalline,Bar);

ArraySetAsSeries(Gipstogram, true);
ArraySetAsSeries(Signalline, true);
}
if (W==0)
{
int limit=Bar-1;
for(int i=0; i Gipstogram=iMAOnArray(Closef,0,FastEMA,0,MODE_EMA,i)-iMAOnArray(Closef,0,SlowEMA,0,MODE_EMA,i);}
for(i=0; i Signalline=iMAOnArray(Gipstogram,0,SignalSMA,0,MODE_SMA,i);}
}
if (W!=0)
{
int limi=SlowEMA;
for(int ii=0; ii Gipstogram[ii]=iMAOnArray(Closef,0,FastEMA,0,MODE_EMA,ii)-iMAOnArray(Closef,0,SlowEMA,0,MODE_EMA,ii);}
for(ii=0; i Signalline[ii]=iMAOnArray(Gipstogram,0,SignalSMA,0,MODE_SMA,ii);}
}
}


Массивы Gipstogram[] и Signalline[] как раз и использует в расчетах FR-Signal, получая их используя iMACD(). Следовательно мы просто заменим код вызова MACD на массивы полученные заранее.
Для функции SignalFRSls() мы обозначим бва глобальных массива в которые посчитаем сигналы на покупку продажу и передадим их функции с изменением их значений, а так же массивы цен графика ренко.
И у нас получилась:

Функция SignalFRSls:


int SignalFRS (double &SignalBay[],double &SignalSell[],double Lowf[], double Highf[],double Closef[])
{
int FastEMA = 3;
int SlowEMA = 6;
int SignalSMA = 3;
double Signalline[];
double Gipstogram[];
static int Y=0;
double ld_28;
double ld_36;
double ld_44;
double ld_52;
double ld_60;
double ld_68;
int Bar=ArraySize(Lowf);
int iCount=ArraySize(SignalSell);
if (iCount {
ArraySetAsSeries(SignalBay, false);
ArraySetAsSeries(SignalSell, false);

ArrayResize(SignalBay, Bar);
ArrayResize(SignalSell,Bar);

ArraySetAsSeries(SignalBay, true);
ArraySetAsSeries(SignalSell, true);
}
MyMACD (Closef,Gipstogram,Signalline, FastEMA,SlowEMA,SignalSMA);
if (Y==0)
{
for (int li_24 = Bar - 2; li_24 >= 0; li_24--) {
ld_28 = Gipstogram[li_24 + 1];
ld_36 = Signalline[li_24 + 1];
ld_44 = ld_28 - ld_36;
ld_52 = Gipstogram[li_24];
ld_60 = Signalline[li_24];
ld_68 = ld_52 - ld_60;
if (ld_68 > 0.0 && ld_44 SignalBay[li_24] = Lowf[li_24] - 10.0 * Point;

}else{ SignalBay[li_24]=EMPTY_VALUE;}
if (ld_68 0.0) {
SignalSell[li_24] = Highf[li_24] + 10.0 * Point;

}else{ SignalSell[li_24]=EMPTY_VALUE;}
}}
if(Y!=0)
{
for (int li_2 = SlowEMA; li_2 >= 0; li_2--) {
ld_28 = Gipstogram[li_2 + 1];
ld_36 = Signalline[li_2 + 1];
ld_44 = ld_28 - ld_36;
ld_52 = Gipstogram[li_2];
ld_60 = Signalline[li_2];
ld_68 = ld_52 - ld_60;
if (ld_68 > 0.0 && ld_44 SignalBay[li_2] = Lowf[li_2] - 10.0 * Point;

}else{ SignalBay[li_24]=EMPTY_VALUE;}
if (ld_68 0.0) {
SignalSell[li_2] = Highf[li_2] + 10.0 * Point;

}else{ SignalSell[li_24]=EMPTY_VALUE;}
}

}return(0);}


По желанию вы могли бы вынести параметры скользящих для последующей их оптимизации в тестере.

Добавлено: 09-08-2013 13:54:12

Ну как же без проверки??? Сегодня весь провел в тестировании функции и отлаживании их работы. Подробнее о советнике test я расскажу если кому будет интересно.. А на сегодня этот советник некий помощник в торговле по системе дающий сигнал и воспроизводящий звук при нем. Смотрите сами, тестируйте.... Вешается на любой график и таймфрейм. При соблюдении условий на вход оповещает звуком.
Для теста создаем график той же пары свечей ренко на котором работает эксперт test и к нему применяем шаблон системы. И анализируем сигнал...
И так - test.mq4

Добавлено: 10-08-2013 11:00:31

Добрая половина любого эксперта сделана. Мы обозначили вход в рынок. Его можно теперь тестировать и подбирать необходимые, лучшие, параметры индикаторов. В последствии я исправлю его начальные функции записи и чтения удалив файл графика которые тормозят работу тестера....

Вторая половина не менее увлекательная и не менее важная. Мы входим в рынок!!! Много вопросов возникает... Мы должны описать функцию МаниМененжмента, условия слежения за ордерами, доливки, сетка отложенных ли, присутствует ли режим невидимка когда брокер не видит SL и TP, и главное выход из рынка...

На мой взгляд, или та задача которую я ставлю пред собой, это, раз мы работаем с отложенными ордерами, то главных в системе будут два первых ордера в направлении рынка. Один открывается по периоду в 10 пунктов, второй в 5 пунктов графика ренко. Как только срабатывает один из них в примере советника "Зверь" (Паша как то рассказывал у себя в блоге) будет возникать сетка отложенных ордеров, что позволит доливаться по тренду. Каждый будет сопровождаться тралом и будем скрывать SL и TP. Выходить будем по правилу системы либо раньше тралом...

Лот открытия ордеров изначально будет фиксированным, ну а собрав n историю ордеров посчитаем оптимальный лот - функцию МаниМенежмента из моего топика посвященному этому вопросу ...

test.mq4

Изменено пользователем talliy
  • Лайк 1
Ссылка на сообщение
Поделиться на другие сайты

Советник с ручной стратегии \"Форекс Драйвер… Опубликовано

Давненько не было ничего новенького... Дело в том что работа машины и цифр немного отличается от визуального восприятия и совершение операций в ручную... Цифра жестко диктует логике действия и отладка и получение качественного сигнала порой тот переломный момент в создании советников в котором не реализовывать команды торговли порой стоит смысла его создания. И советник забрасывается в дальний угол.
Именно в этом советнике я считаю что реализация качественного сигнала получено. Дальнейшая работа уже строится на правильном его использовании.

Но прежде чем продумывать логику торговли мне не нравился факт записи и чтения файла. Я занялся написанием функции которая бы заполняла массивы минуя работу с файлами. И как оказалось что время каждого бара в файле отставало на 50-150 миллисекунд от записи в массивы. Что говорит о ускорении работы алгоритма.

Непосредственно сам советник создающий оффлайн график и был переделан в функцию. Сложностью была работа с индексацией массивов, эмуляцию графика.

Подробно объяснять не буду по коду, я думаю взглянув на код вы в принципе смысл поймете.

и....

Функция ArrayRenko() :


#import "stdlib.ex4"
string ErrorDescription(int a0);
bool CompareDoubles(double a0, double a1);


int ArrayRenko(double &Price[],double &Price1[],double &Price2[],double &Price3[],double &Volum[],int &Timf[],int BrickSize)
{
ArraySetAsSeries(Price, false);
ArraySetAsSeries(Price1, false);
ArraySetAsSeries(Price2, false);
ArraySetAsSeries(Price3, false);
ArraySetAsSeries(Volum, false);
ArraySetAsSeries(Timf, false);
//---- Изменить размер эмулируемых индикаторных буферов
ArrayResize(Price, 1);
ArrayResize(Price1,1);
ArrayResize(Price2,1);
ArrayResize(Price3,1);
ArrayResize(Volum,1);
ArrayResize(Timf,1);
//---- Установить обратное направление индексирования в массиве
ArraySetAsSeries(Price, true);
ArraySetAsSeries(Price1, true);
ArraySetAsSeries(Price2, true);
ArraySetAsSeries(Price3, true);
ArraySetAsSeries(Volum, true);
ArraySetAsSeries(Timf, true);



double gd_124;
double gd_132;
double gd_140;
double gd_148;
double gd_156;
double gd_164;
double gd_172;
double gd_180;
double gd_188;
double gd_196;
double gd_204;
double gd_212;
int gi_220;
bool ShowWicks = TRUE;
int li_4;
int li_8;
int lia_12[13];
int li_20;
li_4 = BrickSize;
li_8 = 0;
if (Digits == 5 || (Digits == 3 && StringFind(Symbol(), "JPY") != -1)) {
li_4 = 10 * li_4;
li_8 = 10 * li_8;
}
if (Digits == 6 || (Digits == 4 && StringFind(Symbol(), "JPY") != -1)) {
li_4 = 100 * li_4;
li_8 = 100 * li_8;
}
gd_124 = NormalizeDouble(li_4 * Point, Digits);
gd_148 = NormalizeDouble(li_8 * Point + MathFloor((Close[Bars - 1]) / gd_124) * gd_124, Digits);
gd_140 = gd_148;
gd_156 = gd_148 + gd_124;
gd_132 = gd_156;
gd_164 = gd_148;
gd_172 = gd_156;
gd_180 = 1;
gi_220 = Time[Bars - 1];
int RM=ArraySize(Price);
for (int li_16 = Bars - 2; li_16 >= 0; li_16--) {
gd_180 += Volume[li_16];
gd_132 = MathMax(gd_132, High[li_16]);
gd_140 = MathMin(gd_140, Low[li_16]);
li_20 = High[li_16] + Low[li_16] > High[li_16 + 1] + (Low[li_16 + 1]);
while (li_20 && Low[li_16] gd_156 -= gd_124;
gd_148 -= gd_124;
gd_164 = gd_156;
gd_172 = gd_148;
RM=ArraySize(Price);
if(RM>1){
ArrayResize(Price, RM+1);
ArrayResize(Price1,RM+1);
ArrayResize(Price2,RM+1);
ArrayResize(Price3,RM+1);
ArrayResize(Volum,RM+1);
ArrayResize(Timf,RM+1);
Timf[0]=gi_220;
Price[0]= gd_164;
Price1[0]= gd_148;
if (ShowWicks && gd_132 > gd_156) Price2[0]= gd_132;
else Price2[0]= gd_156;
Price3[0]= gd_172;
Volum[0]= gd_180;
}
if(RM==1){
Timf[0]=gi_220;
Price[0]= gd_164;
Price1[0]= gd_148;
if (ShowWicks && gd_132 > gd_156) Price2[0]= gd_132;
else Price2[0]= gd_156;
Price3[0]= gd_172;
Volum[0]= gd_180;
}
gd_132 = 0;
gd_140 = EMPTY_VALUE;
gd_180 = 0;
gd_196 = gd_148;
gd_188 = gd_148;
if (gi_220 else gi_220++;
}
while (High[li_16] > gd_156 + gd_124 || CompareDoubles(High[li_16], gd_156 + gd_124)) {
gd_156 += gd_124;
gd_148 += gd_124;
gd_164 = gd_148;
gd_172 = gd_156;
RM=ArraySize(Price);
if(RM>1){
ArrayResize(Price, RM+1);
ArrayResize(Price1,RM+1);
ArrayResize(Price2,RM+1);
ArrayResize(Price3,RM+1);
ArrayResize(Volum,RM+1);
ArrayResize(Timf,RM+1);
Timf[0]= gi_220;
Price[0]=gd_164;
if (ShowWicks && gd_140 else Price1[0]=gd_148;
Price2[0]= gd_156;
Price3[0]=gd_172;
Volum[0]= gd_180;
}
if(RM==1){
Timf[0]= gi_220;
Price[0]=gd_164;
if (ShowWicks && gd_140 else Price1[0]=gd_148;
Price2[0]= gd_156;
Price3[0]=gd_172;
Volum[0]= gd_180;
}
gd_132 = 0;
gd_140 = EMPTY_VALUE;
gd_180 = 0;
gd_196 = gd_156;
gd_188 = gd_156;
if (gi_220 else gi_220++;
}
while (!li_20 && Low[li_16] gd_156 -= gd_124;
gd_148 -= gd_124;
gd_164 = gd_156;
gd_172 = gd_148;
RM=ArraySize(Price);
if(RM>1){
ArrayResize(Price, RM+1);
ArrayResize(Price1,RM+1);
ArrayResize(Price2,RM+1);
ArrayResize(Price3,RM+1);
ArrayResize(Volum,RM+1);
ArrayResize(Timf,RM+1);
Timf[0]= gi_220;
Price[0]=gd_164;
Price1[0]= gd_148;
if (ShowWicks && gd_132 > gd_156) Price2[0]= gd_132;
else Price2[0]= gd_156;
Price3[0]= gd_172;
Volum[0]= gd_180;
}
if(RM==1){
Timf[0]= gi_220;
Price[0]=gd_164;
Price1[0]= gd_148;
if (ShowWicks && gd_132 > gd_156) Price2[0]= gd_132;
else Price2[0]= gd_156;
Price3[0]= gd_172;
Volum[0]= gd_180;
}
gd_132 = 0;
gd_140 = EMPTY_VALUE;
gd_180 = 0;
gd_196 = gd_148;
gd_188 = gd_148;
if (gi_220 else gi_220++;
}
}
if (Close[0] > MathMax(gd_172, gd_164)) gd_204 = MathMax(gd_172, gd_164);
else {
if (Close[0] else gd_204 = Close[0];
}
gd_212 = Close[0];
if (gd_132 > gd_156) gd_196 = gd_132;
if (gd_140 RM=ArraySize(Price);
if(RM>1){
ArrayResize(Price, RM+1);
ArrayResize(Price1,RM+1);
ArrayResize(Price2,RM+1);
ArrayResize(Price3,RM+1);
ArrayResize(Volum,RM+1);
ArrayResize(Timf,RM+1);

Timf[0]= gi_220;
Price[0]= gd_204;
Price1[0]= gd_188;
Price2[0]= gd_196;
Price3[0]= gd_212;
Volum[0]= gd_180;
}
if(RM==1){
Timf[0]= gi_220;
Price[0]= gd_204;
Price1[0]= gd_188;
Price2[0]= gd_196;
Price3[0]= gd_212;
Volum[0]= gd_180;
}


gd_132 = MathMax(gd_132, Bid);
gd_140 = MathMin(gd_140, Bid);
gd_180++;
if (Bid > gd_156 + gd_124 || CompareDoubles(Bid, gd_156 + gd_124)) {
RM=ArraySize(Price);
ArrayResize(Price, RM+1);
ArrayResize(Price1,RM+1);
ArrayResize(Price2,RM+1);
ArrayResize(Price3,RM+1);
ArrayResize(Volum,RM+1);
ArrayResize(Timf,RM+1);

gd_156 += gd_124;
gd_148 += gd_124;
gd_164 = gd_148;
gd_172 = gd_156;
Timf[0]= gi_220;
Price[0]= gd_164;
if (ShowWicks && gd_140 else Price1[0]=gd_148;
Price2[0]= gd_156 ;
Price3[0]= gd_172 ;
Volum[0]= gd_180;
if (gi_220 else gi_220++;
gd_180 = 0;
gd_196 = gd_156;
gd_188 = gd_156;
gd_132 = 0;
gd_140 = EMPTY_VALUE;
} else {
if (Bid RM=ArraySize(Price);
ArrayResize(Price, RM+1);
ArrayResize(Price1,RM+1);
ArrayResize(Price2,RM+1);
ArrayResize(Price3,RM+1);
ArrayResize(Volum,RM+1);
ArrayResize(Timf,RM+1);
gd_156 -= gd_124;
gd_148 -= gd_124;
gd_164 = gd_156;
gd_172 = gd_148;
Timf[0]= gi_220;
Price[0]= gd_164 ;
Price1[0]= gd_148;
if (ShowWicks && gd_132 > gd_156) Price2[0]= gd_132 ;
else Price2[0]=gd_156;
Price3[0]= gd_172;
Volum[0]=gd_180;
if (gi_220 else gi_220++;
gd_180 = 0;
gd_196 = gd_148;
gd_188 = gd_148;
gd_132 = 0;
gd_140 = EMPTY_VALUE;
} else {
if (Bid > gd_196) gd_196 = Bid;
if (Bid if (gd_156 else {
if (gd_148 >= Bid) gd_204 = gd_148;
else gd_204 = Bid;
}
gd_212 = Bid;
RM=ArraySize(Price);
ArrayResize(Price, RM+1);
ArrayResize(Price1,RM+1);
ArrayResize(Price2,RM+1);
ArrayResize(Price3,RM+1);
ArrayResize(Volum,RM+1);
ArrayResize(Timf,RM+1);
Timf[0]= gi_220;
Price[0]= gd_204;
Price1[0]= gd_188;
Price2[0]= gd_196;
Price3[0]=gd_212;
Volum[0]= gd_180;

}
}
return (0);
}


Так же я решил отказаться от двух индикаторов. Первый индикатор влияющий на качественность сигнала, я кстати не думал что именно от него придется отказаться - это FR-Trend. В его расчетах да и вы наверное видели что он западает в голубой зоне на длительные промежутки... месяцами может просидеть.. Это влияет на количество сделок в общем. Следующий индикатор - это FR-Scanner. Он в своих расчетах использует три самых последних бара и дает сигнал верный только через три бара, а это в ренко кирпичиках целых 30 пунктов...

Далее для ускорения работы эксперта, я перенес все функции в файл библиотеки и вызвал из нее функции которые мне требуются.



#property copyright "Copyright 2013, MetaQuotes Software Corp."
#property link "http://www.metaquotes.net"
#include
//#include
#import "indiSignals.ex4"
int ArrayRenko(double &Price[],double &Price1[],double &Price2[],double &Price3[],int &Timf[],int BrickSize);
int SignalFRTL (double Lowf[],double Highf[], int Shift);
int SignalFRSls (double &SignalBay[],double &SignalSell[],double Lowf[], double Highf[],double Closef[]);
#import

int BrickSize = 10;

...........
...........
...........



Думаю применить расчет Heiken Ashi...

На сегодня самое трудное для меня это разработка логики окрытия, сопровождение и закрытие ордеров. Система поиска и систима модификации. Да, функция открытия позиций написана, в ней реализован уровень безубытка, сейчас работаю над системой трала профита, также разрабатывается система запоминания своих позиций, некий стакан параметров ордеров. В общем с поступлением успешно завершенных функций они будут описаны здесь же...

А пока посмотрите первые сделки в тестере...

Спойлер



StrategyTester.zip

Ссылка на сообщение
Поделиться на другие сайты

Советник с ручной стратегии \"Форекс Драйвер… Опубликовано

завтра потестирую :) Скажи, сова кидать на обычный график или запустить сначала скрипт для ренко?

Ссылка на сообщение
Поделиться на другие сайты

Советник с ручной стратегии \"Форекс Драйвер… Опубликовано


завтра потестирую :) Скажи, сова кидать на обычный график или запустить сначала скрипт для ренко?



На сегодня test.mq4 не актуален ... Со времени когда его выложил прошли некоторые модификации функций. Я чуть позже расскажу о них. Сейчас полноценный советник с входом в рынок. сопровождением и выходом тестируется на предмет багов в различных ситуациях. Также его немного разукрасил цветными линиями SL, TP и трала...

Изначально планировалось и реализовано, что советник кидается непосредственно на график пары без создания графиков ренкои применения различных скриптов.
Ссылка на сообщение
Поделиться на другие сайты

Советник с ручной стратегии \"Форекс Драйвер… Опубликовано

В общем то что у меня получилось вы моглибы протестировать сами... Бот во вложении...

Что добавил:

Ну во первых как я сказал я убрал со стратегии два индикатора. Заменил их функцией индикатора Heiken Ashi. Смысл индикатора прост, он усредняет скользящую среднюю каждой из 4 цен. В принципе код не сложный:


double maOpen, maClose, maLow, maHigh;
double haOpen, haHigh, haLow, haClose;
if(Bars ExtCountedBars=IndicatorCounted();
//---- check for possible errors
if (ExtCountedBars//---- last counted bar will be recounted
if (ExtCountedBars>0) ExtCountedBars--;
int pos=Bars-ExtCountedBars-1;
while(pos>=0)
{
maOpen=iMA(NULL,0,MaPeriod,0,MaMetod,MODE_OPEN,pos);
maClose=iMA(NULL,0,MaPeriod,0,MaMetod,MODE_CLOSE,pos);
maLow=iMA(NULL,0,MaPeriod,0,MaMetod,MODE_LOW,pos);
maHigh=iMA(NULL,0,MaPeriod,0,MaMetod,MODE_HIGH,pos);

haOpen=(ExtMapBuffer5[pos+1]+ExtMapBuffer6[pos+1])/2;
haClose=(maOpen+maHigh+maLow+maClose)/4;
haHigh=MathMax(maHigh, MathMax(haOpen, haClose));
haLow=MathMin(maLow, MathMin(haOpen, haClose));

if (haOpen {
trend[pos]=1;
ExtMapBuffer7[pos]=haLow;
ExtMapBuffer8[pos]=haHigh;
if (SoundAlertMode>0 && pos==0 && trend[1] }
else
{
trend[pos]=-1;
ExtMapBuffer7[pos]=haHigh;
ExtMapBuffer8[pos]=haLow;
if (SoundAlertMode>0 && pos==0 && trend[1]>0) PlaySound("alert2.wav");
}
ExtMapBuffer5[pos]=haOpen;
ExtMapBuffer6[pos]=haClose;

pos--;
}

int i;
for(i=0; i=iMAOnArray(ExtMapBuffer7,Bars,MaPeriod2,0,MaMetod2,i);
for(i=0; i=iMAOnArray(ExtMapBuffer8,Bars,MaPeriod2,0,MaMetod2,i);
for(i=0; i=iMAOnArray(ExtMapBuffer5,Bars,MaPeriod2,0,MaMetod2,i);
for(i=0; i=iMAOnArray(ExtMapBuffer6,Bars,MaPeriod2,0,MaMetod2,i);


Здесь мы передадим в функцию наши архивы графика ренко и заменим iMA() на iMaOnArray() передав ту или иную цену бара.

Функция SignalHAS:


int SignalHAS(double Closef[],double Lowf[],double Highf[],double Openf[])
{
int MaMetod = 0;
int MaPeriod = 1;
int MaMetod2 = 3;
int MaPeriod2 = 2;
int SoundAlertMode = 0;
//---- buffers
double ExtMapBuffer1[];
double ExtMapBuffer2[];
double ExtMapBuffer3[];
double ExtMapBuffer4[];
double ExtMapBuffer5[];
double ExtMapBuffer6[];
double ExtMapBuffer7[];
double ExtMapBuffer8[];
double trend[];
int Bar=ArraySize(Openf);
if(ArraySize(ExtMapBuffer1){
ArraySetAsSeries(ExtMapBuffer1, false);
ArraySetAsSeries(ExtMapBuffer2, false);
ArraySetAsSeries(ExtMapBuffer3, false);
ArraySetAsSeries(ExtMapBuffer4, false);
ArraySetAsSeries(ExtMapBuffer5, false);
ArraySetAsSeries(ExtMapBuffer6, false);
ArraySetAsSeries(ExtMapBuffer7, false);
ArraySetAsSeries(ExtMapBuffer8, false);
ArraySetAsSeries(trend, false);

ArrayResize(ExtMapBuffer1, Bar);
ArrayResize(ExtMapBuffer2,Bar);
ArrayResize(ExtMapBuffer3, Bar);
ArrayResize(ExtMapBuffer4,Bar);
ArrayResize(ExtMapBuffer5, Bar);
ArrayResize(ExtMapBuffer6,Bar);
ArrayResize(ExtMapBuffer7, Bar);
ArrayResize(ExtMapBuffer8,Bar);
ArrayResize(trend, Bar);

ArraySetAsSeries(ExtMapBuffer1, true);
ArraySetAsSeries(ExtMapBuffer2, true);
ArraySetAsSeries(ExtMapBuffer3, true);
ArraySetAsSeries(ExtMapBuffer4, true);
ArraySetAsSeries(ExtMapBuffer5, true);
ArraySetAsSeries(ExtMapBuffer6, true);
ArraySetAsSeries(ExtMapBuffer7, true);
ArraySetAsSeries(ExtMapBuffer8, true);
ArraySetAsSeries(trend, true);
}
double maOpen, maClose, maLow, maHigh;
double haOpen, haHigh, haLow, haClose;
int pos=Bar;
while(pos>=0)
{
maOpen=iMAOnArray(Openf,0,MaPeriod,0,MaMetod,pos);
maClose=iMAOnArray(Closef,0,MaPeriod,0,MaMetod,pos);
maLow=iMAOnArray(Lowf,0,MaPeriod,0,MaMetod,pos);
maHigh=iMAOnArray(Highf,0,MaPeriod,0,MaMetod,pos);

haOpen=(ExtMapBuffer5[pos+1]+ExtMapBuffer6[pos+1])/2;
haClose=(maOpen+maHigh+maLow+maClose)/4;
haHigh=MathMax(maHigh, MathMax(haOpen, haClose));
haLow=MathMin(maLow, MathMin(haOpen, haClose));

if (haOpen {
trend[pos]=1;
ExtMapBuffer7[pos]=haLow;
ExtMapBuffer8[pos]=haHigh;
if (SoundAlertMode>0 && pos==0 && trend[1] }
else
{
trend[pos]=-1;
ExtMapBuffer7[pos]=haHigh;
ExtMapBuffer8[pos]=haLow;
if (SoundAlertMode>0 && pos==0 && trend[1]>0) PlaySound("alert2.wav");
}
ExtMapBuffer5[pos]=haOpen;
ExtMapBuffer6[pos]=haClose;

pos--;
}


int i;
for(i=0; i=iMAOnArray(ExtMapBuffer7,Bar,MaPeriod2,0,MaMetod2,i);
for(i=0; i=iMAOnArray(ExtMapBuffer8,Bar,MaPeriod2,0,MaMetod2,i);
for(i=0; i=iMAOnArray(ExtMapBuffer5,Bar,MaPeriod2,0,MaMetod2,i);
for(i=0; i=iMAOnArray(ExtMapBuffer6,Bar,MaPeriod2,0,MaMetod2,i);

if ( trend[2]0 )
{
return(1);
}

if ( trend[2]>0 && trend[1] {
return(2);
}

//----
return(0);
}


Теперь подробней про логику открытия позиций:

Параметры:
StopOrder - в пунктах целым числом. Расстояние от цены закрытия бара для открытия ордера stop
FLots - лот торговли первого ордера.
SLots - лот второго ордера.
StopLoss - в пунктах, указывается целое число. Работает ни как стандартный стоплос.
Tral - в пунктах целым числом. Позиция включения трала.
Shag- в пунктах целым числом. Дистанция трала от цены закрытия бара.

И так. Как функции дали сигнал на покупку/продажу мы открылись отложенным ордером. Линия стоп лоса будет обозначена оранжевокрасным цветом. Но в отличии от настоящего стоп лоса закрывающего позицию, это расстояние используется для того чтобы отвязать ордер от повторения сигнала в сторону открытия. Наверное вы знаете, если программируете, что порой необходим запрет на открытие повторной позиции по сигналу. Так вот эта черта снимает этот запрет. С точки зрения отложенного ордера позволяет долится на откате, с точки зрения сработанного отложенного ордера работает как усреднение просадки. У меня второй ордер открывался с лотом втрое больше чем первый. ну а с тралом все понятно, как только цена пересекает зеленую линию устанавливается скрытый от брокера стоп лосс обозначенный на графике красной линией. Как только цена ниже красной линии ордер закроется.... Так же ордера закроются при противоположном сигнале.

Прошу бэк тест за год выложите пожалуйста, а то у меня атом на ноутбуке совсем медленно тестирует... Изменено пользователем talliy
Ссылка на сообщение
Поделиться на другие сайты

Советник с ручной стратегии \"Форекс Драйвер… Опубликовано

Уважаемый talliy, простите, я не программист :( Подскажите пожалуйста как его тестировать, в обычном тестере он ничего не открывает, а как подключить в тестер ренко не знаю >:d

Ссылка на сообщение
Поделиться на другие сайты

Советник с ручной стратегии \"Форекс Драйвер… Опубликовано

В обычном тестере..... на любой таймфрейм и пару.. попробуй компельнуть у себя в метаедиторе


Добавлено: 18-08-2013 23:01:42

Так же не писал всяких проверок на разрешение загрузки библиотек и разрешение для работы советника, но вы имейте в виду что он использует библиотеки. Orders.ex4 и indiSignals.ex4 содержат в себе функции сигнала и управление ордерами...
У кого не идет в метаедиторе компелируйте сам бот... Изменено пользователем talliy
Ссылка на сообщение
Поделиться на другие сайты

Советник с ручной стратегии \"Форекс Драйвер… Опубликовано

Автор. вручную систему гонял? Просто как мне, неудобоваримо бу, столько труды- туды, если псу под хвост.

Изменено пользователем IR
Ссылка на сообщение
Поделиться на другие сайты

Советник с ручной стратегии \"Форекс Драйвер… Опубликовано


Автор. вручную систему гонял? Просто как мне, неудобоваримо бу, столько труды- туды, если псу под хвост.



Нет не гонял... Тестер в помощь...)))

А вам как? Выложи рабочую сову профитную?? На то и есть коррекция работы кода... ))) но факт в том что все компоненты системы сложены воедино и сейчас уже ну прям что хочешь с ней делай....

Ребят дайте бек тест за год... у меня атом не шевелится...

.... кому под хвост, кому увлекательная работа...

Добавлено: 19-08-2013 15:27:52

поставил с 1 января на ночь (у меня на Дальнем Востоке уже 2 ночи) по паре GBPUSD. Работает в два индикатора Heiken и FR-Signals. С утра результат выложу..

... и один черт тупняка ловил с этими линиями разноцветными, ну хоть трал видно как работает... Изменено пользователем talliy
Ссылка на сообщение
Поделиться на другие сайты

Советник с ручной стратегии \"Форекс Драйвер… Опубликовано



Автор. вручную систему гонял? Просто как мне, неудобоваримо бу, столько труды- туды, если псу под хвост.



Нет не гонял... Тестер в помощь...)))


Тестр ни о чем, зачем он в мт4 , я хз, результаты в тестере и торговле сильно различны как правило.

100% буит коту под хвост, без обид, потом сами к этому придете и даст бог вспомните мои слова))
Ссылка на сообщение
Поделиться на другие сайты

Советник с ручной стратегии \"Форекс Драйвер… Опубликовано
IR, честно, ни хрена не понятно что ты пишешь...
Ты хочешь сказать, что исходная ручная ТС не прибыльная и, поэтому, не стоило ее кодировать?

А так talliy, как по мне, весьма интересную и вообще полезную работу проделал и таки стоит попытаться упереться и довести бота до корректной работы и профита.
Ссылка на сообщение
Поделиться на другие сайты

Советник с ручной стратегии \"Форекс Драйвер… Опубликовано

Загнал его в тестер, по прежнему ничего не открывает и дико подгружает комп(cori5-2.1Ггц) Все раскидал по папкам как у автора. Не пойму что не так? Система повторюсь очень хорошая, довести ее до ума будет очень не плохо..

Ссылка на сообщение
Поделиться на другие сайты

Советник с ручной стратегии \"Форекс Драйвер… Опубликовано


IR, честно, ни хрена не понятно что ты пишешь...
Ты хочешь сказать, что исходная ручная ТС не прибыльная и, поэтому, не стоило ее кодировать?

А так talliy, как по мне, весьма интересную и вообще полезную работу проделал и таки стоит попытаться упереться и довести бота до корректной работы и профита.


Пишу то что:
Результаты в тестере могут и будут очень отличаться от реальной торговли, не в лучшую сторону. Поэтому тестер брать во внимание не стОит.
Так понятно?

Как -то торговал по этой тс ручками на демке. Результаты не очень, без обид. В лучшем случае в ноль или небольшой плюс.
Просто поставить в известность автора, потому что автор по ней не торговал.
Если автомат будет показывать лучшие результаты, чем руки тогда конечно, работа полезная. ) Изменено пользователем IR
Ссылка на сообщение
Поделиться на другие сайты

Советник с ручной стратегии \"Форекс Драйвер… Опубликовано


.....
Если автомат будет показывать лучшие результаты, чем руки тогда конечно, работа полезная. )



Тема создана не для написание одним автором прибыльного бота форуму... Я и говорю что большинству трейдеров главное прибыль и оценка автора идет с этой точки зрения. Здесь же я пытаюсь вести работу, так сказать, "в слух", дабы начинающие программисты понимали как это можно делать. Mql язык логики, а логику можно составить по разному. Мое виденье одно, другого другое, а вот реализация и трудности при переносе логики это много стоит, а уж и если в прибыль, то в большинстве случаев это стечение обстоятельств, т.к. программисты любители в основном работают в одиночку и для решения порой глобальных вопросов требуется команда. Так о чем мы говорим???
Ссылка на сообщение
Поделиться на другие сайты

Советник с ручной стратегии \"Форекс Драйвер… Опубликовано

Talliy, здравствуйте, вы еще работаете над советником? Рабочего варианта пока нет? :) Очень ждем..

Ссылка на сообщение
Поделиться на другие сайты

Советник с ручной стратегии \"Форекс Драйвер… Опубликовано


....Рабочего варианта пока нет?....



Они в принципе все рабочие. Убрал вход первого отложенного ордера. Сразу в рынок. Результаты улучшились... Доработаю линии тралов и выложу.

P.S. Я тут с командировки вернулся, любимая заждалась, так что пока не до бота)))
Ссылка на сообщение
Поделиться на другие сайты

Для публикации сообщений создайте учётную запись или авторизуйтесь

Вы должны быть пользователем, чтобы оставить комментарий

Создать учетную запись

Зарегистрируйте новую учётную запись в нашем сообществе. Это очень просто!

Регистрация нового пользователя

Войти

Уже есть аккаунт? Войти в систему.

Войти
×
×
  • Создать...