oslib/tst/PST/P1_MQL5EMD/MQL5/Experts/TestEMD.mq5

163 lines
4.2 KiB
MQL5
Raw Permalink Normal View History

2025-05-30 16:15:18 +02:00
//+------------------------------------------------------------------+
//| TestEMD.mq5 |
//| Copyright (c) 2020, Marketeer |
//| https://www.mql5.com/en/users/marketeer |
//| https://www.mql5.com/ru/articles/7601 |
//+------------------------------------------------------------------+
#property copyright "Copyright (c) 2020 Marketeer"
#property link "https://www.mql5.com/en/users/marketeer"
#property version "1.0"
#property description "Test expert adviser for timeseries forecasting based on Empirical Mode Decomposition (EMD)"
// I N P U T S
input int Length = 200;
int Offset = 0;
input int Forecast = 2;
input int Reconstruction = 1;
input int SignalBar = -2;
input double Lot = 0.01;
const int deviation = 10;
const double sl = 0, tp = 0;
#include <MT4Bridge/MT4Orders.mqh>
// G L O B A L S
int handle;
double totalPlus, totalMinus;
int total, correct, skipped;
// E V E N T H A N D L E R S
int OnInit()
{
totalPlus = totalMinus = 0;
total = correct = skipped = 0;
if(Forecast <= 0) return INIT_PARAMETERS_INCORRECT;
if(SignalBar > 0) return INIT_PARAMETERS_INCORRECT;
Offset = SignalBar == 0 ? Forecast : 0;
handle = iCustom(_Symbol, _Period, "EMD", Length, Offset, Forecast, Reconstruction);
return handle == INVALID_HANDLE ? INIT_FAILED : INIT_SUCCEEDED;
}
void OnTick()
{
static datetime lastBar = 0;
const datetime now = iTime(NULL, 0, 0);
if(now == lastBar) return;
lastBar = now;
double mult = 0;
static double buffer[];
ArrayResize(buffer, Forecast + 1);
int result = CopyBuffer(handle, 0, SignalBar, Forecast + 1, buffer);
ArrayPrint(buffer);
if(SignalBar == 0)
{
if(result == Forecast + 1 && buffer[Forecast] != EMPTY_VALUE && buffer[0] != EMPTY_VALUE)
{
double forecast = (buffer[Forecast] - buffer[0]) / _Point;
static double open[];
ArrayResize(open, Forecast + 1);
CopyOpen(_Symbol, _Period, 0, Forecast + 1, open);
ArrayPrint(open);
double actual = (open[Forecast] - open[0]) / _Point;
mult = forecast * actual;
}
if(mult > 0)
{
correct++;
totalPlus += mult;
}
else if(mult < 0)
{
totalMinus -= mult;
}
else
{
skipped++;
}
Print(" ", (string)lastBar, " ", mult);
total++;
}
else
{
closeMarketOrders(iTime(_Symbol, _Period, Forecast - 1));
if(result == Forecast + 1 && buffer[Forecast] != EMPTY_VALUE && buffer[0] != EMPTY_VALUE)
{
if(buffer[Forecast] > buffer[0])
{
placeMarketOrder(OP_BUY);
}
else
{
placeMarketOrder(OP_SELL);
}
}
}
}
double OnTester()
{
if(totalPlus == 0) return 0;
if(skipped * 1.0 / total > 0.5) return 0;
return (totalMinus != 0) ? totalPlus / totalMinus : DBL_MAX;
}
void OnDeinit(const int r)
{
if(total > 0)
{
Print(correct, " (", skipped, ") / ", total, " = ", (float)(correct * 1.0 / total * 100), "%; PF ", (float)((totalMinus != 0) ? (totalPlus / totalMinus) : DBL_MAX));
}
}
// A U X F U N C T I O N S
void closeMarketOrders(const datetime olderThan = 0)
{
for(int i = OrdersTotal() - 1; i >= 0; i--)
{
if(OrderSelect(i, SELECT_BY_POS))
{
if((OrderType() == OP_BUY || OrderType() == OP_SELL))
{
if(olderThan > 0 && OrderOpenTime() >= olderThan) continue;
if(!OrderClose(OrderTicket(), OrderLots(), OrderClosePrice(), deviation))
{
Print("OrderClose failed for #", OrderTicket(), " ", OrderSymbol(), " with error ", GetLastError());
}
}
}
}
}
long placeMarketOrder(const int type)
{
static ENUM_SYMBOL_INFO_DOUBLE priceTypes[2] = {SYMBOL_ASK, SYMBOL_BID};
const double point = SymbolInfoDouble(_Symbol, SYMBOL_POINT);
const double tickSize = SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_SIZE);
double price = SymbolInfoDouble(_Symbol, priceTypes[type]);
price = MathRound(price / tickSize) * tickSize;
return OrderSend(_Symbol, type, Lot, price, deviation, sl, tp);
}