#property copyright "Copyright 2025, MetaQuotes Ltd."
#property link "https://www.mql5.com"
#property version "1.00"
#define OBJ_NAME_ASK "TestObjectMoveAsk" // Ask価格のグラフィックオブジェクトの名前
#define OBJ_NAME_BID "TestObjectMoveBid" // Bid価格のグラフィックオブジェクトの名前
#define COUNT 100000000 // 歴史を読み込むティックの数
#define DELAY 1 // ティック間の遅延(ミリ秒単位)
//+------------------------------------------------------------------+
//| スクリプトプログラム開始関数 |
//+------------------------------------------------------------------+
void OnStart()
{
//--- 現在のチャートID、チャートシンボル、およびシンボルの小数桁数
long chart_id= ChartID();
string symbol = ChartSymbol(chart_id);
int digits = (int)SymbolInfoInteger(symbol, SYMBOL_DIGITS);
//--- チャート上に、Ask価格とBid価格を表示する2つの価格ラベルを作成する
if(!CreatePriceLabel(chart_id, true) || !CreatePriceLabel(chart_id, false))
return;
//--- ティックを受け取る配列
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(); // ティック配列サイズ
//--- ティック配列のループ
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
*/
}
//+------------------------------------------------------------------+
//| 価格ラベルオブジェクトを作成する |
//+------------------------------------------------------------------+
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);
}
//+------------------------------------------------------------------+
//| ティックを配列に読み込む |
//+------------------------------------------------------------------+
bool GetTicksToArray(const string symbol, MqlTick &array[])
{
int attempts=0; // ティック履歴を読み込む試みのカウンタ
bool success =false; // 正常なティックコピーのフラグ
//--- ティックの受信を3回試行する
while(attempts<3)
{
//--- ティックを受信する前に開始時間を測定する
uint start=GetTickCount();
//--- 1970.01.01 00:00.001 以降のティック履歴を要求する (パラメータ from=1 ms)
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);
//--- ティック履歴が同期されている場合、エラーコードはゼロになる
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++;
//--- ティック データベースの同期が終了するまで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]);
}
|