gryps2/EA-code/TNK/VariableSpreadCSV.mq4
super.admin ae3f0ebf03 convert
2025-05-30 14:58:21 +02:00

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);
}
//+------------------------------------------------------------------+