Fix download links

This commit is contained in:
ironsan2kk-pixel
2026-06-08 10:36:15 +02:00
commit 6450d1efc6
138 changed files with 71156 additions and 0 deletions
Vendored
BIN
View File
Binary file not shown.
View File
+96
View File
@@ -0,0 +1,96 @@
//+------------------------------------------------------------------+
//| GridEA.mq4 |
//| Copyright 2018, Valentinos Galanos <sonidelav@hotmail.com> |
//+------------------------------------------------------------------+
#define ver "1.00"
#property copyright "Copyright 2018, Valentinos Galanos <sonidelav@hotmail.com>"
#property version ver
#property strict
//--- input parameters
input int GridGap = 50; // Grid Gap (Pips)
input double LotSize = 0.01; // Trade Lot Volume
input int TotalGridLines = 7; // Total Grid Lines Each Side
//--- Includes
#include "Library\GridExpert.mqh"
//--- Expert
CGridExpert* GridEA;
//--- Memory
bool initialized=false;
bool timerCalled=false;
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
//--- create timer
EventSetMillisecondTimer(500);
if( initialized == false )
{
initialized = true;
GridEA = new CGridExpert;
return GridEA.OnInit();
}
//---
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Expert deinitialization function |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
//--- destroy timer
EventKillTimer();
switch(reason)
{
case REASON_CLOSE:
case REASON_INITFAILED:
case REASON_RECOMPILE:
case REASON_REMOVE:
case REASON_ACCOUNT:
case REASON_CHARTCLOSE:
case REASON_PROGRAM:
if( initialized && GridEA != NULL)
{
GridEA.OnDeinit(reason);
initialized = false;
delete GridEA;
}
break;
}
}
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick()
{
//---
if( initialized && GridEA != NULL )
{
GridEA.OnTick();
}
}
//+------------------------------------------------------------------+
//| Timer function |
//+------------------------------------------------------------------+
void OnTimer()
{
if(timerCalled == false)
{
timerCalled = true;
//---
if( initialized && GridEA != NULL )
{
GridEA.OnTimer();
}
timerCalled = false;
}
}
//+------------------------------------------------------------------+
Binary file not shown.
+332
View File
@@ -0,0 +1,332 @@
//+------------------------------------------------------------------+
//| GridMaster Pro.mq5 |
//| Copyright 2024, Sajid. |
//| https://www.mql5.com/en/users/sajidmahamud835 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2024, Sajid."
#property link "https://www.mql5.com/en/users/sajidmahamud835"
#property version "2.00"
#property strict
#property description "GridMaster Pro v2 — Bi-directional ATR grid with proper MM, min-stop awareness, and drawdown protection."
#include <Trade\Trade.mqh>
//--- Enums
enum ENUM_GRID_MODE {
GRID_NEUTRAL = 0, // Neutral: BUY below + SELL above
GRID_BULLISH = 1, // Bullish: BUY only
GRID_BEARISH = 2, // Bearish: SELL only
};
enum ENUM_LOT_MODE {
LOT_FIXED = 0, // Fixed lot size
LOT_DYNAMIC = 1, // Risk-based (% of balance per order)
};
//--- Input Parameters — Grid
input ENUM_GRID_MODE GridMode = GRID_NEUTRAL; // Grid Mode
input int MaxOrders = 5; // Max orders per side
input int ATRPeriod = 14; // ATR period
input double ATRMultiplier = 1.5; // ATR multiplier for grid distance
//--- Input Parameters — Orders
input ENUM_LOT_MODE LotMode = LOT_FIXED; // Lot sizing mode
input double LotSize = 0.1; // Fixed lot size
input double RiskPercent = 1.0; // Risk % per order (dynamic mode)
input bool UseTakeProfit = true; // Enable Take Profit
input double DefaultTP = 200.0; // Min TP in points (auto-adjusted for broker)
input bool UseStopLoss = true; // Enable Stop Loss
input double DefaultSL = 1000.0; // Min SL in points (auto-adjusted for broker)
input bool UseTrailingStop = true; // Enable Trailing Stop
input double TrailingPoints = 100.0; // Trailing stop in points
input double TrailingStep = 20.0; // Trailing step in points
//--- Input Parameters — Risk Management
input double MaxDrawdownPct = 5.0; // Max drawdown % before pausing
input bool CloseOnDrawdown = true; // Close all orders on drawdown breach
//--- Input Parameters — Magic & Debug
input int MagicBase = 47291; // Base magic number
input bool DebugMode = false; // Enable debug logging
//--- Global Variables
CTrade trade;
int magicNumber;
double gridDistance;
double accountEquityStart;
bool gridPaused = false;
string logFile;
//+------------------------------------------------------------------+
//| Expert initialization |
//+------------------------------------------------------------------+
int OnInit() {
// Generate collision-safe magic number: base + symbol hash + timeframe
magicNumber = MagicBase + (int)(StringLen(_Symbol) * 1000) + (int)Period();
trade.SetExpertMagicNumber(magicNumber);
trade.SetDeviationInPoints(50);
trade.SetTypeFilling(ORDER_FILLING_IOC);
accountEquityStart = AccountInfoDouble(ACCOUNT_EQUITY);
logFile = "GridMasterPro_" + _Symbol + "_" + IntegerToString(Period()) + ".log";
WriteLog("GridMaster Pro v2.00 initialized | Magic: " + IntegerToString(magicNumber) +
" | Symbol: " + _Symbol + " | Grid mode: " + EnumToString(GridMode));
return INIT_SUCCEEDED;
}
//+------------------------------------------------------------------+
//| Expert deinitialization |
//+------------------------------------------------------------------+
void OnDeinit(const int reason) {
WriteLog("EA deinitialized. Reason: " + IntegerToString(reason) + " | Open positions left: " + IntegerToString(CountOurPositions(ORDER_TYPE_BUY) + CountOurPositions(ORDER_TYPE_SELL)));
}
//+------------------------------------------------------------------+
//| Expert tick |
//+------------------------------------------------------------------+
void OnTick() {
// Drawdown check
if (CloseOnDrawdown && CheckDrawdown()) {
if (!gridPaused) {
WriteLog("DRAWDOWN LIMIT REACHED — closing all positions and pausing grid");
CloseAllPositions();
gridPaused = true;
}
return;
}
// Resume grid if paused and equity has recovered
if (gridPaused) {
double currentEquity = AccountInfoDouble(ACCOUNT_EQUITY);
if (currentEquity >= accountEquityStart * (1.0 - MaxDrawdownPct / 200.0)) {
gridPaused = false;
accountEquityStart = currentEquity;
WriteLog("Grid resumed after equity recovery");
} else {
return;
}
}
// Recalculate grid distance every tick
gridDistance = CalculateGridDistance();
if (gridDistance <= 0) return;
double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);
double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
int buyCount = CountOurPositions(ORDER_TYPE_BUY);
int sellCount = CountOurPositions(ORDER_TYPE_SELL);
// Manage trailing stops
if (UseTrailingStop) ManageTrailingStops();
// Place BUY grid orders
if (GridMode != GRID_BEARISH && buyCount < MaxOrders) {
double buyPrice = ask - gridDistance * (buyCount + 1) * _Point;
PlaceGridOrder(ORDER_TYPE_BUY, buyPrice);
}
// Place SELL grid orders
if (GridMode != GRID_BULLISH && sellCount < MaxOrders) {
double sellPrice = bid + gridDistance * (sellCount + 1) * _Point;
PlaceGridOrder(ORDER_TYPE_SELL, sellPrice);
}
}
//+------------------------------------------------------------------+
//| Place a grid order with proper SL/TP |
//+------------------------------------------------------------------+
void PlaceGridOrder(ENUM_ORDER_TYPE type, double price) {
// Check if order already exists near this price level
if (OrderExistsNearPrice(type, price, gridDistance * 0.5 * _Point)) return;
// Broker minimum stop distance
long stopLevel = SymbolInfoInteger(_Symbol, SYMBOL_TRADE_STOPS_LEVEL);
double minStop = MathMax((double)stopLevel, 10.0) * _Point * 1.2; // 20% buffer over broker min
double sl = 0, tp = 0;
double lot = CalculateLot();
if (type == ORDER_TYPE_BUY) {
if (UseTakeProfit) tp = price + MathMax(DefaultTP * _Point, minStop * 1.5);
if (UseStopLoss) sl = price - MathMax(DefaultSL * _Point, minStop * MaxOrders);
} else {
if (UseTakeProfit) tp = price - MathMax(DefaultTP * _Point, minStop * 1.5);
if (UseStopLoss) sl = price + MathMax(DefaultSL * _Point, minStop * MaxOrders);
}
// Normalize prices
int digits = (int)SymbolInfoInteger(_Symbol, SYMBOL_DIGITS);
price = NormalizeDouble(price, digits);
sl = sl > 0 ? NormalizeDouble(sl, digits) : 0;
tp = tp > 0 ? NormalizeDouble(tp, digits) : 0;
bool sent;
if (type == ORDER_TYPE_BUY) {
sent = trade.Buy(lot, _Symbol, 0, sl, tp, "Grid BUY");
} else {
sent = trade.Sell(lot, _Symbol, 0, sl, tp, "Grid SELL");
}
if (sent) {
WriteLog("Placed " + (type == ORDER_TYPE_BUY ? "BUY" : "SELL") +
" | Lot: " + DoubleToString(lot, 2) +
" | Price: ~" + DoubleToString(price, digits) +
" | SL: " + DoubleToString(sl, digits) +
" | TP: " + DoubleToString(tp, digits));
} else {
WriteLog("FAILED to place " + (type == ORDER_TYPE_BUY ? "BUY" : "SELL") +
" | Error: " + IntegerToString(GetLastError()) +
" | Price: " + DoubleToString(price, digits) +
" | MinStop: " + DoubleToString(minStop / _Point, 0) + " pts");
}
}
//+------------------------------------------------------------------+
//| Manage trailing stops for all our positions |
//+------------------------------------------------------------------+
void ManageTrailingStops() {
double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);
double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
int digits = (int)SymbolInfoInteger(_Symbol, SYMBOL_DIGITS);
long stopLevel = SymbolInfoInteger(_Symbol, SYMBOL_TRADE_STOPS_LEVEL);
double minStop = MathMax((double)stopLevel, 10.0) * _Point * 1.2;
for (int i = PositionsTotal() - 1; i >= 0; i--) {
if (!PositionSelectByTicket(PositionGetTicket(i))) continue;
if (PositionGetString(POSITION_SYMBOL) != _Symbol) continue;
if (PositionGetInteger(POSITION_MAGIC) != magicNumber) continue;
ENUM_POSITION_TYPE posType = (ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);
double openPrice = PositionGetDouble(POSITION_PRICE_OPEN);
double currentSL = PositionGetDouble(POSITION_SL);
ulong ticket = PositionGetInteger(POSITION_TICKET);
double newSL = 0;
if (posType == POSITION_TYPE_BUY) {
double profit = bid - openPrice;
if (profit >= TrailingPoints * _Point) {
newSL = NormalizeDouble(bid - TrailingPoints * _Point, digits);
if (newSL > currentSL + TrailingStep * _Point && newSL > openPrice - minStop) {
trade.PositionModify(ticket, newSL, PositionGetDouble(POSITION_TP));
}
}
} else {
double profit = openPrice - ask;
if (profit >= TrailingPoints * _Point) {
newSL = NormalizeDouble(ask + TrailingPoints * _Point, digits);
if ((currentSL == 0 || newSL < currentSL - TrailingStep * _Point) && newSL < openPrice + minStop) {
trade.PositionModify(ticket, newSL, PositionGetDouble(POSITION_TP));
}
}
}
}
}
//+------------------------------------------------------------------+
//| Calculate ATR-based grid distance in points |
//+------------------------------------------------------------------+
double CalculateGridDistance() {
double atr = iATR(_Symbol, 0, ATRPeriod);
if (atr <= 0) return 0;
return (atr * ATRMultiplier) / _Point; // Return in points
}
//+------------------------------------------------------------------+
//| Calculate lot size based on mode |
//+------------------------------------------------------------------+
double CalculateLot() {
if (LotMode == LOT_FIXED) return LotSize;
double balance = AccountInfoDouble(ACCOUNT_BALANCE);
double tickValue = SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_VALUE);
double tickSize = SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_SIZE);
if (tickValue <= 0 || tickSize <= 0 || DefaultSL <= 0) return LotSize;
double riskAmount = balance * RiskPercent / 100.0;
double slValue = DefaultSL * _Point / tickSize * tickValue;
double lot = NormalizeDouble(riskAmount / slValue, 2);
double minLot = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MIN);
double maxLot = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MAX);
double lotStep = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_STEP);
lot = MathMax(minLot, MathMin(maxLot, MathRound(lot / lotStep) * lotStep));
return lot;
}
//+------------------------------------------------------------------+
//| Count our open positions by type |
//+------------------------------------------------------------------+
int CountOurPositions(ENUM_ORDER_TYPE type) {
int count = 0;
for (int i = PositionsTotal() - 1; i >= 0; i--) {
if (!PositionSelectByTicket(PositionGetTicket(i))) continue;
if (PositionGetString(POSITION_SYMBOL) != _Symbol) continue;
if (PositionGetInteger(POSITION_MAGIC) != magicNumber) continue;
ENUM_POSITION_TYPE posType = (ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);
if ((type == ORDER_TYPE_BUY && posType == POSITION_TYPE_BUY) ||
(type == ORDER_TYPE_SELL && posType == POSITION_TYPE_SELL)) {
count++;
}
}
return count;
}
//+------------------------------------------------------------------+
//| Check if order already exists near a price level |
//+------------------------------------------------------------------+
bool OrderExistsNearPrice(ENUM_ORDER_TYPE type, double price, double tolerance) {
for (int i = PositionsTotal() - 1; i >= 0; i--) {
if (!PositionSelectByTicket(PositionGetTicket(i))) continue;
if (PositionGetString(POSITION_SYMBOL) != _Symbol) continue;
if (PositionGetInteger(POSITION_MAGIC) != magicNumber) continue;
ENUM_POSITION_TYPE posType = (ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);
if ((type == ORDER_TYPE_BUY && posType == POSITION_TYPE_BUY) ||
(type == ORDER_TYPE_SELL && posType == POSITION_TYPE_SELL)) {
double openPrice = PositionGetDouble(POSITION_PRICE_OPEN);
if (MathAbs(openPrice - price) <= tolerance) return true;
}
}
return false;
}
//+------------------------------------------------------------------+
//| Check if drawdown limit breached |
//+------------------------------------------------------------------+
bool CheckDrawdown() {
double equity = AccountInfoDouble(ACCOUNT_EQUITY);
double maxLoss = accountEquityStart * MaxDrawdownPct / 100.0;
return (accountEquityStart - equity) >= maxLoss;
}
//+------------------------------------------------------------------+
//| Close all our positions |
//+------------------------------------------------------------------+
void CloseAllPositions() {
for (int i = PositionsTotal() - 1; i >= 0; i--) {
ulong ticket = PositionGetTicket(i);
if (!PositionSelectByTicket(ticket)) continue;
if (PositionGetString(POSITION_SYMBOL) != _Symbol) continue;
if (PositionGetInteger(POSITION_MAGIC) != magicNumber) continue;
trade.PositionClose(ticket);
}
}
//+------------------------------------------------------------------+
//| Append log to file (fixes overwrite bug) |
//+------------------------------------------------------------------+
void WriteLog(string message) {
if (!DebugMode && StringFind(message, "FAILED") < 0 && StringFind(message, "DRAWDOWN") < 0) return;
int handle = FileOpen(logFile, FILE_READ | FILE_WRITE | FILE_TXT | FILE_COMMON);
if (handle != INVALID_HANDLE) {
FileSeek(handle, 0, SEEK_END); // Append — seek to end
string ts = TimeToString(TimeCurrent(), TIME_DATE | TIME_MINUTES | TIME_SECONDS);
FileWriteString(handle, ts + " | " + message + "\n");
FileClose(handle);
}
}
Binary file not shown.
Binary file not shown.
Binary file not shown.
+1
View File
@@ -0,0 +1 @@
//Pending: Awaiting confirmation on whether it will be released for free or as a paid-only option.
Binary file not shown.
+540
View File
@@ -0,0 +1,540 @@
//+------------------------------------------------------------------+
//| Biased Martingale.mq4 |
//| Matthew Kastor |
//| https://github.com/matthewkastor |
//+------------------------------------------------------------------+
#property copyright "Matthew Kastor"
#property link "https://github.com/matthewkastor"
#property version "1.00"
#property strict
bool TestDisabled=false;
//+------------------------------------------------------------------+
//|Enumeration to indicate directional bias. |
//+------------------------------------------------------------------+
enum Enum_Direction
{
BUYING,
SELLING,
NONE
};
Enum_Direction Direction=NONE;
input double StartFactor=0.5;
input double IncreaseFactor=2;
input ENUM_TIMEFRAMES BiasTimeframe=PERIOD_D1;
input int BiasPeriod=20;
input int BiasLookback=12;
input ENUM_DAY_OF_WEEK StartDay=SUNDAY;
input ENUM_DAY_OF_WEEK EndDay=SUNDAY;
input int StartHour=0;
input int EndHour=0;
datetime lastBarTime=0;
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Expert deinitialization function |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
}
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick()
{
if(IsTesting() && TestDisabled==true)
{
return;
}
PositionManagement();
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool IsTimeBetween(int startDay,int startHour,int endDay,int endHour)
{
if((startDay==endDay) && (startHour==endHour))
{
// The schedule starts and ends at the same time, it is neither
// day trading nor night trading... so it's always trading because
// never trading is as simple as removing the EA.
return true;
}
int D=TimeDayOfWeek(TimeCurrent());
int H=TimeHour(TimeCurrent());
if((startDay<=D) && (endDay>=D) && (startHour<=H) && (endHour>=H))
{
//Print(StartDay+" "+StartHour+" < "+D+" "+H+" < "+EndDay+" "+EndHour);
return true;
}
//Print(StartDay+" "+StartHour+" > "+D+" "+H+" > "+EndDay+" "+EndHour);
return false;
}
//+------------------------------------------------------------------+
//|Gets the profit of the last closed order. |
//+------------------------------------------------------------------+
double PairProfitSince(string symbol,int secondsAgo)
{
double num=0;
for(int i=OrdersHistoryTotal()-1;i>=0;i--)
{
if(OrderSelect(i,SELECT_BY_POS,MODE_HISTORY) && OrderSymbol()==symbol && (OrderType()==OP_BUY || OrderType()==OP_SELL))
{
if(OrderCloseTime()>(Time[0]-secondsAgo))
{
num+=OrderProfit();
}
}
}
return num;
}
//+------------------------------------------------------------------+
//|Gets the total size on the given currency pair. |
//+------------------------------------------------------------------+
double PairLotsTotal(string symbol)
{
double num=0;
for(int i=0;i<OrdersTotal();i++)
{
if(OrderSelect(i,SELECT_BY_POS,MODE_TRADES) && OrderSymbol()==symbol && (OrderType()==OP_BUY || OrderType()==OP_SELL))
{
num=num+OrderLots();
}
}
return num;
}
//+------------------------------------------------------------------+
//|Gets the current average price paid for the given currency pair. |
//+------------------------------------------------------------------+
double PairAveragePrice(string symbol)
{
double num=0;
double sum=0;
for(int i=0;i<OrdersTotal();i++)
{
if(OrderSelect(i,SELECT_BY_POS,MODE_TRADES) && OrderSymbol()==symbol && (OrderType()==OP_BUY || OrderType()==OP_SELL))
{
sum=sum+OrderOpenPrice() * OrderLots();
num=num+OrderLots();
}
}
if(num>0 && sum>0)
{
return (sum / num);
}
else
{
return 0;
}
}
//+------------------------------------------------------------------+
//|Gets the lowest price paid for any order on the given pair. |
//+------------------------------------------------------------------+
double PairLowestPricePaid(string symbol)
{
double num=0;
for(int i=0;i<OrdersTotal();i++)
{
if(OrderSelect(i,SELECT_BY_POS,MODE_TRADES) && OrderSymbol()==symbol && (OrderType()==OP_BUY || OrderType()==OP_SELL))
{
if(num==0 || OrderOpenPrice()<num)
{
num=OrderOpenPrice();
}
}
}
return num;
}
//+------------------------------------------------------------------+
//|Gets the highest price paid for any order on the given pair. |
//+------------------------------------------------------------------+
double PairHighestPricePaid(string symbol)
{
double num=0;
for(int i=0;i<OrdersTotal();i++)
{
if(OrderSelect(i,SELECT_BY_POS,MODE_TRADES) && OrderSymbol()==symbol && (OrderType()==OP_BUY || OrderType()==OP_SELL))
{
if(num==0 || OrderOpenPrice()>num)
{
num=OrderOpenPrice();
}
}
}
return num;
}
//+------------------------------------------------------------------+
//|Gets the direction the given symbol is already traded in. |
//+------------------------------------------------------------------+
Enum_Direction PairDirection(string symbol)
{
for(int i=0;i<OrdersTotal();i++)
{
if(OrderSelect(i,SELECT_BY_POS,MODE_TRADES) && OrderSymbol()==symbol && (OrderType()==OP_BUY || OrderType()==OP_SELL))
{
if(OrderType()==OP_BUY)
{
return BUYING;
}
else
{
return SELLING;
}
}
}
return NONE;
}
//+------------------------------------------------------------------+
//|Closes all open orders on the given currency pair. |
//+------------------------------------------------------------------+
void CloseOpenOrders(string symbol)
{
double bid = MarketInfo(symbol, MODE_BID);
double ask = MarketInfo(symbol, MODE_ASK);
while(PairLotsTotal(symbol)>0)
{
for(int i=0;i<OrdersTotal();i++)
{
if(OrderSelect(i,SELECT_BY_POS,MODE_TRADES) && OrderSymbol()==symbol)
{
if(OrderType()==OP_BUY)
{
bool ret=OrderClose(OrderTicket(),OrderLots(),bid,0);
if(!ret)
{
PrintFormat("Attempt to CLOSE ticket %25.0i for %2.2f %s @ %2.5f failed. (mql error %5.0i)",OrderTicket(),OrderLots(),symbol,bid,GetLastError());
}
}
else if(OrderType()==OP_SELL)
{
bool ret=OrderClose(OrderTicket(),OrderLots(),ask,0);
if(!ret)
{
PrintFormat("Attempt to CLOSE ticket %25.0i for %2.2f %s @ %2.5f failed. (mql error %5.0i)",OrderTicket(),OrderLots(),symbol,ask,GetLastError());
}
}
}
}
}
}
//+------------------------------------------------------------------+
//|set stop loss on all open orders on the given currency pair. |
//+------------------------------------------------------------------+
void SetStopLossOpenOrders(string symbol)
{
double bid = MarketInfo(symbol, MODE_BID);
double ask = MarketInfo(symbol, MODE_ASK);
double pa = PairAveragePrice(symbol);
double sl = 0;
for(int i=0;i<OrdersTotal();i++)
{
if(OrderSelect(i,SELECT_BY_POS,MODE_TRADES) && OrderSymbol()==symbol)
{
if(OrderType()==OP_BUY)
{
sl=NormalizeDouble((bid+pa)/2,Digits);
if(OrderStopLoss()==0 || sl>OrderStopLoss())
{
bool ret=OrderModify(OrderTicket(),OrderOpenPrice(),sl,OrderTakeProfit(),0);
if(!ret)
{
PrintFormat("Attempt to set stop loss on ticket %25.0i for %2.2f %s @ %2.5f failed. (mql error %5.0i)",OrderTicket(),OrderLots(),symbol,bid,GetLastError());
}
}
}
else if(OrderType()==OP_SELL)
{
sl=NormalizeDouble((ask+pa)/2,Digits);
if(OrderStopLoss()==0 || sl<OrderStopLoss())
{
bool ret=OrderModify(OrderTicket(),OrderOpenPrice(),sl,OrderTakeProfit(),0);
if(!ret)
{
PrintFormat("Attempt to set stop loss on ticket %25.0i for %2.2f %s @ %2.5f failed. (mql error %5.0i)",OrderTicket(),OrderLots(),symbol,ask,GetLastError());
}
}
}
}
}
}
//+------------------------------------------------------------------+
//|Opens an order on the given currency pair. |
//+------------------------------------------------------------------+
void OpenOrder(string symbol,Enum_Direction buyingOrSelling)
{
double bid = MarketInfo(symbol, MODE_BID);
double ask = MarketInfo(symbol, MODE_ASK);
double minLot=MarketInfo(symbol,MODE_MINLOT);
double maxLot=MarketInfo(symbol,MODE_MAXLOT);
double orderSize=PairLotsTotal(symbol)*IncreaseFactor;
//double riskFactor = (20 / iADX(symbol,PERIOD_W1,104,PRICE_CLOSE,MODE_MAIN,0));
double riskFactor=1;
if(orderSize<minLot)
{
double accountSizedLots=(AccountBalance()/100000)*StartFactor*riskFactor;
if(minLot>accountSizedLots)
{
orderSize=minLot;
}
else
{
orderSize=accountSizedLots;
}
}
orderSize=NormalizeDouble(orderSize,2);
if(orderSize>maxLot)
{
//PrintFormat("Not Opening order, maximum lot size exceeded. Reduce the StartFactor. (Max) %2.2f < (Requested) %2.2f lots.",maxLot,orderSize);
//CloseOpenOrders(symbol);
orderSize=maxLot-minLot;
//return;
}
if(buyingOrSelling==BUYING)
{
if(AccountFreeMarginCheck(symbol,OP_BUY,orderSize)<=AccountEquity()*0.1 || GetLastError()==134)
{
PrintFormat("Not Opening order, not enough free margin for %2.2f lots. Reduce the StartFactor.",orderSize);
//CloseOpenOrders(symbol);
return;
}
int ret=OrderSend(symbol,OP_BUY,orderSize,ask,0,0,0);
if(ret == -1)
{
PrintFormat("Failed attempt to BUY %2.2f %s @ %2.5f (mql error %5.0i)",orderSize,symbol,ask,GetLastError());
}
}
else if(buyingOrSelling==SELLING)
{
if(AccountFreeMarginCheck(symbol,OP_SELL,orderSize)<=AccountEquity()*0.1 || GetLastError()==134)
{
PrintFormat("Not Opening order, not enough free margin for %2.2f lots. Reduce the StartFactor.",orderSize);
//CloseOpenOrders(symbol);
return;
}
int ret=OrderSend(symbol,OP_SELL,orderSize,bid,0,0,0);
if(ret == -1)
{
PrintFormat("Failed attempt to SELL %2.2f %s @ %2.5f (mql error %5.0i)",orderSize,symbol,bid,GetLastError());
}
}
}
//+------------------------------------------------------------------+
//|Gets the direction to trade in for the given symbol. |
//+------------------------------------------------------------------+
Enum_Direction GetBiasDirection(string symbol)
{
double custAvgNow=iMA(symbol,BiasTimeframe,BiasPeriod,0,MODE_SMA,PRICE_CLOSE,1);
double custAvgLookback=iMA(symbol,BiasTimeframe,BiasPeriod,0,MODE_SMA,PRICE_CLOSE,BiasLookback);
if(custAvgNow>custAvgLookback)
{
return BUYING;
}
if(custAvgNow<custAvgLookback)
{
return SELLING;
}
return NONE;
}
//+------------------------------------------------------------------+
//|Calculates the standard range. |
//+------------------------------------------------------------------+
double GetVolatilityFactor(string symbol)
{
return iATR(symbol,PERIOD_W1,6,1) / iATR(symbol,PERIOD_W1,52,1);
}
//+------------------------------------------------------------------+
//|Calculates the price to take profit at. |
//+------------------------------------------------------------------+
double GetProfitPoints(string symbol)
{
double bid = MarketInfo(symbol, MODE_BID);
double ask = MarketInfo(symbol, MODE_ASK);
double spread=ask-bid;
if(spread<=0)
{
spread=Point*1000;
}
double vf=GetVolatilityFactor(symbol);
if(vf>2)
{
vf=2;
}
if(vf<=0)
{
vf=1;
}
double output=1.5 *(vf*iATR(symbol,BiasTimeframe,BiasPeriod,1));
if(output<spread*6)
{
output=spread*6;
}
return output;
}
//+------------------------------------------------------------------+
//|Calculates the price to open another order in the same direction. |
//+------------------------------------------------------------------+
double GetStepSize(string symbol)
{
double bid = MarketInfo(symbol, MODE_BID);
double ask = MarketInfo(symbol, MODE_ASK);
double spread=ask-bid;
if(spread<=0)
{
spread=Point*1000;
}
double vf=GetVolatilityFactor(symbol);
if(vf<0.25)
{
vf=0.25;
}
double output=0.5 *(vf*iATR(symbol,BiasTimeframe,BiasPeriod,1));
if(output<spread*4)
{
output=spread*4;
}
return output;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
double GetDrawdownPercent()
{
return 100 * (1 - (AccountEquity()/AccountBalance()));
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
int GetLockFactor()
{
int lockFactor=-25+OrdersTotal();
if(lockFactor>-1)
{
lockFactor=-1;
}
return lockFactor;
}
//+------------------------------------------------------------------+
//|Manages the position. |
//+------------------------------------------------------------------+
void PositionManagement()
{
string Pair=Symbol();
int biasBarCount=Bars(Pair,BiasTimeframe);
int volatilityBarsCount=Bars(Pair,PERIOD_W1);
if((BiasLookback+BiasPeriod)>biasBarCount)
{
Print("Not enough history to form bias : BiasLookback + BiasPeriod");
return;
}
if(52>volatilityBarsCount)
{
Print("Not enough history to form bias : volatilityBarsCount");
return;
}
double ProfitPoints=GetProfitPoints(Pair);
double PairAveragePrice=PairAveragePrice(Pair);
double PairLots=PairLotsTotal(Pair);
double bid = MarketInfo(Pair, MODE_BID);
double ask = MarketInfo(Pair, MODE_ASK);
double ProfitTarget=0;
double CurrentOpenPrice=0;
double CurrentClosePrice=0;
string dirMsg="No Direction";
// manual entry could initialize the trades while the
// "Direction" latch is considering the opposite direction.
if(PairAveragePrice>0)
{
Direction=PairDirection(Pair);
}
if(Direction==BUYING)
{
dirMsg="Buying";
ProfitTarget=PairAveragePrice+ProfitPoints;
CurrentOpenPrice=ask;
CurrentClosePrice=bid;
}
if(Direction==SELLING)
{
dirMsg="Selling";
ProfitTarget=PairAveragePrice-ProfitPoints;
CurrentOpenPrice=bid;
CurrentClosePrice=ask;
}
double dd=GetDrawdownPercent();
Comment(
StringFormat(
"%s %3.2f Lots at %3.5f, Targeting %3.5f %2.2f DD %2.2f"
,dirMsg,PairLots,PairAveragePrice,ProfitTarget,PairProfitSince(Pair,60*60*24*30),dd));
bool tradingTime=IsTimeBetween(StartDay,StartHour,EndDay,EndHour);
if(PairAveragePrice==0 && tradingTime)
{
Direction=GetBiasDirection(Pair);
if(Direction!=NONE)
{
Print("Opening order, initializing position.");
OpenOrder(Pair,Direction);
}
return;
}
else if(AccountFreeMargin()<AccountBalance()*0.05)
{
Print("Closing orders, account free margin is too low.");
CloseOpenOrders(Pair);
return;
}
else if(PairAveragePrice!=0 && Direction==BUYING && CurrentClosePrice>ProfitTarget)
{
Print("Closing orders, profit target reached.");
CloseOpenOrders(Pair);
return;
}
else if(PairAveragePrice!=0 && Direction==SELLING && CurrentClosePrice<ProfitTarget)
{
Print("Closing orders, profit target reached.");
CloseOpenOrders(Pair);
return;
}
else if(GetDrawdownPercent()<GetLockFactor())
{
Print("Setting stop loss to prevent losing all of this gain.");
SetStopLossOpenOrders(Pair);
return;
}
else if(PairAveragePrice!=0 && Direction==BUYING)
{
double stepSize=GetStepSize(Pair);
if((CurrentClosePrice+stepSize)<PairLowestPricePaid(Pair))
{
Print("Opening order, averaging down.");
OpenOrder(Pair,Direction);
}
return;
}
else if(PairAveragePrice!=0 && Direction==SELLING)
{
double stepSize=GetStepSize(Pair);
if((CurrentClosePrice-stepSize)>PairHighestPricePaid(Pair))
{
Print("Opening order, averaging down.");
OpenOrder(Pair,Direction);
}
return;
}
}
//+------------------------------------------------------------------+
Binary file not shown.
+90
View File
@@ -0,0 +1,90 @@
//+------------------------------------------------------------------+
//| Basket Case.mq4 |
//| Matthew Kastor |
//| https://github.com/matthewkastor |
//+------------------------------------------------------------------+
#property copyright "Matthew Kastor"
#property link "https://github.com/matthewkastor"
#property version "1.00"
#property strict
#include <CurrencyBasket\Basket.mqh>
#property indicator_separate_window
#property indicator_buffers 1
#property indicator_plots 1
//--- plot Label1
#property indicator_type1 DRAW_LINE
#property indicator_color1 clrDeepSkyBlue
#property indicator_style1 STYLE_SOLID
#property indicator_width1 1
//--- indicator buffers
double IndexLineBuffer[];
extern int BarsLimit=5000;
extern color colorOne=clrDeepSkyBlue; //Line Color
extern string BasketSpecs1="EURUSDpro,sell,0.576"; //Pair,direction,weight;Pair,direction,weight
extern string BasketSpecs2=";USDJPYpro,buy,0.136"; //;Pair,direction,weight;Pair,direction,weight
extern string BasketSpecs3=";GBPUSDpro,sell,0.119"; //;Pair,direction,weight;Pair,direction,weight
extern string BasketSpecs4=";USDCADpro,buy,0.091"; //;Pair,direction,weight;Pair,direction,weight
extern string BasketSpecs5=";USDSEKpro,buy,0.042"; //;Pair,direction,weight;Pair,direction,weight
extern string BasketSpecs6=";USDCHFpro,buy,0.036"; //;Pair,direction,weight;Pair,direction,weight
extern string BasketSpecs7=""; //;Pair,direction,weight;Pair,direction,weight
Basket *basket;
//+------------------------------------------------------------------+
//| Custom indicator initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
IndicatorShortName("Basket Case");
SetIndexBuffer(0,IndexLineBuffer);
SetIndexLabel(0,"Basket Points");
SetIndexStyle(0,0,0,1,colorOne);
string basketSpecs=StringConcatenate(BasketSpecs1,BasketSpecs2,BasketSpecs3,BasketSpecs4,BasketSpecs5,BasketSpecs6,BasketSpecs7);
basket=new Basket(basketSpecs);
if(!basket.ValidatePairsExist())
{
return (INIT_FAILED);
}
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Custom indicator iteration function |
//+------------------------------------------------------------------+
int start()
{
int i=Bars-IndicatorCounted()-1;
if(i>BarsLimit)
{
i=BarsLimit;
}
double val=0;
while(i>0)
{
val=basket.GetWeightedPoints(i);
if(val==0)
{
IndexLineBuffer[i]=EMPTY_VALUE;
}
else
{
IndexLineBuffer[i]=val;
}
i--;
}
return (0);
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
int deinit()
{
delete basket;
return(0);
}
//+------------------------------------------------------------------+
Binary file not shown.
+165
View File
@@ -0,0 +1,165 @@
//+------------------------------------------------------------------+
//| MA Cross.mq4 |
//| Copyright 2013, Eugene Sia |
//| http://eugenesia.co.uk |
//+------------------------------------------------------------------+
/**
* This is a simple Metatrader 4 Expert Advisor I made to revise my
* MQL4, after a long hiatus. Hoping to re-explore automated forex
* trading!
*
* This EA trades based on a moving average crossovers, a common
* breakout strategy. When the short MA crosses the long MA, enter a
* trade.
*/
#property copyright "Copyright 2013, Eugene Sia"
#property link "http://eugenesia.co.uk"
//--- Constant definitions
// Prefix a unique identifier e.g. MACROSS so we don't conflict with
// other predefined constants.
// This defines the magic number for this EA. A magic number can be
// assigned to an order, so that orders opened by this EA have this magic
// number. This is how we distinguish between orders opened by this EA,
// and those opened by the user or other EAs.
// Ref: http://articles.mql4.com/145
#define MACROSS_MAGIC_NUM 20130715
#define MACROSS_OPEN_BUY_SIGNAL 1
#define MACROSS_OPEN_SELL_SIGNAL -1
#define MACROSS_NO_SIGNAL 0
//--- input parameters
// extern keyword defines parameters that can be set by the user in the
// "Expert properties" dialog.
extern int ShortMaPeriod = 10;
extern int LongMaPeriod = 50;
// These are in fractional pips, which are 0.1 of a pip.
extern int StopLoss = 500;
extern int TakeProfit = 1600;
// Number of lots for each trade.
extern double Lots = 1;
/**
* Get moving average values for the most recent price points.
*
* Params:
* maPeriod: period of the MA.
* numValues: Number of values to insert into the returned array.
* ma: returned array of MA values, with ma[0] being the value for the
* current price, ma[1] the value for the previous bar's price, etc.
*
*/
void MaRecentValues(double& ma[], int maPeriod, int numValues = 3)
{
// i is the index of the price array to calculate the MA value for.
// e.g. i=0 is the current price, i=1 is the previous bar's price.
for (int i=0; i < numValues; i++)
{
ma[i] = iMA(NULL,0,maPeriod,0,MODE_SMA,PRICE_CLOSE,i);
}
}
/**
* Check if we should open a trade.
*
* Returns: +1 to open a buy order, -1 to open a sell order, 0 for no action.
*/
int OpenSignal()
{
int signal = MACROSS_NO_SIGNAL;
// Execute only on the first tick of a new bar, to avoid repeatedly
// opening orders when an open condition is satisfied.
if (Volume[0] > 1) return(0);
//---- get Moving Average values
double shortMa[3];
MaRecentValues(shortMa, ShortMaPeriod, 3);
double longMa[3];
MaRecentValues(longMa, LongMaPeriod, 3);
//---- buy conditions
if (shortMa[2] < longMa[2]
&& shortMa[1] > longMa[1])
{
signal = MACROSS_OPEN_BUY_SIGNAL;
}
//---- sell conditions
if (shortMa[2] > longMa[2]
&& shortMa[1] < longMa[1])
{
signal = MACROSS_OPEN_SELL_SIGNAL;
}
//----
return(signal);
}
//+------------------------------------------------------------------+
//| expert initialization function |
//+------------------------------------------------------------------+
int init()
{
//----
//----
return(0);
}
//+------------------------------------------------------------------+
//| expert deinitialization function |
//+------------------------------------------------------------------+
int deinit()
{
//----
//----
return(0);
}
//+------------------------------------------------------------------+
//| expert start function |
//+------------------------------------------------------------------+
int start()
{
//----
int signal = OpenSignal();
// Set slippage to a large enough number to avoid error 138 - quote
// outdated.
int slippage = 30;
if (signal == MACROSS_OPEN_BUY_SIGNAL)
{
Print("Buy signal");
OrderSend(Symbol(),OP_BUY,Lots,Bid,slippage,
Bid-StopLoss*Point, // Stop loss price.
Bid+TakeProfit*Point, // Take profit price.
NULL,MACROSS_MAGIC_NUM,0,Green);
}
else if (signal == MACROSS_OPEN_SELL_SIGNAL)
{
Print("Sell signal");
OrderSend(Symbol(),OP_SELL,Lots,Ask,slippage,
Ask+StopLoss*Point, // Stop loss price.
Ask-TakeProfit*Point, // Take profit price.
NULL,MACROSS_MAGIC_NUM,0,Red);
}
//----
return(0);
}
//+------------------------------------------------------------------+
Binary file not shown.
+78
View File
@@ -0,0 +1,78 @@
/**
* @copyright 2019, pipbolt.io <beta@pipbolt.io>
* @license https://github.com/pipbolt/experts/blob/master/LICENSE
*/
#include <PipboltFramework\Constants.mqh>
#define NAME "Moving Average Cross EA"
#define VERSION "0.022"
#property copyright COPYRIGHT
#property link LINK
#property icon ICON
#property description DESCRIPTION
#property version VERSION
#include <PipboltFramework\Params\MainSettings.mqh>
input group "Entry Strategy";
input group "Exit Strategy";
input bool UseExitStrategy = false; // Use Exit Strategy
input group "Moving Averages";
input string Fast_Moving_Average = "----------"; // ---------- Fast Moving Average ----------
input int MaFastPeriod = 12; // Moving Average Period
input ENUM_MA_METHOD MaFastMethod = MODE_SMA; // Method
input ENUM_APPLIED_PRICE MaFastAppliedPrice = PRICE_CLOSE; // Applied Price
input string Slow_Moving_Average = "----------"; // ---------- Slow Moving Average ----------
input int MaSlowPeriod = 30; // Moving Average Period
input ENUM_MA_METHOD MaSlowMethod = MODE_SMA; // Method
input ENUM_APPLIED_PRICE MaSlowAppliedPrice = PRICE_CLOSE; // Applied Price
#include <PipboltFramework\Experts.mqh>
CiMA MAFast;
CiMA MASlow;
int OnInit(void)
{
if (ONINIT() != INIT_SUCCEEDED)
return INIT_FAILED;
MAFast.Init(MaFastPeriod, 0, MaFastMethod, MaFastAppliedPrice);
MASlow.Init(MaSlowPeriod, 0, MaSlowMethod, MaSlowAppliedPrice);
return INIT_SUCCEEDED;
}
void OnTick(void) { ONTICK(); }
void OnDeinit(const int reason) { ONDEINIT(reason); }
void OnTimer() { ONTIMER(); }
void CheckForOpen(bool &openBuy, bool &openSell)
{
// Buy Entry Strategy
if (MAFast.Main(1) < MASlow.Main(1) && MAFast.Main(0) >= MASlow.Main(0))
openBuy = true;
// Sell Entry Strategy
else if (MAFast.Main(1) > MASlow.Main(1) && MAFast.Main(0) <= MASlow.Main(0))
openSell = true;
// Apply MA Filter
openBuy = openBuy && MAFilter.Check(DIR_BUY);
openSell = openSell && MAFilter.Check(DIR_SELL);
}
void CheckForClose(bool &closeBuy, bool &closeSell)
{
// Buy Exit Strategy
closeBuy = (MAFast.Main(1) > MASlow.Main(1) && MAFast.Main(0) <= MASlow.Main(0));
// Sell Exit Strategy
closeSell = (MAFast.Main(1) < MASlow.Main(1) && MAFast.Main(0) >= MASlow.Main(0));
}
Binary file not shown.
@@ -0,0 +1,74 @@
/**
* @copyright 2019, pipbolt.io <beta@pipbolt.io>
* @license https://github.com/pipbolt/experts/blob/master/LICENSE
*/
#include <PipboltFramework\Constants.mqh>
#define NAME "Moving Average EA"
#define VERSION "0.022"
#property copyright COPYRIGHT
#property link LINK
#property icon ICON
#property description DESCRIPTION
#property version VERSION
#include <PipboltFramework\Params\MainSettings.mqh>
input group "Entry Strategy";
input group "Exit Strategy";
input bool UseExitStrategy = false; // Use Exit Strategy
input group "Moving Average";
input int MaPeriod = 10; // Period
input ENUM_MA_METHOD MaMethod = MODE_SMA; // Method
input ENUM_APPLIED_PRICE MaAppliedPrice = PRICE_CLOSE; // Applied Price
#include <PipboltFramework\Experts.mqh>
CiMA MA;
int OnInit(void)
{
if (ONINIT() != INIT_SUCCEEDED)
return INIT_FAILED;
MA.Init(MaPeriod, 0, MaMethod, MaAppliedPrice);
return INIT_SUCCEEDED;
}
void OnTick(void) { ONTICK(); }
void OnDeinit(const int reason) { ONDEINIT(reason); }
void OnTimer() { ONTIMER(); }
void CheckForOpen(bool &openBuy, bool &openSell)
{
// Close prices
double close0 = iClose(NULL, NULL, _indicatorShift + 0);
double close1 = iClose(NULL, NULL, _indicatorShift + 1);
// Buy Entry Strategy
openBuy = (close0 > MA.Main(0) && close1 <= MA.Main(1));
// Sell Entry Strategy
openSell = (close0 < MA.Main(0) && close1 >= MA.Main(1));
// Apply MA Filter
openBuy = openBuy && MAFilter.Check(DIR_BUY);
openSell = openSell && MAFilter.Check(DIR_SELL);
}
void CheckForClose(bool &closeBuy, bool &closeSell)
{
// Close price
double close0 = iClose(NULL, NULL, _indicatorShift + 0);
// Buy Exit Strategy
closeBuy = (close0 < MA.Main(0));
// Sell Exit Strategy
closeSell = (close0 > MA.Main(0));
}
Binary file not shown.
+169
View File
@@ -0,0 +1,169 @@
//+------------------------------------------------------------------+
//| SpikeTrader.mq4 |
//| Copyright © 2012-2022, EarnForex.com |
//| https://www.earnforex.com/ |
//+------------------------------------------------------------------+
#property copyright "Copyright © 2012-2022, EarnForex"
#property link "https://www.earnforex.com/metatrader-expert-advisors/Spike-Trader/"
#property version "1.01"
#property strict
#property description "Trades on spikes that are:"
#property description "1) Higher/lower than N preceding bars;"
#property description "2) Higher/lower than the previous bar by X percent;"
#property description "3) Close in bottom or upper third/half of the bar."
input group "Main"
input int Hold = 11; // Hold: Position holding time in bars.
input int BarsNumber = 3; // BarsNumber: N preceding bars to check.
input double PercentageDifference = 0.003; // PercentageDifference1: X percentage for bar comparison.
input double ThirdOrHalf = 0.5; // ThirdOrHalf: Top/bottom share of a bar to close in.
input group "Money management"
input double Lots = 0.1;
input group "Miscellaneous"
input int Slippage = 30;
input string OrderCommentary = "Spike Trader";
input int Magic = 173923183;
int LastBars = 0;
int Timer = 0;
void OnTick()
{
if ((!IsTradeAllowed()) || (IsTradeContextBusy()) || (!IsConnected()) || ((!MarketInfo(Symbol(), MODE_TRADEALLOWED)) && (!IsTesting()))) return;
//Wait for the new Bar in a chart.
if (LastBars == Bars) return;
else LastBars = Bars;
if (Timer == 1) ClosePrev();
if (Timer > 0) Timer--;
CheckEntry();
}
//+------------------------------------------------------------------+
//| Check for entry conditions and trade if necessary. |
//+------------------------------------------------------------------+
void CheckEntry()
{
// Empty bar.
if (High[1] - Low[1] == 0) return;
if (CheckSellEntry())
{
// If found a BUY order, close it and open a SELL. Otherwise, only reset timer.
if (ClosePrev(OP_SELL)) fSell();
Timer = Hold;
}
else if (CheckBuyEntry())
{
// If found a SELL order, close it and open a BUY. Otherwise, only reset timer.
if (ClosePrev(OP_BUY)) fBuy();
Timer = Hold;
}
}
bool CheckSellEntry()
{
// If the bar isn't higher than at least one of the previous bars - return false.
for (int i = 2; i < BarsNumber + 2; i++)
if (High[1] <= High[i]) return false;
// If not higher than the previous bar by required percentage difference - return false.
if ((High[1] - High[2]) / High[2] < PercentageDifference) return false;
// If closed above the lower third/half - return false.
if ((Close[1] - Low[1]) / (High[1] - Low[1]) > ThirdOrHalf) return false;
// Passed all tests.
return true;
}
bool CheckBuyEntry()
{
// If the bar isn't lower than at least one of the previous bars - return false.
for (int i = 2; i < BarsNumber + 2; i++)
if (Low[1] >= Low[i]) return false;
// If not lower than the previous bar by required percentage difference - return false.
if ((Low[2] - Low[1]) / Low[2] < PercentageDifference) return false;
// If closed below the upper third/half - return false.
if ((High[1] - Close[1]) / (High[1] - Low[1]) > ThirdOrHalf) return false;
// Passed all tests.
return true;
}
//+------------------------------------------------------------------+
//| Close previous position. |
//| order_type - skip positions of this directions. |
//+------------------------------------------------------------------+
bool ClosePrev(int order_type = -1)
{
int total = OrdersTotal();
for (int i = total - 1; i >= 0; i--)
{
if (OrderSelect(i, SELECT_BY_POS) == false) continue;
if ((OrderSymbol() == Symbol()) && (OrderMagicNumber() == Magic))
{
if (OrderType() == OP_BUY)
{
if (order_type == OP_BUY) return false;
RefreshRates();
if (!OrderClose(OrderTicket(), OrderLots(), Bid, Slippage))
{
int e = GetLastError();
Print("OrderClose Error: ", e);
}
return true;
}
else if (OrderType() == OP_SELL)
{
if (order_type == OP_SELL) return false;
RefreshRates();
if (!OrderClose(OrderTicket(), OrderLots(), Ask, Slippage))
{
int e = GetLastError();
Print("OrderClose Error: ", e);
}
return true;
}
}
}
return true;
}
//+------------------------------------------------------------------+
//| Sell |
//+------------------------------------------------------------------+
int fSell()
{
RefreshRates();
int result = OrderSend(Symbol(), OP_SELL, Lots, Bid, Slippage, 0, 0, OrderCommentary, Magic);
if (result == -1)
{
int e = GetLastError();
Print("OrderSend Error: ", e);
}
else return result;
return 0;
}
//+------------------------------------------------------------------+
//| Buy |
//+------------------------------------------------------------------+
int fBuy()
{
RefreshRates();
int result = OrderSend(Symbol(), OP_BUY, Lots, Ask, Slippage, 0, 0, OrderCommentary, Magic);
if (result == -1)
{
int e = GetLastError();
Print("OrderSend Error: ", e);
}
else return result;
return 0;
}
//+------------------------------------------------------------------+
Binary file not shown.
+519
View File
@@ -0,0 +1,519 @@
//+------------------------------------------------------------------+
//| DonchianTurtle_v3_Consensus.mq5 |
//| EA v4 — Donchian Turtle + QuantAgent-Inspired Consensus Filter |
//| |
//| Base: V3.13 (Volatility Scaling + CSV Logging) |
//| New: Consensus gate — RSI + MACD + LinReg must agree |
//| Inspired by QuantAgent paper (arXiv:2509.09995) |
//| |
//| Validated params (Python IS/OOS + MT5 86% quality OOS): |
//| S1: Donchian(20/8), S2: Donchian(40/8) |
//| ADX>20, SL=2.0xATR(20), Vol Scaling ON |
//| Consensus: RSI>50 + MACD cross + Price>LinReg(50) |
//| Scorecard: 81/100 Grade B (OOS 2023-2025) |
//+------------------------------------------------------------------+
#property copyright "EA v4 — Turtle Consensus"
#property version "4.00"
#include <Trade\Trade.mqh>
//--- System 1
input group "=== System 1 (Donchian 20) ==="
input int S1_EntryPeriod = 20;
input int S1_ExitPeriod = 8; // Updated: was 10
input double S1_RiskPct = 0.5;
//--- System 2
input group "=== System 2 (Donchian 40) ==="
input int S2_EntryPeriod = 40; // Updated: was 55
input int S2_ExitPeriod = 8; // Updated: was 10
input double S2_RiskPct = 0.5;
//--- ATR / Base Filters
input group "=== Filters ==="
input int ADX_Period = 20;
input double ADX_MinLevel = 20.0; // Updated: was 25
input int ATR_Period = 20;
input double ATR_StopMult = 2.0;
input int MA_Period = 200;
input double ATR_SpikeMult = 3.0;
input double MaxDrawdownPct = 20.0;
//--- Break-Even + Trailing
input group "=== Break-Even + Trailing Stop ==="
input bool UseBreakEven = true;
input double BE_RMultiple = 1.0;
input bool UseTrailing = true;
input double Trail_RMultiple = 2.0;
input double Trail_ATRMult = 1.5;
//--- Volatility Scaling
input group "=== Volatility Scaling ==="
input bool UseVolScaling = true;
input int VolScale_Period = 252;
input double VolScale_LowPct = 0.33;
input double VolScale_HighPct = 0.67;
input double VolScale_LowMult = 1.5;
input double VolScale_HighMult = 0.5;
//--- Consensus Filter (QuantAgent-Inspired)
input group "=== Consensus Filter (QuantAgent-Inspired) ==="
input bool UseConsensus = true; // เปิด/ปิด consensus gate
input int ConsensusMin = 2; // ต้องผ่านอย่างน้อยกี่ conditions (max=3)
// Condition 1: RSI momentum
input int RSI_Period = 14;
input double RSI_BullLevel = 50.0; // RSI > 50 = bullish
// Condition 2: MACD direction
input int MACD_Fast = 12;
input int MACD_Slow = 26;
input int MACD_Signal = 9;
// Condition 3: Price vs OLS trend line
input int LinReg_Period = 50; // Linear regression period (TrendAgent)
//--- Magic Numbers
input group "=== Order Settings ==="
input int MagicS1 = 202901; // New magic (v4)
input int MagicS2 = 202902;
input string TradeComment = "Turtle_v4_Consensus";
//+------------------------------------------------------------------+
//--- Globals
CTrade trade;
int g_hATR = INVALID_HANDLE;
int g_hADX = INVALID_HANDLE;
int g_hMA = INVALID_HANDLE;
int g_hRSI = INVALID_HANDLE;
int g_hMACD = INVALID_HANDLE;
int g_hLR = INVALID_HANDLE; // Linear Regression handle
double g_AccountPeak = 0;
datetime g_LastBarTime = 0;
int g_hLog = INVALID_HANDLE;
double g_lastVolMult = 1.0;
double g_lastATRpct = -1.0;
int g_lastConsensus = 0;
//+------------------------------------------------------------------+
int OnInit()
{
// Base indicators
g_hATR = iATR(Symbol(), PERIOD_D1, ATR_Period);
g_hADX = iADX(Symbol(), PERIOD_D1, ADX_Period);
g_hMA = iMA(Symbol(), PERIOD_D1, MA_Period, 0, MODE_SMA, PRICE_CLOSE);
// Consensus indicators
g_hRSI = iRSI(Symbol(), PERIOD_D1, RSI_Period, PRICE_CLOSE);
g_hMACD = iMACD(Symbol(), PERIOD_D1, MACD_Fast, MACD_Slow, MACD_Signal, PRICE_CLOSE);
g_hLR = iMA(Symbol(), PERIOD_D1, LinReg_Period, 0, MODE_SMA, PRICE_CLOSE); // SMA50 as trend proxy (iLinReg not in MQL5 std)
if(g_hATR == INVALID_HANDLE || g_hADX == INVALID_HANDLE ||
g_hMA == INVALID_HANDLE || g_hRSI == INVALID_HANDLE ||
g_hMACD == INVALID_HANDLE || g_hLR == INVALID_HANDLE)
{
Print("ERROR: Failed to create indicator handles");
return INIT_FAILED;
}
// Warmup (skip in backtester)
bool inTester = (bool)MQLInfoInteger(MQL_TESTER);
if(!inTester)
{
double dummy[1];
int attempts = 0;
while(CopyBuffer(g_hMA, 0, 1, 1, dummy) <= 0 && attempts < 100)
{
Sleep(100);
attempts++;
}
if(attempts >= 100)
{
Print("ERROR: Indicators not ready.");
return INIT_FAILED;
}
}
trade.SetDeviationInPoints(50);
trade.SetTypeFilling(ORDER_FILLING_IOC);
g_AccountPeak = AccountInfoDouble(ACCOUNT_BALANCE);
// CSV log
string fname = "TurtleConsensus_" + Symbol() + "_trades.csv";
g_hLog = FileOpen(fname, FILE_WRITE|FILE_READ|FILE_CSV|FILE_ANSI|FILE_SHARE_READ, ',');
if(g_hLog == INVALID_HANDLE)
Print("WARNING: Cannot open log file");
else
{
if(FileTell(g_hLog) == 0)
FileWrite(g_hLog,
"Timestamp","Event","System","Magic",
"Lots","Price","SL","RiskPct",
"ATR_pct","VolMult","Consensus","PnL","Balance","Note");
FileSeek(g_hLog, 0, SEEK_END);
FileFlush(g_hLog);
}
PrintFormat("DonchianTurtle v4 Consensus | %s D1 | S1:%d/%d S2:%d/%d ADX>%.0f SL=%.1fx ConsMin=%d",
Symbol(), S1_EntryPeriod, S1_ExitPeriod,
S2_EntryPeriod, S2_ExitPeriod,
ADX_MinLevel, ATR_StopMult, ConsensusMin);
return INIT_SUCCEEDED;
}
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
IndicatorRelease(g_hATR);
IndicatorRelease(g_hADX);
IndicatorRelease(g_hMA);
IndicatorRelease(g_hRSI);
IndicatorRelease(g_hMACD);
IndicatorRelease(g_hLR);
if(g_hLog != INVALID_HANDLE) { FileFlush(g_hLog); FileClose(g_hLog); }
}
//+------------------------------------------------------------------+
void OnTick()
{
// Trail runs every tick
double atrNow[1];
double atr = 0;
if(CopyBuffer(g_hATR, 0, 0, 1, atrNow) > 0) atr = atrNow[0];
if(atr > 0)
{
ManageTrail(MagicS1, atr);
ManageTrail(MagicS2, atr);
}
// New bar check
datetime barTime = iTime(Symbol(), PERIOD_D1, 0);
if(barTime == g_LastBarTime) return;
g_LastBarTime = barTime;
double balance = AccountInfoDouble(ACCOUNT_BALANCE);
if(balance > g_AccountPeak) g_AccountPeak = balance;
// DD halt
if(g_AccountPeak > 0)
{
double dd = (g_AccountPeak - balance) / g_AccountPeak * 100.0;
if(dd >= MaxDrawdownPct)
{
PrintFormat("DD HALT: %.1f%% >= %.1f%%", dd, MaxDrawdownPct);
return;
}
}
// Read base indicators (bar[1] = last completed bar)
double atrBuf[1], adxBuf[1], maBuf[1];
if(CopyBuffer(g_hATR, 0, 1, 1, atrBuf) <= 0) return;
if(CopyBuffer(g_hADX, 0, 1, 1, adxBuf) <= 0) return;
if(CopyBuffer(g_hMA, 0, 1, 1, maBuf) <= 0) return;
double atrD1 = atrBuf[0];
double adx = adxBuf[0];
double ma200 = maBuf[0];
double close1 = iClose(Symbol(), PERIOD_D1, 1);
if(atrD1 <= 0 || adx <= 0 || ma200 <= 0 || close1 <= 0) return;
// ATR spike filter
double atrArr[20];
double atrAvg = 0;
if(CopyBuffer(g_hATR, 0, 1, 20, atrArr) == 20)
{
for(int k = 0; k < 20; k++) atrAvg += atrArr[k];
atrAvg /= 20.0;
}
if(atrAvg > 0 && atrD1 > atrAvg * ATR_SpikeMult) return;
// Donchian exits
ManageExits(MagicS1, S1_ExitPeriod);
ManageExits(MagicS2, S2_ExitPeriod);
// Base entry filters
if(close1 <= ma200) return; // Below MA200
if(adx < ADX_MinLevel) return; // Weak trend
// Consensus check (QuantAgent-inspired)
g_lastConsensus = 0;
if(UseConsensus)
{
g_lastConsensus = GetConsensusScore();
if(g_lastConsensus < ConsensusMin)
{
PrintFormat("Consensus FAIL: score=%d/%d (need %d) — skip entry",
g_lastConsensus, 3, ConsensusMin);
return;
}
PrintFormat("Consensus PASS: score=%d/3", g_lastConsensus);
}
// Volatility scaling
double scaledRiskS1 = S1_RiskPct;
double scaledRiskS2 = S2_RiskPct;
g_lastVolMult = 1.0;
g_lastATRpct = -1.0;
if(UseVolScaling)
{
double atrPct = GetATRPercentile(VolScale_Period, 1);
double mult = 1.0;
if(atrPct >= 0 && atrPct < VolScale_LowPct) mult = VolScale_LowMult;
else if(atrPct > VolScale_HighPct) mult = VolScale_HighMult;
scaledRiskS1 = S1_RiskPct * mult;
scaledRiskS2 = S2_RiskPct * mult;
g_lastVolMult = mult;
g_lastATRpct = atrPct;
}
// Entries
if(!HasPosition(MagicS1))
TryEntry(MagicS1, S1_EntryPeriod, scaledRiskS1, atrD1, close1, "S1");
if(!HasPosition(MagicS2))
TryEntry(MagicS2, S2_EntryPeriod, scaledRiskS2, atrD1, close1, "S2");
}
//+------------------------------------------------------------------+
//| Consensus Score — 3 conditions from QuantAgent |
//| Returns 0-3. Called after base filters pass. |
//+------------------------------------------------------------------+
int GetConsensusScore()
{
int score = 0;
// Condition 1: RSI(14) > 50 — bullish momentum (IndicatorAgent)
double rsiBuf[1];
if(CopyBuffer(g_hRSI, 0, 1, 1, rsiBuf) > 0)
{
if(rsiBuf[0] > RSI_BullLevel)
{
score++;
PrintFormat(" [C1] RSI=%.1f > %.1f PASS", rsiBuf[0], RSI_BullLevel);
}
else
PrintFormat(" [C1] RSI=%.1f <= %.1f FAIL", rsiBuf[0], RSI_BullLevel);
}
// Condition 2: MACD line > Signal line — directional confirm (IndicatorAgent)
double macdMain[1], macdSig[1];
if(CopyBuffer(g_hMACD, MAIN_LINE, 1, 1, macdMain) > 0 &&
CopyBuffer(g_hMACD, SIGNAL_LINE, 1, 1, macdSig) > 0)
{
if(macdMain[0] > macdSig[0])
{
score++;
PrintFormat(" [C2] MACD=%.4f > Signal=%.4f PASS", macdMain[0], macdSig[0]);
}
else
PrintFormat(" [C2] MACD=%.4f <= Signal=%.4f FAIL", macdMain[0], macdSig[0]);
}
// Condition 3: Price above OLS Linear Regression line — trend bias (TrendAgent)
double lrBuf[1];
double close1 = iClose(Symbol(), PERIOD_D1, 1);
if(CopyBuffer(g_hLR, 0, 1, 1, lrBuf) > 0)
{
if(close1 > lrBuf[0])
{
score++;
PrintFormat(" [C3] Close=%.2f > LinReg=%.2f PASS", close1, lrBuf[0]);
}
else
PrintFormat(" [C3] Close=%.2f <= LinReg=%.2f FAIL", close1, lrBuf[0]);
}
return score;
}
//+------------------------------------------------------------------+
void TryEntry(int magic, int period, double riskPct, double atr,
double close1, string label)
{
// Donchian entry band (bars 2..period+1, shift=2 matching MQL5 convention)
int hiIdx = iHighest(Symbol(), PERIOD_D1, MODE_HIGH, period, 2);
if(hiIdx < 0) return;
double prevBand = iHigh(Symbol(), PERIOD_D1, hiIdx);
if(close1 <= prevBand) return; // No breakout
double ask = SymbolInfoDouble(Symbol(), SYMBOL_ASK);
double sl = ask - atr * ATR_StopMult;
double lots = CalcLots(ask, sl, riskPct);
if(lots <= 0) return;
trade.SetExpertMagicNumber(magic);
if(trade.Buy(lots, Symbol(), ask, sl, 0, TradeComment + "_" + label))
{
PrintFormat("%s ENTRY | Ask=%.2f SL=%.2f Lots=%.2f Band=%.2f Vol=%.1f Cons=%d/3",
label, ask, sl, lots, prevBand, g_lastVolMult, g_lastConsensus);
if(g_hLog != INVALID_HANDLE)
{
FileWrite(g_hLog,
TimeToString(TimeCurrent(), TIME_DATE|TIME_SECONDS),
"ENTRY", label, magic,
DoubleToString(lots, 2),
DoubleToString(ask, 2),
DoubleToString(sl, 2),
DoubleToString(riskPct, 3),
DoubleToString(g_lastATRpct, 3),
DoubleToString(g_lastVolMult, 2),
IntegerToString(g_lastConsensus),
"",
DoubleToString(AccountInfoDouble(ACCOUNT_BALANCE), 2),
"");
FileFlush(g_hLog);
}
}
else
PrintFormat("%s FAIL | code=%d %s", label,
trade.ResultRetcode(), trade.ResultRetcodeDescription());
}
//+------------------------------------------------------------------+
void ManageTrail(int magic, double atr)
{
if(!UseBreakEven && !UseTrailing) return;
if(atr <= 0) return;
for(int i = PositionsTotal() - 1; i >= 0; i--)
{
ulong ticket = PositionGetTicket(i);
if(!PositionSelectByTicket(ticket)) continue;
if(PositionGetInteger(POSITION_MAGIC) != magic) continue;
if(PositionGetString(POSITION_SYMBOL) != Symbol()) continue;
if(PositionGetInteger(POSITION_TYPE) != POSITION_TYPE_BUY) continue;
double entry = PositionGetDouble(POSITION_PRICE_OPEN);
double curSL = PositionGetDouble(POSITION_SL);
double bid = SymbolInfoDouble(Symbol(), SYMBOL_BID);
double initRisk = atr * ATR_StopMult;
double profit = bid - entry;
double newSL = curSL;
if(UseBreakEven && profit >= BE_RMultiple * initRisk)
{
double beLevel = entry + 2 * SymbolInfoDouble(Symbol(), SYMBOL_POINT);
if(beLevel > curSL) newSL = MathMax(newSL, beLevel);
}
if(UseTrailing && profit >= Trail_RMultiple * initRisk)
{
double trailLevel = bid - atr * Trail_ATRMult;
if(trailLevel > curSL) newSL = MathMax(newSL, trailLevel);
}
if(newSL > curSL + SymbolInfoDouble(Symbol(), SYMBOL_POINT))
{
double tp = PositionGetDouble(POSITION_TP);
trade.SetExpertMagicNumber(magic);
trade.PositionModify(ticket, NormalizeDouble(newSL, _Digits), tp);
}
}
}
//+------------------------------------------------------------------+
void ManageExits(int magic, int exitPeriod)
{
for(int i = PositionsTotal() - 1; i >= 0; i--)
{
ulong ticket = PositionGetTicket(i);
if(!PositionSelectByTicket(ticket)) continue;
if(PositionGetInteger(POSITION_MAGIC) != magic) continue;
if(PositionGetString(POSITION_SYMBOL) != Symbol()) continue;
int loIdx = iLowest(Symbol(), PERIOD_D1, MODE_LOW, exitPeriod, 1);
if(loIdx < 0) continue;
double exitLow = iLow(Symbol(), PERIOD_D1, loIdx);
double close1 = iClose(Symbol(), PERIOD_D1, 1);
if(close1 < exitLow)
{
trade.SetExpertMagicNumber(magic);
trade.PositionClose(ticket);
}
}
}
//+------------------------------------------------------------------+
void OnTradeTransaction(const MqlTradeTransaction& trans,
const MqlTradeRequest& request,
const MqlTradeResult& result)
{
if(trans.type != TRADE_TRANSACTION_DEAL_ADD) return;
if(g_hLog == INVALID_HANDLE) return;
if(!HistoryDealSelect(trans.deal)) return;
long dealEntry = HistoryDealGetInteger(trans.deal, DEAL_ENTRY);
if(dealEntry != DEAL_ENTRY_OUT && dealEntry != DEAL_ENTRY_INOUT) return;
long magic = HistoryDealGetInteger(trans.deal, DEAL_MAGIC);
if(magic != MagicS1 && magic != MagicS2) return;
string system = (magic == MagicS1) ? "S1" : "S2";
double profit = HistoryDealGetDouble(trans.deal, DEAL_PROFIT)
+ HistoryDealGetDouble(trans.deal, DEAL_SWAP)
+ HistoryDealGetDouble(trans.deal, DEAL_COMMISSION);
double price = HistoryDealGetDouble(trans.deal, DEAL_PRICE);
double lots = HistoryDealGetDouble(trans.deal, DEAL_VOLUME);
string outcome = (profit >= 0) ? "WIN" : "LOSS";
FileWrite(g_hLog,
TimeToString(TimeCurrent(), TIME_DATE|TIME_SECONDS),
"EXIT_" + outcome, system, magic,
DoubleToString(lots, 2),
DoubleToString(price, 2),
"", "", "", "", "",
DoubleToString(profit, 2),
DoubleToString(AccountInfoDouble(ACCOUNT_BALANCE), 2),
outcome);
FileFlush(g_hLog);
}
//+------------------------------------------------------------------+
bool HasPosition(int magic)
{
for(int i = 0; i < PositionsTotal(); i++)
{
ulong ticket = PositionGetTicket(i);
if(!PositionSelectByTicket(ticket)) continue;
if(PositionGetInteger(POSITION_MAGIC) == magic &&
PositionGetString(POSITION_SYMBOL) == Symbol())
return true;
}
return false;
}
//+------------------------------------------------------------------+
double GetATRPercentile(int period, int shift)
{
double atrArr[];
ArraySetAsSeries(atrArr, true);
int copied = CopyBuffer(g_hATR, 0, shift, period, atrArr);
if(copied < period) return -1.0;
double curATR = atrArr[0];
int rank = 0;
for(int i = 1; i < period; i++)
if(atrArr[i] < curATR) rank++;
return (double)rank / (double)(period - 1);
}
//+------------------------------------------------------------------+
double CalcLots(double entry, double sl, double riskPct)
{
double balance = AccountInfoDouble(ACCOUNT_BALANCE);
double riskAmt = balance * riskPct / 100.0;
double slDist = MathAbs(entry - sl);
if(slDist <= 0) return 0;
double tickVal = SymbolInfoDouble(Symbol(), SYMBOL_TRADE_TICK_VALUE);
double tickSize = SymbolInfoDouble(Symbol(), SYMBOL_TRADE_TICK_SIZE);
if(tickSize <= 0 || tickVal <= 0) return 0;
double lots = riskAmt / ((slDist / tickSize) * tickVal);
double step = SymbolInfoDouble(Symbol(), SYMBOL_VOLUME_STEP);
double minL = SymbolInfoDouble(Symbol(), SYMBOL_VOLUME_MIN);
double maxL = SymbolInfoDouble(Symbol(), SYMBOL_VOLUME_MAX);
lots = MathFloor(lots / step) * step;
return MathMax(minL, MathMin(maxL, lots));
}
//+------------------------------------------------------------------+
Binary file not shown.
+38
View File
@@ -0,0 +1,38 @@
//+------------------------------------------------------------------+
//| TrendEngine Core Demo MQL5 EA |
//| Author: Hossein Asgari (Fintor AI) |
//+------------------------------------------------------------------+
#property strict
#property copyright "Hossein Asgari - Fintor AI"
#property link "https://fintorai.com"
#property version "1.00"
#include <TrendEngine/TrendEngineCore.mqh>
//--- inputs
input double InpLots = 0.10;
input int InpMaFast = 20;
input int InpMaSlow = 50;
input int InpSlPoints = 300;
input int InpTpPoints = 600;
//--- core engine
CTrendEngineCore g_engine;
//+------------------------------------------------------------------+
int OnInit()
{
g_engine.Init(InpLots,InpMaFast,InpMaSlow,InpSlPoints,InpTpPoints);
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
g_engine.Deinit();
}
//+------------------------------------------------------------------+
void OnTick()
{
g_engine.OnTick();
}
//+------------------------------------------------------------------+
Binary file not shown.
+106
View File
@@ -0,0 +1,106 @@
#include <stderror.mqh>
#include <stdlib.mqh>
#property copyright "Copyright 2023, MetaQuotes Ltd."
#property link "https://www.mql5.com"
#property version "1.00"
#property strict
// config parameters
double stopLoss = 2.5;
double takeProfit = 3;
double Lots = 0.01;
int waitForOrderTime = 60; // seconds
// global variables
double tickPrices[];
int tickCounts = 0;
datetime lastOrderOpenTime = 0;
int OnInit()
{
// create zero array for tickPrices
ArraySetAsSeries(tickPrices, true);
ArrayResize(tickPrices, stdTicksNumbers);
ArraySetAsSeries(tickPrices, false);
ArrayInitialize(tickPrices, 0.0);
return(INIT_SUCCEEDED);
}
void OnDeinit(const int reason)
{
}
void PlaceOrderBuy()
{
double orderPrice = SymbolInfoDouble(_Symbol, SYMBOL_BID);
double tp = orderPrice + takeProfitDistance;
double sl = orderPrice - stopLossDistance;
int result = OrderSend(_Symbol, OP_BUY, Lots, orderPrice , 10, sl, tp, "Buy Order", 0, 0, clrGreen);
if (result > 0){
Print("Buy order placed. Ticket: ", result);
}
else{
int error = GetLastError();
string errorDescription = ErrorDescription(error);
Print("OrderSend failed with error #", error, ": ", errorDescription);
}
}
void PlaceOrderSell()
{
double orderPrice = SymbolInfoDouble(_Symbol, SYMBOL_BID);
double tp = orderPrice - takeProfitDistance;
double sl = orderPrice + stopLossDistance;
int result = OrderSend(_Symbol, OP_SELL, Lots, orderPrice , 10, sl, tp, "Sell Order", 0, 0, clrRed);
if (result > 0){
Print("Sell order placed. Ticket: ", result);
}
else{
int error = GetLastError();
string errorDescription = ErrorDescription(error);
Print("OrderSend failed with error #", error, ": ", errorDescription);
}
}
void updateTickData()
{
tickCounts ++;
// shift
for(int i = stdTicksNumbers - 1; i > 0; i--)
tickPrices[i] = tickPrices[i-1];
tickPrices[0] = (Bid + Ask) / 2.0;
}
double getSlope(const double &array[]){
return 0;
}
bool BuyIsOK(){
}
bool SellIsOK(){
}
void OnTick()
{
updateTickData();
datetime currentTime = iTime(NULL, 0, 0);
int timeDifferenceSinceLastOrder = currentTime - lastOrderOpenTime;
if (timeDifferenceSinceLastOrder > waitForOrderTime || lastOrderOpenTime == 0)
{
if (BuyIsOK())
{
PlaceOrderBuy();
lastOrderOpenTime = iTime(NULL, 0, 0);
}
else if (SellIsOK())
{
PlaceOrderSell();
lastOrderOpenTime = iTime(NULL, 0, 0);
}
}
}
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,73 @@
/**
* @copyright 2019, pipbolt.io <beta@pipbolt.io>
* @license https://github.com/pipbolt/experts/blob/master/LICENSE
*/
#include <PipboltFramework\Constants.mqh>
#define NAME "Bollinger Bands EA"
#define VERSION "0.022"
#property copyright COPYRIGHT
#property link LINK
#property icon ICON
#property description DESCRIPTION
#property version VERSION
#include <PipboltFramework\Params\MainSettings.mqh>
input group "Entry Strategy";
input group "Exit Strategy";
input bool UseExitStrategy = false; // Use Exit Strategy
input group "Bollinger Bands";
input int Bands_Period = 20; // Period
input double Bands_Deviation = 2; // Deviation
input ENUM_APPLIED_PRICE Bands_Applied_Price = PRICE_CLOSE; // Applied Price
#include <PipboltFramework\Experts.mqh>
CiBollinger BBands;
int OnInit(void)
{
if (ONINIT() != INIT_SUCCEEDED)
return INIT_FAILED;
BBands.Init(NULL, NULL, Bands_Period, 0, Bands_Deviation, Bands_Applied_Price);
return INIT_SUCCEEDED;
}
void OnTick(void) { ONTICK(); }
void OnDeinit(const int reason) { ONDEINIT(reason); }
void OnTimer() { ONTIMER(); }
void CheckForOpen(bool &openBuy, bool &openSell)
{
// Close variable
double close = iClose(NULL, NULL, _indicatorShift);
// Buy Entry Strategy
openBuy = close < BBands.Lower(0);
// Sell Entry Strategy
openSell = close > BBands.Upper(0);
// Apply MA Filter
openBuy = openBuy && MAFilter.Check(DIR_BUY);
openSell = openSell && MAFilter.Check(DIR_SELL);
}
void CheckForClose(bool &closeBuy, bool &closeSell)
{
// Close variable
double close = iClose(NULL, NULL, _indicatorShift);
// Buy Exit Strategy
closeBuy = close > BBands.Upper(0);
// Sell Exit Strategy
closeSell = close < BBands.Lower(0);
}
Binary file not shown.
+68
View File
@@ -0,0 +1,68 @@
/**
* @copyright 2019, pipbolt.io <beta@pipbolt.io>
* @license https://github.com/pipbolt/experts/blob/master/LICENSE
*/
#include <PipboltFramework\Constants.mqh>
#define NAME "Ichimoku EA"
#define VERSION "0.022"
#property copyright COPYRIGHT
#property link LINK
#property icon ICON
#property description DESCRIPTION
#property version VERSION
#include <PipboltFramework\Params\MainSettings.mqh>
input group "Entry Strategy";
input group "Exit Strategy";
input bool UseExitStrategy = false; // Use Exit Strategy
input group "Ichimoku Kynko Hyo";
input int tenkanSen = 9; // period of Tenkan-sen
input int kijunSen = 26; // period of Kijun-sen
input int senkouSpanB = 52; // period of Senkou Span B
#include <PipboltFramework\Experts.mqh>
CiIchimoku Ichimoku;
int OnInit(void)
{
if (ONINIT() != INIT_SUCCEEDED)
return INIT_FAILED;
Ichimoku.Init(NULL, NULL, tenkanSen, kijunSen, senkouSpanB);
return INIT_SUCCEEDED;
}
void OnTick(void) { ONTICK(); }
void OnDeinit(const int reason) { ONDEINIT(reason); }
void OnTimer() { ONTIMER(); }
void CheckForOpen(bool &openBuy, bool &openSell)
{
// Buy Entry Strategy
openBuy = Ichimoku.TenkanSen(0) > Ichimoku.KijunSen(0) && Ichimoku.TenkanSen(1) <= Ichimoku.KijunSen(1);
// Sell Entry Stategy
openSell = Ichimoku.TenkanSen(0) < Ichimoku.KijunSen(0) && Ichimoku.TenkanSen(1) >= Ichimoku.KijunSen(1);
// Apply MA Filter
openBuy = openBuy && MAFilter.Check(DIR_BUY);
openSell = openSell && MAFilter.Check(DIR_SELL);
}
void CheckForClose(bool &closeBuy, bool &closeSell)
{
// Buy Exit Strategy
closeBuy = Ichimoku.TenkanSen(0) <= Ichimoku.KijunSen(0);
// Sell Exit Stategy
closeSell = Ichimoku.TenkanSen(0) >= Ichimoku.KijunSen(0);
}
//+------------------------------------------------------------------+
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,825 @@
//+------------------------------------------------------------------+
//| ConservativeScalper.mq4 |
//| MT4 Conservative Scalping Expert Advisor|
//| |
//| Strategy: |
//| - M15 trend bias via EMA 50/200 |
//| - M5 execution via EMA 20 + RSI 14 + candle breakout |
//| - Session, spread, ATR, rollover, and day-of-week filters |
//| - Fixed-fractional risk sizing (default 0.25% per trade) |
//| - Hard SL/TP on every trade — no martingale, no grid |
//| - Break-even, trailing stop, time-based exit |
//| - Daily loss cap, max trades/day, consecutive loss pause |
//| - Equity drawdown hard stop |
//| |
//| Pairs: EURUSD, GBPUSD, USDJPY (tune per pair) |
//| Timeframe: M5 (with M15 bias) |
//+------------------------------------------------------------------+
#property copyright "NAK"
#property link "https://github.com/NadirAliOffical/conservative-scalper-ea"
#property version "1.00"
#property strict
//====================================================================
// GENERAL INPUTS
//====================================================================
extern int MagicNumber = 20260409; // Unique EA identifier
extern string TradeComment = "CScalp"; // Order comment tag
extern bool EnableLong = true; // Allow buy trades
extern bool EnableShort = true; // Allow sell trades
extern bool OneTradePerSymbol = true; // One open trade per symbol
extern bool AllowNewTrades = true; // Master on/off switch
//====================================================================
// SESSION / TIME FILTERS
//====================================================================
extern int SessionStartHour = 8; // Server hour to start trading
extern int SessionEndHour = 17; // Server hour to stop new trades
extern bool AllowMonday = true;
extern bool AllowTuesday = true;
extern bool AllowWednesday = true;
extern bool AllowThursday = true;
extern bool AllowFriday = false; // Off by default — thin close
extern int RolloverBlockBefore = 30; // Mins to block before 00:00
extern int RolloverBlockAfter = 30; // Mins to block after 00:00
//====================================================================
// BIAS INDICATORS (Higher timeframe)
//====================================================================
extern ENUM_TIMEFRAMES BiasTimeframe = PERIOD_M15; // Trend filter timeframe
extern int BiasFastEMA = 50; // Fast EMA period on bias TF
extern int BiasSlowEMA = 200; // Slow EMA period on bias TF
//====================================================================
// EXECUTION INDICATORS (Chart timeframe — run EA on M5)
//====================================================================
extern int ExecEMA_Period = 20; // EMA for local direction
extern int RSI_Period = 14; // RSI period
extern double RSI_LongLevel = 50.0; // RSI cross-above for longs
extern double RSI_ShortLevel = 50.0; // RSI cross-below for shorts
extern int ATR_Period = 14; // ATR period
extern double MinATR_Pips = 3.0; // Min ATR (pips) — avoid dead mkt
extern int BreakoutBars = 1; // Bars back for high/low breakout
//====================================================================
// RISK SIZING
//====================================================================
extern int LotSizingMode = 1; // 0=Fixed lot 1=Risk %
extern double FixedLot = 0.01; // Used when mode=0
extern double RiskPercent = 0.50; // % of equity risked per trade
extern double MaxSpreadPips = 2.5; // Max allowed spread in pips
extern int MaxSlippagePts = 3; // Max slippage in broker points
//====================================================================
// STOP LOSS / TAKE PROFIT
//====================================================================
extern int StopLossMode = 1; // 0=Fixed pips 1=ATR multiple
extern double StopLossPips = 8.0; // Fixed SL (pips) mode=0
extern double StopLossATRMult = 1.2; // ATR multiplier for SL mode=1
extern int TakeProfitMode = 1; // 0=Fixed pips 1=ATR multiple
extern double TakeProfitPips = 10.0; // Fixed TP (pips) mode=0
extern double TakeProfitATRMult = 1.2; // ATR multiplier for TP mode=1
//====================================================================
// TRADE MANAGEMENT
//====================================================================
extern bool UseBreakEven = true;
extern double BreakEvenTriggerR = 0.8; // Move SL to BE after 0.8R profit
extern double BreakEvenOffsetPips = 0.5; // Buffer pips beyond entry for BE
extern bool UseTrailingStop = false;
extern double TrailingStartR = 1.0; // Start trailing after 1R profit
extern double TrailingDistancePips = 5.0; // Trail distance in pips
extern bool UseTimeExit = true;
extern int MaxTradeMinutes = 20; // Close stalled trades after N min
extern bool CloseAtSessionEnd = true; // Close open trades at session end
//====================================================================
// DAILY / SESSION PROTECTION
//====================================================================
extern int MaxTradesPerDay = 6; // Max new trades per session day
extern double MaxDailyLossPercent = 2.0; // Stop trading if daily loss >= X%
extern int MaxConsecutiveLosses = 3; // Pause after N consecutive losses
extern double MaxDrawdownPercent = 20.0; // Hard stop if equity DD >= X%
extern double MaxTotalOpenRiskPct = 1.0; // Cap on total open risk %
//====================================================================
// NEWS FILTER (auto-fetches ForexFactory calendar)
//====================================================================
extern bool UseNewsFilter = true; // Enable automatic news filter
extern string NewsFilterCurrencies = "USD,EUR,GBP";// Block news for these currencies
extern int NewsBlockMinsBefore = 30; // Mins to block before event
extern int NewsBlockMinsAfter = 30; // Mins to block after event
extern int BrokerGMTOffset = 2; // Broker server GMT offset (check chart)
//====================================================================
// GLOBALS
//====================================================================
double g_pip; // Value of 1 pip in price units
double g_point; // Broker point
int g_digits; // Symbol digits
int g_todayTrades; // Trades opened today
double g_todayStartEquity; // Equity at start of today
int g_consecutiveLosses; // Rolling loss streak count
int g_lastHistoryTotal; // History size snapshot (for tracking closed orders)
bool g_tradingHalted; // True when max DD hit (persists across days)
double g_peakEquity; // All-time equity high for DD calculation
datetime g_lastTradeDay; // Date of last counter reset
// News filter globals
datetime g_newsEvents[];
int g_newsEventCount = 0;
datetime g_lastNewsFetch = 0;
datetime g_lastNewsLogTime = 0;
// GlobalVariable key names (set in OnInit)
string g_gvPeak;
string g_gvHalt;
string g_gvConsec;
//+------------------------------------------------------------------+
//| INIT |
//+------------------------------------------------------------------+
int OnInit()
{
g_digits = (int)MarketInfo(Symbol(), MODE_DIGITS);
// Normalise pip for 4-digit and 5-digit brokers
if(g_digits == 5 || g_digits == 3)
g_pip = Point * 10;
else
g_pip = Point;
g_point = Point;
// GlobalVariable keys unique to this symbol + magic number
string suffix = Symbol() + "_" + IntegerToString(MagicNumber);
g_gvPeak = "CScalp_Peak_" + suffix;
g_gvHalt = "CScalp_Halt_" + suffix;
g_gvConsec = "CScalp_Consec_" + suffix;
g_todayTrades = 0;
g_todayStartEquity = AccountEquity();
g_lastHistoryTotal = OrdersHistoryTotal();
g_lastTradeDay = 0;
// Restore persistent state so restarts don't reset DD protection
g_peakEquity = GlobalVariableCheck(g_gvPeak) ? GlobalVariableGet(g_gvPeak) : AccountEquity();
g_tradingHalted = GlobalVariableCheck(g_gvHalt) && GlobalVariableGet(g_gvHalt) > 0;
g_consecutiveLosses = GlobalVariableCheck(g_gvConsec) ? (int)GlobalVariableGet(g_gvConsec) : 0;
Log("Initialized | Symbol=" + Symbol() +
" Digits=" + IntegerToString(g_digits) +
" Pip=" + DoubleToString(g_pip, g_digits + 1));
return INIT_SUCCEEDED;
}
//+------------------------------------------------------------------+
//| DEINIT |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
Log("Deinitialized | Reason=" + IntegerToString(reason));
}
//+------------------------------------------------------------------+
//| TICK |
//+------------------------------------------------------------------+
void OnTick()
{
// 1. Reset daily counters if calendar date changed
ResetDailyIfNewDay();
// 2a. Refresh news calendar once per day
FetchNewsCalendar();
// 2. Track peak equity
if(AccountEquity() > g_peakEquity)
{
g_peakEquity = AccountEquity();
GlobalVariableSet(g_gvPeak, g_peakEquity);
}
// 3. Track closed order outcomes (update consecutive loss counter)
TrackClosedOrders();
// 4. Manage existing open trades (BE, trail, time/session exit)
ManageOpenTrades();
// 5. Evaluate new entry
if(!CanOpenNewTrade()) return;
int signal = GetEntrySignal();
if(signal != 0) ExecuteTrade(signal);
}
//====================================================================
// DAILY RESET
//====================================================================
void ResetDailyIfNewDay()
{
datetime today = StringToTime(TimeToStr(TimeCurrent(), TIME_DATE));
if(today == g_lastTradeDay) return;
g_lastTradeDay = today;
g_todayTrades = 0;
g_todayStartEquity = AccountEquity();
// Consecutive loss streak is NOT reset on new day — only a win resets it
Log("New day reset | Equity=" + DoubleToString(AccountEquity(), 2));
}
//====================================================================
// PRE-TRADE GATE CHECKS
//====================================================================
bool CanOpenNewTrade()
{
if(!AllowNewTrades) return false;
if(g_tradingHalted) return false;
// Hard drawdown check
if(g_peakEquity > 0)
{
double dd = (g_peakEquity - AccountEquity()) / g_peakEquity * 100.0;
if(dd >= MaxDrawdownPercent)
{
Log("HARD HALT — max drawdown " + DoubleToString(dd, 2) + "% reached");
g_tradingHalted = true;
GlobalVariableSet(g_gvHalt, 1.0);
return false;
}
}
// Daily loss cap
if(g_todayStartEquity > 0)
{
double dailyLoss = (g_todayStartEquity - AccountEquity()) / g_todayStartEquity * 100.0;
if(dailyLoss >= MaxDailyLossPercent) return false;
}
// Max trades today
if(g_todayTrades >= MaxTradesPerDay) return false;
// Consecutive loss pause
if(g_consecutiveLosses >= MaxConsecutiveLosses) return false;
// Day of week
if(!IsAllowedDay()) return false;
// Session hours
if(!IsSessionTime()) return false;
// Rollover block
if(IsRolloverTime()) return false;
// News filter
if(IsNewsTime()) return false;
// Spread
double spreadPips = MarketInfo(Symbol(), MODE_SPREAD) * g_point / g_pip;
if(spreadPips > MaxSpreadPips) return false;
// ATR minimum (avoid dead market)
double atrPips = iATR(Symbol(), Period(), ATR_Period, 1) / g_pip;
if(atrPips < MinATR_Pips) return false;
// One trade per symbol
if(OneTradePerSymbol && HasOpenTrade()) return false;
// Total open risk cap
if(GetTotalOpenRiskPct() >= MaxTotalOpenRiskPct) return false;
return true;
}
//====================================================================
// ENTRY SIGNAL
// Returns: 1 = BUY -1 = SELL 0 = NONE
//====================================================================
int GetEntrySignal()
{
// --- Higher timeframe bias (M15 EMA 50 vs 200) ---
double biasFast = iMA(Symbol(), BiasTimeframe, BiasFastEMA, 0, MODE_EMA, PRICE_CLOSE, 1);
double biasSlow = iMA(Symbol(), BiasTimeframe, BiasSlowEMA, 0, MODE_EMA, PRICE_CLOSE, 1);
double biasFastPrev = iMA(Symbol(), BiasTimeframe, BiasFastEMA, 0, MODE_EMA, PRICE_CLOSE, 2);
bool bullBias = (biasFast > biasSlow) && (biasFast >= biasFastPrev);
bool bearBias = (biasFast < biasSlow) && (biasFast <= biasFastPrev);
// --- Execution timeframe indicators ---
double execEMA = iMA(Symbol(), Period(), ExecEMA_Period, 0, MODE_EMA, PRICE_CLOSE, 1);
double rsiNow = iRSI(Symbol(), Period(), RSI_Period, PRICE_CLOSE, 1);
double rsiPrev = iRSI(Symbol(), Period(), RSI_Period, PRICE_CLOSE, 2);
double prevHigh = iHigh(Symbol(), Period(), BreakoutBars + 1);
double prevLow = iLow(Symbol(), Period(), BreakoutBars + 1);
double closeNow = iClose(Symbol(), Period(), 1);
// --- LONG ---
if(EnableLong && bullBias)
{
bool aboveEMA = (closeNow > execEMA);
bool rsiCross = (rsiNow >= RSI_LongLevel) && (rsiPrev < RSI_LongLevel);
bool breakout = (closeNow > prevHigh);
if(aboveEMA && rsiCross && breakout) return 1;
}
// --- SHORT ---
if(EnableShort && bearBias)
{
bool belowEMA = (closeNow < execEMA);
bool rsiCross = (rsiNow <= RSI_ShortLevel) && (rsiPrev > RSI_ShortLevel);
bool breakout = (closeNow < prevLow);
if(belowEMA && rsiCross && breakout) return -1;
}
return 0;
}
//====================================================================
// EXECUTE TRADE
//====================================================================
void ExecuteTrade(int direction)
{
double atr = iATR(Symbol(), Period(), ATR_Period, 1);
// SL distance
double slDist = (StopLossMode == 0)
? StopLossPips * g_pip
: StopLossATRMult * atr;
// TP distance
double tpDist = (TakeProfitMode == 0)
? TakeProfitPips * g_pip
: TakeProfitATRMult * atr;
// Enforce broker minimum stop level
double minStop = MarketInfo(Symbol(), MODE_STOPLEVEL) * g_point;
if(slDist < minStop + g_pip) slDist = minStop + g_pip;
if(tpDist < minStop + g_pip) tpDist = minStop + g_pip;
// Lot size
double lots = (LotSizingMode == 0)
? FixedLot
: CalcLotByRisk(slDist);
lots = NormalizeLots(lots);
if(lots <= 0)
{
Log("ERROR: Lot size <=0 — trade skipped");
return;
}
// Free margin check
double reqMargin = MarketInfo(Symbol(), MODE_MARGINREQUIRED) * lots;
if(AccountFreeMargin() < reqMargin)
{
Log("ERROR: Insufficient margin — trade skipped");
return;
}
double sl, tp;
int cmd;
double price;
color arrowCol;
if(direction == 1)
{
cmd = OP_BUY;
price = Ask;
sl = NormalizeDouble(price - slDist, g_digits);
tp = NormalizeDouble(price + tpDist, g_digits);
arrowCol = clrDodgerBlue;
}
else
{
cmd = OP_SELL;
price = Bid;
sl = NormalizeDouble(price + slDist, g_digits);
tp = NormalizeDouble(price - tpDist, g_digits);
arrowCol = clrOrangeRed;
}
int ticket = OrderSend(Symbol(), cmd, lots, price, MaxSlippagePts,
sl, tp, TradeComment, MagicNumber, 0, arrowCol);
if(ticket < 0)
{
Log("ORDER FAILED | Error=" + IntegerToString(GetLastError()) +
" Dir=" + IntegerToString(direction));
}
else
{
g_todayTrades++;
Log("ORDER OPEN | Ticket=" + IntegerToString(ticket) +
" Dir=" + IntegerToString(direction) +
" Lots=" + DoubleToString(lots, 2) +
" Price=" + DoubleToString(price, g_digits) +
" SL=" + DoubleToString(sl, g_digits) +
" TP=" + DoubleToString(tp, g_digits) +
" SLpips=" + DoubleToString(slDist / g_pip, 1));
}
}
//====================================================================
// MANAGE OPEN TRADES (BE, trail, time/session exits)
//====================================================================
void ManageOpenTrades()
{
for(int i = OrdersTotal() - 1; i >= 0; i--)
{
if(!OrderSelect(i, SELECT_BY_POS, MODE_TRADES)) continue;
if(OrderSymbol() != Symbol()) continue;
if(OrderMagicNumber() != MagicNumber) continue;
if(OrderType() > OP_SELL) continue; // skip pending
int ticket = OrderTicket();
int type = OrderType();
double openPrice = OrderOpenPrice();
double curSL = OrderStopLoss();
double curTP = OrderTakeProfit();
double slDist = MathAbs(openPrice - curSL);
// --- Session-end close ---
if(CloseAtSessionEnd && !IsSessionTime())
{
CloseOrder(ticket, type, "SessionEnd");
continue;
}
// --- Time-based exit ---
if(UseTimeExit)
{
int minsOpen = (int)((TimeCurrent() - OrderOpenTime()) / 60);
if(minsOpen >= MaxTradeMinutes)
{
CloseOrder(ticket, type, "TimeExit");
continue;
}
}
// Current P&L in price units
double profit = (type == OP_BUY)
? Bid - openPrice
: openPrice - Ask;
double profitR = (slDist > 0) ? profit / slDist : 0;
// --- Break-even ---
if(UseBreakEven && slDist > 0 && profitR >= BreakEvenTriggerR)
{
double beOffset = BreakEvenOffsetPips * g_pip;
if(type == OP_BUY)
{
double newSL = NormalizeDouble(openPrice + beOffset, g_digits);
if(newSL > curSL + g_point)
{
if(OrderModify(ticket, openPrice, newSL, curTP, 0, clrGold))
Log("BE set | Ticket=" + IntegerToString(ticket) +
" NewSL=" + DoubleToString(newSL, g_digits));
}
}
else
{
double newSL = NormalizeDouble(openPrice - beOffset, g_digits);
if(curSL == 0 || newSL < curSL - g_point)
{
if(OrderModify(ticket, openPrice, newSL, curTP, 0, clrGold))
Log("BE set | Ticket=" + IntegerToString(ticket) +
" NewSL=" + DoubleToString(newSL, g_digits));
}
}
}
// --- Trailing stop ---
if(UseTrailingStop && slDist > 0 && profitR >= TrailingStartR)
{
double trailDist = TrailingDistancePips * g_pip;
if(type == OP_BUY)
{
double newSL = NormalizeDouble(Bid - trailDist, g_digits);
if(newSL > curSL + g_point)
{
if(OrderModify(ticket, openPrice, newSL, curTP, 0, clrAqua))
Log("Trail updated | Ticket=" + IntegerToString(ticket) +
" NewSL=" + DoubleToString(newSL, g_digits));
}
}
else
{
double newSL = NormalizeDouble(Ask + trailDist, g_digits);
if(curSL == 0 || newSL < curSL - g_point)
{
if(OrderModify(ticket, openPrice, newSL, curTP, 0, clrAqua))
Log("Trail updated | Ticket=" + IntegerToString(ticket) +
" NewSL=" + DoubleToString(newSL, g_digits));
}
}
}
}
}
//====================================================================
// TRACK CLOSED ORDERS (update consecutive loss counter)
//====================================================================
void TrackClosedOrders()
{
int histTotal = OrdersHistoryTotal();
if(histTotal <= g_lastHistoryTotal) return;
for(int i = g_lastHistoryTotal; i < histTotal; i++)
{
if(!OrderSelect(i, SELECT_BY_POS, MODE_HISTORY)) continue;
if(OrderSymbol() != Symbol()) continue;
if(OrderMagicNumber() != MagicNumber) continue;
if(OrderType() > OP_SELL) continue;
double netPnl = OrderProfit() + OrderSwap() + OrderCommission();
if(netPnl < 0)
{
g_consecutiveLosses++;
GlobalVariableSet(g_gvConsec, (double)g_consecutiveLosses);
Log("LOSS | Ticket=" + IntegerToString(OrderTicket()) +
" PnL=" + DoubleToString(netPnl, 2) +
" ConsecLosses=" + IntegerToString(g_consecutiveLosses));
}
else
{
if(g_consecutiveLosses > 0)
Log("WIN — loss streak reset from " + IntegerToString(g_consecutiveLosses));
g_consecutiveLosses = 0;
GlobalVariableSet(g_gvConsec, 0.0);
}
}
g_lastHistoryTotal = histTotal;
}
//====================================================================
// CLOSE ORDER HELPER
//====================================================================
void CloseOrder(int ticket, int type, string reason)
{
double price = (type == OP_BUY) ? Bid : Ask;
bool ok = OrderClose(ticket, OrderLots(), price, MaxSlippagePts, clrWhite);
if(ok)
Log("ORDER CLOSED | Ticket=" + IntegerToString(ticket) + " Reason=" + reason);
else
Log("CLOSE FAILED | Ticket=" + IntegerToString(ticket) +
" Error=" + IntegerToString(GetLastError()));
}
//====================================================================
// POSITION SIZING
//====================================================================
double CalcLotByRisk(double slDist)
{
double equity = AccountEquity();
double riskAmt = equity * RiskPercent / 100.0;
double tickVal = MarketInfo(Symbol(), MODE_TICKVALUE);
double tickSize = MarketInfo(Symbol(), MODE_TICKSIZE);
if(tickVal <= 0 || tickSize <= 0 || slDist <= 0) return FixedLot;
double slTicks = slDist / tickSize;
return riskAmt / (slTicks * tickVal);
}
double NormalizeLots(double lots)
{
double minLot = MarketInfo(Symbol(), MODE_MINLOT);
double maxLot = MarketInfo(Symbol(), MODE_MAXLOT);
double lotStep = MarketInfo(Symbol(), MODE_LOTSTEP);
if(lotStep > 0)
lots = MathFloor(lots / lotStep) * lotStep;
return NormalizeDouble(MathMax(minLot, MathMin(maxLot, lots)), 2);
}
//====================================================================
// UTILITY FUNCTIONS
//====================================================================
bool HasOpenTrade()
{
for(int i = 0; i < OrdersTotal(); i++)
{
if(!OrderSelect(i, SELECT_BY_POS, MODE_TRADES)) continue;
if(OrderSymbol() == Symbol() && OrderMagicNumber() == MagicNumber)
return true;
}
return false;
}
double GetTotalOpenRiskPct()
{
double totalRisk = 0;
double equity = AccountEquity();
if(equity <= 0) return 0;
for(int i = 0; i < OrdersTotal(); i++)
{
if(!OrderSelect(i, SELECT_BY_POS, MODE_TRADES)) continue;
if(OrderMagicNumber() != MagicNumber) continue;
if(OrderType() > OP_SELL) continue;
double sl = OrderStopLoss();
if(sl == 0) continue;
double slDist = MathAbs(OrderOpenPrice() - sl);
double tickVal = MarketInfo(OrderSymbol(), MODE_TICKVALUE);
double tickSize = MarketInfo(OrderSymbol(), MODE_TICKSIZE);
if(tickSize <= 0) continue;
totalRisk += (slDist / tickSize) * tickVal * OrderLots() / equity * 100.0;
}
return totalRisk;
}
bool IsSessionTime()
{
int h = TimeHour(TimeCurrent());
return (h >= SessionStartHour && h < SessionEndHour);
}
bool IsRolloverTime()
{
int h = TimeHour(TimeCurrent());
int m = TimeMinute(TimeCurrent());
int totalMin = h * 60 + m;
// Minutes until next midnight
int beforeMid = 1440 - totalMin;
// Minutes since last midnight
int afterMid = totalMin;
return (beforeMid <= RolloverBlockBefore || afterMid <= RolloverBlockAfter);
}
bool IsAllowedDay()
{
int dow = TimeDayOfWeek(TimeCurrent());
switch(dow)
{
case 1: return AllowMonday;
case 2: return AllowTuesday;
case 3: return AllowWednesday;
case 4: return AllowThursday;
case 5: return AllowFriday;
default: return false;
}
}
//====================================================================
// NEWS FILTER — auto-fetches ForexFactory high-impact calendar
// Requires: MT4 Tools → Options → Expert Advisors →
// Allow WebRequest for: https://nfs.faireconomy.media
//====================================================================
void FetchNewsCalendar()
{
if(!UseNewsFilter) return;
datetime today = StringToTime(TimeToStr(TimeCurrent(), TIME_DATE));
if(g_lastNewsFetch == today) return; // Already fetched today
string url = "https://nfs.faireconomy.media/ff_calendar_thisweek.json";
string headers = "User-Agent: Mozilla/5.0\r\n";
char post[];
char result[];
string resultHeaders;
ResetLastError();
int httpCode = WebRequest("GET", url, headers, 10000, post, result, resultHeaders);
if(httpCode != 200)
{
Log("NEWS: Fetch failed. HTTP=" + IntegerToString(httpCode) +
" Error=" + IntegerToString(GetLastError()) +
" — Check WebRequest whitelist in MT4 options");
return;
}
string json = CharArrayToString(result);
ParseNewsJSON(json);
g_lastNewsFetch = today;
Log("NEWS: Calendar updated. High-impact events found=" + IntegerToString(g_newsEventCount));
}
void ParseNewsJSON(string json)
{
g_newsEventCount = 0;
ArrayResize(g_newsEvents, 200);
int pos = 0;
int jsonLen = StringLen(json);
while(pos < jsonLen)
{
// Find next JSON object
int objStart = StringFind(json, "{", pos);
if(objStart < 0) break;
int objEnd = StringFind(json, "}", objStart);
if(objEnd < 0) break;
string obj = StringSubstr(json, objStart, objEnd - objStart + 1);
// Only process High impact events
if(StringFind(obj, "\"impact\":\"High\"") >= 0)
{
// Check currency filter
string country = ExtractJSONString(obj, "country");
if(StringFind(NewsFilterCurrencies, country) >= 0)
{
// Parse date
string dateStr = ExtractJSONString(obj, "date");
datetime eventTime = ParseISODate(dateStr);
if(eventTime > 0 && g_newsEventCount < 200)
{
g_newsEvents[g_newsEventCount] = eventTime;
g_newsEventCount++;
string title = ExtractJSONString(obj, "title");
Log("NEWS: Loaded | " + country + " " + title +
" @ " + TimeToStr(eventTime, TIME_DATE | TIME_MINUTES));
}
}
}
pos = objEnd + 1;
}
ArrayResize(g_newsEvents, g_newsEventCount);
}
string ExtractJSONString(string obj, string key)
{
string search = "\"" + key + "\":\"";
int start = StringFind(obj, search);
if(start < 0) return "";
start += StringLen(search);
int end = StringFind(obj, "\"", start);
if(end < 0) return "";
return StringSubstr(obj, start, end - start);
}
datetime ParseISODate(string iso)
{
// Format: "2026-04-04T08:30:00-0400"
if(StringLen(iso) < 19) return 0;
int year = (int)StringToInteger(StringSubstr(iso, 0, 4));
int month = (int)StringToInteger(StringSubstr(iso, 5, 2));
int day = (int)StringToInteger(StringSubstr(iso, 8, 2));
int hour = (int)StringToInteger(StringSubstr(iso, 11, 2));
int min = (int)StringToInteger(StringSubstr(iso, 14, 2));
// Parse timezone offset (e.g. -0400 or +0000)
int tzOffsetSecs = 0;
int tzPos = StringFind(iso, "+", 19);
int tzSign = 1;
if(tzPos < 0) { tzPos = StringFind(iso, "-", 19); tzSign = -1; }
if(tzPos >= 0)
{
int tzH = (int)StringToInteger(StringSubstr(iso, tzPos + 1, 2));
int tzM = (int)StringToInteger(StringSubstr(iso, tzPos + 3, 2));
tzOffsetSecs = tzSign * (tzH * 3600 + tzM * 60);
}
// Build UTC datetime
string dtStr = StringFormat("%04d.%02d.%02d %02d:%02d", year, month, day, hour, min);
datetime utc = StringToTime(dtStr) - tzOffsetSecs;
// Convert UTC → broker server time
datetime serverTime = utc + BrokerGMTOffset * 3600;
return serverTime;
}
bool IsNewsTime()
{
if(!UseNewsFilter || g_newsEventCount == 0) return false;
datetime now = TimeCurrent();
int blockBefore = NewsBlockMinsBefore * 60;
int blockAfter = NewsBlockMinsAfter * 60;
for(int i = 0; i < g_newsEventCount; i++)
{
if(now >= g_newsEvents[i] - blockBefore &&
now <= g_newsEvents[i] + blockAfter)
{
if(g_newsEvents[i] != g_lastNewsLogTime)
{
Log("NEWS: Trading blocked near event @ " +
TimeToStr(g_newsEvents[i], TIME_DATE | TIME_MINUTES));
g_lastNewsLogTime = g_newsEvents[i];
}
return true;
}
}
return false;
}
void Log(string msg)
{
Print("[CScalp] " + TimeToStr(TimeCurrent(), TIME_DATE | TIME_MINUTES) + " | " + msg);
}
//+------------------------------------------------------------------+
Binary file not shown.
@@ -0,0 +1,103 @@
//+------------------------------------------------------------------+
//| XAUUSD / USDJPY ATR Scalper EA |
//| Author: GIMS_Dev |
//| Platform: MetaTrader 4 |
//| Strategy: ATR + Trend + Price Action |
//+------------------------------------------------------------------+
#property strict
// ================= INPUTS =================
input double Lots = 0.01;
input int ATR_Period = 14;
input double ATR_Multiplier_SL = 1.2;
input double ATR_Multiplier_TP = 1.5;
input int EMA_Fast = 50;
input int EMA_Slow = 200;
input int Slippage = 3;
input int BreakevenPips = 20;
input int TrailingStopPips = 15;
input int MaxTradesPerSymbol = 3;
input int MagicNumber = 123456;
// ================= SYMBOLS =================
string Symbols[] = {"XAUUSD", "USDJPY"};
//+------------------------------------------------------------------+
int OnInit()
{
CreateDashboard();
Print("ATR Scalper EA initialized");
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
ObjectsDeleteAll(0, OBJ_LABEL);
}
//+------------------------------------------------------------------+
void OnTick()
{
for(int i=0; i<ArraySize(Symbols); i++)
{
string sym = Symbols[i];
if(!SymbolSelect(sym, true)) continue;
ManageTrades(sym);
if(CanOpenTrade(sym))
EvaluateEntry(sym);
UpdateDashboard(sym);
}
}
//+------------------------------------------------------------------+
// ================= ENTRY LOGIC =================
void EvaluateEntry(string sym)
{
if(!TrendIsValid(sym)) return;
if(!EngulfingPattern(sym)) return;
PlaceMarketOrder(sym);
}
// ================= TREND FILTER =================
bool TrendIsValid(string sym)
{
double fast = iMA(sym, PERIOD_H1, EMA_Fast, 0, MODE_EMA, PRICE_CLOSE, 0);
double slow = iMA(sym, PERIOD_H1, EMA_Slow, 0, MODE_EMA, PRICE_CLOSE, 0);
return (fast > slow || fast < slow);
}
// ================= PRICE ACTION =================
bool EngulfingPattern(string sym)
{
double o1 = iOpen(sym, PERIOD_M5, 1);
double c1 = iClose(sym, PERIOD_M5, 1);
double o2 = iOpen(sym, PERIOD_M5, 2);
double c2 = iClose(sym, PERIOD_M5, 2);
bool bullish = c2 < o2 && c1 > o1 && c1 > o2;
bool bearish = c2 > o2 && c1 < o1 && c1 < o2;
return (bullish || bearish);
}
// ================= ORDER PLACEMENT =================
void PlaceMarketOrder(string sym)
{
double atr = iATR(sym, PERIOD_M5, ATR_Period, 0);
if(atr <= 0) return;
double point = MarketInfo(sym, MODE_POINT);
int digits = (int)MarketInfo(sym, MODE_DIGITS);
double ask = MarketInfo(sym, MODE_ASK);
double bid = MarketInfo(sym, MODE_BID);
double sl, tp;
int type;
}
Binary file not shown.
+409
View File
@@ -0,0 +1,409 @@
//+------------------------------------------------------------------+
//| ThreeBarPlay.mq4 |
//| Copyright 2020, MetaQuotes Software Corp. |
//| https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2020, MetaQuotes Software Corp."
#property link "https://www.mql5.com"
#property version "1.00"
#property strict
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
//---
//---
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Expert deinitialization function |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
//---
}
//+------------------------------------------------------------------+
//| trading mechanics is the same as BUYSTOCK/SELLSTOCK scripts |
//+------------------------------------------------------------------+
int numOfTrades=0;
int takeprofit=100;
int stoploss=100;
void trade(bool buy, int sl)
{
numOfTrades++;
if(buy)
{
int pips=sl;
double risk=AccountBalance()*0.02/1.3;
double shares = (int)(risk / pips * 100);
double maxShares = (int)(AccountFreeMargin()/1.3 * 14.8 / (Ask));
if((MarketInfo(_Symbol,17))<0.01)//if forex
{
maxShares/=100;
shares/=100;
}
if(shares>(MarketInfo(_Symbol,MODE_MAXLOT)))
{
shares=MarketInfo(_Symbol,MODE_MAXLOT);
}
if(maxShares < shares)
{
shares = maxShares;
pips=(int)(risk/shares*100);
}
Alert("Buy ",shares," shares of ", _Symbol);
double x=Ask;
double y=shares*0.67;
double z=shares*0.33;
int pipstostoploss=pips;
int takeprofit2= pips;
int takeprofit1= (int)(pips/2);
int order0=OrderSend(
_Symbol,//currencyPair
OP_BUY,//buy
y,//howmuch*SYMBOL_VOLUME_MIN
x,//price
3,//tolerance
x-pipstostoploss*_Point, //stoploss
x+takeprofit1*_Point,//takeprofit
NULL,//comment
0,//magic number
0,//expiration
CLR_NONE//color of arrow
);
int order1=OrderSend(
_Symbol,//currencyPair
OP_BUY,//buy
z,//howmuch*SYMBOL_VOLUME_MIN
x,//price
3,//tolerance
x-pipstostoploss*_Point, //stoploss
x+takeprofit2*_Point,//takeprofit
NULL,//comment
0,//magic number
0,//expiration
CLR_NONE//color of arrow
);
}
else
if(!buy)
{
int pips=sl;
double risk=AccountBalance()*0.02/1.3;
double shares = (int)(risk / pips * 100);
double maxShares = (int)(AccountFreeMargin()/1.3 * 14.8 / (Bid));
if((MarketInfo(_Symbol,17))<0.01)//if forex
{
maxShares/=100;
shares/=100;
}
if(shares>(MarketInfo(_Symbol,MODE_MAXLOT)))
{
shares=MarketInfo(_Symbol,MODE_MAXLOT);
}
if(maxShares < shares)
{
shares = maxShares;
pips=(int)(risk/shares*100);
}
Alert("Sell ",shares," shares of ", _Symbol);
double x=Bid;
double y=shares*0.67;
double z=shares*0.33;
int pipstostoploss=pips;
int takeprofit2= pips;
int takeprofit1= (int)(pips/2);
int order0=OrderSend(
_Symbol,//currencyPair
OP_SELL,//sell
y,//howmuch*SYMBOL_VOLUME_MIN
x,//price
3,//tolerance
x+pipstostoploss*_Point, //stoploss
x-takeprofit1*_Point,//takeprofit
NULL,//comment
0,//magic number
0,//expiration
CLR_NONE//color of arrow
);
int order1=OrderSend(
_Symbol,//currencyPair
OP_SELL,//sell
z,//howmuch*SYMBOL_VOLUME_MIN
x,//price
3,//tolerance
x+pipstostoploss*_Point, //stoploss
x-takeprofit2*_Point,//takeprofit
NULL,//comment
0,//magic number
0,//expiration
CLR_NONE//color of arrow
);
}
}
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
double height;
bool traded=false;
void OnTick()
{
//find average size of candlesticks
int numOfCandles=200;
double total=0;
for(int i=0; i<numOfCandles; i++)
{
total+=(MathAbs(Open[i]-Close[i]));
}
double average=(int)((total/numOfCandles)/_Point);
//average volume
double totalVol=0;
for(int i=0; i<50; i++)
{
totalVol+=Volume[i];
}
double averageVol=(totalVol/(50));
//delete all trades with second candle doji
bool doji=false;
bool hammer =false;
bool star=false;
double high=High[1];
double low=Low[1];
double open=Open[1];
double close=Close[1];
double body=open-close;
double top=0;
double bot=0;
double topratio,botratio;
if(body>0)
{
top=high-close;
bot=open-low;
}
else
if(body<0)
{
top=high-open;
bot=close-low;
}
if(body!=0)
{
topratio=top/(MathAbs(body));
botratio=bot/(MathAbs(body));
}
else
{
//if body is 0
topratio=0;
botratio=0;
}
double dojiratio=1;
if((botratio>=dojiratio)&&(topratio>=dojiratio)&&(botratio>=(dojiratio+2))&&(topratio>=(dojiratio+2)))
{
doji=true;
if((botratio/topratio)>=2)
{
doji=false;
hammer=true;
}
else
if((topratio/botratio)>=2)
{
doji=false;
star=true;
}
}
else
if((botratio>=dojiratio)&&(botratio>=(dojiratio+2)))
{
hammer=true;
}
else
if((topratio>=(dojiratio+2))&&(topratio>=dojiratio))
{
star=true;
}
/*
calculations:
if spread<=16, then look for plays
ignition is any bar [a certain number] times or more than spread
correction is if second bar is less than 1 quarter ignition in op direction
enter trade when bid passes the ignition close
stoploss will be at ignition's open+spread
*/
//init variables
double MFI=iMFI(_Symbol,_Period,14,0);
int spread=SYMBOL_SPREAD;
double goldenNum=0.8;
double goldenMax=10;
double goldenNum2=2.5;
bool bull=false;
bool bear=false;
bool ignition=false;
bool correction=false;
bool confirmation=false;
bool rejection=false;
int height2=(int)((Close[2]-Open[2])/_Point);
int height1=(int)((Close[1]-Open[1])/_Point);
//one trade per 3barcombo
if(height!=Close[1])
{
traded=false;
}
//ignition : any bar [a certain number] times or more than average candle
if((height2>=(goldenNum*average))&&(height2<=(goldenMax*average)))
{
ignition=true;
//bull
bull=true;
bear=false;
}
if((height2<=(goldenNum*-1*average))&&(height2>=(goldenMax*-1*average)))
{
ignition=true;
bear=true;
bull=false;
height2*=-1;
}
//correction : second bar is less than [a second certain number] times of ignition in op direction
if(bull && (height1<-2) && (height1>=((-1)*height2/goldenNum2)))
{
if(!doji && !star)
{
correction=true;
}
}
else
if((bear &&(height1>2) && (height1<=(height2/goldenNum2))))
{
if(!doji && !hammer)
{
correction=true;
}
}
//confirmation : when the price passes the ignition close
if(((bull)&&(Ask>=(Close[2]+(spread*_Point))))||((bear)&&(Bid<=(Close[2]-(spread*_Point)))))
{
if(correction)
{
confirmation=true;
}
}
else
{
if(((bull)&&(Bid<=(Close[1]-(1.5*spread*_Point))))||((bear)&&(Ask>=(Close[1]+(1.5*spread*_Point)))))
{
if((bull==true)&&(bear==false)&&(star||doji))
{
rejection=true;
bear=true;
bull=false;
}
else
if((bear==true)&&(bull==false)&&(hammer||doji))
{
rejection=true;
bull=true;
bear=false;
}
}
}
//make trade if all true
//only trade with higher than average relative volume
bool withVol=false;
withVol=((Volume[1]/averageVol)>=1);
//trading format "trade(bool buy,int pipstostoploss));"
if(ignition && correction && confirmation && bull && !traded && withVol)
{
//buy after confirmation
stoploss=height2+(2*spread);
takeprofit=stoploss/2;
trade(true,stoploss);
traded=true;
}
else
if(ignition && correction && confirmation && bear && !traded && withVol)
{
//sell after confirmation
stoploss=height2+(2*spread);
takeprofit=stoploss/2;
trade(false,stoploss);
traded=true;
}
else
if(!traded && ignition && bull && rejection && withVol)
{
//buy after rejection
stoploss=height2+spread;
takeprofit=stoploss/2;
trade(true,stoploss);
traded=true;
}
else
if(!traded && ignition && bear && rejection && withVol)
{
//sell after rejection
stoploss=height2+spread;
takeprofit=stoploss/2;
trade(false,stoploss);
traded=true;
}
Comment(
"balance : ",AccountBalance(),"\n",
"ignition : ",ignition,"\n",
"correction : ",correction,"\n",
"confirmation: ",confirmation,"\n",
"doji: ",doji,"\n",
"hammer: ",hammer,"\n",
"star: ",star,"\n",
numOfTrades," trades "
);
height=Close[1];
//if there is a trade open, make a trailing stop while profitable by 20+ pips
if(OrdersTotal()>0)
{
for(int i=OrdersTotal(); i>=0; i--)
{
int pips=(int)(takeprofit);
//select an order
if(OrderSelect(i,SELECT_BY_POS,MODE_TRADES))
{
//make sure its the right currency pair
if(OrderSymbol()==_Symbol)
{
//check if buy or sell
if(OrderType()==OP_BUY)
{
if((Bid>(OrderOpenPrice()+pips*_Point))&&(OrderStopLoss()<OrderOpenPrice()) && (OrderStopLoss()<(Ask-pips*_Point)))
{
bool evenbuy=OrderModify(OrderTicket(),OrderOpenPrice(),Ask-pips*_Point,OrderTakeProfit(),0);
}
}
else
if(OrderType()==OP_SELL)
{
if((Ask<(OrderOpenPrice()-pips*_Point))&&(OrderStopLoss()>OrderOpenPrice()) && (OrderStopLoss()>(Bid+pips*_Point)))
{
bool evensell=OrderModify(OrderTicket(),OrderOpenPrice(),Bid+pips*_Point,OrderTakeProfit(),0);
}
}
}
}
}
}
}
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
Binary file not shown.
+764
View File
@@ -0,0 +1,764 @@
//-PROPERTIES-//
// Properties help the software look better when you load it in MT5.
// They provide more information and details
// This is what you see in the About tab when you attach the expert advisor to a chart.
#property link "https://www.earnforex.com/metatrader-expert-advisors/rsi-expert-advisor/"
#property version "1.00"
#property copyright "EarnForex.com - 2024"
#property description "A basic RSI EA created using an EA template."
#property description ""
#property description "WARNING: There is no guarantee that this expert advisor will work as intended. Use at your own risk."
#property description ""
#property description "Find more on www.EarnForex.com"
#property icon "\\Files\\EF-Icon-64x64px.ico"
//-INCLUDES-//
// '#include' allows to import code from other files.
// In the following instance the file has to be placed in the MQL5\Include folder.
#include <Trade\Trade.mqh> // This file is required to easily manage orders and positions.
#include <MQLTA ErrorHandling.mqh> // This file contains useful descriptions for errors.
#include <MQLTA Utils.mqh> // This file contains some useful functions.
//-COMMENTS-//
// This is a single line comment and you can do it by placing // at the start of the comment, this text is ignored when compiling.
/*
This is a multi-line comment.
It starts with /* and it finishes with the * and / like below
*/
enum ENUM_RISK_BASE
{
RISK_BASE_EQUITY = 1, // EQUITY
RISK_BASE_BALANCE = 2, // BALANCE
RISK_BASE_FREEMARGIN = 3, // FREE MARGIN
};
enum ENUM_RISK_DEFAULT_SIZE
{
RISK_DEFAULT_FIXED = 1, // FIXED SIZE
RISK_DEFAULT_AUTO = 2, // AUTOMATIC SIZE BASED ON RISK
};
enum ENUM_MODE_SL
{
SL_FIXED = 0, // FIXED STOP LOSS
SL_AUTO = 1, // AUTOMATIC STOP LOSS
};
enum ENUM_MODE_TP
{
TP_FIXED = 0, // FIXED TAKE PROFIT
TP_AUTO = 1, // AUTOMATIC TAKE PROFIT
};
// EA Parameters
input string Comment_0 = "=========="; // EA-Specific Parameters
// !! Declare parameters specific to your EA here.
// For example, a moving average period, an RSI level, or anything else your EA needs to know to implement its trading strategy.
// All input parameters start with 'input' keyword.
// input int example = 10; // This is an example input parameter
input int RSIPeriod = 14; // RSI period
input double RSIOverbought = 80; // RSI overbought level
input double RSIOversold = 20; // RSI oversold level
input ENUM_APPLIED_PRICE RSIPrice = PRICE_CLOSE; // RSI applied price
input string Comment_1 = "=========="; // Trading Hours Settings
input bool UseTradingHours = false; // Limit trading hours
input ENUM_HOUR TradingHourStart = h07; // Trading start hour (Broker server hour)
input ENUM_HOUR TradingHourEnd = h19; // Trading end hour (Broker server hour)
input string Comment_2 = "=========="; // ATR Settings
input int ATRPeriod = 100; // ATR period
input ENUM_TIMEFRAMES ATRTimeFrame = PERIOD_CURRENT; // ATR timeframe
input double ATRMultiplierSL = 2; // ATR multiplier for stop-loss
input double ATRMultiplierTP = 3; // ATR multiplier for take-profit
// General input parameters
input string Comment_a = "=========="; // Risk Management Settings
input ENUM_RISK_DEFAULT_SIZE RiskDefaultSize = RISK_DEFAULT_FIXED; // Position size mode
input double DefaultLotSize = 0.1; // Position size (if fixed or if no stop loss defined)
input ENUM_RISK_BASE RiskBase = RISK_BASE_BALANCE; // Risk base
input int MaxRiskPerTrade = 2; // Percentage to risk each trade
input double MinLotSize = 0.01; // Minimum position size allowed
input double MaxLotSize = 100; // Maximum position size allowed
input int MaxPositions = 1; // Maximum number of positions for this EA
input string Comment_b = "=========="; // Stop-Loss and Take-Profit Settings
input ENUM_MODE_SL StopLossMode = SL_FIXED; // Stop-loss mode
input int DefaultStopLoss = 0; // Default stop-loss in points (0 = no stop-loss)
input int MinStopLoss = 0; // Minimum allowed stop-loss in points
input int MaxStopLoss = 5000; // Maximum allowed stop-loss in points
input ENUM_MODE_TP TakeProfitMode = TP_FIXED; // Take-profit mode
input int DefaultTakeProfit = 0; // Default take-profit in points (0 = no take-profit)
input int MinTakeProfit = 0; // Minimum allowed take-profit in points
input int MaxTakeProfit = 5000; // Maximum allowed take-profit in points
input string Comment_c = "=========="; // Partial Close Settings
input bool UsePartialClose = false; // Use partial close
input double PartialClosePerc = 50; // Partial close percentage
input double ATRMultiplierPC = 1; // ATR multiplier for partial close
input string Comment_d = "=========="; // Additional Settings
input int MagicNumber = 0; // Magic number
input string OrderNote = ""; // Comment for orders
input int Slippage = 5; // Slippage in points
input int MaxSpread = 50; // Maximum allowed spread to trade, in points
// Global Variables
CTrade Trade; // Trade object.
int ATRHandle; // Indicator handle for ATR.
int IndicatorHandle = -1; // Global indicator handle for the EA's main signal indicator.
double ATR_current, ATR_previous; // ATR values.
double Indicator_current, Indicator_previous; // Indicator values.
// Here go all the event handling functions. They all run on specific events generated for the expert advisor.
// All event handlers are optional and can be removed if you don't need to process that specific event.
//+-------------------------------------------------------------------+
//| Expert initialization handler |
//| Here goes the code that runs just once each time you load the EA. |
//+-------------------------------------------------------------------+
int OnInit()
{
// EventSetTimer(60); // Starting a 60-second timer.
// EventSetMillisecondTimer(500); // Starting a 500-millisecond timer.
if (!Prechecks()) // Check if everything is OK with input parameters.
{
return INIT_FAILED; // Don't initialize the EA if checks fail.
}
if (!InitializeHandles()) // Initialize indicator handles.
{
PrintFormat("Error initializing indicator handles - %s - %d", GetLastErrorText(GetLastError()), GetLastError());
return INIT_FAILED;
}
SetTradeObject();
return INIT_SUCCEEDED; // Successful initialization.
}
//+---------------------------------------------------------------------+
//| Expert deinitialization handler |
//| Here goes the code that runs just once each time you unload the EA. |
//+---------------------------------------------------------------------+
void OnDeinit(const int reason)
{
// Normally, there isn't much stuff you need to do on deinitialization.
}
//+------------------------------------------------------------------+
//| Expert tick handler |
//| Here goes the code that runs every tick. |
//+------------------------------------------------------------------+
void OnTick()
{
ProcessTick(); // Calling the EA's main processing function here. It's defined farther below.
}
//+------------------------------------------------------------------+
//| Timer event handler |
//| Here goes the code that runs on timer. |
//+------------------------------------------------------------------+
void OnTimer()
{
// For example, you can update a display timer here if you have one in your EA.
}
//+------------------------------------------------------------------------------+
//| Trade event handler |
//| Here goes the code that runs each time something related to trading happens. |
//+------------------------------------------------------------------------------+
void OnTrade()
{
// For example, if you want to do something when a pending order gets triggered, you can do it here without overloading the OnTick() handler too much.
}
//+--------------------------------------------------------------------------------+
//| Backtest end handler |
//| Here goes the code that runs each time a backtest in Strategy Tester finishes. |
//| The goal is to calculate the value of a custom optimization criterion. |
//+--------------------------------------------------------------------------------+
double OnTester()
{
double NetProfit = TesterStatistics(STAT_PROFIT);
double InitialDeposit = TesterStatistics(STAT_INITIAL_DEPOSIT);
double MaxDrawDownPerc = TesterStatistics(STAT_EQUITYDD_PERCENT);
double TotalTrades = TesterStatistics(STAT_TRADES);
if (InitialDeposit == 0) return 0; // Avoiding division by zero.
if (TotalTrades == 0) return -100; // Discard a backtest with zero trades.
if ((TotalTrades > 0) && (MaxDrawDownPerc == 0)) MaxDrawDownPerc = 0.01; // Avoiding division by zero.
double NetProfitPerc = NetProfit / InitialDeposit * 100;
double Max = 0;
if (NetProfitPerc > 0) Max = NetProfitPerc / MaxDrawDownPerc; // Adjust net profit by maximum drawdown.
if (NetProfitPerc < 0) Max = NetProfitPerc;
return Max; // Return the value as a custom optimization criterion.
}
// Here go all custom functions. They all are called either from the above-defined event handlers or from other custom functions.
// Entry and exit processing
void ProcessTick()
{
if (!GetIndicatorsData()) return;
if (CountPositions())
{
// There is a position open. Manage SL, TP, or close if necessary.
if (UsePartialClose) PartialCloseAll();
CheckExitSignal();
}
// A block of code that lets the subsequent code execute only when a new bar appears on the chart.
// This means that the entry signals will be checked only twice per bar.
static datetime current_bar_time = WRONG_VALUE;
datetime previous_bar_time = current_bar_time;
current_bar_time = iTime(Symbol(), Period(), 0);
static int ticks_of_new_bar = 0; // Process two ticks of each new bar to allow indicator buffers to refresh.
if (current_bar_time == previous_bar_time)
{
ticks_of_new_bar++;
if (ticks_of_new_bar > 1) return; // Skip after two ticks.
}
else ticks_of_new_bar = 0;
// The number is recalculated after the first call because some trades could have been gotten closed.
if (CountPositions() < MaxPositions) CheckEntrySignal(); // Check entry signals only if there aren't too many positions already.
}
int CountPositions()
{
int count = 0;
int TotalPositions = PositionsTotal();
for (int i = 0; i < TotalPositions; i++)
{
string Instrument = PositionGetSymbol(i);
if (Instrument == "")
{
PrintFormat(__FUNCTION__, ": ERROR - Unable to select the position - %s - %d.", GetLastErrorText(GetLastError()), GetLastError());
}
else
{
// Skip positions in other symbols.
if (Instrument != Symbol()) continue;
// Skip counting positions with a different Magic number if the EA has non-zero Magic number set.
if ((MagicNumber != 0) && (PositionGetInteger(POSITION_MAGIC) != MagicNumber)) continue;
count++;
}
}
return count;
}
// Initialize handles. Indicator handles have to be initialized at the beginning of the EA's operation.
bool InitializeHandles()
{
// Indicator handle is the main handle for the signal generating indicator.
IndicatorHandle = iRSI(Symbol(), Period(), RSIPeriod, RSIPrice);
if (IndicatorHandle == INVALID_HANDLE)
{
PrintFormat("Unable to create main indicator handle - %s - %d.", GetLastErrorText(GetLastError()), GetLastError());
return false;
}
// ATR handle for stop-loss and take-profit.
ATRHandle = iATR(Symbol(), ATRTimeFrame, ATRPeriod);
if (ATRHandle == INVALID_HANDLE)
{
PrintFormat("Unable to create ATR handle - %s - %d.", GetLastErrorText(GetLastError()), GetLastError());
return false;
}
return true;
}
// Trading functions
// Set the basic parameters of the Trade object.
void SetTradeObject()
{
// All future trade operations will take into account these parameters - Magic number and deviation/slippage.
Trade.SetExpertMagicNumber(MagicNumber);
Trade.SetDeviationInPoints(Slippage);
}
// Open a position with a buy order.
bool OpenBuy()
{
double Ask = SymbolInfoDouble(Symbol(), SYMBOL_ASK);
double Bid = SymbolInfoDouble(Symbol(), SYMBOL_BID);
double OpenPrice = Ask; // Buy at Ask.
double StopLossPrice = StopLoss(ORDER_TYPE_BUY, OpenPrice); // Calculate SL based on direction, price, and SL rules.
double TakeProfitPrice = TakeProfit(ORDER_TYPE_BUY, OpenPrice); // Calculate TP based on direction, price, and TP rules.
double Size = LotSize(StopLossPrice, OpenPrice); // Calculate position size based on the SL, price, and the given rules.
// Use the standard Trade object to open the position with calculated parameters.
if (!Trade.Buy(Size, Symbol(), OpenPrice, StopLossPrice, TakeProfitPrice))
{
PrintFormat("Unable to open BUY: %s - %d", Trade.ResultRetcodeDescription(), Trade.ResultRetcode());
return false;
}
return true;
}
// Open a position with a sell order.
bool OpenSell()
{
double Ask = SymbolInfoDouble(Symbol(), SYMBOL_ASK);
double Bid = SymbolInfoDouble(Symbol(), SYMBOL_BID);
double OpenPrice = Bid; // Sell at Bid.
double StopLossPrice = StopLoss(ORDER_TYPE_SELL, OpenPrice); // Calculate SL based on direction, price, and SL rules.
double TakeProfitPrice = TakeProfit(ORDER_TYPE_SELL, OpenPrice); // Calculate TP based on direction, price, and TP rules.
double Size = LotSize(StopLossPrice, OpenPrice); // Calculate position size based on the SL, price, and the given rules.
// Use the standard Trade object to open the position with calculated parameters.
if (!Trade.Sell(Size, Symbol(), OpenPrice, StopLossPrice, TakeProfitPrice))
{
PrintFormat("Unable to open SELL: %s - %d", Trade.ResultRetcodeDescription(), Trade.ResultRetcode());
return false;
}
return true;
}
// Close the specified position completely.
//!! Unused. Can be uncommented and used to close specific positions.
/* bool ClosePosition(ulong ticket)
{
if (!Trade.PositionClose(ticket))
{
PrintFormat(__FUNCTION__, ": ERROR - Unable to close position: %s - %d", Trade.ResultRetcodeDescription(), Trade.ResultRetcode());
return false;
}
return true;
}*/
void CloseAllSell()
{
int total = PositionsTotal();
// Start a loop to scan all the positions.
// The loop starts from the last, otherwise it could skip positions.
for (int i = total - 1; i >= 0; i--)
{
// If the position cannot be selected log an error.
if (PositionGetSymbol(i) == "")
{
PrintFormat(__FUNCTION__, ": ERROR - Unable to select the position - %s - %d.", GetLastErrorText(GetLastError()), GetLastError());
continue;
}
if (PositionGetString(POSITION_SYMBOL) != Symbol()) continue; // Only close current symbol trades.
if (PositionGetInteger(POSITION_TYPE) != POSITION_TYPE_SELL) continue; // Only close Sell positions.
if (PositionGetInteger(POSITION_MAGIC) != MagicNumber) continue; // Only close own positions.
for (int try = 0; try < 10; try++)
{
bool result = Trade.PositionClose(PositionGetInteger(POSITION_TICKET));
if (!result)
{
PrintFormat(__FUNCTION__, ": ERROR - Unable to close position: %s - %d", Trade.ResultRetcodeDescription(), Trade.ResultRetcode());
}
else break;
}
}
}
void CloseAllBuy()
{
int total = PositionsTotal();
// Start a loop to scan all the positions.
// The loop starts from the last, otherwise it could skip positions.
for (int i = total - 1; i >= 0; i--)
{
// If the position cannot be selected log an error.
if (PositionGetSymbol(i) == "")
{
PrintFormat(__FUNCTION__, ": ERROR - Unable to select the position - %s - %d.", GetLastErrorText(GetLastError()), GetLastError());
continue;
}
if (PositionGetString(POSITION_SYMBOL) != Symbol()) continue; // Only close current symbol trades.
if (PositionGetInteger(POSITION_TYPE) != POSITION_TYPE_BUY) continue; // Only close Buy positions.
if (PositionGetInteger(POSITION_MAGIC) != MagicNumber) continue; // Only close own positions.
for (int try = 0; try < 10; try++)
{
bool result = Trade.PositionClose(PositionGetInteger(POSITION_TICKET));
if (!result)
{
PrintFormat(__FUNCTION__, ": ERROR - Unable to close position: %s - %d", Trade.ResultRetcodeDescription(), Trade.ResultRetcode());
}
else break;
}
}
}
// Close all positions opened by this EA.
void CloseAllPositions()
{
int total = PositionsTotal();
// Start a loop to scan all the positions.
// The loop starts from the last, otherwise it could skip positions.
for (int i = total - 1; i >= 0; i--)
{
// If the position cannot be selected log an error.
if (PositionGetSymbol(i) == "")
{
PrintFormat(__FUNCTION__, ": ERROR - Unable to select the position - %s - %d.", GetLastErrorText(GetLastError()), GetLastError());
continue;
}
if (PositionGetString(POSITION_SYMBOL) != Symbol()) continue; // Only close current symbol trades.
if (PositionGetInteger(POSITION_MAGIC) != MagicNumber) continue; // Only close own positions.
for (int try = 0; try < 10; try++)
{
bool result = Trade.PositionClose(PositionGetInteger(POSITION_TICKET));
if (!result)
{
PrintFormat(__FUNCTION__, ": ERROR - Unable to close position: %s - %d", Trade.ResultRetcodeDescription(), Trade.ResultRetcode());
}
else break;
}
}
}
// Partially close a position with a given ticket.
bool PartialClose(ulong ticket, double percentage)
{
if (!PositionSelectByTicket(ticket))
{
PrintFormat("ERROR - Unable to select position by ticket #%d: %s - %d", ticket, GetLastErrorText(GetLastError()), GetLastError());
return false;
}
double OriginalSize = PositionGetDouble(POSITION_VOLUME);
double Size = OriginalSize * percentage / 100;
double LotStep = SymbolInfoDouble(Symbol(), SYMBOL_VOLUME_STEP);
double MaxLot = SymbolInfoDouble(Symbol(), SYMBOL_VOLUME_MAX);
double MinLot = SymbolInfoDouble(Symbol(), SYMBOL_VOLUME_MIN);
Size = MathFloor(Size / LotStep) * LotStep;
if (Size < MinLot) return false;
if (!Trade.PositionClosePartial(ticket, Size))
{
PrintFormat("ERROR - Unable to partially close position #%d: %s - %d", ticket, Trade.ResultRetcodeDescription(), Trade.ResultRetcode());
return false;
}
return true;
}
// Calculate a stop-loss price for an order.
double StopLoss(ENUM_ORDER_TYPE order_type, double open_price)
{
double StopLossPrice = 0;
if (StopLossMode == SL_FIXED) // Easy way.
{
if (DefaultStopLoss == 0) return 0;
if (order_type == ORDER_TYPE_BUY)
{
StopLossPrice = open_price - DefaultStopLoss * SymbolInfoDouble(Symbol(), SYMBOL_POINT);
}
if (order_type == ORDER_TYPE_SELL)
{
StopLossPrice = open_price + DefaultStopLoss * SymbolInfoDouble(Symbol(), SYMBOL_POINT);
}
}
else // Special cases.
{
StopLossPrice = DynamicStopLossPrice(order_type, open_price);
}
return NormalizeDouble(StopLossPrice, (int)SymbolInfoInteger(Symbol(), SYMBOL_DIGITS));
}
// Calculate the take-profit price for an order.
double TakeProfit(ENUM_ORDER_TYPE order_type, double open_price)
{
double TakeProfitPrice = 0;
if (TakeProfitMode == TP_FIXED) // Easy way.
{
if (DefaultTakeProfit == 0) return 0;
if (order_type == ORDER_TYPE_BUY)
{
TakeProfitPrice = open_price + DefaultTakeProfit * SymbolInfoDouble(Symbol(), SYMBOL_POINT);
}
if (order_type == ORDER_TYPE_SELL)
{
TakeProfitPrice = open_price - DefaultTakeProfit * SymbolInfoDouble(Symbol(), SYMBOL_POINT);
}
}
else // Special cases.
{
TakeProfitPrice = DynamicTakeProfitPrice(order_type, open_price);
}
return NormalizeDouble(TakeProfitPrice, (int)SymbolInfoInteger(Symbol(), SYMBOL_DIGITS));
}
// Calculate the position size for an order.
double LotSize(double stop_loss, double open_price)
{
double Size = DefaultLotSize;
if (RiskDefaultSize == RISK_DEFAULT_AUTO) // If the position size is dynamic.
{
if (stop_loss != 0) // Calculate position size only if SL is non-zero, otherwise there will be a division by zero error.
{
double RiskBaseAmount = 0;
// TickValue is the value of the individual price increment for 1 lot of the instrument expressed in the account currency.
double TickValue = SymbolInfoDouble(Symbol(), SYMBOL_TRADE_TICK_VALUE);
// Define the base for the risk calculation depending on the parameter chosen
if (RiskBase == RISK_BASE_BALANCE) RiskBaseAmount = AccountBalance();
else if (RiskBase == RISK_BASE_EQUITY) RiskBaseAmount = AccountEquity();
else if (RiskBase == RISK_BASE_FREEMARGIN) RiskBaseAmount = AccountFreeMargin();
double SL = MathAbs(open_price - stop_loss) / SymbolInfoDouble(Symbol(), SYMBOL_POINT); // SL as a number of points.
// Calculate the Position Size.
Size = (RiskBaseAmount * MaxRiskPerTrade / 100) / (SL * TickValue);
}
// If the stop loss is zero, then use the default size.
if (stop_loss == 0)
{
Size = DefaultLotSize;
}
}
// Normalize the Lot Size to satisfy the allowed lot increment and minimum and maximum position size.
double LotStep = SymbolInfoDouble(Symbol(), SYMBOL_VOLUME_STEP);
double MaxLot = SymbolInfoDouble(Symbol(), SYMBOL_VOLUME_MAX);
double MinLot = SymbolInfoDouble(Symbol(), SYMBOL_VOLUME_MIN);
Size = MathFloor(Size / LotStep) * LotStep;
// Limit the lot size in case it is greater than the maximum allowed by the user.
if (Size > MaxLotSize) Size = MaxLotSize;
// Limit the lot size in case it is greater than the maximum allowed by the broker.
if (Size > MaxLot) Size = MaxLot;
// If the lot size is too small, then set it to 0 and don't trade.
if ((Size < MinLotSize) || (Size < MinLot)) Size = 0;
return Size;
}
// Utility functions
// Checks to run at initialization to complete it.
bool Prechecks()
{
// An example of a check to run here.
if (MaxLotSize < MinLotSize)
{
Print("MaxLotSize cannot be less than MinLotSize");
return false;
}
return true;
}
// Retrieve indicator data necessary for entry, update, and exit.
// Boolean type, so it can return true if all the data is available or false if it is not.
// Other advantage of this function is to move part of repetitive code into one location to make it leaner.
bool GetIndicatorsData()
{
double buf[2]; // Needed for CopyBuffer().
int count; // Will store the number of array elements returned by CopyBuffer().
bool AllDataAvailable = false;
int MaxAttemptsForData = 5;
int DelayBetweenAttempts = 200; // Milliseconds.
int Attempt = 0;
while ((!AllDataAvailable) && (Attempt < MaxAttemptsForData))
{
AllDataAvailable = true;
count = CopyBuffer(ATRHandle, 0, 0, 2, buf); // Copy using ATR indicator handle 2 latest values from 0th buffer to the buf array.
if ((count < 2) || (buf[0] == NULL) || (buf[0] == EMPTY_VALUE))
{
Print("Unable to get ATR values.");
AllDataAvailable = false;
}
else
{
ATR_current = buf[1];
ATR_previous = buf[0];
}
// This is where the main indicator data is read.
count = CopyBuffer(IndicatorHandle, 0, 1, 2, buf); // Copying using main indicator handle 2 latest completed candles (hence starting from the 1st, and not 0th, candle) from 0th buffer to the buf array.
if (count < 2)
{
Print("Main indicator buffer not ready yet.");
AllDataAvailable = false;
}
else
{
Indicator_current = buf[1];
Indicator_previous = buf[0];
}
Attempt++;
Sleep(DelayBetweenAttempts);
}
if (!AllDataAvailable)
{
Print("Unable to get some data for the entry signal, skipping candle.");
return false;
}
return true;
}
// Entry signal
void CheckEntrySignal()
{
if ((UseTradingHours) && (!IsCurrentTimeInInterval(TradingHourStart, TradingHourEnd))) return; // Trading hours restrictions for entry.
bool BuySignal = false;
bool SellSignal = false;
// Buy signal conditions
// This is where you should insert your entry signal for BUY orders.
// Include a condition to open a buy order, the condition will have to set BuySignal to true or false.
//!! Uncomment and modify this buy entry signal check line:
if ((Indicator_current > RSIOversold) && (Indicator_previous <= RSIOversold)) BuySignal = true; // Check if the RSI crossed the oversold level from below.
if (BuySignal)
{
OpenBuy();
}
// Sell signal conditions
// This is where you should insert your entry signal for SELL orders.
// Include a condition to open a sell order, the condition will have to set SellSignal to true or false.
//!! Uncomment and modify this sell entry signal check line:
if ((Indicator_current < RSIOverbought) && (Indicator_previous >= RSIOverbought)) SellSignal = true; // Check if the RSI crossed the overbought level from above.
if (SellSignal)
{
OpenSell();
}
}
// Exit signal
void CheckExitSignal()
{
//!! if ((UseTradingHours) && (!IsCurrentTimeInInterval(TradingHourStart, TradingHourEnd))) return; // Trading hours restrictions for exit. Normally, you don't want to restrict exit by hours. Still, it's a possibility.
bool SignalExitLong = false;
bool SignalExitShort = false;
//!! Uncomment and modify these exit signal checks:
if ((Indicator_current > RSIOversold) && (Indicator_previous <= RSIOversold)) SignalExitShort = true; // Check if the RSI crossed the oversold level from below.
else if ((Indicator_current < RSIOverbought) && (Indicator_previous >= RSIOverbought)) SignalExitLong = true; // Check if the RSI crossed the overbought level from above.
if (SignalExitLong) CloseAllBuy();
if (SignalExitShort) CloseAllSell();
}
// Dynamic stop-loss calculation
double DynamicStopLossPrice(ENUM_ORDER_TYPE type, double open_price)
{
double StopLossPrice = 0;
if (type == ORDER_TYPE_BUY)
{
StopLossPrice = open_price - ATR_previous * ATRMultiplierSL;
}
else if (type == ORDER_TYPE_SELL)
{
StopLossPrice = open_price + ATR_previous * ATRMultiplierSL;
}
return NormalizeDouble(StopLossPrice, (int)SymbolInfoInteger(Symbol(), SYMBOL_DIGITS));
}
// Dynamic take-profit calculation
double DynamicTakeProfitPrice(ENUM_ORDER_TYPE type, double open_price)
{
double TakeProfitPrice = 0;
if (type == ORDER_TYPE_BUY)
{
TakeProfitPrice = open_price + ATR_previous * ATRMultiplierTP;
}
else if (type == ORDER_TYPE_SELL)
{
TakeProfitPrice = open_price - ATR_previous * ATRMultiplierTP;
}
return NormalizeDouble(TakeProfitPrice, (int)SymbolInfoInteger(Symbol(), SYMBOL_DIGITS));
}
// Partially close all positions opened by this EA.
void PartialCloseAll()
{
int total = PositionsTotal();
// Start a loop to scan all the positions.
// The loop starts from the last, otherwise it could skip positions.
for (int i = total - 1; i >= 0; i--)
{
// If the position cannot be selected log an error.
if (PositionGetSymbol(i) == "")
{
Print(__FUNCTION__, ": ERROR - Unable to select the position - ", GetLastError());
continue;
}
if (PositionGetString(POSITION_SYMBOL) != Symbol()) continue; // Only close current symbol trades.
if (PositionGetInteger(POSITION_MAGIC) != MagicNumber) continue; // Only close own positions.
int position_ticket = (int)PositionGetInteger(POSITION_TICKET);
// Retrieve the history of deals and orders for that position to check if it hasn't been already partially closed.
if (!HistorySelectByPosition(PositionGetInteger(POSITION_IDENTIFIER)))
{
PrintFormat("ERROR - Unable to get position history for %d - %s - %d", position_ticket, GetLastErrorText(GetLastError()), GetLastError());
continue;
}
bool need_partial_close = true;
// Process partial close for a long position.
if (PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY)
{
for (int j = HistoryDealsTotal() - 1; j >= 0; j--)
{
long deal_ticket = (int)HistoryDealGetTicket(j);
if (!deal_ticket)
{
PrintFormat("Unable to get deal for %d - %s - %d", position_ticket, GetLastErrorText(GetLastError()), GetLastError());
break;
}
if (HistoryDealGetInteger(deal_ticket, DEAL_TYPE) == DEAL_TYPE_SELL) // Looks like this long position has already been partially closed at least once.
{
need_partial_close = false;
break; // No need to partially close this position.
}
}
// Condition for partial close of a long position.
if ((need_partial_close) && (SymbolInfoDouble(Symbol(), SYMBOL_BID) - PositionGetDouble(POSITION_PRICE_OPEN) > ATR_previous * ATRMultiplierPC))
{
PartialClose(position_ticket, PartialClosePerc);
}
}
// Process partial close for a short position.
else if (PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_SELL)
{
for (int j = HistoryDealsTotal() - 1; j >= 0; j--)
{
long deal_ticket = (int)HistoryDealGetTicket(j);
if (!deal_ticket)
{
PrintFormat("Unable to get deal for %d - %s - %d", position_ticket, GetLastErrorText(GetLastError()), GetLastError());
return;
}
if (HistoryDealGetInteger(deal_ticket, DEAL_TYPE) == DEAL_TYPE_BUY) // Looks like this short position has already been partially closed at least once.
{
need_partial_close = false;
break; // No need to partially close this position.
}
}
// Condition for partial close of a short position.
if ((need_partial_close) && (PositionGetDouble(POSITION_PRICE_OPEN) - SymbolInfoDouble(Symbol(), SYMBOL_ASK) > ATR_previous * ATRMultiplierPC))
{
PartialClose(position_ticket, PartialClosePerc);
}
return;
}
}
}
//+------------------------------------------------------------------+
Binary file not shown.
+75
View File
@@ -0,0 +1,75 @@
/**
* @copyright 2019, pipbolt.io <beta@pipbolt.io>
* @license https://github.com/pipbolt/experts/blob/master/LICENSE
*/
#include <PipboltFramework\Constants.mqh>
#define NAME "Stochastic Oscillator EA"
#define VERSION "0.022"
#property copyright COPYRIGHT
#property link LINK
#property icon ICON
#property description DESCRIPTION
#property version VERSION
#include <PipboltFramework\Params\MainSettings.mqh>
input group "Entry Strategy";
input group "Exit Strategy";
input bool UseExitStrategy = false; // Use Exit Strategy
input group "Stochastic Oscillator";
input int StochKPeriod = 5; // %K Period
input int StochDPeriod = 3; // %D Period
input int StochSlowing = 3; // Slowing
input ENUM_MA_METHOD StochMethod = MODE_SMA; // Method
input ENUM_STO_PRICE StochPrice = STO_LOWHIGH; // Price
input int StochBuyLevel = 20; // Buy Level
input int StochSellLevel = 80; // Sell Level
#include <PipboltFramework\Experts.mqh>
CiStochastic Stoch;
int OnInit(void)
{
if (ONINIT() != INIT_SUCCEEDED)
return INIT_FAILED;
Stoch.Init(NULL, NULL, StochKPeriod, StochDPeriod, StochSlowing, StochMethod, StochPrice);
return INIT_SUCCEEDED;
}
void OnTick(void) { ONTICK(); }
void OnDeinit(const int reason) { ONDEINIT(reason); }
void OnTimer() { ONTIMER(); }
void CheckForOpen(bool &openBuy, bool &openSell)
{
// Buy Entry Strategy
if (Stoch.Signal(1) <= StochBuyLevel && Stoch.Main(1) <= Stoch.Signal(1) &&
Stoch.Main(0) <= StochBuyLevel && Stoch.Signal(0) <= Stoch.Main(0))
openBuy = true;
// Sell Entry Strategy
else if (Stoch.Signal(1) >= StochSellLevel && Stoch.Main(1) >= Stoch.Signal(1) &&
Stoch.Main(0) >= StochSellLevel && Stoch.Signal(0) >= Stoch.Main(0))
openSell = true;
// Apply MA Filter
openBuy = openBuy && MAFilter.Check(DIR_BUY);
openSell = openSell && MAFilter.Check(DIR_SELL);
}
void CheckForClose(bool &closeBuy, bool &closeSell)
{
// Buy Exit Strategy
closeBuy = Stoch.Main(0) >= StochSellLevel;
// Sell Exit Strategy
closeSell = Stoch.Main(0) <= StochBuyLevel;
}
Binary file not shown.
+76
View File
@@ -0,0 +1,76 @@
/**
* @copyright 2019, pipbolt.io <beta@pipbolt.io>
* @license https://github.com/pipbolt/experts/blob/master/LICENSE
*/
#include <PipboltFramework\Constants.mqh>
#define NAME "Parabolic SAR EA"
#define VERSION "0.022"
#property copyright COPYRIGHT
#property link LINK
#property icon ICON
#property description DESCRIPTION
#property version VERSION
#include <PipboltFramework\Params\MainSettings.mqh>
input group "Entry Strategy";
input group "Exit Strategy";
input bool UseExitStrategy = false; // Use Exit Strategy
input group "Parabolic SAR";
input double PSAR_Step = 0.02; // Step
input double PSAR_Maximum = 0.2; // Maximum
#include <PipboltFramework\Experts.mqh>
CiSAR PSAR;
int OnInit(void)
{
if (ONINIT() != INIT_SUCCEEDED)
return INIT_FAILED;
PSAR.Init(NULL, NULL, PSAR_Step, PSAR_Maximum);
return INIT_SUCCEEDED;
}
void OnTick(void) { ONTICK(); }
void OnDeinit(const int reason) { ONDEINIT(reason); }
void OnTimer() { ONTIMER(); }
void CheckForOpen(bool &openBuy, bool &openSell)
{
// Close variables
double close0 = iClose(NULL, NULL, _indicatorShift);
double close1 = iClose(NULL, NULL, _indicatorShift + 1);
// Buy Entry Strategy
if (PSAR.Main(1) > close1 && PSAR.Main(0) < close0)
openBuy = true;
// Sell Entry Strategy
else if (PSAR.Main(1) < close1 && PSAR.Main(0) > close0)
openSell = true;
// Apply MA Filter
openBuy = openBuy && MAFilter.Check(DIR_BUY);
openSell = openSell && MAFilter.Check(DIR_SELL);
}
void CheckForClose(bool &closeBuy, bool &closeSell)
{
// Close variables
double close0 = iClose(NULL, NULL, _indicatorShift);
double close1 = iClose(NULL, NULL, _indicatorShift + 1);
// Buy Exit Strategy
closeBuy = PSAR.Main(0) > close0 && PSAR.Main(1) < close1;
// Sell Exit Strategy
closeSell = PSAR.Main(0) < close0 && PSAR.Main(1) > close1;
}
Binary file not shown.
@@ -0,0 +1,253 @@
//+------------------------------------------------------------------+
//| DAILY RANGE BREAKOUT EA.mq5 |
//| Copyright 2024, MetaQuotes Ltd. |
//| https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2024, MetaQuotes Ltd."
#property link "https://www.mql5.com"
#property version "1.00"
double maximum_price = -DBL_MAX;
double minimum_price = +DBL_MAX;
datetime maximum_time, minimum_time;
bool isHaveDailyRange_Prices = false;
bool isHaveDailyRange_Break = false;
#define RECTANGLE_PREFIX "RANGE RECTANGLE "
#define UPPER_LINE_PREFIX "UPPER LINE"
#define LOWER_LINE_PREFIX "LOWER LINE"
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int OnInit(){
//---
//---
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Expert deinitialization function |
//+------------------------------------------------------------------+
void OnDeinit(const int reason){
//---
}
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick(){
//---
static datetime midnight = iTime(_Symbol,PERIOD_D1,0);
static datetime sixAM = midnight + 6 * 3600;
static datetime scanBarTime = sixAM + 1 * PeriodSeconds(_Period); // next bar
static datetime validBreakTime_start = scanBarTime;
static datetime validBreakTime_end = midnight + (6+5) * 3600; // 11 AM
//Print("END TIME = ",validBreakTime_end);
//Print("Midnight T = ",midnight,", 6 AM = ",sixAM,", SCAN BAT T = ",scanBarTime);
if (isNewDay()){
midnight = iTime(_Symbol,PERIOD_D1,0);
sixAM = midnight + 6 * 3600;
scanBarTime = sixAM + 1 * PeriodSeconds(_Period); // next bar
validBreakTime_start = scanBarTime;
validBreakTime_end = midnight + (6+5) * 3600; // 11 AM
maximum_price = -DBL_MAX;
minimum_price = +DBL_MAX;
isHaveDailyRange_Prices = false;
isHaveDailyRange_Break = false;
}
if (isNewBar()){
datetime currentBarTime = iTime(_Symbol,_Period,0);
if (currentBarTime == scanBarTime && !isHaveDailyRange_Prices){
Print("WE HAVE ENOUGH BARS DATA FOR DOCUMENTATION. MAKE THE DATA EXTRACTION NOW");
int total_bars = int((sixAM - midnight)/PeriodSeconds(_Period))+1;
Print("Total bars for scan = ",total_bars);
int highest_price_bar_index = -1;
int lowest_price_bar_index = -1;
for (int i=1; i<=total_bars; i++){
double open_i = open(i);
double close_i = close(i);
double highest_price_i = (open_i > close_i) ? open_i : close_i;
double lowest_price_i = (open_i < close_i) ? open_i : close_i;
if (highest_price_i > maximum_price){
maximum_price = highest_price_i;
highest_price_bar_index = i;
maximum_time = time(i);
}
if (lowest_price_i < minimum_price){
minimum_price = lowest_price_i;
lowest_price_bar_index = i;
minimum_time = time(i);
}
}
Print("Maximum Price = ",maximum_price,", Bar Index = ",highest_price_bar_index,", Time = ",maximum_time);
Print("Minimum Price = ",minimum_price,", Bar Index = ",lowest_price_bar_index,", Time = ",minimum_time);
create_Rectangle(RECTANGLE_PREFIX+TimeToString(maximum_time),maximum_time,maximum_price,minimum_time,minimum_price,clrBlue);
create_Line(UPPER_LINE_PREFIX+TimeToString(midnight),midnight,maximum_price,sixAM,maximum_price,3,clrBlack,DoubleToString(maximum_price,_Digits));
create_Line(LOWER_LINE_PREFIX+TimeToString(midnight),midnight,minimum_price,sixAM,minimum_price,3,clrRed,DoubleToString(minimum_price,_Digits));
isHaveDailyRange_Prices = true;
}
}
double barClose = close(1);
datetime barTime = time(1);
if (barClose > maximum_price && isHaveDailyRange_Prices && !isHaveDailyRange_Break
&& barTime >= validBreakTime_start && barTime <= validBreakTime_end
){
Print("CLOSE Price broke the HIGH range. ",barClose," > ",maximum_price);
isHaveDailyRange_Break = true;
drawBreakPoint(TimeToString(barTime),barTime,barClose,234,clrBlack,-1);
}
else if (barClose < minimum_price && isHaveDailyRange_Prices && !isHaveDailyRange_Break
&& barTime >= validBreakTime_start && barTime <= validBreakTime_end
){
Print("CLOSE Price broke the LOW range. ",barClose," < ",minimum_price);
isHaveDailyRange_Break = true;
drawBreakPoint(TimeToString(barTime),barTime,barClose,233,clrBlue,+1);
}
}
//+------------------------------------------------------------------+
double open(int index){return (iOpen(_Symbol,_Period,index));}
double high(int index){return (iHigh(_Symbol,_Period,index));}
double low(int index){return (iLow(_Symbol,_Period,index));}
double close(int index){return (iClose(_Symbol,_Period,index));}
datetime time(int index){return (iTime(_Symbol,_Period,index));}
bool isNewBar(){
static int prevbars = 0;
int currbars = iBars(_Symbol,_Period);
if (prevbars == currbars) return (false);
prevbars = currbars;
return (true);
}
void create_Rectangle(string objName,datetime time1,double price1,
datetime time2,double price2,color clr){
if (ObjectFind(0,objName) < 0){
ObjectCreate(0,objName,OBJ_RECTANGLE,0,time1,price1,time2,price2);
ObjectSetInteger(0,objName,OBJPROP_TIME,0,time1);
ObjectSetDouble(0,objName,OBJPROP_PRICE,0,price1);
ObjectSetInteger(0,objName,OBJPROP_TIME,1,time2);
ObjectSetDouble(0,objName,OBJPROP_PRICE,1,price2);
ObjectSetInteger(0,objName,OBJPROP_FILL,true);
ObjectSetInteger(0,objName,OBJPROP_COLOR,clr);
ObjectSetInteger(0,objName,OBJPROP_BACK,false);
ChartRedraw(0);
}
}
bool isNewDay(){
bool newDay = false;
MqlDateTime str_datetime;
TimeToStruct(TimeCurrent(), str_datetime);
static int prevday = 0;
int currday = str_datetime.day;
if (prevday == currday){// we are still in current day
newDay = false;
}
else if (prevday != currday){// we have a new day
Print("WE HAVE A NEW DAY WITH DATE ",currday);
prevday = currday;
newDay = true;
}
return (newDay);
}
void create_Line(string objName,datetime time1,double price1,
datetime time2,double price2,int width,color clr,string text){
if (ObjectFind(0,objName) < 0){
ObjectCreate(0,objName,OBJ_TREND,0,time1,price1,time2,price2);
ObjectSetInteger(0,objName,OBJPROP_TIME,0,time1);
ObjectSetDouble(0,objName,OBJPROP_PRICE,0,price1);
ObjectSetInteger(0,objName,OBJPROP_TIME,1,time2);
ObjectSetDouble(0,objName,OBJPROP_PRICE,1,price2);
ObjectSetInteger(0,objName,OBJPROP_WIDTH,width);
ObjectSetInteger(0,objName,OBJPROP_COLOR,clr);
ObjectSetInteger(0,objName,OBJPROP_BACK,false);
long scale = 0;
if (!ChartGetInteger(0,CHART_SCALE,0,scale)){
Print("UNABLE TO GET THE CHART SCALE. DEFAULT VALUE OF ",scale," IS CONSIDERED.");
}
int fontsize = 11;
// 0=minimized, 5 = maximized
if (scale==0){fontsize=5;}
else if (scale==1){fontsize=6;}
else if (scale==2){fontsize=7;}
else if (scale==3){fontsize=9;}
else if (scale==4){fontsize=11;}
else if (scale==5){fontsize=13;}
string txt = " Right Price";
string objNameDescr = objName + txt;
ObjectCreate(0,objNameDescr,OBJ_TEXT,0,time2,price2);
ObjectSetInteger(0,objNameDescr,OBJPROP_COLOR,clr);
ObjectSetInteger(0,objNameDescr,OBJPROP_FONTSIZE,fontsize);
ObjectSetInteger(0,objNameDescr,OBJPROP_ANCHOR,ANCHOR_LEFT);
ObjectSetString(0,objNameDescr,OBJPROP_TEXT, " " + text);
ObjectSetString(0,objNameDescr,OBJPROP_FONT,"Calibri");
ChartRedraw(0);
}
}
void drawBreakPoint(string objName,datetime time,double price,int arrCode,
color clr,int direction){
if (ObjectFind(0,objName) < 0){
ObjectCreate(0,objName,OBJ_ARROW,0,time,price);
ObjectSetInteger(0,objName,OBJPROP_ARROWCODE,arrCode);
ObjectSetInteger(0,objName,OBJPROP_COLOR,clr);
ObjectSetInteger(0,objName,OBJPROP_FONTSIZE,12);
if (direction > 0) ObjectSetInteger(0,objName,OBJPROP_ANCHOR,ANCHOR_TOP);
if (direction < 0) ObjectSetInteger(0,objName,OBJPROP_ANCHOR,ANCHOR_BOTTOM);
string txt = " Breakout";
string objNameDescr = objName + txt;
ObjectCreate(0,objNameDescr,OBJ_TEXT,0,time,price);
ObjectSetInteger(0,objNameDescr,OBJPROP_COLOR,clr);
ObjectSetInteger(0,objNameDescr,OBJPROP_FONTSIZE,12);
if (direction > 0) {
ObjectSetInteger(0,objNameDescr,OBJPROP_ANCHOR,ANCHOR_LEFT_UPPER);
ObjectSetString(0,objNameDescr,OBJPROP_TEXT, " " + txt);
}
if (direction < 0) {
ObjectSetInteger(0,objNameDescr,OBJPROP_ANCHOR,ANCHOR_LEFT_LOWER);
ObjectSetString(0,objNameDescr,OBJPROP_TEXT, " " + txt);
}
}
ChartRedraw(0);
}
Binary file not shown.
+206
View File
@@ -0,0 +1,206 @@
//+------------------------------------------------------------------+
//| JamesOBR.mq4 |
//| Copyright 2012,Clifford H. James |
//| |
//+------------------------------------------------------------------+
#include <user/utils_trades.mq4>
#property copyright "Copyright 2012,Clifford H. James"
#property link ""
// CONSTANTS
extern double OBR_PIP_OFFSET = 0.0002;
extern int EET_START = 10;
extern double OBR_RATIO = 1.9;
extern double ATR_PERIOD = 72;
//+------------------------------------------------------------------+
//| expert initialization function |
//+------------------------------------------------------------------+
int init()
{
//---
//----
return(0);
}
//+------------------------------------------------------------------+
//| expert deinitialization function |
//+------------------------------------------------------------------+
int deinit()
{
//----
//----
return(0);
}
//---
// calculates the ORB
//---
double CalcCurrORB()
{
// Get the ATR of the 10EET Bar...we run on the
double currATR = iATR(NULL, 0, ATR_PERIOD, 1);
//Print("Curr ATR(72): ", currATR);
return (currATR + OBR_PIP_OFFSET);
}
//---
// Generate Daily pending orders based on the specified ORB value
// This will generate both a BUY_STOP and SELL_STOP pending order.
//---
void generateDailyPendingOrders(double orbval)
{
double tenEETHi = High[1]; //Goes back 1 bar to compute 10EET bar high
double tenEETLo = Low[1]; // Goes back 1 bar to compute 10EET bar low
int slippage = 2;
double buyEntry = tenEETHi + orbval;
double SL = buyEntry - (1.65 * orbval);
double TP = buyEntry + orbval;
double SL_Dist = RelDistToPoints(SL);
double TP_Dist = RelDistToPoints(TP);
int lotSize = 1;
Alert("Current Price: ", Bid,"/",Ask);
// buy side
PlacePendingStopOrder(
OP_BUYSTOP,
Symbol(),
buyEntry,
lotSize,
SL_Dist,
TP_Dist
);
double sellEntry = tenEETLo - orbval;
SL = sellEntry + (1.65 * orbval);
TP = sellEntry - orbval;
SL_Dist = RelDistToPoints(SL);
TP_Dist = RelDistToPoints(TP);
// sell side
PlacePendingStopOrder(
OP_SELLSTOP,
Symbol(),
sellEntry,
lotSize,
SL_Dist,
TP_Dist
);
}
//---
// determine if we are at the close of the day or not
//---
bool AtCloseOfDay() {
int currHour=TimeHour(TimeCurrent());
int currMin=TimeMinute(TimeCurrent());
return(currHour == 17 && currMin == 30);
}
//-------------------------------------------------------------------------------
// Calculate trade volume (lot size) for the current symbol based on:
// - Current free margin in your account
// - SL dist in points
// - Desired risk % (0-100)
// - Tick Value of current symbol
//
// Additional MIN/MAX lot constraints for the current symbold are applied
//
// - If you are requesting a volume < minLots for the current symbol
// then -1 is returned, this indicates that the current trade cannot be made
//
// - If you are requesting a volume > maxLots for the current symbol
// then your trade volume is effectively "capped" at maxLotSize
//-------------------------------------------------------------------------------
double calcTradeVolume(double risk, double stopLossPoints)
{
double minLotAllowed = MarketInfo(Symbol(), MODE_MINLOT);
double maxLotAllowed = MarketInfo(Symbol(), MODE_MAXLOT);
double vol = (AccountFreeMargin() * (risk/100)) /
( stopLossPoints * MarketInfo(Symbol(), MODE_TICKVALUE) );
if(vol < minLotAllowed)
vol = -1.0;
if(vol > maxLotAllowed)
vol = maxLotAllowed;
return(vol);
}
double calcSLDist(double entryPrice, double stopLossPrice)
{
return(-1.0);
}
//+------------------------------------------------------------------+
//| expert start function |
//+------------------------------------------------------------------+
int start()
{
//----
// TODO: Check some start conditions ...
// little magic to detect new bars ...
static datetime Time0;
static bool processedClose;
//int currMin = TimeMinute(Time[0]);
if(AtCloseOfDay()) {
if(!processedClose) {
//Alert("Got Close of Day @: ", TimeToStr(Time[0],TIME_DATE|TIME_MINUTES));
//printInfo();
CloseAllOutstandingOrders();
processedClose = true;
}
return(0);
}
processedClose = false;
// check for first bar of the hour ...
if (Time0 == Time[0]) return;
Time0 = Time[0];
int currHour = TimeHour(Time[0]);
//Alert("Got a new bar at time: ", TimeToStr(Time[0],TIME_DATE|TIME_MINUTES));
double currOrb = 0;
if(currHour == 11) {
currOrb = CalcCurrORB();
//Alert("ORB value on: ", TimeToStr(Time[0],TIME_DATE|TIME_MINUTES), " is: ", currOrb);
// generate daily pending orders for buy/sell
generateDailyPendingOrders(currOrb);
}
//----
return(0);
}
//+------------------------------------------------------------------+
Binary file not shown.
+328
View File
@@ -0,0 +1,328 @@
/*
============================================================
Demo File: Asia_Session_Breakout_EA - Signal Logic Showcase
Category: Session Breakout
Platform: MetaTrader 4 (MQL4)
Version: 1.0
Author: Giacomo Cipolat Bares
Portfolio: MQL4 Expert Advisors Portfolio
============================================================
Description:
This is a simplified public demo derived from the full
Asia Session Breakout EA.
Included in this demo:
- Asia session high/low detection
- session range calculation
- breakout trigger calculation
- Asia range filter
- late breakout filter
- basic on-chart signal output
Excluded from this demo:
- order execution
- pending order management
- risk management engine
- break-even / trailing stop
- retry logic
- broker protection handling
- full production trade framework
- chart visualization layer
============================================================
*/
#property strict
#property version "1.00"
//========================= INPUTS ==================================
input string __01_SessionSettings = "01 ======== Session Settings ========";
input int AsiaStartHour = 0;
input int AsiaEndHour = 6;
input int LondonStartHour = 7;
input int LondonEndHour = 12;
input int SessionCalculationTimeframe = PERIOD_M1;
input string __02_BreakoutSettings = "02 ======== Breakout Settings ========";
input double BreakoutBufferPips = 1.0;
input bool UseAsiaRangeFilter = true;
input bool NoLateBreakout = true;
input double MinAsiaRangePips = 5.0;
input double MaxAsiaRangePips = 30.0;
//======================= GLOBALS ===================================
double g_point;
double g_pip;
int g_digits;
double g_asiaHigh = -1.0;
double g_asiaLow = -1.0;
bool g_asiaRangeFinalized = false;
datetime g_lastSessionDay = -1;
datetime g_lastBarTime = 0;
//+------------------------------------------------------------------+
//| Expert initialization |
//+------------------------------------------------------------------+
int OnInit()
{
g_point = Point;
g_digits = Digits;
if(g_digits == 5 || g_digits == 3)
g_pip = g_point * 10.0;
else
g_pip = g_point;
Print("Asia Session Breakout demo initialized");
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Detects a new bar |
//+------------------------------------------------------------------+
bool IsNewBar()
{
datetime currentBarTime = iTime(NULL, 0, 0);
if(currentBarTime != g_lastBarTime)
{
g_lastBarTime = currentBarTime;
return true;
}
return false;
}
//+------------------------------------------------------------------+
//| Current hour helper |
//+------------------------------------------------------------------+
int CurrentHour()
{
return TimeHour(TimeCurrent());
}
//+------------------------------------------------------------------+
//| Session checks |
//+------------------------------------------------------------------+
bool IsInsideAsiaSession()
{
int hour = TimeHour(TimeCurrent());
return (hour >= AsiaStartHour && hour < AsiaEndHour);
}
bool IsLondonSession()
{
int hour = CurrentHour();
return (hour >= LondonStartHour && hour < LondonEndHour);
}
//+------------------------------------------------------------------+
//| Date helper |
//+------------------------------------------------------------------+
datetime DateOfDay(datetime t)
{
return t - (t % 86400);
}
//+------------------------------------------------------------------+
//| Session time builders |
//+------------------------------------------------------------------+
datetime GetSessionStart(datetime dayStart, int startHour)
{
return dayStart + startHour * 3600;
}
datetime GetSessionEnd(datetime dayStart, int endHour)
{
return dayStart + endHour * 3600;
}
//+------------------------------------------------------------------+
//| Calculates Asia session high/low |
//+------------------------------------------------------------------+
bool CalculateAsiaRange(double &asiaHigh, double &asiaLow)
{
datetime today = DateOfDay(TimeCurrent());
datetime asiaStart = GetSessionStart(today, AsiaStartHour);
datetime asiaEnd = GetSessionEnd(today, AsiaEndHour);
int tf = SessionCalculationTimeframe;
int startShift = iBarShift(Symbol(), tf, asiaEnd - 1, false);
int endShift = iBarShift(Symbol(), tf, asiaStart, false);
if(startShift < 0 || endShift < 0)
return false;
int count = endShift - startShift + 1;
if(count <= 0)
return false;
int highestShift = iHighest(Symbol(), tf, MODE_HIGH, count, startShift);
int lowestShift = iLowest(Symbol(), tf, MODE_LOW, count, startShift);
if(highestShift < 0 || lowestShift < 0)
return false;
asiaHigh = iHigh(Symbol(), tf, highestShift);
asiaLow = iLow(Symbol(), tf, lowestShift);
return (asiaHigh > 0 && asiaLow > 0);
}
//+------------------------------------------------------------------+
//| Updates tracked Asia range |
//+------------------------------------------------------------------+
void UpdateAsiaRange()
{
if(g_asiaRangeFinalized)
return;
double asiaHigh = -1.0;
double asiaLow = -1.0;
if(CalculateAsiaRange(asiaHigh, asiaLow))
{
g_asiaHigh = asiaHigh;
g_asiaLow = asiaLow;
}
datetime today = DateOfDay(TimeCurrent());
datetime asiaEnd = GetSessionEnd(today, AsiaEndHour);
if(TimeCurrent() >= asiaEnd)
g_asiaRangeFinalized = true;
}
//+------------------------------------------------------------------+
//| Reset session state daily |
//+------------------------------------------------------------------+
void ResetSessionState()
{
datetime today = DateOfDay(TimeCurrent());
if(today != g_lastSessionDay)
{
g_lastSessionDay = today;
g_asiaHigh = -1.0;
g_asiaLow = -1.0;
g_asiaRangeFinalized = false;
}
}
//+------------------------------------------------------------------+
//| Range and trigger helpers |
//+------------------------------------------------------------------+
double GetAsiaRangePips()
{
if(g_asiaHigh <= 0 || g_asiaLow <= 0)
return 0.0;
return (g_asiaHigh - g_asiaLow) / g_pip;
}
bool AsiaRangeFilterPassed()
{
if(!UseAsiaRangeFilter)
return true;
double asiaRangePips = GetAsiaRangePips();
if(asiaRangePips < MinAsiaRangePips)
return false;
if(asiaRangePips > MaxAsiaRangePips)
return false;
return true;
}
double GetBuyTrigger()
{
return g_asiaHigh + BreakoutBufferPips * g_pip;
}
double GetSellTrigger()
{
return g_asiaLow - BreakoutBufferPips * g_pip;
}
//+------------------------------------------------------------------+
//| Late breakout filter |
//+------------------------------------------------------------------+
bool LateBreakout()
{
if(!NoLateBreakout)
return true;
if(Ask > GetBuyTrigger() || Bid < GetSellTrigger())
return false;
return true;
}
//+------------------------------------------------------------------+
//| Demo breakout signal wrappers |
//+------------------------------------------------------------------+
bool BuySignal()
{
if(!IsLondonSession())
return false;
if(!AsiaRangeFilterPassed())
return false;
if(!LateBreakout())
return false;
if(g_asiaHigh <= 0 || g_asiaLow <= 0)
return false;
return (Ask > GetBuyTrigger());
}
bool SellSignal()
{
if(!IsLondonSession())
return false;
if(!AsiaRangeFilterPassed())
return false;
if(!LateBreakout())
return false;
if(g_asiaHigh <= 0 || g_asiaLow <= 0)
return false;
return (Bid < GetSellTrigger());
}
//+------------------------------------------------------------------+
//| Expert tick |
//+------------------------------------------------------------------+
void OnTick()
{
if(!IsNewBar())
return;
ResetSessionState();
UpdateAsiaRange();
if(BuySignal())
{
Comment("Demo Signal: BUY Asia breakout detected");
return;
}
if(SellSignal())
{
Comment("Demo Signal: SELL Asia breakout detected");
return;
}
Comment("Demo Signal: No valid Asia breakout");
}
Binary file not shown.
@@ -0,0 +1,647 @@
//+------------------------------------------------------------------+
//| Trendline Breakout Trader EA.mq5 |
//| Copyright 2025, Allan Munene Mutiiria. |
//| https://t.me/Forex_Algo_Trader |
//+------------------------------------------------------------------+
#property copyright "Copyright 2025, Allan Munene Mutiiria."
#property link "https://t.me/Forex_Algo_Trader"
#property version "1.00"
#property strict
#include <Trade\Trade.mqh> //--- Include Trade library for trading operations
CTrade obj_Trade; //--- Instantiate trade object
//+------------------------------------------------------------------+
//| Breakout definition enumeration |
//+------------------------------------------------------------------+
enum ENUM_BREAKOUT_TYPE {
BREAKOUT_CLOSE = 0, // Breakout on close above/below line
BREAKOUT_CANDLE = 1 // Breakout on entire candle above/below line
};
//+------------------------------------------------------------------+
//| Swing point structure |
//+------------------------------------------------------------------+
struct Swing { //--- Define swing point structure
datetime time; //--- Store swing time
double price; //--- Store swing price
};
//+------------------------------------------------------------------+
//| Starting point structure |
//+------------------------------------------------------------------+
struct StartingPoint { //--- Define starting point structure
datetime time; //--- Store starting point time
double price; //--- Store starting point price
bool is_support; //--- Indicate support/resistance flag
};
//+------------------------------------------------------------------+
//| Trendline storage structure |
//+------------------------------------------------------------------+
struct TrendlineInfo { //--- Define trendline info structure
string name; //--- Store trendline name
datetime start_time; //--- Store start time
datetime end_time; //--- Store end time
double start_price; //--- Store start price
double end_price; //--- Store end price
double slope; //--- Store slope
bool is_support; //--- Indicate support/resistance flag
int touch_count; //--- Store number of touches
datetime creation_time; //--- Store creation time
int touch_indices[]; //--- Store touch indices array
bool is_signaled; //--- Indicate signal flag
};
//+------------------------------------------------------------------+
//| Forward declarations |
//+------------------------------------------------------------------+
void DetectSwings(); //--- Declare swing detection function
void SortSwings(Swing &swings[], int count); //--- Declare swing sorting function
double CalculateAngle(datetime time1, double price1, datetime time2, double price2); //--- Declare angle calculation function
bool ValidateTrendline(bool isSupport, datetime start_time, datetime ref_time, double ref_price, double slope, double tolerance_pen); //--- Declare trendline validation function
void FindAndDrawTrendlines(bool isSupport); //--- Declare trendline finding/drawing function
void UpdateTrendlines(); //--- Declare trendline update function
void RemoveTrendlineFromStorage(int index); //--- Declare trendline removal function
bool IsStartingPointUsed(datetime time, double price, bool is_support); //--- Declare starting point usage check function
double CalculateRSquared(const datetime &times[], const double &prices[], int n, double slope, double intercept); //--- Declare R-squared calculation function
//+------------------------------------------------------------------+
//| Inputs |
//+------------------------------------------------------------------+
input ENUM_BREAKOUT_TYPE BreakoutType = BREAKOUT_CLOSE; // Breakout Definition
input int LookbackBars = 200; // Set bars for swing detection lookback
input double TouchTolerance = 10.0; // Set tolerance for touch points (points)
input int MinTouches = 3; // Set minimum touch points for valid trendline
input double PenetrationTolerance = 5.0; // Set allowance for bar penetration (points)
input int ExtensionBars = 100; // Set bars to extend trendline right
input int MinBarSpacing = 10; // Set minimum bar spacing between touches
input double inpLot = 0.01; // Set lot size
input double inpSLPoints = 100.0; // Set stop loss (points)
input double inpRRRatio = 1.1; // Set risk:reward ratio
input double MinAngle = 1.0; // Set minimum inclination angle (degrees)
input double MaxAngle = 89.0; // Set maximum inclination angle (degrees)
input double MinRSquared = 0.8; // Minimum R-squared for trendline acceptance
input bool DeleteExpiredObjects = false; // Enable deletion of expired/broken objects
input bool EnableTradingSignals = true; // Enable buy/sell signals and trades
input bool DrawTouchArrows = true; // Enable drawing arrows at touch points
input bool DrawLabels = true; // Enable drawing trendline/point labels
input color SupportLineColor = clrGreen; // Set color for support trendlines
input color ResistanceLineColor = clrRed; // Set color for resistance trendlines
//+------------------------------------------------------------------+
//| Global variables |
//+------------------------------------------------------------------+
Swing swingLows[]; //--- Store swing lows
int numLows = 0; //--- Track number of swing lows
Swing swingHighs[]; //--- Store swing highs
int numHighs = 0; //--- Track number of swing highs
TrendlineInfo trendlines[]; //--- Store trendlines
int numTrendlines = 0; //--- Track number of trendlines
StartingPoint startingPoints[]; //--- Store used starting points
int numStartingPoints = 0; //--- Track number of starting points
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int OnInit() {
ArrayResize(trendlines, 0); //--- Resize trendlines array
numTrendlines = 0; //--- Reset trendlines count
ArrayResize(startingPoints, 0); //--- Resize starting points array
numStartingPoints = 0; //--- Reset starting points count
return(INIT_SUCCEEDED); //--- Return success
}
//+------------------------------------------------------------------+
//| Expert deinitialization function |
//+------------------------------------------------------------------+
void OnDeinit(const int reason) {
ArrayResize(trendlines, 0); //--- Resize trendlines array
numTrendlines = 0; //--- Reset trendlines count
ArrayResize(startingPoints, 0); //--- Resize starting points array
numStartingPoints = 0; //--- Reset starting points count
}
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick() {
if (!IsNewBar()) return; //--- Exit if not new bar
DetectSwings(); //--- Detect swings
UpdateTrendlines(); //--- Update trendlines
FindAndDrawTrendlines(true); //--- Find/draw support trendlines
FindAndDrawTrendlines(false); //--- Find/draw resistance trendlines
}
//+------------------------------------------------------------------+
//| Check for new bar |
//+------------------------------------------------------------------+
bool IsNewBar() {
static datetime lastTime = 0; //--- Store last bar time
datetime currentTime = iTime(_Symbol, _Period, 0); //--- Get current bar time
if (lastTime != currentTime) { //--- Check for new bar
lastTime = currentTime; //--- Update last time
return true; //--- Indicate new bar
}
return false; //--- Indicate no new bar
}
//+------------------------------------------------------------------+
//| Sort swings by time (ascending, oldest first) |
//+------------------------------------------------------------------+
void SortSwings(Swing &swings[], int count) {
for (int i = 0; i < count - 1; i++) { //--- Iterate through swings
for (int j = 0; j < count - i - 1; j++) { //--- Compare adjacent swings
if (swings[j].time > swings[j + 1].time) { //--- Check time order
Swing temp = swings[j]; //--- Store temporary swing
swings[j] = swings[j + 1]; //--- Swap swings
swings[j + 1] = temp; //--- Complete swap
}
}
}
}
//+------------------------------------------------------------------+
//| Detect swing highs and lows |
//+------------------------------------------------------------------+
void DetectSwings() {
numLows = 0; //--- Reset lows count
ArrayResize(swingLows, 0); //--- Resize lows array
numHighs = 0; //--- Reset highs count
ArrayResize(swingHighs, 0); //--- Resize highs array
int totalBars = iBars(_Symbol, _Period); //--- Get total bars
int effectiveLookback = MathMin(LookbackBars, totalBars); //--- Calculate effective lookback
if (effectiveLookback < 5) { //--- Check sufficient bars
Print("Not enough bars for swing detection."); //--- Log insufficient bars
return; //--- Exit function
}
for (int i = 2; i < effectiveLookback - 2; i++) { //--- Iterate through bars
double low_i = iLow(_Symbol, _Period, i); //--- Get current low
double low_im1 = iLow(_Symbol, _Period, i - 1); //--- Get previous low
double low_im2 = iLow(_Symbol, _Period, i - 2); //--- Get two bars prior low
double low_ip1 = iLow(_Symbol, _Period, i + 1); //--- Get next low
double low_ip2 = iLow(_Symbol, _Period, i + 2); //--- Get two bars next low
if (low_i < low_im1 && low_i < low_im2 && low_i < low_ip1 && low_i < low_ip2) { //--- Check for swing low
Swing s; //--- Create swing struct
s.time = iTime(_Symbol, _Period, i); //--- Set swing time
s.price = low_i; //--- Set swing price
ArrayResize(swingLows, numLows + 1); //--- Resize lows array
swingLows[numLows] = s; //--- Add swing low
numLows++; //--- Increment lows count
}
double high_i = iHigh(_Symbol, _Period, i); //--- Get current high
double high_im1 = iHigh(_Symbol, _Period, i - 1); //--- Get previous high
double high_im2 = iHigh(_Symbol, _Period, i - 2); //--- Get two bars prior high
double high_ip1 = iHigh(_Symbol, _Period, i + 1); //--- Get next high
double high_ip2 = iHigh(_Symbol, _Period, i + 2); //--- Get two bars next high
if (high_i > high_im1 && high_i > high_im2 && high_i > high_ip1 && high_i > high_ip2) { //--- Check for swing high
Swing s; //--- Create swing struct
s.time = iTime(_Symbol, _Period, i); //--- Set swing time
s.price = high_i; //--- Set swing price
ArrayResize(swingHighs, numHighs + 1); //--- Resize highs array
swingHighs[numHighs] = s; //--- Add swing high
numHighs++; //--- Increment highs count
}
}
if (numLows > 0) SortSwings(swingLows, numLows); //--- Sort swing lows
if (numHighs > 0) SortSwings(swingHighs, numHighs); //--- Sort swing highs
}
//+------------------------------------------------------------------+
//| Calculate visual inclination angle |
//+------------------------------------------------------------------+
double CalculateAngle(datetime time1, double price1, datetime time2, double price2) {
int x1, y1, x2, y2; //--- Declare coordinate variables
if (!ChartTimePriceToXY(0, 0, time1, price1, x1, y1)) return 0.0; //--- Convert time1/price1 to XY
if (!ChartTimePriceToXY(0, 0, time2, price2, x2, y2)) return 0.0; //--- Convert time2/price2 to XY
double dx = (double)(x2 - x1); //--- Calculate x difference
double dy = (double)(y2 - y1); //--- Calculate y difference
if (dx == 0.0) return (dy > 0.0 ? -90.0 : 90.0); //--- Handle vertical line case
double angle = MathArctan(-dy / dx) * 180.0 / M_PI; //--- Calculate angle in degrees
return angle; //--- Return angle
}
//+------------------------------------------------------------------+
//| Validate trendline |
//+------------------------------------------------------------------+
bool ValidateTrendline(bool isSupport, datetime start_time, datetime ref_time, double ref_price, double slope, double tolerance_pen) {
int bar_start = iBarShift(_Symbol, _Period, start_time); //--- Get start bar index
if (bar_start < 0) return false; //--- Check invalid bar index
for (int bar = bar_start; bar >= 0; bar--) { //--- Iterate through bars
datetime bar_time = iTime(_Symbol, _Period, bar); //--- Get bar time
double dk = (double)(bar_time - ref_time); //--- Calculate time difference
double line_price = ref_price + slope * dk; //--- Calculate line price
if (isSupport) { //--- Check support case
double low = iLow(_Symbol, _Period, bar); //--- Get bar low
if (low < line_price - tolerance_pen) return false;//--- Check if broken
} else { //--- Handle resistance case
double high = iHigh(_Symbol, _Period, bar); //--- Get bar high
if (high > line_price + tolerance_pen) return false;//--- Check if broken
}
}
return true; //--- Return valid
}
//+------------------------------------------------------------------+
//| Calculate R-squared for goodness of fit |
//+------------------------------------------------------------------+
double CalculateRSquared(const datetime &times[], const double &prices[], int n, double slope, double intercept) {
double sum_y = 0.0; //--- Initialize sum of y
for (int k = 0; k < n; k++) { //--- Iterate through points
sum_y += prices[k]; //--- Accumulate y
}
double mean_y = sum_y / n; //--- Calculate mean y
double ss_tot = 0.0, ss_res = 0.0; //--- Initialize sums of squares
for (int k = 0; k < n; k++) { //--- Iterate through points
double x = (double)times[k]; //--- Get x (time)
double y_pred = intercept + slope * x; //--- Calculate predicted y
double y = prices[k]; //--- Get actual y
ss_res += (y - y_pred) * (y - y_pred); //--- Accumulate residual sum
ss_tot += (y - mean_y) * (y - mean_y); //--- Accumulate total sum
}
if (ss_tot == 0.0) return 1.0; //--- Handle constant y case
return 1.0 - ss_res / ss_tot; //--- Calculate and return R-squared
}
//+------------------------------------------------------------------+
//| Check if starting point is already used |
//+------------------------------------------------------------------+
bool IsStartingPointUsed(datetime time, double price, bool is_support) {
for (int i = 0; i < numStartingPoints; i++) { //--- Iterate through starting points
if (startingPoints[i].time == time && MathAbs(startingPoints[i].price - price) < TouchTolerance * _Point && startingPoints[i].is_support == is_support) { //--- Check match
return true; //--- Return used
}
}
return false; //--- Return not used
}
//+------------------------------------------------------------------+
//| Remove trendline from storage and optionally chart objects |
//+------------------------------------------------------------------+
void RemoveTrendlineFromStorage(int index) {
if (index < 0 || index >= numTrendlines) return; //--- Check valid index
Print("Removing trendline from storage: ", trendlines[index].name); //--- Log removal
if (DeleteExpiredObjects) { //--- Check deletion flag
ObjectDelete(0, trendlines[index].name); //--- Delete trendline object
for (int m = 0; m < trendlines[index].touch_count; m++) { //--- Iterate touches
string arrow_name = trendlines[index].name + "_touch" + IntegerToString(m); //--- Generate arrow name
ObjectDelete(0, arrow_name); //--- Delete touch arrow
string text_name = trendlines[index].name + "_point_label" + IntegerToString(m); //--- Generate text name
ObjectDelete(0, text_name); //--- Delete point label
}
string label_name = trendlines[index].name + "_label"; //--- Generate label name
ObjectDelete(0, label_name); //--- Delete trendline label
string signal_arrow = trendlines[index].name + "_signal_arrow"; //--- Generate signal arrow name
ObjectDelete(0, signal_arrow); //--- Delete signal arrow
string signal_text = trendlines[index].name + "_signal_text"; //--- Generate signal text name
ObjectDelete(0, signal_text); //--- Delete signal text
}
for (int i = index; i < numTrendlines - 1; i++) { //--- Shift array
trendlines[i] = trendlines[i + 1]; //--- Copy next trendline
}
ArrayResize(trendlines, numTrendlines - 1); //--- Resize trendlines array
numTrendlines--; //--- Decrement trendlines count
}
//+------------------------------------------------------------------+
//| Update trendlines and check for signals |
//+------------------------------------------------------------------+
void UpdateTrendlines() {
datetime current_time = iTime(_Symbol, _Period, 0); //--- Get current time
double pointValue = _Point; //--- Get point value
double pen_tolerance = PenetrationTolerance * pointValue; //--- Calculate penetration tolerance
double touch_tolerance = TouchTolerance * pointValue; //--- Calculate touch tolerance
for (int i = numTrendlines - 1; i >= 0; i--) { //--- Iterate trendlines backward
string type = trendlines[i].is_support ? "Support" : "Resistance"; //--- Determine trendline type
string name = trendlines[i].name; //--- Get trendline name
if (current_time > trendlines[i].end_time) { //--- Check if expired
PrintFormat("%s trendline %s is no longer valid (expired). End time: %s, Current time: %s.", type, name, TimeToString(trendlines[i].end_time), TimeToString(current_time)); //--- Log expiration
RemoveTrendlineFromStorage(i); //--- Remove trendline
continue; //--- Skip to next
}
datetime prev_bar_time = iTime(_Symbol, _Period, 1); //--- Get previous bar time
double dk = (double)(prev_bar_time - trendlines[i].start_time); //--- Calculate time difference
double line_price = trendlines[i].start_price + trendlines[i].slope * dk; //--- Calculate line price
double prev_close = iClose(_Symbol, _Period, 1); //--- Get previous bar close
double prev_low = iLow(_Symbol, _Period, 1); //--- Get previous bar low
double prev_high = iHigh(_Symbol, _Period, 1); //--- Get previous bar high
bool broken = false; //--- Initialize broken flag
if (BreakoutType == BREAKOUT_CLOSE) { //--- Check breakout on close
if (trendlines[i].is_support && prev_close < line_price) { //--- Support break by close
PrintFormat("%s trendline %s is no longer valid (broken by close). Line price: %.5f, Prev close: %.5f.", type, name, line_price, prev_close); //--- Log break
broken = true; //--- Set broken flag
} else if (!trendlines[i].is_support && prev_close > line_price) { //--- Resistance break by close
PrintFormat("%s trendline %s is no longer valid (broken by close). Line price: %.5f, Prev close: %.5f.", type, name, line_price, prev_close); //--- Log break
broken = true; //--- Set broken flag
}
} else if (BreakoutType == BREAKOUT_CANDLE) { //--- Check breakout on entire candle
if (trendlines[i].is_support && prev_high < line_price) { //--- Entire candle below support
PrintFormat("%s trendline %s is no longer valid (entire candle below). Line price: %.5f, Prev high: %.5f.", type, name, line_price, prev_high); //--- Log break
broken = true; //--- Set broken flag
} else if (!trendlines[i].is_support && prev_low > line_price) { //--- Entire candle above resistance
PrintFormat("%s trendline %s is no longer valid (entire candle above). Line price: %.5f, Prev low: %.5f.", type, name, line_price, prev_low); //--- Log break
broken = true; //--- Set broken flag
}
}
if (broken && EnableTradingSignals && !trendlines[i].is_signaled) { //--- Check for breakout signal
bool signaled = false; //--- Initialize signaled flag
string signal_type = ""; //--- Initialize signal type
color signal_color = clrNONE; //--- Initialize signal color
int arrow_code = 0; //--- Initialize arrow code
int anchor = 0; //--- Initialize anchor
double text_angle = 0.0; //--- Initialize text angle
double text_offset = 0.0; //--- Initialize text offset
double text_price = 0.0; //--- Initialize text price
int text_anchor = 0; //--- Initialize text anchor
if (trendlines[i].is_support) { //--- Support break: SELL
signaled = true; //--- Set signaled flag
signal_type = "SELL BREAK"; //--- Set sell break signal
signal_color = clrRed; //--- Set red color
arrow_code = 218; //--- Set down arrow
anchor = ANCHOR_BOTTOM; //--- Set bottom anchor
text_angle = 90.0; //--- Set vertical downward
text_offset = 20 * pointValue; //--- Set text offset
text_price = line_price + text_offset; //--- Calculate text price
text_anchor = ANCHOR_BOTTOM; //--- Set bottom anchor
double Bid = NormalizeDouble(SymbolInfoDouble(_Symbol, SYMBOL_BID), _Digits); //--- Get bid price
double SL = NormalizeDouble(line_price + inpSLPoints * _Point, _Digits); //--- SL above the line
double risk = SL - Bid; //--- Calculate risk
double TP = NormalizeDouble(Bid - risk * inpRRRatio, _Digits); //--- Calculate take profit
obj_Trade.Sell(inpLot, _Symbol, Bid, SL, TP); //--- Execute sell trade
} else { //--- Resistance break: BUY
signaled = true; //--- Set signaled flag
signal_type = "BUY BREAK"; //--- Set buy break signal
signal_color = clrBlue; //--- Set blue color
arrow_code = 217; //--- Set up arrow
anchor = ANCHOR_TOP; //--- Set top anchor
text_angle = -90.0; //--- Set vertical upward
text_offset = -20 * pointValue; //--- Set text offset
text_price = line_price + text_offset; //--- Calculate text price
text_anchor = ANCHOR_LEFT; //--- Set left anchor
double Ask = NormalizeDouble(SymbolInfoDouble(_Symbol, SYMBOL_ASK), _Digits); //--- Get ask price
double SL = NormalizeDouble(line_price - inpSLPoints * _Point, _Digits); //--- SL below the line
double risk = Ask - SL; //--- Calculate risk
double TP = NormalizeDouble(Ask + risk * inpRRRatio, _Digits); //--- Calculate take profit
obj_Trade.Buy(inpLot, _Symbol, Ask, SL, TP); //--- Execute buy trade
}
if (signaled) { //--- Check if signaled
PrintFormat("Breakout signal generated for %s trendline %s: %s at price %.5f, time %s.", type, name, signal_type, line_price, TimeToString(current_time)); //--- Log signal
string arrow_name = name + "_signal_arrow"; //--- Generate signal arrow name
if (ObjectFind(0, arrow_name) < 0) { //--- Check if arrow exists
ObjectCreate(0, arrow_name, OBJ_ARROW, 0, prev_bar_time, line_price); //--- Create signal arrow
ObjectSetInteger(0, arrow_name, OBJPROP_ARROWCODE, arrow_code); //--- Set arrow code
ObjectSetInteger(0, arrow_name, OBJPROP_ANCHOR, anchor); //--- Set anchor
ObjectSetInteger(0, arrow_name, OBJPROP_COLOR, signal_color); //--- Set color
ObjectSetInteger(0, arrow_name, OBJPROP_WIDTH, 1); //--- Set width
ObjectSetInteger(0, arrow_name, OBJPROP_BACK, false); //--- Set to foreground
}
string text_name = name + "_signal_text"; //--- Generate signal text name
if (ObjectFind(0, text_name) < 0) { //--- Check if text exists
ObjectCreate(0, text_name, OBJ_TEXT, 0, prev_bar_time, text_price); //--- Create signal text
ObjectSetString(0, text_name, OBJPROP_TEXT, " " + signal_type); //--- Set text content
ObjectSetInteger(0, text_name, OBJPROP_COLOR, signal_color); //--- Set color
ObjectSetInteger(0, text_name, OBJPROP_FONTSIZE, 10); //--- Set font size
ObjectSetInteger(0, text_name, OBJPROP_ANCHOR, text_anchor); //--- Set anchor
ObjectSetDouble(0, text_name, OBJPROP_ANGLE, text_angle); //--- Set angle
ObjectSetInteger(0, text_name, OBJPROP_BACK, false); //--- Set to foreground
}
trendlines[i].is_signaled = true; //--- Set signaled flag
}
}
if (broken) { //--- Remove if broken
RemoveTrendlineFromStorage(i); //--- Remove trendline
}
}
}
//+------------------------------------------------------------------+
//| Find and draw trendlines if no active one exists |
//+------------------------------------------------------------------+
void FindAndDrawTrendlines(bool isSupport) {
bool has_active = false; //--- Initialize active flag
for (int i = 0; i < numTrendlines; i++) { //--- Iterate through trendlines
if (trendlines[i].is_support == isSupport) { //--- Check type match
has_active = true; //--- Set active flag
break; //--- Exit loop
}
}
if (has_active) return; //--- Exit if active trendline exists
Swing swings[]; //--- Initialize swings array
int numSwings; //--- Initialize swings count
color lineColor; //--- Initialize line color
string prefix; //--- Initialize prefix
if (isSupport) { //--- Handle support case
numSwings = numLows; //--- Set number of lows
ArrayResize(swings, numSwings); //--- Resize swings array
for (int i = 0; i < numSwings; i++) { //--- Iterate through lows
swings[i].time = swingLows[i].time; //--- Copy low time
swings[i].price = swingLows[i].price; //--- Copy low price
}
lineColor = SupportLineColor; //--- Set support line color
prefix = "Trendline_Support_"; //--- Set support prefix
} else { //--- Handle resistance case
numSwings = numHighs; //--- Set number of highs
ArrayResize(swings, numSwings); //--- Resize swings array
for (int i = 0; i < numSwings; i++) { //--- Iterate through highs
swings[i].time = swingHighs[i].time; //--- Copy high time
swings[i].price = swingHighs[i].price; //--- Copy high price
}
lineColor = ResistanceLineColor; //--- Set resistance line color
prefix = "Trendline_Resistance_"; //--- Set resistance prefix
}
if (numSwings < 2) return; //--- Exit if insufficient swings
double pointValue = _Point; //--- Get point value
double touch_tolerance = TouchTolerance * pointValue; //--- Calculate touch tolerance
double pen_tolerance = PenetrationTolerance * pointValue; //--- Calculate penetration tolerance
int best_j = -1; //--- Initialize best j index
int max_touches = 0; //--- Initialize max touches
double best_rsquared = -1.0; //--- Initialize best R-squared
int best_touch_indices[]; //--- Initialize best touch indices
double best_slope = 0.0; //--- Initialize best slope
double best_intercept = 0.0; //--- Initialize best intercept
datetime best_min_time = 0; //--- Initialize best min time
for (int i = 0; i < numSwings - 1; i++) { //--- Iterate through first points
for (int j = i + 1; j < numSwings; j++) { //--- Iterate through second points
datetime time1 = swings[i].time; //--- Get first time
double price1 = swings[i].price; //--- Get first price
datetime time2 = swings[j].time; //--- Get second time
double price2 = swings[j].price; //--- Get second price
double dt = (double)(time2 - time1); //--- Calculate time difference
if (dt <= 0) continue; //--- Skip invalid time difference
double initial_slope = (price2 - price1) / dt; //--- Calculate initial slope
int touch_indices[]; //--- Initialize touch indices
ArrayResize(touch_indices, 0); //--- Resize touch indices
int touches = 0; //--- Initialize touches count
ArrayResize(touch_indices, touches + 1); //--- Add first index
touch_indices[touches] = i; //--- Set first index
touches++; //--- Increment touches
ArrayResize(touch_indices, touches + 1); //--- Add second index
touch_indices[touches] = j; //--- Set second index
touches++; //--- Increment touches
for (int k = 0; k < numSwings; k++) { //--- Iterate through swings
if (k == i || k == j) continue; //--- Skip used indices
datetime tk = swings[k].time; //--- Get swing time
double dk = (double)(tk - time1); //--- Calculate time difference
double expected = price1 + initial_slope * dk; //--- Calculate expected price
double actual = swings[k].price; //--- Get actual price
if (MathAbs(expected - actual) <= touch_tolerance) { //--- Check touch within tolerance
ArrayResize(touch_indices, touches + 1); //--- Add index
touch_indices[touches] = k; //--- Set index
touches++; //--- Increment touches
}
}
if (touches >= MinTouches) { //--- Check minimum touches
ArraySort(touch_indices); //--- Sort touch indices
bool valid_spacing = true; //--- Initialize spacing flag
for (int m = 0; m < touches - 1; m++) { //--- Iterate through touches
int idx1 = touch_indices[m]; //--- Get first index
int idx2 = touch_indices[m + 1]; //--- Get second index
int bar1 = iBarShift(_Symbol, _Period, swings[idx1].time); //--- Get first bar
int bar2 = iBarShift(_Symbol, _Period, swings[idx2].time); //--- Get second bar
int diff = MathAbs(bar1 - bar2); //--- Calculate bar difference
if (diff < MinBarSpacing) { //--- Check minimum spacing
valid_spacing = false; //--- Mark invalid spacing
break; //--- Exit loop
}
}
if (valid_spacing) { //--- Check valid spacing
datetime touch_times[]; //--- Initialize touch times
double touch_prices[]; //--- Initialize touch prices
ArrayResize(touch_times, touches); //--- Resize times array
ArrayResize(touch_prices, touches); //--- Resize prices array
for (int m = 0; m < touches; m++) { //--- Iterate through touches
int idx = touch_indices[m]; //--- Get index
touch_times[m] = swings[idx].time; //--- Set time
touch_prices[m] = swings[idx].price; //--- Set price
}
double slope = initial_slope; //--- Use initial slope from two points
double intercept = price1 - slope * (double)time1; //--- Calculate intercept
double rsquared = CalculateRSquared(touch_times, touch_prices, touches, slope, intercept); //--- Calculate R-squared
if (rsquared >= MinRSquared) { //--- Check minimum R-squared
int adjusted_touch_indices[]; //--- Initialize adjusted indices
ArrayResize(adjusted_touch_indices, touches); //--- Resize to current touches
ArrayCopy(adjusted_touch_indices, touch_indices); //--- Copy indices
int adjusted_touches = touches; //--- Set adjusted touches
if (adjusted_touches >= MinTouches) { //--- Check minimum adjusted touches
datetime temp_min_time = swings[adjusted_touch_indices[0]].time; //--- Get min time
double temp_ref_price = intercept + slope * (double)temp_min_time; //--- Calculate ref price
if (ValidateTrendline(isSupport, temp_min_time, temp_min_time, temp_ref_price, slope, pen_tolerance)) { //--- Validate trendline
datetime temp_max_time = swings[adjusted_touch_indices[adjusted_touches - 1]].time; //--- Get max time
double temp_max_price = intercept + slope * (double)temp_max_time; //--- Calculate max price
double angle = CalculateAngle(temp_min_time, temp_ref_price, temp_max_time, temp_max_price); //--- Calculate angle
double abs_angle = MathAbs(angle); //--- Get absolute angle
if (abs_angle >= MinAngle && abs_angle <= MaxAngle) { //--- Check angle range
if (adjusted_touches > max_touches || (adjusted_touches == max_touches && rsquared > best_rsquared)) { //--- Check better trendline
max_touches = adjusted_touches; //--- Update max touches
best_rsquared = rsquared; //--- Update best R-squared
best_j = j; //--- Update best j
best_slope = slope; //--- Update best slope
best_intercept = intercept; //--- Update best intercept
best_min_time = temp_min_time; //--- Update best min time
ArrayResize(best_touch_indices, adjusted_touches); //--- Resize best indices
ArrayCopy(best_touch_indices, adjusted_touch_indices); //--- Copy indices
}
}
}
}
}
}
}
}
}
if (max_touches < MinTouches) { //--- Check insufficient touches
string type = isSupport ? "Support" : "Resistance"; //--- Set type string
return; //--- Exit function
}
int touch_indices[]; //--- Initialize touch indices
ArrayResize(touch_indices, max_touches); //--- Resize touch indices
ArrayCopy(touch_indices, best_touch_indices); //--- Copy best indices
int touches = max_touches; //--- Set touches count
datetime min_time = best_min_time; //--- Set min time
double price_min = best_intercept + best_slope * (double)min_time; //--- Calculate min price
datetime max_time = swings[touch_indices[touches - 1]].time; //--- Set max time
double price_max = best_intercept + best_slope * (double)max_time; //--- Calculate max price
datetime start_time_check = min_time; //--- Set start time check
double start_price_check = price_min; //--- Set start price check (approximate if not exact)
if (IsStartingPointUsed(start_time_check, start_price_check, isSupport)) { //--- Check used starting point
return; //--- Skip if used
}
datetime time_end = iTime(_Symbol, _Period, 0) + PeriodSeconds(_Period) * ExtensionBars; //--- Calculate end time
double dk_end = (double)(time_end - min_time); //--- Calculate end time difference
double price_end = price_min + best_slope * dk_end; //--- Calculate end price
string unique_name = prefix + TimeToString(TimeCurrent(), TIME_DATE|TIME_MINUTES|TIME_SECONDS); //--- Generate unique name
if (ObjectFind(0, unique_name) < 0) { //--- Check if trendline exists
ObjectCreate(0, unique_name, OBJ_TREND, 0, min_time, price_min, time_end, price_end); //--- Create trendline
ObjectSetInteger(0, unique_name, OBJPROP_COLOR, lineColor); //--- Set color
ObjectSetInteger(0, unique_name, OBJPROP_STYLE, STYLE_SOLID); //--- Set style
ObjectSetInteger(0, unique_name, OBJPROP_WIDTH, 1); //--- Set width
ObjectSetInteger(0, unique_name, OBJPROP_RAY_RIGHT, false); //--- Disable right ray
ObjectSetInteger(0, unique_name, OBJPROP_RAY_LEFT, false); //--- Disable left ray
ObjectSetInteger(0, unique_name, OBJPROP_BACK, false); //--- Set to foreground
}
ArrayResize(trendlines, numTrendlines + 1); //--- Resize trendlines array
trendlines[numTrendlines].name = unique_name; //--- Set trendline name
trendlines[numTrendlines].start_time = min_time; //--- Set start time
trendlines[numTrendlines].end_time = time_end; //--- Set end time
trendlines[numTrendlines].start_price = price_min; //--- Set start price
trendlines[numTrendlines].end_price = price_end; //--- Set end price
trendlines[numTrendlines].slope = best_slope; //--- Set slope
trendlines[numTrendlines].is_support = isSupport; //--- Set type
trendlines[numTrendlines].touch_count = touches; //--- Set touch count
trendlines[numTrendlines].creation_time = TimeCurrent(); //--- Set creation time
trendlines[numTrendlines].is_signaled = false; //--- Set signaled flag
ArrayResize(trendlines[numTrendlines].touch_indices, touches); //--- Resize touch indices
ArrayCopy(trendlines[numTrendlines].touch_indices, touch_indices); //--- Copy touch indices
numTrendlines++; //--- Increment trendlines count
ArrayResize(startingPoints, numStartingPoints + 1); //--- Resize starting points array
startingPoints[numStartingPoints].time = start_time_check;//--- Set starting point time
startingPoints[numStartingPoints].price = start_price_check; //--- Set starting point price
startingPoints[numStartingPoints].is_support = isSupport; //--- Set starting point type
numStartingPoints++; //--- Increment starting points count
if (DrawTouchArrows) { //--- Check draw arrows
for (int m = 0; m < touches; m++) { //--- Iterate through touches
int idx = touch_indices[m]; //--- Get touch index
datetime tk_time = swings[idx].time; //--- Get touch time
double tk_price = swings[idx].price; //--- Get touch price
string arrow_name = unique_name + "_touch" + IntegerToString(m); //--- Generate arrow name
if (ObjectFind(0, arrow_name) < 0) { //--- Check if arrow exists
ObjectCreate(0, arrow_name, OBJ_ARROW, 0, tk_time, tk_price); //--- Create touch arrow
ObjectSetInteger(0, arrow_name, OBJPROP_ARROWCODE, 159); //--- Set arrow code
ObjectSetInteger(0, arrow_name, OBJPROP_ANCHOR, isSupport ? ANCHOR_TOP : ANCHOR_BOTTOM); //--- Set anchor
ObjectSetInteger(0, arrow_name, OBJPROP_COLOR, lineColor); //--- Set color
ObjectSetInteger(0, arrow_name, OBJPROP_WIDTH, 1); //--- Set width
ObjectSetInteger(0, arrow_name, OBJPROP_BACK, false); //--- Set to foreground
}
}
}
double angle = CalculateAngle(min_time, price_min, max_time, price_max); //--- Calculate angle
string type = isSupport ? "Support" : "Resistance"; //--- Set type string
Print(type + " Trendline " + unique_name + " drawn with " + IntegerToString(touches) + " touches. Inclination angle: " + DoubleToString(angle, 2) + " degrees."); //--- Log trendline
if (DrawLabels) { //--- Check draw labels
datetime mid_time = min_time + (max_time - min_time) / 2; //--- Calculate mid time
double dk_mid = (double)(mid_time - min_time); //--- Calculate mid time difference
double mid_price = price_min + best_slope * dk_mid; //--- Calculate mid price
double label_offset = 20 * _Point * (isSupport ? -1 : 1); //--- Calculate label offset
double label_price = mid_price + label_offset; //--- Calculate label price
int label_anchor = isSupport ? ANCHOR_TOP : ANCHOR_BOTTOM;//--- Set label anchor
string label_text = type + " Trendline"; //--- Set label text
string label_name = unique_name + "_label"; //--- Generate label name
if (ObjectFind(0, label_name) < 0) { //--- Check if label exists
ObjectCreate(0, label_name, OBJ_TEXT, 0, mid_time, label_price); //--- Create label
ObjectSetString(0, label_name, OBJPROP_TEXT, label_text); //--- Set text
ObjectSetInteger(0, label_name, OBJPROP_COLOR, clrBlack); //--- Set color
ObjectSetInteger(0, label_name, OBJPROP_FONTSIZE, 8); //--- Set font size
ObjectSetInteger(0, label_name, OBJPROP_ANCHOR, label_anchor); //--- Set anchor
ObjectSetDouble(0, label_name, OBJPROP_ANGLE, angle); //--- Set angle
ObjectSetInteger(0, label_name, OBJPROP_BACK, false); //--- Set to foreground
}
color point_label_color = isSupport ? clrSaddleBrown : clrDarkGoldenrod; //--- Set point label color
double point_text_offset = 20.0 * _Point; //--- Set point text offset
for (int m = 0; m < touches; m++) { //--- Iterate through touches
int idx = touch_indices[m]; //--- Get touch index
datetime tk_time = swings[idx].time; //--- Get touch time
double tk_price = swings[idx].price; //--- Get touch price
double text_price; //--- Initialize text price
int point_text_anchor; //--- Initialize text anchor
if (isSupport) { //--- Handle support
text_price = tk_price - point_text_offset; //--- Set text price below
point_text_anchor = ANCHOR_LEFT; //--- Set left anchor
} else { //--- Handle resistance
text_price = tk_price + point_text_offset; //--- Set text price above
point_text_anchor = ANCHOR_BOTTOM; //--- Set bottom anchor
}
string text_name = unique_name + "_point_label" + IntegerToString(m); //--- Generate text name
string point_text = "Pt " + IntegerToString(m + 1); //--- Set point text
if (ObjectFind(0, text_name) < 0) { //--- Check if text exists
ObjectCreate(0, text_name, OBJ_TEXT, 0, tk_time, text_price); //--- Create text
ObjectSetString(0, text_name, OBJPROP_TEXT, point_text); //--- Set text
ObjectSetInteger(0, text_name, OBJPROP_COLOR, point_label_color); //--- Set color
ObjectSetInteger(0, text_name, OBJPROP_FONTSIZE, 8); //--- Set font size
ObjectSetInteger(0, text_name, OBJPROP_ANCHOR, point_text_anchor); //--- Set anchor
ObjectSetDouble(0, text_name, OBJPROP_ANGLE, 0); //--- Set angle
ObjectSetInteger(0, text_name, OBJPROP_BACK, false); //--- Set to foreground
}
}
}
}
//+------------------------------------------------------------------+
Binary file not shown.
+258
View File
@@ -0,0 +1,258 @@
/*
============================================================
Demo File: Range_Breakout_EA - Signal Logic Showcase
Category: Breakout
Platform: MetaTrader 4 (MQL4)
Version: 1.0
Author: Giacomo Cipolat Bares
Portfolio: MQL4 Expert Advisors Portfolio
============================================================
Description:
This is a simplified public demo derived from the full
Range Breakout EA.
Included in this demo:
- range high/low detection
- breakout trigger calculation
- breakout buffer logic
- one-breakout-per-range logic
- breakout cooldown logic
- basic on-chart signal output
Excluded from this demo:
- order execution
- risk management engine
- break-even / trailing stop
- retry logic
- broker protection handling
- full production trade framework
- chart visualization layer
============================================================
*/
#property strict
#property version "1.00"
//========================= INPUTS ==================================
input string __01_BreakoutSettings = "01 ======== Breakout Settings ========";
input int BreakoutBars = 20;
input double BreakoutBufferPips = 0.5;
input bool UseCloseBreakout = false;
input bool OneBreakoutPerRange = true;
input bool ResetRangeAfterTrade = true;
input bool UseBreakoutCooldown = true;
input int BreakoutCooldownBars = 5;
//======================= BREAKOUT GLOBALS ==========================
double g_lastRangeHigh = 0.0;
double g_lastRangeLow = 0.0;
bool g_rangeAlreadyTraded = false;
int g_lastTradeBarIndex = -1;
//======================= GENERAL GLOBALS ===========================
double g_point;
double g_pip;
int g_digits;
datetime g_lastBarTime = 0;
//+------------------------------------------------------------------+
//| Expert initialization |
//+------------------------------------------------------------------+
int OnInit()
{
g_point = Point;
g_digits = Digits;
if(g_digits == 5 || g_digits == 3)
g_pip = g_point * 10.0;
else
g_pip = g_point;
Print("Range Breakout demo initialized");
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Detects a new bar |
//+------------------------------------------------------------------+
bool IsNewBar()
{
datetime currentBarTime = iTime(NULL, 0, 0);
if(currentBarTime != g_lastBarTime)
{
g_lastBarTime = currentBarTime;
return true;
}
return false;
}
//+------------------------------------------------------------------+
//| Range high from previous N bars |
//+------------------------------------------------------------------+
double GetBreakoutHigh()
{
int highestIndex = iHighest(NULL, 0, MODE_HIGH, BreakoutBars, 1);
return High[highestIndex];
}
//+------------------------------------------------------------------+
//| Range low from previous N bars |
//+------------------------------------------------------------------+
double GetBreakoutLow()
{
int lowestIndex = iLowest(NULL, 0, MODE_LOW, BreakoutBars, 1);
return Low[lowestIndex];
}
//+------------------------------------------------------------------+
//| Bullish breakout condition |
//+------------------------------------------------------------------+
bool IsBullishBreakout()
{
double breakoutHigh = GetBreakoutHigh();
double triggerPrice = breakoutHigh + BreakoutBufferPips * g_pip;
if(UseCloseBreakout)
return (Close[1] > triggerPrice);
return (Ask > triggerPrice);
}
//+------------------------------------------------------------------+
//| Bearish breakout condition |
//+------------------------------------------------------------------+
bool IsBearishBreakout()
{
double breakoutLow = GetBreakoutLow();
double triggerPrice = breakoutLow - BreakoutBufferPips * g_pip;
if(UseCloseBreakout)
return (Close[1] < triggerPrice);
return (Bid < triggerPrice);
}
//+------------------------------------------------------------------+
//| Checks if current range is same as previous tracked range |
//+------------------------------------------------------------------+
bool IsSameRange(double rangeHigh, double rangeLow)
{
if(MathAbs(rangeHigh - g_lastRangeHigh) < (g_point * 0.5) &&
MathAbs(rangeLow - g_lastRangeLow) < (g_point * 0.5))
{
return true;
}
return false;
}
//+------------------------------------------------------------------+
//| Updates tracked breakout range |
//+------------------------------------------------------------------+
void UpdateRangeState()
{
double currentRangeHigh = GetBreakoutHigh();
double currentRangeLow = GetBreakoutLow();
if(!IsSameRange(currentRangeHigh, currentRangeLow))
{
g_lastRangeHigh = currentRangeHigh;
g_lastRangeLow = currentRangeLow;
if(ResetRangeAfterTrade)
g_rangeAlreadyTraded = false;
}
}
//+------------------------------------------------------------------+
//| One breakout per range filter |
//+------------------------------------------------------------------+
bool CanTradeCurrentRange()
{
if(!OneBreakoutPerRange)
return true;
if(g_rangeAlreadyTraded)
return false;
return true;
}
//+------------------------------------------------------------------+
//| Breakout cooldown filter |
//+------------------------------------------------------------------+
bool BreakoutCooldownPassed()
{
if(!UseBreakoutCooldown)
return true;
if(g_lastTradeBarIndex < 0)
return true;
int barsPassed = Bars - g_lastTradeBarIndex;
if(barsPassed >= BreakoutCooldownBars)
return true;
return false;
}
//+------------------------------------------------------------------+
//| Demo buy signal wrapper |
//+------------------------------------------------------------------+
bool BuySignal()
{
if(!CanTradeCurrentRange())
return false;
if(!BreakoutCooldownPassed())
return false;
return IsBullishBreakout();
}
//+------------------------------------------------------------------+
//| Demo sell signal wrapper |
//+------------------------------------------------------------------+
bool SellSignal()
{
if(!CanTradeCurrentRange())
return false;
if(!BreakoutCooldownPassed())
return false;
return IsBearishBreakout();
}
//+------------------------------------------------------------------+
//| Expert tick |
//+------------------------------------------------------------------+
void OnTick()
{
if(!IsNewBar())
return;
UpdateRangeState();
if(BuySignal())
{
g_lastTradeBarIndex = Bars;
g_rangeAlreadyTraded = true;
Comment("Demo Signal: BUY breakout detected");
return;
}
if(SellSignal())
{
g_lastTradeBarIndex = Bars;
g_rangeAlreadyTraded = true;
Comment("Demo Signal: SELL breakout detected");
return;
}
Comment("Demo Signal: No valid breakout");
}
Binary file not shown.
@@ -0,0 +1,317 @@
//+------------------------------------------------------------------+
//| Support and Resistance EA.mq4 |
//| Copyright 2023,JBlanked |
//| https://www.jblanked.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2023,JBlanked"
#property link "https://www.jblanked.com"
#property strict
#include <CustomFunctionsFix.mqh>
input string orderSeng = "======= ORDER SETTINGS ======"; //--------------------------->
input double StopLoss = 10; // Stop Loss
input double TakeProfit = 600; // Take Profit
input bool usepercentrisk = true; // Use risk per trade?
input double percentrisk = 0.10; // Percent risk
input bool uselotsize = false; // Use lot size?
input double lotsizee = 0.10; // Lot size
input string orderSeting = "======= TREND SETTINGS ======"; //--------------------------->
input int MA_Period = 160; // Period for moving average
input int RSI_Period = 8; // Period for RSI
input int rsibuylevel = 20; // RSI under which level to buy
input int rsiselllevel = 80; // RSI above which level to sell
input bool reverseorder = false; // Reverse trend?
input bool HODL = false; // HODL til opposite setup?
input string BreakEvenSettings = "--------TAKE PARTIAL SETTINGS-------"; //--------------------------->
input bool UseBreakEvenStop = true; //Use take partials?
input double BEclosePercent = 50.0; //Close how much percent?
input double breakstart = 200; // Take partials after how many pips in profit (1)
input double breakstart2 = 300; // Take partials after how many pips in profit (2)
input double breakstart3 = 400; // Take partials after how many pips in profit (3)
input double breakstart4 = 500; // Take partials after how many pips in profit (4)
input double breakstop = 20; // Move stop loss in profit X pips
input string BkEvnSettings = "======= MARTINGALE SETTINGS ======="; //--------------------------->
input bool useMartingale = false; // Use martingale?
input double martinPips = 78; // Pips in between martingales
input double martinMULTI = 5; // Martingale multiplier
input string timeSettings = "======= TIME SETTINGS ======"; //--------------------
input bool UseTimer = false; // Custom trading hours (true/false)
input string StartTime1 = "16:30"; //1 Trading start time (hh:mm)
input string StopTime1 = "16:31"; //1 Trading stop time (hh:mm)
input string DAILY_TARGETS = "======= Gain/Loss ======="; //---------------
input double dailyTargetP = 10.0; // Daily Profit Target (%)
input double dailyLossP = 0.4; // Daily Max DD (%)
input string orderSettins = "======= OTHER SETTINGS ======"; //---------------
input string orderComments = "Support/Resistance EA"; // Order Comment
input int magicnumb = 918119; // Magic Number
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
//---
JBlankedInitCEO(magicnumb,918119,"Support/Resistance EA");
JBlankedBranding("Support/Resistance EA",magicnumb,string(expiryDateVIP));
//---
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Expert deinitialization function |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
//---
JBlankedDeinit();
}
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick()
{
//---
if(ApplyDailyTarget(dailyTargetP,dailyLossP,magicnumb)) return;
if(useMartingale) { martingale(_Symbol,magicnumb,OrderStopLoss(),martinMULTI,martinPips); }
//////////////////// Start Take Partials Tempalte
if(UseBreakEvenStop)DoBreak2(magicnumb,breakstart,BEclosePercent,breakstop,breakstart2,breakstart3,breakstart4);
//////////////////// End Take Partials Tempalte
//+------------------------------------------------------------------+
double MA = iMA(NULL,0,MA_Period,0,MODE_SMA,PRICE_CLOSE,0);
double RSI = iRSI(NULL,0,RSI_Period,PRICE_CLOSE,0);
double currentPrice = Close[0];
if(allowTime(UseTimer,StartTime1,StopTime1))
{
if(!CheckIfOpenOrdersByMagicNB(magicnumb,orderComments) && StopLoss != 0 && !HODL)
{
if(!reverseorder)
{
if (currentPrice > MA && RSI < rsibuylevel)
{
//price is above moving average and RSI is below 30, indicating oversold
//enter long position
int orderr= OrderSend(Symbol(),OP_BUY,GetRisk(usepercentrisk,uselotsize,percentrisk,StopLoss,lotsizee),Ask,3,Ask-StopLoss*GetPipValue(),Ask+TakeProfit*GetPipValue(),orderComments,magicnumb,0,Green);
}
else if (currentPrice < MA && RSI > rsiselllevel)
{
//price is below moving average and RSI is above 70, indicating overbought
//enter short position
int orderr= OrderSend(Symbol(),OP_SELL,GetRisk(usepercentrisk,uselotsize,percentrisk,StopLoss,lotsizee),Bid,3,Bid+StopLoss*GetPipValue(),Bid-TakeProfit*GetPipValue(),orderComments,magicnumb,0,Red);
}
}
if(reverseorder)
{
if (currentPrice > MA && RSI < rsibuylevel)
{
//price is above moving average and RSI is below 30, indicating oversold
//enter long position
int orderr= OrderSend(Symbol(),OP_SELL,GetRisk(usepercentrisk,uselotsize,percentrisk,StopLoss,lotsizee),Bid,3,Bid+StopLoss*GetPipValue(),Bid-TakeProfit*GetPipValue(),orderComments,magicnumb,0,Red);
}
else if (currentPrice < MA && RSI > rsiselllevel)
{
//price is below moving average and RSI is above 70, indicating overbought
//enter short position
int orderr= OrderSend(Symbol(),OP_BUY,GetRisk(usepercentrisk,uselotsize,percentrisk,StopLoss,lotsizee),Ask,3,Ask-StopLoss*GetPipValue(),Ask+TakeProfit*GetPipValue(),orderComments,magicnumb,0,Green);
}
}
}
if(!CheckIfOpenOrdersByMagicNB(magicnumb,orderComments) && StopLoss == 0)
{
if(!reverseorder)
{
if (currentPrice > MA && RSI < rsibuylevel)
{
//price is above moving average and RSI is below 30, indicating oversold
//enter long position
int orderr= OrderSend(Symbol(),OP_BUY,GetRisk(usepercentrisk,uselotsize,percentrisk,StopLoss,lotsizee),Ask,3,0,Ask+TakeProfit*GetPipValue(),orderComments,magicnumb,0,Green);
}
else if (currentPrice < MA && RSI > rsiselllevel)
{
//price is below moving average and RSI is above 70, indicating overbought
//enter short position
int orderr= OrderSend(Symbol(),OP_SELL,GetRisk(usepercentrisk,uselotsize,percentrisk,StopLoss,lotsizee),Bid,3,0,Bid-TakeProfit*GetPipValue(),orderComments,magicnumb,0,Red);
}
}
if(reverseorder)
{
if (currentPrice > MA && RSI < rsibuylevel)
{
//price is above moving average and RSI is below 30, indicating oversold
//enter long position
int orderr= OrderSend(Symbol(),OP_SELL,GetRisk(usepercentrisk,uselotsize,percentrisk,StopLoss,lotsizee),Bid,3,0,Bid-TakeProfit*GetPipValue(),orderComments,magicnumb,0,Red);
}
else if (currentPrice < MA && RSI > rsiselllevel)
{
//price is below moving average and RSI is above 70, indicating overbought
//enter short position
int orderr= OrderSend(Symbol(),OP_BUY,GetRisk(usepercentrisk,uselotsize,percentrisk,StopLoss,lotsizee),Ask,3,0,Ask+TakeProfit*GetPipValue(),orderComments,magicnumb,0,Green);
}
}
}
if(!CheckIfOpenOrdersByMagicNB(magicnumb,orderComments) && StopLoss != 0 && HODL)
{
if(!reverseorder)
{
if (currentPrice > MA && RSI < rsibuylevel)
{
//price is above moving average and RSI is below 30, indicating oversold
//enter long position
int orderr= OrderSend(Symbol(),OP_BUY,GetRisk(usepercentrisk,uselotsize,percentrisk,StopLoss,lotsizee),Ask,3,Ask-StopLoss*GetPipValue(),0,orderComments,magicnumb,0,Green);
}
else if (currentPrice < MA && RSI > rsiselllevel)
{
//price is below moving average and RSI is above 70, indicating overbought
//enter short position
int orderr= OrderSend(Symbol(),OP_SELL,GetRisk(usepercentrisk,uselotsize,percentrisk,StopLoss,lotsizee),Bid,3,Bid+StopLoss*GetPipValue(),0,orderComments,magicnumb,0,Red);
}
}
if(reverseorder)
{
if (currentPrice > MA && RSI < rsibuylevel)
{
//price is above moving average and RSI is below 30, indicating oversold
//enter long position
int orderr= OrderSend(Symbol(),OP_SELL,GetRisk(usepercentrisk,uselotsize,percentrisk,StopLoss,lotsizee),Bid,3,Bid+StopLoss*GetPipValue(),0,orderComments,magicnumb,0,Red);
}
else if (currentPrice < MA && RSI > rsiselllevel)
{
//price is below moving average and RSI is above 70, indicating overbought
//enter short position
int orderr= OrderSend(Symbol(),OP_BUY,GetRisk(usepercentrisk,uselotsize,percentrisk,StopLoss,lotsizee),Ask,3,Ask-StopLoss*GetPipValue(),0,orderComments,magicnumb,0,Green);
}
}
}
if(!CheckIfOpenOrdersByMagicNB(magicnumb,orderComments) && StopLoss == 0)
{
if(!reverseorder)
{
if (currentPrice > MA && RSI < rsibuylevel)
{
//price is above moving average and RSI is below 30, indicating oversold
//enter long position
int orderr= OrderSend(Symbol(),OP_BUY,GetRisk(usepercentrisk,uselotsize,percentrisk,StopLoss,lotsizee),Ask,3,0,0,orderComments,magicnumb,0,Green);
}
else if (currentPrice < MA && RSI > rsiselllevel)
{
//price is below moving average and RSI is above 70, indicating overbought
//enter short position
int orderr= OrderSend(Symbol(),OP_SELL,GetRisk(usepercentrisk,uselotsize,percentrisk,StopLoss,lotsizee),Bid,3,0,0,orderComments,magicnumb,0,Red);
}
}
if(reverseorder)
{
if (currentPrice > MA && RSI < rsibuylevel)
{
//price is above moving average and RSI is below 30, indicating oversold
//enter long position
int orderr= OrderSend(Symbol(),OP_SELL,GetRisk(usepercentrisk,uselotsize,percentrisk,StopLoss,lotsizee),Bid,3,0,0,orderComments,magicnumb,0,Red);
}
else if (currentPrice < MA && RSI > rsiselllevel)
{
//price is below moving average and RSI is above 70, indicating overbought
//enter short position
int orderr= OrderSend(Symbol(),OP_BUY,GetRisk(usepercentrisk,uselotsize,percentrisk,StopLoss,lotsizee),Ask,3,0,0,orderComments,magicnumb,0,Green);
}
}
}
}
}
Binary file not shown.
+413
View File
@@ -0,0 +1,413 @@
//+------------------------------------------------------------------+
//| HedgeEA.mq4 |
//| Copyright 2024, MetaQuotes Software Corp. |
//| https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2024"
#property link "https://www.mql5.com"
#property version "1.00"
#property strict
// Input Parameters
input double LotSize = 0.1; // Lot Size
input double HedgeLotSize = 0.1; // Hedge Lot Size
input int StopLoss = 50; // Stop Loss in pips
input int TakeProfit = 100; // Take Profit in pips
input int MagicNumber = 123456; // Magic Number
input int Slippage = 3; // Slippage in pips
input double MaxLossPercent = 1.0; // Maximum Loss Percent before Hedging
input double TargetProfit = 2.0; // Target Profit Percent to Close All
input int StartHour = 0; // Trading Start Hour
input int EndHour = 24; // Trading End Hour
input double MaxMarginLevel = 1000; // Maximum margin level before closing positions
input bool UseTrailingStop = true; // Use trailing stop
input int TrailingStop = 20; // Trailing stop in pips
input int TrailingStep = 5; // Trailing step in pips
input bool UseDynamicLotSize = false; // Use dynamic lot size
input double RiskPercent = 1.0; // Risk percent for dynamic lot size
input int MaxPositionAge = 24; // Maximum position age in hours
input bool UseNewsFilter = true; // Use news filter
input int NewsMinutesBefore = 30; // Minutes before news to avoid trading
input int NewsMinutesAfter = 30; // Minutes after news to avoid trading
input bool UseSessionFilter = true; // Use session filter
input string AsianSession = "00:00-08:00"; // Asian session
input string LondonSession = "08:00-16:00"; // London session
input string NewYorkSession = "13:00-21:00"; // New York session
input bool UseRiskManagement = true; // Use advanced risk management
input double DailyLossLimit = 2.0; // Daily loss limit in percent
input double WeeklyLossLimit = 5.0; // Weekly loss limit in percent
// Global Variables
int ticket = 0;
bool hedgedPositions[]; // Array to track hedged positions
int totalPositions = 0;
datetime lastTradeTime = 0;
double dailyProfit = 0;
double weeklyProfit = 0;
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
ArrayResize(hedgedPositions, 100); // Initialize array for 100 positions
ArrayInitialize(hedgedPositions, false);
lastTradeTime = TimeCurrent();
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Expert deinitialization function |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
ArrayFree(hedgedPositions);
}
//+------------------------------------------------------------------+
//| Check if trading is allowed in current time |
//+------------------------------------------------------------------+
bool IsTradingTime()
{
int currentHour = TimeHour(TimeCurrent());
return (currentHour >= StartHour && currentHour < EndHour);
}
//+------------------------------------------------------------------+
//| Check if current time is within a trading session |
//+------------------------------------------------------------------+
bool IsInSession(string session)
{
string times[];
StringSplit(session, '-', times);
if(ArraySize(times) != 2) return false;
string currentTime = TimeToString(TimeCurrent(), TIME_MINUTES);
return (currentTime >= times[0] && currentTime < times[1]);
}
//+------------------------------------------------------------------+
//| Check if trading is allowed based on sessions |
//+------------------------------------------------------------------+
bool IsSessionAllowed()
{
if(!UseSessionFilter) return true;
return (IsInSession(AsianSession) || IsInSession(LondonSession) || IsInSession(NewYorkSession));
}
//+------------------------------------------------------------------+
//| Check if there is important news coming |
//+------------------------------------------------------------------+
bool IsNewsTime()
{
if(!UseNewsFilter) return false;
// Here you would implement your news checking logic
// This is a placeholder - you would need to integrate with a news API
return false;
}
//+------------------------------------------------------------------+
//| Calculate total profit of all positions |
//+------------------------------------------------------------------+
double CalculateTotalProfit()
{
double totalProfit = 0;
for(int i = 0; i < OrdersTotal(); i++)
{
if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
{
if(OrderMagicNumber() == MagicNumber)
{
totalProfit += OrderProfit();
}
}
}
return totalProfit;
}
//+------------------------------------------------------------------+
//| Calculate dynamic lot size based on risk |
//+------------------------------------------------------------------+
double CalculateLotSize()
{
if(!UseDynamicLotSize) return LotSize;
double riskAmount = AccountBalance() * RiskPercent / 100;
double tickValue = MarketInfo(Symbol(), MODE_TICKVALUE);
double stopLossPoints = StopLoss * Point;
return NormalizeDouble(riskAmount / (stopLossPoints * tickValue), 2);
}
//+------------------------------------------------------------------+
//| Check if position is too old |
//+------------------------------------------------------------------+
bool IsPositionTooOld(int ticket)
{
if(OrderSelect(ticket, SELECT_BY_TICKET))
{
datetime positionAge = TimeCurrent() - OrderOpenTime();
return (positionAge > MaxPositionAge * 3600);
}
return false;
}
//+------------------------------------------------------------------+
//| Check if daily or weekly loss limits are reached |
//+------------------------------------------------------------------+
bool IsLossLimitReached()
{
if(!UseRiskManagement) return false;
datetime currentTime = TimeCurrent();
if(TimeDay(currentTime) != TimeDay(lastTradeTime))
{
dailyProfit = 0;
lastTradeTime = currentTime;
}
if(TimeDayOfWeek(currentTime) == 0) // Sunday
{
weeklyProfit = 0;
}
double currentProfit = CalculateTotalProfit();
dailyProfit += currentProfit;
weeklyProfit += currentProfit;
return (dailyProfit <= -AccountBalance() * DailyLossLimit / 100 ||
weeklyProfit <= -AccountBalance() * WeeklyLossLimit / 100);
}
//+------------------------------------------------------------------+
//| Close all positions |
//+------------------------------------------------------------------+
void CloseAllPositions()
{
for(int i = OrdersTotal() - 1; i >= 0; i--)
{
if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
{
if(OrderMagicNumber() == MagicNumber)
{
bool result = false;
if(OrderType() == OP_BUY)
result = OrderClose(OrderTicket(), OrderLots(), Bid, Slippage, clrRed);
else if(OrderType() == OP_SELL)
result = OrderClose(OrderTicket(), OrderLots(), Ask, Slippage, clrGreen);
if(!result)
{
Print("Error closing order #", OrderTicket(), ": ", GetLastError());
}
}
}
}
}
//+------------------------------------------------------------------+
//| Check if trading conditions are met |
//+------------------------------------------------------------------+
bool CheckTradeConditions()
{
if(!IsTradeAllowed()) return false;
if(!IsTradingTime()) return false;
if(!IsSessionAllowed()) return false;
if(IsNewsTime()) return false;
if(AccountMargin() > MaxMarginLevel) return false;
if(IsLossLimitReached()) return false;
return true;
}
//+------------------------------------------------------------------+
//| Print trade information |
//+------------------------------------------------------------------+
void PrintTradeInfo()
{
Print("Total Positions: ", OrdersTotal());
Print("Total Profit: ", CalculateTotalProfit());
Print("Account Balance: ", AccountBalance());
Print("Daily Profit: ", dailyProfit);
Print("Weekly Profit: ", weeklyProfit);
Print("Current Session: ", IsInSession(AsianSession) ? "Asian" :
(IsInSession(LondonSession) ? "London" :
(IsInSession(NewYorkSession) ? "New York" : "No Session")));
}
//+------------------------------------------------------------------+
//| Check if lot size is valid and can be opened |
//+------------------------------------------------------------------+
bool IsValidLotSize(double lot)
{
double minLot = MarketInfo(Symbol(), MODE_MINLOT);
double maxLot = MarketInfo(Symbol(), MODE_MAXLOT);
double lotStep = MarketInfo(Symbol(), MODE_LOTSTEP);
// بررسی محدوده حجم
if(lot < minLot || lot > maxLot)
{
Print("Invalid lot size: ", lot, " (Min: ", minLot, ", Max: ", maxLot, ")");
return false;
}
// بررسی گام حجم
if(MathAbs(MathMod(lot, lotStep)) > 0.00001)
{
Print("Lot size must be a multiple of ", lotStep);
return false;
}
return true;
}
//+------------------------------------------------------------------+
//| Check if there is enough margin to open position |
//+------------------------------------------------------------------+
bool HasEnoughMargin(int type, double lot)
{
double margin = MarketInfo(Symbol(), MODE_MARGINREQUIRED) * lot;
double freeMargin = AccountFreeMargin();
if(freeMargin < margin)
{
Print("Not enough margin. Required: ", margin, ", Free: ", freeMargin);
return false;
}
return true;
}
//+------------------------------------------------------------------+
//| Try to reduce lot size if original size cannot be opened |
//+------------------------------------------------------------------+
double GetAdjustedLotSize(double originalLot)
{
double minLot = MarketInfo(Symbol(), MODE_MINLOT);
double lotStep = MarketInfo(Symbol(), MODE_LOTSTEP);
double adjustedLot = originalLot;
while(adjustedLot > minLot)
{
if(IsValidLotSize(adjustedLot) && HasEnoughMargin(OP_BUY, adjustedLot))
{
Print("Adjusted lot size from ", originalLot, " to ", adjustedLot);
return adjustedLot;
}
adjustedLot -= lotStep;
}
return 0; // اگر هیچ حجمی نتواند باز شود
}
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick()
{
if(!CheckTradeConditions()) return;
// Check total profit and close all if target reached
double totalProfit = CalculateTotalProfit();
if(totalProfit >= AccountBalance() * TargetProfit / 100)
{
CloseAllPositions();
return;
}
// Check if we have any open positions
if(OrdersTotal() > 0)
{
for(int i = 0; i < OrdersTotal(); i++)
{
if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
{
if(OrderMagicNumber() == MagicNumber)
{
// Check if position is too old
if(IsPositionTooOld(OrderTicket()))
{
bool result = false;
if(OrderType() == OP_BUY)
result = OrderClose(OrderTicket(), OrderLots(), Bid, Slippage, clrRed);
else if(OrderType() == OP_SELL)
result = OrderClose(OrderTicket(), OrderLots(), Ask, Slippage, clrGreen);
continue;
}
// Calculate loss percentage
double lossPercent = MathAbs(OrderProfit()) / AccountBalance() * 100;
// If position is in loss and not hedged yet and loss exceeds threshold
if(OrderProfit() < 0 && !hedgedPositions[OrderTicket()] && lossPercent >= MaxLossPercent)
{
double hedgeLot = CalculateLotSize();
// بررسی و تنظیم حجم
if(!IsValidLotSize(hedgeLot) || !HasEnoughMargin(OrderType() == OP_BUY ? OP_SELL : OP_BUY, hedgeLot))
{
hedgeLot = GetAdjustedLotSize(hedgeLot);
if(hedgeLot == 0)
{
Print("Cannot open hedge position - no valid lot size available");
// اینجا می‌توانید تصمیم بگیرید چه کاری انجام شود
// مثلاً بستن پوزیشن اصلی یا ارسال هشدار
if(CloseOnHedgeFailure) // یک پارامتر جدید
{
OrderClose(OrderTicket(), OrderLots(),
OrderType() == OP_BUY ? Bid : Ask,
Slippage, clrRed);
Print("Closed original position due to hedge failure");
}
continue;
}
}
// باز کردن پوزیشن هدج با حجم تنظیم شده
if(OrderType() == OP_BUY)
{
ticket = OrderSend(Symbol(), OP_SELL, hedgeLot, Bid, Slippage,
OrderOpenPrice() + StopLoss * Point,
OrderOpenPrice() - TakeProfit * Point,
"Hedge", MagicNumber, 0, clrRed);
}
else if(OrderType() == OP_SELL)
{
ticket = OrderSend(Symbol(), OP_BUY, hedgeLot, Ask, Slippage,
OrderOpenPrice() - StopLoss * Point,
OrderOpenPrice() + TakeProfit * Point,
"Hedge", MagicNumber, 0, clrGreen);
}
if(ticket > 0)
{
hedgedPositions[OrderTicket()] = true;
Print("Hedge position opened successfully for order #", OrderTicket(),
" with adjusted lot size: ", hedgeLot);
}
else
{
Print("Error opening hedge position: ", GetLastError());
if(CloseOnHedgeFailure)
{
OrderClose(OrderTicket(), OrderLots(),
OrderType() == OP_BUY ? Bid : Ask,
Slippage, clrRed);
Print("Closed original position due to hedge failure");
}
}
}
}
}
}
}
// Print trade information periodically
static datetime lastPrintTime = 0;
if(TimeCurrent() - lastPrintTime >= 3600) // Print every hour
{
PrintTradeInfo();
lastPrintTime = TimeCurrent();
}
}
Binary file not shown.
File diff suppressed because it is too large Load Diff
Binary file not shown.
+199
View File
@@ -0,0 +1,199 @@
#include <stderror.mqh>
#include <stdlib.mqh>
#property copyright "Copyright 2023, MetaQuotes Ltd."
#property link "https://www.mql5.com"
#property version "1.00"
#property strict
// config parameters
double initialDistance = 3; // Initial distance for the first order
double orderInterval = 0.5; // Distance between orders in points
int orderCount = 20; // Number of orders to place on each side
double stopLossDistance = 0.5; // Stop loss distance in points
double takeProfitDistance = 0.5; // Take profit distance in points
double Lots = 0.01; // Lot size for orders
int expirationMinutes = 1000; // Expiration time for orders in minutes
double stdThreshold = 0.5; // Standard deviation threshold for placing orders
int stdTicksNumbers = 200;
int removeOrderTime = 180; // seconds
int waitForOrderTime = 180; // seconds
datetime lastOrderOpenTime = 0;
// global variables
double tickPrices[];
int tickCounts = 0;
int OnInit()
{
// create zero array for tickPrices
ArraySetAsSeries(tickPrices, true);
ArrayResize(tickPrices, stdTicksNumbers);
ArraySetAsSeries(tickPrices, false);
ArrayInitialize(tickPrices, 0.0);
return(INIT_SUCCEEDED);
}
void OnDeinit(const int reason)
{
}
void PrintArray(const double &array[])
{
string arrayString = "";
int arraySize = ArraySize(array);
for (int i = 0; i < arraySize; i++)
arrayString += DoubleToString(array[i], 5) + " ";
Print(arrayString);
}
double getAverage(const int _period)
{
double sum = 0.0;
for (int i = 0; i < _period; i++)
sum += iClose(NULL, 0, i);
return sum / _period;
}
void PlaceOrders()
{
double currentPrice = SymbolInfoDouble(_Symbol, SYMBOL_BID);
// Calculate the distance for the first order
double firstOrderDistance = initialDistance;
for (int i = 0; i < orderCount; i++)
{
// Calculate expiration time
datetime expirationTime = iTime(NULL, 0, 0) + expirationMinutes * 60;
// Place Buy Orders1
double orderPrice = currentPrice + firstOrderDistance;
double tp = orderPrice + takeProfitDistance;
double sl = orderPrice - stopLossDistance;
int result = OrderSend(_Symbol, OP_BUYSTOP, Lots, orderPrice , 10, sl, tp, "Buy Order", 0, expirationTime, clrGreen);
if (result > 0){
Print("Buy order placed. Ticket: ", result);
}
else{
int error = GetLastError();
string errorDescription = ErrorDescription(error);
Print("OrderSend failed with error #", error, ": ", errorDescription);
}
orderPrice = currentPrice - firstOrderDistance;
tp = orderPrice - takeProfitDistance;
sl = orderPrice + stopLossDistance;
result = OrderSend(_Symbol, OP_SELLSTOP, Lots, orderPrice , 10, sl, tp , "Sell Order", 0, expirationTime, clrRed);
if (result > 0){
Print("Buy order placed. Ticket: ", result);
}
else{
int error = GetLastError();
string errorDescription = ErrorDescription(error);
Print("OrderSend failed with error #", error, ": ", errorDescription);
}
// Increment distance for subsequent orders
firstOrderDistance += orderInterval;
}
}
double getStdTicks()
{
if (tickCounts < stdTicksNumbers )
return stdThreshold + 1;
// Calculate mean
double mean = 0.0;
for (int i = 0; i < stdTicksNumbers ; i++)
mean += tickPrices[i];
mean /= stdTicksNumbers ;
// Calculate sum of squared differences
double ss = 0.0;
for (int i = 0; i < stdTicksNumbers ; i++)
{
double tickPrice = tickPrices[i];
ss += MathPow(tickPrice - mean, 2);
}
return MathSqrt(ss / stdTicksNumbers );
}
void updateTickData()
{
tickCounts ++;
// shift
for(int i = stdTicksNumbers - 1; i > 0; i--)
tickPrices[i] = tickPrices[i-1];
tickPrices[0] = (Bid + Ask) / 2.0;
}
void CheckAndRemovePendingOrders()
{
int totalOrders = OrdersTotal();
for (int i = 0; i < totalOrders; i++)
{
if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES)==false){
Print("ERROR - Unable to select the order - ", GetLastError());
continue;
}
// check time
int type = OrderType();
if (type != OP_BUYSTOP && type != OP_SELLSTOP)
continue;
// Check if the order hasn't been opened yet
if (OrderSymbol() == _Symbol && OrderMagicNumber() ==0)
{
datetime orderOpenTime = OrderOpenTime();
datetime currentTime = iTime(NULL, 0, 0);
// Calculate the time difference in seconds
int timeDifference = currentTime - orderOpenTime;
// If the order's pending time exceeds 3 minutes (180 seconds), remove the order
if (timeDifference > removeOrderTime )
{
bool deleteResult = OrderDelete(OrderTicket());
if (deleteResult)
{
Print("Pending order removed. Ticket: ", OrderTicket());
}
else
{
int error = GetLastError();
string errorDescription = ErrorDescription(error);
Print("OrderDelete failed with error #", error, ": ", errorDescription);
}
}
}
}
}
void OnTick()
{
updateTickData();
double mean = getAverage(10); // average per minute
double std = getStdTicks(); // std per ticks
CheckAndRemovePendingOrders();
datetime currentTime = iTime(NULL, 0, 0);
int timeDifferenceSinceLastOrder = currentTime - lastOrderOpenTime;
if (timeDifferenceSinceLastOrder > waitForOrderTime || lastOrderOpenTime == 0) // 120 seconds = 2 minutes
{
// Additional condition: if std is below the threshold, place orders
Print(std);
if (std < stdThreshold)
{
PlaceOrders();
lastOrderOpenTime = iTime(NULL, 0, 0); // Update the last order open time
}
}
}
Binary file not shown.
File diff suppressed because it is too large Load Diff
Binary file not shown.
+28
View File
@@ -0,0 +1,28 @@
//+------------------------------------------------------------------+
//| EA31337 - multi-strategy advanced trading robot. |
//| Copyright 2016-2023, EA31337 Ltd |
//| https://ea31337.github.io/ |
//+------------------------------------------------------------------+
// Main code.
#include "EA31337.mq5"
// EA indicator resources.
#ifdef __resource__
// Indicator resources.
// #resource INDI_ATR_MA_TREND_PATH + MQL_EXT // @todo: Not supported in MT4.
#resource INDI_EWO_OSC_PATH + MQL_EXT
#resource INDI_SVEBB_PATH + MQL_EXT
#resource INDI_TMA_CG_PATH + MQL_EXT
#resource INDI_TMA_TRUE_PATH + MQL_EXT
#resource INDI_SAWA_PATH + MQL_EXT
// #resource INDI_SUPERTREND_PATH + MQL_EXT // @todo: Not supported in MT4.
// Strategy resources (MQL4 workaround).
string MetaNewsData2018 = "";
string MetaNewsData2019 = "";
string MetaNewsData2020 = "";
string MetaNewsData2021 = "";
string MetaNewsData2022 = "";
string MetaNewsData2023 = "";
string MetaNewsData2024 = "";
#endif
Binary file not shown.
+373
View File
@@ -0,0 +1,373 @@
#property version "1.20";
#include <Trade\PositionInfo.mqh>;
#include <Trade\Trade.mqh>;
CPositionInfo position;
CTrade ctrade;
#define HR0800 28800
#define HR0830 30600
#define HR1300 46800
#define HR1330 48600
#define HR1900 68400
#define HR2400 86400
#define SECONDS uint
// settings
input string RISK_MANAGEMENT_SETTINGS;
input double lot_size;
input int bars_look_back;
input bool one_trade_per_session;
// global variables
ulong orderTicket = OrderGetTicket(1);
double shortFirstBarLow;
double shortFirstBarHigh;
double shortThirdBarHigh;
double shortThirdBarLow;
double longFirstBarLow;
double longFirstBarHigh;
double longThirdBarHigh;
double longThirdBarLow;
bool isShortEntry = false;
bool isLongEntry = false;
bool londonReset = false;
bool newYorkReset = false;
bool longReEntry = false;
bool shortReEntry = false;
int longImbalanceStorage;
int shortImbalanceStorage;
int longOrShort = 3;
datetime shortBeginningCandleTime;
datetime longBeginningCandleTime;
// returns the time in GMT in seconds
SECONDS time(datetime when = 0) {
return SECONDS(when == 0 ? TimeCurrent() : when) % HR2400;
}
datetime date(datetime when = 0) {
return datetime((when == 0 ? TimeCurrent() : when) - time(when));
}
bool isValidTime(SECONDS start, SECONDS end, datetime when = 0) {
SECONDS now = time(when);
return start < end ? start <= now && now < end : !isValidTime(end, start, when);
}
// returns true if it finds a short imbalance
bool isImbalanceShort(bool sa = false) {
// set the chart to 1 min to get precise entries
ChartSetSymbolPeriod(0, NULL, PERIOD_M1);
// store a reference to the first bar
shortBeginningCandleTime = TimeCurrent();
// store the high of the first bar
shortFirstBarLow = iLow(NULL, 0, 1);
shortFirstBarHigh = iHigh(NULL, 0, 1);
// store the low of the third bar
shortThirdBarHigh = iHigh(NULL, 0, 3);
return shortFirstBarLow > shortThirdBarHigh ? sa = true : sa = false;
}
// returns true if it finds a long imbalance
bool isImbalanceLong(bool la = false) {
// set the chart to 1 min to get precise entries
ChartSetSymbolPeriod(0, NULL, PERIOD_M1);
// store a reference to the first candle
longBeginningCandleTime = TimeCurrent();
// store the high of the first bar
longFirstBarHigh = iHigh(NULL, 0, 1);
// store the low of the third bar
longThirdBarLow = iLow(NULL, 0, 3);
return longFirstBarHigh < longThirdBarLow ? la = true : la = false;
}
// returns true or false if the short imbalance has been entered
bool isImbalanaceShortEntered(bool sb = false) {
// set the chart to 1 min to get precise entries
ChartSetSymbolPeriod(0, NULL, PERIOD_M1);
return iClose(NULL, 0, 1) > shortThirdBarLow && iClose(NULL, 0, 3) < shortFirstBarHigh ? sb = true : sb = false;
}
// returns true or false is the long imbalance has been entered
bool isImbalanceLongEntered(bool lb = false) {
// set the chart to 1 min to get precise entries
ChartSetSymbolPeriod(0, NULL, PERIOD_M1);
return iClose(NULL, 0, 1) < longThirdBarLow && iClose(NULL, 0, 3) > longFirstBarHigh ? lb = true : lb = false;
}
// returns true if there is a long imbalance (for use in a for loop)
bool initialLongImbalance(bool ik = false, int firstInt = 1, int secondInt = 1) {
return iHigh(NULL, 0, firstInt) < iLow(NULL, 0, secondInt) ? ik = true : ik = false;
}
// returns true if there is a short imbalance (for use in a for loop)
bool initialShortImbalance(bool on = false, int firstInt = 1, int secondInt = 1) {
return iLow(NULL, 0, firstInt) > iHigh(NULL, 0, secondInt) ? on = true : on = false;
}
// as there are no imbalances, it checks the close of the first candle of the more recently closed session to the first of the new one
bool alternateStrategyShort(bool ass = false) {
return iClose(NULL, 0, 12) > iClose(NULL, 0, 1) ? ass = true : ass = false;
}
// as there are no imbalances, it check the close of the first candle of the more recently closed session to the first of the new one
bool alternateStrategyLong(bool asl = false) {
return iClose(NULL, 0, 12) < iClose(NULL, 0, 1) ? asl = true : asl = false;
}
// creates a stop order
void stopOrderAction(int x, double tbl, double fbl, double tbh, double fbh)
{
// place a limit order at the first bar's low
MqlTradeRequest stopOrderRequest;
MqlTradeResult stopOrderResult;
stopOrderRequest.symbol = Symbol();
stopOrderRequest.order = orderTicket;
stopOrderRequest.volume = lot_size;
stopOrderRequest.deviation = 2;
stopOrderRequest.action = TRADE_ACTION_PENDING;
stopOrderRequest.type_filling = ENUM_ORDER_TYPE_FILLING::ORDER_FILLING_FOK;
if(x == 1) {
stopOrderRequest.price = tbl;
stopOrderRequest.type = ORDER_TYPE_BUY_STOP;
stopOrderRequest.sl = fbl + 5 * Point();
}
if(x == 2) {
stopOrderRequest.price = tbh;
stopOrderRequest.type = ORDER_TYPE_SELL_STOP;
stopOrderRequest.sl = fbh + 5 * Point();
}
// send the order with the inputs above
OrderSend(stopOrderRequest, stopOrderResult);
}
// makes order ticket for use in cancelling the stop order if it doesn't get triggered
void removeStopOrder()
{
MqlTradeRequest removeOrderRequest;
MqlTradeResult removeOrderResult;
removeOrderRequest.action = TRADE_ACTION_REMOVE;
removeOrderRequest.order = orderTicket;
OrderSend(removeOrderRequest, removeOrderResult);
}
// this function closes the current position
void closePosition()
{
if(position.Symbol()==Symbol()) {
ctrade.PositionClose(position.Ticket());
}
}
// this function finds the entry for both New York and London trades
void entry()
{
// go through each candle and see if there is an imbalance
for(int i = 12; i > 3; i--) {
int k = i - 2;
if(initialLongImbalance(false, i, k) == true) {
longImbalanceStorage = longImbalanceStorage + 1;
} else if(initialShortImbalance(false, i, k) == true) {
shortImbalanceStorage = shortImbalanceStorage + 1;
}
}
// check to make sure there are imbalances, and if not do a different calculation for the same bias thing
if((longImbalanceStorage == shortImbalanceStorage) || (longImbalanceStorage == 0 && shortImbalanceStorage == 0)) {
// do the check the first candle of the end of the last session to the one before the session now
if(alternateStrategyLong() == true) {
longImbalanceStorage = longImbalanceStorage + 1;
} else if (alternateStrategyShort() == true) {
shortImbalanceStorage = shortImbalanceStorage + 1;
}
}
// see if more short imbalances have been found and then find an entry in the opposite direction
if(longImbalanceStorage < shortImbalanceStorage) {
ChartSetSymbolPeriod(0, NULL, PERIOD_M5);
while(isValidTime(HR0800, HR0830) && isLongEntry == false) {
if(isImbalanceLong() == true && isImbalanceLongEntered() == true) {
printf("got an entry");
longOrShort = 1;
stopOrderAction(longOrShort, longThirdBarLow, longFirstBarLow, longThirdBarHigh, longFirstBarHigh);
isLongEntry = true;
}
}
} else if(longImbalanceStorage > shortImbalanceStorage) {
ChartSetSymbolPeriod(0, NULL, PERIOD_M5);
// see if more long imbalances have been found and then find an entry in the opposite direction
while(isValidTime(HR0800, HR0830) && isShortEntry == false) {
if(isImbalanceShort() == true && isImbalanaceShortEntered() == true) {
printf("got an entry");
longOrShort = 2;
stopOrderAction(longOrShort, shortThirdBarLow, shortFirstBarLow, shortThirdBarHigh, shortFirstBarHigh);
isShortEntry = true;
}
}
}
printf("reset variables");
// reset these variables
shortImbalanceStorage = 0;
longImbalanceStorage = 0;
londonReset = true;
newYorkReset = true;
}
void reEntryLong()
{
printf("if long entry");
// remove entry if price doesn't enter it within 6 bars
if(iBarShift(Symbol(), 0, longBeginningCandleTime, true) == 6) {
printf("cancelled order after time");
removeStopOrder();
isLongEntry = false;
}
if(iLow(NULL, 0, 1) > iHigh(NULL, 0, 3)) {
printf("went opposite direction");
closePosition();
if(one_trade_per_session == false) {
if(isImbalanceShort() == true && isImbalanaceShortEntered() == true) {
longBeginningCandleTime = TimeCurrent();
longOrShort = 2;
stopOrderAction(longOrShort, shortThirdBarLow, shortFirstBarLow, shortThirdBarHigh, shortFirstBarLow);
longReEntry = true;
}
} else {
isLongEntry = false;
}
}
}
void reEntryShort()
{
printf("if short entry");
if(iBarShift(Symbol(), 0, shortBeginningCandleTime, true) == 6) {
removeStopOrder();
isShortEntry = false;
}
// finds an imbalance in the opposing direction
if(iHigh(NULL, 0, 1) < iLow(NULL, 0, 3)) {
closePosition();
if(one_trade_per_session == false) {
if(isImbalanceLong() == true && isImbalanceLongEntered() == true) {
shortBeginningCandleTime = TimeCurrent();
longOrShort = 1;
stopOrderAction(longOrShort, shortThirdBarLow, shortFirstBarLow, shortThirdBarHigh, shortFirstBarLow);
shortReEntry = true;
}
} else {
isShortEntry = false;
}
}
}
void OnInit()
{
// sets the timeframe to the 5 minute
ChartSetSymbolPeriod(0, NULL, PERIOD_M5);
}
void OnTick()
{
// when it approcahes london session, it can start to find an entry
if(isValidTime(HR0800, HR0830) && londonReset == false) {
closePosition();
entry();
newYorkReset = false;
}
// when it approaches new york session, it can start to find an entry
if(isValidTime(HR1300, HR1330) && newYorkReset == false) {
printf("in new york session");
closePosition();
entry();
londonReset = false;
}
// finds when a long trade has been opened in the London session and it manages stop loss and what to do if prices reverse
if(isLongEntry == true && isValidTime(HR0800, HR1300)) {
reEntryLong();
if(longReEntry == true) {
if(iBarShift(Symbol(), 0, longBeginningCandleTime, true) == 6) {
removeStopOrder();
isLongEntry = false;
}
}
ChartSetSymbolPeriod(0, NULL, PERIOD_M5);
// finds an imbalance in the opposing direction
if(iLow(NULL, 0, 1) > iHigh(NULL, 0, 3)) {
closePosition();
longReEntry = false;
}
}
// finds when a long trade has been opened in the New York session and it manages stop loss and what to do if prices reverse
if(isLongEntry == true && isValidTime(HR1300, HR1900)) {
reEntryLong();
if(longReEntry == true) {
if(iBarShift(Symbol(), 0, longBeginningCandleTime, true) == 6) {
removeStopOrder();
isLongEntry = false;
}
}
ChartSetSymbolPeriod(0, NULL, PERIOD_M5);
// finds an imbalance in the opposing direction
if(iLow(NULL, 0, 1) > iHigh(NULL, 0, 3)) {
closePosition();
longReEntry = false;
}
}
// finds when a short trade in London session has been opened and it manages stop loss and what to do if prices reverse
if(isShortEntry == true && isValidTime(HR0800, HR1300)) {
reEntryShort();
if(shortReEntry == true) {
if(iBarShift(Symbol(), 0, shortBeginningCandleTime, true) == 6) {
removeStopOrder();
isShortEntry = false;
}
}
// finds an imbalance in the opposing direction
if(iHigh(NULL, 0, 1) < iLow(NULL, 0, 3)) {
closePosition();
shortReEntry = false;
}
}
// finds when a short trade in New York session has been opened and it manages stop loss and what to do if prices reverse
if(isShortEntry == true && isValidTime(HR1300, HR1900)) {
reEntryShort();
if(shortReEntry == true) {
if(iBarShift(Symbol(), 0, shortBeginningCandleTime, true) == 6) {
removeStopOrder();
isShortEntry = false;
}
}
// finds an imbalance in the opposing direction
if(iHigh(NULL, 0, 1) < iLow(NULL, 0, 3)) {
closePosition();
shortReEntry = false;
}
}
}
// remove stop order and any open postions just in case
void OnDeinit(const int reason)
{
removeStopOrder();
closePosition();
}
Binary file not shown.
+769
View File
@@ -0,0 +1,769 @@
//+------------------------------------------------------------------+
//| FxChartAI OpenEA |
//| Copyright 2025, FxChartAI |
//| https://www.fxchartai.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2025, FxChartAI"
#property link "https://www.fxchartai.com"
#property version "1.1.0"
#include <Files\File.mqh>
#include <JAson.mqh> // JSON parser library per https://www.mql5.com/en/articles/14108
//--- Input Parameters
input double LotSize = 1; // Risk management: Position size
input int StopLossPips = 400; // Stop loss in pips
input int TakeProfitPips = 500; // Take profit in pips
input int ConfidenceLevel = 5; // Minimum confidence level required (1-5)
input int MaxDataSize = 7; // Maximum dataset size for analysis
input int OperationMode = 0; // 0 = Test (CSV), 1 = Live (API)
input int MaxRetryAttempts = 9; // Maximum data loading retry attempts
input int MagicNumber = 12345;
input int TrailingPips = 50;
#define RETRY_DELAY_MS 60000 // 1 minute delay between retries
//--- Constants
enum SIGNAL_POSITION { SIGNAL_SELL, SIGNAL_BUY, SIGNAL_NONE };
enum TREND_WEIGHT { TREND_HIGH, TREND_LOW, TREND_NONE };
//--- Global variables
string m10FileName = "signal_dataset_" + _Symbol + "_m10.csv";
string h1FileName = "signal_dataset_" + _Symbol + "_h1.csv";
datetime lastM10UpdateTime = 0;
datetime lastH1UpdateTime = 0;
int pendingOrderTicket = -1;
//--- SignalData structure
struct SignalData
{
datetime time;
SIGNAL_POSITION position;
TREND_WEIGHT weight;
};
//--- Global arrays for signal data (declared externally, e.g., in a header)
SignalData m10Data[];
int m10DataIndex = 0;
SignalData h1Data[];
int h1DataIndex = 0;
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
if(OperationMode != 0 && OperationMode != 1)
{ Print("Invalid OperationMode value"); return(INIT_FAILED); }
if(MaxRetryAttempts < 1 || MaxRetryAttempts > _Period)
{ Print("Invalid MaxRetryAttempts value"); return(INIT_FAILED); }
if(MaxDataSize < 1)
{ Print("Invalid MaxDataSize value"); return(INIT_FAILED); }
if(ConfidenceLevel < 1)
{ Print("Invalid ConfidenceLevel value"); return(INIT_FAILED); }
if(TakeProfitPips < 1)
{ Print("Invalid TakeProfitPips value"); return(INIT_FAILED); }
if(StopLossPips < 1)
{ Print("Invalid StopLossPips value"); return(INIT_FAILED); }
if(LotSize < 0)
{ Print("Invalid LotSize value"); return(INIT_FAILED); }
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick()
{
static datetime prevM10Bar = 0;
static datetime prevH1Bar = 0;
if(_Period == PERIOD_M10)
{
datetime currentM10Bar = iTime(_Symbol, PERIOD_M10, 1);
if(currentM10Bar != prevM10Bar)
{
prevM10Bar = currentM10Bar;
ProcessTimeframe(PERIOD_M10, m10FileName, m10Data, m10DataIndex, lastM10UpdateTime);
}
}
else
if(_Period == PERIOD_H1)
{
datetime currentH1Bar = iTime(_Symbol, PERIOD_H1, 1);
if(currentH1Bar != prevH1Bar)
{
prevH1Bar = currentH1Bar;
ProcessTimeframe(PERIOD_H1, h1FileName, h1Data, h1DataIndex, lastH1UpdateTime);
}
}
}
//+------------------------------------------------------------------+
//| Process timeframe data |
//+------------------------------------------------------------------+
void ProcessTimeframe(ENUM_TIMEFRAMES tf, string filename, SignalData &data[], int &dataIndex, datetime &lastUpdate)
{
datetime currentTime = iTime(_Symbol, tf, 1);
bool result = false;
for(int attempt = 0; attempt < MaxRetryAttempts; attempt++)
{
if(OperationMode == 0 && LoadCSVData(filename, data, dataIndex, lastUpdate, currentTime))
{
result = true;
break;
}
else
if(OperationMode == 1 && LoadAPIRequest(data, dataIndex, lastUpdate, currentTime, tf))
{
result = true;
break;
}
if(attempt < MaxRetryAttempts - 1)
{
Print("Load ", (OperationMode == 0 ? "test" : "live"), " data failed, retrying in 1 minute... Attempt ", attempt + 1, "/", MaxRetryAttempts);
Sleep(RETRY_DELAY_MS);
}
}
if(result)
{
lastUpdate = currentTime;
AnalyzeAndTrade(tf, data);
ManageOpenOrders(tf);
}
else
{
Print("Failed to load ", (OperationMode == 0 ? "test" : "live"), " data after ", MaxRetryAttempts, " attempts");
}
}
//+------------------------------------------------------------------+
//| Load CSV data using circular buffer |
//+------------------------------------------------------------------+
bool LoadCSVData(string filePath, SignalData &data[], int &index, datetime &lastUpdate, datetime currentTime)
{
int handle = FileOpen(filePath, FILE_READ|FILE_CSV|FILE_ANSI, '\n');
if(handle == INVALID_HANDLE)
{
Print("Unable to load file");
return false;
}
Print("Reading file");
bool updated = false;
while(!FileIsEnding(handle))
{
string line = FileReadString(handle);
StringReplace(line, "\r", "");
string parts[];
if(StringSplit(line, ',', parts) == 3)
{
datetime dt = StringToTime(parts[0]);
if(dt > lastUpdate && dt <= currentTime)
{
Print("Data found for ", currentTime);
SignalData newData;
newData.time = dt;
newData.position = (SIGNAL_POSITION)StringToInteger(parts[1]);
newData.weight = (TREND_WEIGHT)StringToInteger(parts[2]);
// Update circular buffer
int size = ArraySize(data);
if(size < MaxDataSize)
ArrayResize(data, size + 1);
for(int x = size - 1; x > 0; x--)
data[x] = data[x - 1];
data[0] = newData;
updated = true;
}
}
}
Print("Done read csv");
FileClose(handle);
return updated;
}
//+------------------------------------------------------------------+
//| Function: LoadAPIRequest |
//| Description: Calls FxChartAI API via GET and parses the JSON |
//| response into an array of SignalData. |
//+------------------------------------------------------------------+
bool LoadAPIRequest(SignalData &data[], int &index, datetime &lastUpdate, datetime currentTime, ENUM_TIMEFRAMES timeframe)
{
// Convert timeframe to string representation
string tfString;
switch(timeframe)
{
case PERIOD_M10:
tfString = "M10";
break;
case PERIOD_H1:
tfString = "H1";
break;
default:
tfString = "M10";
break;
}
// Construct API URL
string url = BuildAPIRequestURL(timeframe, currentTime);
// Send HTTP GET request
uchar result[];
string headers;
string requestMethod = "GET";
int timeout = 5000;
string resulthHeaders;
char postData[]; // GET request uses empty POST data
int response = WebRequest(requestMethod,url, headers, timeout, postData, result, resulthHeaders);
Print(CharArrayToString(result));
if(response != 200)
{
Print("API request failed with error: ", GetLastError());
return false;
}
// Parse JSON response
CJAVal parser;
string jsonStr = CharArrayToString(result);
if(!parser.Deserialize(jsonStr))
{
Print("Failed to parse JSON response");
return false;
}
if(parser.m_type != jtARRAY)
{
Print("Invalid JSON structure received");
return false;
}
bool dataUpdated = false;
// Process array in reverse chronological order
for(int i = parser.Size() - 1; i >= 0; i--)
{
CJAVal *item = parser[i];
// Parse trade date
string dateStr = item["tradedate"].ToStr();
StringReplace(dateStr, "-", ".");
Print(dateStr);
datetime tradeDate = StringToTime(dateStr);
if(tradeDate <= lastUpdate)
continue;
// Create new signal data entry
SignalData newData;
newData.time = tradeDate;
newData.position = (SIGNAL_POSITION)item["position"].ToInt();
newData.weight = (TREND_WEIGHT)item["weight"].ToInt();
// Update data array with new entry
int size = ArraySize(data);
if(size < MaxDataSize)
ArrayResize(data, size + 1);
// Shift existing elements
for(int j = size - 1; j > 0; j--)
data[j] = data[j - 1];
data[0] = newData;
lastUpdate = tradeDate;
dataUpdated = true;
}
// Maintain maximum data size
if(ArraySize(data) > MaxDataSize)
ArrayResize(data, MaxDataSize);
if(ArraySize(data) > 0)
Print("Index0: "+data[0].time);
return dataUpdated;
}
//+------------------------------------------------------------------+
//| Build API Request URL |
//+------------------------------------------------------------------+
string BuildAPIRequestURL(ENUM_TIMEFRAMES tf, datetime time)
{
string timeframeStr = (tf == PERIOD_M10) ? "M10" : "H1";
string formattedTime = TimeToString(time, TIME_DATE) + "T" +
TimeToString(time, TIME_MINUTES);
return StringFormat(
"https://chartapi.fxchartai.com/easignal?currencypair=%s&size=%d&tradedate=%s&timeframe=%s",
_Symbol, MaxDataSize, formattedTime, timeframeStr
);
}
//+------------------------------------------------------------------+
//| Trend confirmation check |
//+------------------------------------------------------------------+
bool IsTrendConfirmed(const SignalData &data[], int requiredConsecutive, SIGNAL_POSITION &result)
{
int count = 0;
SIGNAL_POSITION lastSignal = SIGNAL_NONE;
for(int i = 0; i < ArraySize(data); i++)
{
if(data[i].position == SIGNAL_NONE)
continue;
if(data[i].position == lastSignal)
{
if(++count >= requiredConsecutive)
{
result = data[i].position;
return true;
}
}
else
{
count = 1;
lastSignal = data[i].position;
}
}
return false;
}
//+------------------------------------------------------------------+
//| Order management |
//+------------------------------------------------------------------+
void DeletePendingOrders()
{
for(int i = OrdersTotal()-1; i >= 0; i--)
{
ulong ticket = OrderGetTicket(i);
if(ticket <= 0)
continue;
if(OrderGetInteger(ORDER_MAGIC) == MagicNumber &&
(OrderGetInteger(ORDER_TYPE) == ORDER_TYPE_BUY_STOP ||
OrderGetInteger(ORDER_TYPE) == ORDER_TYPE_SELL_STOP))
{
MqlTradeRequest req = {};
MqlTradeResult res = {};
req.action = TRADE_ACTION_REMOVE;
req.order = ticket;
OrderSend(req, res);
}
}
pendingOrderTicket = -1;
}
//+------------------------------------------------------------------+
//| Candle tail signal detection |
//+------------------------------------------------------------------+
SIGNAL_POSITION GetCandleTailSignal(ENUM_TIMEFRAMES tf)
{
double open = iOpen(_Symbol, tf, 1);
double close = iClose(_Symbol, tf, 1);
double high = iHigh(_Symbol, tf, 1);
double low = iLow(_Symbol, tf, 1);
if(close > open) // Bullish
{
double upperTail = high - close;
double lowerTail = open - low;
return (upperTail > lowerTail*2) ? SIGNAL_SELL :
(lowerTail > upperTail*2) ? SIGNAL_BUY : SIGNAL_NONE;
}
// Bearish
double upperTail = high - open;
double lowerTail = close - low;
return (upperTail > lowerTail*2) ? SIGNAL_SELL :
(lowerTail > upperTail*2) ? SIGNAL_BUY : SIGNAL_NONE;
}
//+------------------------------------------------------------------+
//| Trendline check |
//+------------------------------------------------------------------+
bool CheckTrendline(ENUM_TIMEFRAMES tf, bool bullish)
{
double price = bullish ? iLow(_Symbol, tf, 1) : iHigh(_Symbol, tf, 1);
datetime time = iTime(_Symbol, tf, 1);
int touches = 0;
for(int i = 2; i <= 20; i++)
{
double testPrice = bullish ? iLow(_Symbol, tf, i) : iHigh(_Symbol, tf, i);
datetime testTime = iTime(_Symbol, tf, i);
if((bullish && testPrice <= price) || (!bullish && testPrice >= price))
{
if(++touches >= 2)
return true;
}
else
if(iTime(_Symbol, tf, i) < time)
break;
}
return false;
}
//+------------------------------------------------------------------+
//| Execute trade |
//+------------------------------------------------------------------+
void ExecuteTrade(SIGNAL_POSITION signal, ENUM_TIMEFRAMES tf)
{
DeletePendingOrders();
double price = (signal == SIGNAL_BUY) ? SymbolInfoDouble(_Symbol, SYMBOL_ASK)
: SymbolInfoDouble(_Symbol, SYMBOL_BID);
double sl = StopLossPips * _Point * ((tf == PERIOD_H1) ? 10 : 1);
double tp = TakeProfitPips * _Point * ((tf == PERIOD_H1) ? 10 : 1);
MqlTradeRequest req = {};
MqlTradeResult res = {};
req.action = TRADE_ACTION_PENDING;
req.symbol = _Symbol;
req.volume = LotSize;
req.type = (signal == SIGNAL_BUY) ? ORDER_TYPE_BUY_STOP : ORDER_TYPE_SELL_STOP;
req.price = price + ((signal == SIGNAL_BUY) ? 100*_Point : -100*_Point);
req.sl = (signal == SIGNAL_BUY) ? req.price - sl : req.price + sl;
req.tp = (signal == SIGNAL_BUY) ? req.price + tp : req.price - tp;
req.magic = MagicNumber;
if(OrderSend(req, res))
pendingOrderTicket = res.order;
}
//+------------------------------------------------------------------+
//| Main trading logic |
//+------------------------------------------------------------------+
void AnalyzeAndTrade(ENUM_TIMEFRAMES tf, const SignalData &data[])
{
if(PositionsTotal() > 0)
return;
SIGNAL_POSITION trendSignal;
if(IsTrendConfirmed(data,ConfidenceLevel, trendSignal))
{
SIGNAL_POSITION candleSignal = GetCandleTailSignal(tf);
if(candleSignal == trendSignal)
ExecuteTrade(trendSignal, tf);
}
}
//+------------------------------------------------------------------+
//| Manage Open Positions |
//+------------------------------------------------------------------+
void ManageOpenOrders(ENUM_TIMEFRAMES timeframe)
{
// Process market positions
for(int i = PositionsTotal() - 1; i >= 0; i--)
{
ulong ticket = PositionGetTicket(i);
if(ticket > 0)
{
if(PositionGetInteger(POSITION_MAGIC) == MagicNumber)
{
string symbol = PositionGetString(POSITION_SYMBOL);
ENUM_POSITION_TYPE posType = (ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);
double openPrice = PositionGetDouble(POSITION_PRICE_OPEN);
double sl = PositionGetDouble(POSITION_SL);
double tp = PositionGetDouble(POSITION_TP);
double volume = PositionGetDouble(POSITION_VOLUME);
double currentPrice = (posType == POSITION_TYPE_BUY) ?
SymbolInfoDouble(symbol, SYMBOL_BID) :
SymbolInfoDouble(symbol, SYMBOL_ASK);
// Check for TP/SL hit
if((posType == POSITION_TYPE_BUY && currentPrice >= tp) ||
(posType == POSITION_TYPE_SELL && currentPrice <= tp))
{
ClosePosition(ticket);
}
else
if((posType == POSITION_TYPE_BUY && currentPrice <= sl) ||
(posType == POSITION_TYPE_SELL && currentPrice >= sl))
{
ClosePosition(ticket);
}
else
{
// Trailing stop logic
UpdateTrailingStop(ticket, posType, currentPrice, timeframe);
}
}
}
}
// Process pending orders
for(int i = OrdersTotal() - 1; i >= 0; i--)
{
ulong orderTicket = OrderGetTicket(i);
if(orderTicket > 0 && OrderGetInteger(ORDER_MAGIC) == MagicNumber)
{
CheckPendingOrderExpiry(orderTicket, timeframe);
}
}
}
//+------------------------------------------------------------------+
//| Close position |
//+------------------------------------------------------------------+
bool ClosePosition(ulong ticket)
{
MqlTradeRequest request = {};
MqlTradeResult result = {};
request.action = TRADE_ACTION_DEAL;
request.position = ticket;
request.symbol = PositionGetString(POSITION_SYMBOL);
request.volume = PositionGetDouble(POSITION_VOLUME);
request.deviation = 5;
request.type = (ENUM_ORDER_TYPE)(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY) ? ORDER_TYPE_SELL : ORDER_TYPE_BUY;
request.price = (request.type == ORDER_TYPE_BUY) ?
SymbolInfoDouble(request.symbol, SYMBOL_ASK) :
SymbolInfoDouble(request.symbol, SYMBOL_BID);
if(OrderSend(request, result))
{
Print("Position closed: ", ticket);
return true;
}
else
{
Print("Error closing position: ", GetLastError());
return false;
}
}
//+------------------------------------------------------------------+
//| Perforrm Minor Trailing stop |
//+------------------------------------------------------------------+
bool performMinorTrail(ulong ticket, ENUM_POSITION_TYPE posType, double priceOpen, double currentSl, int trailingPips, ENUM_TIMEFRAMES timeframe)
{
MqlTradeRequest request = {};
MqlTradeResult result = {};
double newSl = 0.0;
if(posType == POSITION_TYPE_BUY)
{
newSl = priceOpen + trailingPips * _Point;
if(newSl > currentSl)
{
request.action = TRADE_ACTION_SLTP;
request.position = ticket;
request.symbol = PositionGetString(POSITION_SYMBOL);
request.sl = newSl;
request.tp = PositionGetDouble(POSITION_TP);
if(OrderSend(request, result))
{
Print("Minor trailing stop updated for buy position");
return true;
}
}
}
else
{
newSl = priceOpen - trailingPips * _Point;
if(newSl < currentSl || currentSl == 0)
{
request.action = TRADE_ACTION_SLTP;
request.position = ticket;
request.symbol = PositionGetString(POSITION_SYMBOL);
request.sl = newSl;
request.tp = PositionGetDouble(POSITION_TP);
if(OrderSend(request, result))
{
Print("Minor trailing stop updated for sell position");
return true;
}
}
}
return false;
}
//+------------------------------------------------------------------+
//| Perforrm Major Trailing stop |
//+------------------------------------------------------------------+
bool performMajorTrail(ulong ticket, ENUM_POSITION_TYPE posType, double currentPrice, double lastCandleSize, double currentSl, int trailingPips, ENUM_TIMEFRAMES timeframe)
{
MqlTradeRequest request = {};
MqlTradeResult result = {};
double newSl = 0.0;
double newTrailSL = 0.0;
if(posType == POSITION_TYPE_BUY)
{
newSl = currentPrice - lastCandleSize;
newTrailSL = currentPrice - trailingPips * _Point;
newSl = (newSl < newTrailSL) ? newTrailSL : newSl;
if(newSl > currentSl)
{
request.action = TRADE_ACTION_SLTP;
request.position = ticket;
request.symbol = PositionGetString(POSITION_SYMBOL);
request.sl = newSl;
request.tp = PositionGetDouble(POSITION_TP);
if(OrderSend(request, result))
{
Print("Major trailing stop updated for buy position");
return true;
}
else
{
Print("Failed: Major trailing stop for buy position");
}
}
}
else
{
newSl = currentPrice + lastCandleSize;
newTrailSL = currentPrice + trailingPips * _Point;
newSl = (newSl > newTrailSL) ? newTrailSL : newSl;
if(newSl < currentSl || currentSl == 0)
{
request.action = TRADE_ACTION_SLTP;
request.position = ticket;
request.symbol = PositionGetString(POSITION_SYMBOL);
request.sl = newSl;
request.tp = PositionGetDouble(POSITION_TP);
if(OrderSend(request, result))
{
Print("Major trailing stop updated for sell position");
return true;
}
else
{
Print("Failed: Major trailing stop for sell position");
}
}
}
return false;
}
//+------------------------------------------------------------------+
//| Update Trailing stop |
//+------------------------------------------------------------------+
void UpdateTrailingStop(ulong ticket, ENUM_POSITION_TYPE posType, double currentPrice, ENUM_TIMEFRAMES timeframe)
{
double currentSl = PositionGetDouble(POSITION_SL);
double priceOpen = PositionGetDouble(POSITION_PRICE_OPEN);
double currentProfit = PositionGetDouble(POSITION_PROFIT);
double lastCandleHigh = iHigh(Symbol(), timeframe, 1);
double lastCandleLow = iLow(Symbol(), timeframe, 1);
double lastCandleSize = MathAbs(lastCandleHigh - lastCandleLow);
int candlesOpen = (int)((TimeCurrent() - PositionGetInteger(POSITION_TIME)) / PeriodSeconds(timeframe));
if(candlesOpen > 1 && candlesOpen <= 3 && currentProfit > 0)
{
performMinorTrail(ticket, posType, priceOpen, currentSl, TrailingPips, timeframe);
}
else
if(candlesOpen >= 4 && currentProfit > 0)
{
performMajorTrail(ticket, posType, currentPrice, lastCandleSize, currentSl, TrailingPips, timeframe);
}
}
//+------------------------------------------------------------------+
//| Modify pending order |
//+------------------------------------------------------------------+
bool ModifyPendingOrder(ulong ticket, double price, ENUM_TIMEFRAMES timeframe)
{
MqlTradeRequest request = {};
MqlTradeResult result = {};
if(OrderSelect(ticket))
{
double stopLoss = (timeframe == PERIOD_M10) ? StopLossPips * _Point : StopLossPips * _Point * 10;
double takeProfit = (timeframe == PERIOD_M10) ? TakeProfitPips * _Point : TakeProfitPips * _Point * 10;
request.action = TRADE_ACTION_MODIFY;
request.order = ticket;
request.price = price;
request.sl = (OrderGetInteger(ORDER_TYPE) == ORDER_TYPE_BUY_STOP) ? price - stopLoss : price + stopLoss;
request.tp = (OrderGetInteger(ORDER_TYPE) == ORDER_TYPE_BUY_STOP) ? price + takeProfit : price - takeProfit;
request.deviation = 5;
if(OrderSend(request, result))
{
Print("Pending order modified successfully");
return true;
}
else
{
Print("ModifyPendingOrder::Error modifying orderrr: ", GetLastError());
return false;
}
}
else
{
Print("ModifyPendingOrder::order select failed for ticket"+ticket);
}
return false;
}
//+------------------------------------------------------------------+
//| Check and delete expired pending orders |
//+------------------------------------------------------------------+
void CheckPendingOrderExpiry(ulong ticket, ENUM_TIMEFRAMES timeframe)
{
datetime expiration = OrderGetInteger(ORDER_TIME_EXPIRATION);
if(expiration > 0 && expiration < TimeCurrent())
{
MqlTradeRequest request = {};
MqlTradeResult result = {};
request.action = TRADE_ACTION_REMOVE;
request.order = ticket;
if(OrderSend(request, result))
{
Print("Expired order removed: ", ticket);
}
else
{
Print("Error removing order: ", GetLastError());
}
}
}
//+------------------------------------------------------------------+
//| Place pending order |
//+------------------------------------------------------------------+
ulong PlacePendingOrder(ENUM_ORDER_TYPE orderType, double price, ENUM_TIMEFRAMES timeframe)
{
MqlTradeRequest request = {};
MqlTradeResult result = {};
double stopLoss = (timeframe == PERIOD_M10) ? StopLossPips * _Point : StopLossPips * _Point * 10;
double takeProfit = (timeframe == PERIOD_M10) ? TakeProfitPips * _Point : TakeProfitPips * _Point * 10;
request.action = TRADE_ACTION_PENDING;
request.symbol = _Symbol;
request.volume = LotSize;
request.type = orderType;
request.price = price;
request.sl = (orderType == ORDER_TYPE_BUY_STOP) ? price - stopLoss : price + stopLoss;
request.tp = (orderType == ORDER_TYPE_BUY_STOP) ? price + takeProfit : price - takeProfit;
request.deviation = 5;
request.magic = MagicNumber;
if(OrderSend(request, result))
{
Print("Pending order placed: ", result.order);
return result.order;
}
else
{
Print("Error placing order: ", GetLastError());
return 0;
}
}
//+------------------------------------------------------------------+
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,339 @@
//+------------------------------------------------------------------+
//| Mitigation Order Blocks EA.mq5 |
//| Copyright 2025, MetaQuotes Ltd. |
//| https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2025, MetaQuotes Ltd."
#property link "https://www.mql5.com"
#property version "1.00"
#include <Trade/Trade.mqh>
CTrade obj_Trade;
input double tradeLotSize = 0.01;
input bool enableTrading = true;
input bool enableTrailingStop = true;
input double trailingStopPoints = 30;
input double minProfitToTrail = 50;
input int uniqueMagicNumber = 1234567;
input int consolidationBars = 7;
input double maxconsolidationSpread = 50;
input int barstowaitafterbreakout = 3;
input double impulseMultiplier = 1.0;
input double stoplossDistance = 1500;
input double takeProfitdistance = 1500;
input color bullishOrderBlockColor = clrGreen;
input color bearishOrderBlockColor = clrRed;
input color mitigatedOrderBlockColor = clrGray;
input color labelTextColor = clrBlack;
struct PriceAndIndex{
double price;
int index;
};
PriceAndIndex rangeHighestHigh = {0,0};
PriceAndIndex rangeLowestLow = {0,0};
bool isBreakoutDetected = false;
double lastImpulseLow = 0.0;
double lastImpulseHigh = 0.0;
int breakoutBarNumber = -1;
datetime breakoutTimestamp = 0;
string orderBlockNames[];
string orderBlockLabels[];
datetime orderBlockEndTimes[];
bool orderblockMitigatedStatus[];
bool isBullishImpulse = false;
bool isBearishImpulse = false;
#define OB_Prefix "OB REC "
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int OnInit(){
//---
obj_Trade.SetExpertMagicNumber(uniqueMagicNumber);
//---
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Expert deinitialization function |
//+------------------------------------------------------------------+
void OnDeinit(const int reason){
//---
}
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick(){
//---
if (enableTrailingStop){
applyTrailingStop(trailingStopPoints,obj_Trade,uniqueMagicNumber);
}
static bool isNewBar = false;
int currentBarCount = iBars(_Symbol,_Period);
static int previousBarCount = currentBarCount;
if (previousBarCount == currentBarCount){
isNewBar = false;
}
else if (previousBarCount != currentBarCount){
isNewBar = true;
previousBarCount = currentBarCount;
}
if (!isNewBar){
return;
}
int startBarIndex = 1;
int chartscale = (int)ChartGetInteger(0,CHART_SCALE);
int dynamicFontSize = 8+(chartscale*2);
if (!isBreakoutDetected){
if (rangeHighestHigh.price == 0 && rangeLowestLow.price == 0){
bool isConsolidated = true;
for (int i=startBarIndex; i<startBarIndex+consolidationBars-1; i++){
if (MathAbs(high(i) - high(i+1)) > maxconsolidationSpread * _Point){
isConsolidated = false;
break;
}
if (MathAbs(low(i) - low(i+1)) > maxconsolidationSpread * _Point){
isConsolidated = false;
break;
}
}
if (isConsolidated){
rangeHighestHigh.price = high(startBarIndex);
rangeHighestHigh.index = startBarIndex;
for (int i=startBarIndex+1; i<startBarIndex+consolidationBars; i++){
if (high(i) > rangeHighestHigh.price){
rangeHighestHigh.price = high(i);
rangeHighestHigh.index = i;
}
}
rangeLowestLow.price = low(startBarIndex);
rangeLowestLow.index = startBarIndex;
for (int i=startBarIndex+1; i<startBarIndex+consolidationBars; i++){
if (low(i) < rangeLowestLow.price){
rangeLowestLow.price = low(i);
rangeLowestLow.index = i;
}
}
Print("Consolidation Range Established./nHighest High: ",rangeHighestHigh.price,
", Lowest Low: ",rangeLowestLow.price);
}
}
else {
double currentHigh = high(1);
double currentLow = low(1);
if (currentHigh <= rangeHighestHigh.price && currentLow >= rangeLowestLow.price){
Print("Range EXTENDED: High = ",currentHigh, ", Low = ",currentLow);
}
else {
Print("No extension: Bar outside range.");
}
}
}
if (rangeHighestHigh.price > 0 && rangeLowestLow.price > 0){
double currentClosePrice = close(1);
if (currentClosePrice > rangeHighestHigh.price){
Print("Upward Breakout at ",currentClosePrice, " > ",rangeHighestHigh.price);
isBreakoutDetected = true;
}
else if (currentClosePrice < rangeLowestLow.price){
Print("Downward Breakout at ",currentClosePrice, " < ",rangeLowestLow.price);
isBreakoutDetected = true;
}
}
if (isBreakoutDetected){
Print("Breakout detected. Resetting for the next range.");
breakoutBarNumber = 1;
breakoutTimestamp = TimeCurrent();
lastImpulseHigh = rangeHighestHigh.price;
lastImpulseLow = rangeLowestLow.price;
isBreakoutDetected = false;
rangeHighestHigh.price = 0;
rangeLowestLow.price = 0;
rangeHighestHigh.index = 0;
rangeLowestLow.index = 0;
}
if (breakoutBarNumber >= 0 && TimeCurrent() > breakoutTimestamp+barstowaitafterbreakout*PeriodSeconds()){
double impulseRange = lastImpulseHigh - lastImpulseLow;
double impulseThresholdPrice = impulseRange * impulseMultiplier;
isBullishImpulse = false;
isBearishImpulse = false;
for (int i=1; i<=barstowaitafterbreakout; i++){
double closePrice = close(i);
if (closePrice >= lastImpulseHigh+impulseThresholdPrice){
isBullishImpulse = true;
Print("Impulsive upward move: ",closePrice," >= ",lastImpulseHigh+impulseThresholdPrice);
break;
}
else if (closePrice <= lastImpulseLow-impulseThresholdPrice){
isBearishImpulse = true;
Print("Impulsive downward move: ",closePrice," <= ",lastImpulseLow-impulseThresholdPrice);
break;
}
}
if (!isBullishImpulse && !isBearishImpulse){
Print("No impulsive movement detected.");
}
bool isOrderBlockValid = isBearishImpulse || isBullishImpulse;
if (isOrderBlockValid){
datetime blockStartTime = iTime(_Symbol,_Period,consolidationBars+barstowaitafterbreakout+1);
double blockTopPrice = lastImpulseHigh;
int visibleBarsOnchart = (int)ChartGetInteger(0,CHART_VISIBLE_BARS);
datetime blockEndTime = blockStartTime+(visibleBarsOnchart/1)*PeriodSeconds();
double blockBottomPrice = lastImpulseLow;
string orderBlockName = OB_Prefix+"("+TimeToString(blockStartTime)+")";
color orderBlockColor = isBullishImpulse ? bullishOrderBlockColor : bearishOrderBlockColor;
string orderBlockLabel = isBullishImpulse ? "Bullish OB" : "Bearish OB";
if (ObjectFind(0, orderBlockName) < 0){
ObjectCreate(0,orderBlockName,OBJ_RECTANGLE,0,blockStartTime,blockTopPrice,blockEndTime,blockBottomPrice);
ObjectSetInteger(0,orderBlockName,OBJPROP_TIME,0,blockStartTime);
ObjectSetDouble(0,orderBlockName,OBJPROP_PRICE,0,blockTopPrice);
ObjectSetInteger(0,orderBlockName,OBJPROP_TIME,1,blockEndTime);
ObjectSetDouble(0,orderBlockName,OBJPROP_PRICE,1,blockBottomPrice);
ObjectSetInteger(0,orderBlockName,OBJPROP_FILL,true);
ObjectSetInteger(0,orderBlockName,OBJPROP_COLOR,orderBlockColor);
ObjectSetInteger(0,orderBlockName,OBJPROP_BACK,false);
datetime labelTime = blockStartTime + (blockEndTime-blockStartTime)/2;
double labelPrice = (blockTopPrice+blockBottomPrice)/2;
string labelObjectName = orderBlockName+orderBlockLabel;
if (ObjectFind(0,labelObjectName) < 0){
ObjectCreate(0,labelObjectName,OBJ_TEXT,0,labelTime,labelPrice);
ObjectSetString(0,labelObjectName,OBJPROP_TEXT,orderBlockLabel);
ObjectSetInteger(0,labelObjectName,OBJPROP_COLOR,labelTextColor);
ObjectSetInteger(0,labelObjectName,OBJPROP_ANCHOR,ANCHOR_CENTER);
ObjectSetInteger(0,labelObjectName,OBJPROP_FONTSIZE,dynamicFontSize);
}
ChartRedraw(0);
ArrayResize(orderBlockNames,ArraySize(orderBlockNames)+1);
orderBlockNames[ArraySize(orderBlockNames)-1] = orderBlockName;
ArrayResize(orderBlockLabels,ArraySize(orderBlockLabels)+1);
orderBlockLabels[ArraySize(orderBlockLabels)-1] = labelObjectName;
ArrayResize(orderBlockEndTimes,ArraySize(orderBlockEndTimes)+1);
orderBlockEndTimes[ArraySize(orderBlockEndTimes)-1] = blockEndTime;
ArrayResize(orderblockMitigatedStatus,ArraySize(orderblockMitigatedStatus)+1);
orderblockMitigatedStatus[ArraySize(orderblockMitigatedStatus)-1] = false;
Print("Order Block created: ",orderBlockName);
}
}
breakoutBarNumber = -1;
breakoutTimestamp = 0;
lastImpulseHigh = 0;
lastImpulseLow = 0;
isBullishImpulse = false;
isBearishImpulse = false;
}
for (int j=ArraySize(orderBlockNames)-1; j>=0; j--){
string currentOrderBlockName = orderBlockNames[j];
string currentOrderBlockLabel = orderBlockLabels[j];
bool doesOrderBlockExist = false;
double orderBlockHigh = ObjectGetDouble(0,currentOrderBlockName,OBJPROP_PRICE,0);
double orderBlockLow = ObjectGetDouble(0,currentOrderBlockName,OBJPROP_PRICE,1);
datetime orderBlockStartTime = (datetime)ObjectGetInteger(0,currentOrderBlockName,OBJPROP_TIME,0);
datetime orderBlockEndTime = (datetime)ObjectGetInteger(0,currentOrderBlockName,OBJPROP_TIME,1);
color orderBlockCurrentColor = (color)ObjectGetInteger(0,currentOrderBlockName,OBJPROP_COLOR);
if (time(1) < orderBlockEndTime){
doesOrderBlockExist = true;
}
double currentAskPrice = NormalizeDouble(SymbolInfoDouble(_Symbol,SYMBOL_ASK),_Digits);
double currentBidPrice = NormalizeDouble(SymbolInfoDouble(_Symbol,SYMBOL_BID),_Digits);
if (enableTrading && orderBlockCurrentColor == bullishOrderBlockColor && close(1) < orderBlockLow && !orderblockMitigatedStatus[j]){
double entryPrice = currentBidPrice;
double stoplossPrice = entryPrice+stoplossDistance*_Point;
double takeprofitPrice = entryPrice-takeProfitdistance*_Point;
obj_Trade.Sell(tradeLotSize,_Symbol,entryPrice,stoplossPrice,takeprofitPrice);
orderblockMitigatedStatus[j] = true;
ObjectSetInteger(0,currentOrderBlockName,OBJPROP_COLOR,mitigatedOrderBlockColor);
string blockDescription = "Bullish Order Block";
string textObjectName = currentOrderBlockName+blockDescription;
ObjectSetString(0,currentOrderBlockLabel,OBJPROP_TEXT,"Mitigated "+blockDescription);
Print("Sell trade entered upon mitigation of the bullish OB: ",currentOrderBlockName);
}
else if (enableTrading && orderBlockCurrentColor == bearishOrderBlockColor && close(1) > orderBlockHigh && !orderblockMitigatedStatus[j]){
double entryPrice = currentAskPrice;
double stoplossPrice = entryPrice-stoplossDistance*_Point;
double takeprofitPrice = entryPrice+takeProfitdistance*_Point;
obj_Trade.Buy(tradeLotSize,_Symbol,entryPrice,stoplossPrice,takeprofitPrice);
orderblockMitigatedStatus[j] = true;
ObjectSetInteger(0,currentOrderBlockName,OBJPROP_COLOR,mitigatedOrderBlockColor);
string blockDescription = "Bearish Order Block";
string textObjectName = currentOrderBlockName+blockDescription;
ObjectSetString(0,currentOrderBlockLabel,OBJPROP_TEXT,"Mitigated "+blockDescription);
Print("Buy trade entered upon mitigation of the bearish OB: ",currentOrderBlockName);
}
if (!doesOrderBlockExist){
bool removedName = ArrayRemove(orderBlockNames,j,1);
bool removedLabel = ArrayRemove(orderBlockLabels,j,1);
bool removedTime = ArrayRemove(orderBlockEndTimes,j,1);
bool removedStatus = ArrayRemove(orderblockMitigatedStatus,j,1);
if (removedName && removedTime && removedStatus && removedLabel){
Print("Success removing OB data from arrays at index ",j);
}
}
}
}
//+------------------------------------------------------------------+
double high (int index) {return iHigh(_Symbol,_Period,index);}
double low (int index) {return iLow(_Symbol,_Period,index);}
double open (int index) {return iOpen(_Symbol,_Period,index);}
double close (int index) {return iClose(_Symbol,_Period,index);}
datetime time (int index) {return iTime(_Symbol,_Period,index);}
void applyTrailingStop(double trailingPoints, CTrade &trade_object, int magicNo = 0){
double buyStopLoss = NormalizeDouble(SymbolInfoDouble(_Symbol,SYMBOL_BID)-trailingPoints*_Point,_Digits);
double sellStopLoss = NormalizeDouble(SymbolInfoDouble(_Symbol,SYMBOL_ASK)+trailingPoints*_Point,_Digits);
for (int i=PositionsTotal()-1; i>=0; i--){
ulong ticket = PositionGetTicket(i);
if (ticket > 0){
if (PositionSelectByTicket(ticket)){
if (PositionGetString(POSITION_SYMBOL)==_Symbol &&
(magicNo == 0 || PositionGetInteger(POSITION_MAGIC)==magicNo)
){
if (PositionGetInteger(POSITION_TYPE)==POSITION_TYPE_BUY &&
buyStopLoss > PositionGetDouble(POSITION_PRICE_OPEN) &&
(buyStopLoss > PositionGetDouble(POSITION_SL) || PositionGetDouble(POSITION_SL) == 0)
){
trade_object.PositionModify(ticket,buyStopLoss,PositionGetDouble(POSITION_TP));
}
else if (PositionGetInteger(POSITION_TYPE)==POSITION_TYPE_SELL &&
sellStopLoss < PositionGetDouble(POSITION_PRICE_OPEN) &&
(sellStopLoss < PositionGetDouble(POSITION_SL) || PositionGetDouble(POSITION_SL) == 0)
){
trade_object.PositionModify(ticket,sellStopLoss,PositionGetDouble(POSITION_TP));
}
}
}
}
}
}
+175
View File
@@ -0,0 +1,175 @@
//+------------------------------------------------------------------+
//| prueba.mq5 |
//| Copyright 2020, MetaQuotes Software Corp. |
//| https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2020, MetaQuotes Software Corp."
#property link "https://www.mql5.com"
#property version "1.00"
//+------------------------------------------------------------------+
//| Include |
//+------------------------------------------------------------------+
#include <Expert\Expert.mqh>
//--- available signals
#include <Expert\Signal\SignalMACD.mqh>
//--- available trailing
#include <Expert\Trailing\TrailingNone.mqh>
//--- available money management
#include <Expert\Money\MoneyFixedLot.mqh>
//+------------------------------------------------------------------+
//| Inputs |
//+------------------------------------------------------------------+
//--- inputs for expert
input string Expert_Title ="prueba"; // Document name
ulong Expert_MagicNumber =2727; //
bool Expert_EveryTick =false; //
//--- inputs for main signal
input int Signal_ThresholdOpen =10; // Signal threshold value to open [0...100]
input int Signal_ThresholdClose =10; // Signal threshold value to close [0...100]
input double Signal_PriceLevel =0.0; // Price level to execute a deal
input double Signal_StopLevel =50.0; // Stop Loss level (in points)
input double Signal_TakeLevel =50.0; // Take Profit level (in points)
input int Signal_Expiration =4; // Expiration of pending orders (in bars)
input int Signal_MACD_PeriodFast =12; // MACD(12,24,9,PRICE_CLOSE) Period of fast EMA
input int Signal_MACD_PeriodSlow =24; // MACD(12,24,9,PRICE_CLOSE) Period of slow EMA
input int Signal_MACD_PeriodSignal=9; // MACD(12,24,9,PRICE_CLOSE) Period of averaging of difference
input ENUM_APPLIED_PRICE Signal_MACD_Applied =PRICE_CLOSE; // MACD(12,24,9,PRICE_CLOSE) Prices series
input double Signal_MACD_Weight =1.0; // MACD(12,24,9,PRICE_CLOSE) Weight [0...1.0]
//--- inputs for money
input double Money_FixLot_Percent =10.0; // Percent
input double Money_FixLot_Lots =0.1; // Fixed volume
//+------------------------------------------------------------------+
//| Global expert object |
//+------------------------------------------------------------------+
CExpert ExtExpert;
//+------------------------------------------------------------------+
//| Initialization function of the expert |
//+------------------------------------------------------------------+
int OnInit()
{
//--- Initializing expert
if(!ExtExpert.Init(Symbol(),Period(),Expert_EveryTick,Expert_MagicNumber))
{
//--- failed
printf(__FUNCTION__+": error initializing expert");
ExtExpert.Deinit();
return(INIT_FAILED);
}
//--- Creating signal
CExpertSignal *signal=new CExpertSignal;
if(signal==NULL)
{
//--- failed
printf(__FUNCTION__+": error creating signal");
ExtExpert.Deinit();
return(INIT_FAILED);
}
//---
ExtExpert.InitSignal(signal);
signal.ThresholdOpen(Signal_ThresholdOpen);
signal.ThresholdClose(Signal_ThresholdClose);
signal.PriceLevel(Signal_PriceLevel);
signal.StopLevel(Signal_StopLevel);
signal.TakeLevel(Signal_TakeLevel);
signal.Expiration(Signal_Expiration);
//--- Creating filter CSignalMACD
CSignalMACD *filter0=new CSignalMACD;
if(filter0==NULL)
{
//--- failed
printf(__FUNCTION__+": error creating filter0");
ExtExpert.Deinit();
return(INIT_FAILED);
}
signal.AddFilter(filter0);
//--- Set filter parameters
filter0.PeriodFast(Signal_MACD_PeriodFast);
filter0.PeriodSlow(Signal_MACD_PeriodSlow);
filter0.PeriodSignal(Signal_MACD_PeriodSignal);
filter0.Applied(Signal_MACD_Applied);
filter0.Weight(Signal_MACD_Weight);
//--- Creation of trailing object
CTrailingNone *trailing=new CTrailingNone;
if(trailing==NULL)
{
//--- failed
printf(__FUNCTION__+": error creating trailing");
ExtExpert.Deinit();
return(INIT_FAILED);
}
//--- Add trailing to expert (will be deleted automatically))
if(!ExtExpert.InitTrailing(trailing))
{
//--- failed
printf(__FUNCTION__+": error initializing trailing");
ExtExpert.Deinit();
return(INIT_FAILED);
}
//--- Set trailing parameters
//--- Creation of money object
CMoneyFixedLot *money=new CMoneyFixedLot;
if(money==NULL)
{
//--- failed
printf(__FUNCTION__+": error creating money");
ExtExpert.Deinit();
return(INIT_FAILED);
}
//--- Add money to expert (will be deleted automatically))
if(!ExtExpert.InitMoney(money))
{
//--- failed
printf(__FUNCTION__+": error initializing money");
ExtExpert.Deinit();
return(INIT_FAILED);
}
//--- Set money parameters
money.Percent(Money_FixLot_Percent);
money.Lots(Money_FixLot_Lots);
//--- Check all trading objects parameters
if(!ExtExpert.ValidationSettings())
{
//--- failed
ExtExpert.Deinit();
return(INIT_FAILED);
}
//--- Tuning of all necessary indicators
if(!ExtExpert.InitIndicators())
{
//--- failed
printf(__FUNCTION__+": error initializing indicators");
ExtExpert.Deinit();
return(INIT_FAILED);
}
//--- ok
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Deinitialization function of the expert |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
ExtExpert.Deinit();
}
//+------------------------------------------------------------------+
//| "Tick" event handler function |
//+------------------------------------------------------------------+
void OnTick()
{
ExtExpert.OnTick();
}
//+------------------------------------------------------------------+
//| "Trade" event handler function |
//+------------------------------------------------------------------+
void OnTrade()
{
ExtExpert.OnTrade();
}
//+------------------------------------------------------------------+
//| "Timer" event handler function |
//+------------------------------------------------------------------+
void OnTimer()
{
ExtExpert.OnTimer();
}
//+------------------------------------------------------------------+
Binary file not shown.
@@ -0,0 +1,483 @@
//+------------------------------------------------------------------+
//| AlphaStrategyV1.mq4 |
//| Copyright 2020, MetaQuotes Software Corp. |
//| https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2020, MetaQuotes Software Corp."
#property link "https://www.mql5.com"
#property version "1.00"
#property strict
#include <Mql4Book\Timer.mqh>
#include <NNFX\Indicators\Baseline\NiKijun.mqh>
#include <NNFX\Indicators\NiSSLActivator.mqh>
#include <NNFX\Indicators\Confirmation\NiASH.mqh>
#include <NNFX\Indicators\Volumen\NiWAE.mqh>
#include <NNFX\Indicators\Exit\NiRex.mqh>
#include <NNFX\Indicators\NiNone.mqh>
#include <NNFX\Money\NiMoney.mqh>
#include <NNFX\Money\NiMoneyScaleOut.mqh>
#include <NNFX\functions.mqh>
//--- inputs
input int InpMagic = 1024;
input int Deviation = 50;
input string x7 = "------Special Rules-----";
input bool ApplySevenCandleRule = false;
input bool ApplyOneCandleRule = true;
input bool ApplyPullbackRule = true;
input bool ApplyContinuationRule = true;
input string x = "----Baseline-----";
input int InpKijun_b = 26; //InpKijun
input string x2 = "------C1-----------";
input int InpPeriods_C1 = 14; // InpPeriods
input ENUM_MA_METHOD InpMethod_C1 = MODE_SMA; //InpMethod
input string x3 = "------C2-----------";
input string InpModeStr_C2="Mode: 0 - RSI, 1 - Stoch";
input int InpMode_C2=0; // InpMode
input int InpLength_C2=9; //InpLength
input int InpSmooth_Length_C2=2; // InpSmooth_Length
input int InpPrice_C2=0; // InpPrice
// Applied price
// 0 - Close
// 1 - Open
// 2 - High
// 3 - Low
// 4 - Median
// 5 - Typical
// 6 - Weighted
input int InpMethod_C2=0;
// 0 - SMA
// 1 - EMA
// 2 - SMMA
// 3 - LWMA
input string x4 = "---------Volumen------";
input int InpSensetive_v = 150; //InpSensitive
input int InpDeadZonePip_v = 30; // InpDeadZonePip
input int InpExplosionPower_v = 15; // InpExplosionPower
input int InpTrendPower_v = 15; // InpTrendPower
input string x5 = "---------Exit---------";
input int InpSmoothing_Length_x=14; // InpSmoothing_Length
input int InpSmoothing_Method_x=0; // InpSmoothing_Method
// 0 - SMA
// 1 - EMA
// 2 - SMMA
// 3 - LWMA
input int InpSignal_Length_x=14; // InpSignal_Length
input int InpSignal_Method_x=0; // InpSignal_Method
// 0 - SMA
// 1 - EMA
// 2 - SMMA
// 3 - LWMA
input string x6 = "---------Monet management------";
input int InpTakeProfit = 100;
input int InpStopLoss = 100;
input double InpLotSize = 0.05;
//--- global variables
CNewBar NewBar;
string symbol;
int period;
bool longPosition;
bool shortPosition;
bool isPositionOpened;
bool OneCandleForLong;
bool OneCandleForShort;
OrderState orderState;
EnterTime forLong;
EnterTime forShort;
TrendStatus trendStatus;
NiKijun *baseline;
/*
NiSSLActivator *c1;
NiASH *c2;
NiWAE *volumeIndicator;
NiRex *exitIndicator;
*/
NiNone *c1;
NiNone *c2;
NiNone *volumeIndicator;
NiNone *exitIndicator;
NiMoneyScaleOut *money;
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
//---
orderState.LongPosition = false;
orderState.ShortPosition = false;
orderState.OrderStatus = false;
symbol = _Symbol;
period = _Period;
baseline = new NiKijun(InpKijun_b);
/*
c1 = new NiSSLActivator(InpPeriods_C1,InpMethod_C1);
c2 = new NiASH(InpModeStr_C2,InpMode_C2,InpLength_C2,InpSmooth_Length_C2,InpPrice_C2,InpMethod_C2);
volumeIndicator = new NiWAE(InpSensetive_v,InpDeadZonePip_v,InpExplosionPower_v,InpTrendPower_v);
exitIndicator = new NiRex(InpSmoothing_Length_x,InpSmoothing_Method_x,InpSignal_Length_x,InpSignal_Method_x);
*/
c1 = new NiNone();
c2 = new NiNone();
volumeIndicator = new NiNone();
exitIndicator = new NiNone();
baseline.InitIndicator(symbol,period);
c1.InitIndicator(symbol,period);
c2.InitIndicator(symbol,period);
volumeIndicator.InitIndicator(symbol,period);
exitIndicator.InitIndicator(symbol,period);
//money = new NiMoney(InpLotSize,InpTakeProfit,InpStopLoss,InpMagic,Deviation);
money = new NiMoneyScaleOut(InpLotSize,InpMagic,Deviation);
//---
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Expert deinitialization function |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
//---
delete baseline;
delete c1;
delete c2;
delete volumeIndicator;
delete exitIndicator;
delete money;
}
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick()
{
//---Detect New Bar
bool isNewBar = NewBar.checkNewBar(_Symbol,_Period);
//datetime t = iTime(_Symbol,_Period,0);
//Print("now: " + t);
if(!isNewBar){
return;
}
//Print("On new Bar");
OnBar();
}
//+------------------------------------------------------------------+
//|OnBar function |
//+------------------------------------------------------------------+
void OnBar()
{
//---Update Buffers
Refresh();
//---Exit rules
if(money.isOpenedPosition()){
manageClose();
}
//---Entry Rules
if(!money.isOpenedPosition()){
manageOpen();
}
}
//+------------------------------------------------------------------+
//|Open Positions: Entry rules |
//+------------------------------------------------------------------+
void manageOpen()
{
manageLong();
manageShort();
if(money.isOpenedPosition()) {
//Print("Position openend...");
//Print("position status: "+orderState.OrderStatus);
}
}
/*
* Checks conditions if is possible open long positions
*/
bool manageLong()
{
bool LongSignal = false;
bool InSevenCandles = false;
//--- Triggers an entry signal event, then checks all rules
if(c1.entryLong() || c2.entryLong()|| baseline.entryLong() || (OneCandleForLong && ApplyOneCandleRule)){
//--- Apply Seven Candle rule
if(ApplySevenCandleRule)
{ InSevenCandles = SevenCandleRuleForLong(); }
else{ InSevenCandles = false;}
//-- Checks all Indicators for a long trade
if((InSevenCandles && ApplySevenCandleRule) || !ApplySevenCandleRule ){
LongSignal = checkLongConditions();
if(OneCandleForLong && LongSignal) Print("Trade ok by one candle rule");
}
//--- Apply One candle Rule
if(!LongSignal && !OneCandleForLong && ApplyOneCandleRule)
{ OneCandleForLong = true;}
else if(OneCandleForLong == true)
{ OneCandleForLong = false;}
//---Apply Continuation Trade Rule
if(!LongSignal && ApplyContinuationRule && ((InSevenCandles && ApplySevenCandleRule) || !ApplySevenCandleRule))
{
if(baseline.entryLong()) {
trendStatus.EnteredInLong = Time[1];
}
if(trendStatus.EnteredInLong > trendStatus.EnteredInShort && trendStatus.EnteredInLong > Time[7])
{
LongSignal = checkContinuationLongConditions();
if(LongSignal) Print("Continuation Trade ok");
}
}
}
if(LongSignal){
money.OpenLong();
Print("Open Signal Long");
}
return LongSignal;
}
/*
* Use Special conditions in a continuation trade
*/
bool checkContinuationLongConditions()
{
bool LongSignal = baseline.baselineDirection() > 0.0 && c1.confirmationLong() && c2.confirmationLong();
return LongSignal;
}
/*
* Checks if c1,c2 gives the signal with in seven candles
*/
bool SevenCandleRuleForLong()
{
bool entrySignal = false;
if(c1.entryLong()) forLong.c1EnteredTime = Time[1];
if(c2.entryLong()) forLong.c2EnteredTime = Time[1];
//Print("7 candle rule: c1:" + forLong.c1EnteredTime + ", c2:" + forLong.c2EnteredTime);
//Print("7 candle rule: time: " + Time[7]);
if(forLong.c1EnteredTime > Time[7] && forLong.c2EnteredTime > Time[7])
{
//Print("7 candle rule: entry");
entrySignal = true;
}
return entrySignal;
}
//+------------------------------------------------------------------+
//|Check conditions for entry long position |
//+------------------------------------------------------------------+
bool checkLongConditions(){
bool openSignal = false;
double atr_value = iATR(symbol,period,14,1);
if(volumeIndicator.confirmationLong()){ // Enough volumen to open a position
if(baseline.baselineDirection() > 0.0 && (!ApplyPullbackRule || (ApplyPullbackRule && baseline.baselineDirection() < atr_value))){ // In long tendency
if(c1.confirmationLong() && c2.confirmationLong()){
openSignal = true;
}
}
}
Print("In long: " +volumeIndicator.confirmationLong() +" " + baseline.baselineDirection() + " "+ c1.confirmationLong() + c2.confirmationLong());
//openSignal = volumeIndicator.isAbleOpenPosition() && (baseline.baselineDirection(0) > 0.0) && c1.signalLong() && c2.signalLong();
return openSignal;
}
bool manageShort()
{
bool ShortSignal = false;
bool InSevenCandles = false;
if(c1.entryShort() || c2.entryShort() || baseline.entryShort() || (OneCandleForShort && ApplyOneCandleRule) ){
//--- Apply Seven Candle rule
if(ApplySevenCandleRule)
{ InSevenCandles = SevenCandleRuleForShort(); }
else{ InSevenCandles = false;}
//--------------------
//-- Checks all Indicators for a short trade
if((InSevenCandles && ApplySevenCandleRule) || !ApplySevenCandleRule ){
ShortSignal = checkShortConditions();
if(OneCandleForShort && ShortSignal) Print("Short trade ok by one candle rule");
} //-----------
//--- Apply One candle Rule
if(!ShortSignal && !OneCandleForShort && ApplyOneCandleRule)
{ OneCandleForShort = true;}
else if(OneCandleForShort == true)
{ OneCandleForShort = false;}
//--------
//---Apply Continuation Trade Rule
if(!ShortSignal && ApplyContinuationRule && ((InSevenCandles && ApplySevenCandleRule) || !ApplySevenCandleRule))
{
if(baseline.entryShort()) {
trendStatus.EnteredInShort = Time[1];
}
if(trendStatus.EnteredInShort > trendStatus.EnteredInLong && trendStatus.EnteredInShort > Time[7])
{
ShortSignal = checkContinuationShortConditions();
if(ShortSignal) Print("Continuation short Trade ok");
}
}// end continuation trade rule
}
if(ShortSignal){
money.OpenShort();
Print("Open Signal Short");
}
return ShortSignal;
}
/*
* Use Special conditions in a continuation trade
*/
bool checkContinuationShortConditions()
{
bool ShortSignal = baseline.baselineDirection() < 0.0 && c1.confirmationShort() && c2.confirmationShort();
return ShortSignal;
}
/*
* Checks if c1,c2 gives the signal with in seven candles
*/
bool SevenCandleRuleForShort()
{
bool entrySignal = false;
if(c1.entryShort()) forShort.c1EnteredTime = Time[1];
if(c2.entryShort()) forShort.c2EnteredTime = Time[1];
if(forShort.c1EnteredTime > Time[7] && forShort.c2EnteredTime > Time[7])
{
entrySignal = true;
}
return entrySignal;
}
//+------------------------------------------------------------------+
//|Check conditions for entry short position |
//+------------------------------------------------------------------+
bool checkShortConditions(){
bool openSignal = false;
double atr_value = iATR(symbol,period,14,1);
if(volumeIndicator.confirmationShort()){
if(baseline.baselineDirection() < 0.0 && (!ApplyPullbackRule || (ApplyPullbackRule && baseline.baselineDirection() < -1*atr_value)) ){
if(c1.confirmationShort() && c2.confirmationShort()){
openSignal = true;
}
}
}
Print("In short: " + volumeIndicator.confirmationShort() +" " + baseline.baselineDirection() + " "+ c1.confirmationShort() + c2.confirmationShort());
//openSignal = volumeIndicator.isAbleOpenPosition() && (baseline.baselineDirection(0) < 0.0) && c1.signalShort() && c2.signalShort();
return openSignal;
}
//+------------------------------------------------------------------+
//|Close Positions: Exit rules |
//+------------------------------------------------------------------+
void manageClose()
{
bool closeSignal = false;
if(money.isLongPosition()){
closeSignal = exitIndicator.exitLong();
}else if(money.isShortPosition()){
closeSignal = exitIndicator.exitShort();
}
if(closeSignal)
{
if(money.isLongPosition()){
money.CloseLongPosition();
}else if(money.isShortPosition()){
money.CloseShortPosition();
}
Print("Close Signal");
//Print("Position closed...");
//Print("position status: "+orderState.OrderStatus);
}
}
//+------------------------------------------------------------------+
//|Refresh indicators buffers data |
//+------------------------------------------------------------------+
void Refresh()
{
baseline.Refresh();
c1.Refresh();
c2.Refresh();
volumeIndicator.Refresh();
exitIndicator.Refresh();
money.Refresh();
/*Maybe In NiMomey class*/
int i = 0;
bool flag = false;
while(i< OrdersTotal() && !flag)
{
OrderSelect(i,SELECT_BY_POS);
if(OrderMagicNumber() == InpMagic)
{
flag = true;
}
i++;
}
if(!flag){ /*No orders made by this EA founded*/
money.InitTSParams();
}
//Print("Orders total :" + OrdersTotal());
}
Binary file not shown.
+486
View File
@@ -0,0 +1,486 @@
//+------------------------------------------------------------------+
//| StrategyOne.mq4 |
//| Copyright 2020, MetaQuotes Software Corp. |
//| https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2020, MetaQuotes Software Corp."
#property link "https://www.mql5.com"
#property version "3.00"
#property strict
#include <Mql4Book\Timer.mqh>
#include <NNFX\Indicators\Baseline\NiKijun.mqh>
#include <NNFX\Indicators\Baseline\NiMA.mqh>
#include <NNFX\Indicators\NiSSLActivator.mqh>
#include <NNFX\Indicators\Confirmation\NiASH.mqh>
#include <NNFX\Indicators\Volumen\NiWAE.mqh>
#include <NNFX\Indicators\Exit\NiRex.mqh>
#include <NNFX\Indicators\NiNone.mqh>
#include <NNFX\Money\NiMoney.mqh>
#include <NNFX\Money\NiMoneyScaleOut.mqh>
#include <NNFX\functions.mqh>
//--- inputs
input int InpMagic = 1024;
input int Deviation = 50;
input string x7 = "------Special Rules-----";
input bool ApplySevenCandleRule = false;
input bool ApplyOneCandleRule = true;
input bool ApplyPullbackRule = true;
input bool ApplyContinuationRule = true;
input string x = "----Baseline-----";
input int InpKijun_b = 26; //InpKijun
input string x2 = "------C1-----------";
input int InpPeriods_C1 = 14; // InpPeriods
input ENUM_MA_METHOD InpMethod_C1 = MODE_SMA; //InpMethod
input string x3 = "------C2-----------";
input string InpModeStr_C2="Mode: 0 - RSI, 1 - Stoch";
input int InpMode_C2=0; // InpMode
input int InpLength_C2=9; //InpLength
input int InpSmooth_Length_C2=2; // InpSmooth_Length
input int InpPrice_C2=0; // InpPrice
// Applied price
// 0 - Close
// 1 - Open
// 2 - High
// 3 - Low
// 4 - Median
// 5 - Typical
// 6 - Weighted
input int InpMethod_C2=0;
// 0 - SMA
// 1 - EMA
// 2 - SMMA
// 3 - LWMA
input string x4 = "---------Volumen------";
input int InpSensetive_v = 150; //InpSensitive
input int InpDeadZonePip_v = 30; // InpDeadZonePip
input int InpExplosionPower_v = 15; // InpExplosionPower
input int InpTrendPower_v = 15; // InpTrendPower
input string x5 = "---------Exit---------";
input int InpSmoothing_Length_x=14; // InpSmoothing_Length
input int InpSmoothing_Method_x=0; // InpSmoothing_Method
// 0 - SMA
// 1 - EMA
// 2 - SMMA
// 3 - LWMA
input int InpSignal_Length_x=14; // InpSignal_Length
input int InpSignal_Method_x=0; // InpSignal_Method
// 0 - SMA
// 1 - EMA
// 2 - SMMA
// 3 - LWMA
input string x6 = "---------Monet management------";
input int InpTakeProfit = 100;
input int InpStopLoss = 100;
input double InpLotSize = 0.05;
//--- global variables
CNewBar NewBar;
string symbol;
int period;
bool longPosition;
bool shortPosition;
bool isPositionOpened;
bool OneCandleForLong;
bool OneCandleForShort;
OrderState orderState;
EnterTime forLong;
EnterTime forShort;
TrendStatus trendStatus;
//NiKijun *baseline;
NiMA *baseline;
/*
NiSSLActivator *c1;
NiASH *c2;
NiWAE *volumeIndicator;
NiRex *exitIndicator;
*/
NiNone *c1;
NiNone *c2;
NiNone *volumeIndicator;
NiNone *exitIndicator;
IMoney *money;
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
//---
orderState.LongPosition = false;
orderState.ShortPosition = false;
orderState.OrderStatus = false;
symbol = _Symbol;
period = _Period;
//baseline = new NiKijun(InpKijun_b);
baseline = new NiMA(30,0,MODE_SMA,PRICE_CLOSE);
/*
c1 = new NiSSLActivator(InpPeriods_C1,InpMethod_C1);
c2 = new NiASH(InpModeStr_C2,InpMode_C2,InpLength_C2,InpSmooth_Length_C2,InpPrice_C2,InpMethod_C2);
volumeIndicator = new NiWAE(InpSensetive_v,InpDeadZonePip_v,InpExplosionPower_v,InpTrendPower_v);
exitIndicator = new NiRex(InpSmoothing_Length_x,InpSmoothing_Method_x,InpSignal_Length_x,InpSignal_Method_x);
*/
c1 = new NiNone();
c2 = new NiNone();
volumeIndicator = new NiNone();
exitIndicator = new NiNone();
baseline.InitIndicator(symbol,period);
c1.InitIndicator(symbol,period);
c2.InitIndicator(symbol,period);
volumeIndicator.InitIndicator(symbol,period);
exitIndicator.InitIndicator(symbol,period);
//money = new NiMoney(InpLotSize,InpTakeProfit,InpStopLoss,InpMagic,Deviation);
money = new NiMoneyScaleOut(InpLotSize,InpMagic,Deviation);
//---
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Expert deinitialization function |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
//---
delete baseline;
delete c1;
delete c2;
delete volumeIndicator;
delete exitIndicator;
delete money;
}
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick()
{
//---Detect New Bar
bool isNewBar = NewBar.checkNewBar(_Symbol,_Period);
//datetime t = iTime(_Symbol,_Period,0);
//Print("now: " + t);
if(!isNewBar){
return;
}
//Print("On new Bar");
OnBar();
}
//+------------------------------------------------------------------+
//|OnBar function |
//+------------------------------------------------------------------+
void OnBar()
{
//---Update Buffers
Refresh();
//---Exit rules
if(money.isOpenedPosition()){
manageClose();
}
//---Entry Rules
if(!money.isOpenedPosition()){
manageOpen();
}
}
//+------------------------------------------------------------------+
//|Open Positions: Entry rules |
//+------------------------------------------------------------------+
void manageOpen()
{
manageLong();
manageShort();
if(money.isOpenedPosition()) {
//Print("Position openend...");
//Print("position status: "+orderState.OrderStatus);
}
}
/*
* Checks conditions if is possible open long positions
*/
bool manageLong()
{
bool LongSignal = false;
bool InSevenCandles = false;
//--- Triggers an entry signal event, then checks all rules
if(c1.entryLong() || c2.entryLong()|| baseline.entryLong() || (OneCandleForLong && ApplyOneCandleRule)){
//--- Apply Seven Candle rule
if(ApplySevenCandleRule)
{ InSevenCandles = SevenCandleRuleForLong(); }
else{ InSevenCandles = false;}
//-- Checks all Indicators for a long trade
if((InSevenCandles && ApplySevenCandleRule) || !ApplySevenCandleRule ){
LongSignal = checkLongConditions();
if(OneCandleForLong && LongSignal) Print("Trade ok by one candle rule");
}
//--- Apply One candle Rule
if(!LongSignal && !OneCandleForLong && ApplyOneCandleRule)
{ OneCandleForLong = true;}
else if(OneCandleForLong == true)
{ OneCandleForLong = false;}
//---Apply Continuation Trade Rule
if(!LongSignal && ApplyContinuationRule && ((InSevenCandles && ApplySevenCandleRule) || !ApplySevenCandleRule))
{
if(baseline.entryLong()) {
trendStatus.EnteredInLong = Time[1];
}
if(trendStatus.EnteredInLong > trendStatus.EnteredInShort && trendStatus.EnteredInLong > Time[7])
{
LongSignal = checkContinuationLongConditions();
if(LongSignal) Print("Continuation Trade ok");
}
}
}
if(LongSignal){
money.OpenLong();
Print("Open Signal Long");
}
return LongSignal;
}
/*
* Use Special conditions in a continuation trade
*/
bool checkContinuationLongConditions()
{
bool LongSignal = baseline.baselineDirection() > 0.0 && c1.confirmationLong() && c2.confirmationLong();
return LongSignal;
}
/*
* Checks if c1,c2 gives the signal with in seven candles
*/
bool SevenCandleRuleForLong()
{
bool entrySignal = false;
if(c1.entryLong()) forLong.c1EnteredTime = Time[1];
if(c2.entryLong()) forLong.c2EnteredTime = Time[1];
//Print("7 candle rule: c1:" + forLong.c1EnteredTime + ", c2:" + forLong.c2EnteredTime);
//Print("7 candle rule: time: " + Time[7]);
if(forLong.c1EnteredTime > Time[7] && forLong.c2EnteredTime > Time[7])
{
//Print("7 candle rule: entry");
entrySignal = true;
}
return entrySignal;
}
//+------------------------------------------------------------------+
//|Check conditions for entry long position |
//+------------------------------------------------------------------+
bool checkLongConditions(){
bool openSignal = false;
double atr_value = iATR(symbol,period,14,1);
if(volumeIndicator.confirmationLong()){ // Enough volumen to open a position
if(baseline.baselineDirection() > 0.0 && (!ApplyPullbackRule || (ApplyPullbackRule && baseline.baselineDirection() < atr_value))){ // In long tendency
if(c1.confirmationLong() && c2.confirmationLong()){
openSignal = true;
}
}
}
Print("In long: " +volumeIndicator.confirmationLong() +" " + baseline.baselineDirection() + " "+ c1.confirmationLong() + c2.confirmationLong());
//openSignal = volumeIndicator.isAbleOpenPosition() && (baseline.baselineDirection(0) > 0.0) && c1.signalLong() && c2.signalLong();
return openSignal;
}
bool manageShort()
{
bool ShortSignal = false;
bool InSevenCandles = false;
if(c1.entryShort() || c2.entryShort() || baseline.entryShort() || (OneCandleForShort && ApplyOneCandleRule) ){
//--- Apply Seven Candle rule
if(ApplySevenCandleRule)
{ InSevenCandles = SevenCandleRuleForShort(); }
else{ InSevenCandles = false;}
//--------------------
//-- Checks all Indicators for a short trade
if((InSevenCandles && ApplySevenCandleRule) || !ApplySevenCandleRule ){
ShortSignal = checkShortConditions();
if(OneCandleForShort && ShortSignal) Print("Short trade ok by one candle rule");
} //-----------
//--- Apply One candle Rule
if(!ShortSignal && !OneCandleForShort && ApplyOneCandleRule)
{ OneCandleForShort = true;}
else if(OneCandleForShort == true)
{ OneCandleForShort = false;}
//--------
//---Apply Continuation Trade Rule
if(!ShortSignal && ApplyContinuationRule && ((InSevenCandles && ApplySevenCandleRule) || !ApplySevenCandleRule))
{
if(baseline.entryShort()) {
trendStatus.EnteredInShort = Time[1];
}
if(trendStatus.EnteredInShort > trendStatus.EnteredInLong && trendStatus.EnteredInShort > Time[7])
{
ShortSignal = checkContinuationShortConditions();
if(ShortSignal) Print("Continuation short Trade ok");
}
}// end continuation trade rule
}
if(ShortSignal){
money.OpenShort();
Print("Open Signal Short");
}
return ShortSignal;
}
/*
* Use Special conditions in a continuation trade
*/
bool checkContinuationShortConditions()
{
bool ShortSignal = baseline.baselineDirection() < 0.0 && c1.confirmationShort() && c2.confirmationShort();
return ShortSignal;
}
/*
* Checks if c1,c2 gives the signal with in seven candles
*/
bool SevenCandleRuleForShort()
{
bool entrySignal = false;
if(c1.entryShort()) forShort.c1EnteredTime = Time[1];
if(c2.entryShort()) forShort.c2EnteredTime = Time[1];
if(forShort.c1EnteredTime > Time[7] && forShort.c2EnteredTime > Time[7])
{
entrySignal = true;
}
return entrySignal;
}
//+------------------------------------------------------------------+
//|Check conditions for entry short position |
//+------------------------------------------------------------------+
bool checkShortConditions(){
bool openSignal = false;
double atr_value = iATR(symbol,period,14,1);
if(volumeIndicator.confirmationShort()){
if(baseline.baselineDirection() < 0.0 && (!ApplyPullbackRule || (ApplyPullbackRule && baseline.baselineDirection() < -1*atr_value)) ){
if(c1.confirmationShort() && c2.confirmationShort()){
openSignal = true;
}
}
}
Print("In short: " + volumeIndicator.confirmationShort() +" " + baseline.baselineDirection() + " "+ c1.confirmationShort() + c2.confirmationShort());
//openSignal = volumeIndicator.isAbleOpenPosition() && (baseline.baselineDirection(0) < 0.0) && c1.signalShort() && c2.signalShort();
return openSignal;
}
//+------------------------------------------------------------------+
//|Close Positions: Exit rules |
//+------------------------------------------------------------------+
void manageClose()
{
bool closeSignal = false;
if(money.isLongPosition()){
closeSignal = exitIndicator.exitLong();
}else if(money.isShortPosition()){
closeSignal = exitIndicator.exitShort();
}
if(closeSignal)
{
if(money.isLongPosition()){
money.CloseLongPosition();
}else if(money.isShortPosition()){
money.CloseShortPosition();
}
Print("Close Signal");
//Print("Position closed...");
//Print("position status: "+orderState.OrderStatus);
}
}
//+------------------------------------------------------------------+
//|Refresh indicators buffers data |
//+------------------------------------------------------------------+
void Refresh()
{
baseline.Refresh();
c1.Refresh();
c2.Refresh();
volumeIndicator.Refresh();
exitIndicator.Refresh();
money.Refresh();
/*Maybe In NiMomey class*/
int i = 0;
bool flag = false;
while(i< OrdersTotal() && !flag)
{
OrderSelect(i,SELECT_BY_POS);
if(OrderMagicNumber() == InpMagic)
{
flag = true;
}
i++;
}
if(!flag){ /*No orders made by this EA founded*/
money.InitTSParams();
}
//Print("Orders total :" + OrdersTotal());
}
Binary file not shown.
@@ -0,0 +1,208 @@
//+------------------------------------------------------------------+
//| StrategyOne.mq4 |
//| Copyright 2020, MetaQuotes Software Corp. |
//| https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2020, MetaQuotes Software Corp."
#property link "https://www.mql5.com"
#property version "4.00"
#property strict
#include <Mql4Book\Timer.mqh>
#include <NNFX\Indicators\Baseline\NiKijun.mqh>
#include <NNFX\Indicators\Baseline\NiMA.mqh>
#include <NNFX\Indicators\NiSSLActivator.mqh>
#include <NNFX\Indicators\Confirmation\NiASH.mqh>
#include <NNFX\Indicators\Volumen\NiWAE.mqh>
#include <NNFX\Indicators\Exit\NiRex.mqh>
#include <NNFX\Indicators\NiNone.mqh>
#include <NNFX\Money\NiMoney.mqh>
#include <NNFX\Money\NiMoneyScaleOut.mqh>
#include <NNFX\NExpert.mqh>
#include <NNFX\functions.mqh>
#include <NNFX\Rules\NRules.mqh>
//--- inputs
input int InpMagic = 1024;
input int Deviation = 50;
input double InpLotSize = 0.05;
input double InpSLalpha = 1.5;
input double InpTPbeta = 1;
input string x7 = "------Special Rules-----";
input bool ApplySevenCandleRule = true;
input bool ApplyOneCandleRule = true;
input bool ApplyPullbackRule = true;
input bool ApplyContinuationRule = true;
input string x = "----Baseline-----";
input int InpKijun_b = 26; //InpKijun
input string x2 = "------C1-----------";
input int InpPeriods_C1 = 14; // InpPeriods
input ENUM_MA_METHOD InpMethod_C1 = MODE_SMA; //InpMethod
input string x3 = "------C2-----------";
input string InpModeStr_C2="Mode: 0 - RSI, 1 - Stoch";
input int InpMode_C2=0; // InpMode
input int InpLength_C2=9; //InpLength
input int InpSmooth_Length_C2=2; // InpSmooth_Length
input int InpPrice_C2=0; // InpPrice
// Applied price
// 0 - Close
// 1 - Open
// 2 - High
// 3 - Low
// 4 - Median
// 5 - Typical
// 6 - Weighted
input int InpMethod_C2=0;
// 0 - SMA
// 1 - EMA
// 2 - SMMA
// 3 - LWMA
input string x4 = "---------Volumen------";
input int InpSensetive_v = 150; //InpSensitive
input int InpDeadZonePip_v = 30; // InpDeadZonePip
input int InpExplosionPower_v = 15; // InpExplosionPower
input int InpTrendPower_v = 15; // InpTrendPower
input string x5 = "---------Exit---------";
input int InpSmoothing_Length_x=14; // InpSmoothing_Length
input int InpSmoothing_Method_x=0; // InpSmoothing_Method
// 0 - SMA
// 1 - EMA
// 2 - SMMA
// 3 - LWMA
input int InpSignal_Length_x=14; // InpSignal_Length
input int InpSignal_Method_x=0; // InpSignal_Method
// 0 - SMA
// 1 - EMA
// 2 - SMMA
// 3 - LWMA
input string x6 = "---------Monet management------";
input int InpTakeProfit = 100;
input int InpStopLoss = 100;
//--- global variables
CNewBar NewBar;
string symbol;
int period;
bool longPosition;
bool shortPosition;
bool isPositionOpened;
bool OneCandleForLong;
bool OneCandleForShort;
OrderState orderState;
EnterTime forLong;
EnterTime forShort;
TrendStatus trendStatus;
IBaseline *baseline;
IConfirmation *c1;
IConfirmation *c2;
IVolume *volumeIndicator;
IExit *exitIndicator;
IMoney *money;
NExpert *expert;
/*
NiNone *c1;
NiNone *c2;
NiNone *volumeIndicator;
NiNone *exitIndicator;
*/
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
//---
orderState.LongPosition = false;
orderState.ShortPosition = false;
orderState.OrderStatus = false;
symbol = _Symbol;
period = _Period;
baseline = new NiKijun(InpKijun_b);
//baseline = new NiMA(30,0,MODE_SMA,PRICE_CLOSE);
c1 = new NiSSLActivator(InpPeriods_C1,InpMethod_C1);
c2 = new NiASH(InpModeStr_C2,InpMode_C2,InpLength_C2,InpSmooth_Length_C2,InpPrice_C2,InpMethod_C2);
volumeIndicator = new NiWAE(InpSensetive_v,InpDeadZonePip_v,InpExplosionPower_v,InpTrendPower_v);
exitIndicator = new NiRex(InpSmoothing_Length_x,InpSmoothing_Method_x,InpSignal_Length_x,InpSignal_Method_x);
//money = new NiMoneyScaleOut(InpLotSize,InpMagic,Deviation);
money = new NiMoneyScaleOut(InpLotSize,InpSLalpha,InpTPbeta,14,InpMagic,Deviation);
/*
c1 = new NiNoneC();
c2 = new NiNoneC();
volumeIndicator = new NiNoneV();
exitIndicator = new NiNoneE();
*/
baseline.InitIndicator(symbol,period);
c1.InitIndicator(symbol,period);
c2.InitIndicator(symbol,period);
volumeIndicator.InitIndicator(symbol,period);
exitIndicator.InitIndicator(symbol,period);
expert = new NExpert(baseline,c1,c2,exitIndicator,volumeIndicator,money,InpMagic,
ApplyPullbackRule,ApplySevenCandleRule,ApplyContinuationRule,ApplyOneCandleRule);
//money = new NiMoney(InpLotSize,InpTakeProfit,InpStopLoss,InpMagic,Deviation);
//---
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Expert deinitialization function |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
//---
delete baseline;
delete c1;
delete c2;
delete volumeIndicator;
delete exitIndicator;
delete money;
delete expert;
}
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick()
{
//---Detect New Bar
bool isNewBar = NewBar.checkNewBar(_Symbol,_Period);
//datetime t = iTime(_Symbol,_Period,0);
//Print("now: " + t);
if(!isNewBar)
{
return;
}
//Print("On new Bar");
expert.OnBar();
}
Binary file not shown.
@@ -0,0 +1,212 @@
/*
============================================================
Demo File: RSI_Mean_Reversion_EA - Signal Logic Showcase
Category: Mean Reversion
Platform: MetaTrader 4 (MQL4)
Version: 1.0
Author: Giacomo Cipolat Bares
Portfolio: MQL4 Expert Advisors Portfolio
============================================================
Description:
This is a simplified public demo derived from the full
RSI Mean Reversion EA.
Included in this demo:
- RSI overbought / oversold logic
- optional candle-close confirmation
- optional moving average trend filter
- optional ATR volatility filter
- basic on-chart signal output
Excluded from this demo:
- order execution
- risk management engine
- break-even / trailing stop
- retry logic
- broker protection handling
- full production trade framework
- chart visualization layer
============================================================
*/
#property strict
#property version "1.00"
//========================= INPUTS ==================================
input string __01_RSISettings = "01 =========== RSI Settings ==========";
input int RSIPeriod = 14;
input double RSIBuyLevel = 30.0;
input double RSISellLevel = 70.0;
input double RSIExitLevel = 50.0;
input int RSIPrice = PRICE_CLOSE;
input bool UseClosedCandleSignal = true;
input string __02_TrendFilter = "02 ========= Trend Filter =========";
input bool UseTrendFilter = false;
input int MAPeriod = 200;
input int MAMethod = MODE_SMA;
input int MAPrice = PRICE_CLOSE;
input string __03_ATRFilter = "03 =========== ATR Filter ==========";
input bool UseATRFilter = false;
input int ATRPeriod = 14;
input double MinATRValuePips = 5.0;
//======================= GLOBALS ===================================
double g_point;
double g_pip;
int g_digits;
datetime g_lastBarTime = 0;
//+------------------------------------------------------------------+
//| Expert initialization |
//+------------------------------------------------------------------+
int OnInit()
{
g_point = Point;
g_digits = Digits;
if(g_digits == 5 || g_digits == 3)
g_pip = g_point * 10.0;
else
g_pip = g_point;
Print("RSI Mean Reversion demo initialized");
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Detects a new bar |
//+------------------------------------------------------------------+
bool IsNewBar()
{
datetime currentBarTime = iTime(NULL, 0, 0);
if(currentBarTime != g_lastBarTime)
{
g_lastBarTime = currentBarTime;
return true;
}
return false;
}
//+------------------------------------------------------------------+
//| Indicator helpers |
//+------------------------------------------------------------------+
double GetRSI(int shift)
{
return iRSI(NULL, 0, RSIPeriod, RSIPrice, shift);
}
double GetMA(int shift)
{
return iMA(NULL, 0, MAPeriod, 0, MAMethod, MAPrice, shift);
}
double GetATRInPips(int shift)
{
double atr = iATR(NULL, 0, ATRPeriod, shift);
return atr / g_pip;
}
//+------------------------------------------------------------------+
//| Filters |
//+------------------------------------------------------------------+
bool TrendFilterBuyPassed()
{
if(!UseTrendFilter)
return true;
return (Close[1] >= GetMA(1));
}
bool TrendFilterSellPassed()
{
if(!UseTrendFilter)
return true;
return (Close[1] <= GetMA(1));
}
bool ATRFilterPassed()
{
if(!UseATRFilter)
return true;
return (GetATRInPips(1) >= MinATRValuePips);
}
//+------------------------------------------------------------------+
//| RSI signal logic |
//+------------------------------------------------------------------+
bool IsOversoldSignal()
{
double rsiPrev = GetRSI(2);
double rsiCurr = GetRSI(1);
if(UseClosedCandleSignal)
return (rsiPrev <= RSIBuyLevel && rsiCurr > RSIBuyLevel);
return (GetRSI(0) <= RSIBuyLevel);
}
bool IsOverboughtSignal()
{
double rsiPrev = GetRSI(2);
double rsiCurr = GetRSI(1);
if(UseClosedCandleSignal)
return (rsiPrev >= RSISellLevel && rsiCurr < RSISellLevel);
return (GetRSI(0) >= RSISellLevel);
}
//+------------------------------------------------------------------+
//| Demo wrappers |
//+------------------------------------------------------------------+
bool BuySignal()
{
if(!ATRFilterPassed())
return false;
if(!TrendFilterBuyPassed())
return false;
return IsOversoldSignal();
}
bool SellSignal()
{
if(!ATRFilterPassed())
return false;
if(!TrendFilterSellPassed())
return false;
return IsOverboughtSignal();
}
//+------------------------------------------------------------------+
//| Expert tick |
//+------------------------------------------------------------------+
void OnTick()
{
if(!IsNewBar())
return;
if(BuySignal())
{
Comment("Demo Signal: BUY RSI mean reversion detected");
return;
}
if(SellSignal())
{
Comment("Demo Signal: SELL RSI mean reversion detected");
return;
}
Comment("Demo Signal: No valid RSI mean reversion setup");
}
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+741
View File
@@ -0,0 +1,741 @@
//+------------------------------------------------------------------+
//| NewsTrader.mq4 |
//| Copyright © 2024, EarnForex.com |
//| https://www.earnforex.com/ |
//+------------------------------------------------------------------+
#property copyright "Copyright © 2024, EarnForex"
#property link "https://www.earnforex.com/metatrader-expert-advisors/News-Trader/"
#property version "1.12"
#property strict
#property description "Opens a buy/sell trade (random, chosen direction, or both directions) seconds before news release."
#property description "Sets SL and TP. Keeps updating them until the very release."
#property description "Can set use trailing stop and breakeven."
#property description "ATR-based stop-loss option is also available."
#property description "Closes trade after one hour."
enum dir_enum
{
Buy,
Sell,
Both,
Random
};
enum trailing_enum
{
None,
Breakeven,
Normal, // Normal trailing stop
NormalPlusBE // Normal trailing stop + Breakeven
};
input group "Trading"
input datetime NewsTime = -1; // News date/time (Server)
input int StopLoss = 15; // Stop-loss in points
input int TakeProfit = 75; // Take-profit in points
input dir_enum Direction = Both; // Direction of the trade to open
input trailing_enum TrailingStop = None; // Trailing stop type
input int BEOnProfit = 0; // Profit to trigger breakeven, points
input int BEExtraProfit = 0; // Extra profit for breakeven, points
input int TSOnProfit = 0; // Profit to start trailing stop, points
input bool PreAdjustSLTP = false; // Preadjust SL/TP until news is out
input int SecondsBefore = 18; // Seconds before the news to open a trade
input int CloseAfterSeconds = 3600; // Close trade X seconds after the news, 0 - turn the feature off
input bool SpreadFuse = true; // SpreadFuse - prevent trading if spread >= stop-loss
input group "ATR"
input bool UseATR = false; // Use ATR-based stop-loss and take-profit levels
input int ATR_Period = 14; // ATR Period
input double ATR_Multiplier_SL = 1; // ATR multiplier for SL
input double ATR_Multiplier_TP = 5; // ATR multiplier for TP
input group "Money management"
input double Lots = 0.01;
input bool MM = true; // Money Management, if true - position sizing based on stop-loss
input double Risk = 1; // Risk - Risk tolerance in percentage points
input double FixedBalance = 0; // FixedBalance: If > 0, trade size calc. uses it as balance
input double MoneyRisk = 0; // MoneyRisk: Risk tolerance in account currency
input bool UseMoneyInsteadOfPercentage = false; // Use money risk instead of percentage
input bool UseEquityInsteadOfBalance = false; // Use equity instead of balance
input group "Timer"
input bool ShowTimer = true; // Show timer before and after news
input int FontSize = 18;
input string Font = "Arial";
input color FontColor = clrRed;
input ENUM_BASE_CORNER Corner = CORNER_LEFT_UPPER;
input int X_Distance = 10; // X-axis distance from the chart corner
input int Y_Distance = 130; // Y-axis distance from the chart corner
input group "Miscellaneous"
input int Slippage = 3;
input int Magic = 794823491;
input string Commentary = "NewsTrader"; // Comment - trade description (e.g. "US CPI", "EU GDP", etc.)
input bool IgnoreECNMode = true; // IgnoreECNMode: Always attach SL/TP immediately
// Global variables:
bool HaveLongPosition, HaveShortPosition;
bool ECN_Mode;
int news_time;
bool CanTrade = false;
bool Terminal_Trade_Allowed = true;
double SL, TP;
// For tick value adjustment:
string ProfitCurrency = "", account_currency = "", BaseCurrency = "", ReferenceSymbol = NULL, AdditionalReferenceSymbol = NULL;
bool ReferenceSymbolMode, AdditionalReferenceSymbolMode;
int ProfitCalcMode;
void OnInit()
{
news_time = (int)NewsTime;
double min_lot = SymbolInfoDouble(Symbol(), SYMBOL_VOLUME_MIN);
if ((Lots < min_lot) && (!MM))
{
double lot_step = SymbolInfoDouble(Symbol(), SYMBOL_VOLUME_STEP);
int LotStep_digits = CountDecimalPlaces(lot_step);
Print("Minimum lot: ", DoubleToString(min_lot, LotStep_digits), ", lot step: ", DoubleToString(lot_step, LotStep_digits), ".");
Alert("Lots should be not less than: ", DoubleToString(min_lot, LotStep_digits), ".");
}
else CanTrade = true;
if (ShowTimer)
{
ObjectCreate(ChartID(), "NewsTraderTimer", OBJ_LABEL, 0, 0, 0);
ObjectSetInteger(ChartID(), "NewsTraderTimer", OBJPROP_CORNER, Corner);
ObjectSetInteger(ChartID(), "NewsTraderTimer", OBJPROP_XDISTANCE, X_Distance);
ObjectSetInteger(ChartID(), "NewsTraderTimer", OBJPROP_YDISTANCE, Y_Distance);
ObjectSetInteger(ChartID(), "NewsTraderTimer", OBJPROP_SELECTABLE, true);
EventSetMillisecondTimer(100); // For smooth updates.
}
// If UseATR = false, these values will be used. Otherwise, ATR values will be calculated later.
SL = StopLoss;
TP = TakeProfit;
if (BEExtraProfit > BEOnProfit) Print("Extra profit for breakeven shouldn't be greater than the profit to trigger breakeven parameter. Please check your input parameters.");
}
//+------------------------------------------------------------------+
//| Deletes graphical object if needed. |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
ObjectDelete(ChartID(), "NewsTraderTimer");
}
//+------------------------------------------------------------------+
//| Updates text about time left to news or passed after news. |
//+------------------------------------------------------------------+
void OnTimer()
{
DoTrading();
string text;
int difference = (int)TimeCurrent() - news_time;
if (difference <= 0) text = "Time to news: " + TimeDistance(-difference);
else text = "Time after news: " + TimeDistance(difference) + ".";
ObjectSetString(ChartID(), "NewsTraderTimer", OBJPROP_TEXT, text);
ObjectSetString(ChartID(), "NewsTraderTimer", OBJPROP_FONT, Font);
ObjectSetInteger(ChartID(), "NewsTraderTimer", OBJPROP_FONTSIZE, FontSize);
ObjectSetInteger(ChartID(), "NewsTraderTimer", OBJPROP_COLOR, FontColor);
}
//+------------------------------------------------------------------+
//| Format time distance from the number of seconds to normal string |
//| of years, days, hours, minutes, and seconds. |
//| t - number of seconds |
//| Returns: formatted string. |
//+------------------------------------------------------------------+
string TimeDistance(int t)
{
if (t == 0) return "0 seconds";
string s = "";
int y = 0;
int d = 0;
int h = 0;
int m = 0;
y = t / 31536000;
t -= y * 31536000;
d = t / 86400;
t -= d * 86400;
h = t / 3600;
t -= h * 3600;
m = t / 60;
t -= m * 60;
if (y) s += IntegerToString(y) + " year";
if (y > 1) s += "s";
if (d) s += " " + IntegerToString(d) + " day";
if (d > 1) s += "s";
if (h) s += " " + IntegerToString(h) + " hour";
if (h > 1) s += "s";
if (m) s += " " + IntegerToString(m) + " minute";
if (m > 1) s += "s";
if (t) s += " " + IntegerToString(t) + " second";
if (t > 1) s += "s";
return StringTrimLeft(s);
}
void OnTick()
{
DoTrading();
}
//+------------------------------------------------------------------+
//| Main execution procedure. |
//+------------------------------------------------------------------+
void DoTrading()
{
if ((TerminalInfoInteger(TERMINAL_TRADE_ALLOWED) == false) || (!CanTrade))
{
if ((TerminalInfoInteger(TERMINAL_TRADE_ALLOWED) == false) && (Terminal_Trade_Allowed == true))
{
Print("Trading not allowed.");
Terminal_Trade_Allowed = false;
}
else if ((TerminalInfoInteger(TERMINAL_TRADE_ALLOWED) == true) && (Terminal_Trade_Allowed == false))
{
Print("Trading allowed.");
Terminal_Trade_Allowed = true;
}
return;
}
ENUM_SYMBOL_TRADE_EXECUTION Execution_Mode = (ENUM_SYMBOL_TRADE_EXECUTION)SymbolInfoInteger(Symbol(), SYMBOL_TRADE_EXEMODE);
if (Execution_Mode == SYMBOL_TRADE_EXECUTION_MARKET) ECN_Mode = true;
else ECN_Mode = false;
if (IgnoreECNMode) ECN_Mode = false;
// Do nothing if it is too early.
int time = (int)TimeCurrent();
if (time < news_time - SecondsBefore) return;
if (UseATR)
{
// Getting the ATR values
double ATR = iATR(NULL, 0, ATR_Period, 0);
SL = ATR * ATR_Multiplier_SL;
if (SL <= (SymbolInfoInteger(Symbol(), SYMBOL_TRADE_STOPS_LEVEL) + SymbolInfoInteger(Symbol(), SYMBOL_SPREAD)) * Point) SL = (SymbolInfoInteger(Symbol(), SYMBOL_TRADE_STOPS_LEVEL) + SymbolInfoInteger(Symbol(), SYMBOL_SPREAD)) * Point;
TP = ATR * ATR_Multiplier_TP;
if (TP <= (SymbolInfoInteger(Symbol(), SYMBOL_TRADE_STOPS_LEVEL) + SymbolInfoInteger(Symbol(), SYMBOL_SPREAD)) * Point) TP = (SymbolInfoInteger(Symbol(), SYMBOL_TRADE_STOPS_LEVEL) + SymbolInfoInteger(Symbol(), SYMBOL_SPREAD)) * Point;
SL /= Point;
TP /= Point;
}
// Check what position is currently open.
GetPositionStates();
// Adjust SL and TP of the current position.
if ((HaveLongPosition) || (HaveShortPosition)) ControlPosition();
else
{
// Time to news is less or equal to SecondsBefore but is not negative.
if ((news_time - time <= SecondsBefore) && (news_time > time))
{
// Prevent position opening when spreads are too wide (bigger than StopLoss input).
int spread = (int)MarketInfo(Symbol(), MODE_SPREAD);
if ((SpreadFuse) && (spread >= StopLoss))
{
Print(Symbol(), ": Spread fuse prevents positions from opening. Current spread: ", spread, " points.");
return;
}
if (Direction == Buy) fBuy();
else if (Direction == Sell) fSell();
else if (Direction == Both)
{
fBuy();
fSell();
}
else if (Direction == Random)
{
MathSrand((uint)TimeCurrent());
if (MathRand() % 2 == 1) fBuy();
else fSell();
}
if (ECN_Mode) ControlPosition();
}
}
}
//+------------------------------------------------------------------+
//| Check what positions are currently open. |
//+------------------------------------------------------------------+
void GetPositionStates()
{
HaveLongPosition = false;
HaveShortPosition = false;
int total = OrdersTotal();
for (int cnt = 0; cnt < total; cnt++)
{
if (OrderSelect(cnt, SELECT_BY_POS, MODE_TRADES) == false) continue;
if (OrderMagicNumber() != Magic) continue;
if (OrderSymbol() != Symbol()) continue;
if (OrderType() == OP_BUY) HaveLongPosition = true;
else if (OrderType() == OP_SELL) HaveShortPosition = true;
}
}
//+------------------------------------------------------------------+
//| Add SL/TP, adjust SL/TP, set breakeven, close trade. |
//+------------------------------------------------------------------+
void ControlPosition()
{
int total = OrdersTotal();
for (int cnt = total - 1; cnt >= 0; cnt--)
{
if (OrderSelect(cnt, SELECT_BY_POS, MODE_TRADES) == false) continue;
if (OrderMagicNumber() != Magic) continue;
if (OrderSymbol() != Symbol()) continue;
if ((OrderType() == OP_BUY) || (OrderType() == OP_SELL))
{
int time = (int)TimeCurrent();
double new_sl, new_tp;
if (SL < MarketInfo(Symbol(), MODE_STOPLEVEL) + MarketInfo(Symbol(), MODE_SPREAD)) SL = MarketInfo(Symbol(), MODE_STOPLEVEL) + MarketInfo(Symbol(), MODE_SPREAD);
if (TP < MarketInfo(Symbol(), MODE_STOPLEVEL) + MarketInfo(Symbol(), MODE_SPREAD)) TP = MarketInfo(Symbol(), MODE_STOPLEVEL) + MarketInfo(Symbol(), MODE_SPREAD);
if (OrderType() == OP_BUY)
{
RefreshRates();
new_sl = NormalizeDouble(Ask - SL * Point, Digits);
new_tp = NormalizeDouble(Ask + TP * Point, Digits);
}
else if (OrderType() == OP_SELL)
{
RefreshRates();
new_sl = NormalizeDouble(Bid + SL * Point, Digits);
new_tp = NormalizeDouble(Bid - TP * Point, Digits);
}
// Need to adjust or add SL/TP.
if (time < news_time)
{
// Adjust only if parameter is set or if in ECN mode and need to assign SL/TP first time.
if ((((new_sl != NormalizeDouble(OrderStopLoss(), Digits)) || (new_tp != NormalizeDouble(OrderTakeProfit(), Digits))) && (PreAdjustSLTP)) ||
(((OrderStopLoss() == 0) || (OrderTakeProfit() == 0)) && (ECN_Mode)))
{
Print("Adjusting SL: ", DoubleToString(new_sl, _Digits), " and TP: ", DoubleToString(new_tp, _Digits), ".");
for (int i = 0; i < 10; i++)
{
bool result = OrderModify(OrderTicket(), OrderOpenPrice(), new_sl, new_tp, 0);
if (result) return;
else Print("Error modifying the order: ", GetLastError());
}
}
}
// Check for breakeven or trade time out. Plus, sometimes, in ECN mode, it is necessary to check if SL/TP was set even after the news.
else
{
RefreshRates();
// Adjust only if in ECN mode and need to assign SL/TP first time.
if (((OrderStopLoss() == 0) || (OrderTakeProfit() == 0)) && (ECN_Mode))
{
Print("Adjusting SL: ", DoubleToString(new_sl, _Digits), " and TP: ", DoubleToString(new_tp, _Digits), ".");
for (int i = 0; i < 10; i++)
{
bool result = OrderModify(OrderTicket(), OrderOpenPrice(), new_sl, new_tp, 0);
if (result) return;
else Print("Error modifying the order: ", GetLastError());
}
}
// Breakeven.
if (((TrailingStop == Breakeven) || (TrailingStop == NormalPlusBE)) && ((((OrderType() == OP_BUY) && (Bid - OrderOpenPrice() >= BEOnProfit * _Point)) || ((OrderType() == OP_SELL) && (OrderOpenPrice() - Ask >= BEOnProfit * _Point)))))
{
new_sl = NormalizeDouble(OrderOpenPrice(), _Digits);
if (BEExtraProfit > 0) // Breakeven extra profit?
{
if (OrderType() == OP_BUY) new_sl += BEExtraProfit * _Point; // For buys.
else new_sl -= BEExtraProfit * _Point; // For sells.
new_sl = NormalizeDouble(new_sl, _Digits);
}
if (((OrderType() == OP_BUY) && (new_sl > OrderStopLoss())) || ((OrderType() == OP_SELL) && ((new_sl < OrderStopLoss()) || (OrderStopLoss() == 0)))) // Avoid moving SL to BE if this SL is already there or in a better position.
{
Print("Moving SL to breakeven: ", new_sl, ".");
for (int i = 0; i < 10; i++)
{
bool result = OrderModify(OrderTicket(), OrderOpenPrice(), new_sl, OrderTakeProfit(), 0);
if (result) break;
else Print("Position modification error: ", GetLastError());
}
}
}
// Trailing stop.
if (((TrailingStop == Normal) || (TrailingStop == NormalPlusBE)) && ((TSOnProfit == 0) || ((OrderType() == OP_BUY) && (Bid - OrderOpenPrice() >= TSOnProfit * _Point)) || ((OrderType() == OP_SELL) && (OrderOpenPrice() - Ask >= TSOnProfit * _Point))))
{
if (OrderType() == OP_BUY) new_sl = NormalizeDouble(Bid - SL * _Point, _Digits);
else if (OrderType() == OP_SELL) new_sl = NormalizeDouble(Ask + SL * _Point, _Digits);
if (((OrderType() == OP_BUY) && (new_sl > OrderStopLoss())) || ((OrderType() == OP_SELL) && ((new_sl < OrderStopLoss()) || (OrderStopLoss() == 0)))) // Avoid moving the SL if this SL is already in a better position.
{
Print("Moving trailing SL to ", new_sl, ".");
for (int i = 0; i < 10; i++)
{
bool result = OrderModify(OrderTicket(), OrderOpenPrice(), new_sl, OrderTakeProfit(), 0);
if (result) break;
else Print("Position modification error: ", GetLastError());
}
}
}
if (CloseAfterSeconds > 0)
{
if (time - news_time >= CloseAfterSeconds)
{
Print("Closing trade by time out.");
double price;
RefreshRates();
if (OrderType() == OP_BUY) price = Bid;
else if (OrderType() == OP_SELL) price = Ask;
if (!OrderClose(OrderTicket(), OrderLots(), price, Slippage, clrBlue))
{
Print("OrderClose() failed: ", GetLastError());
}
}
}
}
}
}
}
//+------------------------------------------------------------------+
//| Generic buy. |
//+------------------------------------------------------------------+
void fBuy()
{
Print("Opening Buy.");
for (int i = 0; i < 10; i++)
{
double new_sl = 0, new_tp = 0;
double lots = LotsOptimized(OP_BUY);
RefreshRates();
// Bid and Ask are swapped to preserve the probabilities and decrease/increase profit/loss size.
if (!ECN_Mode)
{
new_sl = NormalizeDouble(Ask - SL * Point, Digits);
new_tp = NormalizeDouble(Ask + TP * Point, Digits);
}
int result = OrderSend(Symbol(), OP_BUY, lots, Ask, Slippage, new_sl, new_tp, Commentary, Magic, 0, clrBlue);
Sleep(1000);
if (result == -1)
{
int e = GetLastError();
Print("OrderSend Error: ", e, ".");
}
else return;
}
}
//+------------------------------------------------------------------+
//| Generic sell. |
//+------------------------------------------------------------------+
void fSell()
{
Print("Opening Sell.");
for (int i = 0; i < 10; i++)
{
double new_sl = 0, new_tp = 0;
double lots = LotsOptimized(OP_SELL);
RefreshRates();
// Bid and Ask are swapped to preserve the probabilities and decrease/increase profit/loss size.
if (!ECN_Mode)
{
new_sl = NormalizeDouble(Bid + SL * Point, Digits);
new_tp = NormalizeDouble(Bid - TP * Point, Digits);
}
int result = OrderSend(Symbol(), OP_SELL, lots, Bid, Slippage, new_sl, new_tp, Commentary, Magic, 0, clrRed);
Sleep(1000);
if (result == -1)
{
int e = GetLastError();
Print("OrderSend Error: ", e, ".");
}
else return;
}
}
//+------------------------------------------------------------------+
//| Calculate position size depending on money management parameters.|
//+------------------------------------------------------------------+
double LotsOptimized(int dir)
{
if (!MM) return Lots;
double Size, RiskMoney, PositionSize = 0, UnitCost;
ProfitCurrency = SymbolInfoString(Symbol(), SYMBOL_CURRENCY_PROFIT);
BaseCurrency = SymbolInfoString(Symbol(), SYMBOL_CURRENCY_BASE);
ProfitCalcMode = (int)MarketInfo(Symbol(), MODE_PROFITCALCMODE);
account_currency = AccountCurrency();
// A rough patch for cases when account currency is set as RUR instead of RUB.
if (account_currency == "RUR") account_currency = "RUB";
if (ProfitCurrency == "RUR") ProfitCurrency = "RUB";
if (BaseCurrency == "RUR") BaseCurrency = "RUB";
double LotStep = MarketInfo(Symbol(), MODE_LOTSTEP);
int LotStep_digits = CountDecimalPlaces(LotStep);
if (AccountCurrency() == "") return 0;
if (FixedBalance > 0)
{
Size = FixedBalance;
}
else if (UseEquityInsteadOfBalance)
{
Size = AccountEquity();
}
else
{
Size = AccountBalance();
}
if (!UseMoneyInsteadOfPercentage) RiskMoney = Size * Risk / 100;
else RiskMoney = MoneyRisk;
// If Symbol is CFD.
if (ProfitCalcMode == 1)
UnitCost = SymbolInfoDouble(Symbol(), SYMBOL_TRADE_TICK_SIZE) * SymbolInfoDouble(Symbol(), SYMBOL_TRADE_CONTRACT_SIZE); // Apparently, it is more accurate than taking TICKVALUE directly in some cases.
else UnitCost = MarketInfo(Symbol(), MODE_TICKVALUE); // Futures or Forex.
if (ProfitCalcMode != 0) // Non-Forex might need to be adjusted.
{
// If profit currency is different from account currency.
if (ProfitCurrency != account_currency)
{
double CCC = CalculateAdjustment(); // Valid only for loss calculation.
// Adjust the unit cost.
UnitCost *= CCC;
}
}
// If account currency == pair's base currency, adjust UnitCost to future rate (SL). Works only for Forex pairs.
if ((account_currency == BaseCurrency) && (ProfitCalcMode == 0))
{
double current_rate = 1, future_rate = 1;
RefreshRates();
if (dir == OP_BUY)
{
current_rate = Ask;
future_rate = current_rate - SL * _Point;
}
else if (dir == OP_SELL)
{
current_rate = Bid;
future_rate = current_rate + SL * _Point;
}
if (future_rate == 0) future_rate = _Point; // Zero divide prevention.
UnitCost *= (current_rate / future_rate);
}
double TickSize = MarketInfo(Symbol(), MODE_TICKSIZE);
if ((SL != 0) && (UnitCost != 0) && (TickSize != 0)) PositionSize = NormalizeDouble(RiskMoney / (SL * _Point * UnitCost / TickSize), LotStep_digits);
if (PositionSize < MarketInfo(Symbol(), MODE_MINLOT))
{
Print("Calculated position size (" + DoubleToString(PositionSize, 2) + ") is less than minimum position size (" + DoubleToString(MarketInfo(Symbol(), MODE_MINLOT), 2) + "). Setting position size to minimum.");
PositionSize = MarketInfo(Symbol(), MODE_MINLOT);
}
else if (PositionSize > MarketInfo(Symbol(), MODE_MAXLOT))
{
Print("Calculated position size (" + DoubleToString(PositionSize, 2) + ") is greater than maximum position size (" + DoubleToString(MarketInfo(Symbol(), MODE_MAXLOT), 2) + "). Setting position size to maximum.");
PositionSize = MarketInfo(Symbol(), MODE_MAXLOT);
}
double steps = PositionSize / LotStep;
if (MathFloor(steps) < steps)
{
Print("Calculated position size (" + DoubleToString(PositionSize, 2) + ") uses uneven step size. Allowed step size = " + DoubleToString(MarketInfo(Symbol(), MODE_LOTSTEP), 2) + ". Setting position size to " + DoubleToString(MathFloor(steps) * LotStep, 2) + ".");
PositionSize = MathFloor(steps) * LotStep;
}
return PositionSize;
}
//+-----------------------------------------------------------------------------------+
//| Calculates necessary adjustments for cases when ProfitCurrency != AccountCurrency.|
//+-----------------------------------------------------------------------------------+
#define FOREX_SYMBOLS_ONLY 0
#define NONFOREX_SYMBOLS_ONLY 1
double CalculateAdjustment()
{
double add_coefficient = 1; // Might be necessary for correction coefficient calculation if two pairs are used for profit currency to account currency conversion. This is handled differently in MT5 version.
if (ReferenceSymbol == NULL)
{
ReferenceSymbol = GetSymbolByCurrencies(ProfitCurrency, account_currency, FOREX_SYMBOLS_ONLY);
if (ReferenceSymbol == NULL) ReferenceSymbol = GetSymbolByCurrencies(ProfitCurrency, account_currency, NONFOREX_SYMBOLS_ONLY);
ReferenceSymbolMode = true;
// Failed.
if (ReferenceSymbol == NULL)
{
// Reversing currencies.
ReferenceSymbol = GetSymbolByCurrencies(account_currency, ProfitCurrency, FOREX_SYMBOLS_ONLY);
if (ReferenceSymbol == NULL) ReferenceSymbol = GetSymbolByCurrencies(account_currency, ProfitCurrency, NONFOREX_SYMBOLS_ONLY);
ReferenceSymbolMode = false;
}
if (ReferenceSymbol == NULL)
{
// The condition checks whether we are caclulating conversion coefficient for the chart's symbol or for some other.
// The error output is OK for the current symbol only because it won't be repeated ad infinitum.
// It should be avoided for non-chart symbols because it will just flood the log.
Print("Couldn't detect proper currency pair for adjustment calculation. Profit currency: ", ProfitCurrency, ". Account currency: ", account_currency, ". Trying to find a possible two-symbol combination.");
if ((FindDoubleReferenceSymbol("USD")) // USD should work in 99.9% of cases.
|| (FindDoubleReferenceSymbol("EUR")) // For very rare cases.
|| (FindDoubleReferenceSymbol("GBP")) // For extremely rare cases.
|| (FindDoubleReferenceSymbol("JPY"))) // For extremely rare cases.
{
Print("Converting via ", ReferenceSymbol, " and ", AdditionalReferenceSymbol, ".");
}
else
{
Print("Adjustment calculation critical failure. Failed both simple and two-pair conversion methods.");
return 1;
}
}
}
if (AdditionalReferenceSymbol != NULL) // If two reference pairs are used.
{
// Calculate just the additional symbol's coefficient and then use it in final return's multiplication.
MqlTick tick;
SymbolInfoTick(AdditionalReferenceSymbol, tick);
add_coefficient = GetCurrencyCorrectionCoefficient(tick, AdditionalReferenceSymbolMode);
}
MqlTick tick;
SymbolInfoTick(ReferenceSymbol, tick);
return GetCurrencyCorrectionCoefficient(tick, ReferenceSymbolMode) * add_coefficient;
}
//+---------------------------------------------------------------------------+
//| Returns a currency pair with specified base currency and profit currency. |
//+---------------------------------------------------------------------------+
string GetSymbolByCurrencies(const string base_currency, const string profit_currency, const uint symbol_type)
{
// Cycle through all symbols.
for (int s = 0; s < SymbolsTotal(false); s++)
{
// Get symbol name by number.
string symbolname = SymbolName(s, false);
string b_cur;
// Normal case - Forex pairs:
if (MarketInfo(symbolname, MODE_PROFITCALCMODE) == 0)
{
if (symbol_type == NONFOREX_SYMBOLS_ONLY) continue; // Avoid checking symbols of a wrong type.
// Get its base currency.
b_cur = SymbolInfoString(symbolname, SYMBOL_CURRENCY_BASE);
}
else // Weird case for brokers that set conversion pairs as CFDs.
{
if (symbol_type == FOREX_SYMBOLS_ONLY) continue; // Avoid checking symbols of a wrong type.
// Get its base currency as the initial three letters - prone to huge errors!
b_cur = StringSubstr(symbolname, 0, 3);
}
// Get its profit currency.
string p_cur = SymbolInfoString(symbolname, SYMBOL_CURRENCY_PROFIT);
// If the currency pair matches both currencies, select it in Market Watch and return its name.
if ((b_cur == base_currency) && (p_cur == profit_currency))
{
// Select if necessary.
if (!(bool)SymbolInfoInteger(symbolname, SYMBOL_SELECT)) SymbolSelect(symbolname, true);
return symbolname;
}
}
return NULL;
}
//+----------------------------------------------------------------------------+
//| Finds reference symbols using 2-pair method. |
//| Results are returned via reference parameters. |
//| Returns true if found the pairs, false otherwise. |
//+----------------------------------------------------------------------------+
bool FindDoubleReferenceSymbol(const string cross_currency)
{
// A hypothetical example for better understanding:
// The trader buys CAD/CHF.
// account_currency is known = SEK.
// cross_currency = USD.
// profit_currency = CHF.
// I.e., we have to buy dollars with francs (using the Ask price) and then sell those for SEKs (using the Bid price).
ReferenceSymbol = GetSymbolByCurrencies(cross_currency, account_currency, FOREX_SYMBOLS_ONLY);
if (ReferenceSymbol == NULL) ReferenceSymbol = GetSymbolByCurrencies(cross_currency, account_currency, NONFOREX_SYMBOLS_ONLY);
ReferenceSymbolMode = true; // If found, we've got USD/SEK.
// Failed.
if (ReferenceSymbol == NULL)
{
// Reversing currencies.
ReferenceSymbol = GetSymbolByCurrencies(account_currency, cross_currency, FOREX_SYMBOLS_ONLY);
if (ReferenceSymbol == NULL) ReferenceSymbol = GetSymbolByCurrencies(account_currency, cross_currency, NONFOREX_SYMBOLS_ONLY);
ReferenceSymbolMode = false; // If found, we've got SEK/USD.
}
if (ReferenceSymbol == NULL)
{
Print("Error. Couldn't detect proper currency pair for 2-pair adjustment calculation. Cross currency: ", cross_currency, ". Account currency: ", account_currency, ".");
return false;
}
AdditionalReferenceSymbol = GetSymbolByCurrencies(cross_currency, ProfitCurrency, FOREX_SYMBOLS_ONLY);
if (AdditionalReferenceSymbol == NULL) AdditionalReferenceSymbol = GetSymbolByCurrencies(cross_currency, ProfitCurrency, NONFOREX_SYMBOLS_ONLY);
AdditionalReferenceSymbolMode = false; // If found, we've got USD/CHF. Notice that mode is swapped for cross/profit compared to cross/acc, because it is used in the opposite way.
// Failed.
if (AdditionalReferenceSymbol == NULL)
{
// Reversing currencies.
AdditionalReferenceSymbol = GetSymbolByCurrencies(ProfitCurrency, cross_currency, FOREX_SYMBOLS_ONLY);
if (AdditionalReferenceSymbol == NULL) AdditionalReferenceSymbol = GetSymbolByCurrencies(ProfitCurrency, cross_currency, NONFOREX_SYMBOLS_ONLY);
AdditionalReferenceSymbolMode = true; // If found, we've got CHF/USD. Notice that mode is swapped for profit/cross compared to acc/cross, because it is used in the opposite way.
}
if (AdditionalReferenceSymbol == NULL)
{
Print("Error. Couldn't detect proper currency pair for 2-pair adjustment calculation. Cross currency: ", cross_currency, ". Chart's pair currency: ", ProfitCurrency, ".");
return false;
}
return true;
}
//+------------------------------------------------------------------+
//| Get profit correction coefficient based on current prices. |
//| Valid for loss calculation only. |
//+------------------------------------------------------------------+
double GetCurrencyCorrectionCoefficient(MqlTick &tick, const bool ref_symbol_mode)
{
if ((tick.ask == 0) || (tick.bid == 0)) return -1; // Data is not yet ready.
// Reverse quote.
if (ref_symbol_mode)
{
// Using Buy price for reverse quote.
return tick.ask;
}
// Direct quote.
else
{
// Using Sell price for direct quote.
return (1 / tick.bid);
}
}
//+------------------------------------------------------------------+
//| Counts decimal places. |
//+------------------------------------------------------------------+
int CountDecimalPlaces(double number)
{
// 100 as maximum length of number.
for (int i = 0; i < 100; i++)
{
double pwr = MathPow(10, i);
if (MathRound(number * pwr) / pwr == number) return i;
}
return -1;
}
//+------------------------------------------------------------------+
Binary file not shown.
+728
View File
@@ -0,0 +1,728 @@
//+------------------------------------------------------------------+
//| Amazing |
//| Copyright © 2023, EarnForex.com |
//| https://www.earnforex.com/ |
//| Based on the EA by FiFtHeLeMeNt. |
//+------------------------------------------------------------------+
#property copyright "Copyright © 2023, EarnForex"
#property link "https://www.earnforex.com/metatrader-expert-advisors/Amazing/"
#property version "1.04"
#property strict
#property description "Amazing - EA that helps to trade on news."
#property description "Set the NewsDateTime input parameter to the actual date and time of the news."
#property description "EA will set up the pending orders (buy and sell) to be triggered by the news."
#property description "It will use a profit target, breakeven, and trailing stop to manage it."
#include <stdlib.mqh>
input group "Main"
input datetime NewsDateTime = __DATE__; // NewsDateTime: Date and time of the news release.
input int EntryDistance = 100; // EntryDistance: Entry distance from recent high/low in points.
input int StopLoss = 200; // StopLoss: Stop-loss in points.
input int TakeProfit = 200; // TakeProfit: Take-profit in points.
input int CTCBN = 0; // CTCBN: Number of candles to check before news for High & Low.
input int SecBPO = 300; // SecBPO: Seconds before news to place pending orders.
input int SecBMO = 0; // SecBMO: Seconds before news when to stop modifying orders.
input int STWAN = 150; // STWAN: Seconds to wait after news to delete pending orders.
input bool OCO = true; // OCO: EA will cancel the other pending order if one is hit.
input int BEPoints = 0; // BEPoints: Points of profit when EA will move SL to breakeven + 1.
input int TrailingStop = 0; // Trailing Stop in points
input group "ATR"
input bool UseATR = false; // Use ATR-based stop-loss and take-profit levels.
input int ATR_Period = 14; // ATR Period.
input double ATR_Multiplier_SL = 5; // ATR multiplier for SL.
input double ATR_Multiplier_TP = 5; // ATR multiplier for TP.
input group "Money management"
input double Lots = 0.01;
input bool MM = true; // Money Management, if true - position sizing based on stop-loss.
input double Risk = 1; // Risk - Risk tolerance in percentage points.
input double FixedBalance = 0; // FixedBalance: If > 0, trade size calc. uses it as balance.
input double MoneyRisk = 0; // MoneyRisk: Risk tolerance in account currency.
input bool UseMoneyInsteadOfPercentage = false; // Use money risk instead of percentage.
input bool UseEquityInsteadOfBalance = false; // Use equity instead of balance.
input group "Miscellaneous"
input string TradeLog = "Am_Log_"; // TradeLog: Log file prefix.
input string Commentary = "Amazing"; // Commentary: trade description.
// Global variables:
double buy_stop_entry, sell_stop_entry, buy_stop_loss, sell_stop_loss, buy_take_profit, sell_take_profit;
int Magic;
string filename;
double SL, TP;
double RiskMoney;
// For tick value adjustment:
string ProfitCurrency = "", account_currency = "", BaseCurrency = "", ReferenceSymbol = NULL, AdditionalReferenceSymbol = NULL;
bool ReferenceSymbolMode, AdditionalReferenceSymbolMode;
int ProfitCalcMode;
void OnInit()
{
Magic = (int)NewsDateTime; // Dynamically generated Magic number to allow multiple instances for different news announcements.
double min_lot = SymbolInfoDouble(Symbol(), SYMBOL_VOLUME_MIN);
double lot_step = SymbolInfoDouble(Symbol(), SYMBOL_VOLUME_STEP);
Print("Minimum lot: ", DoubleToString(min_lot, 2), ", lot step: ", DoubleToString(lot_step, 2), ".");
if ((Lots < min_lot) && (!MM)) Alert("Lots should be not less than: ", DoubleToString(min_lot, 2), ".");
// If UseATR = false, these values will be used. Otherwise, ATR values will be calculated later.
SL = StopLoss;
TP = TakeProfit;
if (StringLen(Commentary) > 0) filename = TradeLog + Symbol() + "-" + IntegerToString(Month()) + "-" + IntegerToString(Day()) + ".txt";
else filename = ""; // Turning logging off.
}
void OnDeinit(const int reason)
{
Comment("");
}
// Result Pattern
// 1 1 1 1
// | | | |
// | | | -------- Sell Stop Order
// | | --------Buy Stop Order
// | --------Sell Position
// --------Buy Position
int CheckOrdersCondition()
{
int result = 0;
for (int i = 0; i < OrdersTotal(); i++)
{
if (!OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
{
Write(__FUNCTION__ + " | Error selecting an order: " + ErrorDescription(GetLastError()));
continue;
}
if ((OrderSymbol() != Symbol()) || (OrderMagicNumber() != Magic)) continue;
if (OrderType() == OP_BUY)
{
result = result + 1000;
}
else if (OrderType() == OP_SELL)
{
result = result + 100;
}
else if (OrderType() == OP_BUYSTOP)
{
result = result + 10;
}
else if (OrderType() == OP_SELLSTOP)
{
result = result + 1;
}
}
return result; // 0 means there are no trades.
}
void OpenBuyStop()
{
for (int tries = 0; tries < 10; tries++)
{
int ticket = OrderSend(Symbol(), OP_BUYSTOP, LotsOptimized(OP_BUY, buy_stop_entry), buy_stop_entry, 0, buy_stop_loss, buy_take_profit, Commentary, Magic);
if (ticket < 0)
{
Write("Error in OrderSend: " + ErrorDescription(GetLastError()) + " Buy Stop @ " + DoubleToString(buy_stop_entry, _Digits) + " SL @ " + DoubleToString(buy_stop_loss, _Digits) + " TP @" + DoubleToString(buy_take_profit, _Digits));
}
else
{
Write("Open Buy Stop: OrderSend executed. Ticket = " + IntegerToString(ticket));
break;
}
}
}
void OpenSellStop()
{
for (int tries = 0; tries < 10; tries++)
{
int ticket = OrderSend(Symbol(), OP_SELLSTOP, LotsOptimized(OP_SELL, sell_stop_entry), sell_stop_entry, 0, sell_stop_loss, sell_take_profit, Commentary, Magic);
if (ticket < 0)
{
Write("Error in OrderSend: " + ErrorDescription(GetLastError()) + " Sell Stop @ " + DoubleToString(sell_stop_entry, _Digits) + " SL @ " + DoubleToString(sell_stop_loss, _Digits) + " TP @" + DoubleToString(sell_take_profit, _Digits));
}
else
{
Write("Open Sell Stop: OrderSend executed. Ticket = " + IntegerToString(ticket));
break;
}
}
}
// Set breakeven on positions if needed.
void DoBE(int byPoints)
{
for (int i = 0; i < OrdersTotal(); i++)
{
if (!OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
{
Write(__FUNCTION__ + " | Error selecting an order: " + ErrorDescription(GetLastError()));
continue;
}
if ((OrderSymbol() != Symbol()) || (OrderMagicNumber() != Magic)) continue;
if ((OrderType() == OP_BUY) && (NormalizeDouble(Bid - OrderOpenPrice(), _Digits) > NormalizeDouble(byPoints * _Point, _Digits)) && (OrderStopLoss() < OrderOpenPrice()))
{
Write("Moving stop-loss of Buy order to breakeven + 1 point.");
if (!OrderModify(OrderTicket(), OrderOpenPrice(), OrderOpenPrice() + _Point, OrderTakeProfit(), OrderExpiration()))
{
Write(__FUNCTION__ + " | Error modifying Buy: " + ErrorDescription(GetLastError()));
}
}
else if ((OrderType() == OP_SELL) && (NormalizeDouble(OrderOpenPrice() - Ask, _Digits) > NormalizeDouble(byPoints * _Point, _Digits)) && (OrderStopLoss() > OrderOpenPrice()))
{
Write("Moving stop-loss of Sell order to breakeven - 1 point.");
if (!OrderModify(OrderTicket(), OrderOpenPrice(), OrderOpenPrice() - _Point, OrderTakeProfit(), OrderExpiration()))
{
Write(__FUNCTION__ + " | Error modifying Sell: " + ErrorDescription(GetLastError()));
}
}
}
}
// Trailing stop for open positions.
void DoTrail()
{
for (int i = 0; i < OrdersTotal(); i++)
{
if (!OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
{
Write(__FUNCTION__ + " | Error selecting an order: " + ErrorDescription(GetLastError()));
continue;
}
if ((OrderSymbol() != Symbol()) || (OrderMagicNumber() != Magic)) continue;
if (OrderType() == OP_BUY)
{
if (Bid - OrderOpenPrice() > _Point * TrailingStop)
{
if (OrderStopLoss() < NormalizeDouble(Bid - _Point * TrailingStop, _Digits))
{
if (!OrderModify(OrderTicket(), OrderOpenPrice(), Bid - _Point * TrailingStop, OrderTakeProfit(), OrderExpiration()))
{
Write(__FUNCTION__ + " | Error modifying Buy: " + ErrorDescription(GetLastError()));
}
}
}
}
else if (OrderType() == OP_SELL)
{
if (OrderOpenPrice() - Ask > _Point * TrailingStop)
{
if ((OrderStopLoss() > NormalizeDouble(Ask + _Point * TrailingStop, _Digits)) || (OrderStopLoss() == 0))
{
if (!OrderModify(OrderTicket(), OrderOpenPrice(), Ask + _Point * TrailingStop, OrderTakeProfit(), OrderExpiration()))
{
Write(__FUNCTION__ + " | Error modifying Sell: " + ErrorDescription(GetLastError()));
}
}
}
}
}
}
void DeleteBuyStop()
{
for (int i = 0; i < OrdersTotal(); i++) // The order of cycle doesn't matter as only one order will be deleted.
{
if (!OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
{
Write(__FUNCTION__ + " | Error selecting an order: " + ErrorDescription(GetLastError()));
continue;
}
if ((OrderSymbol() != Symbol()) || (OrderMagicNumber() != Magic)) continue;
if (OrderType() == OP_BUYSTOP)
{
if (!OrderDelete(OrderTicket()))
{
Write("Error deleting Buy Stop: " + ErrorDescription(GetLastError()));
}
else Write("Buy Stop order deleted.");
return;
}
}
}
void DeleteSellStop()
{
for (int i = 0; i < OrdersTotal(); i++)
{
if (!OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
{
Write(__FUNCTION__ + " | Error selecting an order: " + ErrorDescription(GetLastError()));
continue;
}
if ((OrderSymbol() != Symbol()) || (OrderMagicNumber() != Magic)) continue;
if (OrderType() == OP_SELLSTOP)
{
if (!OrderDelete(OrderTicket()))
{
Write("Error deleting Sell Stop: " + ErrorDescription(GetLastError()));
}
else Write("Sell Stop order deleted.");
return;
}
}
}
// Update pending stop orders according to new price levels.
void DoModify()
{
for (int i = 0; i < OrdersTotal(); i++)
{
if (!OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
{
Write(__FUNCTION__ + " | Error selecting an order: " + ErrorDescription(GetLastError()));
continue;
}
if ((OrderSymbol() != Symbol()) || (OrderMagicNumber() != Magic)) continue;
if (OrderType() == OP_BUYSTOP)
{
if (OrderOpenPrice() != buy_stop_entry)
{
if (!OrderModify(OrderTicket(), buy_stop_entry, buy_stop_loss, buy_take_profit, OrderExpiration()))
{
Write(__FUNCTION__ + " | Error modifying Buy Stop: " + ErrorDescription(GetLastError()));
}
else Write("Buy Stop OrderModify executed: " + DoubleToString(OrderOpenPrice(), _Digits) + " -> " + DoubleToString(buy_stop_entry, _Digits));
}
}
if (OrderType() == OP_SELLSTOP)
{
if (OrderOpenPrice() != sell_stop_entry)
{
if (!OrderModify(OrderTicket(), sell_stop_entry, sell_stop_loss, sell_take_profit, OrderExpiration()))
{
Write(__FUNCTION__ + " | Error modifying Sell Stop: " + ErrorDescription(GetLastError()));
}
else Write("Sell Stop OrderModify executed: " + DoubleToString(OrderOpenPrice(), _Digits) + " -> " + DoubleToString(sell_stop_entry, _Digits));
}
}
}
}
// Prints a string and writes it to a log file too.
void Write(string str)
{
Print(str);
if (filename == "") return;
int handle = FileOpen(filename, FILE_READ | FILE_WRITE | FILE_TXT);
if (handle == INVALID_HANDLE)
{
Print("Error opening file ", filename, ": ", ErrorDescription(GetLastError()));
return;
}
FileSeek(handle, 0, SEEK_END);
FileWrite(handle, str + " Time " + TimeToStr(CurTime(), TIME_DATE | TIME_SECONDS));
FileClose(handle);
}
void OnTick()
{
if (BEPoints > 0) DoBE(BEPoints);
if (TrailingStop > 0) DoTrail();
int OrdersCondition = CheckOrdersCondition();
// Find recent High/Low for pre-news orders.
double recent_high = iHigh(NULL, PERIOD_M1, 0);
double recent_low = iLow(NULL, PERIOD_M1, 0);
for (int i = 1; i <= CTCBN; i++)
{
if (iHigh(NULL, PERIOD_M1, i) > recent_high) recent_high = iHigh(NULL, PERIOD_M1, i);
if (iLow(NULL, PERIOD_M1, i) < recent_low) recent_low = iLow(NULL, PERIOD_M1, i);
}
double spread = Ask - Bid;
buy_stop_entry = NormalizeDouble(recent_high + spread + EntryDistance * _Point, _Digits);
sell_stop_entry = NormalizeDouble(recent_low - EntryDistance * _Point, _Digits);
if (UseATR)
{
// Getting the ATR values
double ATR = iATR(NULL, 0, ATR_Period, 0);
SL = ATR * ATR_Multiplier_SL;
if (SL <= (SymbolInfoInteger(Symbol(), SYMBOL_TRADE_STOPS_LEVEL) + SymbolInfoInteger(Symbol(), SYMBOL_SPREAD)) * Point) SL = (SymbolInfoInteger(Symbol(), SYMBOL_TRADE_STOPS_LEVEL) + SymbolInfoInteger(Symbol(), SYMBOL_SPREAD)) * Point;
TP = ATR * ATR_Multiplier_TP;
if (TP <= (SymbolInfoInteger(Symbol(), SYMBOL_TRADE_STOPS_LEVEL) + SymbolInfoInteger(Symbol(), SYMBOL_SPREAD)) * Point) TP = (SymbolInfoInteger(Symbol(), SYMBOL_TRADE_STOPS_LEVEL) + SymbolInfoInteger(Symbol(), SYMBOL_SPREAD)) * Point;
SL /= Point;
TP /= Point;
}
buy_stop_loss = NormalizeDouble(buy_stop_entry - SL * _Point, _Digits);
sell_stop_loss = NormalizeDouble(sell_stop_entry + SL * _Point, _Digits);
buy_take_profit = NormalizeDouble(buy_stop_entry + TP * _Point, _Digits);
sell_take_profit= NormalizeDouble(sell_stop_entry - TP * _Point, _Digits);
int sectonews = (int)(NewsDateTime - TimeCurrent());
Comment("\nAmazing Expert Advisor",
"\nHigh @ ", recent_high, " Buy Order @ ", buy_stop_entry, " Stop-loss @ ", buy_stop_loss, " Take-profit @ ", buy_take_profit,
"\nLow @ ", recent_low, " Sell Order @ ", sell_stop_entry, " Stop-loss @ ", sell_stop_loss, " Take-profit @ ", sell_take_profit,
"\nNews time: ", TimeToString(NewsDateTime),
"\nCurrent time: ", TimeToString(TimeCurrent()),
"\nSeconds left to news: ", IntegerToString(sectonews),
"\nCTCBN: ", CTCBN, " SecBPO: ", SecBPO, " SecBMO: ", SecBMO, " STWAN: ", STWAN, " OCO: ", OCO, " BEPips: ", BEPoints,
"\nMoney management: ", MM, " Risk: ", DoubleToString(RiskMoney, 2), " ", AccountCurrency(), " Lots (B/S): ", DoubleToString(LotsOptimized(OP_BUY, buy_stop_entry), 2), "/", DoubleToString(LotsOptimized(OP_SELL, sell_stop_entry), 2));
// Before the news, but after the time when orders have to be placed.
if ((TimeCurrent() < NewsDateTime) && (TimeCurrent() >= NewsDateTime - SecBPO))
{
if (OrdersCondition == 0) // No orders.
{
Write("Opening Buy Stop and Sell Stop. OrdersCondition = " + IntegerToString(OrdersCondition) + " Timestamp = " + TimeToString(TimeCurrent(), TIME_DATE|TIME_SECONDS) + ".");
OpenBuyStop();
OpenSellStop();
}
else if (OrdersCondition == 10)
{
Write("Opening Sell Stop. OrdersCondition = " + IntegerToString(OrdersCondition) + " Timestamp = " + TimeToString(TimeCurrent(), TIME_DATE|TIME_SECONDS) + ".");
OpenSellStop();
}
else if (OrdersCondition == 1)
{
Write("Opening Buy Stop. OrdersCondition = " + IntegerToString(OrdersCondition) + " Timestamp = " + TimeToString(TimeCurrent(), TIME_DATE|TIME_SECONDS) + ".");
OpenBuyStop();
}
}
// Still have time to modify the orders.
if ((TimeCurrent() < NewsDateTime) && (TimeCurrent() >= NewsDateTime - SecBPO) && (TimeCurrent() < NewsDateTime - SecBMO))
{
Write("Modifying orders. OrdersCondition = " + IntegerToString(OrdersCondition) + " Timestamp = " + TimeToString(TimeCurrent(), TIME_DATE|TIME_SECONDS) + ".");
DoModify();
}
// News announcement already happened, but it is too early to delete all untriggered orders, yet the EA has to delete the untriggered one due to OCO if the opposite was hit.
if ((TimeCurrent() > NewsDateTime) && (TimeCurrent() < NewsDateTime + STWAN) && (OCO))
{
if (OrdersCondition == 1001)
{
Write("Deleting Sell Stop because Buy Stop was hit. OrdersCondition = " + IntegerToString(OrdersCondition) + " Timestamp = " + TimeToString(TimeCurrent(), TIME_DATE|TIME_SECONDS) + ".");
DeleteSellStop();
}
else if (OrdersCondition == 110)
{
Write("Deleting Buy Stop because Sell Stop was hit. OrdersCondition=" + IntegerToString(OrdersCondition) + " Timestamp=" + TimeToString(TimeCurrent(), TIME_DATE|TIME_SECONDS) + ".");
DeleteBuyStop();
}
}
// News has passed and it is time to delete untriggered orders.
if ((TimeCurrent() > NewsDateTime) && (TimeCurrent() > NewsDateTime + STWAN))
{
if (OrdersCondition == 11)
{
Write("Deleting Buy Stop and Sell Stop because time expired. OrdersCondition = " + IntegerToString(OrdersCondition) + " Timestamp=" + TimeToString(TimeCurrent(), TIME_DATE|TIME_SECONDS) + ".");
DeleteBuyStop();
DeleteSellStop();
}
if ((OrdersCondition == 10) || (OrdersCondition == 110))
{
Write("Deleting BuyStop Because expired, OrdersCondition=" + IntegerToString(OrdersCondition) + " Timestamp = " + TimeToString(TimeCurrent(), TIME_DATE|TIME_SECONDS) + ".");
DeleteBuyStop();
}
if ((OrdersCondition == 1) || (OrdersCondition == 1001))
{
Write("Deleting SellStop Because expired, OrdersCondition=" + IntegerToString(OrdersCondition) + " Timestamp = " + TimeToString(TimeCurrent(), TIME_DATE|TIME_SECONDS) + ".");
DeleteSellStop();
}
}
}
//+------------------------------------------------------------------+
//| Calculate position size depending on money management parameters.|
//+------------------------------------------------------------------+
double LotsOptimized(int dir, double entry)
{
if (!MM) return Lots;
double Size, PositionSize = 0, UnitCost;
ProfitCurrency = SymbolInfoString(Symbol(), SYMBOL_CURRENCY_PROFIT);
BaseCurrency = SymbolInfoString(Symbol(), SYMBOL_CURRENCY_BASE);
ProfitCalcMode = (int)MarketInfo(Symbol(), MODE_PROFITCALCMODE);
account_currency = AccountCurrency();
// A rough patch for cases when account currency is set as RUR instead of RUB.
if (account_currency == "RUR") account_currency = "RUB";
if (ProfitCurrency == "RUR") ProfitCurrency = "RUB";
if (BaseCurrency == "RUR") BaseCurrency = "RUB";
double LotStep = MarketInfo(Symbol(), MODE_LOTSTEP);
int LotStep_digits = CountDecimalPlaces(LotStep);
if (AccountCurrency() == "") return 0;
if (FixedBalance > 0)
{
Size = FixedBalance;
}
else if (UseEquityInsteadOfBalance)
{
Size = AccountEquity();
}
else
{
Size = AccountBalance();
}
if (!UseMoneyInsteadOfPercentage) RiskMoney = Size * Risk / 100;
else RiskMoney = MoneyRisk;
// If Symbol is CFD.
if (ProfitCalcMode == 1)
UnitCost = SymbolInfoDouble(Symbol(), SYMBOL_TRADE_TICK_SIZE) * SymbolInfoDouble(Symbol(), SYMBOL_TRADE_CONTRACT_SIZE); // Apparently, it is more accurate than taking TICKVALUE directly in some cases.
else UnitCost = MarketInfo(Symbol(), MODE_TICKVALUE); // Futures or Forex.
if (ProfitCalcMode != 0) // Non-Forex might need to be adjusted.
{
// If profit currency is different from account currency.
if (ProfitCurrency != account_currency)
{
double CCC = CalculateAdjustment(); // Valid only for loss calculation.
// Adjust the unit cost.
UnitCost *= CCC;
}
}
// If account currency == pair's base currency, adjust UnitCost to future rate (SL). Works only for Forex pairs.
if ((account_currency == BaseCurrency) && (ProfitCalcMode == 0))
{
double current_rate = 1, future_rate = 1;
RefreshRates();
if (dir == OP_BUY)
{
if (entry == 0) current_rate = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
else current_rate = entry;
future_rate = current_rate - SL * _Point;
}
else if (dir == OP_SELL)
{
if (entry == 0) current_rate = SymbolInfoDouble(_Symbol, SYMBOL_BID);
else current_rate = entry;
future_rate = current_rate + SL * _Point;
}
if (future_rate == 0) future_rate = _Point; // Zero divide prevention.
UnitCost *= (current_rate / future_rate);
}
double TickSize = MarketInfo(Symbol(), MODE_TICKSIZE);
if ((SL != 0) && (UnitCost != 0) && (TickSize != 0)) PositionSize = NormalizeDouble(RiskMoney / (SL * _Point * UnitCost / TickSize), LotStep_digits);
if (PositionSize < MarketInfo(Symbol(), MODE_MINLOT))
{
Print("Calculated position size (" + DoubleToString(PositionSize, 2) + ") is less than minimum position size (" + DoubleToString(MarketInfo(Symbol(), MODE_MINLOT), 2) + "). Setting position size to minimum.");
PositionSize = MarketInfo(Symbol(), MODE_MINLOT);
}
else if (PositionSize > MarketInfo(Symbol(), MODE_MAXLOT))
{
Print("Calculated position size (" + DoubleToString(PositionSize, 2) + ") is greater than maximum position size (" + DoubleToString(MarketInfo(Symbol(), MODE_MAXLOT), 2) + "). Setting position size to maximum.");
PositionSize = MarketInfo(Symbol(), MODE_MAXLOT);
}
double steps = PositionSize / LotStep;
if (MathAbs(MathRound(steps) - steps) < 0.00000001) steps = MathRound(steps);
if (steps - MathFloor(steps) > 0.5)
{
Print(steps, " ", MathFloor(steps));
Print("Calculated position size (" + DoubleToString(PositionSize, 2) + ") uses uneven step size. Allowed step size = " + DoubleToString(MarketInfo(Symbol(), MODE_LOTSTEP), 2) + ". Setting position size to " + DoubleToString(MathFloor(steps) * LotStep, 2) + ".");
PositionSize = MathFloor(steps) * LotStep;
}
return PositionSize;
}
//+-----------------------------------------------------------------------------------+
//| Calculates necessary adjustments for cases when ProfitCurrency != AccountCurrency.|
//+-----------------------------------------------------------------------------------+
#define FOREX_SYMBOLS_ONLY 0
#define NONFOREX_SYMBOLS_ONLY 1
double CalculateAdjustment()
{
double add_coefficient = 1; // Might be necessary for correction coefficient calculation if two pairs are used for profit currency to account currency conversion. This is handled differently in MT5 version.
if (ReferenceSymbol == NULL)
{
ReferenceSymbol = GetSymbolByCurrencies(ProfitCurrency, account_currency, FOREX_SYMBOLS_ONLY);
if (ReferenceSymbol == NULL) ReferenceSymbol = GetSymbolByCurrencies(ProfitCurrency, account_currency, NONFOREX_SYMBOLS_ONLY);
ReferenceSymbolMode = true;
// Failed.
if (ReferenceSymbol == NULL)
{
// Reversing currencies.
ReferenceSymbol = GetSymbolByCurrencies(account_currency, ProfitCurrency, FOREX_SYMBOLS_ONLY);
if (ReferenceSymbol == NULL) ReferenceSymbol = GetSymbolByCurrencies(account_currency, ProfitCurrency, NONFOREX_SYMBOLS_ONLY);
ReferenceSymbolMode = false;
}
if (ReferenceSymbol == NULL)
{
// The condition checks whether we are caclulating conversion coefficient for the chart's symbol or for some other.
// The error output is OK for the current symbol only because it won't be repeated ad infinitum.
// It should be avoided for non-chart symbols because it will just flood the log.
Print("Couldn't detect proper currency pair for adjustment calculation. Profit currency: ", ProfitCurrency, ". Account currency: ", account_currency, ". Trying to find a possible two-symbol combination.");
if ((FindDoubleReferenceSymbol("USD")) // USD should work in 99.9% of cases.
|| (FindDoubleReferenceSymbol("EUR")) // For very rare cases.
|| (FindDoubleReferenceSymbol("GBP")) // For extremely rare cases.
|| (FindDoubleReferenceSymbol("JPY"))) // For extremely rare cases.
{
Print("Converting via ", ReferenceSymbol, " and ", AdditionalReferenceSymbol, ".");
}
else
{
Print("Adjustment calculation critical failure. Failed both simple and two-pair conversion methods.");
return 1;
}
}
}
if (AdditionalReferenceSymbol != NULL) // If two reference pairs are used.
{
// Calculate just the additional symbol's coefficient and then use it in final return's multiplication.
MqlTick tick;
SymbolInfoTick(AdditionalReferenceSymbol, tick);
add_coefficient = GetCurrencyCorrectionCoefficient(tick, AdditionalReferenceSymbolMode);
}
MqlTick tick;
SymbolInfoTick(ReferenceSymbol, tick);
return GetCurrencyCorrectionCoefficient(tick, ReferenceSymbolMode) * add_coefficient;
}
//+---------------------------------------------------------------------------+
//| Returns a currency pair with specified base currency and profit currency. |
//+---------------------------------------------------------------------------+
string GetSymbolByCurrencies(const string base_currency, const string profit_currency, const uint symbol_type)
{
// Cycle through all symbols.
for (int s = 0; s < SymbolsTotal(false); s++)
{
// Get symbol name by number.
string symbolname = SymbolName(s, false);
string b_cur;
// Normal case - Forex pairs:
if (MarketInfo(symbolname, MODE_PROFITCALCMODE) == 0)
{
if (symbol_type == NONFOREX_SYMBOLS_ONLY) continue; // Avoid checking symbols of a wrong type.
// Get its base currency.
b_cur = SymbolInfoString(symbolname, SYMBOL_CURRENCY_BASE);
}
else // Weird case for brokers that set conversion pairs as CFDs.
{
if (symbol_type == FOREX_SYMBOLS_ONLY) continue; // Avoid checking symbols of a wrong type.
// Get its base currency as the initial three letters - prone to huge errors!
b_cur = StringSubstr(symbolname, 0, 3);
}
// Get its profit currency.
string p_cur = SymbolInfoString(symbolname, SYMBOL_CURRENCY_PROFIT);
// If the currency pair matches both currencies, select it in Market Watch and return its name.
if ((b_cur == base_currency) && (p_cur == profit_currency))
{
// Select if necessary.
if (!(bool)SymbolInfoInteger(symbolname, SYMBOL_SELECT)) SymbolSelect(symbolname, true);
return symbolname;
}
}
return NULL;
}
//+----------------------------------------------------------------------------+
//| Finds reference symbols using 2-pair method. |
//| Results are returned via reference parameters. |
//| Returns true if found the pairs, false otherwise. |
//+----------------------------------------------------------------------------+
bool FindDoubleReferenceSymbol(const string cross_currency)
{
// A hypothetical example for better understanding:
// The trader buys CAD/CHF.
// account_currency is known = SEK.
// cross_currency = USD.
// profit_currency = CHF.
// I.e., we have to buy dollars with francs (using the Ask price) and then sell those for SEKs (using the Bid price).
ReferenceSymbol = GetSymbolByCurrencies(cross_currency, account_currency, FOREX_SYMBOLS_ONLY);
if (ReferenceSymbol == NULL) ReferenceSymbol = GetSymbolByCurrencies(cross_currency, account_currency, NONFOREX_SYMBOLS_ONLY);
ReferenceSymbolMode = true; // If found, we've got USD/SEK.
// Failed.
if (ReferenceSymbol == NULL)
{
// Reversing currencies.
ReferenceSymbol = GetSymbolByCurrencies(account_currency, cross_currency, FOREX_SYMBOLS_ONLY);
if (ReferenceSymbol == NULL) ReferenceSymbol = GetSymbolByCurrencies(account_currency, cross_currency, NONFOREX_SYMBOLS_ONLY);
ReferenceSymbolMode = false; // If found, we've got SEK/USD.
}
if (ReferenceSymbol == NULL)
{
Print("Error. Couldn't detect proper currency pair for 2-pair adjustment calculation. Cross currency: ", cross_currency, ". Account currency: ", account_currency, ".");
return false;
}
AdditionalReferenceSymbol = GetSymbolByCurrencies(cross_currency, ProfitCurrency, FOREX_SYMBOLS_ONLY);
if (AdditionalReferenceSymbol == NULL) AdditionalReferenceSymbol = GetSymbolByCurrencies(cross_currency, ProfitCurrency, NONFOREX_SYMBOLS_ONLY);
AdditionalReferenceSymbolMode = false; // If found, we've got USD/CHF. Notice that mode is swapped for cross/profit compared to cross/acc, because it is used in the opposite way.
// Failed.
if (AdditionalReferenceSymbol == NULL)
{
// Reversing currencies.
AdditionalReferenceSymbol = GetSymbolByCurrencies(ProfitCurrency, cross_currency, FOREX_SYMBOLS_ONLY);
if (AdditionalReferenceSymbol == NULL) AdditionalReferenceSymbol = GetSymbolByCurrencies(ProfitCurrency, cross_currency, NONFOREX_SYMBOLS_ONLY);
AdditionalReferenceSymbolMode = true; // If found, we've got CHF/USD. Notice that mode is swapped for profit/cross compared to acc/cross, because it is used in the opposite way.
}
if (AdditionalReferenceSymbol == NULL)
{
Print("Error. Couldn't detect proper currency pair for 2-pair adjustment calculation. Cross currency: ", cross_currency, ". Chart's pair currency: ", ProfitCurrency, ".");
return false;
}
return true;
}
//+------------------------------------------------------------------+
//| Get profit correction coefficient based on current prices. |
//| Valid for loss calculation only. |
//+------------------------------------------------------------------+
double GetCurrencyCorrectionCoefficient(MqlTick &tick, const bool ref_symbol_mode)
{
if ((tick.ask == 0) || (tick.bid == 0)) return -1; // Data is not yet ready.
// Reverse quote.
if (ref_symbol_mode)
{
// Using Buy price for reverse quote.
return tick.ask;
}
// Direct quote.
else
{
// Using Sell price for direct quote.
return (1 / tick.bid);
}
}
//+------------------------------------------------------------------+
//| Counts decimal places. |
//+------------------------------------------------------------------+
int CountDecimalPlaces(double number)
{
// 100 as maximum length of number.
for (int i = 0; i < 100; i++)
{
double pwr = MathPow(10, i);
if (MathRound(number * pwr) / pwr == number) return i;
}
return -1;
}
//+------------------------------------------------------------------+
Binary file not shown.
+174
View File
@@ -0,0 +1,174 @@
//+------------------------------------------------------------------+
//| Binario.mq4 |
//| Copyright © 2008-2022, EarnForex.com |
//| https://www.earnforex.com/ |
//| Based on the EA by don_forex. |
//+------------------------------------------------------------------+
#property copyright "Copyright © 2008-2022, EarnForex"
#property link "https://www.earnforex.com/metatrader-expert-advisors/Binario/"
#property version "1.01"
#property strict
#property description "Uses a band of two same period MAs - one over High prices, one over Low prices."
#property description "A breakout from within the bands triggers a trade."
input group "Main"
input int MA_Period = 144; // MA Period
input ENUM_MA_METHOD MA_Method = MODE_EMA; // MA Method
input int TakeProfit = 100;
input int PipDifference = 25; // PipDifference: distance from MA for breakout.
input group "Money management"
input double Lots = 0.1; // Lots: Fixed position size.
input double MaximumRisk = 2; // MaximumRisk: Position sizing increase coefficient. 0 - disable.
input group "Miscellaneous"
input int Slippage = 3;
input string OrderCommentary = "Binario";
input int Magic = 16384;
double Poin;
void OnInit()
{
// Checking for unconvetional Point digits number.
if (Point == 0.00001) Poin = 0.0001; // 5 digits.
else if (Point == 0.001) Poin = 0.01; // 3 digits.
else Poin = Point; // Normal.
}
void OnTick()
{
if (Bars(Symbol(), Period()) < 144)
{
Print("Fewer than 144 bars on the chart. Trading disabled.");
return;
}
double MA144H = MathRound(iMA(NULL, 0, 144, 0, MODE_EMA, PRICE_HIGH, 0) / Poin) * Poin;
double MA144L = MathRound(iMA(NULL, 0, 144, 0, MODE_EMA, PRICE_LOW, 0) / Poin) * Poin;
double Spread = Ask - Bid;
double BuyPrice = NormalizeDouble(MA144H + Spread + PipDifference * Poin, _Digits);
double BuyStopLoss = NormalizeDouble(MA144L - Poin, _Digits);
double BuyTakeProfit = NormalizeDouble(MA144H + (PipDifference + TakeProfit) * Poin, _Digits);
double SellPrice = NormalizeDouble(MA144L - (PipDifference) * Poin, _Digits);
double SellStopLoss = NormalizeDouble(MA144H + Spread + Poin, _Digits);
double SellTakeProfit = NormalizeDouble(MA144L - Spread - (PipDifference + TakeProfit) * Poin, _Digits);
double Lot = Lots;
if (MaximumRisk > 0) // Use increasing position size.
{
int LotStep_digits = CountDecimalPlaces(SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_STEP));
Lot = NormalizeDouble(AccountInfoDouble(ACCOUNT_MARGIN_FREE) * MaximumRisk / 50000, LotStep_digits);
}
if (Lot < SymbolInfoDouble(Symbol(), SYMBOL_VOLUME_MIN)) Lot = SymbolInfoDouble(Symbol(), SYMBOL_VOLUME_MIN);
if (Lot > SymbolInfoDouble(Symbol(), SYMBOL_VOLUME_MAX)) Lot = SymbolInfoDouble(Symbol(), SYMBOL_VOLUME_MAX);
bool need_long = true;
bool need_short = true;
int total = OrdersTotal();
for (int cnt = 0; cnt < total; cnt++)
{
if (!OrderSelect(cnt, SELECT_BY_POS, MODE_TRADES))
{
Print("OrderSelect() failed. Error: ", GetLastError());
continue;
}
if ((OrderSymbol() != Symbol()) || (OrderMagicNumber() != Magic)) continue;
if (OrderType() == OP_BUYSTOP)
{
need_long = false;
if (OrderStopLoss() != BuyStopLoss)
{
if (!OrderModify(OrderTicket(), BuyPrice, BuyStopLoss, BuyTakeProfit, 0))
{
Print("OrderModify() failed. Error: ", GetLastError());
}
}
}
else if (OrderType() == OP_SELLSTOP)
{
need_short = false;
if (OrderStopLoss() != SellStopLoss)
{
if (!OrderModify(OrderTicket(), SellPrice, SellStopLoss, SellTakeProfit, 0))
{
Print("OrderModify() failed. Error: ", GetLastError());
}
}
}
else if (OrderType() == OP_BUY)
{
need_long = false;
if (OrderStopLoss() < BuyStopLoss)
{
if (!OrderModify(OrderTicket(), OrderOpenPrice(), BuyStopLoss, BuyTakeProfit, 0))
{
Print("OrderModify() failed. Error: ", GetLastError());
}
}
}
else if (OrderType() == OP_SELL)
{
need_short = false;
if (OrderStopLoss() > SellStopLoss)
{
if (!OrderModify(OrderTicket(), OrderOpenPrice(), SellStopLoss, SellTakeProfit, 0))
{
Print("OrderModify() failed. Error: ", GetLastError());
}
}
}
}
if (AccountFreeMargin() < (1000 * Lot))
{
Print("No money. Free margin = ", AccountFreeMargin());
return;
}
if ((Bid < MA144H) && (Bid > MA144L)) // Inside the MA bands.
{
if (need_long)
{
for (int i = 0; i < 10; i++) // 10 attempts.
{
int ticket = OrderSend(Symbol(), OP_BUYSTOP, Lot, BuyPrice, Slippage, BuyStopLoss, BuyTakeProfit, OrderCommentary, Magic, 0, clrGreen);
if (ticket == -1)
{
Print("OrderSend() failed. Error: ", GetLastError());
}
else break;
}
}
else if (need_short)
{
for (int i = 0; i < 10; i++) // 10 attempts.
{
int ticket = OrderSend(Symbol(), OP_SELLSTOP, Lot, SellPrice, Slippage, SellStopLoss, SellTakeProfit, OrderCommentary, Magic, 0, clrRed);
if (ticket == -1)
{
Print("OrderSend() failed. Error: ", GetLastError());
}
else break;
}
}
}
}
//+------------------------------------------------------------------+
//| Counts decimal places. |
//+------------------------------------------------------------------+
int CountDecimalPlaces(double number)
{
// 100 as maximum length of number.
for (int i = 0; i < 100; i++)
{
double pwr = MathPow(10, i);
if (MathRound(number * pwr) / pwr == number) return i;
}
return -1;
}
//+------------------------------------------------------------------+
Binary file not shown.
Binary file not shown.
Binary file not shown.

Some files were not shown because too many files have changed in this diff Show More