#property copyright "Copyright 2025, MetaQuotes Ltd."
#property link "https://www.mql5.com"
#property version "1.00"
#define OBJ_NAME_ASK "TestObjectMoveAsk" // Ask price에 대한 그래픽 객체의 이름
#define OBJ_NAME_BID "TestObjectMoveBid" // Bid price에 대한 그래픽 객체의 이름
#define COUNT 100000000 // 히스토리에 로드할 틱의 수
#define DELAY 1 // 밀리세컨드로 틱 사이의 딜레이
/+------------------------------------------------------------------+
//| Script program start function |
/+------------------------------------------------------------------+
void OnStart()
{
//--- 현재 차트 ID, 차트 심볼 및 심볼 Digits
long chart_id= ChartID();
string symbol = ChartSymbol(chart_id);
int digits = (int)SymbolInfoInteger(symbol, SYMBOL_DIGITS);
//--- 차트에 Ask 가격과 Bid 가격을 표시하기 위해 두 개의 가격 레이블을 만듭니다.
if(!CreatePriceLabel(chart_id, true) || !CreatePriceLabel(chart_id, false))
return;
//--- tick을 수신하기 위한 배열
MqlTick ticks[]={};
//--- 차트에서 다음으로 보이는 바의 번호와 이 바가 열리는 시간(밀리초)을 가져옵니다.
int first= (int)ChartGetInteger(chart_id, CHART_FIRST_VISIBLE_BAR)-1;
ulong from = GetTime(symbol, PERIOD_CURRENT, first)*1000;
//--- 틱 기록을 배열에 로드합니다.
Print("Started collecting ticks...");
if(!GetTicksToArray(symbol, ticks))
return;
//--- 틱 배열을 재설정하고 차트에서 보이는 바의 범위에서 틱을 가져옵니다.
ZeroMemory(ticks);
if(CopyTicksRange(symbol, ticks, COPY_TICKS_INFO, from)<1)
{
PrintFormat("CopyTicksRange() from date %s failed. Error %d", TimeToString(GetTime(symbol, PERIOD_CURRENT, first)), GetLastError());
return;
}
Sleep(500);
PrintFormat("Tick visualization started at %s (%I64u), ticks total: %u", TimeToString(GetTime(symbol, PERIOD_CURRENT, first)), from, ticks.Size());
int count=0; // 처리된 틱의 수
int changes=0; // 처리된 가격 변화의 수
int total=(int)ticks.Size(); // 틱 배열 사이즈
//--- tick 배열을 통한 루프에서
for(int i=0; i<total && !IsStopped(); i++)
{
//--- 배열에서 틱을 가져와 틱 카운터를 증가시킵니다.
MqlTick tick=ticks[i];
count++;
//--- 틱 Ask 및 Bid 플래그를 체크
bool ask_tick=((tick.flags &TICK_FLAG_ASK)==TICK_FLAG_ASK);
bool bid_tick=((tick.flags &TICK_FLAG_BID)==TICK_FLAG_BID);
bool done=false;
//--- Ask 가격이 변경되면
if(ask_tick)
{
if(Move(chart_id, OBJ_NAME_ASK, tick.time, tick.ask))
{
changes++;
done=true;
}
}
//--- Bid 가격이 변경되는 경우
if(bid_tick)
{
if(Move(chart_id, OBJ_NAME_BID, tick.time, tick.bid))
{
changes++;
done=true;
}
}
//--- 그래픽 객체 중 하나(또는 둘 다)가 이동된 경우 차트를 업데이트합니다.
if(done)
{
ChartRedraw(chart_id);
Sleep(DELAY);
}
}
//--- 루프가 끝나면 처리된 틱 수를 저널에 보고합니다.
//--- 몇 초간 기다린 후 생성된 객체를 삭제하고 차트를 다시 그립니다.
PrintFormat("Total ticks completed: %u, Total price changes: %d", count, changes);
Sleep(2000);
if(ObjectsDeleteAll(chart_id, "TestObjectMove")>0)
ChartRedraw(chart_id);
/*
스크립트 실행의 결과로,Ask 그리고Bid 가격은 현재 보이는 차트에 표시됩니다.
차트의 왼쪽 가장자리부터 시작하여 과거 데이터의 끝까지
다음 데이터가 저널에 표시됩니다:
Started collecting ticks...
AUDUSD: received 13726794 ticks in 969 ms
Tick visualization started at 2025.01.31 09:00 (1738314000000), ticks total: 44380
Total ticks completed: 44380, Total price changes: 68513
*/
}
/+------------------------------------------------------------------+
//| Create a "Price label" object |
/+------------------------------------------------------------------+
bool CreatePriceLabel(const long chart_id, const bool obj_ask)
{
string obj_name=(obj_ask ? OBJ_NAME_ASK : OBJ_NAME_BID);
ResetLastError();
if(!ObjectCreate(chart_id, obj_name, (obj_ask ? OBJ_ARROW_RIGHT_PRICE : OBJ_ARROW_LEFT_PRICE), 0, 0, 0))
{
PrintFormat("%s: ObjectCreate() failed. Error %d",__FUNCTION__, GetLastError());
return(false);
}
return(ObjectSetInteger(chart_id, obj_name, OBJPROP_COLOR, (obj_ask ? clrRed : clrBlue)));
}
/+------------------------------------------------------------------+
//| 그래픽 객체를 지정된 가격/시간 좌표로 이동합니다. |
/+------------------------------------------------------------------+
bool Move(const long chart_id, const string obj_name, const datetime time, const double price)
{
ResetLastError();
if(!ObjectSetInteger(chart_id, obj_name, OBJPROP_TIME, time))
{
PrintFormat("%s: ObjectSetInteger() failed. Error %d",__FUNCTION__, GetLastError());
return(false);
}
if(!ObjectSetDouble(chart_id, obj_name, OBJPROP_PRICE, price))
{
PrintFormat("%s: ObjectSetDouble() failed. Error %d",__FUNCTION__, GetLastError());
return(false);
}
return(true);
}
/+------------------------------------------------------------------+
//| 배열에 ticks 로드 |
/+------------------------------------------------------------------+
bool GetTicksToArray(const string symbol, MqlTick &array[])
{
int attempts=0; // 틱 기록을 얻으려는 시도 카운터
bool success =false; // 성공적으로 틱을 복사한 플래그
//--- 틱을 받기 위해 3번 시도합니다.
while(attempts<3)
{
//--- tick을 받기 전 시작 시간을 측정합니다.
uint start=GetTickCount();
//--- 1970.01.01 00:00.001부터의 틱 기록을 요청합니다(매개변수 시작=1ms)
ResetLastError();
int received=CopyTicks(symbol, array, COPY_TICKS_ALL, 1, COUNT);
if(received!=-1)
{
//--- 틱 수와 소요 시간에 데이터를 표시합니다.
PrintFormat("%s: received %d ticks in %d ms", symbol, received, GetTickCount()-start);
//--- 틱 기록이 동기화되면 오류 코드는 0과 같습니다.
if(GetLastError()==0)
{
success=true;
break;
}
else
PrintFormat("%s: %s ticks are not synchronized yet, %d ticks received for %d ms. Error=%d",
__FUNCTION__, symbol, received, GetTickCount()-start, GetLastError());
}
//--- 카운트 시도
attempts++;
//--- tick 데이터베이스 동기화가 끝날 때까지 1초간 일시 정지합니다.
Sleep(1000);
}
//--- 요청된 틱을 틱 기록의 시작 부분에서 수신하는 데 3번 시도에 실패했습니다.
if(!success)
{
PrintFormat("Error! Failed to get ticks for symbol %s after three attempts", symbol);
return(false);
}
return(true);
}
/+------------------------------------------------------------------+
//| 바 인덱스로 시간을 반환합니다. |
/+------------------------------------------------------------------+
datetime GetTime(const string symbol, const ENUM_TIMEFRAMES timeframe, const int index)
{
datetime array[1]={};
ResetLastError();
if(CopyTime(symbol, timeframe, index, 1, array)!=1)
PrintFormat("%s: CopyTime() failed. Error %d",__FUNCTION__, GetLastError());
return(array[0]);
}
|