Различия

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

Ссылка на это сравнение

Следующая версия
Предыдущая версия
codeless:concept_dataframe [2019/03/09 14:48]
nektomk создано
codeless:concept_dataframe [2019/03/10 14:11]
nektomk
Строка 1: Строка 1:
 ====== Концепция DataFrame ====== ====== Концепция DataFrame ======
  
-Пользователю привычно ​представление данных в виде таблиц. Советник будет следовать ​этим привычкам конечных пользователей и предоставлять механизм для такой организации данных с элементами электронной таблицы. ​+Продолжаем делать советник. Для того чтобы пореже порождать множественные иерерархии и не обобщать многократно обобщённое,​ воспользуемся кладезью возможностей ООП и сделаем ​предстваление данных. Есть такая штука как "​табличная модель данных",​ хорошо знакомая всем например по Excel - вот её-то и реализуем. Первоначально чтобы пользователю было просто описывать исходные данные и их взаимоотношения,​ а далее задействем это по максимуму. 
 + 
 +Даже по начальному use-case прям-таки хочется сделать а-ля большой ​индикатор с несколькими буферами, ​в виде двумерного массива у которого колонки - таймсерии,​ а по строкам бары. А в отдельных ячейках double. Так программистам MQL привычно,​ и можно использовать обычные математические функции и всякие CopyArray без ограничений. 
 + 
 +Так и сделаем :-) 
 + 
 +Реализуем класс [[DataFrame]] у которого внутри массив из таймсерий [[DataSeries]] у которых внутри массив double. (как дом-который-построил-джек, но с ограниченными вложениями и без рекурсии). 
 + 
 +Немного забегая - не всё так просто :-) всё-же MQL он ни разу не C++ и массивы у него не first-class и есть куча ограничений по перегрузке и приведению типов. Придётся выкручиваться, чтобы пользователь получил более-менее ​привычный интерфейс. 
 +--- 
 +в принципе мы выкрутились - изначальный use-case работает и даже торгует :-) Но с кучей ​ограничений: сейчас внутри советника нет ничего кроме интерфейса с исходными данными,​ остальное это много-много заглушек и прямые/​неправильные вызовы. Это надо развивать далее. 
 + 
 +Итог, как говорится "​вот он" - сделки открываются/​закрываются,​ всё работает. 
 + 
 + 
 +Баланс конечно валится вниз :-) Ну а что вы хотели от "пересечения ​двух МА" :-) 
 + 
 +<WRAP center round download 60%> 
 +Исходники можно скачать тут https://​chiselapp.com/​user/​nektomk/​repository/​CodeLess/​home 
 + 
 +правда сам репозиторий ещё не оформлен всякими README :-) 
 +</​WRAP>​ 
 + 
 +**не ​теряя совместимости**,​по ​ходу реализации предложен фикс исходного use-case позволяющий проводить более сложные вычисления над данными и отчасти демонстирующий функционирование DataFrame. А именно ​изменить последний в функции ​пользователя,​ чтобы предоставить доступ сразу ко всему фрейму ​данных
 + 
 +//(для компактности - в copy-past удалены лишние комментарии и код MQL5)// 
 +<code c> 
 + 
 +enum ENUM_SERIES { 
 +   ​FAST_MA, ​      // id. значений FAST_MA 
 +   ​SLOW_MA, ​      // id. значений SLOW_MA  
 +   // для примера - добавим пару вычислимых полей 
 +   ​SIGNAL_BUY, ​   // сигнал к покупкам 
 +   ​SIGNAL_SELL, ​  // сигнал к продажам 
 + 
 +   ​TOTAL_SERIES ​  // последний ​элемент перечисления = кол-во элементов 
 +}; 
 + 
 +// в функцию пользователя добавим параметр table для доступа ко всем данным 
 +double GetData(EA *ea,int id,int shift,​double &​data[],​DataFrame *table) 
 +
 +   ​switch ((ENUM_SERIES)id) { 
 +      case FAST_MA: 
 +         ​return table[FAST_MA][shift]=iMA(ea.Symbol,​ea.Period,​FAST_MA_PERIOD,​0,​FAST_MA_METHOD,​FAST_MA_PRICE,​shift);​ 
 +      case SLOW_MA: 
 +         ​return table[SLOW_MA][shift]=iMA(ea.Symbol,​ea.Period,​SLOW_MA_PERIOD,​0,​SLOW_MA_METHOD,​SLOW_MA_PRICE,​shift);​ 
 +      /* пример вычисления зависимых данных. 
 +         обратите внимание:​ пользователь не заботится о последовательности вычислений, а просто декларирует "​формулы"​ 
 +      */ 
 +      case SIGNAL_BUY:​ 
 +         ​return table[SIGNAL_BUY][shift]=table.CrossedUp(FAST_MA,​SLOW_MA,​shift);​ 
 +      break; 
 +      case SIGNAL_SELL:​ 
 +         ​return table[SIGNAL_SELL][shift]=table.CrossedDn(FAST_MA,​SLOW_MA,​shift);​ 
 +      break; 
 +   } 
 +   ​return EMPTY_VALUE;​ 
 +
 +// в функцию генерации сигнала также добавлен параметр - таблица 
 +// можно использовать любый её данные 
 +int SignalOfCross(EA *ea,int shift,​DataFrame *data) 
 +
 +   if (FAST_MA_PRICE!=PRICE_OPEN || SLOW_MA_PRICE!=PRICE_OPEN) shift++; 
 +   if (table[SIGNAL_BUY][shift]==1.0) ​ return OP_BUY; 
 +   if (table[SIGNAL_SELL][shift]==1.0) return OP_SELL; 
 +   ​return -1; 
 +
 +</​code>​ 
 +//(всё прочее остаётся без изменений)//​ 
 + 
 +Всё работает,​ так-же как и первоначальный use-case. Одинаково 
 + 
 + 
 + 
 + 
  
-Пользователь будет работать с данными как с таблицами,​ а советник уже сам переведёт это в свои внутренние структуры. И наоборот - при необходимости советник заполняет элементы таблиц,​ а пользователь их читает. ​ 
  
-Для этого сделан [[DataFrame|класс DataFrame]]. Фактически класс представляет собой двумерный массив из double, организованный по колонкам. Колонки в свою очередь - это серии данных. И во многом DataFrame похож на комплексный индикатор с несколькими буферами. ​