Не работает MarketInfo в тестере. - страница 3

 
4x4ever:

Тема старенькая, 4-летняя но я вчера столкнулся с этой же проблемой. Тоесть явно портфельное моделирование в тестере все еще не сделано? В связи с этим 2 вопроса:

1. Планов добавить это в ближайшем будущем есть? (MT4)

2. В MT5 ситуация такая же или там работает?

..имеется ввиду портфельная тоговля в тестере или хотя бы MarketInfo (или ее MT5-еквивалент)?



1. Нету


2. Там - работает

 
4x4ever:

Тема старенькая, 4-летняя но я вчера столкнулся с этой же проблемой. Тоесть явно портфельное моделирование в тестере все еще не сделано? В связи с этим 2 вопроса:

1. Планов добавить это в ближайшем будущем есть? (MT4)

2. В MT5 ситуация такая же или там работает?

..имеется ввиду портфельная тоговля в тестере или хотя бы MarketInfo (или ее MT5-еквивалент)?

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

Рекомендую даже не пытаться сподвигнуть на мультивалютный тестер. Пока что даже слушать не будут. А вот навести порядок с вычислением всех MarketInfo-данных в тестере хотя бы для текущего символа тестирования - это гораздо более реальная задача, с неё рекомендую и начать. // Из данных для текущего символа выводятся данные и для других. Только самостоятельно придётся прописать.

 

Резюме, чтобы закрыть тему:

1. Портфельного моделирования в тестере MT4, очевидно, можно не ждать.

2. Никаких МТ5, по крайней мере, для меня точно. Лично я этот продукт не выношу так же остро, как ООП.

3. Ну что же, раз разрабы принципиально не хотят развивать МТ4, обойдёмся и без них, своими силами.

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

const bool Real = !(IsOptimization() || IsTesting()); // признак работы советника в тестере или на счёте: false - тестер, true - торговля на счёте

if (!Real) { ... }

Для каждой кросс-пары XXX/YYY базовыми являются две: XXX/USD (USD/XXX) - для расчёта залога открываемых позиций (здесь и далее рассматриваю USD в качестве валюты депозита) и YYY/USD (USD/YYY) - для расчёта результатов закрываемых позиций. Наоборот бывает редко, но даже если Вы имеете дело с таким исключением, - не проблема поменять местами расчёты. Перед началом тестирования вся минутная история из архива котировок и свежие графиковые котировки со всех предшествующих рабочиму таймфреймов должны быть закачаны и пересчитаны для всех трёх пар: рабочей и двух родительских. Чем меньше будет "дыр" в истории, тем точнее будут результаты тестирования.

Функция взятия текущей котировки по одной из родительских пар будет может выглядеть примерно так (для кроссов, составленных из комбинаций 8 основных валют):

double BasePairQuote(bool Result,datetime TC,double &BasePoint)//Result - что мы рассчитываем: результат позиции - true, залог - false
{                                  //TC - результат функции TimeCurrent, указывающий, с какого бара графика родительской пары брать значение
    uint Bar = 0;                  //BasePoint - попутная передача в вызвавшую функцию информации о размере пункта родительской пары, что может быть по-
                                   //лезно при расчётах уровней (размеры пунктов рабочей и родительской пары могут не совпадать)
    string BasePair = StringSubstr(_Symbol,Result ? 3 : 0,3);
    if (BasePair == "AUD") BasePair = "AUDUSD";
    if (BasePair == "CAD") BasePair = "USDCAD";
    if (BasePair == "CHF") BasePair = "USDCHF";
    if (BasePair == "GBP") BasePair = "GBPUSD";
    if (BasePair == (Result ? "JPY" : "EUR")) BasePair = Result ? "USDJPY" : "EURUSD";
    if (BasePair == "NZD") BasePair = "NZDUSD";
    if (iBarShift(BasePair,PERIOD_M1,TC,true) == -1)
    {
        Bar = iBarShift(BasePair,PERIOD_M1,TC,false);
        Print("Текущий бар ",BasePair," отсутствует, цена будет взята с ближайшего бара (",TimeToStr(iTime(BasePair,PERIOD_M1,Bar),
              TIME_DATE|TIME_MINUTES),")");
    }
    BasePoint = MarketInfo(BasePair,MODE_POINT);
    return(StringGetChar(BasePair,0) == 'U' ? NormalizeDouble(1 / iOpen(BasePair,PERIOD_M1,Bar),uchar(MarketInfo(BasePair,MODE_DIGITS))) :
           iOpen(BasePair,PERIOD_M1,Bar));
} //для обратных котировок (XXX/USD) функция возвращает цену открытия соответствующего бара, для прямых (USD/XXX) - цену виртуальной пары XXX/USD
Примечание: крайне не рекомендую брать значение TimeCurrent() непосредственно в функции, следует именно передавать его из OnTick(). Это связано с тем, что, когда поток котировок в терминал очень редок (во время мёртвых флэтянок или в ночные часы), советник может ловить тайм-ауты, т.к. запрос на время последней котировки придёт не от OnTick() (которая "должна" принимать тики), а от пользовательской функции. При этом в журнал будет выведено что-то типа:
Test9 EURUSD.rann,M1: shutdown by timeout
Terminate execution thread #....

Я в своё время поистине вывихнул мозги, пытаясь понять причину этих зависаний.

Функция расчёта значения результата как открытой, так и закрытой позиции может выглядеть примерно так:

double CrossTrueResult(datetime TC) //перед вызовом этой функции обрабатываемая позиция должна быть выбрана функцией OrderSelect()
{                               //BaseSpreadResult - в моём случае input-переменная со средним спредом родительской пары для расчёта результата позиции
   RefreshRates();
   bool OT = OrderType();
   double BP,BPQ = BasePairQuote(true,TC,BP);
   return(NormalizeDouble(_Point * OrderLots() * 100000 * (BPQ + (OT ? BaseSpreadResult * BP : 0)) * MathAbs((OrderOpenPrice() -
          (OrderCloseTime() == 0 ? OT ? Ask : Bid : OrderClosePrice())) / _Point) * (OrderProfit() + OrderSwap() + OrderCommission() < 0 ? -1 : 1),2));
}

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

 
Иван #:

Резюме, чтобы закрыть тему:


Как мне вас жаль… Одно только вот это


говорит о многом. Разве можно торговать успешно в этом ДЦ?

Но даже не смотря на это, я не очень уверен, но кажется что даже «это» поставило сервер МТ5 и подключает счета…

 
Alexey Viktorov #:


Как мне вас жаль… Одно только вот это


говорит о многом. Разве можно торговать успешно в этом ДЦ?

Но даже не смотря на это, я не очень уверен, но кажется что даже «это» поставило сервер МТ5 и подключает счета…

Вы меня немного удивили, я торгую не у этого брокера, а в Альпари, но вроде как контора Раннева считается чуть ли не "образцово-показательной". Хотя, возможно, это тонкий PR самого отца-основателя. Так или иначе, здесь это просто в качестве иллюстрации, я заскринил ошибку, обсуждавшуюся здесь: https://www.mql5.com/ru/forum/365109.

Я, собственно, хотел дополнить свой предыдущий пост ещё и функцией правильного подсчёта залога/свободных средств при торговле кроссами:

double CrossTrueFreeMargin(datetime TC) //перед вызовом этой функции обрабатываемая позиция должна быть выбрана функцией OrderSelect()
{                             //BaseSpreadMargin - в моём случае input-переменная со средним спредом родительской пары для расчёта залога позиции
   bool OT = OrderType();
   uchar TO = uchar(OrdersTotal()),i;
   double BP,BPQ = BasePairQuote(false,TC,BP),Margin = AccountMargin() * (BPQ + (OT ? 0 : BaseSpreadMargin * BP)),TotalResult = 0;
   for (i = 0;i < TO;i++)//получаем итог позиций
   {
      while (!OrderSelect(i,SELECT_BY_POS))
         Print("Не удалось выбрать позицию для подсчёта результата");
      TotalResult += CrossTrueResult(TC) + OrderSwap() + OrderCommission();
   }
   TotalResult += GlobalVariableGet("Balance");//получаем эквити
   return(NormalizeDouble(TotalResult - Margin,2));//эквити - залог = свободные средства
}

Примечания:

1. Глобальная переменная Balance хранит правильное нарастающее значение баланса счёта, подсчитанное методом, приведённым выше.

2. В данном случае я немного "смалодушничал", не рассчитав правильное значение залога самостоятельно, а просто пересчитав выдаваемое тестером неправильное значение "из будущего" по курсу на "оптимизационный момент". Сделал это ради универсальности, т.к. у разных брокеров могут быть свои нюансы расчёта залога плюс надо ещё учитывать возможные локированные и встречные позиции, там тоже кто так считает перекрытые залоги, кто сяк... всё это учесть нереально. То же самое касается свопов и комиссий из функции CrossTrueResult. Да и в точности восстановить свопы в том виде, в котором они были на "оптимизационный момент", не получится, т.к. история свопов нигде не хранится, в отличие от тиковой истории. Да и сам размер свопов, думаю, вследствие своей малости (если только Вы не держите позиции неделями), особого влияния на торговлю не оказывает. Поэтому со свопами лично я не заморачиваюсь, принимая их, как есть. Их также можно пересчитать по курсу на нужный момент. Если Вы уверены, что знаете, как в точности Ваш брокер считает всё перечисленное, можете вместо AccountMargin() подставить формулу расчёта залога для своего случая - в общем виде её не проблема найти в Интернете.

 
Иван #:

Вы меня немного удивили, 

Вы меня удивили ещё больше. Достали тему ДЕВЯТИЛЕТНЕЙ ДАВНОСТИ и втюхиваете какие-то претензии выпячивая что-то своё.

Зачем было такую старую тему вытаскивать, а потом говорить «чтобы закрыть тему», ведь её уже 9 лет никто не открывал, считай что тема закрыта…

Причина обращения: