//+------------------------------------------------------------------+ //| ProjectName | //| Copyright 2020, CompanyName | //| http://www.companyname.net | //+------------------------------------------------------------------+ #property version "0.5.7" #include #include "..\MTLibrary\MTUtils.mqh" input group "Evaluator SMA" input int Short_Positions = 4;; /* Amount of Possible Short Positions that can be held in a given run*/ input int Long_Positions = 4;; /* Amount of Possible Long Positions that can be held in a given run*/ input int Avail_Positions = 2;; /* Amount Positions that can be open at any given time */ input int Activiate_Trailing = 1;; /* How many PIPs in favor of the position will it take to drag the SL to the SMA, AT + OpenPrice if 'long' or AT - OpenPrice if 'short'*/ input int SMA_Period = 200;; /**/ input int RVI_Period = 386;; /**/ input bool DecideByRVI = true;; /*This will enable the option to decide the position direction not by SMA but by RVI. If prev > curr is Long, if prev < curr is Short*/ enum Signal { signal_long = 1, signal_short = 2, signal_unset = 0 }; enum CrossingPatern { cross_from_above = 1, cross_from_below = 2, cross_not_happened = 0 }; struct CrossingInstance { MqlRates curr_candle; MqlRates past_candle; double past_sma; double curr_sma; }; //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ class Evaluator { private: int e_short_positions_budget; int e_long_positions_budget; int e_corrective_band; int e_avail_positions; int e_ma_period; int e_rvi_period; bool e_deciding_by_rvi; Signal e_signal; CArrayLong *e_correcting_positions; public: void flushSignal() { e_signal = signal_unset; }; Signal getSignal() { return e_signal; }; CrossingPatern CrossAtCandle(CrossingInstance &crx_buffer); CrossingPatern CrossBetweenCandles(CrossingInstance &crx_buffer); int RVIDrivenPosition(double& rvi_info_b0[]); bool shouldPlaceLong(); bool shouldPlaceShort(); void IdentifyNewPositionsToFollowSMA(); void MakePositionsFollowSMA(); void FollowTheSMA(); void loadIndicators(); void Init(); }; //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ void Evaluator::Init() { e_short_positions_budget = Short_Positions; e_long_positions_budget = Long_Positions; e_avail_positions = Avail_Positions; e_signal = signal_unset; e_corrective_band = Activiate_Trailing; e_ma_period = SMA_Period; e_rvi_period = RVI_Period; e_deciding_by_rvi = DecideByRVI; e_correcting_positions = new CArrayLong; } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ bool Evaluator::shouldPlaceLong(void) { Print("Lets Log Positions [L]: " + CountPositionsByType(true)); return (e_signal == signal_long) && (CountPositionsByType(true) < e_long_positions_budget) ; } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ bool Evaluator::shouldPlaceShort(void) { Print("Lets Log Positions [S]: " + CountPositionsByType(false)); return (e_signal == signal_short) && (CountPositionsByType(false) < e_short_positions_budget); } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ void Evaluator::loadIndicators(void) { CrossingInstance crx_buffer; // In this instance i dont have enough avail positions so just jump away! if(PositionsTotal() >= e_avail_positions) { return; } MqlRates PriceInfo[]; ArraySetAsSeries(PriceInfo, true); int PriceData = CopyRates(_Symbol, _Period, 0, 3, PriceInfo); double ma_array[]; ArraySetAsSeries(ma_array, true); int ma_handler = iMA(_Symbol, _Period, e_ma_period, 0, MODE_SMA, PRICE_CLOSE); CopyBuffer(ma_handler, 0,0,3, ma_array); double rvi_info_b0[]; int rvi_handler = iRVI(_Symbol, PERIOD_M15, e_rvi_period); ArraySetAsSeries(rvi_info_b0, true); CopyBuffer(rvi_handler, 0,0,3, rvi_info_b0); // Only require the main-line, no need for the 2nd buffer //bool crossing_from_below = (PriceInfo[2].close < ma_array[2] && PriceInfo[1].close > ma_array[1]); //bool crossing_from_above = (PriceInfo[2].close > ma_array[2] && PriceInfo[1].close < ma_array[1]); // bool crossing_from_below = (PriceInfo[2].low < ma_array[2] && PriceInfo[1].low > ma_array[1]); // bool crossing_from_above = (PriceInfo[2].low > ma_array[2] && PriceInfo[1].low < ma_array[1]); crx_buffer.curr_candle = PriceInfo[0]; crx_buffer.past_candle = PriceInfo[1]; crx_buffer.curr_sma = ma_array[0]; crx_buffer.past_sma = ma_array[1]; CrossingPatern crossing_at_candle = CrossAtCandle(crx_buffer); CrossingPatern crossing_betwen_candles = CrossBetweenCandles(crx_buffer); bool crossing_from_above = (crossing_at_candle == cross_from_above || crossing_betwen_candles == cross_from_above); bool crossing_from_below = (crossing_at_candle == cross_from_below || crossing_betwen_candles == cross_from_below); if(crossing_from_below) { if(e_deciding_by_rvi && RVIDrivenPosition(rvi_info_b0) == 1) { e_signal = signal_long; } else { e_signal = signal_long; } } if(crossing_from_above) { if(e_deciding_by_rvi && RVIDrivenPosition(rvi_info_b0) == 2) { e_signal = signal_short; } else { e_signal = signal_short; } } } //+------------------------------------------------------------------+ //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ void Evaluator::IdentifyNewPositionsToFollowSMA() { for(int i = PositionsTotal()-1 ; i>=0 ; i--) { ulong ticket = PositionGetTicket(i); PositionSelectByTicket(ticket); double corrective_price_value = 0.0; if(e_correcting_positions.SearchLinear(ticket) == -1) { if(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY) { corrective_price_value = NormalizeDouble(PositionGetDouble(POSITION_PRICE_OPEN) + e_corrective_band * _Point, _Digits); if(PRICE >= corrective_price_value) { int r_value = e_correcting_positions.Add(ticket); } } else if(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_SELL) { corrective_price_value = NormalizeDouble(PositionGetDouble(POSITION_PRICE_OPEN) - e_corrective_band * _Point, _Digits); if(PRICE <= corrective_price_value) { e_correcting_positions.Add(ticket); } } } } } //+------------------------------------------------------------------+ //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ void Evaluator::MakePositionsFollowSMA() { double SMA[]; ArraySetAsSeries(SMA, true); int ma_handler = iMA(_Symbol, _Period, e_ma_period, 0, MODE_SMA, PRICE_CLOSE); CopyBuffer(ma_handler, 0, 0, 3, SMA); for(int i = e_correcting_positions.Total()-1; i>=0; i--) { ulong ticket = e_correcting_positions.At(i); bool position_completed = PositionSelectByTicket(ticket); if(!position_completed) { bool status = e_correcting_positions.Delete(i); Print("Position: "+ticket+" Status: "+position_completed+" List Status "+e_correcting_positions.Total()); } else { double take_profit = PositionGetDouble(POSITION_TP); double sma_current = NormalizeDouble(SMA[1], _Digits); double sl_current = PositionGetDouble(POSITION_SL); if((PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY) && sl_current < sma_current) { trade.PositionModify(ticket,SMA[1], take_profit);; // Add the take profit } if((PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_SELL) && sl_current > sma_current) { trade.PositionModify(ticket,SMA[1], take_profit);; // Add the take profit } } } } //+------------------------------------------------------------------+ //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ void Evaluator::FollowTheSMA() { IdentifyNewPositionsToFollowSMA(); MakePositionsFollowSMA(); } //+------------------------------------------------------------------+ //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ int Evaluator::RVIDrivenPosition(double& rvi_info_b0[]) { double current_value_rvi = rvi_info_b0[0]; double prev_value_rvi = rvi_info_b0[1]; if(prev_value_rvi < current_value_rvi) { // this is a Long Signal return 1; } if(prev_value_rvi > current_value_rvi) { //this is a Short Signal return 2; } //This is a nothing signal ... should i even do something here? return -1; } //+------------------------------------------------------------------+ //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ CrossingPatern Evaluator::CrossAtCandle(CrossingInstance &crx_buffer) { if(crx_buffer.curr_candle.low < crx_buffer.curr_sma && crx_buffer.curr_candle.high > crx_buffer.curr_sma) { if(crx_buffer.past_candle.high < crx_buffer.past_sma) { return cross_from_below; } else if(crx_buffer.past_candle.low > crx_buffer.past_sma) { return cross_from_above; } else { return cross_not_happened; } } else { return cross_not_happened; } } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ CrossingPatern Evaluator::CrossBetweenCandles(CrossingInstance &crx_buffer) { if(crx_buffer.past_candle.low < crx_buffer.past_sma && crx_buffer.curr_candle.high > crx_buffer.curr_sma) { return cross_from_below; // cross from below! } else if(crx_buffer.past_candle.high > crx_buffer.past_sma && crx_buffer.curr_candle.low < crx_buffer.curr_sma) { return cross_from_above; // cross from above! } return cross_not_happened; } //+------------------------------------------------------------------+