0% found this document useful (0 votes)
530 views23 pages

EA Studio EURUSD M15 1680673860

This document contains the code for an expert advisor created with the Expert Advisor Studio software. It includes risk disclosure statements, input parameters for trading signals, position management logic, and account/trade protections. The EA uses ADX, moving average crossover, and envelopes indicators to generate trading signals and manages open positions by checking for close signals, trailing stops, and session/news filters.

Uploaded by

macklean lionel
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as TXT, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
530 views23 pages

EA Studio EURUSD M15 1680673860

This document contains the code for an expert advisor created with the Expert Advisor Studio software. It includes risk disclosure statements, input parameters for trading signals, position management logic, and account/trade protections. The EA uses ADX, moving average crossover, and envelopes indicators to generate trading signals and manages open positions by checking for close signals, trailing stops, and session/news filters.

Uploaded by

macklean lionel
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as TXT, PDF, TXT or read online on Scribd
You are on page 1/ 23

//

// EA Studio Expert Advisor


//
// Created with: Expert Advisor Studio
// Website: https://studio.eatradingacademy.com/
//
// Copyright 2024, Forex Software Ltd.
//
// Risk Disclosure
//
// Futures and forex trading contains substantial risk and is not for every
investor.
// An investor could potentially lose all or more than the initial investment.
// Risk capital is money that can be lost without jeopardizing ones’ financial
security or life style.
// Only risk capital should be used for trading and only those with sufficient risk
capital should consider trading.

#property copyright "Forex Software Ltd."


#property version "6.0"
#property strict

static input string _Properties_ = "------"; // --- Expert Properties ---


static input int Magic_Number = 1680673860; // Magic number
static input double Entry_Amount = 0.10; // Entry lots
input int Stop_Loss = 38; // Stop Loss (pips)
input int Take_Profit = 65; // Take Profit (pips)

static input string ___0______ = "------"; // --- ADX ---


input int Ind0Param0 = 46; // Period
input double Ind0Param1 = 0.0; // Level

static input string ___1______ = "------"; // --- Moving Averages Crossover ---
input int Ind1Param0 = 24; // Fast MA period
input int Ind1Param1 = 42; // Slow MA period

static input string ___2______ = "------"; // --- Envelopes ---


input int Ind2Param0 = 10; // Period
input double Ind2Param1 = 0.15; // Deviation %

// "Entry protections" prevents new entry if a protection is activated


static input string Entry_prot__ = "------"; // --- Entry Protections ---
static input int Max_Spread = 0; // Max spread (points)
static input int Max_OpenPos = 0; // Max open positions
static input double Max_OpenLots = 0; // Max open lots

// "Account protections" stops the expert if a protection is activated


static input string Account_prot = "------"; // --- Account Protections ---
static input int MaxDailyLoss = 0; // Maximum daily loss (currency)
static input int Min_Equity = 0; // Minimum equity (currency)
static input int Max_Equity = 0; // Maximum equity (currency)

static input string _NewsFilter_ = "------"; // --- News Filter ---


enum NewsFilterPriority
{
NewsFilter_Disabled, // News filter disabled
NewsFilter_HighOnly, // High news filter
NewsFilter_HighAndMedium // Medium and High news filter
};
static input NewsFilterPriority News_Priority = NewsFilter_Disabled; // News
priority
static input string News_Currencies = "USD,EUR,JPY,GBP,CAD,AUD,CHF,NZD"; // News
currencies
static input int News_BeforeMedium = 2; // Before Medium news (minutes)
static input int News_AfterMedium = 2; // After Medium news (minutes)
static input int News_BeforeHigh = 2; // Before High news (minutes)
static input int News_AfterHigh = 5; // After High news (minutes)
static input int News_ViewCount = 10; // News records to show

static input string __Stats_____ = "------"; // --- Stats ---


static input bool Pos_Stat = true; // Position stats
static input bool Robot_Stats = true; // Robot stats

#define TRADE_RETRY_COUNT 4
#define TRADE_RETRY_WAIT 100
#define OP_FLAT -1

string robotTagline = "An Expert Advisor from Expert Advisor Studio";

// Session time is set in seconds from 00:00


int sessionSundayOpen = 0; // 00:00
int sessionSundayClose = 86400; // 24:00
int sessionMondayThursdayOpen = 0; // 00:00
int sessionMondayThursdayClose = 86400; // 24:00
int sessionFridayOpen = 0; // 00:00
int sessionFridayClose = 86400; // 24:00
bool sessionIgnoreSunday = true;
bool sessionCloseAtSessionClose = false;
bool sessionCloseAtFridayClose = false;

const double sigma = 0.000001;

int posType = OP_FLAT;


int posTicket = 0;
double posLots = 0;
double posStopLoss = 0;
double posTakeProfit = 0;
double posProfit = 0;
double posPriceOpen = 0;
double posPriceCurr = 0;

datetime lastStatsUpdate = 0;
datetime barTime;
double pip;
double stopLevel;
bool isTrailingStop=false;
bool setProtectionSeparately = false;

int maxRectangles = 0;
int maxLabels = 0;
int posStatCount = 0;
double posStatLots = 0;

string accountProtectionMessage = "";


string entryProtectionMessage = "";

struct NewsRecord
{
datetime time;
string priority;
string currency;
string title;
};

NewsRecord newsRecords[];
string newsCurrencies[];
datetime lastNewsUpdate = 0;
string loadNewsError = "";
bool isNewsFeedOk = true;

//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
int OnInit(void)
{
barTime = Time[0];
stopLevel = MarketInfo(_Symbol, MODE_STOPLEVEL);
pip = GetPipValue();
isTrailingStop = isTrailingStop && Stop_Loss > 0;
lastStatsUpdate = 0;

Comment("");
UpdatePosition();

ParseNewsCurrenciesText();
lastNewsUpdate = TimeCurrent();
if(!MQLInfoInteger(MQL_TESTER))
LoadNews();

DeleteObjects();

OnTick();
ChartRedraw(0);

return ValidateInit();
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
DeleteObjects();

if(accountProtectionMessage != "")
Comment(accountProtectionMessage);
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void DeleteObjects(void)
{
if(ObjectFind(0, "Stats_background") == 0)
ObjectDelete(0, "Stats_background");
maxLabels = MathMax(maxLabels, 35);
for(int i = 0; i < maxLabels; i += 1)
{
const string objName = "label" + IntegerToString(i);
if(ObjectFind(0, objName) == 0)
ObjectDelete(0, objName);
}
maxRectangles = 0;
maxLabels = 0;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void OnTick(void)
{
if(!MQLInfoInteger(MQL_TESTER))
{
CheckAccountProtection();
const datetime time = TimeCurrent();
if(time > lastStatsUpdate + 3)
{
lastStatsUpdate = time;
if(Max_OpenPos || Max_OpenLots)
SetPosStats();

UpdateStats();
}

if(time > lastNewsUpdate + 6*60*60 || !isNewsFeedOk)


{
lastNewsUpdate = time;
LoadNews();
}
}

const datetime time = Time(0);


if(time > barTime)
{
barTime = time;
OnBar();
}
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void OnBar(void)
{
UpdatePosition();

if(posType != OP_FLAT && IsForceSessionClose())


{
ClosePosition();
return;
}

if(IsOutOfSession())
return;

if(posType != OP_FLAT)
{
ManageClose();
UpdatePosition();
}

if(posType != OP_FLAT && isTrailingStop)


{
double trailingStop = GetTrailingStopPrice();
ManageTrailingStop(trailingStop);
UpdatePosition();
}

int entrySignal = GetEntrySignal();

if(posType == OP_FLAT && entrySignal != OP_FLAT)


{
OpenPosition(entrySignal);
UpdatePosition();
}
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void UpdatePosition(void)
{
posType = OP_FLAT;
posTicket = 0;
posLots = 0;
posProfit = 0;
posStopLoss = 0;
posTakeProfit = 0;
posPriceOpen = 0;
posPriceCurr = 0;

for(int pos = OrdersTotal() - 1; pos >= 0; pos -= 1)


{
if(OrderSelect(pos, SELECT_BY_POS) &&
OrderSymbol() == _Symbol &&
OrderMagicNumber() == Magic_Number)
{
posType = OrderType();
posTicket = OrderTicket();
posLots = OrderLots();
posProfit = OrderProfit();
posStopLoss = OrderStopLoss();
posTakeProfit = OrderTakeProfit();
posPriceOpen = NormalizeDouble(OrderOpenPrice(), _Digits);
posPriceCurr = NormalizeDouble(OrderClosePrice(), _Digits);
break;
}
}
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
int GetEntrySignal(void)
{
// ADX (46)
double ind0val1 = iADX(NULL, 0, Ind0Param0, PRICE_CLOSE, 0, 1);
double ind0val2 = iADX(NULL, 0, Ind0Param0, PRICE_CLOSE, 0, 2);
bool ind0long = ind0val1 > ind0val2 + sigma;
bool ind0short = ind0long;
// Moving Averages Crossover (Simple, Simple, 24, 42)
double ind1val1 = iMA(NULL, 0, Ind1Param0, 0, MODE_SMA, PRICE_CLOSE, 1);
double ind1val2 = iMA(NULL, 0, Ind1Param1, 0, MODE_SMA, PRICE_CLOSE, 1);
double ind1val3 = iMA(NULL, 0, Ind1Param0, 0, MODE_SMA, PRICE_CLOSE, 2);
double ind1val4 = iMA(NULL, 0, Ind1Param1, 0, MODE_SMA, PRICE_CLOSE, 2);
bool ind1long = ind1val1 > ind1val2 + sigma && ind1val3 < ind1val4 - sigma;
bool ind1short = ind1val1 < ind1val2 - sigma && ind1val3 > ind1val4 + sigma;

bool canOpenLong = ind0long && ind1long;


bool canOpenShort = ind0short && ind1short;

return canOpenLong && !canOpenShort ? OP_BUY


: canOpenShort && !canOpenLong ? OP_SELL
: OP_FLAT;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void ManageClose(void)
{
// Envelopes (Close, Simple, 10, 0.15)
double ind2upBand1 = iEnvelopes(NULL, 0, Ind2Param0, MODE_SMA, 0, PRICE_CLOSE,
Ind2Param1, MODE_UPPER, 1);
double ind2dnBand1 = iEnvelopes(NULL, 0, Ind2Param0, MODE_SMA, 0, PRICE_CLOSE,
Ind2Param1, MODE_LOWER, 1);
bool ind2long = Open(0) > ind2upBand1 + sigma;
bool ind2short = Open(0) < ind2dnBand1 - sigma;

if((posType == OP_BUY && ind2long) ||


(posType == OP_SELL && ind2short) )
ClosePosition();
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void OpenPosition(const int command)
{
entryProtectionMessage = "";
const int spread = (int)((Ask() - Bid()) / _Point);
if(Max_OpenPos > sigma && posStatCount > Max_OpenPos)
entryProtectionMessage += StringFormat("Protection: Max open positions: %d,
current: %d\n",
Max_OpenPos, posStatCount);
if(Max_OpenLots > sigma && posStatLots > Max_OpenLots)
entryProtectionMessage += StringFormat("Protection: Max open lots: %.2f,
current: %.2f\n",
Max_OpenLots, posStatLots);
if(Max_Spread > sigma && spread > Max_Spread)
entryProtectionMessage += StringFormat("Protection: Max spread: %d, current:
%d\n",
Max_Spread, spread);

const int newsIndex = NewsFilterActive();


if(newsIndex > -1)
{
const NewsRecord newsRecord = newsRecords[newsIndex];
const datetime timeShift = (datetime) MathRound((TimeLocal() - TimeGMT()) /
3600.0) * 3600;
const string priority = newsRecord.priority == "high" ? "[high]" :
"[med]";
entryProtectionMessage += StringFormat("News filter: %s %s %s %s\n",
priority,
TimeToString(newsRecord.time +
timeShift,
TIME_DATE | TIME_MINUTES),
newsRecord.currency,
newsRecord.title);
}

if(entryProtectionMessage != "")
{
entryProtectionMessage = TimeToString(TimeCurrent()) + " " +
"Entry order was canceled:\n" +
entryProtectionMessage;
return;
}

for(int attempt = 0; attempt < TRADE_RETRY_COUNT; attempt++)


{
int ticket = 0;
int lastError = 0;
bool modified = false;
string comment = IntegerToString(Magic_Number);
color arrowColor = command == OP_BUY ? clrGreen : clrRed;

if(IsTradeContextFree())
{
const double price = command == OP_BUY ? Ask() : Bid();
const double stopLoss = GetStopLossPrice(command);
const double takeProfit = GetTakeProfitPrice(command);

if(setProtectionSeparately)
{
// Send an entry order without SL and TP
ticket = OrderSend(_Symbol, command, Entry_Amount, price, 10, 0, 0,
comment, Magic_Number, 0, arrowColor);

// If the order is successful, modify the position with the


corresponding SL and TP
if(ticket > 0 && (Stop_Loss > 0 || Take_Profit > 0))
modified = OrderModify(ticket, 0, stopLoss, takeProfit, 0, clrBlue);
}
else
{
// Send an entry order with SL and TP
ticket = OrderSend(_Symbol, command, Entry_Amount, price, 10,
stopLoss, takeProfit, comment, Magic_Number, 0, arrowColor);
lastError = GetLastError();

// If order fails, check if it is because inability to set SL or TP


if(ticket <= 0 && lastError == 130)
{
// Send an entry order without SL and TP
ticket = OrderSend(_Symbol, command, Entry_Amount, price, 10, 0, 0,
comment, Magic_Number, 0, arrowColor);

// Try setting SL and TP


if(ticket > 0 && (Stop_Loss > 0 || Take_Profit > 0))
modified = OrderModify(ticket, 0, stopLoss, takeProfit, 0,
clrBlue);

// Mark the expert to set SL and TP with a separate order


if(ticket > 0 && modified)
{
setProtectionSeparately = true;
Print("Detected ECN type position protection.");
}
}
}
}

if(ticket > 0) break;

lastError = GetLastError();
if(lastError != 135 && lastError != 136 && lastError != 137 && lastError !=
138)
break;

Sleep(TRADE_RETRY_WAIT);
Print("Open Position retry no: " + IntegerToString(attempt + 2));
}
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void ClosePosition(void)
{
for(int attempt = 0; attempt < TRADE_RETRY_COUNT; attempt++)
{
bool closed;
int lastError = 0;

if(IsTradeContextFree())
{
const double price = posType == OP_BUY ? Bid() : Ask();
closed = OrderClose(posTicket, posLots, price, 10, clrYellow);
lastError = GetLastError();
}

if(closed) break;
if(lastError == 4108) break;

Sleep(TRADE_RETRY_WAIT);
Print("Close Position retry no: " + IntegerToString(attempt + 2));
}
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void ModifyPosition(void)
{
for(int attempt = 0; attempt < TRADE_RETRY_COUNT; attempt++)
{
bool modified;
int lastError = 0;
if(IsTradeContextFree())
{
modified = OrderModify(posTicket, 0, posStopLoss, posTakeProfit, 0,
clrBlue);
lastError = GetLastError();
}

if(modified)
break;

if(lastError == 4108) break;

Sleep(TRADE_RETRY_WAIT);
Print("Modify Position retry no: " + IntegerToString(attempt + 2));
}
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
double GetStopLossPrice(int command)
{
if(Stop_Loss == 0) return 0;

const double delta = MathMax(pip * Stop_Loss, _Point * stopLevel);


const double stopLoss = command == OP_BUY ? Bid() - delta : Ask() + delta;

return NormalizeDouble(stopLoss, _Digits);


}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
double GetTakeProfitPrice(int command)
{
if(Take_Profit == 0) return 0;

const double delta = MathMax(pip * Take_Profit, _Point * stopLevel);


const double takeProfit = command == OP_BUY ? Bid() + delta : Ask() - delta;

return NormalizeDouble(takeProfit, _Digits);


}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
double GetTrailingStopPrice(void)
{
const double bid = Bid();
const double ask = Ask();
const double spread = ask - bid;
const double stopLevelPoints = _Point * stopLevel;
const double stopLossPoints = pip * Stop_Loss;

if(posType == OP_BUY)
{
const double newStopLoss = High(1) - stopLossPoints;
if(posStopLoss <= newStopLoss - pip)
return newStopLoss < bid
? newStopLoss >= bid - stopLevelPoints
? bid - stopLevelPoints
: newStopLoss
: bid;
}

if(posType == OP_SELL)
{
const double newStopLoss = Low(1) + spread + stopLossPoints;
if(posStopLoss >= newStopLoss + pip)
return newStopLoss > ask
? newStopLoss <= ask + stopLevelPoints
? ask + stopLevelPoints
: newStopLoss
: ask;
}

return posStopLoss;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void ManageTrailingStop(double trailingStop)
{
if((posType == OP_BUY && MathAbs(trailingStop - Bid()) < _Point) ||
(posType == OP_SELL && MathAbs(trailingStop - Ask()) < _Point))
{
ClosePosition();
return;
}

if( MathAbs(trailingStop - posStopLoss) > _Point )


{
posStopLoss = NormalizeDouble(trailingStop, _Digits);
ModifyPosition();
}
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
double Bid(void)
{
return MarketInfo(_Symbol, MODE_BID);
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
double Ask(void)
{
return MarketInfo(_Symbol, MODE_ASK);
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
datetime Time(int bar)
{
return Time[bar];
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
double Open(int bar)
{
return Open[bar];
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
double High(int bar)
{
return High[bar];
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
double Low(int bar)
{
return Low[bar];
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
double Close(int bar)
{
return Close[bar];
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
double GetPipValue()
{
return _Digits == 4 || _Digits == 5 ? 0.0001
: _Digits == 2 || _Digits == 3 ? 0.01
: _Digits == 1 ? 0.1 : 1;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool IsTradeContextFree(void)
{
if(IsTradeAllowed())
return true;

const uint startWait = GetTickCount();


Print("Trade context is busy! Waiting...");

while(true)
{
if(IsStopped())
return false;

const uint diff = GetTickCount() - startWait;


if(diff > 30 * 1000)
{
Print("The waiting limit exceeded!");
return false;
}

if(IsTradeAllowed())
{
RefreshRates();
return true;
}

Sleep(TRADE_RETRY_WAIT);
}

return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool IsOutOfSession(void)
{
const int dayOfWeek = DayOfWeek();
const int periodStart = int(Time(0) % 86400);
const int periodLength = PeriodSeconds(_Period);
const int periodFix = periodStart + (sessionCloseAtSessionClose ?
periodLength : 0);
const int friBarFix = periodStart + (sessionCloseAtFridayClose ||
sessionCloseAtSessionClose ?
periodLength : 0);

return dayOfWeek == 0 && sessionIgnoreSunday ? true


: dayOfWeek == 0 ? periodStart < sessionSundayOpen ||
periodFix > sessionSundayClose
: dayOfWeek < 5 ? periodStart < sessionMondayThursdayOpen ||
periodFix > sessionMondayThursdayClose
: periodStart < sessionFridayOpen ||
friBarFix > sessionFridayClose;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool IsForceSessionClose(void)
{
if(!sessionCloseAtFridayClose && !sessionCloseAtSessionClose)
return false;

const int dayOfWeek = DayOfWeek();


const int periodEnd = int(Time(0) % 86400) + PeriodSeconds(_Period);

return dayOfWeek == 0 && sessionCloseAtSessionClose ? periodEnd >


sessionSundayClose
: dayOfWeek < 5 && sessionCloseAtSessionClose ? periodEnd >
sessionMondayThursdayClose
: dayOfWeek == 5 ? periodEnd > sessionFridayClose : false;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void CheckAccountProtection(void)
{
const double accountEquity = AccountInfoDouble(ACCOUNT_EQUITY);

if(Min_Equity > sigma && accountEquity < Min_Equity)


{
const string equityTxt = DoubleToString(accountEquity, 2);
const string message = "Minimum equity protection activated. Equity: " +
equityTxt;
ActivateProtection(message);
return;
}

if(Max_Equity > sigma && accountEquity >= Max_Equity)


{
const string equityTxt = DoubleToString(accountEquity, 2);
const string message = "Maximum equity protection activated. Equity: " +
equityTxt;
ActivateProtection(message);
return;
}

if(MaxDailyLoss > sigma)


{
const double dailyProfit = GetLastDaysProfit(1, -1);
if(dailyProfit < 0 && MathAbs(dailyProfit) >= MaxDailyLoss)
{
const string dailyProfitTxt = DoubleToString(MathAbs(dailyProfit), 2);
const string message = "Maximum daily loss protection activate! Daily
loss: " + dailyProfitTxt;
ActivateProtection(message);
return;
}
}
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
double GetLastDaysProfit(int days, int magic)
{
const datetime t0 = TimeCurrent();
const datetime t1 = t0 - 60*60*24;

double lastProfit = 0;

const int totalOrders = OrdersTotal();


for(int i = 0; i < totalOrders; i+=1)
{
if(OrderSelect(i, SELECT_BY_POS))
{
if((OrderCloseTime() > t1 && OrderCloseTime() <= t0) ||
OrderCloseTime() == 0)
{
const int ordType = OrderType();
if(ordType != OP_BUY && ordType != OP_SELL) continue;
if(magic > 0 && (OrderMagicNumber() != Magic_Number ||
OrderSymbol() != _Symbol)) continue;

lastProfit += OrderProfit() + OrderSwap() + OrderCommission();


}
}
}

return lastProfit;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void ActivateProtection(string message)
{
if(posType == OP_BUY || posType == OP_SELL)
ClosePosition();

DeleteObjects();

accountProtectionMessage = StringFormat("\n%s\nMagic number: %d\n",


robotTagline, Magic_Number);
accountProtectionMessage += message + "\n";
accountProtectionMessage += "Current position closed. ";
accountProtectionMessage += "Expert Advisor #" + IntegerToString(Magic_Number) +
" turned off.";
Comment(accountProtectionMessage);
Print(accountProtectionMessage);

Sleep(20 * 1000);
ExpertRemove();
OnDeinit(0);
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void SetPosStats(void)
{
posStatCount = 0;
posStatLots = 0;

for(int i = OrdersTotal() - 1; i >= 0; i -= 1)


{
if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
{
const int ordType = OrderType();
if(ordType != OP_BUY && ordType != OP_SELL) continue;

posStatCount += 1;
posStatLots += OrderLots();
}
}
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void UpdateStats(void)
{
string comment = StringFormat("\n%s\nMagic number %d\n", robotTagline,
Magic_Number);

if(entryProtectionMessage != "")
comment += "\n" + entryProtectionMessage;
if(Pos_Stat)
comment += GetPositionStats() + "\n";
if(Robot_Stats)
comment += GetRobotStats() + "\n";
if(Max_Spread || Max_OpenPos || Max_OpenLots || MaxDailyLoss || Min_Equity ||
Max_Equity)
comment += GetProtectionInfo();
if(News_Priority != NewsFilter_Disabled)
comment += GetNewsText() + "\n";
RenderStats(comment);
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
string GetProtectionInfo(void)
{
string protectionInfo = "\n ..:: Active Protections ::..\n";

if(Max_Spread)
protectionInfo += StringFormat("Max spread: %d, current: %d\n",
Max_Spread, (int)MathRound((Ask() - Bid()) /
_Point));
if(Max_OpenPos)
protectionInfo += StringFormat("Max open positions: %d, current: %d\n",
Max_OpenPos, posStatCount);
if(Max_OpenLots)
protectionInfo += StringFormat("Max open lots: %.2f, current: %.2f\n",
Max_OpenLots, posStatLots);
if(MaxDailyLoss)
protectionInfo += StringFormat("Max daily loss: %.2f, current: %.2f\n",
-MathAbs(MaxDailyLoss), GetLastDaysProfit(1, -
1));
if(Min_Equity)
protectionInfo += StringFormat("Min equity: %.2f, current: %.2f\n",
Min_Equity,
AccountInfoDouble(ACCOUNT_EQUITY));
if(Max_Equity)
protectionInfo += StringFormat("Max equity: %.2f, current: %.2f\n",
Max_Equity,
AccountInfoDouble(ACCOUNT_EQUITY));

return protectionInfo;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
string GetPositionStats(void)
{
const string positionStats = "\n ..:: Position Stats ::..\n";

if(posType==OP_FLAT)
return positionStats + "Position: no open position";

return positionStats +
StringFormat("Position: %s, Lots: %.2f, Profit %.2f\n",
(posType==OP_BUY) ? "Long" : "Short",
posLots, posProfit) +
StringFormat("Open price: %s, Current price: %s\n",
DoubleToString(posPriceOpen, _Digits),
DoubleToString(posPriceCurr, _Digits)) +
StringFormat("Stop Loss: %s, Take Profit: %s",
DoubleToString(posStopLoss, _Digits),
DoubleToString(posTakeProfit,_Digits));
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
string GetRobotStats(void)
{
return "\n ..:: Robot Stats ::..\n" +
"Today " + GetRobotStatsDays( 1) + "\n" +
"This Week " + GetRobotStatsDays( 7) + "\n" +
"This Month " + GetRobotStatsDays(30);
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
string GetRobotStatsDays(int days)
{
double grossProfit = 0;
double grossLoss = 0;
int histDealsCnt = 0;
double histDealsProfit = 0;

const datetime timeCurrent = TimeCurrent();


const datetime timeStart = timeCurrent - days*PeriodSeconds(PERIOD_D1);
const int deals = OrdersHistoryTotal();

for(int i = 0; i < deals; i += 1)


{
if(!OrderSelect(i, SELECT_BY_POS, MODE_HISTORY)) continue;
if(OrderCloseTime() < timeStart) continue;
const long dealMagic = OrderMagicNumber();
if(dealMagic != Magic_Number && dealMagic != 0) continue;
if(OrderSymbol() != _Symbol) continue;
const int ordType = OrderType();
if(ordType != OP_BUY && ordType != OP_SELL) continue;

const double profit = OrderProfit() + OrderSwap() + OrderCommission();

histDealsProfit += profit;
histDealsCnt += 1;

if(profit > sigma) grossProfit += profit;


if(profit < -sigma) grossLoss -= profit;
}

const double profitFactor = grossLoss > sigma ? grossProfit / grossLoss :


grossProfit;

return StringFormat("Trades: %d, Profit: %.2f, Profit factor: %.2f",


histDealsCnt, histDealsProfit, profitFactor);
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void RenderStats(string text)
{
string lines[];
const int linesCount = StringSplit(text, '\n', lines);

int lineWidth, lineHeight;


TextGetSize(robotTagline, lineWidth, lineHeight);

if(maxRectangles == 0)
RectLabelCreate(0, "Stats_background", 0, 0, 30, lineWidth,
linesCount * lineHeight, GetChartBackColor(0));

const color foreColor = GetChartForeColor(0);


for(int i = 0; i < linesCount; i += 1)
{
if(lines[i] == "")
lines[i] = " ";
string labelName = "label" + IntegerToString(i);
if(i < maxLabels)
LabelUpdate(0, labelName, lines[i]);
else
LabelCreate(0, labelName, 0, 10, 20 + i * lineHeight,
CORNER_LEFT_UPPER, lines[i], "Arial", 10, foreColor);

int lnWidth, lnHeight;


TextGetSize(lines[i], lnWidth, lnHeight);
if(lnWidth > lineWidth)
lineWidth = lnWidth;
}
ObjectSetInteger(0, "Stats_background", OBJPROP_XSIZE,
(int) MathRound(lineWidth * 0.90));
ObjectSetInteger(0, "Stats_background", OBJPROP_YSIZE,
linesCount * lineHeight);
for(int i = linesCount; i < maxLabels; i += 1)
LabelUpdate(0, "label" + IntegerToString(i), " ");
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void RectLabelCreate(
const long chartId = 0, // chart's ID
const string name = "RectLabel", // label name
const int sub_window = 0, // subwindow index
const int x = 0, // X coordinate
const int y = 0, // Y coordinate
const int width = 50, // width
const int height = 18, // height
const color back_clr = clrBlack, // background color
const ENUM_BORDER_TYPE border = BORDER_SUNKEN, // border type
const ENUM_BASE_CORNER corner = CORNER_LEFT_UPPER, // chart corner for
anchoring
const color clr = clrBlack, // flat border color
(Flat)
const ENUM_LINE_STYLE style = STYLE_SOLID, // flat border style
const int line_width = 0, // flat border width
const bool back = false, // in the background
const bool selection = false, // highlight to move
const bool hidden = true, // hidden in the object
list
const long z_order = 0) // priority for mouse
click
{
if(!ObjectCreate(chartId, name, OBJ_RECTANGLE_LABEL, sub_window, 0, 0)) return;
maxRectangles += 1;
ObjectSetInteger(chartId, name, OBJPROP_XDISTANCE, x);
ObjectSetInteger(chartId, name, OBJPROP_YDISTANCE, y);
ObjectSetInteger(chartId, name, OBJPROP_XSIZE, width);
ObjectSetInteger(chartId, name, OBJPROP_YSIZE, height);
ObjectSetInteger(chartId, name, OBJPROP_BGCOLOR, back_clr);
ObjectSetInteger(chartId, name, OBJPROP_BORDER_TYPE, border);
ObjectSetInteger(chartId, name, OBJPROP_CORNER, corner);
ObjectSetInteger(chartId, name, OBJPROP_COLOR, clr);
ObjectSetInteger(chartId, name, OBJPROP_STYLE, style);
ObjectSetInteger(chartId, name, OBJPROP_WIDTH, line_width);
ObjectSetInteger(chartId, name, OBJPROP_BACK, back);
ObjectSetInteger(chartId, name, OBJPROP_SELECTABLE, selection);
ObjectSetInteger(chartId, name, OBJPROP_SELECTED, selection);
ObjectSetInteger(chartId, name, OBJPROP_HIDDEN, hidden);
ObjectSetInteger(chartId, name, OBJPROP_ZORDER, z_order);
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void LabelCreate(
const long chartId=0, // chart's ID
const string name="Label", // label name
const int sub_window=0, // subwindow index
const int x=0, // X coordinate
const int y=0, // Y coordinate
const ENUM_BASE_CORNER corner=CORNER_LEFT_UPPER, // chart corner for anchoring
const string text="Label", // text
const string font="Arial", // font
const int font_size=10, // font size
const color clr=clrYellow, // color
const double angle=0.0, // text slope
const ENUM_ANCHOR_POINT anchor=ANCHOR_LEFT_UPPER, // anchor type
const bool back=false, // in the background
const bool selection=false, // highlight to move
const bool hidden=true, // hidden in the object list
const long z_order=0) // priority for mouse click
{
if(!ObjectCreate(chartId, name, OBJ_LABEL, sub_window, 0 , 0)) return;
maxLabels += 1;
ObjectSetInteger(chartId, name, OBJPROP_XDISTANCE, x);
ObjectSetInteger(chartId, name, OBJPROP_YDISTANCE, y);
ObjectSetInteger(chartId, name, OBJPROP_CORNER, corner);
ObjectSetString( chartId, name, OBJPROP_TEXT, text);
ObjectSetString( chartId, name, OBJPROP_FONT, font);
ObjectSetString( chartId, name, OBJPROP_TOOLTIP, "\n");
ObjectSetInteger(chartId, name, OBJPROP_FONTSIZE, font_size);
ObjectSetDouble( chartId, name, OBJPROP_ANGLE, angle);
ObjectSetInteger(chartId, name, OBJPROP_ANCHOR, anchor);
ObjectSetInteger(chartId, name, OBJPROP_COLOR, clr);
ObjectSetInteger(chartId, name, OBJPROP_BACK, back);
ObjectSetInteger(chartId, name, OBJPROP_SELECTABLE, selection);
ObjectSetInteger(chartId, name, OBJPROP_SELECTED, selection);
ObjectSetInteger(chartId, name, OBJPROP_HIDDEN, hidden);
ObjectSetInteger(chartId, name, OBJPROP_ZORDER, z_order);
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void LabelUpdate(int chartId, string name, string text)
{
ObjectSetString(chartId, name, OBJPROP_TEXT, text);
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
color GetChartForeColor(const long chartId=0)
{
long foreColor = clrWhite;
ChartGetInteger(chartId, CHART_COLOR_FOREGROUND, 0, foreColor);
return (color) foreColor;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
color GetChartBackColor(const long chartId=0)
{
long backColor = clrBlack;
ChartGetInteger(chartId, CHART_COLOR_BACKGROUND, 0, backColor);
return (color) backColor;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void LoadNews(void)
{
loadNewsError = "";
string error = "";
const string newsContent = GetNewsContent(error);
if(error != "")
{
loadNewsError = error;
return;
}

if(newsContent == "")
{
loadNewsError = StringFormat("Cannot load news. Last error code: %d",
GetLastError());
return;
}

ParseNewsContent(newsContent, error);

if(error != "")
loadNewsError = error;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void ParseNewsContent(string newsContent, string &error)
{
string lines[];
const int linesLen = StringSplit(newsContent, '\n', lines);

if(linesLen == -1)
{
error = "Cannot parse the news feed";
return;
}

ArrayResize(newsRecords, linesLen);

for(int i = 0; i < linesLen; i += 1)


{
string fields[];
const int fieldsLen = StringSplit(lines[i], ';', fields);

if(fieldsLen != 4)
{
error = "Cannot parse the news feed records";
return;
}

NewsRecord record;
record.time = (datetime) StringToInteger(fields[0]);
record.priority = fields[1];
record.currency = fields[2];
record.title = fields[3];

newsRecords[i] = record;
}
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
string GetNewsContent(string &error)
{
const string url = "https://forexsb.com/updates/news-feed.txt";

char reqBody[], resData[];


string headers;

ResetLastError();

const int resCode = WebRequest("GET", url, "", 10000, reqBody, resData,


headers);
const int resError = GetLastError();

isNewsFeedOk = false;
if(resError == ERR_FUNCTION_NOT_CONFIRMED)
{
error = "News Filter cannot access the news server.\n" +
"Follow these steps to fix it:\n"
" - open the \"Tool\" -> \"Options\" panel\n" +
" - go to the \"Expert Advisors\" tab\n" +
" - enable the \"Allow WebRequest for the listed URL:\" option.\n" +
" - add \"https://forexsb.com\" in a field below.";
return "";
}

if(resError != ERR_NO_MQLERROR)
{
error = StringFormat("News Filter connection error! Error code: %d",
resError);
return "";
}

if(resCode != 200)
{
error = StringFormat("Response code: %d", resCode);
return "";
}
isNewsFeedOk = true;
return CharArrayToString(resData, 0, ArraySize(resData), CP_UTF8);
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
string GetNewsText(void)
{
string newsText = "\n ..:: Upcoming News ::..\n";
if(loadNewsError != "") return newsText + loadNewsError;

const datetime timeNow = TimeGMT();


const datetime timeShift = (datetime) MathRound((TimeLocal() - timeNow) /
3600.0) * 3600;
const int newsCount = ArraySize(newsRecords);

for(int i = 0, count = 0; i < newsCount && count < News_ViewCount; i += 1)


{
const NewsRecord newsRecord = newsRecords[i];

if(newsRecord.time < timeNow - News_AfterHigh * 60 ||


!NewsIsAcceptedCurrency(newsRecord) ||
!NewsIsAcceptedPriority(newsRecord))
continue;

const string newLine = count > 0 ? "\n" : "";


const string newsTime = TimeToString(newsRecord.time + timeShift, TIME_DATE |
TIME_MINUTES);
const string priority = newsRecord.priority == "high" ? "[high]" : "[med]";
const string text = StringFormat("%s%s %s %s %s", newLine, priority,
newsTime,
newsRecord.currency, newsRecord.title);
StringAdd(newsText, text);
count += 1;
}

return newsText;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool NewsIsAcceptedCurrency(const NewsRecord &newsRecord)
{
for(int i = 0; i < ArraySize(newsCurrencies); i += 1)
if(newsCurrencies[i] == newsRecord.currency)
return true;

return false;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool NewsIsAcceptedPriority(const NewsRecord &newsRecord)
{
return (News_Priority == NewsFilter_HighAndMedium) ||
(News_Priority == NewsFilter_HighOnly && newsRecord.priority == "high");
}
//+------------------------------------------------------------------+
//| Gets the index of an active news or -1 |
//+------------------------------------------------------------------+
int NewsFilterActive()
{
if(News_Priority == NewsFilter_Disabled)
return -1;

const datetime timeUtc = TimeGMT();


const int newsLen = ArraySize(newsRecords);
for(int i = 0; i < newsLen; i += 1)
{
const NewsRecord news = newsRecords[i];
if(!NewsIsAcceptedCurrency(news) || !NewsIsAcceptedPriority(news))
continue;

if(news.priority == "high" &&


news.time - News_BeforeHigh * 60 - 15 <= timeUtc &&
news.time + News_AfterHigh * 60 - 15 >= timeUtc)
return i;

if(news.priority == "medium" &&


news.time - News_BeforeMedium * 60 - 15 <= timeUtc &&
news.time + News_AfterMedium * 60 - 15 >= timeUtc)
return i;
}

return -1;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void ParseNewsCurrenciesText()
{
string parts[], parsed[];
const int partsLen = StringSplit(News_Currencies, ',', parts);
ArrayResize(parsed, partsLen);
int len = 0;
for(int i = 0; i < partsLen; i += 1)
{
string part = parts[i];
StringReplace(part, " ", "");
if(StringLen(part) > 0)
{
parsed[i] = part;
len += 1;
}
}

ArrayResize(newsCurrencies, len);
for(int i = 0; i < len; i += 1)
newsCurrencies[i] = parsed[i];
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
ENUM_INIT_RETCODE ValidateInit()
{
return INIT_SUCCEEDED;
}
//+------------------------------------------------------------------+
/*STRATEGY MARKET Premium Data; EURUSD; M15 */
/*STRATEGY CODE {"properties":
{"entryLots":0.1,"tradeDirectionMode":0,"oppositeEntrySignal":0,"stopLoss":38,"take
Profit":65,"useStopLoss":true,"useTakeProfit":true,"isTrailingStop":false},"openFil
ters":[{"name":"ADX","listIndexes":[0,0,0,0,0],"numValues":[46,0,0,0,0,0]},
{"name":"Moving Averages Crossover","listIndexes":[0,0,0,0,0],"numValues":
[24,42,0,0,0,0]}],"closeFilters":[{"name":"Envelopes","listIndexes":
[0,3,0,0,0],"numValues":[10,0.15,0,0,0,0]}]} */

You might also like