Fix invalid price errors - add stop level validation
This commit is contained in:
@@ -353,8 +353,23 @@ bool PlaceBuyStop(double priceLevel, int level)
|
|||||||
|
|
||||||
double lots = CalcLots();
|
double lots = CalcLots();
|
||||||
double point = SymbolInfoDouble(_Symbol, SYMBOL_POINT);
|
double point = SymbolInfoDouble(_Symbol, SYMBOL_POINT);
|
||||||
double sl = (StopLoss > 0) ? priceLevel - (StopLoss * point) : 0;
|
double currentAsk = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
|
||||||
double tp = priceLevel + (TP * point);
|
double stopLevel = SymbolInfoInteger(_Symbol, SYMBOL_TRADE_STOPS_LEVEL) * point;
|
||||||
|
|
||||||
|
// Ensure price is above current Ask + stop level
|
||||||
|
double minDistance = currentAsk + stopLevel + (Entry * point);
|
||||||
|
if(priceLevel < minDistance)
|
||||||
|
{
|
||||||
|
Print("Buy Stop too close to price. Adjusting from ", priceLevel, " to ", minDistance);
|
||||||
|
priceLevel = minDistance;
|
||||||
|
}
|
||||||
|
|
||||||
|
double sl = (StopLoss > 0) ? NormalizeDouble(priceLevel - (StopLoss * point), _Digits) : 0;
|
||||||
|
double tp = NormalizeDouble(priceLevel + (TP * point), _Digits);
|
||||||
|
|
||||||
|
// Ensure TP is valid distance from price
|
||||||
|
if(tp <= priceLevel + stopLevel)
|
||||||
|
tp = NormalizeDouble(priceLevel + stopLevel + (TP * point), _Digits);
|
||||||
|
|
||||||
MqlTradeRequest request = {};
|
MqlTradeRequest request = {};
|
||||||
MqlTradeResult result = {};
|
MqlTradeResult result = {};
|
||||||
@@ -362,7 +377,7 @@ bool PlaceBuyStop(double priceLevel, int level)
|
|||||||
request.action = TRADE_ACTION_PENDING;
|
request.action = TRADE_ACTION_PENDING;
|
||||||
request.symbol = _Symbol;
|
request.symbol = _Symbol;
|
||||||
request.volume = lots;
|
request.volume = lots;
|
||||||
request.price = priceLevel;
|
request.price = NormalizeDouble(priceLevel, _Digits);
|
||||||
request.sl = sl;
|
request.sl = sl;
|
||||||
request.tp = tp;
|
request.tp = tp;
|
||||||
request.deviation = 10;
|
request.deviation = 10;
|
||||||
@@ -371,16 +386,18 @@ bool PlaceBuyStop(double priceLevel, int level)
|
|||||||
request.type = ORDER_TYPE_BUY_STOP;
|
request.type = ORDER_TYPE_BUY_STOP;
|
||||||
request.type_filling = ORDER_FILLING_IOC;
|
request.type_filling = ORDER_FILLING_IOC;
|
||||||
|
|
||||||
if(trade.OrderSend(request, result))
|
if(!trade.OrderSend(request, result))
|
||||||
{
|
{
|
||||||
if(result.retcode == TRADE_RETCODE_DONE || result.retcode == TRADE_RETCODE_PLACED)
|
Print("Error placing buy stop: ", trade.ResultRetcodeDescription(), " (", result.retcode, ")");
|
||||||
{
|
return false;
|
||||||
Print("Buy Stop Level ", level, " placed at ", priceLevel, " Ticket: ", result.order);
|
}
|
||||||
return true;
|
|
||||||
}
|
if(result.retcode == TRADE_RETCODE_DONE || result.retcode == TRADE_RETCODE_PLACED)
|
||||||
|
{
|
||||||
|
Print("Buy Stop Level ", level, " placed at ", request.price, " TP: ", tp, " Ticket: ", result.order);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
Print("Error placing buy stop: ", trade.ResultRetcodeDescription());
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -393,8 +410,23 @@ bool PlaceSellStop(double priceLevel, int level)
|
|||||||
|
|
||||||
double lots = CalcLots();
|
double lots = CalcLots();
|
||||||
double point = SymbolInfoDouble(_Symbol, SYMBOL_POINT);
|
double point = SymbolInfoDouble(_Symbol, SYMBOL_POINT);
|
||||||
double sl = (StopLoss > 0) ? priceLevel + (StopLoss * point) : 0;
|
double currentBid = SymbolInfoDouble(_Symbol, SYMBOL_BID);
|
||||||
double tp = priceLevel - (TP * point);
|
double stopLevel = SymbolInfoInteger(_Symbol, SYMBOL_TRADE_STOPS_LEVEL) * point;
|
||||||
|
|
||||||
|
// Ensure price is below current Bid - stop level
|
||||||
|
double minDistance = currentBid - stopLevel - (Entry * point);
|
||||||
|
if(priceLevel > minDistance)
|
||||||
|
{
|
||||||
|
Print("Sell Stop too close to price. Adjusting from ", priceLevel, " to ", minDistance);
|
||||||
|
priceLevel = minDistance;
|
||||||
|
}
|
||||||
|
|
||||||
|
double sl = (StopLoss > 0) ? NormalizeDouble(priceLevel + (StopLoss * point), _Digits) : 0;
|
||||||
|
double tp = NormalizeDouble(priceLevel - (TP * point), _Digits);
|
||||||
|
|
||||||
|
// Ensure TP is valid distance from price
|
||||||
|
if(tp >= priceLevel - stopLevel)
|
||||||
|
tp = NormalizeDouble(priceLevel - stopLevel - (TP * point), _Digits);
|
||||||
|
|
||||||
MqlTradeRequest request = {};
|
MqlTradeRequest request = {};
|
||||||
MqlTradeResult result = {};
|
MqlTradeResult result = {};
|
||||||
@@ -402,7 +434,7 @@ bool PlaceSellStop(double priceLevel, int level)
|
|||||||
request.action = TRADE_ACTION_PENDING;
|
request.action = TRADE_ACTION_PENDING;
|
||||||
request.symbol = _Symbol;
|
request.symbol = _Symbol;
|
||||||
request.volume = lots;
|
request.volume = lots;
|
||||||
request.price = priceLevel;
|
request.price = NormalizeDouble(priceLevel, _Digits);
|
||||||
request.sl = sl;
|
request.sl = sl;
|
||||||
request.tp = tp;
|
request.tp = tp;
|
||||||
request.deviation = 10;
|
request.deviation = 10;
|
||||||
@@ -411,68 +443,109 @@ bool PlaceSellStop(double priceLevel, int level)
|
|||||||
request.type = ORDER_TYPE_SELL_STOP;
|
request.type = ORDER_TYPE_SELL_STOP;
|
||||||
request.type_filling = ORDER_FILLING_IOC;
|
request.type_filling = ORDER_FILLING_IOC;
|
||||||
|
|
||||||
if(trade.OrderSend(request, result))
|
if(!trade.OrderSend(request, result))
|
||||||
{
|
{
|
||||||
if(result.retcode == TRADE_RETCODE_DONE || result.retcode == TRADE_RETCODE_PLACED)
|
Print("Error placing sell stop: ", trade.ResultRetcodeDescription(), " (", result.retcode, ")");
|
||||||
{
|
return false;
|
||||||
Print("Sell Stop Level ", level, " placed at ", priceLevel, " Ticket: ", result.order);
|
}
|
||||||
return true;
|
|
||||||
}
|
if(result.retcode == TRADE_RETCODE_DONE || result.retcode == TRADE_RETCODE_PLACED)
|
||||||
|
{
|
||||||
|
Print("Sell Stop Level ", level, " placed at ", request.price, " TP: ", tp, " Ticket: ", result.order);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
Print("Error placing sell stop: ", trade.ResultRetcodeDescription());
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//+------------------------------------------------------------------+
|
||||||
|
//| Count pending orders |
|
||||||
|
//+------------------------------------------------------------------+
|
||||||
|
int CountPendingOrders(int type)
|
||||||
|
{
|
||||||
|
int count = 0;
|
||||||
|
for(int i = OrdersTotal() - 1; i >= 0; i--)
|
||||||
|
{
|
||||||
|
ulong ticket = OrderGetTicket(i);
|
||||||
|
if(ticket <= 0) continue;
|
||||||
|
if(OrderGetString(ORDER_SYMBOL) != _Symbol) continue;
|
||||||
|
if(OrderGetInteger(ORDER_MAGIC) != MagicNum) continue;
|
||||||
|
if(OrderGetInteger(ORDER_TYPE) == type) count++;
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
//+------------------------------------------------------------------+
|
//+------------------------------------------------------------------+
|
||||||
//| Expert tick function |
|
//| Expert tick function |
|
||||||
//+------------------------------------------------------------------+
|
//+------------------------------------------------------------------+
|
||||||
void OnTick()
|
void OnTick()
|
||||||
{
|
{
|
||||||
static datetime lastBarTime = 0;
|
static datetime lastBarTime = 0;
|
||||||
|
static bool gridPlaced = false;
|
||||||
datetime currentBarTime = iTime(_Symbol, PERIOD_CURRENT, 0);
|
datetime currentBarTime = iTime(_Symbol, PERIOD_CURRENT, 0);
|
||||||
MqlDateTime dt;
|
MqlDateTime dt;
|
||||||
TimeToStruct(TimeCurrent(), dt);
|
TimeToStruct(TimeCurrent(), dt);
|
||||||
|
|
||||||
// Recalculate pivots at new day (hour 0, first 5 minutes)
|
// Recalculate pivots at new day (hour 0, first 5 minutes)
|
||||||
if(dt.hour == 0 && dt.min < 5 && currentBarTime != lastBarTime)
|
if(dt.hour == 0 && dt.min < 5)
|
||||||
{
|
{
|
||||||
CalculatePivotPoints();
|
CalculatePivotPoints();
|
||||||
|
gridPlaced = false; // Reset grid for new day
|
||||||
}
|
}
|
||||||
|
|
||||||
if(currentBarTime != lastBarTime)
|
if(currentBarTime == lastBarTime) return;
|
||||||
|
lastBarTime = currentBarTime;
|
||||||
|
|
||||||
|
// Check if we should trade
|
||||||
|
if(!IsRangingMarket())
|
||||||
{
|
{
|
||||||
lastBarTime = currentBarTime;
|
Print("Market not suitable for grid trading");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only place grid once, then monitor
|
||||||
|
if(gridPlaced)
|
||||||
|
{
|
||||||
|
// Check if grid needs replenishing (orders filled)
|
||||||
|
int buyStops = CountPendingOrders(ORDER_TYPE_BUY_STOP);
|
||||||
|
int sellStops = CountPendingOrders(ORDER_TYPE_SELL_STOP);
|
||||||
|
|
||||||
// Check if we should trade
|
if(buyStops == 0 && sellStops == 0)
|
||||||
if(!IsRangingMarket())
|
|
||||||
{
|
{
|
||||||
Print("Market not suitable for grid trading");
|
Print("All grid orders filled or cancelled. Resetting grid.");
|
||||||
return;
|
gridPlaced = false;
|
||||||
}
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get grid boundaries
|
||||||
|
double actualHigh = (HIGH > 0) ? HIGH : PivotR1;
|
||||||
|
double actualLow = (LOW > 0) ? LOW : PivotS1;
|
||||||
|
double currentPrice = SymbolInfoDouble(_Symbol, SYMBOL_BID);
|
||||||
|
double point = SymbolInfoDouble(_Symbol, SYMBOL_POINT);
|
||||||
|
double entryPips = Entry * point;
|
||||||
|
|
||||||
|
// Log status
|
||||||
|
Print("Smart Grid: Placing grid. Price=", currentPrice, " Range: ", actualLow, " - ", actualHigh);
|
||||||
|
|
||||||
|
// Place grid orders
|
||||||
|
int buyCount = 0, sellCount = 0;
|
||||||
|
for(int i = 0; i < MaxLevels; i++)
|
||||||
|
{
|
||||||
|
double buyLevel = actualLow + (i * entryPips);
|
||||||
|
double sellLevel = actualHigh - (i * entryPips);
|
||||||
|
|
||||||
// Get grid boundaries
|
// Only place if valid distance from current price
|
||||||
double actualHigh = (HIGH > 0) ? HIGH : PivotR1;
|
if(buyLevel < currentPrice - (Entry * 2 * point))
|
||||||
double actualLow = (LOW > 0) ? LOW : PivotS1;
|
|
||||||
double currentPrice = SymbolInfoDouble(_Symbol, SYMBOL_BID);
|
|
||||||
double point = SymbolInfoDouble(_Symbol, SYMBOL_POINT);
|
|
||||||
double entryPips = Entry * point;
|
|
||||||
|
|
||||||
// Log status
|
|
||||||
Print("Smart Grid: Price=", currentPrice, " Range: ", actualLow, " - ", actualHigh);
|
|
||||||
Print("RSI/ADX filters passed - Grid active");
|
|
||||||
|
|
||||||
// Example: Place grid orders (simplified)
|
|
||||||
// In full implementation, check existing orders first
|
|
||||||
for(int i = 0; i < MaxLevels; i++)
|
|
||||||
{
|
{
|
||||||
double buyLevel = actualLow + (i * entryPips);
|
if(PlaceBuyStop(buyLevel, i)) buyCount++;
|
||||||
double sellLevel = actualHigh - (i * entryPips);
|
}
|
||||||
|
if(sellLevel > currentPrice + (Entry * 2 * point))
|
||||||
if(buyLevel < currentPrice)
|
{
|
||||||
PlaceBuyStop(buyLevel, i);
|
if(PlaceSellStop(sellLevel, i)) sellCount++;
|
||||||
if(sellLevel > currentPrice)
|
|
||||||
PlaceSellStop(sellLevel, i);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Print("Grid placed: ", buyCount, " buy stops, ", sellCount, " sell stops");
|
||||||
|
if(buyCount > 0 || sellCount > 0) gridPlaced = true;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user