코드에서 오류를 찾도록 도와주시거나 CopyTicks() 함수가 올바르게 작동하지 않는지 확인하십시오 .
문제: CopyTicks()로 복사할 때 눈금 누락
시퀀싱:
코드
//+------------------------------------------------------------------+ //| ABL_Collector.mq5 | //| Copyright 2021, prostotrader | //| https://www.mql5.com | //+------------------------------------------------------------------+ #property copyright "Copyright 2021, prostotrader" #property link " https://www.mql5.com " #property version "1.00" //--- input string StTime = "07:00:00" ; //Начало сбора тиков input string EndTime = "23:50:00" ; //Конец сбора тиков //--- struct MARKET_DATA { int cnt; datetime time[]; ulong time_msc[]; double ask[]; double bid[]; double last[]; long volume[]; string flags[]; ulong mem_time; int skip_cnt; MqlTick ticks[]; } m_data; int f_handle; datetime start_time, end_time; //+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit () { m_data.cnt = 0 ; m_data.mem_time = 0 ; ArrayResize (m_data.time, 5000000 , 5000000 ); ArrayResize (m_data.time_msc, 5000000 , 5000000 ); ArrayResize (m_data.ask, 5000000 , 5000000 ); ArrayResize (m_data.bid, 5000000 , 5000000 ); ArrayResize (m_data.last, 5000000 , 5000000 ); ArrayResize (m_data.volume, 5000000 , 5000000 ); ArrayResize (m_data.flags, 5000000 , 5000000 ); f_handle = FileOpen ( "ABL_Colletor.csv" , FILE_WRITE | FILE_CSV ); if (f_handle == INVALID_HANDLE ) { Alert ( "Не создан *.CSV файл!" ); return ( INIT_FAILED ); } else { FileWrite (f_handle, "Symbol: " , Symbol ()); FileWrite (f_handle, "Tick num" , "Date" , "Tick time" , "ASK" , "BID" , "LAST" , "VOLUME" , "Tick Flags" ); } start_time = StringToTime (StTime); end_time = StringToTime (EndTime); return ( INIT_SUCCEEDED ); } //+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit ( const int reason) { if (f_handle != INVALID_HANDLE ) { ulong a_time = m_data.time_msc[ 0 ]; for ( int i = 0 ; i<m_data.cnt; i++) { if (a_time != m_data.time_msc[i]) { FileWrite (f_handle, "" ); a_time = m_data.time_msc[i]; } FileWrite (f_handle, IntegerToString (i + 1 ), TimeToString (m_data.time[i], TIME_DATE ), TimeToString (m_data.time[i], TIME_SECONDS ) + "." + StringFormat ( "%03i" , m_data.time_msc[i]% 1000 ), DoubleToString (m_data.ask[i], Digits ()), DoubleToString (m_data.bid[i], Digits ()), DoubleToString (m_data.last[i], Digits ()), string (m_data.volume[i]), m_data.flags[i]); } } ArrayResize (m_data.time, 0 , - 1 ); ArrayResize (m_data.time_msc, 0 , - 1 ); ArrayResize (m_data.ask, 0 , - 1 ); ArrayResize (m_data.bid, 0 , - 1 ); ArrayResize (m_data.last, 0 , - 1 ); ArrayResize (m_data.volume, 0 , - 1 ); ArrayResize (m_data.flags, 0 , - 1 ); } //+------------------------------------------------------------------+ //| Expert fill data function | //+------------------------------------------------------------------+ void FillData( const int skip, const int t_cnt) { string c_flags; m_data.skip_cnt = 0 ; //Обнуляем счетчик тиков с одним временем (последним) for ( int i = skip; i < t_cnt; i++) { c_flags = "" ; m_data.ask[m_data.cnt] = m_data.ticks[i].ask; //Сохраняем значения m_data.bid[m_data.cnt] = m_data.ticks[i].bid; m_data.last[m_data.cnt] = m_data.ticks[i].last; m_data.volume[m_data.cnt] = long (m_data.ticks[i].volume_real); m_data.time[m_data.cnt] = m_data.ticks[i].time; m_data.time_msc[m_data.cnt] = m_data.ticks[i].time_msc; //Собираем все флаги if ((m_data.ticks[i].flags& TICK_FLAG_ASK ) == TICK_FLAG_ASK ) c_flags += " TICK_FLAG_ASK," ; if ((m_data.ticks[i].flags& TICK_FLAG_BID ) == TICK_FLAG_BID ) c_flags += " TICK_FLAG_BID," ; if ((m_data.ticks[i].flags& TICK_FLAG_LAST ) == TICK_FLAG_LAST ) c_flags += " TICK_FLAG_LAST," ; if ((m_data.ticks[i].flags& TICK_FLAG_BUY ) == TICK_FLAG_BUY ) c_flags += " TICK_FLAG_BUY," ; if ((m_data.ticks[i].flags& TICK_FLAG_SELL ) == TICK_FLAG_SELL ) c_flags += " TICK_FLAG_SELL," ; if ((m_data.ticks[i].flags& TICK_FLAG_VOLUME ) == TICK_FLAG_VOLUME ) c_flags += " TICK_FLAG_VOLUME," ; int f_len = StringLen (c_flags); //Кастрируем последнюю запятую в строке if (f_len > 1 ) { StringSetCharacter (c_flags, f_len - 1 , ushort ( " " )); StringTrimRight (c_flags); } m_data.flags[m_data.cnt] = c_flags + " (" + string (m_data.ticks[i].flags) + ")" ; //Записываем флаги m_data.cnt++; //Увеличиваем счетчик всех записей if (m_data.mem_time == ulong (m_data.ticks[i].time_msc)) m_data.skip_cnt++; //Увеличиваем счетчик тиков с последним (одинаковым) временем } } //+------------------------------------------------------------------+ //| Expert tick function | //+------------------------------------------------------------------+ void OnTick () { datetime cur_time = TimeTradeServer (); //Берем текущее время сервера if ((cur_time >=start_time)&&(cur_time<end_time)) //Проверка времени торговли { int result = 0 ; if (m_data.mem_time == 0 ) //Проверка на 1-ю запись { result = CopyTicks ( Symbol (), m_data.ticks, COPY_TICKS_ALL , 0 , 20 ); //Копируем последние 20 тиков if (result >= 1 ) { m_data.mem_time = ulong (m_data.ticks[result- 1 ].time_msc); //Запоминаем время последнего тика FillData( 0 , result); //Сохраняем данные } } else //Последующие записи { result = CopyTicks ( Symbol (), m_data.ticks, COPY_TICKS_ALL , m_data.mem_time, 1000 ); //Копируем тики с запомненного времени if (result >= 1 ) //плюс последующие тики (если есть) { if (m_data.mem_time < ulong (m_data.ticks[result- 1 ].time_msc)) //Проверяем, изменилось ли время последнего тика { m_data.mem_time = ulong (m_data.ticks[result- 1 ].time_msc); //Запоминаем время последнего тика FillData(m_data.skip_cnt, result); //Сохраняем данные, минус уже сохраненные с } //предыдущим последнем временем (m_data.skip_cnt) } } } } //+------------------------------------------------------------------+
어드바이저 작업 후 ABL_Colletor.csv 파일을 얻습니다(zip 파일로).
터미널에서 틱 저장
GAZR-12.21.csv 파일이 나타납니다( zip 파일에 있음).
GAZR-12.21_mix.csv.xlsx의 파일 비교( zip 파일 )
예, 실제로 COPY_TICKS_TRADE 플래그를 사용하면 패스 가 없지만 거래와 입찰가가 모두 필요합니다.
또 목발?
result = CopyTicks ( Symbol (), m_data.ticks, COPY_TICKS_TRADE , m_data.mem_time, 1000 ); //плюс result = CopyTicks ( Symbol (), m_data.ticks, COPY_TICKS_INFO , m_data.mem_time, 1000 );
그러나 즉시 2가지 큰 문제가 발생합니다.
1. 시간을 "동기화"하는 방법
2. ASK와 BID가 맞는지 확인하는 방법
거래, 자동 거래 시스템 및 거래 전략 테스트에 관한 포럼
MetaTrader 5 플랫폼 빌드 3081의 새 버전: MQL5 서비스 개선 및 디자인 업데이트
fxsaber , 2021.10.19 16:30
두 개의 다른 스트림(INFO 및 LAST)이 인위적으로 하나의 ALL 스트림으로 결합됩니다.
같은 밀리초 안에 거래소는 INFO 스트림에 36800의 입찰가를 제시했고 LAST 스트림에 많은 거래를 했습니다. 시간을 나노초 단위로 측정했다면 INFO 가격이 거래보다 늦을 것이 분명합니다.
MT5는 스레드를 병합하고 동기화하는 데 시간을 소비합니다. 이 때문에 현재 틱 기록의 형성에 매우 적절한 실시간 지연이 있을 수 있습니다. 밀리초를 잃을 수 있습니다.
거래, 자동 거래 시스템 및 거래 전략 테스트에 관한 포럼
MetaTrader 5 플랫폼 빌드 3081의 새 버전: MQL5 서비스 개선 및 디자인 업데이트
fxsaber , 2021.10.19 16:38
터미널에서 Book-stream을 모니터링하고 새로운 CopyTicks와 비교하면 불일치가 많을 것이라고 생각합니다. 동시에 모든 것이 돌이켜 보면 꽤 괜찮을 것입니다.
Exchange의 트랜잭션은 별도의 스트림으로 이동합니다. 예,
요청 및 입찰과 같은
COPY_TICKS_ALL을 사용하면 이 두 스트림에서 선택이 이루어지지만 올바르게 수행되지 않습니다.
그리고 이러한 샘플은 두 스트림 모두 불일치가 아닌 "통과"시간을 갖기 때문에 밀리초가 걸릴 수 없습니다!
목발을 만들었는데 효과가 있는 것 같습니다.
//+------------------------------------------------------------------+ //| ABL_Collector.mq5 | //| Copyright 2021, prostotrader | //| https://www.mql5.com | //+------------------------------------------------------------------+ #property copyright "Copyright 2021, prostotrader" #property link " https://www.mql5.com " #property version "1.00" //--- input string StTime = "07:00:00" ; //Начало сбора тиков input string EndTime = "23:50:00" ; //Конец сбора тиков //--- struct MARKET_DATA { datetime time; ulong time_msc; double ask; double bid; double last; long volume; string flags; }; struct A_DATA { int cnt; ulong m_time_info; ulong m_time_trade; int s_cnt_info; int s_cnt_trade; MqlTick ticks_trade[]; MqlTick ticks_info[]; MARKET_DATA m_data[]; }a_data; int f_handle; datetime start_time, end_time; //+------------------------------------------------------------------+ //| Expert Array fast sort function | //+------------------------------------------------------------------+ void ArrayFastSort(MARKET_DATA &array[], const int size) { ulong msc_val; MARKET_DATA temp; MARKET_DATA tmp_arr[]; ArrayResize (tmp_arr, size, size); for ( int i = 0 ; i < size; i++) { tmp_arr[i] = array[i]; } int n[] = { 9 , 5 , 3 , 2 , 1 }; int i, j, z, y; for (z = 0 ;z < 5 ;z++) { y = n[z]; for (i = y;i < size;i++) { msc_val = tmp_arr[i].time_msc; temp = tmp_arr[i]; for (j = i - y; j >= 0 && msc_val < tmp_arr[j].time_msc; j -= y) { tmp_arr[j + y] = tmp_arr[j]; } tmp_arr[j + y] = temp; } } for (i = 0 ; i < size; i++) { msc_val = tmp_arr[i].time_msc; for (j = 0 ; j < size; j++) { if (array[j].time_msc == 0 ) continue ; if (msc_val == array[j].time_msc) { tmp_arr[i] = array[j]; array[j].time_msc = 0 ; break ; } } } for (i = 0 ; i < size; i++) { array[i] = tmp_arr[i]; } } //+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit () { a_data.cnt = 0 ; a_data.m_time_info = 0 ; a_data.m_time_trade = 0 ; ArrayResize (a_data.m_data, 5000000 , 5000000 ); f_handle = FileOpen ( "ABL_Colletor.csv" , FILE_WRITE | FILE_CSV ); if (f_handle == INVALID_HANDLE ) { Alert ( "Не создан *.CSV файл!" ); return ( INIT_FAILED ); } else { FileWrite (f_handle, "Symbol: " , Symbol ()); FileWrite (f_handle, "Tick num" , "Date" , "Tick time" , "ASK" , "BID" , "LAST" , "VOLUME" , "Tick Flags" ); } start_time = StringToTime (StTime); end_time = StringToTime (EndTime); int result = CopyTicks ( Symbol (), a_data.ticks_info, COPY_TICKS_ALL , 0 , 1 ); if (result >= 1 ) { a_data.m_time_info = a_data.ticks_info[ 0 ].time_msc; a_data.m_time_trade = a_data.ticks_info[ 0 ].time_msc; } return ( INIT_SUCCEEDED ); } //+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit ( const int reason) { if (f_handle != INVALID_HANDLE ) { ArrayFastSort(a_data.m_data, a_data.cnt); ulong a_time = a_data.m_data[ 0 ].time_msc; for ( int i = 0 ; i < a_data.cnt; i++) { if (a_time != a_data.m_data[i].time_msc) { FileWrite (f_handle, "" ); a_time = a_data.m_data[i].time_msc; } FileWrite (f_handle, IntegerToString (i + 1 ), TimeToString (a_data.m_data[i].time, TIME_DATE ), TimeToString (a_data.m_data[i].time, TIME_SECONDS ) + "." + StringFormat ( "%03i" , a_data.m_data[i].time_msc% 1000 ), DoubleToString (a_data.m_data[i].ask, Digits ()), DoubleToString (a_data.m_data[i].bid, Digits ()), DoubleToString (a_data.m_data[i].last, Digits ()), string (a_data.m_data[i].volume), a_data.m_data[i].flags); } } ArrayResize (a_data.m_data, 0 , - 1 ); Print ( "Collect ticks DONE!" ); } //+------------------------------------------------------------------+ //| Expert fill data function | //+------------------------------------------------------------------+ void FillData( const int skip, const int t_cnt, ulong &mem_time, int &skip_cnt, MqlTick &ticks[]) { string c_flags; skip_cnt = 0 ; for ( int i = skip; i < t_cnt; i++) { c_flags = "" ; a_data.m_data[a_data.cnt].ask = ticks[i].ask; a_data.m_data[a_data.cnt].bid = ticks[i].bid; a_data.m_data[a_data.cnt].last = ticks[i].last; a_data.m_data[a_data.cnt].volume = long (ticks[i].volume_real); a_data.m_data[a_data.cnt].time = ticks[i].time; a_data.m_data[a_data.cnt].time_msc = ticks[i].time_msc; //--- if ((ticks[i].flags& TICK_FLAG_ASK ) == TICK_FLAG_ASK ) c_flags += " TICK_FLAG_ASK," ; if ((ticks[i].flags& TICK_FLAG_BID ) == TICK_FLAG_BID ) c_flags += " TICK_FLAG_BID," ; if ((ticks[i].flags& TICK_FLAG_LAST ) == TICK_FLAG_LAST ) c_flags += " TICK_FLAG_LAST," ; if ((ticks[i].flags& TICK_FLAG_BUY ) == TICK_FLAG_BUY ) c_flags += " TICK_FLAG_BUY," ; if ((ticks[i].flags& TICK_FLAG_SELL ) == TICK_FLAG_SELL ) c_flags += " TICK_FLAG_SELL," ; if ((ticks[i].flags& TICK_FLAG_VOLUME ) == TICK_FLAG_VOLUME ) c_flags += " TICK_FLAG_VOLUME," ; int f_len = StringLen (c_flags); if (f_len > 1 ) { StringSetCharacter (c_flags, f_len - 1 , ushort ( " " )); StringTrimRight (c_flags); } a_data.m_data[a_data.cnt].flags = c_flags + " (" + string (ticks[i].flags) + ")" ; a_data.cnt++; if (mem_time == ulong (ticks[i].time_msc)) skip_cnt++; } } //+------------------------------------------------------------------+ //| Expert tick function | //+------------------------------------------------------------------+ void OnTick () { datetime cur_time = TimeTradeServer (); if ((cur_time >=start_time)&&(cur_time<end_time)) { int result = 0 ; result = CopyTicks ( Symbol (), a_data.ticks_info, COPY_TICKS_INFO , a_data.m_time_info, 1000 ); if (result >= 1 ) { if (a_data.m_time_info < ulong (a_data.ticks_info[result - 1 ].time_msc)) { a_data.m_time_info = a_data.ticks_info[result - 1 ].time_msc; FillData(a_data.s_cnt_info, result, a_data.m_time_info, a_data.s_cnt_info, a_data.ticks_info); } } result = CopyTicks ( Symbol (), a_data.ticks_trade, COPY_TICKS_TRADE , a_data.m_time_trade, 1000 ); if (result >= 1 ) { if (a_data.m_time_trade < ulong (a_data.ticks_trade[result - 1 ].time_msc)) { a_data.m_time_trade = a_data.ticks_trade[result - 1 ].time_msc; FillData(a_data.s_cnt_trade, result, a_data.m_time_trade, a_data.s_cnt_trade, a_data.ticks_trade); } } } } //+------------------------------------------------------------------+
누군가 견적을 수집해야 하는 경우 사용할 수 있습니다.
거래소 규정 준수 여부를 묻고 입찰가를 확인할 수 없는 점은 유감입니다.
CopyTicks() CopyTicksRange() 함수의 작업에 대한 연구를 요약합니다.
빌드 3101, 리얼, 오프너
1. COPY_TICKS_ALL 플래그를 사용할 때 - 누락된 거래가 있습니다.
COPY_TICKS_TRADE 플래그 를 사용하면 올바르게 표시됩니다.
2. 견적(ASK/BID)으로 상상할 수 없는 일이 발생합니다.
거래는 존재하지 않는 가격으로 이루어집니다
거래는 반대 가격으로 이루어집니다 (ASK 대신 BID가 취함)
따옴표 건너뛰기
큰 질문이 남아 있습니다.
큰 따옴표 불일치가 있기 때문에 터미널에 무엇이 있습니까?
우리는 어떤 가격으로 거래합니까?
ZIP 아카이브의 소스 파일
거래, 자동 거래 시스템 및 거래 전략 테스트에 관한 포럼
MetaTrader 5 플랫폼 빌드 3081의 새 버전: MQL5 서비스 개선 및 디자인 업데이트
fxsaber , 2021.10.19 16:57
그렇다면 거래소에서 방송한 데이터가 유출되고 있다는 증거로 MQ를 찌르십시오!
MQ가 무시하지 않는 스레드와 스레드의 첫 번째 게시물의 이미지와 유사성에서 이 작업을 수행해야 합니다.
거래, 자동 거래 시스템 및 거래 전략 테스트에 관한 포럼
드미트리 스쿠브 , 2015.03.24 09:17
간단한 볼륨으로 시작하겠습니다. 아래는 결함이 감지된 사진입니다. "쌍둥이"는 주기적으로 볼륨에 나타납니다.
친애하는 중재자 여러분!
"공익 청산????*" 주제에서 메시지를 옮겨주세요.
여기에서 정리와 관련이 없습니다.