Скачать MetaTrader 5

Формат файлов тестера *.FXT

Авторизуйтесь или зарегистрируйтесь, чтобы добавить комментарий
MetaQuotes Software Corp.
Модератор
182667
MetaQuotes Software Corp.  
В своей работе тестер использует файл *.FXT со сгенерированной последовательностью баров. Проводя моделирование баров, он берет из этого файла новые бары и обновляет/добавляет к существующим.

Любой может отказаться от стандартного моделирования баров и подсунуть тестеру свой файл для расчетов. Для этого достаточно перед тестом отключить галочку "Recalculate", поместить необходимый файл *.FXT в каталог /tester/history . Имя файла должно быть в определенном формате SymbolPeriod_Type.fxt, где Symbol - название символа, Period - период графика в минутах, Type - тип выбранного моделирования (0 - по всем тикам, 1 - по контрольным точкам, 2 - по ценам открытия).

Ниже приведено краткое описание формата.

Файл начинается с заголовка:
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
struct TestHistoryHeader
  {
   int               version;
   char              copyright[64];      // копирайт
   char              symbol[12];
   int               period;
   int               model;              // для какого режима тестирования сгенерирована последовательность
   int               bars;               // количество баров в истории
   time_t            fromdate;
   time_t            todate;
   double            modelquality;       // качество генерации
   //---- общие параметры
   char              currency[12];       // валютная база
   int               spread;
   int               digits;
   double            point;
   int               lot_min;            // минимальный размер лота
   int               lot_max;            // максимальный размер лота
   int               lot_step;
   int               stops_level;        // величина отступа стопов
   int               gtc_pendings;       // указание закрывать отложенные ордера в конце дня
   //---- параметры расчёта профитов
   double            contract_size;      // величина контракта
   double            tick_value;         // цена одного пункта
   double            tick_size;          // размер одного пункта
   int               profit_mode;        // тип расчёта профитов { PROFIT_CALC_FOREX, PROFIT_CALC_CFD, PROFIT_CALC_FUTURES }
   //---- расчёты свопов
   int               swap_enable;        // разрешение взятия свопа
   int               swap_type;          // тип свопа            { SWAP_BY_POINTS, SWAP_BY_DOLLARS, SWAP_BY_INTEREST }
   double            swap_long;
   double            swap_short;         // величина овернайт свопа
   int               swap_rollover3days; // день тройных свопов
   //---- расчёт маржи
   int               leverage;           // плечо
   int               free_margin_mode;   // тип расчетов свободной маржи   { MARGIN_DONT_USE, MARGIN_USE_ALL, MARGIN_USE_PROFIT, MARGIN_USE_LOSS }
   int               margin_mode;        // тип расчетов маржи             { MARGIN_CALC_FOREX,MARGIN_CALC_CFD,MARGIN_CALC_FUTURES,MARGIN_CALC_CFDINDEX };
   int               margin_stopout;     // уровень стопаута
   double            margin_initial;     // маржевые требования
   double            margin_maintenance; // обязательные маржевые требования
   double            margin_hedged;      // маржевые требования на хеджируемых позициях
   double            margin_divider;     // делитель маржи
   char              margin_currency[12];// валюта маржевых требований
   //---- расчёт комиссии
   double            comm_base;          // базовая комиссия
   int               comm_type;          // тип базовой комиссии { COMM_TYPE_MONEY, COMM_TYPE_PIPS, COMM_TYPE_PERCENT }
   int               comm_lots;          // за лот или сделку    { COMMISSION_PER_LOT, COMMISSION_PER_DEAL }
   //----
   int               from_bar;           // номер бара fromdate
   int               to_bar;             // номер бара todate
   int               start_period[6];    // номер бара с которого началось моделирование меньшего периода
   //----
   int               reserved[64];
  };


После чего идет массив сгенерированных баров:

#pragma pack(push,1)
struct TestHistory
  {
   time_t            otm;                // время бара
   double            open;               // значения OHLCV
   double            low;
   double            high;
   double            close;
   double            volume;
   time_t            ctm;                // текущее рабочее время внутри бара
   int               flag;               // флаг запуска эксперта (0-бар модифицируем, а эксперта не запускаем)
  };
#pragma pack(pop)


Чтобы было более понятно, можно посмотреть как терминал сам заполняет поля этих структур.

Forex Trader
114269
Forex Trader  
Можно подробнее насчет struct TestHistory. Я предполагал, что в тестере просто хранится поток котировок, которые передаются в терминал так же как и реальные котировки, а терминал уже сам из них формирует бары, а у вас там хранятся сами бары. Можете объяснить, как из этих баров получаются котировки, т.е. Bid для каждого тика? Или у вас эти бары просто разлиные этапы развития одного главного бара, и каждый раз в метод start() передается сlose последнего бара?

Было бы не плохо, если бы вы привели пример заполнения TestHistory для различных методов. Например тестируемый период H1 и мы эмулируем два H1 бара 2005.07.13 00:00 и 2005.07.13 01:00. Для первого метода моделирования у нас будет две TestHistory, для второго четыре, для третьего .... и соответственно значения этих TestHistory для каждого метода моделирования.

Для чего используется flag?
Forex Trader
114269
Forex Trader  
когда вы открываете автономно сгенерированный файл (сколько можно про это говорить?), то как раз и видно, что сгенерировано. фактически, это состояние бара на определённый (time_t ctm) момент времени. к сожалению, этот момент времени не виден на графике, так как он не входит в формат HST. обратите внимание на то, что первые 6 полей формата TestHistory точно соответствуюь формату RateInfo.
Forex Trader
114269
Forex Trader  
Вернулся из отпуска и вижу, что формат FXT большой заинтересованности у пользователей не вызвал :) Или кто-то уже написал свой конвертор?

Если нет, подскажите можно ли средствами MQL4 сформировать данный файл? Прежде всего меня интерсует совпадает ли байтовое представление double и int, записываемых через FileWriteDouble(), FileWriteInteger() и т.п. и байтовое представление этих данных, используемое оригинальным генератором.

Как записать, например, char margin_currency[12]? Т.е. масив символов заданной длины?

Как рассчитывать double modelquality?

Правильно ли я понял, что в TestHistory на int flag принимающий значения {0,1} расходуется 4 байта? Когда у этого флага должно быть значение 0?
Forex Trader
114269
Forex Trader  
подскажите можно ли средствами MQL4 сформировать данный файл?

можно

Прежде всего меня интерсует совпадает ли байтовое представление double и int, записываемых через FileWriteDouble(), FileWriteInteger() и т.п. и байтовое представление этих данных, используемое оригинальным генератором.

Как записать, например, char margin_currency[12]? Т.е. масив символов заданной длины?

посмотрите наш пример period_converter - там решаются аналогичные задачи

Как рассчитывать double modelquality?

как хотите, так и рассчитывайте. число должно быть в диапазоне от 0 до 100. иначе файл будет признан ошибочным и стёрт.

Правильно ли я понял, что в TestHistory на int flag принимающий значения {0,1} расходуется 4 байта? Когда у этого флага должно быть значение 0?

да, 4 байта. на флаге, равном 0, эксперт не запускается. если Вы почитаете нашу статью про моделирование, то обратите внимание на тот факт, что при моделировании по ценам открытия бар рисуется 2 раза - сначала открытие с флагом 1, потом закрытие бара с флагом 0 (первые 100 баров также помечены флагом 0). в сгенерированном файле хранятся "слепки" баров на тот или иной момент времени.

структура заголовка претерпела изменения. следующим постом я выложу обновлённую структуру
Forex Trader
114269
Forex Trader  
struct TestHistoryHeader
  {
   int               version;
   char              copyright[64];      // копирайт
   char              symbol[12];
   int               period;
   int               model;              // для какого режима тестирования сгенерирована последовательность
   int               bars;               // количество баров в истории
   time_t            fromdate;
   time_t            todate;
   double            modelquality;       // качество генерации
   //---- общие параметры
   char              currency[12];       // валютная база
   int               spread;
   int               digits;
   double            point;
   int               lot_min;            // минимальный размер лота
   int               lot_max;            // максимальный размер лота
   int               lot_step;
   int               stops_level;        // величина отступа стопов
   int               gtc_pendings;       // указание закрывать отложенные ордера в конце дня
   //---- параметры расчёта профитов
   double            contract_size;      // величина контракта
   double            tick_value;         // цена одного пункта
   double            tick_size;          // размер одного пункта
   int               profit_mode;        // тип расчёта профитов { PROFIT_CALC_FOREX, PROFIT_CALC_CFD, PROFIT_CALC_FUTURES }
   //---- расчёты свопов
   int               swap_enable;        // разрешение взятия свопа
   int               swap_type;          // тип свопа            { SWAP_BY_POINTS, SWAP_BY_DOLLARS, SWAP_BY_INTEREST }
   double            swap_long;
   double            swap_short;         // величина овернайт свопа
   int               swap_rollover3days; // день тройных свопов
   //---- расчёт маржи
   int               leverage;           // плечо
   int               free_margin_mode;   // тип расчетов свободной маржи   { MARGIN_DONT_USE, MARGIN_USE_ALL, MARGIN_USE_PROFIT, MARGIN_USE_LOSS }
   int               margin_mode;        // тип расчетов маржи             { MARGIN_CALC_FOREX,MARGIN_CALC_CFD,MARGIN_CALC_FUTURES,MARGIN_CALC_CFDINDEX };
   int               margin_stopout;     // уровень стопаута
   double            margin_initial;     // маржевые требования
   double            margin_maintenance; // обязательные маржевые требования
   double            margin_hedged;      // маржевые требования на хеджируемых позициях
   double            margin_divider;     // делитель маржи
   char              margin_currency[12];// валюта маржевых требований
   //---- расчёт комиссии
   double            comm_base;          // базовая комиссия
   int               comm_type;          // тип базовой комиссии { COMM_TYPE_MONEY, COMM_TYPE_PIPS, COMM_TYPE_PERCENT }
   int               comm_lots;          // за лот или сделку    { COMMISSION_PER_LOT, COMMISSION_PER_DEAL }
   //----
   int               from_bar;           // номер бара fromdate
   int               to_bar;             // номер бара todate
   int               start_period[6];    // номер бара с которого началось моделирование меньшего периода
   //----
   int               reserved[64];
  };


поле version должно содержать число 402
ниже приведу наш код проверки сгенерированного файла на адекватность

      //---- проверяем адекватность заголовка
      if(fread(&m_header,sizeof(m_header),1,m_file)==1 &&
                m_header.version==TestHistoryVersion   &&
                m_header.model==model && m_header.period==scheme->period &&
                strcmp(m_header.symbol,scheme->symbol)==0)
        {
         //---- проверяем дальше
         if(m_header.bars<=100   || m_header.modelquality<=0.0 ||
            m_header.spread<0    || m_header.spread>100000 ||
            m_header.digits<0    || m_header.digits>8 ||
            m_header.lot_min<0   || m_header.lot_step<=0 ||
            m_header.leverage<=0 || m_header.leverage>500 ||
            m_header.swap_rollover3days<0 ||
            m_header.swap_rollover3days>6 ||
            m_header.stops_level<0) refresh=TRUE;
         //---- проверяем необходимость обновления
         if(refresh==FALSE)
           {
            m_testes_total=(_filelength(_fileno(m_file))-sizeof(m_header))/sizeof(TestHistory);
            return(TRUE);
           }
        }


некоторые дополнительные пояснения. как я уже сказал version должна быть равна 402. символ, период и модель в заголовке должны точно соответствовать имени файла SSSSSSPP_M.fxt

Forex Trader
114269
Forex Trader  
Спасибо за разъяснения. Будем пробовать. Можно ли еще объяснить смысл следующих параметров:
int               from_bar;           // номер бара fromdate
int               to_bar;               // номер бара todate
int               start_period[6];   // номер бара с которого началось моделирование меньшего периода



Когда я в настройках тестирования в интерфейсе меняю промежкток дат для тестирования, у меня что переписывается заголовок файла, а в самом файле всегда содержатся тики по всем барам моделируемого периода (независимо от того какая дата установлена)?

Если тестеру подложить свой файл с тиками, можно ли будет из интерфейса менять начало и конец тестирования (UseDate) или при попытке изменить дату свой файл с тиками будет испорчен?

Forex Trader
114269
Forex Trader  
эти параметры нужны для расчёта качества моделирования и для рисования цветной полоски в отчёте. можете забить нулями.
в заголовке файла пишется состояние на момент генерации. например, при генерации днёвок данные до даты From и после даты To будут представлены только конечными состояниями баров без промежуточных тиков.
без проблем можно использовать даты, главное, не нажимайте галочку "пересчитать"
Forex Trader
114269
Forex Trader  
2dev
Делись успехами :)
иначе не понятно или моделирование "хромает", или тестер "врет" что скорее всего, т.к. смоделированные бары (те что на графике вроде совпадают) хотел сравнить с реальными , но не знаю как сделать экспорт смоделированных баров в ексцел, а котировки записанные экспертом (что ему подаются на вход) в режиме тестирования отличаются от реальных даже на контрольных точках, про внутри я пока молчу
Forex Trader
114269
Forex Trader  
Последнюю неделю не было времени заниматься тестером, только сегодня получилось. Выяснил, что формат fxt несколько отличается от представленного выше в ветке.

1. Такие поля как ниже, реально не int, a double.
int               lot_min;            // минимальный размер лота
int               lot_max;            // максимальный размер лота
int               lot_step;



Так же есть и другие поля объявленные как int, а реально они double (в исходном коде это видно - код записывающий их как int закомментирован, а ниже идет запись как double).

2. Между modelquality и currency[12] в TestHistoryHeader, есть еще 4 байта, природа которых неизвества (либо какой-то недокументированный параметр либо где-то выше невыявленный double) . Сейчас я в то место пишу 16457 (такое же значение туда пишет оригинальный тестер). Что это за 4 байта?

3. Есть подозрение, что между TestHistoryHeader и TestHistory, есть что-то еще? Влияет ли на файл #pragma pack(push,1) - эту инструкцию я игнорировал?

Поскольку все вышеречисленное я искал с помощью hex-редактора, возможно, что-то я интерпртеровал неправильно, Слава, посмотри, пожалуйста, мой код, который пишет заголовок.


Непосредственно о тестере. Принцип работы прост - используются данные 1 (Одного) самого младшего интересующего периода и из них генерируются данные нужного старшего периода. Параметр CurrentBarsPerTargetBar отвечают за то, как будут группироваться бары. Например, из M1 можно генерировать H1, на котром потом тестироваться, установив CurrentBarsPerTargetBar == 60. Или генерировать D1 из H1 для быстрого предварительного тестирования, установив CurrentBarsPerTargetBar == 24.

Изменяя FromDate и ToDate можно ограничивать диапазон первичных данных и следовательно размер файла. По умолчанию нет ограничений, но полезно знать, что при генерации из M1 любого таймфрема размер будет около 70Мб/год.

Сам алгоритм моделирования предельно прост (а значит близок к реальности :))) и представлен в методе writeTestHistory():

		double peak1 = high0, peak2 = low0;		
		if (close0 > open0 || (MathAbs(close0 - open0) < Point && i % 2 == 0)) {//up bar
			peak1 = low0;
			peak2 = high0;		
		}
		
		writeTick(barTimeStep, open0, tickVolume, 1);
		
		if (!SkipEqualQuotes || !(MathAbs(open0 - peak1) < Point))//skip peak1==open0 
			writeTick(barTimeStep, peak1, tickVolume, 1);
			
		writeTick(barTimeStep, median0, tickVolume, 1);
		writeTick(barTimeStep, peak2, tickVolume, 1);
		
		if (!SkipEqualQuotes || !(MathAbs(close0 - peak2) < Point))//skip close0==peak2
			writeTick(barTimeStep, close0, tickVolume, 1);



Из каждого исходного бара берется 5 котировок OHLC и средняя цена M = (H+L)/2. Если O<C, то считаем что вначале будет достигнут минимум бара, потом максимум и наоборот. В итоге эти пять котировок будут записаны в выходной файл, как OLMHC или OHMLC. Если открытие и закрытие совпадают с близким пиком, их можно не записывать (параметр SkipEqualQuotes). Таким образом на один H1 бар при генерации из M1 баров мы получим 60*5=300 тиков. каждый из этих тиков будет находится внутри соотвествующего M1 бара, т.е. максимально близко к реальному движению цены. Таким образом максимальная погрешность этого морделирования составляет примерно 1/4 от среднего разброса H и L внутри первичного бара (в случае M1 - около 3 пунктов) , а средняя погрешность, понятное дело, стремиться к нулю :)

Графики генерируются и открываются через Open Offline. Пробовал EURUSD и USDCHF. Тестирование идет, но в конце выдается ошибка
TestGenerator: error reading file for 'EURUSD60'

Тестированием я еще плотно не занимался, все больше сгенерированные графики с оригинальными сравнивал.

Собственно код скрипта:

//+------------------------------------------------------------------+
//|                                         TestHistoryGenerator.mq4 |
//|                                                              dev |
//|Генерирует историю для тестирования экспертов на основе OHLCM     |
//+------------------------------------------------------------------+
#property copyright "dev"
#property link      "self at dogada dot com"
#property show_inputs

#define VERSION 402
#define COPYRIGHT "Public domain, generated by dev"


//сколько баров текущего периода попадает в 1 бар моделируемого
extern int CurrentBarsPerTargetBar = 4;
extern datetime FromDate = 0;//D'2005.07.25 00:00'
extern datetime ToDate = 0;
extern bool SkipEqualQuotes = true;

int fileHandle = -1;
int targetPeriod, targetBars, targetFromDate, targetToDate;
double targetModelQuality;
string targetBaseCurrency = "";

int firstBarOffset, lastBarOffset;

int start() {
	Print(Symbol() + " " + Period() + " Bars=" + Bars);
	if (analyzeTarget() < 0)
		return (-1);

	fileHandle = FileOpen(Symbol() + targetPeriod + "_0.fxt", FILE_BIN | FILE_WRITE);
		
   if(fileHandle < 0)
   	return(-1);
   	
		   	
	writeTestHistoryHeader();
	writeTestHistory();   		
   return(0);
}

void deinit() {
   if (fileHandle >= 0) {
   	FileClose(fileHandle);
   	//TODO: check last error
   	fileHandle =-1;
   }
}

int analyzeTarget() {

	if (Bars < 100)
		return (-1);
		
	if (CurrentBarsPerTargetBar < 2)
		return (-2);

	if (ToDate > Time[1])
		ToDate = 0;
		
	string symbol = Symbol();
	
	int period = Period();
	targetPeriod = CurrentBarsPerTargetBar*Period();
	targetBaseCurrency = StringSubstr(Symbol(), 0, 3);
		

	Print("targetPeriod="  + targetPeriod);
	firstBarOffset = Bars - 1;
	if (FromDate > 0)
		firstBarOffset = iBarShift(symbol, period, FromDate, false);
	
	lastBarOffset = 1;
	
	if (ToDate > 0)
		lastBarOffset = iBarShift(symbol, period, ToDate, false);
	
	if (firstBarOffset - lastBarOffset < 2*CurrentBarsPerTargetBar || 
	firstBarOffset < 0 || lastBarOffset < 0)
		return (-3);
	
	int targetSeconds = targetPeriod*60;
	targetFromDate = (Time[firstBarOffset]/targetSeconds)*targetSeconds;
	targetToDate = (Time[lastBarOffset]/targetSeconds)*targetSeconds;					

	targetBars = 0;
	int lastTargetBarTime = targetFromDate;
	for (int i = firstBarOffset; i >= lastBarOffset; i--) {
		int time0 = Time[i];
		if (time0 >= lastTargetBarTime + targetSeconds || i == lastBarOffset) {
			targetBars++;
			lastTargetBarTime = (time0/targetSeconds)*targetSeconds;
		}	
	}

	
	Print(" From=" + timeStr(targetFromDate)  + " To=" + timeStr(targetToDate) +
	" targetBars=" + targetBars + " firstBarOffset=" + firstBarOffset + 
	" lastBarOffset=" + lastBarOffset);
	
	if (targetBars < 100)
		return (-4);		

	int innerBars = targetBars*CurrentBarsPerTargetBar;
	int missedBars = innerBars - (firstBarOffset - lastBarOffset + 1);
	targetModelQuality = MathMin(1.0*(firstBarOffset - lastBarOffset + 1)/innerBars, 1.0);
	
	Print("Model quality=" + targetModelQuality + 
	", was missed " + missedBars + " from " + innerBars + " inner bars.");
}

void writeTestHistoryHeader() {
	FileWriteInteger(fileHandle, VERSION, LONG_VALUE);
   FileWriteString(fileHandle, COPYRIGHT, 64);	
	FileWriteString(fileHandle, Symbol(), 12);
	FileWriteInteger(fileHandle, targetPeriod, LONG_VALUE);
	FileWriteInteger(fileHandle, 0, LONG_VALUE);//model
	FileWriteInteger(fileHandle, targetBars, LONG_VALUE);
	FileWriteInteger(fileHandle, targetFromDate, LONG_VALUE);
	FileWriteInteger(fileHandle, targetToDate, LONG_VALUE);
	FileWriteDouble(fileHandle, targetModelQuality, DOUBLE_VALUE);

	FileWriteInteger(fileHandle, 16457, LONG_VALUE);//??
	
   //---- общие параметры
   FileWriteString(fileHandle, targetBaseCurrency, 12);//??currency[12]			
	FileWriteInteger(fileHandle, MarketInfo(Symbol(), MODE_SPREAD), LONG_VALUE);
	FileWriteInteger(fileHandle, Digits, LONG_VALUE);	
	FileWriteDouble(fileHandle, Point, DOUBLE_VALUE);
	//FileWriteInteger(fileHandle, 1, LONG_VALUE);//lot_min ?? int or double
	FileWriteDouble(fileHandle, 0.1, DOUBLE_VALUE);//lot_min ?? int or double
	//FileWriteInteger(fileHandle, 10, LONG_VALUE);//lot max
	FileWriteDouble(fileHandle, 10.0, DOUBLE_VALUE);//lot max
	
	//FileWriteInteger(fileHandle, 1, LONG_VALUE);//lot step
	FileWriteDouble(fileHandle, 0.1, DOUBLE_VALUE);//lot step
	
	FileWriteInteger(fileHandle, MarketInfo(Symbol(), MODE_STOPLEVEL), LONG_VALUE);
	FileWriteInteger(fileHandle, 0, LONG_VALUE);//gtc_pendings
	
   //---- параметры расчёта профитов
	FileWriteDouble(fileHandle, 100000.0, DOUBLE_VALUE);//contract_size
	FileWriteDouble(fileHandle, 0.0, DOUBLE_VALUE);//tick_value; цена одного пункта
	FileWriteDouble(fileHandle, 0.0, DOUBLE_VALUE);//tick_size
	FileWriteInteger(fileHandle, 0, LONG_VALUE);//profit_mode { PROFIT_CALC_FOREX, PROFIT_CALC_CFD, PROFIT_CALC_FUTURES }
	
	
   //---- расчёты свопов
	FileWriteInteger(fileHandle, 1, LONG_VALUE);//swap_enable
	FileWriteInteger(fileHandle, 0, LONG_VALUE);//swap_type
	FileWriteDouble(fileHandle, -0.35, DOUBLE_VALUE);//swap_long
	FileWriteDouble(fileHandle, 0.15, DOUBLE_VALUE);//swap_short
	FileWriteInteger(fileHandle, 4, LONG_VALUE);//swap_rollover3days

	//---- расчёт маржи
	FileWriteInteger(fileHandle, 100);//leverage
	FileWriteInteger(fileHandle, 1);//free_margin_mode
	FileWriteInteger(fileHandle, 0);//margin_mode
	
	
	//FileWriteInteger(fileHandle, 30);//margin_stopout
	FileWriteDouble(fileHandle, 30.0, DOUBLE_VALUE);//margin_stopout
	
	FileWriteDouble(fileHandle, 0.0, DOUBLE_VALUE);//margin_initial		
	FileWriteDouble(fileHandle, 0.0, DOUBLE_VALUE);//margin_maintenance		
	FileWriteDouble(fileHandle, 0.0, DOUBLE_VALUE);//margin_hedged		
	FileWriteDouble(fileHandle, 2.0, DOUBLE_VALUE);//margin_divider
   FileWriteString(fileHandle, targetBaseCurrency, 12);//??margin_currency

   //---- расчёт комиссии
	FileWriteDouble(fileHandle, 0.0, DOUBLE_VALUE);//comm_base
	FileWriteInteger(fileHandle, 0);//comm_type
	//FileWriteInteger(fileHandle, 0);//comm_lots
	FileWriteDouble(fileHandle, 0.0);//comm_lots
		
   //----
	FileWriteInteger(fileHandle, targetBars - 2);//from_bar номер бара fromdate
	FileWriteInteger(fileHandle, 0);//to_bar номер бара todate
	int startPeriod[6];
	FileWriteArray(fileHandle, startPeriod, 0, 6);//start_period[6]	
	   
   //----
   int reserved[64];
   FileWriteArray(fileHandle, reserved, 0, 64);//reserved[64]
}

double barLow = 0.0, barHigh = 0.0, barOpen = 0.0, barClose = 0.0, barVolume = 0.0;
int barTime, barWorkTime;
 
void writeTestHistory() {
	int targetSeconds = targetPeriod*60;
	int barTimeStep = (60*Period())/4 - 1;
	
	Print("barTimeStep=" + barTimeStep);
	
	barTime = targetFromDate;
	for (int i = firstBarOffset; i >= lastBarOffset; i--) {
		int time0 = Time[i];
		double low0 = Low[i];
		double high0 = High[i];
		double open0 = Open[i];
		double close0 = Close[i];
		double volume0 = Volume[i];
		double median0 = NormalizeDouble((high0 + low0)/2, Digits);
			
		if (time0 >= barTime + targetSeconds || i == firstBarOffset) {// || i == lastBarOffset
			barTime = (time0/targetSeconds)*targetSeconds;
			barLow = 1000000.0;
			barHigh = 0.0;
			barOpen = open0;
			barClose = 0.0;
			barVolume = 0.0;
		}
		
		barWorkTime = time0;
		double tickVolume = MathMax(volume0/5, 1.0);

		double peak1 = high0, peak2 = low0;		
		if (close0 > open0 || (MathAbs(close0 - open0) < Point && i % 2 == 0)) {//up bar
			peak1 = low0;
			peak2 = high0;		
		}
		
		writeTick(barTimeStep, open0, tickVolume, 1);
		
		if (!SkipEqualQuotes || !(MathAbs(open0 - peak1) < Point))//skip peak1==open0 
			writeTick(barTimeStep, peak1, tickVolume, 1);
			
		writeTick(barTimeStep, median0, tickVolume, 1);
		writeTick(barTimeStep, peak2, tickVolume, 1);
		
		if (!SkipEqualQuotes || !(MathAbs(close0 - peak2) < Point))//skip close0==peak2
			writeTick(barTimeStep, close0, tickVolume, 1);
	}
}

void writeTick(int time, double price, double volume, int flag) {
	if (false && barTime < D'2005.07.25 02:00') {
		Print(StringConcatenate("tick: ", timeStr(barWorkTime), "  ", quoteStr(price), 
		", bar: ", timeStr(barTime), " O=", quoteStr(barOpen), " L=", quoteStr(barLow),
		" H=", quoteStr(barHigh), " C=", quoteStr(barClose)));
	}

	barClose = price;
	barVolume += volume;
	
	if (price < barLow)
		barLow = price;
		
	if (price > barHigh)
		barHigh =  price;


	//52 байта в файле - 52 здесь
	FileWriteInteger(fileHandle, barTime);//otm
	FileWriteDouble(fileHandle, barOpen, DOUBLE_VALUE);//open
	FileWriteDouble(fileHandle, barLow, DOUBLE_VALUE);//low
	FileWriteDouble(fileHandle, barHigh, DOUBLE_VALUE);//high
	FileWriteDouble(fileHandle, barClose, DOUBLE_VALUE);//close
	FileWriteDouble(fileHandle, barVolume, DOUBLE_VALUE);//volume
	FileWriteInteger(fileHandle, barWorkTime);//ctm
	FileWriteInteger(fileHandle, flag);//flag
	
	barWorkTime += time;
}

string quoteStr(double quote) {
    return (DoubleToStr(NormalizeDouble(quote, Digits), Digits));
}

string timeStr(int time) {
	return (TimeToStr(time, TIME_DATE | TIME_SECONDS));
}
Forex Trader
114269
Forex Trader  
Также в коде можно заметить, что
сurrency[12]
margin_currency[12]// валюта маржевых требований

определяются неуниверсально, но как их получить универсально через MT4 я не знаю.
12
Авторизуйтесь или зарегистрируйтесь, чтобы добавить комментарий