L1Trend/Experts/MovingAverageFilteredL1.mq5

349 lines
24 KiB
MQL5
Raw Permalink Normal View History

<EFBFBD><EFBFBD>//+------------------------------------------------------------------+
//| MovingAverageFilteredL1.mq5 |
//| Copyright 2000-2026, MetaQuotes Ltd. |
//| https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2000-2026, MetaQuotes Ltd."
#property link "https://www.mql5.com"
#property version "1.00"
//--- best MovingAverage parameters for EURUSD,H1,2025
input int MovingPeriod = 61; // MA period
input int MovingShift = 0; // MA shift
//--- trade volume
input double TradeLot = 0.1; // Lot size
//--- L1 filter parameters
input int L1TotalBars = 1000; // Total bars for L1 filter
input bool L1FilterOpen = false; // Use filter for Open
input bool L1FilterClose = false; // Use filter for Close
input double L1CoefLambda = 0.2; // Lambda in lambda_max units
//--- save statistics
input bool SaveStatistics = false; // Save statistics to file
//---
#define MA_MAGIC 1234501
#include <Trade\Trade.mqh>
CTrade ExtTrade;
int ExtHandle = INVALID_HANDLE;
bool ExtHedging = false;
string ExtStrategyName="MA";
string ExtStrategyFileName="";
//+------------------------------------------------------------------+
//| Check new bar |
//+------------------------------------------------------------------+
bool IsNewBar()
{
static datetime last_time = 0;
datetime t[1];
if(CopyTime(_Symbol,_Period,0,1,t) > 0)
{
if(t[0] != last_time)
{
last_time = t[0];
return true;
}
}
else
{
Print("CopyTime error: ", GetLastError());
ResetLastError();
}
return false;
}
//+------------------------------------------------------------------+
//| CheckTrendL1 |
//+------------------------------------------------------------------+
double CheckTrendL1()
{
int max_bars=L1TotalBars;
MqlRates rates_data[];
ArrayResize(rates_data,max_bars);
ArraySetAsSeries(rates_data,false);
if(CopyRates(_Symbol,_Period,0,max_bars,rates_data) != max_bars)
{
Print("CopyRates failed for L1Trend");
return 0;
}
//--- prepare data (close prices vector)
int data_count=max_bars;
vector<double> data_close;
data_close.Resize(data_count);
for(int i=0; i<data_count; i++)
data_close[i] = rates_data[i].close;
//--- calculate L1 filter
vector<double> data_filtered;
data_filtered.Resize(data_count);
double delta=0.0;
//double lambda_max=data_close.L1TrendFilterLambdaMax();
//bool res=data_close.L1TrendFilter(data_filtered,L1CoefLambda*lambda_max,false);
bool res=data_close.L1TrendFilter(data_filtered,L1CoefLambda,true);
if(res)
delta = data_filtered[data_count-1] - data_filtered[data_count-2];
//---
return delta;
}
//+------------------------------------------------------------------+
//| GetTradeSignal |
//+------------------------------------------------------------------+
bool GetTradeSignal(ENUM_ORDER_TYPE &signal)
{
signal = WRONG_VALUE;
MqlRates bars[];
double ma[];
ArraySetAsSeries(bars,true);
ArraySetAsSeries(ma,true);
ArrayResize(bars,2);
ArrayResize(ma,2);
//-- two last closed bars
if(CopyRates(_Symbol,_Period,2,2,bars) != 2)
{
Print("CopyRates failed");
return false;
}
if(CopyBuffer(ExtHandle,0,2,2,ma) != 2)
{
Print("CopyBuffer failed");
return false;
}
double close_prev = bars[1].close;
double close_last = bars[0].close;
double ma_prev = ma[1];
double ma_last = ma[0];
//--- check MA crossover
if(close_prev < ma_prev && close_last > ma_last)
signal = ORDER_TYPE_BUY;
else
if(close_prev > ma_prev && close_last < ma_last)
signal = ORDER_TYPE_SELL;
//--- log
PrintFormat("PrevBar: time=%s close=%.5f ma=%.5f | LastBar: time=%s close=%.5f ma=%.5f | Signal=%s",
TimeToString(bars[0].time,TIME_DATE|TIME_MINUTES), close_prev, ma_prev,
TimeToString(bars[1].time,TIME_DATE|TIME_MINUTES), close_last, ma_last,
(signal==ORDER_TYPE_BUY?"BUY":signal==ORDER_TYPE_SELL?"SELL":"NONE"));
//---
return true;
}
//+------------------------------------------------------------------+
//| CheckForOpen |
//+------------------------------------------------------------------+
void CheckForOpen()
{
ENUM_ORDER_TYPE signal;
if(!GetTradeSignal(signal))
return;
if(signal == WRONG_VALUE)
return;
//--- L1 filter
if(L1FilterOpen)
{
double delta = CheckTrendL1();
if(signal == ORDER_TYPE_BUY && delta < 0)
{
signal = WRONG_VALUE;
PrintFormat("Open BUY signal cancelled by L1 trend delta=%.5f", delta);
}
if(signal == ORDER_TYPE_SELL && delta > 0)
{
signal = WRONG_VALUE;
PrintFormat("Open SELL signal cancelled by L1 trend delta=%.5f", delta);
}
}
//---
if(signal == WRONG_VALUE)
return;
//---
if(!TerminalInfoInteger(TERMINAL_TRADE_ALLOWED) || Bars(_Symbol,_Period)<L1TotalBars)
return;
//---
double price = (signal==ORDER_TYPE_BUY) ? SymbolInfoDouble(_Symbol,SYMBOL_ASK): SymbolInfoDouble(_Symbol,SYMBOL_BID);
//---
ExtTrade.PositionOpen(_Symbol, signal, TradeLot, price, 0, 0);
}
//+------------------------------------------------------------------+
//| CheckForClose |
//+------------------------------------------------------------------+
void CheckForClose()
{
//--- check position
if(!PositionSelect(_Symbol))
return;
//--- check position magic
if(PositionGetInteger(POSITION_MAGIC)!=MA_MAGIC)
return;
//--- check trade signal
ENUM_ORDER_TYPE signal;
if(!GetTradeSignal(signal))
return;
//---
long type = PositionGetInteger(POSITION_TYPE);
bool close_signal = false;
//---
if(type == POSITION_TYPE_BUY && signal == ORDER_TYPE_SELL)
close_signal = true;
if(type == POSITION_TYPE_SELL && signal == ORDER_TYPE_BUY)
close_signal = true;
//--- check L1 filter
if(L1FilterClose)
{
double delta = CheckTrendL1();
if(type == POSITION_TYPE_BUY && delta > 0)
{
close_signal = false;
PrintFormat("Close BUY signal cancelled by L1 trend delta=%.5f", delta);
}
if(type == POSITION_TYPE_SELL && delta < 0)
{
close_signal = false;
PrintFormat("Close SELL signal cancelled by L1 trend delta=%.5f", delta);
}
}
//---
if(close_signal && TerminalInfoInteger(TERMINAL_TRADE_ALLOWED) && Bars(_Symbol,_Period)>=L1TotalBars)
ExtTrade.PositionClose(_Symbol,3);
}
//+------------------------------------------------------------------+
//| SelectPosition |
//+------------------------------------------------------------------+
bool SelectPosition()
{
bool res = false;
if(ExtHedging)
{
uint total = PositionsTotal();
for(uint i=0; i<total; i++)
{
string sym = PositionGetSymbol(i);
if(sym == _Symbol && PositionGetInteger(POSITION_MAGIC)==MA_MAGIC)
{
res = true;
break;
}
}
}
else
{
if(PositionSelect(_Symbol))
res = (PositionGetInteger(POSITION_MAGIC)==MA_MAGIC);
}
return res;
}
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
//--- check parameters
if(MovingPeriod<=0)
{
Print("Error: MovingPeriod parameter must be positive");
return(INIT_PARAMETERS_INCORRECT);
}
ExtHedging = (AccountInfoInteger(ACCOUNT_MARGIN_MODE)==ACCOUNT_MARGIN_MODE_RETAIL_HEDGING);
ExtTrade.SetExpertMagicNumber(MA_MAGIC);
ExtTrade.SetMarginMode();
ExtTrade.SetTypeFillingBySymbol(_Symbol);
//--- prepare indicator
ExtHandle = iMA(_Symbol,_Period,MovingPeriod,MovingShift,MODE_SMA,PRICE_CLOSE);
if(ExtHandle==INVALID_HANDLE)
{
Print("Failed to create MA handle");
return INIT_FAILED;
}
//--- prepare filename
ExtStrategyFileName=PrepareStrategyFileName(ExtStrategyName);
//--- delete old file if exists
if(FileIsExist(ExtStrategyFileName))
FileDelete(ExtStrategyFileName);
//---
return INIT_SUCCEEDED;
}
//+------------------------------------------------------------------+
//| PrepareStrategyFileName |
//+------------------------------------------------------------------+
string PrepareStrategyFileName(string strategy_name)
{
int v=0;
if(L1FilterOpen)
v=v | 1;
//---
if(L1FilterClose)
v=v | 2;
//---
string filename=IntegerToString(v)+"_"+strategy_name+"_"+_Symbol+".txt";
return filename;
}
//+------------------------------------------------------------------+
//| Save account statistics to file |
//+------------------------------------------------------------------+
void SaveAccountStatistics()
{
//--- check file name
if(ExtStrategyFileName=="")
return;
//---
int file=FileOpen(ExtStrategyFileName,FILE_WRITE|FILE_READ|FILE_TXT|FILE_SHARE_WRITE|FILE_ANSI);
if(file==INVALID_HANDLE)
{
Print("File open error: ",GetLastError());
return;
}
//--- append
FileSeek(file,0,SEEK_END);
//--- account data
double balance = AccountInfoDouble(ACCOUNT_BALANCE);
double equity = AccountInfoDouble(ACCOUNT_EQUITY);
double margin = AccountInfoDouble(ACCOUNT_MARGIN);
double free_margin = AccountInfoDouble(ACCOUNT_MARGIN_FREE);
double margin_lvl = AccountInfoDouble(ACCOUNT_MARGIN_LEVEL);
//--- volume
double volume=0.0;
if(PositionSelect(_Symbol))
volume=PositionGetDouble(POSITION_VOLUME);
//--- time
datetime t[1];
if(CopyTime(_Symbol,_Period,0,1,t)<=0)
{
FileClose(file);
return;
}
double current_close[1];
if(CopyClose(_Symbol,_Period,0,1,current_close)<=0)
{
FileClose(file);
return;
}
string line=StringFormat("%s;%.2f;%.2f;%.2f;%.2f;%.2f;%.2f;%f",TimeToString(t[0],TIME_DATE|TIME_SECONDS),
balance,equity,margin,free_margin,margin_lvl,volume,current_close[0]);
//---
FileWrite(file,line);
//---
FileClose(file);
}
//+------------------------------------------------------------------+
//| Expert OnTick function |
//+------------------------------------------------------------------+
void OnTick()
{
//--- trade only at new bar
if(!IsNewBar())
return;
//--- check trade conditions
if(SelectPosition())
CheckForClose();
else
CheckForOpen();
//--- save account statistics
if(SaveStatistics)
SaveAccountStatistics();
}
//+------------------------------------------------------------------+
//| Expert deinitialization function |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
//--- save account statistics
if(SaveStatistics)
SaveAccountStatistics();
//---
IndicatorRelease(ExtHandle);
}
//+------------------------------------------------------------------+