353 lines
12 KiB
MQL5
353 lines
12 KiB
MQL5
|
//+------------------------------------------------------------------+
|
||
|
//| ProjectName |
|
||
|
//| Copyright 2020, CompanyName |
|
||
|
//| http://www.companyname.net |
|
||
|
//+------------------------------------------------------------------+
|
||
|
|
||
|
#property version "0.5.7"
|
||
|
|
||
|
#include <Arrays\ArrayLong.mqh>
|
||
|
#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;
|
||
|
}
|
||
|
//+------------------------------------------------------------------+
|