//+------------------------------------------------------------------+ //| base.mqh | //| Benjamin Pillet | //| | //+------------------------------------------------------------------+ #property copyright "Benjamin Pillet" #property link "" #include CTrade trade; //+------------------------------------------------------------------+ //| global variables | //+------------------------------------------------------------------+ //--- main input parameters input ulong MagicNumber = 1234; input ENUM_TIMEFRAMES TimeFrame = PERIOD_D1; input int AddPoint = 50; input double TpSlRatio = 2; //take profit/stop loss ratio input double SlPercent = 2; input bool SafeMode = false;//safe mode on input double SafeActivationRatio = 4; input double SafeSlRatio = 2; input bool TrailingMode =false;//trailing mode on input double TrailingActivationRatio = 6; input double TrailingDistance = 20; //trailing distance input bool CancelOrderOnTP = true; //cancel orders on TP input bool CancelOrderOnSL = true; //cancel orders on profitable SL input bool CancelOrderOnLoss = false; //cancel orders on non-profitable SL input bool OrderOnce = false; //place orders only once input bool DrawLines = true; //Draw safe and trailing activation lines input int TimeOffset = 0; //--- market variables double volumeStep; double tickSize; double tickPrice; double bid; double prevBid; double prevAsk; double ask; long tickVolume[]; MqlRates bar[]; double lastOpen; //--- time variables MqlDateTime firstBar; MqlDateTime today; MqlDateTime startTime[]; MqlDateTime endTime[]; datetime lastRefreshDay; datetime prevDay; //--- account variables double accountBalance; double accountEquity; //--- trade variables //--- orders and positions handling system variables bool orderConditions; bool resetOrderPlaced; bool orderPlaced[2]; int arrayIndex; int arraySize; double cancellingSL[2]; int prevPositionTotal; int positionTotal; ulong positionTicket[]; double safeActivationPrice[]; double safeSL[]; double trailingActivationPrice[]; double trailingDistance[]; double trailingSL; long positionType; double positionOpenPrice; double positionCurrentPrice; double positionTP; double positionSL; ulong lastPositionTicket; ulong posTicket; ulong histOrderTicket; ulong histDealTicket; double histOrderPrice; double initialPositionSL; bool profitableSL; bool timeSet; //+------------------------------------------------------------------+ //| functions | //+------------------------------------------------------------------+ double NormalisePrice(double p){ return (MathRound(p/tickSize)*tickSize); } double LotsCalculator(double openPrice, double closePrice, double balance){ double lots = NormalizeDouble(((balance*(SlPercent/100))/(MathAbs(openPrice-closePrice)*(tickPrice/tickSize)))/volumeStep,0)*volumeStep; if(lots < SymbolInfoDouble(_Symbol,SYMBOL_VOLUME_MIN)){ lots = SymbolInfoDouble(_Symbol,SYMBOL_VOLUME_MIN); } else if(lots > SymbolInfoDouble(_Symbol,SYMBOL_VOLUME_MAX)){ lots = SymbolInfoDouble(_Symbol,SYMBOL_VOLUME_MAX); } return lots; } void setVariables(){ lastOpen = 0; volumeStep = SymbolInfoDouble(_Symbol,SYMBOL_VOLUME_STEP); tickSize = SymbolInfoDouble(_Symbol,SYMBOL_TRADE_TICK_SIZE); tickPrice = SymbolInfoDouble(_Symbol,SYMBOL_TRADE_TICK_VALUE); } void refreshVariables(){ bid = SymbolInfoDouble(_Symbol,SYMBOL_BID); ask = SymbolInfoDouble(_Symbol,SYMBOL_ASK); accountBalance = AccountInfoDouble(ACCOUNT_BALANCE); accountEquity = AccountInfoDouble(ACCOUNT_EQUITY); ArraySetAsSeries(bar,true); CopyRates(_Symbol,TimeFrame,0,3,bar); TimeToStruct(bar[1].time,firstBar); TimeToStruct(TimeCurrent(),today); //refresh once a day if(today.day != lastRefreshDay){ volumeStep = SymbolInfoDouble(_Symbol,SYMBOL_VOLUME_STEP); tickSize = SymbolInfoDouble(_Symbol,SYMBOL_TRADE_TICK_SIZE); tickPrice = SymbolInfoDouble(_Symbol,SYMBOL_TRADE_TICK_VALUE); lastRefreshDay = today.day; } } void AddPosition(){ //add a position into the safe and trailing system. The position has to be previously selected and checked arrayIndex = arraySize; arraySize = arraySize + 1; ArrayResize(positionTicket,arraySize,10); positionTicket[arrayIndex] = PositionGetInteger(POSITION_TICKET); positionType = PositionGetInteger(POSITION_TYPE); positionOpenPrice = PositionGetDouble(POSITION_PRICE_OPEN); positionSL = PositionGetDouble(POSITION_SL); //check if the SL is already in a safe/profitable place if((positionType == POSITION_TYPE_BUY && positionSL < positionOpenPrice) || (positionType==POSITION_TYPE_SELL && positionSL > positionOpenPrice)){ initialPositionSL = positionSL; //if not profitable SL then the current SL is the initial SL of the position profitableSL = false; } else{ profitableSL = true; if(TrailingMode){ HistorySelect(0,TimeCurrent()); for(int j=HistoryOrdersTotal()-1; j>=0; j--){ histOrderTicket = HistoryOrderGetTicket(j); if(HistoryOrderGetInteger(histOrderTicket,ORDER_POSITION_ID) == PositionGetInteger(POSITION_IDENTIFIER)){ initialPositionSL = HistoryOrderGetDouble(histOrderTicket,ORDER_SL); } } } } if(SafeMode && !profitableSL){ ArrayResize(safeActivationPrice,arraySize,10); ArrayResize(safeSL,arraySize,10); if(positionType == POSITION_TYPE_BUY){ safeActivationPrice[arrayIndex] = positionOpenPrice + (positionOpenPrice-positionSL)*SafeActivationRatio; safeSL[arrayIndex] = NormalisePrice(positionOpenPrice + (positionOpenPrice-positionSL)*SafeSlRatio); if(safeSL[arrayIndex]<0)safeSL[arrayIndex] = 0; } else if(positionType==POSITION_TYPE_SELL){ safeActivationPrice[arrayIndex] = positionOpenPrice - (positionSL-positionOpenPrice)*SafeActivationRatio; safeSL[arrayIndex] = NormalisePrice(positionOpenPrice - (positionSL-positionOpenPrice)*SafeSlRatio); if(safeSL[arrayIndex]<0)safeSL[arrayIndex] = 0; } if(DrawLines){ ObjectCreate(0,"Safe Activation #"+IntegerToString(positionTicket[arrayIndex]),OBJ_HLINE,0,0,safeActivationPrice[arrayIndex]); ObjectSetInteger(0,"Safe Activation #"+IntegerToString(positionTicket[arrayIndex]),OBJPROP_COLOR,clrDodgerBlue); ObjectSetInteger(0,"Safe Activation #"+IntegerToString(positionTicket[arrayIndex]),OBJPROP_STYLE,STYLE_DASH); } } if(TrailingMode){ ArrayResize(trailingActivationPrice,arraySize,10); ArrayResize(trailingDistance,arraySize,10); if(positionType == POSITION_TYPE_BUY){ trailingActivationPrice[arrayIndex] = positionOpenPrice + (positionOpenPrice-initialPositionSL)*TrailingActivationRatio; trailingDistance[arrayIndex] = (trailingActivationPrice[arrayIndex]-positionOpenPrice)*(TrailingDistance/100); } else if(positionType==POSITION_TYPE_SELL){ trailingActivationPrice[arrayIndex] = positionOpenPrice - (initialPositionSL-positionOpenPrice)*TrailingActivationRatio; trailingDistance[arrayIndex] = (positionOpenPrice - trailingActivationPrice[arrayIndex])*(TrailingDistance/100); } if(DrawLines){ ObjectCreate(0,"Trailing Activation #"+IntegerToString(positionTicket[arrayIndex]),OBJ_HLINE,0,0,trailingActivationPrice[arrayIndex]); ObjectSetInteger(0,"Trailing Activation #"+IntegerToString(positionTicket[arrayIndex]),OBJPROP_COLOR,clrMediumOrchid); ObjectSetInteger(0,"Trailing Activation #"+IntegerToString(positionTicket[arrayIndex]),OBJPROP_STYLE,STYLE_DASH); } } } void CloseAllLongPositions(){ for(int i=0; i< PositionsTotal(); i++){ if(PositionGetInteger(POSITION_MAGIC) == MagicNumber && PositionGetSymbol(i) == _Symbol && PositionGetInteger(POSITION_TYPE)==POSITION_TYPE_BUY) trade.PositionClose(PositionGetTicket(i)); } } void CloseAllShortPositions(){ for(int i=0; i< PositionsTotal(); i++){ if(PositionGetInteger(POSITION_MAGIC) == MagicNumber && PositionGetSymbol(i) == _Symbol && PositionGetInteger(POSITION_TYPE)==POSITION_TYPE_SELL) trade.PositionClose(PositionGetTicket(i)); } } void CloseAllPositions(){ for(int i=0; i< PositionsTotal(); i++){ if(PositionGetInteger(POSITION_MAGIC) == MagicNumber && PositionGetSymbol(i) == _Symbol) trade.PositionClose(PositionGetTicket(i)); } }