Структура рулит. Учимся структурировать программы, изучаем возможности, ошибки, решения и т.п. - страница 6

 
FAQ:

ЗЫ. А вооще меленко как то, давайте задачку поглобальнее ? 

Есть конкретное предложение?
 
MetaDriver:

Ну тады колись (в общих чертах)  как ты эти бреши затыкаешь в четвёрке.  Всё в DLL-ках?  :)

  Никаких ДЛЛ, чистый МКЛ + винапи для обработки событий.

 По поводу этого, надо найти время все красиво описать и сделать большую статью. Могу кинуть или пример, или реализацию псевдоклассов визуала для МТ4, но боюсь без подробного описания будет тяжело переварить. Суть создание DOM (Data Object Module) для МТ по аналогии с JS - они и так реально похожи. Для затравки - основная функция сердце так сказать:

 

//+------------------------------------------------------------------+
//| Brief Description included Functions                             |
/*+----exported function---------------------------------------------+
bool   ObjSet(ObjNm,ObjTyp,isets[],tsets[],{ObjParent})Устанавливает на график объект класса Interface.
void   ObjDelete(string nm,bool delChild=true) Удаляет объект с графика, вместе , или без первого потомка
void   ObjsDelete(string nm) Удаляет объект, вместе со всеми его потомками
double ObjGet(string nm, int prop_id) Ищет объект и возвращает значение его свойства
bool   ObjSearch(string ObjNm):int[];string; Возвращает признак наличия объекта класса Interface
int    This(int prop_id) Ищет значение свойства объекта в списке свойств : obj_props[10]
//+----internal function---------------------------------------------+
string ObjGetName(string,int[],{string})  Собирает полное имя объекта класса Interface
void   ObjSetLabel()Обертка для стандартной функции
*///+----------------------------------------------------------------+
//|                                      OBJECTS_INTERFACE_CLASS.mq4 |
//|           Copyright © 2012, XrustSolution. mail:xrustx@gmail.com |
//|          https://www.youtube.com/user/opmlv http://forexrust.info |
//+------------------------------------------------------------------+
#property copyright "Copyright © 2012, XrustSolution."
#property link      "mail: xrustx@gmail.com https://www.youtube.com/user/opmlv http://forexrust.info"
//+------------------------------------------------------------------+
//|   Extern variables                                               |
//+------------------------------------------------------------------+
extern   string   ObjectsInterfaceSettings = "-------- ObjectsInterfaceSettings ----------";
extern   int      X_Distance                                = 2      ;
extern   int      Y_Distance                                = 2      ;
extern   int      ChartCorner                               = 0      ;

//+------------------------------------------------------------------+
//|   Defines                                                        |
//+------------------------------------------------------------------+
#define GlobalPrefix    "wnd:"   // Префикс имени класса
#define GlobalParent    "chart"  // Имя глобального родителя
#define hName           "Header" // Имя главного родителя (заголовка)
#define wName           "Window" // Имя главного окна
#define cName           ""       // Стандартное имя текущего объекта
#define tName           "Txt"  // Стандартное имя для текстовой строки
#define Objects 500              // Максимальное количество командных объектов
//+------------------------------------------------------------------+
//|   Global variables                                               |
//+------------------------------------------------------------------+
string ObjParent = "";           // Глобальное имя родителя Object Parent Name
string ObjName   = "";           // Глобальное имя объекта  Object Own Name
int    obj_props[10];            // Набор свойств объекта : {xdLeft,ydUp,xdRight,ydDown,zIndex,Class,Corner,Color,Window};
//+------------------------------------------------------------------+
string  ObjsParent[Objects];     // Список имен родителей командных объектов
string  ObjsNames[Objects];      // Список имен командных объектов
int     CommObjs[Objects][6];    // Список параматров командных объектов = {класс,угол,х0,у0,х1,у1}
string  ObjsDom[Objects][2];     // Список всех объектов и их дочерних элементов (объектов) ObjsDom[Parent][Childrens]
string  ObjsDel[5000];           // Список старых объектов для удаления при перемещении окон  
string  ObjsName[5000];      // Список полных имен объектов
//+------------------------------------------------------------------+
//|   Defines                                                        |
//+-----ObjectsTypes-------------------------------------------------+
#define         OBJ_CANVAS      30      // Холст\Окно\Прямоугольник (Основной элемент)
//+---Предопределенные типы окон-------------------------------------+
#define         OBJ_WINDOW     31 // Пустое окно
#define         OBJ_TXTWND     32 // Текстовое окно с форматированием текста
#define         OBJ_HTMWND     33 // Текстовое окно с форматированием, активными ссылками
#define         OBJ_CHARTW     34 // Псевдографическое окно с возможностями граф построений
//#define       OBJ_LEDWND     34 // 

//+---Кнопки командные-----------------------------------------------+ 
#define  OBJ_BUTTON     40 // Кнопка (пустая) общего назначения
//----Кнопки предопределенные(Команда)
#define  OBJ_BUTBUY     41 // OP_BUY
#define  OBJ_BUTSEL     42 // OP_SELL
#define  OBJ_BUTCLO     43 // ORDER_CLOSE
#define  OBJ_BUTREV     44 // ORDER_REVERSE
#define  OBJ_BUTBST     45 // OP_BUYSTOP
#define  OBJ_BUTBLM     46 // OP_BUYLIMIT
#define  OBJ_BUTSST     47 // OP_SELLSTOP
#define  OBJ_BUTSLM     48 // OP_SELLLIMIT
#define  OBJ_BUTDEL     49 // ORDER_DELETE
//+---Ярлыки командные (кнопки 1х1 с значком)------------------------+
#define  OBJ_LABCNT     50 // Командный ярлык (Контрол) Без обкладки в виде канваса 1х1 наследие двигательного аппарата команд
#define  OBJ_LABCOM     51 // Командный ярлык кнопка 1х1 с канвасом (пустой) 
//----Ярлыки предопределенные(Команда)
         /*----Группа ярлыков кнопок находящихся в заголовке (верхнем меню)---*/
#define  OBJ_LABCLO     52 // Ярлык/Кн.закрыть
#define  OBJ_LABHID     53 // Ярлык/Кн.Свернуть
#define  OBJ_LABSHW     54 // Ярлык/Кн.развернуть
#define  OBJ_LABSET     55 // Ярлык/Кн.Настройки
         /*----Двухцветные ярлычки (триггеры(серый\зеленый))----*/
#define  OBJ_LABALR     56 // Ярлык/Кн.Алерт
#define  OBJ_LABSND     57 // Ярлык/Кн.Звук
#define  OBJ_LABEML     58 // Ярлык/Кн.Мыло
#define  OBJ_LABSEL     59 // Ярлык/Кн.Select\Unselect
         /*----Группа ярлыков стрелок и др предустановленных спец символов---*/
#define  OBJ_LABLFT     60 // Ярлык/Стрелка Влево
#define  OBJ_LABRGT     61 // Ярлык/Стрелка Вправо
#define  OBJ_LABUP      62 // Ярлык/Стрелка Вверх
#define  OBJ_LABDWN     63 // Ярлык/Стрелка Вниз
     
#define  OBJ_LAB_TXT    69 // Текстовая строка / значек в ярлыке
//+----Хидеры(заголовки)-Основной родительский объект, наследует все остальные+
#define  OBJ_HD         70 // Пустой хидер (прямоугольник 1 размера блока)
#define  OBJ_HDC        71 // + Кнока закрытия
#define  OBJ_HDH        72 // + Кнопка свернуть\развернуть
#define  OBJ_HDCH       73 // + закрыть + развернуть
#define  OBJ_HDCHT      74 // + закрыть + развернуть + настройки
#define  OBJ_HDСHTS     75 // + закрыть + развернуть + настройки + системное меню алертов
//+-----ObjectProperties---------------------------------------------+
#define  OBJ_PRP_X0         17  // левая координата (Х0)
#define  OBJ_PRP_Y0         18  // верхняя координата (Y0)
#define  OBJ_PRP_X1         19  // правая координата (Х0) 
#define  OBJ_PRP_Y1         20  // нижняя координата (Х0)
#define  OBJ_PRP_ZI         21  // Зет Индекс
#define  OBJ_PRP_CLS        22  // Класс Объекта
#define  OBJ_PRP_CRN        23  // Угол привязки объекта
#define  OBJ_PRP_CLR        24  // Цвет
#define  OBJ_PRP_WND        25  // Окно в котором объект находиться
#define  OBJ_PRP_LAY        26  // Резерв (здесь будет количество слоев, для более точного определения параметров элементов)
//+-----Массив аргументов для функции GetObjectName()----------------+
int     Props[10];                                                      
//              Props[0] = Лево         
//              Props[1] = Верх 
//              Props[2] = Право        
//              Props[3] = Низ  
//              Props[4] = Счетчик по Х 
//              Props[5] = Счетчик по У 
//              Props[6] = Зет индекс (основной)        
//              Props[7] = Зет индекс (дополнительный для объектов из нескольких слоев) 
//              Props[8] = Идентификатор зет индекса последнего (верхнего) слоя в объекте
//              Props[9] = Идентификатор типа объекта                                           
//+---Массивы с корректыми размерами шрифтв Webdings для >= 416 билда---------------+
int realSz[21] = {15,23,31,35,43,47,55,67,75,83,87,91,95,99,119,123,127,143,148,156,164};// Таблица реальных размеров
int fontSz[21]  = {11,17,23,26,32,35,41,50,56,62,65,68,71,74, 89, 92, 95,107,110,116,122};// Таблица корректных шрифтов
int szCorr[21] = { 4, 5, 6, 7, 9,10,12,15,17,19,20,21,22,23, 28, 29, 30, 34, 36, 38, 40};// Разница между размером шрифта, и реальным размером
int vertCr[21] = {-3,-2,-1,-1,-2, 0,-1, 0, 0, 0, 0, 0, 0, 0,  0, -1,  0,  0,  0,  0,  0};// Таблица cмещения по вертикали от размера шрифта

//+------------------------------------------------------------------+
//|  Includes                                                        |
//+------------------------------------------------------------------+
#include <OBJ_CANVAS.mqh> //SetCanvas(onm,xd,yd,xs,ys,[sz,zindx,oClr,crn,wnd,pnm,bord,bClr]);
#include <OBJ_LAB_TEXT.mqh>//SetTextString(onm,pnm,typ,txt,fnm,clr,[center,xd,yd,psz,fsz,crn,wnd]):int:error;
//#include <OBJ_BUTTON.mqh>//SetButton(onm,pnm,type[,xd,yd,xs,ys,text,tx_fnt,txClr,sz,bgClr,bdClr,crn,wnd]);
#include <OBJ_HEADER.mqh>
#include <OBJ_LED_SIMPLE.mqh>
//+------------------------------------------------------------------+
//|           Function  : string GetObjectName(string,int[],{string})|
//|           Copyright © 2012, XrustSolution. mail:xrustx@gmail.com |
//|          https://www.youtube.com/user/opmlv http://forexrust.info |
//+------------------------------------------------------------------+
//|                     Собирает полное имя объекта класса Interface |
//+------------------------------------------------------------------+
//|Полное имя объекта должно состоять из :                           |
//|wnd:        = Основной префикс имени                         4 зн |
//|z_0ax:      = Z индекс для опр. порядка отображения окна 1-9 6 зн |10 зн
//|c_30:       = Тип объекта класса (смотреть в списке типов)   5 зн |15 зн
//|lu_xxx_yyy: = Координаты левого верхнего угла               10 зн |25 зн
//|rd_xxx_yyy: = Координаты правого нижнего угла               10 зн |35 зн
//|id_xxx_yyy: = Номера объектов                               10 зн |45 зн
//|#name|parent= Собственное имя обьекта из максимум 15 знаков,    до|60 зн
//|состоящее из имени элемента класса, и имени родительского объекта |
//+------------------------------------------------------------------+
//|Разделители:  типов свойств     = двоеточите(:),                  |
//|              значений свойств  = нижнее подчеркивание(_)         |
//|              имя объекта       = решетка(#)конец описания свойств|
//|              имя родителя      = слеш[|]                         |
//+------------------------------------------------------------------+
string    ObjGetName(string Name,                                   // Имя объекта
                                                        int      Props[],                                // Набор свойств объекта
                                                        string Parent = GlobalParent                   // Имя родителя, по умолчанию = "chart" , то есть основное окно графика
                                                        ){string out="";
//+------------------------------------------------------------------+
   if(Parent==""){Parent = "chart";}
   if(Props[9]!=OBJ_LAB_TXT){// если объект текстовая строка добавляем в описание имя шрифта
        out = StringConcatenate(GlobalPrefix,                                   //
                                                                        "z_" ,Props[6],StringSetChar("",0,Props[7]+97),StringSetChar("",0,Props[8]+97),":",
                                                                        "c_" ,Props[9],":",
                                                                        "lu_",Props[0],"_",Props[1],":",
                                                                        "rd_",Props[2],"_",Props[3],":",
                                                                        "id" ,Props[4],"" ,Props[5],":",
                                                                        "#"  ,Name    ,"|",Parent);
        }else{// работаем как обычно
        out = StringConcatenate(GlobalPrefix,                                   //
                                                                        "z_" ,Props[6],StringSetChar("",0,Props[7]+97),StringSetChar("",0,Props[8]+97),":",
                                                                        "c_" ,Props[9],":",
                                                                        "lu_",Props[0],"_",Props[1],":",
                                                                        "fn_font_name:",
                                                                        "id" ,Props[4],"" ,Props[5],":",
                                                                        "#"  ,Name    ,"|",Parent);
        }                                                               
        return(out);
}
MetaDriver:
Есть конкретное предложение?

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

 
C-4:
Сейчас ни один нормальный программист не рисует блок-схемы. Все это теоретический бред разработанный для преподавания школьникам, но не для работы в реальных проектах.
Это не бред. Это было необходимо, когда программы писали в машинных кодах. А потом их перетащили в учебники и они стали бредом, когда описывали программы на нормальных языках. А ещё был такая ЕСПД - единая система программной документации. И чтобы сдать программу заказчику её надо было оформить по очень жестким правилам. И блок схема должна была быть и всяческие описания.
 
FAQ:

  Никаких ДЛЛ, чистый МКЛ + винапи для обработки событий.

 По поводу этого, надо найти время все красиво описать и сделать большую статью. Могу кинуть или пример, или реализацию псевдоклассов визуала для МТ4, но боюсь без подробного описания будет тяжело переварить. Суть создание DOM (Data Object Module) для МТ по аналогии с JS - они и так реально похожи. Для затравки - основная функция сердце так сказать:

Да ушш..  С размахом. ))

DOM - это сильно.  Давай хоть пару скриншотов что-ли... Заценить как оно всё смотрится.  Или (если есть) какой-нибудь автономный скомпилированный примерчик, чтоб пощупать это дело в терминале. Есть такой? 

 
MetaDriver:

Да ушш..  С размахом. ))

DOM - это сильно.  Давай хоть пару скриншотов что-ли... Заценить как оно всё смотрится.  Или (если есть) какой-нибудь автономный скомпилированный примерчик, чтоб пощупать это дело в терминале. Есть такой? 

  посмотреть здесь : https://www.youtube.com/user/opmlv там вагон всего можно проследить как развивалось :) 
Rustamzhan Salidzhanov
Rustamzhan Salidzhanov
  • www.youtube.com
Краткая сборка софта созданного мной , для торговой платформы MetaTrader 4. Все имущественные права на данный софт принадлежат заказчикам, как правообладателям. И не могут быть переданы третим лицам без их (правообладателей) согласия. Я за собою оставляю авторское право как создатель данного софта. Quick assembly of software created by me for...
 
MetaDriver:

Поштурмуем задачку?

Нечего.

1. Панель сразу в хвост. стратегия первична, если она не будет пахать, панель бессмысленна и бесполезна.

2. Реализация торговой части зависит от стратегии, так что в рамках штурма гипотетической стратегии обсуждать нечего. Реализация стратегии как ни странно тоже зависит от стратегии :)

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

4. Панель. Ну что панель -- рутина.

 

Что касается написания ТС, то как-то так:

Форум по трейдингу, автоматическим торговым системам и тестированию торговых стратегий

Обсуждение высокочастотной торговли на МТ5

hrenfx, 2013.02.06 14:30


Простой и довольно эффективной логикой написания боевого робота является следующая схема:
- робот делится на две части: тестер и синхронизатор.
- тестер на основании ранней истории и только что пришедшей выдает текущее состоянии торговой стратегии.
- синхронизатор "переносит" текущие тестерные открытые позиции и приказы на реал.

Это чем-то напиминает копирование торговых сигналов с одного счета на другой. Только вместо примитивного копировщика работает грамотный синхронизатор.

К сожалению, правильную логику синхронизатора посмотреть где-либо практически невозможно, поэтому озадачевшемуся придется подумать самому - очень полезно.

Но и такая логика построения боевого-робота далеко не совершенна, т.к. встает дилема первичности курицы и яйца. Поэтому применяются более сложные свои схемы, основанные на опыте автора-алготрейдера.

Все эти действия совершаются только ради одного - адекватной настройки стратегии. Какой бы совершенной не была схема, все равно одинаковые боевые роботы на разных счетах одного и того же ECN/STP брокера покажут расхождения. И помимо поиска рыночных закономерностей, важной задачей для алготрейдера также является уменьшение этих расхождений. Как уже говорилось выше, чем ближе брокер к возможстям HFT, тем меньше расхождения.

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

 
TheXpert:

Нечего.

1. Панель сразу в хвост. стратегия первична, если она не будет пахать, панель бессмысленна и бесполезна.

2. Реализация торговой части зависит от стратегии, так что в рамках штурма гипотетической стратегии обсуждать нечего. Реализация стратегии как ни странно тоже зависит от стратегии :)

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

4. Панель. Ну что панель -- рутина.

Ну вот, сразу есть о чём поспорить... :))

Не поспорить, допустим, но указать на возможные варианты:

1. Панель сразу в хвост. стратегия первична, если она не будет пахать, панель бессмысленна и бесполезна.

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

2. Реализация торговой части зависит от стратегии, .......

А вот и не обязательно.  У меня так практически не зависит.  Вся торговая часть прописана в виде класса (CMarketDriver), который полностью реализует выставление ордеров, отслеживание позиций, реквоты и прочую хрень связанную с торговлей. По всем инструментам сразу. А стратегическая часть только подаёт ему на вход рекомендованные рыночные позиции по инструментам: т.е. заполняет массив структур формата {string Instrument; double Position} и запрашивает синхронизацию с сервером : MD.Synhronize(PositionArray).  И псё. Пока торгует только рыночными ордерами, но на подходе версия торгующая лимитниками выставляемыми внутрь спреда (для уменьшения торговых издержек). Для торговли тейкпрофиты/стоплоссы не использую, но MarketDriver может ставить защитные стопы на случай длительной потери связи с сервером (параметры стопов указываются один раз в настройках драйвера).   Кстати, очень удачное, практически беспроблемное структурное решение.  Для проверки стратегических идей в тестере вообще песня - никаких проблем с торговлей, всё внимание можно посвятить стратегии - вся торговля уже давно отлажена и инкапсулирована в торговом драйвере.

2............., так что в рамках штурма гипотетической стратегии обсуждать нечего. Реализация стратегии как ни странно тоже зависит от стратегии :)

Ну можно тут конкретизировать от балды, чисто щёб было что обсуждать.  Например свежая идея посетила -  можно торговать по пересечению пары машек.  Гениально, правда?  Задача в данном случае - так проструктурировать программу, чтоб при её развитии (ну например добавлении третьей машки), не пришлось менять большую часть кода. В идеале - совсем чуть-чуть и в строго локальной зоне (а не в десятке модулей).  Затем возможно развитие в сторону мультивалютности ( для простоты проекта, предположим что торговля по инструментам строго независимая, взаимосвязи тупо не учитываются).  Как, заранее предвидя такое развитие, организовывать стратегическую часть?

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

Здесь можно немножко пожевать.  Но и не обязательно.  В конце концов тут сложностей особо не предвидится.

4. Панель. Ну что панель -- рутина.

Не очень согласен.  Сама по себе панель, конечно, рутина.  А вот организация событийной связи стратегии с панелью - вполне себе творческая задачка, особенно если пытаться разработать более-менее универсальный шаблон для такой панели, предполагающий лёгкую адаптацию к разным советникам и лёгкое развитие при разрастании/развитии проекта.

 
MetaDriver:

А вот и не обязательно.  У меня так практически не зависит.

У меня почти всегда зависит. Тем более если с ECN работать. Ну т.е. все делается конечно не на самом низком уровне, но просто через оболочки стандартных торговых функций

Документация по MQL5: Торговые функции
Документация по MQL5: Торговые функции
  • www.mql5.com
Торговые функции - Документация по MQL5
 
 
TheXpert:

У меня почти всегда зависит. Тем более если с ECN работать. Ну т.е. все делается конечно не на самом низком уровне, но просто через оболочки стандартных торговых функций

Ну вот плохо это вроде как.  Не знаю как у меня там с ECN сложатся отношения (собираюсь открывать счёт на RoboForex), но буду всеми силами стремиться сохранить эту структурную развязку (стратегия/рыночный драйвер).  Она настолько  удобна, что готов даже на некоторые умеренные торговые издержки (типа недополученной прибыли). 

Смотри как просто в итоге выглядит главный цикл советника:

// Тестовый советник для тестирования обученных в GPU-оптимизаторе нейросеток (или записи значений котировок/индикаторов для отправки исходных данных в тот же оптимизатор).
void OnTick()
  {
   if(Mode==TradesMode) //-- Если режим тестирования
     {
      for(int i=0;i<CountInd;i++)
        {
         vInds[i]=GetInd(i,0);   // получаем значения индикаторов
        }
      Net.CalcResult(vInds);             // рассчитываем значение нейросетки
      float net_result=Net.NetResult[0];  // забираем рекомендованную рыночную позицию      
      SP.Pos=net_result*Lot;             // заполняем структуру для MarketDriver'a
      int err;
      MD.Synhronize(SP,err);             // синхронизируемся с торговым сервером.
     }
   else // Mode==RecordMode  // Если режим записи
..............
На вот глянь упрощённую тестерную версию, может понравится схема.  Если что - доработай под свои нужды и пользуйся на здоровье.
Файлы:
Причина обращения: