254 lines
No EOL
18 KiB
MQL4
254 lines
No EOL
18 KiB
MQL4
//+------------------------------------------------------------------+
|
|
//| VariableSpreadCSV.mq4 |
|
|
//| Copyright 2024, TNK/TNK_SYSTEM |
|
|
//| https://note.com/tnk_system |
|
|
//+------------------------------------------------------------------+
|
|
#property copyright "Copyright 2024, TNK/TNK_SYSTEM"
|
|
#property link "https://note.com/tnk_system"
|
|
#property version "1.0" //
|
|
#property icon "TNKIcon.ico" // アイコン取り込み
|
|
#property strict
|
|
#include <stdlib.mqh>
|
|
|
|
#property description "1. TDSの変動スプレッドは、当EAをバックテストすることで計測できます"
|
|
#property description "2. チャートにセットすることで、リアルタイムスプレッドの計測も行えます"
|
|
#property description "3. 計測したデータは、csv出力を行います(単位はpips)"
|
|
#property description "4. パラメータで稼働時間を入力することで、指定時間のみの計測も可能です"
|
|
#property description "5. 当ツールはEAですので、Expertsフォルダ内に配置してください"
|
|
|
|
// オープンパラメータ
|
|
extern int StartHour = 0; // 開始時刻
|
|
extern int StartMinute = 0; // 開始分
|
|
extern int EndHour = 0; // 終了時刻
|
|
extern int EndMinute = 0; // 終了分
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| 内部パラメータ |
|
|
//+------------------------------------------------------------------+
|
|
// スプレッド計測用
|
|
double myPoint;
|
|
double MeasureSpread, SpreadMin = 1000, SpreadMax = 0, SpreadSum = 0, SpreadAve = 0;
|
|
double SpreadMin1 = 100, SpreadMax1 = 0, SpreadSum1 = 0, SpreadAve1 = 0;
|
|
int TickCount = 0, TickCount1 = 0;
|
|
datetime lastBars;
|
|
|
|
// ファイル出力用
|
|
string Timeframe = (Period() == 1? "M1": Period() == 5? "M5": Period() == 15? "M15": Period() == 30? "M30":
|
|
Period() == 60? "H1": Period() == 240? "H4": Period() == 1440? "D1": Period() == 10080? "W1": "MN1");
|
|
string filename;
|
|
int filehandle;
|
|
bool StartWriting = false;
|
|
|
|
// DPI換算
|
|
double DPIAdjust;
|
|
//+------------------------------------------------------------------+
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| expert initialization function |
|
|
//+------------------------------------------------------------------+
|
|
int OnInit()
|
|
{
|
|
//+------------------------------------------------------------------+
|
|
// 桁合わせ
|
|
myPoint = Point;
|
|
if (Digits % 2 == 1) myPoint *= 10;
|
|
//+------------------------------------------------------------------+
|
|
// ファイル初期処理
|
|
filename = "Spread_" + Symbol() + "_" + Timeframe + "_" + TimeToStr(iTime(NULL, 0, 1),TIME_DATE) + "~.csv";
|
|
filehandle = FileOpen(filename, FILE_CSV|FILE_WRITE|FILE_READ, ",");
|
|
//+------------------------------------------------------------------+
|
|
// CSVヘッダーを書き込む
|
|
if (FileTell(filehandle) == 0)
|
|
{
|
|
FileWrite(filehandle, "日付", "時刻", "最大", "最小", "平均", "ティック");
|
|
//FileWrite(filehandle, "Date", "Time","Max", "Minimum", "Average", "Volume");
|
|
FileClose(filehandle);
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
// DPI換算
|
|
double USERdpi = TerminalInfoInteger(TERMINAL_SCREEN_DPI);
|
|
double DevPCdpi = 144;
|
|
DPIAdjust = USERdpi / DevPCdpi;
|
|
//+------------------------------------------------------------------+
|
|
// チャートコメント初期
|
|
PipsObject();
|
|
//+------------------------------------------------------------------+
|
|
|
|
return(0);
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| expert deinitialization function |
|
|
//+------------------------------------------------------------------+
|
|
void OnDeinit(const int reason)
|
|
{
|
|
if (!IsTesting())
|
|
{
|
|
ObjectsDeleteAll();
|
|
}
|
|
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| expert start function |
|
|
//+------------------------------------------------------------------+
|
|
void OnTick()
|
|
{
|
|
if (isTime())
|
|
{
|
|
TickCount++;
|
|
MeasureSpread = (Ask - Bid) / myPoint;
|
|
SpreadSum += MeasureSpread;
|
|
SpreadMin = SpreadMin == 0 ? SpreadMin = MeasureSpread : SpreadMin;
|
|
if (TickCount > 0 && SpreadSum > 0) SpreadAve = SpreadSum / TickCount;
|
|
if (SpreadMax < MeasureSpread) SpreadMax = MeasureSpread;
|
|
if (SpreadMin > MeasureSpread) SpreadMin = MeasureSpread;
|
|
|
|
if (lastBars != Time[0])
|
|
{
|
|
lastBars = Time[0];
|
|
|
|
//ファイル書込み
|
|
if (StartWriting) // 二回目以降は書込み
|
|
{
|
|
FileWriting();
|
|
if (!IsTesting()) {PipsObject();}
|
|
SpreadSum = 0;
|
|
TickCount = 0;
|
|
SpreadMax = 0;
|
|
SpreadMin = 0;
|
|
}
|
|
|
|
if (!StartWriting) // 初回は書き込みせずに終了
|
|
{
|
|
StartWriting = true;
|
|
SpreadSum = 0;
|
|
TickCount = 0;
|
|
SpreadMax = 0;
|
|
SpreadMin = 0;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| 書込み処理 |
|
|
//+------------------------------------------------------------------+
|
|
void FileWriting()
|
|
{
|
|
for(int i = 0; i < 3000; i++)
|
|
{
|
|
FileClose(filehandle); // ファイルが開きっぱなしで開けないエラーを防ぐ
|
|
filehandle = FileOpen(filename, FILE_READ|FILE_WRITE|FILE_CSV, ',');// ファイルオープン(csv)、失敗戻り値は-1
|
|
|
|
if (filehandle != INVALID_HANDLE)
|
|
{
|
|
FileSeek(filehandle, 0, SEEK_END); // ファイルの末尾に移動
|
|
FileWrite(filehandle, TimeToStr(iTime(NULL, 0, 1),TIME_DATE), TimeToStr(iTime(NULL, 0, 1),TIME_MINUTES),
|
|
DoubleToStr(SpreadMax, 1), DoubleToStr(SpreadMin, 1), DoubleToStr(SpreadAve, 2), TickCount);
|
|
FileClose(filehandle);
|
|
break;
|
|
}
|
|
}
|
|
if (filehandle == -1) Print("Error=", GetLastError(), " ファイルの書込み処理に失敗しました");
|
|
//if (filehandle == -1) Print("Error=", GetLastError(), " Failed to write file");
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| 書込みの時間制御 |
|
|
//+------------------------------------------------------------------+
|
|
bool isTime()
|
|
{
|
|
bool result = false;
|
|
if (StartHour == EndHour) {
|
|
if (StartMinute >= EndMinute) { // 23+ hour interval
|
|
if (Hour() != StartHour) {
|
|
result = true;
|
|
}
|
|
else {
|
|
if (Minute() >= StartMinute || Minute() < EndMinute) {
|
|
result = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else if (StartHour < EndHour) {
|
|
if (Hour() == StartHour) {
|
|
if (Minute() >= StartMinute) {
|
|
result = true;
|
|
}
|
|
}
|
|
else if (Hour() == EndHour) {
|
|
if (Minute() < EndMinute) {
|
|
result = true;
|
|
}
|
|
}
|
|
else if (Hour() > StartHour && Hour() < EndHour) {
|
|
result = true;
|
|
}
|
|
}
|
|
else { // StartHour > EndHour
|
|
if (Hour() == StartHour) {
|
|
if (Minute() >= StartMinute) {
|
|
result = true;
|
|
}
|
|
}
|
|
else if (Hour() == EndHour) {
|
|
if (Minute() < EndMinute) {
|
|
result = true;
|
|
}
|
|
}
|
|
else if (Hour() > StartHour || Hour() < EndHour) {
|
|
result = true;
|
|
}
|
|
}
|
|
return (result);
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| コメント部に計測データ表示 |
|
|
//+------------------------------------------------------------------+
|
|
void PipsObject()
|
|
{
|
|
// 1:00スプ考慮しない場合
|
|
string Data1 = "[Spread log (pips)]";
|
|
string Data2 = TimeToStr(iTime(NULL, 0, 1),TIME_DATE);
|
|
string Data3 = TimeToStr(iTime(NULL, 0, 1),TIME_MINUTES);
|
|
string Data4 = DoubleToStr(SpreadMax,1) + " [Max]";
|
|
string Data5 = SpreadMin==1000? "--- [Min]" : DoubleToStr(SpreadMin,1) + " [Min]";
|
|
string Data6 = DoubleToStr(SpreadAve,2) + " [Average]";
|
|
string Data7 = (string)TickCount + " [Volume]";
|
|
|
|
label("SP1", Data1, 4, 112, 8, clrWhite);
|
|
label("SP2", Data2, 4, 94, 8, clrWhite);
|
|
label("SP3", Data3, 4, 76, 8, clrWhite);
|
|
label("SP4", Data4, 4, 58, 8, clrWhite);
|
|
label("SP5", Data5, 4, 40, 8, clrWhite);
|
|
label("SP6", Data6, 4, 22, 8, clrWhite);
|
|
label("SP7", Data7, 4, 4, 8, clrWhite);
|
|
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
void label(string name, string label_text, int pos_x, int pos_y, int s, color clr= clrBlack)
|
|
{
|
|
pos_x = (int)NormalizeDouble(pos_x * DPIAdjust, 0); // 別途DPI換算コードで調整
|
|
pos_y = (int)NormalizeDouble(pos_y * DPIAdjust, 0); // 別途DPI換算コードで調整
|
|
|
|
ObjectCreate(name, OBJ_LABEL, 0, 0, 0);
|
|
ObjectSetString (0, name, OBJPROP_TEXT, label_text);
|
|
ObjectSetInteger(0, name, OBJPROP_FONTSIZE, s);
|
|
ObjectSetString (0, name, OBJPROP_FONT, "Segoe UI");
|
|
ObjectSetInteger(0, name, OBJPROP_CORNER, CORNER_RIGHT_LOWER);
|
|
ObjectSetInteger(0, name, OBJPROP_ANCHOR, ANCHOR_RIGHT_LOWER);
|
|
ObjectSetInteger(0, name, OBJPROP_XDISTANCE, pos_x);
|
|
ObjectSetInteger(0, name, OBJPROP_YDISTANCE, pos_y);
|
|
ObjectSetInteger(0, name, OBJPROP_COLOR, clr);
|
|
ObjectSetInteger(0, name, OBJPROP_BACK, true);
|
|
ObjectSetInteger(0, name, OBJPROP_SELECTABLE, false);
|
|
}
|
|
//+------------------------------------------------------------------+ |