570 lines
42 KiB
MQL5
570 lines
42 KiB
MQL5
|
|
#include <trade\symbolInfo.mqh>
|
|
#include <trade\PositionInfo.mqh>
|
|
#include <trade\trade.mqh>
|
|
#include <trade\DealInfo.mqh>
|
|
|
|
// Static class objects
|
|
CSymbolInfo symbolInfo;
|
|
CPositionInfo position;
|
|
CTrade trade;
|
|
CDealInfo deal;
|
|
|
|
|
|
enum ENUM_ENTRY_STRAT
|
|
{
|
|
SupportResistance,
|
|
ThreeLastCandles,
|
|
Both,
|
|
};
|
|
enum ENUM_EXIT_STRAT
|
|
{
|
|
StoplossTakeProfit,
|
|
TrailingSL
|
|
};
|
|
enum ENUM_MY_TIMEFRAMES
|
|
{
|
|
M1 = PERIOD_M1,
|
|
M5 = PERIOD_M5,
|
|
M15 = PERIOD_M15,
|
|
M30 = PERIOD_M30,
|
|
H1 = PERIOD_H1,
|
|
H4 = PERIOD_H4,
|
|
H12 = PERIOD_H12,
|
|
D1 = PERIOD_D1
|
|
};
|
|
|
|
enum ENUM_TRIGGER
|
|
{
|
|
Buy,
|
|
Sell,
|
|
DoNothing
|
|
};
|
|
|
|
input group "Money Management";
|
|
input double IN_LotMultiplier = 4.0; //Lot Multiplier
|
|
|
|
input group "Trade Settings";
|
|
input ENUM_EXIT_STRAT IN_ExitStrat = StoplossTakeProfit; //Exit-Strategy
|
|
input int IN_TakeProfit = 200; //Takeprofit in points (Set to 1000 when using TrailingSL)
|
|
input int IN_StopLoss = 100; //Stoploss in points
|
|
input int IN_TrailingStopLossTrigger = 50; //Trailing SL Trigger in points
|
|
input int IN_MaxSlippage = 3; //Max Slippage in points
|
|
input ENUM_MY_TIMEFRAMES IN_Timeframe = H1; //Timeframe
|
|
input ulong IN_MagicNumber = 220193; //Magic number
|
|
|
|
input group "Long Wick Candle";
|
|
input bool ActiveLongWick = true; //Use Long Wick Candle
|
|
input ENUM_ENTRY_STRAT EntryStratLWC = Both; //Keylevel
|
|
input int MaxBodySizeLWC = 10; //Max Body Size in points
|
|
input int MinWickLenLWC = 50; //Min Wick Length in points
|
|
|
|
input group "Inverted Long Wick Candle";
|
|
input bool ActiveInvertedWick = true; //Use Inverted Long Wick Candle
|
|
input ENUM_ENTRY_STRAT EntryStratILW = Both; //Keylevel
|
|
input int MaxBodySizeILW = 10; //Max Body Size in points
|
|
input int MinWickLenILW = 50; //Min Wick Length in points
|
|
|
|
input group "Inside Bar";
|
|
input bool ActiveInsideBar = true; //Use Inverted Long Wick Candle
|
|
input int MinBodySizeINB = 10; //Minimum Body Size in points
|
|
|
|
input group "Support & Resistance";
|
|
input int FirstCandle = 3; //First Candle for Lookup Area
|
|
input int LastCandle = 30; //Last Candle for Lookup Area
|
|
|
|
|
|
//input group "Time Settings"
|
|
//
|
|
//input group "Exception 1"
|
|
//input bool ActiveExc1 = false; //No Trade Exception 1
|
|
//input int startDay1 = 1; //Day, Monday = 1, 0 = Off
|
|
//input int startHour1 = 0; //Start hour
|
|
//input int startMinute1 = 0; //Start Minute
|
|
//input int endHour1 = 24; //End hour
|
|
//input int endMinute1 = 0; //End Minute
|
|
//
|
|
//input group "Exception 2"
|
|
//input bool ActiveExc2 = false; //No Trade Exception 2
|
|
//input int startDay2 = 1; //Start Day, Monday = 1, 0 = Off
|
|
//input int startHour2 = 0; //Start hour
|
|
//input int startMinute2 = 0; //Start Minute
|
|
//input int endHour2 = 24; //End hour
|
|
//input int endMinute2 = 0; //End Minute
|
|
//
|
|
//input group "Exception 3"
|
|
//input bool ActiveExc3 = false; //No Trade Exception 2
|
|
//input int startDay3 = 1; //Start Day, Monday = 1, 0 = Off
|
|
//input int startHour3 = 0; //Start hour
|
|
//input int startMinute3 = 0; //Start Minute
|
|
//input int endHour3 = 24; //End hour
|
|
//input int endMinute3 = 0; //End Minute
|
|
|
|
|
|
input group "Debug Settings"
|
|
input bool IN_PrintDebug = true; //Print debug messages
|
|
|
|
struct STRUCT_PENDING_TRADE
|
|
{
|
|
ENUM_POSITION_TYPE pos_type;
|
|
ulong orderTicket;
|
|
|
|
// When this is true we need to prevent trading since this order has not been confirmed yet
|
|
bool isPending;
|
|
|
|
// When this is true we can remove the entry from the array
|
|
bool isConfirmed;
|
|
|
|
// Constructor for new/blank array entries
|
|
STRUCT_PENDING_TRADE()
|
|
{
|
|
pos_type = WRONG_VALUE;
|
|
orderTicket = 0;
|
|
isPending = false;
|
|
isConfirmed = false;
|
|
}
|
|
};
|
|
STRUCT_PENDING_TRADE PendingTrades[];
|
|
|
|
int OnInit()
|
|
{
|
|
// Init CSymbolInfo variable for easy access
|
|
ResetLastError();
|
|
if (!symbolInfo.Name(_Symbol))
|
|
{
|
|
Print(__FILE__, " ", __FUNCTION__, ", ERROR: CSymbolInfo.Name");
|
|
return(INIT_FAILED);
|
|
}
|
|
|
|
RefreshRates();
|
|
trade.SetExpertMagicNumber(IN_MagicNumber);
|
|
|
|
return(INIT_SUCCEEDED);
|
|
}
|
|
|
|
void OnTick()
|
|
{
|
|
double equity = AccountInfoDouble(ACCOUNT_EQUITY); //Guthaben nach Abzug der offenen Positionen
|
|
double dynamicLotSize = NormalizeDouble(equity / 100000, 2);
|
|
double dynamicTradeVolume = dynamicLotSize * IN_LotMultiplier;
|
|
|
|
if (PositionsTotal() != 0 && IN_ExitStrat == TrailingSL) TrailingStopLoss();
|
|
|
|
int countPendingOrders = ArraySize(PendingTrades);
|
|
if (countPendingOrders > 0)
|
|
{
|
|
for (int i = countPendingOrders - 1; i >= 0; i--)
|
|
{
|
|
// Remove all confirmed orders from the array
|
|
if (PendingTrades[i].isPending && PendingTrades[i].isConfirmed)
|
|
{
|
|
ArrayRemove(PendingTrades, i, 1);
|
|
continue;
|
|
}
|
|
|
|
// Open new order
|
|
if (!PendingTrades[i].isPending)
|
|
{
|
|
OpenPosition(i, dynamicTradeVolume);
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
|
|
if (!RefreshRates())
|
|
return;
|
|
|
|
//Here are 3 possible time filters to set when not to trade
|
|
// MqlDateTime mdt;
|
|
// TimeCurrent(mdt);
|
|
//
|
|
// int day = mdt.day_of_week;
|
|
// int hour = mdt.hour;
|
|
// int min = mdt.min;
|
|
//
|
|
// if(ActiveExc1 && day == startDay1)
|
|
// {
|
|
// if(hour >= startHour1 && min >= startMinute1 && hour <= endHour1 && min <= endMinute1) return;
|
|
// }
|
|
// if(ActiveExc2 && day == startDay2)
|
|
// {
|
|
// if(hour >= startHour2 && min >= startMinute2 && hour <= endHour2 && min <= endMinute2) return;
|
|
// }
|
|
// if(ActiveExc3 && day == startDay3)
|
|
// {
|
|
// if(hour >= startHour3 && min >= startMinute3 && hour <= endHour3 && min <= endMinute3) return;
|
|
// }
|
|
|
|
// We only look for a new trigger when we don't already have an open position
|
|
if (AnyOpenPositions())
|
|
return;
|
|
|
|
// Also need to check our PendingTrades array if we have recently placed an order that hasn't been confirmed yet
|
|
countPendingOrders = ArraySize(PendingTrades);
|
|
if (countPendingOrders > 0)
|
|
return;
|
|
|
|
ENUM_TRIGGER trigger = GetTrigger(SupLevel(), ResLevel());
|
|
if (trigger == DoNothing)
|
|
return;
|
|
if (IN_PrintDebug)
|
|
Print(__FILE__, " " ,__FUNCTION__, "Trigger: ", trigger);
|
|
|
|
// Add new order to PendingTrades array
|
|
ArrayResize(PendingTrades, countPendingOrders + 1);
|
|
switch (trigger)
|
|
{
|
|
case Buy:
|
|
PendingTrades[countPendingOrders].pos_type = POSITION_TYPE_BUY;
|
|
break;
|
|
case Sell:
|
|
PendingTrades[countPendingOrders].pos_type = POSITION_TYPE_SELL;
|
|
break;
|
|
default:
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
ENUM_TRIGGER GetTrigger(double supportLevel, double resistenceLevel)
|
|
{
|
|
|
|
// Now check for a possible trade trigger condition
|
|
// TODO
|
|
// Is defined by the candle patter that needs the most candles
|
|
int startCandle = 1;
|
|
int maxCandles = 4;
|
|
|
|
double candleHigh[];
|
|
ArraySetAsSeries(candleHigh, true);
|
|
CopyHigh(_Symbol, (ENUM_TIMEFRAMES)IN_Timeframe, startCandle, maxCandles, candleHigh);
|
|
|
|
double candleLow[];
|
|
ArraySetAsSeries(candleLow, true);
|
|
CopyLow(_Symbol, (ENUM_TIMEFRAMES)IN_Timeframe, startCandle, maxCandles, candleLow);
|
|
|
|
double candleOpen[];
|
|
ArraySetAsSeries(candleOpen, true);
|
|
CopyOpen(_Symbol, (ENUM_TIMEFRAMES)IN_Timeframe, startCandle, maxCandles, candleOpen);
|
|
|
|
double candleClose[];
|
|
ArraySetAsSeries(candleClose, true);
|
|
CopyClose(_Symbol, (ENUM_TIMEFRAMES)IN_Timeframe, startCandle, maxCandles, candleClose);
|
|
|
|
int candleBodySize[];
|
|
ArrayResize(candleBodySize, maxCandles);
|
|
int wickLengthUp[];
|
|
ArrayResize(wickLengthUp, maxCandles);
|
|
int wickLengthDown[];
|
|
ArrayResize(wickLengthDown, maxCandles);
|
|
|
|
for (int i = 0; i < maxCandles; i++)
|
|
{
|
|
if(candleOpen[i] < candleClose[i]) //If open < close, the candle is bullish
|
|
{
|
|
candleBodySize[i] = (candleClose[i] - candleOpen[i]) /_Point; //Divided by _Point gives the difference in points which is more easy to calculate with
|
|
wickLengthUp[i] = (candleHigh[i] - candleClose[i]) / _Point;
|
|
wickLengthDown[i] = (candleOpen[i] - candleLow[i]) / _Point;
|
|
}
|
|
else if (candleOpen[i] == candleClose[i])
|
|
{
|
|
candleBodySize[i] = 0;
|
|
wickLengthUp[i] = (candleHigh[i] - candleClose[i]) / _Point;
|
|
wickLengthDown[i] = (candleOpen[i] - candleLow[i]) / _Point;
|
|
}
|
|
else //Else candle is bearish
|
|
{
|
|
candleBodySize[i] = (candleOpen[i] - candleClose[i]) / _Point;
|
|
wickLengthUp[i] = (candleHigh[i] - candleOpen[i]) / _Point;
|
|
wickLengthDown[i] = (candleClose[i] - candleLow[i]) / _Point;
|
|
}
|
|
}
|
|
|
|
bool ThreeGreenCandles = false;
|
|
bool ThreeRedCandles = false;
|
|
|
|
if(candleOpen[3] < candleClose[3] && candleOpen[2] < candleClose[2] && candleOpen[1] < candleClose[1]) ThreeGreenCandles = true;
|
|
if(candleOpen[3] > candleClose[3] && candleOpen[2] > candleClose[2] && candleOpen[1] > candleClose[1]) ThreeRedCandles = true;
|
|
|
|
if(ActiveLongWick)
|
|
{
|
|
switch (EntryStratLWC)
|
|
{
|
|
case SupportResistance:
|
|
{
|
|
if (candleBodySize[0] < MaxBodySizeLWC && wickLengthUp[0] > MinWickLenLWC && candleHigh[0] > resistenceLevel)
|
|
return Sell;
|
|
if (candleBodySize[0] < MaxBodySizeLWC && wickLengthDown[0] > MinWickLenLWC && candleLow[0] < supportLevel)
|
|
return Buy;
|
|
}
|
|
break;
|
|
|
|
case ThreeLastCandles:
|
|
{
|
|
if (candleBodySize[0] < MaxBodySizeLWC && wickLengthUp[0] > MinWickLenLWC && ThreeGreenCandles == true)
|
|
return Sell;
|
|
if (candleBodySize[0] < MaxBodySizeLWC && wickLengthDown[0] > MinWickLenLWC && ThreeRedCandles == true)
|
|
return Buy;
|
|
}
|
|
break;
|
|
|
|
case Both:
|
|
{
|
|
|
|
if (candleBodySize[0] < MaxBodySizeLWC && wickLengthUp[0] > MinWickLenLWC && (candleHigh[0] > resistenceLevel || ThreeGreenCandles == true))
|
|
return Sell;
|
|
if (candleBodySize[0] < MaxBodySizeLWC && wickLengthDown[0] > MinWickLenLWC && (candleLow[0] < supportLevel || ThreeRedCandles == true))
|
|
return Buy;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
if(ActiveInvertedWick)
|
|
{
|
|
switch (EntryStratILW)
|
|
{
|
|
case SupportResistance:
|
|
|
|
{
|
|
if (candleBodySize[0] < MaxBodySizeILW && wickLengthDown[0] > MinWickLenILW && candleHigh[0] > resistenceLevel)
|
|
return Sell;
|
|
if (candleBodySize[0] < MaxBodySizeILW && wickLengthUp[0] > MinWickLenILW && candleLow[0] < supportLevel)
|
|
return Buy;
|
|
}
|
|
break;
|
|
|
|
case ThreeLastCandles:
|
|
if(ActiveInvertedWick)
|
|
{
|
|
if (candleBodySize[0] < MaxBodySizeILW && wickLengthDown[0] > MinWickLenILW && ThreeGreenCandles == true)
|
|
return Sell;
|
|
if (candleBodySize[0] < MaxBodySizeILW && wickLengthUp[0] > MinWickLenILW && candleLow[0] < supportLevel && ThreeRedCandles == true)
|
|
return Buy;
|
|
}
|
|
break;
|
|
|
|
case Both:
|
|
if(ActiveInvertedWick)
|
|
{
|
|
if (candleBodySize[0] < MaxBodySizeILW && wickLengthDown[0] > MinWickLenILW && (candleHigh[0] > resistenceLevel || ThreeGreenCandles == true))
|
|
return Sell;
|
|
if (candleBodySize[0] < MaxBodySizeILW && wickLengthUp[0] > MinWickLenILW && candleLow[0] < supportLevel && (candleLow[0] < supportLevel || ThreeRedCandles == true))
|
|
return Buy;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
if(ActiveInsideBar)
|
|
{
|
|
if (candleBodySize[0] > MinBodySizeINB && candleHigh[0] < candleHigh[1] && candleLow[0] > candleLow[1] && candleHigh[1] > resistenceLevel)
|
|
return Sell;
|
|
if (candleBodySize[0] > MinBodySizeINB && candleLow[0] > candleLow[1] && candleHigh[0] < candleHigh[1] && candleLow[1] < supportLevel)
|
|
return Buy;
|
|
}
|
|
|
|
return DoNothing;
|
|
}
|
|
|
|
|
|
//Erster Versuch Support und Resistance Level zu identifizieren
|
|
//Man kann den höchsten und niedrigsten Wert aus einem Array ziehen
|
|
//Großer Nachteil ist die fixe Größe des Arrays, die müsste variabel sein, bis ein neues Level gefunden wird
|
|
//Da fehlt mir aber noch die Idee, wie genau man das umsetzen kann
|
|
|
|
double SupLevel()
|
|
{
|
|
double arrCandles[];
|
|
ArraySetAsSeries(arrCandles, true);
|
|
CopyClose(_Symbol,(ENUM_TIMEFRAMES)IN_Timeframe,FirstCandle,LastCandle,arrCandles);
|
|
double CandleLow = arrCandles[ArrayMinimum(arrCandles,0,WHOLE_ARRAY)];
|
|
return CandleLow;
|
|
}
|
|
|
|
double ResLevel()
|
|
{
|
|
double arrCandles[];
|
|
ArraySetAsSeries(arrCandles, true);
|
|
CopyClose(_Symbol,(ENUM_TIMEFRAMES)IN_Timeframe,FirstCandle,LastCandle,arrCandles);
|
|
double CandleHigh = arrCandles[ArrayMaximum(arrCandles,0,WHOLE_ARRAY)];
|
|
return CandleHigh;
|
|
}
|
|
|
|
|
|
void TrailingStopLoss()
|
|
{
|
|
for (int i = PositionsTotal() - 1; i >= 0; i--)
|
|
{
|
|
ulong posTicket = PositionGetTicket(i);
|
|
|
|
if (PositionSelectByTicket(posTicket) && PositionGetString(POSITION_SYMBOL) == _Symbol)
|
|
{
|
|
ENUM_POSITION_TYPE posType = (ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);
|
|
double posOpenPrice = PositionGetDouble(POSITION_PRICE_OPEN);
|
|
double posTP = PositionGetDouble(POSITION_TP);
|
|
double posSL = PositionGetDouble(POSITION_SL);
|
|
|
|
double bid = SymbolInfoDouble(_Symbol,SYMBOL_BID);
|
|
double ask = SymbolInfoDouble(_Symbol,SYMBOL_ASK);
|
|
|
|
if(posType == POSITION_TYPE_BUY)
|
|
{
|
|
if(bid > posOpenPrice + IN_TrailingStopLossTrigger * _Point)
|
|
{
|
|
double NewSL = bid - IN_TrailingStopLossTrigger * _Point;
|
|
NewSL = NormalizeDouble(NewSL, _Digits);
|
|
|
|
if (NewSL > posSL)
|
|
{
|
|
trade.PositionModify(posTicket, NewSL, posTP);
|
|
}
|
|
}
|
|
}
|
|
|
|
else if (posType == POSITION_TYPE_SELL)
|
|
{
|
|
if (ask < posOpenPrice - IN_TrailingStopLossTrigger * _Point)
|
|
{
|
|
double NewSL = ask + IN_TrailingStopLossTrigger * _Point;
|
|
NewSL = NormalizeDouble(NewSL, _Digits);
|
|
|
|
if (NewSL < posSL || posSL == 0)
|
|
{
|
|
trade.PositionModify(posTicket, NewSL, posTP);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Sets the "isConfirmed" flag in our PendingTrades array
|
|
void OnTradeTransaction(const MqlTradeTransaction &trans, const MqlTradeRequest &request, const MqlTradeResult &result)
|
|
{
|
|
ENUM_TRADE_TRANSACTION_TYPE type = trans.type;
|
|
if (type == TRADE_TRANSACTION_DEAL_ADD)
|
|
{
|
|
ResetLastError();
|
|
if (HistoryDealSelect(trans.deal))
|
|
{
|
|
deal.Ticket(trans.deal);
|
|
}
|
|
else
|
|
{
|
|
Print(__FILE__, " ", __FUNCTION__, ", ERROR: ", "HistoryDealSelect(", trans.deal, ") error: ", GetLastError());
|
|
return;
|
|
}
|
|
if (deal.Symbol() == symbolInfo.Name() && deal.Magic() == IN_MagicNumber)
|
|
{
|
|
if (deal.DealType() == DEAL_TYPE_BUY || deal.DealType() == DEAL_TYPE_SELL)
|
|
{
|
|
int countPendingOrders = ArraySize(PendingTrades);
|
|
if (countPendingOrders > 0)
|
|
{
|
|
for (int i = 0; i < countPendingOrders; i++)
|
|
{
|
|
if (PendingTrades[i].isPending)
|
|
{
|
|
if (PendingTrades[i].orderTicket == deal.Order())
|
|
{
|
|
Print(__FILE__, " ", __FUNCTION__, ", OK: ", " Transaction confirmed");
|
|
PendingTrades[i].isConfirmed = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
bool RefreshRates()
|
|
{
|
|
// Refreshes the symbol quotes data
|
|
if (!symbolInfo.RefreshRates())
|
|
{
|
|
Print(__FILE__, " ", __FUNCTION__, ", ERROR: ", "RefreshRates error");
|
|
return false;
|
|
}
|
|
// Sometimes 0 is returned, no idea why yet
|
|
if (symbolInfo.Ask() == 0 || symbolInfo.Bid() == 0)
|
|
{
|
|
Print(__FILE__, " ", __FUNCTION__, ", ERROR: ", "Ask == 0.0 OR Bid == 0.0");
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
void OpenPosition(int index, double tradeVolume)
|
|
{
|
|
if (!RefreshRates())
|
|
return;
|
|
|
|
bool success = false;
|
|
string debugType = "";
|
|
if (PendingTrades[index].pos_type == POSITION_TYPE_BUY)
|
|
{
|
|
debugType = "Buy";
|
|
success = trade.Buy(tradeVolume, symbolInfo.Name(), symbolInfo.Ask(), symbolInfo.Ask() - IN_StopLoss * _Point,symbolInfo.Ask() + IN_TakeProfit * _Point);
|
|
}
|
|
else if (PendingTrades[index].pos_type == POSITION_TYPE_SELL)
|
|
{
|
|
debugType = "Sell";
|
|
success = trade.Sell(tradeVolume, symbolInfo.Name(), symbolInfo.Bid(), symbolInfo.Bid() + IN_StopLoss * _Point,symbolInfo.Bid() - IN_TakeProfit * _Point);
|
|
}
|
|
if (success)
|
|
{
|
|
if (trade.ResultRetcode() == TRADE_RETCODE_DONE)
|
|
{
|
|
PendingTrades[index].isPending = true;
|
|
PendingTrades[index].orderTicket = trade.ResultOrder();
|
|
}
|
|
else
|
|
{
|
|
PendingTrades[index].isPending = false;
|
|
if (IN_PrintDebug)
|
|
Print(__FILE__, " ", __FUNCTION__, ", ERROR: ", debugType, " -> false, Deal Nr: ", trade.ResultDeal(), " Result Retcode: ", trade.ResultRetcode(), ", descr: ", trade.ResultRetcodeDescription());
|
|
}
|
|
if (IN_PrintDebug)
|
|
PrintResultTrade();
|
|
}
|
|
else
|
|
{
|
|
PendingTrades[index].isPending = false;
|
|
if (IN_PrintDebug)
|
|
Print(__FILE__, " ", __FUNCTION__, ", ERROR: ", debugType, " -> false. Result Retcode: ", trade.ResultRetcode(), ", descrt: ", trade.ResultRetcodeDescription());
|
|
}
|
|
}
|
|
|
|
void PrintResultTrade()
|
|
{
|
|
Print(__FILE__, " ", __FUNCTION__, ", Symbol: ", symbolInfo.Name() + ", " +
|
|
"Code of request result: " + IntegerToString(trade.ResultRetcode()) + ", " +
|
|
"Code of request result as a string: " + trade.ResultRetcodeDescription(),
|
|
"trade execution mode: " + symbolInfo.TradeExecutionDescription());
|
|
Print("deal ticket: " + IntegerToString(trade.ResultDeal()) + ", " +
|
|
"Order ticket: " + IntegerToString(trade.ResultOrder()) + ", " +
|
|
"Order retcode external: " + IntegerToString(trade.ResultRetcodeExternal()) + ", " +
|
|
"Volume of deal or order: " + DoubleToString(trade.ResultVolume(), 2));
|
|
Print("Price, confirmed by broker: " + DoubleToString(trade.ResultPrice(), symbolInfo.Digits()) + ", " +
|
|
"Current bid price: " + DoubleToString(symbolInfo.Bid(), symbolInfo.Digits()) + " (the requote): " + DoubleToString(trade.ResultBid(), symbolInfo.Digits()) + ", " +
|
|
"Current ask price: " + DoubleToString(symbolInfo.Ask(), symbolInfo.Digits()) + " (the requote): " + DoubleToString(trade.ResultAsk(), symbolInfo.Digits()));
|
|
Print("Broker comment: " + trade.ResultComment());
|
|
}
|
|
|
|
bool AnyOpenPositions()
|
|
{
|
|
for (int i = PositionsTotal() - 1; i >= 0; i--)
|
|
{
|
|
if (position.SelectByIndex(i))
|
|
{
|
|
if (position.Symbol() == symbolInfo.Name() && position.Magic() == IN_MagicNumber)
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
return false;
|
|
}
|