Jeff_Max_Trading/JMLibrary/JMUtils.mqh

353 lines
12 KiB
MQL5
Raw Permalink Normal View History

2025-05-30 15:02:04 +02:00
//+------------------------------------------------------------------+
//| 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;
}
//+------------------------------------------------------------------+