Начинающим, да и не только, программистам привет!
Хочу создать тему разработки, автоматизации, ручной стратегии "Форекс Драйвер". Познакомился с ней не давно, использует графики построения свечей ренко. В блоге - 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);
}
Таким образом мы перенесли первый индикатор системы в функции...

