1191 lines
46 KiB
MQL5
1191 lines
46 KiB
MQL5
//+------------------------------------------------------------------+
|
|
//| OrderBlockIndPart2.mq5 |
|
|
//| Copyright 2025, Niquel Mendoza. |
|
|
//| https://www.mql5.com/es/users/nique_372/news |
|
|
//+------------------------------------------------------------------+
|
|
#property copyright "Copyright 2025, Niquel Mendoza."
|
|
#property link "https://www.mql5.com/es/users/nique_372/news"
|
|
|
|
#define Version "2.01"
|
|
#property version Version
|
|
#property indicator_chart_window
|
|
#property strict
|
|
|
|
#property indicator_buffers 6
|
|
#property indicator_plots 6
|
|
|
|
#property indicator_label1 "Buy"
|
|
#property indicator_type1 DRAW_ARROW
|
|
#property indicator_color1 clrGreen
|
|
#property indicator_width1 1
|
|
|
|
#property indicator_label2 "Sell"
|
|
#property indicator_type2 DRAW_ARROW
|
|
#property indicator_color2 clrRed
|
|
#property indicator_width2 1
|
|
|
|
#property indicator_label3 "Take Profit 1"
|
|
#property indicator_label4 "Take Profit 2"
|
|
#property indicator_label5 "Stop Loss 1"
|
|
#property indicator_label6 "Stop Loss 2"
|
|
|
|
|
|
enum ENUM_TP_SL_STYLE
|
|
{
|
|
ATR = 0, //Atr
|
|
POINT = 1 //Points
|
|
};
|
|
|
|
|
|
#include "Main.mqh"
|
|
|
|
sinput group "--- Order Block Indicator settings ---"
|
|
input bool enable_alerts = true; //Enable alerts ?
|
|
|
|
sinput group "-- Order Block --"
|
|
input int Universal_range_search = 500; //Range to find order blocks
|
|
input int Witdth_order_block = 1; //Order Blocks Width
|
|
input bool Back_order_block = true; //Background for the rectangles of the order blocks?
|
|
input bool Fill_order_block = true; //Fill order block?
|
|
input color Color_Order_Block_Bajista = clrRed; //Bullish order block color
|
|
input color Color_Order_Block_Alcista = clrGreen; //Bearish order block color
|
|
input double transparecy = 0.3 ;//Transparency 0 - 1.0 (1.0 opaque and 0.0 transparent)
|
|
|
|
sinput group "-- Strategy --"
|
|
input ENUM_TP_SL_STYLE tp_sl_style = POINT; //Type of TP and SL:
|
|
|
|
sinput group " ATR "
|
|
input double Atr_Multiplier_1 = 1.5; //Atr multiplier 1 for the tp and sl
|
|
input double Atr_Multiplier_2 = 2.0; //Atr multiplier 2 for the tp and sl
|
|
|
|
sinput group " POINT "
|
|
input int TP_POINT = 500; //Takeprofit in points
|
|
input int SL_POINT = 275; //Stoploss in points
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Structures and Global Variables |
|
|
//+------------------------------------------------------------------+
|
|
struct OrderBlocks
|
|
{
|
|
datetime time1;
|
|
datetime time2;
|
|
double price1;
|
|
double price2;
|
|
string name;
|
|
bool mitigated;
|
|
bool case_book;
|
|
};
|
|
|
|
//--- Order Blocks Array
|
|
OrderBlocks bearish_ob[];
|
|
OrderBlocks bullish_ob[];
|
|
string pricetwo_eliminados_oba[];
|
|
string pricetwo_eliminados_obb[];
|
|
|
|
//--- Buffers
|
|
double buy_buffer[];
|
|
double sell_buffer[];
|
|
double tp1_buffer[];
|
|
double tp2_buffer[];
|
|
double sl1_buffer[];
|
|
double sl2_buffer[];
|
|
|
|
//--- Extra variables
|
|
datetime last_candle_time;
|
|
double ma[];
|
|
double atr[];
|
|
|
|
//--- Arrays longs para almacenar el volumen del book
|
|
long buy_volume[];
|
|
long sell_volume[];
|
|
|
|
//--- Flag to mark if the maket_book is used
|
|
bool use_market_book = true;
|
|
|
|
//--- Indicators handles
|
|
int Rsi_Handle; //Rsi handle
|
|
int hanlde_ma; //Ma Handle
|
|
int atr_i; //Atr Handle
|
|
|
|
//--- prefix for objects (this is to avoid conflicts with other order block indicators, or objects with the same name)
|
|
string code_obj;
|
|
|
|
//--- Extra
|
|
color color_of_bullish_ob;
|
|
color color_of_bearish_ob;
|
|
#define ORDER_BLOCK_IND_NAME "OrderBlockIndicator"
|
|
//+------------------------------------------------------------------+
|
|
//| Custom indicator initialization function |
|
|
//+------------------------------------------------------------------+
|
|
int OnInit()
|
|
{
|
|
//---
|
|
MathSrand(GetTickCount());
|
|
code_obj = StringFormat("%s_%s_%d_ob_indicator_",_Symbol,Version,MathRand());
|
|
//---
|
|
color_of_bullish_ob = ApplyTransparency(Color_Order_Block_Alcista, transparecy);
|
|
color_of_bearish_ob = ApplyTransparency(Color_Order_Block_Bajista, transparecy);
|
|
|
|
//---
|
|
if(Universal_range_search < 40)
|
|
{
|
|
ob_logger.LogError(StringFormat("Very small search range = %d", Universal_range_search), ORDER_BLOCK_IND_NAME);
|
|
return (INIT_PARAMETERS_INCORRECT);
|
|
}
|
|
|
|
//---
|
|
if(Universal_range_search >= Bars(_Symbol, _Period) + 31)
|
|
{
|
|
ob_logger.LogError(StringFormat("The data available for the indicator calculations are less than the calculation range %d", Bars(_Symbol, _Period) + 20, Universal_range_search), ORDER_BLOCK_IND_NAME);
|
|
return (INIT_PARAMETERS_INCORRECT);
|
|
}
|
|
|
|
//---
|
|
int max_attempts = 1000; // Maximum attempts (500 x 10ms = 5 seconds)
|
|
while(!SeriesInfoInteger(_Symbol, PERIOD_CURRENT, SERIES_SYNCHRONIZED) && max_attempts-- > 0)
|
|
Sleep(10);
|
|
|
|
if(max_attempts <= 1)
|
|
{
|
|
ob_logger.LogError("The data required for the indicator to function correctly is not synchronized.", ORDER_BLOCK_IND_NAME);
|
|
return INIT_FAILED;
|
|
}
|
|
|
|
datetime dummy[];
|
|
CopyTime(_Symbol, _Period, 0, MathMax(Bars(_Symbol, _Period) - 10, 100), dummy);
|
|
Sleep(100);
|
|
|
|
//--- Atr
|
|
ResetLastError();
|
|
atr_i = iATR(_Symbol, PERIOD_CURRENT, 14);
|
|
if(atr_i == INVALID_HANDLE)
|
|
{
|
|
ob_logger.LogError(StringFormat("The atr handle is invalid, last error descripcion: %s", ErrorDescription(GetLastError())), ORDER_BLOCK_IND_NAME);
|
|
return(INIT_FAILED);
|
|
}
|
|
|
|
//--- Ma
|
|
ResetLastError();
|
|
hanlde_ma = iMA(_Symbol, _Period, 30, 0, MODE_EMA, PRICE_CLOSE);
|
|
if(hanlde_ma == INVALID_HANDLE)
|
|
{
|
|
ob_logger.LogError(StringFormat("The ema indicator is not available. last error descripcion: %s", ErrorDescription(GetLastError())), ORDER_BLOCK_IND_NAME);
|
|
return(INIT_FAILED);
|
|
}
|
|
|
|
//--- Market Book
|
|
ResetLastError();
|
|
if(!MarketBookAdd(_Symbol))
|
|
{
|
|
use_market_book = false;
|
|
ob_logger.LogError(StringFormat("The order book could not be opened. last error descripcion: %s", ErrorDescription(GetLastError())), ORDER_BLOCK_IND_NAME);
|
|
}
|
|
else
|
|
ob_logger.LogInfo(StringFormat("Market Book available for the symbol: %s", _Symbol), ORDER_BLOCK_IND_NAME);
|
|
|
|
//---
|
|
ArrayResize(bearish_ob, 0);
|
|
ArrayResize(bullish_ob, 0);
|
|
ArraySetAsSeries(ma, true);
|
|
ArraySetAsSeries(atr, true);
|
|
string short_name = StringFormat("Order Block Indicator[%d]", Universal_range_search);
|
|
IndicatorSetString(INDICATOR_SHORTNAME, short_name);
|
|
IndicatorSetInteger(INDICATOR_DIGITS, _Digits);
|
|
|
|
//--- Plots
|
|
PlotIndexSetString(0, PLOT_LABEL, "Buy");
|
|
PlotIndexSetInteger(0, PLOT_ARROW, 233);
|
|
|
|
PlotIndexSetString(1, PLOT_LABEL, "Sell");
|
|
PlotIndexSetInteger(1, PLOT_ARROW, 234);
|
|
|
|
PlotIndexSetString(2, PLOT_LABEL, "Take Profit 1");
|
|
PlotIndexSetString(3, PLOT_LABEL, "Take Profit 2");
|
|
PlotIndexSetString(4, PLOT_LABEL, "Stop Loss 1");
|
|
PlotIndexSetString(5, PLOT_LABEL, "Stop Loss 2");
|
|
|
|
//--- Buffers
|
|
SetIndexBuffer(0, buy_buffer, INDICATOR_DATA);
|
|
SetIndexBuffer(1, sell_buffer, INDICATOR_DATA);
|
|
SetIndexBuffer(2, tp1_buffer, INDICATOR_DATA);
|
|
SetIndexBuffer(3, tp2_buffer, INDICATOR_DATA);
|
|
SetIndexBuffer(4, sl1_buffer, INDICATOR_DATA);
|
|
SetIndexBuffer(5, sl2_buffer, INDICATOR_DATA);
|
|
|
|
//---
|
|
ArraySetAsSeries(buy_buffer, true);
|
|
ArraySetAsSeries(sell_buffer, true);
|
|
ArrayFill(buy_buffer, 0, 0, EMPTY_VALUE);
|
|
ArrayFill(sell_buffer, 0, 0, EMPTY_VALUE);
|
|
|
|
//---
|
|
ArraySetAsSeries(tp1_buffer, true);
|
|
ArraySetAsSeries(tp2_buffer, true);
|
|
ArrayFill(tp1_buffer, 0, 0, EMPTY_VALUE);
|
|
ArrayFill(tp2_buffer, 0, 0, EMPTY_VALUE);
|
|
|
|
//---
|
|
ArraySetAsSeries(sl1_buffer, true);
|
|
ArraySetAsSeries(sl2_buffer, true);
|
|
ArrayFill(sl1_buffer, 0, 0, EMPTY_VALUE);
|
|
ArrayFill(sl2_buffer, 0, 0, EMPTY_VALUE);
|
|
|
|
//---
|
|
ArrayResize(buy_volume, 1);
|
|
ArrayResize(sell_volume, 1);
|
|
|
|
//---
|
|
buy_volume[0] = 0.0;
|
|
sell_volume[0] = 0.0;
|
|
|
|
//---
|
|
return(INIT_SUCCEEDED);
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Custom indicator iteration function |
|
|
//+------------------------------------------------------------------+
|
|
int OnCalculate(const int rates_total,
|
|
const int prev_calculated,
|
|
const datetime &time[],
|
|
const double &open[],
|
|
const double &high[],
|
|
const double &low[],
|
|
const double &close[],
|
|
const long &tick_volume[],
|
|
const long &volume[],
|
|
const int &spread[])
|
|
{
|
|
//---
|
|
static int counter = 0;
|
|
|
|
if(rates_total > prev_calculated)
|
|
{
|
|
counter++;
|
|
if(last_candle_time != iTime(_Symbol, PERIOD_D1, 0))
|
|
{
|
|
Eliminar_Objetos();
|
|
ArrayFree(bearish_ob);
|
|
ArrayFree(bullish_ob);
|
|
last_candle_time = iTime(_Symbol, PERIOD_D1, 0);
|
|
}
|
|
|
|
if(counter > 1 && use_market_book == true)
|
|
{
|
|
if(ArraySize(buy_volume) > 4 && ArraySize(sell_volume) > 4)
|
|
{
|
|
if(buy_volume[3] == 0 && sell_volume[3] == 0 &&
|
|
buy_volume[2] == 0 && sell_volume[2] == 0 &&
|
|
buy_volume[1] == 0 && sell_volume[1] == 0)
|
|
{
|
|
use_market_book = false;
|
|
ob_logger.LogWarning("Disabling use of the market book because there is no data available.", ORDER_BLOCK_IND_NAME);
|
|
}
|
|
}
|
|
|
|
if(ArraySize(buy_volume) >= 30)
|
|
{
|
|
ArrayResize(buy_volume, 30); // Ensure that the size of buy_volume does not exceed 30
|
|
ArrayResize(sell_volume, 30); // Ensure that the size of sell_volume does not exceed 30
|
|
}
|
|
|
|
ArrayResize(buy_volume, ArraySize(buy_volume) + 1);
|
|
ArrayResize(sell_volume, ArraySize(sell_volume) + 1);
|
|
|
|
for(int i = ArraySize(buy_volume) - 1; i > 0; i--)
|
|
{
|
|
buy_volume[i] = buy_volume[i - 1];
|
|
sell_volume[i] = sell_volume[i - 1];
|
|
}
|
|
|
|
buy_volume[0] = 0;
|
|
sell_volume[0] = 0;
|
|
}
|
|
}
|
|
|
|
//---
|
|
if(rates_total > prev_calculated)
|
|
{
|
|
ArraySetAsSeries(open, true);
|
|
ArraySetAsSeries(close, true);
|
|
ArraySetAsSeries(high, true);
|
|
ArraySetAsSeries(low, true);
|
|
ArraySetAsSeries(time, true);
|
|
ArraySetAsSeries(tick_volume, true);
|
|
|
|
if(prev_calculated == 0)
|
|
{
|
|
ResetLastError();
|
|
if(CopyBuffer(atr_i, 0, 0, Universal_range_search + 10, atr) < 1)
|
|
{
|
|
ob_logger.LogError(StringFormat("Could not copy data from the ATR indicator, last error description: %s", ErrorDescription(GetLastError())), ORDER_BLOCK_IND_NAME);
|
|
return rates_total;
|
|
}
|
|
|
|
ResetLastError();
|
|
if(CopyBuffer(hanlde_ma, 0, 0, 5, ma) < 5)
|
|
{
|
|
ob_logger.LogError(StringFormat("Could not copy data from the Ma indicator, last error description: %s", ErrorDescription(GetLastError())), ORDER_BLOCK_IND_NAME);
|
|
return rates_total;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ResetLastError();
|
|
if(CopyBuffer(atr_i, 0, 0, 10, atr) < 10)
|
|
{
|
|
ob_logger.LogError(StringFormat("Could not copy data from the ATR indicator, last error description: %s", ErrorDescription(GetLastError())), ORDER_BLOCK_IND_NAME);
|
|
return rates_total;
|
|
}
|
|
|
|
ResetLastError();
|
|
if(CopyBuffer(hanlde_ma, 0, 0, 5, ma) < 5)
|
|
{
|
|
ob_logger.LogError(StringFormat("Could not copy data from the Ma indicator, last error description: %s", ErrorDescription(GetLastError())), ORDER_BLOCK_IND_NAME);
|
|
return rates_total;
|
|
}
|
|
}
|
|
|
|
|
|
//----------------- Bullish order blocks
|
|
OrderBlocks newVela_Order_block_alcista;
|
|
OrderBlocks newVela_Order_block_volumen;
|
|
OrderBlocks newVela_Order_block_Book;
|
|
|
|
int inicio = prev_calculated == 0 ? Universal_range_search : 6;
|
|
|
|
for(int i = inicio ; i > 5 ; i--)
|
|
{
|
|
if(i + 3 > ArraySize(high) || i + 3 > ArraySize(atr))
|
|
continue;
|
|
if(i < 0)
|
|
continue;
|
|
|
|
//--- Declaracion de variables
|
|
int one_vela = i ;
|
|
int two_candles_previous_to_one_candle = i + 2;
|
|
int one_candle_before_one_candle = one_vela + 1;
|
|
int two_vela = one_vela - 1;
|
|
int tree_vela = one_vela - 2;
|
|
int four_vela = one_vela - 3;
|
|
double body1 = close[one_vela] - open[one_vela];
|
|
double body2 = close[two_vela] - open[two_vela];
|
|
double body3 = close[tree_vela] - open[two_vela];
|
|
long Volumen_one_vela = tick_volume[one_vela];
|
|
long Volumen_two_vela = tick_volume[two_vela];
|
|
long volumen_one_candle_before_one_candle = tick_volume[one_candle_before_one_candle];
|
|
|
|
bool case_bullish_orderblock_normal = false; //Flag indicating that the order block has been obtained in the "normal" case
|
|
bool case_orderblock_vol = false; //Flag indicating that the order block has been obtained by the "volume" case
|
|
|
|
//--- Conditions
|
|
bool IsCorrectCandleForNormalCase = close[one_vela] > open[one_vela] && close[two_vela] > open[two_vela]
|
|
&& close[tree_vela] > open[tree_vela] && close[four_vela] > open[four_vela];
|
|
|
|
bool IsHammerCandle = open[one_vela] - low[one_vela] > close[one_vela] - open[one_vela];
|
|
|
|
bool fuerte_movimiento_alcista = close[one_vela + 2] > open[one_vela + 2] &&
|
|
close[one_vela + 1] > open[one_vela + 1] &&
|
|
close[one_vela] > open[one_vela] &&
|
|
close[two_vela] > open[two_vela] &&
|
|
close[tree_vela] > open[tree_vela] &&
|
|
close[four_vela] > open[four_vela];
|
|
|
|
bool atr_case = atr[two_candles_previous_to_one_candle] > atr[one_vela] && atr[two_vela] > atr[one_vela] && atr[two_vela] > atr[two_candles_previous_to_one_candle] && close[one_vela] > open[one_vela]
|
|
&& close[four_vela] > open[four_vela] && close[tree_vela] > open[tree_vela]; //case by atr (included in normal)
|
|
|
|
|
|
if((IsCorrectCandleForNormalCase && ((low[two_vela] > ((body1 * 0.5) + open[one_vela]) && ((body2 * 0.4) + open[two_vela]) > high[one_vela]) || IsHammerCandle)
|
|
&& low[tree_vela] > ((body2 * 0.25) + open[two_vela])) || fuerte_movimiento_alcista || atr_case ) //Here at the beginning we look for the highlights not to exceed important points
|
|
{
|
|
int furthestAlcista = FindFurthestAlcista(time[one_vela], 20, _Period, _Symbol);
|
|
|
|
if(furthestAlcista > 0)
|
|
{
|
|
datetime time1 = time[furthestAlcista];
|
|
double price2 = open[furthestAlcista];
|
|
double price1 = low[furthestAlcista];
|
|
newVela_Order_block_alcista.price1 = price1;
|
|
newVela_Order_block_alcista.time1 = time1;
|
|
newVela_Order_block_alcista.price2 = price2;
|
|
newVela_Order_block_alcista.case_book = false;
|
|
case_bullish_orderblock_normal = true;
|
|
}
|
|
else
|
|
case_bullish_orderblock_normal = false;
|
|
}
|
|
|
|
//--- Verify that the case is met by volume
|
|
bool CorrectCandleForVolumeCase = close[one_vela] > open[one_vela] && close[two_vela] > open[two_vela];
|
|
bool CorrectVolume = Volumen_one_vela > Volumen_two_vela && Volumen_one_vela > volumen_one_candle_before_one_candle;
|
|
bool case_vol_2 = (tick_volume[one_vela] > volumen_one_candle_before_one_candle && tick_volume[two_vela] > tick_volume[one_vela] &&
|
|
open[tree_vela] < close[tree_vela] && open[four_vela] < close[four_vela]);
|
|
|
|
//---
|
|
if((CorrectVolume && CorrectCandleForVolumeCase
|
|
&& ((low[two_vela] > ((body1 * 0.5) + open[one_vela]) && ((body2 * 0.6) + open[two_vela]) > high[one_vela]) || IsHammerCandle == true)
|
|
&& high[tree_vela] > open[two_vela]) || case_vol_2 == true)
|
|
{
|
|
int furthestAlcista = FindFurthestAlcista(time[one_vela], 20, _Period, _Symbol);
|
|
if(furthestAlcista > 0)
|
|
{
|
|
datetime time1 = time[furthestAlcista];
|
|
double price2 = open[furthestAlcista];
|
|
double price1 = low[furthestAlcista];
|
|
newVela_Order_block_volumen.price1 = price1;
|
|
newVela_Order_block_volumen.time1 = time1;
|
|
newVela_Order_block_volumen.case_book = false;
|
|
newVela_Order_block_volumen.price2 = price2;
|
|
case_orderblock_vol = true;
|
|
}
|
|
else
|
|
case_orderblock_vol = false;
|
|
}
|
|
|
|
if(case_bullish_orderblock_normal && IsBullishObMitigated(newVela_Order_block_alcista.price2, low, time, newVela_Order_block_alcista.time1, time[0]) == 0)
|
|
{
|
|
newVela_Order_block_alcista.mitigated = false;
|
|
newVela_Order_block_alcista.name = code_obj + "bull_" + TimeToString(newVela_Order_block_alcista.time1) ;
|
|
AddArray(bullish_ob, newVela_Order_block_alcista);
|
|
}
|
|
if(case_orderblock_vol && IsBullishObMitigated(newVela_Order_block_volumen.price2, low, time, newVela_Order_block_volumen.time1, time[0]) == 0)
|
|
{
|
|
newVela_Order_block_volumen.mitigated = false;
|
|
newVela_Order_block_volumen.name = code_obj + "bull_" + TimeToString(newVela_Order_block_volumen.time1) ;
|
|
AddArray(bullish_ob, newVela_Order_block_volumen);
|
|
}
|
|
}
|
|
|
|
//--- Check the case on MarketBook
|
|
if(ArraySize(buy_volume) >= 5 && ArraySize(sell_volume) >= 5 && use_market_book)
|
|
{
|
|
const double ratio = 1.4;
|
|
bool case_book = buy_volume[3] > buy_volume[4] * ratio && buy_volume[3] > buy_volume[2] * ratio &&
|
|
buy_volume[3] > sell_volume[4] * ratio && buy_volume[3] > sell_volume[2] * ratio;
|
|
|
|
double body_tree = close[3] - open[3];
|
|
|
|
if(low[2] > ((body_tree * 0.5) + open[3]) && high[3] < close[2] &&
|
|
close[3] > open[3] && close[2] > open[2] && close[1] > open[1] && case_book)
|
|
{
|
|
int furthestAlcista = FindFurthestAlcista(time[3], 20, _Period, _Symbol);
|
|
if(furthestAlcista > 0)
|
|
{
|
|
datetime time1 = time[furthestAlcista];
|
|
double price2 = open[furthestAlcista];
|
|
double price1 = low[furthestAlcista];
|
|
newVela_Order_block_Book.price1 = price1;
|
|
newVela_Order_block_Book.time1 = time1;
|
|
newVela_Order_block_Book.price2 = price2;
|
|
newVela_Order_block_Book.case_book = true;
|
|
newVela_Order_block_Book.mitigated = false;
|
|
newVela_Order_block_Book.name = code_obj + "bull_" + TimeToString(newVela_Order_block_Book.time1);
|
|
AddArray(bullish_ob, newVela_Order_block_Book);
|
|
}
|
|
}
|
|
}
|
|
|
|
//---
|
|
static bool buscar_oba = true;
|
|
static datetime time_a = 0;
|
|
string curr_elimiandor_oba[];
|
|
|
|
for(int i = 0; i < ArraySize(bullish_ob); i++)
|
|
{
|
|
datetime mitigadoTime = IsBullishOrderBlockMitigated(bullish_ob[i], bullish_ob[i].time1);
|
|
|
|
if(!bullish_ob[i].mitigated)
|
|
{
|
|
if(ObjectFind(ChartID(), bullish_ob[i].name) < 0)
|
|
{
|
|
|
|
const static string tools[2] = { "Order Block Alcista", "Order Block Alcista Book" };
|
|
RectangleCreate(ChartID(), bullish_ob[i].name, 0, bullish_ob[i].time1, bullish_ob[i].price1,
|
|
time[0], bullish_ob[i].price2, color_of_bullish_ob, Witdth_order_block, Fill_order_block, Back_order_block, STYLE_SOLID, false, tools[int(bullish_ob[i].case_book)]);
|
|
}
|
|
else
|
|
ObjectSetInteger(ChartID(), bullish_ob[i].name, OBJPROP_TIME, 1, time[0]); //On the contrary, if the object exists, all we will do is update it at the current time using anchor point 1
|
|
}
|
|
else
|
|
{
|
|
if(enable_alerts)
|
|
Alert("The bullish order block is being mitigated: ", TimeToString(bullish_ob[i].time1));
|
|
|
|
AddArrayNoVerification(pricetwo_eliminados_oba, bullish_ob[i].name);
|
|
AddArrayNoVerification(curr_elimiandor_oba, bullish_ob[i].name);
|
|
|
|
if(buscar_oba == true)
|
|
{
|
|
buscar_oba = false;
|
|
time_a = iTime(_Symbol, _Period, 1);
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
for(int i = 0; i < ArraySize(curr_elimiandor_oba) ; i++)
|
|
DeleteArrayBiName(bullish_ob, curr_elimiandor_oba[i]);
|
|
|
|
if(buscar_oba == false && time_a > 0)
|
|
{
|
|
double close_ = NormalizeDouble(close[1], _Digits);
|
|
datetime max_time_espera = time_a + (PeriodSeconds() * 7); //Maximum wait 7 candles to confirm the break of the moving average
|
|
if(close_ > ma[1] && time[0] <= max_time_espera)
|
|
{
|
|
double ask = NormalizeDouble(SymbolInfoDouble(_Symbol, SYMBOL_ASK), _Digits);
|
|
double tp1;
|
|
double tp2;
|
|
double sl1;
|
|
double sl2;
|
|
GetTP_SL(ask, POSITION_TYPE_BUY, tp1, tp2, sl1, sl2);
|
|
DrawTP_SL(tp1, tp2, sl1, sl2);
|
|
tp1_buffer[0] = tp1;
|
|
tp2_buffer[0] = tp2;
|
|
sl1_buffer[0] = sl1;
|
|
sl2_buffer[0] = sl2;
|
|
buy_buffer[0] = ask - atr[0] * 1.3;
|
|
time_a = 0;
|
|
buscar_oba = true;
|
|
}
|
|
if(time[0] > max_time_espera)
|
|
{
|
|
time_a = 0;
|
|
buscar_oba = true;
|
|
}
|
|
}
|
|
|
|
//----------------- Bearish order blocks
|
|
OrderBlocks newVela_Order_Block_bajista;
|
|
OrderBlocks newVela_Order_Block_bajista_2;
|
|
OrderBlocks newVela_Order_block_Book_bajista;
|
|
|
|
for(int i = inicio ; i > 5 ; i--)
|
|
{
|
|
if(i + 3 > ArraySize(high) || i + 3 > ArraySize(atr))
|
|
continue;
|
|
|
|
if(i < 0)
|
|
continue;
|
|
|
|
//-------- Variable Declaration --------------------------------------------//
|
|
// Update candlestick indices
|
|
int one_vela = i ; //vela central
|
|
int one_candle_before_one_candle = one_vela + 1;
|
|
int two_vela = one_vela - 1;
|
|
int tree_vela = one_vela - 2;
|
|
int two_candles_previous_to_one_candle = one_vela + 2;
|
|
double body1 = open[one_vela] - close[one_vela];
|
|
double body2 = open[two_vela] - close[two_vela];
|
|
double body3 = open[tree_vela] - close[tree_vela];
|
|
long Volumen_one_vela = tick_volume[one_vela];
|
|
long Volumen_two_vela = tick_volume[two_vela];
|
|
long volumen_one_candle_before_one_candle = tick_volume[one_candle_before_one_candle];
|
|
bool case_OrderBlockBajista_normal = false;
|
|
bool case_OrderBlockBajista_volumen = false;
|
|
|
|
bool IsCorrectCandleForNormalCase = close[one_vela] < open[one_vela] &&
|
|
close[two_vela] < open[two_vela] &&
|
|
close[tree_vela] < open[tree_vela] &&
|
|
close[one_vela - 3] < open[one_vela - 3];
|
|
|
|
bool a = atr[two_candles_previous_to_one_candle] > atr[one_vela] && atr[two_vela] > atr[one_vela] && atr[two_vela] > atr[two_candles_previous_to_one_candle] && IsCorrectCandleForNormalCase;
|
|
|
|
|
|
bool StrongBearishMovement = close[one_vela + 2] < open[one_vela + 2] && close[one_vela + 1] < open[one_vela + 1] && close[one_vela] < open[one_vela] &&
|
|
close[two_vela] < open[two_vela] && close[tree_vela] < open[tree_vela] && close[one_vela - 3] <= open[one_vela - 3];
|
|
|
|
if((IsCorrectCandleForNormalCase == true && high[two_vela] < ((body1 * 0.70) + close[one_vela]) && ((body2 * 0.4) + close[two_vela]) < low[one_vela] && high[tree_vela] < high[two_vela])
|
|
|| a || StrongBearishMovement)
|
|
{
|
|
int furthestBajista = FindFurthestBajista(time[one_vela], 20, _Period, _Symbol);
|
|
if(furthestBajista != -1)
|
|
{
|
|
datetime time1 = time[furthestBajista];
|
|
double price1 = close[furthestBajista];
|
|
double price2 = low[furthestBajista];
|
|
newVela_Order_Block_bajista.price1 = price1;
|
|
newVela_Order_Block_bajista.time1 = time1;
|
|
newVela_Order_Block_bajista.case_book = false;
|
|
newVela_Order_Block_bajista.price2 = price2 ;
|
|
}
|
|
else
|
|
case_OrderBlockBajista_normal = false;
|
|
}
|
|
|
|
bool CorrectCandleForVolumeCase = close[one_vela] < open[one_vela] && close[two_vela] < open[two_vela];
|
|
bool CorrectVolume = Volumen_one_vela > Volumen_two_vela && Volumen_one_vela > volumen_one_candle_before_one_candle;
|
|
bool case_vol_2 = tick_volume[one_vela] > volumen_one_candle_before_one_candle && tick_volume[two_vela] > tick_volume[one_vela] && open[tree_vela] > close[tree_vela] && open[one_vela - 3] > close[one_vela - 3];
|
|
|
|
if((CorrectVolume == true && CorrectCandleForVolumeCase == true && high[two_vela] < ((body1 * 0.5) + close[one_vela])
|
|
&& ((body2 * 0.5) + close[two_vela]) < low[one_vela]) || case_vol_2 == true) // verificamos si se cumple
|
|
{
|
|
int furthestBajista = FindFurthestBajista(time[one_vela], 20, _Period, _Symbol);
|
|
if(furthestBajista > 0)
|
|
{
|
|
datetime time1 = time[furthestBajista];
|
|
double price1 = close[furthestBajista];
|
|
double price2 = low[furthestBajista];
|
|
newVela_Order_Block_bajista_2.price1 = price1;
|
|
newVela_Order_Block_bajista_2.time1 = time1;
|
|
newVela_Order_Block_bajista_2.price2 = price2 ;
|
|
newVela_Order_Block_bajista_2.case_book = false;
|
|
case_OrderBlockBajista_volumen = true;
|
|
}
|
|
else
|
|
case_OrderBlockBajista_volumen = false;
|
|
}
|
|
|
|
if(case_OrderBlockBajista_normal == true && mitigado_bajista(newVela_Order_Block_bajista.price2, high, time, newVela_Order_Block_bajista.time1, time[0]) == 0)
|
|
{
|
|
newVela_Order_Block_bajista.mitigated = false;
|
|
newVela_Order_Block_bajista.name = code_obj + "bear_" + TimeToString(newVela_Order_Block_bajista.time1);
|
|
AddArray(bearish_ob, newVela_Order_Block_bajista); //we add the structure to the array
|
|
}
|
|
if(case_OrderBlockBajista_volumen == true && mitigado_bajista(newVela_Order_Block_bajista_2.price2, high, time, newVela_Order_Block_bajista_2.time1, time[0]) == 0)
|
|
{
|
|
newVela_Order_Block_bajista_2.mitigated = false;
|
|
newVela_Order_Block_bajista_2.name = code_obj + "bear_" + TimeToString(newVela_Order_Block_bajista_2.time1);
|
|
AddArray(bearish_ob, newVela_Order_Block_bajista_2); //we add the structure to the array
|
|
}
|
|
}
|
|
|
|
if(ArraySize(buy_volume) >= 5 && ArraySize(sell_volume) >= 5 && use_market_book == true)
|
|
{
|
|
const double ratio = 1.4;
|
|
bool case_book = sell_volume[3] > buy_volume[4] * ratio && sell_volume[3] > buy_volume[2] * ratio &&
|
|
sell_volume[3] > sell_volume[4] * ratio && sell_volume[3] > sell_volume[2] * ratio;
|
|
|
|
double body_tree = open[3] - close[3];
|
|
if(high[2] < (open[3] - (body_tree * 0.5)) && low[3] > close[2] && close[3] < open[3] && close[2] < open[2] && close[1] < open[1] && case_book)
|
|
{
|
|
int furthestBajista = FindFurthestBajista(time[3], 20, _Period, _Symbol);
|
|
if(furthestBajista > 0)
|
|
{
|
|
datetime time1 = time[furthestBajista];
|
|
double price1 = close[furthestBajista];
|
|
double price2 = low[furthestBajista];
|
|
newVela_Order_block_Book_bajista.price1 = price1;
|
|
newVela_Order_block_Book_bajista.time1 = time1;
|
|
newVela_Order_block_Book_bajista.case_book = true;
|
|
newVela_Order_block_Book_bajista.price2 = price2;
|
|
newVela_Order_block_Book_bajista.mitigated = false;
|
|
newVela_Order_block_Book_bajista.name = code_obj + "bear_" + TimeToString(newVela_Order_block_Book_bajista.time1);
|
|
AddArray(bearish_ob, newVela_Order_block_Book_bajista);
|
|
}
|
|
}
|
|
}
|
|
|
|
//--- Initial declaration of variables
|
|
static bool buscar_obb = true; //Flag indicating whether a bearish order block is being sought
|
|
static datetime time_b = 0; //Time in which the bearish order block was mitigated (to be able to schedule a maximum wait)
|
|
string curr_elimiandor_obb[]; //Array with the names of the order blocks that will be removed from the bearish_ob array
|
|
|
|
for(int i = 0; i < ArraySize(bearish_ob); i++)
|
|
{
|
|
datetime mitigadoTime = esOb_mitigado_array_bajista(bearish_ob[i], bearish_ob[i].time1);
|
|
|
|
if(bearish_ob[i].mitigated == false) //if it has not been mitigated
|
|
{
|
|
if(ObjectFind(ChartID(), bearish_ob[i].name) < 0) //If the object does not exist, we create it
|
|
{
|
|
const static string tools[2] = { "Order Block Bajista", "Order Block Bajista Book"};
|
|
RectangleCreate(ChartID(), bearish_ob[i].name, 0, bearish_ob[i].time1, bearish_ob[i].price1,
|
|
time[0], bearish_ob[i].price2, color_of_bearish_ob, Witdth_order_block, Fill_order_block, Back_order_block, STYLE_SOLID, false, tools[int(bearish_ob[i].case_book)]);
|
|
}
|
|
else //If it exists, we update it (we only move anchor point 1)
|
|
ObjectSetInteger(ChartID(), bearish_ob[i].name, OBJPROP_TIME, 1, time[0]);
|
|
}
|
|
else
|
|
{
|
|
//A bearish order block has been mitigated
|
|
if(enable_alerts)
|
|
Alert("The bearish order block is being mitigated: ", TimeToString(bearish_ob[i].time1)); //We print an alert
|
|
AddArrayNoVerification(pricetwo_eliminados_obb, bearish_ob[i].name); //To be able to remove the rectangle from the order block we save its name
|
|
AddArrayNoVerification(curr_elimiandor_obb, bearish_ob[i].name); //We add to the string array so that it is removed from the main array
|
|
|
|
if(buscar_obb == true) //If we search for obb, it means that we are searching for a signal, so we initialize the start time time_b with the current one, (this is to calculate the maximum wait)
|
|
{
|
|
time_b = iTime(_Symbol, _Period, 0);
|
|
buscar_obb = false;
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
for(int i = 0; i < ArraySize(curr_elimiandor_obb) ; i++)
|
|
DeleteArrayBiName(bearish_ob, curr_elimiandor_obb[i]); //We remove the indicated name from the array (name)
|
|
|
|
if(buscar_obb == false && time_b > 0)
|
|
{
|
|
double close_ = NormalizeDouble(close[1], _Digits); //We normalize the price
|
|
datetime max_time_espera = time_b + (PeriodSeconds() * 5); //Maximum wait 5 candles to confirm the break of the moving average
|
|
if(close_ < ma[1] && time[0] <= max_time_espera) //We verify that the previous close is lower than the value of the previous EMA and that the last opening time is less than the maximum wait
|
|
{
|
|
double bid = NormalizeDouble(SymbolInfoDouble(_Symbol, SYMBOL_BID), _Digits); //Obtenmos el bid
|
|
double tp1, tp2, sl1, sl2;
|
|
|
|
GetTP_SL(bid, POSITION_TYPE_SELL, tp1, tp2, sl1, sl2); //We get the tp, sl
|
|
DrawTP_SL(tp1, tp2, sl1, sl2); //We draw
|
|
|
|
//--- Let's assign to the buffers
|
|
tp1_buffer[0] = tp1;
|
|
tp2_buffer[0] = tp2;
|
|
sl1_buffer[0] = sl1;
|
|
sl2_buffer[0] = sl2;
|
|
|
|
//---
|
|
sell_buffer[0] = bid + atr[0] * 1.3;
|
|
|
|
//--- We reset the variables
|
|
time_b = 0;
|
|
buscar_obb = true;
|
|
}
|
|
if(time[0] > max_time_espera) //If the maximum wait is exceeded, we also restart and look for another mitigated bearish order block.
|
|
{
|
|
time_b = 0;
|
|
buscar_obb = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
//--- return value of prev_calculated for next call
|
|
return(rates_total);
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
void OnDeinit(const int reason)
|
|
{
|
|
//---
|
|
Eliminar_Objetos();
|
|
ArrayFree(bearish_ob);
|
|
ArrayFree(bullish_ob);
|
|
|
|
if(atr_i != INVALID_HANDLE)
|
|
IndicatorRelease(atr_i);
|
|
if(hanlde_ma != INVALID_HANDLE)
|
|
IndicatorRelease(hanlde_ma);
|
|
|
|
ResetLastError();
|
|
//---
|
|
if(MarketBookRelease(_Symbol)) //Verificamos si el cierre fue exitoso
|
|
ob_logger.LogInfo("Market book closed successfully", ORDER_BLOCK_IND_NAME);
|
|
else
|
|
ob_logger.LogWarning(StringFormat("Order book not closed successfully, last error description = %s", ErrorDescription(GetLastError())), ORDER_BLOCK_IND_NAME);
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
void OnBookEvent(const string& symbol)
|
|
{
|
|
if(symbol != _Symbol || use_market_book == false)
|
|
return;
|
|
|
|
MqlBookInfo book_info[];
|
|
bool book_count = MarketBookGet(_Symbol, book_info);
|
|
|
|
if(book_count == true)
|
|
{
|
|
for(int i = 0; i < ArraySize(book_info); i++)
|
|
{
|
|
if(book_info[i].type == BOOK_TYPE_BUY || book_info[i].type == BOOK_TYPE_BUY_MARKET)
|
|
buy_volume[0] += book_info[i].volume;
|
|
else
|
|
if(book_info[i].type == BOOK_TYPE_SELL || book_info[i].type == BOOK_TYPE_SELL_MARKET)
|
|
sell_volume[0] += book_info[i].volume;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ob_logger.LogWarning("No data has been obtained from the Market Book.", ORDER_BLOCK_IND_NAME);
|
|
}
|
|
}
|
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
void OnChartEvent(const int id,
|
|
const long &lparam,
|
|
const double &dparam,
|
|
const string &sparam)
|
|
{
|
|
if(id == CHARTEVENT_CHART_CHANGE && lparam == 3)
|
|
{
|
|
color_of_bullish_ob = ApplyTransparency(Color_Order_Block_Alcista, transparecy);
|
|
color_of_bearish_ob = ApplyTransparency(Color_Order_Block_Bajista, transparecy);
|
|
ModificarColor();
|
|
}
|
|
}
|
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Array |
|
|
//+------------------------------------------------------------------+
|
|
template <typename S>
|
|
bool AddArray(S &Array[], const S &Value)
|
|
{
|
|
for(int i = 0 ; i < ArraySize(Array) ; i++)
|
|
{
|
|
if(Array[i].name == Value.name)
|
|
return false;
|
|
}
|
|
ArrayResize(Array, Array.Size() + 1);
|
|
Array[Array.Size() - 1] = Value;
|
|
return true;
|
|
}
|
|
|
|
template <typename X>
|
|
void AddArrayNoVerification(X &array[], const X &value)
|
|
{
|
|
ArrayResize(array, array.Size() + 1);
|
|
array[array.Size() - 1] = value;
|
|
}
|
|
|
|
template<typename T>
|
|
bool DeleteArrayBiName(T &array[], const string targetName)
|
|
{
|
|
int size = ArraySize(array);
|
|
int index = -1;
|
|
|
|
|
|
for(int i = 0; i < size; i++)
|
|
{
|
|
if(array[i].name == targetName)
|
|
{
|
|
index = i;
|
|
}
|
|
if(index != -1 && i < size - 1)
|
|
{
|
|
array[i] = array[i + 1]; // Move the elements
|
|
}
|
|
}
|
|
|
|
if(index == -1)
|
|
return false;
|
|
|
|
if(size > 1)
|
|
ArrayResize(array, size - 1);
|
|
else
|
|
ArrayFree(array); // If the array had only one element, it is completely freed
|
|
|
|
return true;
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
datetime IsBullishObMitigated(double price, const double &lowArray[], const datetime &Time[], datetime start, datetime end)
|
|
{
|
|
int startIndex = iBarShift(_Symbol, PERIOD_CURRENT, start);
|
|
int endIndex = iBarShift(_Symbol, PERIOD_CURRENT, end);
|
|
|
|
NormalizeDouble(price, _Digits);
|
|
for(int i = startIndex - 2 ; i >= endIndex + 1 ; i--)
|
|
{
|
|
if(price > lowArray[i])
|
|
{
|
|
return Time[i];//if it finds that there was, it returns the time of the candle where the mitigation occurred
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
datetime mitigado_bajista(double price, const double &highArray[], const datetime &Time[], datetime start, datetime end)
|
|
{
|
|
int startIndex = iBarShift(_Symbol, PERIOD_CURRENT, start);
|
|
int endIndex = iBarShift(_Symbol, PERIOD_CURRENT, end);
|
|
NormalizeDouble(price, _Digits);
|
|
for(int i = startIndex - 2 ; i >= endIndex + 1 ; i--)
|
|
{
|
|
if(highArray[i] > price)
|
|
{
|
|
return Time[i]; ///if it finds that there was, it returns the time of the candle where the mitigation occurred
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
datetime IsBullishOrderBlockMitigated(OrderBlocks &newblock, datetime end)
|
|
{
|
|
int endIndex = iBarShift(_Symbol, PERIOD_CURRENT, end) - 2;
|
|
if(endIndex < 0)
|
|
return 0;
|
|
|
|
for(int i = 0 ; i < endIndex; i++)
|
|
{
|
|
double low = iLow(_Symbol, PERIOD_CURRENT, i);
|
|
if(newblock.price2 >= low)
|
|
{
|
|
newblock.mitigated = true;
|
|
newblock.time2 = iTime(_Symbol, _Period, i);
|
|
return newblock.time2;//returns the time of the candle found
|
|
}
|
|
}
|
|
return 0;// not mitigated so far
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
datetime esOb_mitigado_array_bajista(OrderBlocks &newblock, datetime end)
|
|
{
|
|
int endIndex = iBarShift(_Symbol, PERIOD_CURRENT, end) - 2;
|
|
if(endIndex < 0)
|
|
return 0;
|
|
|
|
for(int i = 0 ; i < endIndex ; i++)
|
|
{
|
|
double high = iHigh(_Symbol, PERIOD_CURRENT, i);
|
|
if(high >= newblock.price2)
|
|
{
|
|
newblock.mitigated = true;
|
|
newblock.time2 = iTime(_Symbol, _Period, i);
|
|
return newblock.time2;
|
|
}
|
|
}
|
|
return 0; // not mitigated so far
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
int FindFurthestBajista(datetime start, int numVelas, ENUM_TIMEFRAMES timeframe, string symbol)
|
|
{
|
|
int startVela = iBarShift(symbol, timeframe, start);
|
|
|
|
for(int i = startVela + 1, c = 0; i <= startVela + numVelas; i++, c++)
|
|
{
|
|
if(iClose(symbol, timeframe, i) > iOpen(symbol, timeframe, i))
|
|
return startVela + 1 + c;
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
int FindFurthestAlcista(datetime start, int numVelas, ENUM_TIMEFRAMES timeframe, string symbol)
|
|
{
|
|
int startVela = iBarShift(symbol, timeframe, start);
|
|
|
|
for(int i = startVela + 1, c = 0; i <= startVela + numVelas; i++, c++)
|
|
{
|
|
if(iClose(symbol, timeframe, i) < iOpen(symbol, timeframe, i))
|
|
return startVela + 1 + c;
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| TP-SL |
|
|
//+------------------------------------------------------------------+
|
|
void GetTP_SL(double price_open_position, ENUM_POSITION_TYPE type, double &tp1, double &tp2, double &sl1, double &sl2)
|
|
{
|
|
if(CopyBuffer(atr_i, 0, 0, 1, atr) < 1)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if(tp_sl_style == ATR)
|
|
{
|
|
if(type == POSITION_TYPE_BUY)
|
|
{
|
|
sl1 = price_open_position - (atr[0] * Atr_Multiplier_1);
|
|
sl2 = price_open_position - (atr[0] * Atr_Multiplier_2);
|
|
tp1 = price_open_position + (atr[0] * Atr_Multiplier_1);
|
|
tp2 = price_open_position + (atr[0] * Atr_Multiplier_2);
|
|
}
|
|
if(type == POSITION_TYPE_SELL)
|
|
{
|
|
sl1 = price_open_position + (atr[0] * Atr_Multiplier_1);
|
|
sl2 = price_open_position + (atr[0] * Atr_Multiplier_2);
|
|
tp1 = price_open_position - (atr[0] * Atr_Multiplier_1);
|
|
tp2 = price_open_position - (atr[0] * Atr_Multiplier_2);
|
|
}
|
|
}
|
|
else
|
|
if(tp_sl_style == POINT)
|
|
{
|
|
if(type == POSITION_TYPE_BUY)
|
|
{
|
|
sl1 = price_open_position - (SL_POINT * _Point);
|
|
sl2 = price_open_position - (SL_POINT * _Point * 2);
|
|
tp1 = price_open_position + (TP_POINT * _Point);
|
|
tp2 = price_open_position + (TP_POINT * _Point * 2);
|
|
}
|
|
if(type == POSITION_TYPE_SELL)
|
|
{
|
|
sl1 = price_open_position + (SL_POINT * _Point);
|
|
sl2 = price_open_position + (SL_POINT * _Point * 2);
|
|
tp1 = price_open_position - (TP_POINT * _Point);
|
|
tp2 = price_open_position - (TP_POINT * _Point * 2);
|
|
}
|
|
}
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
void DrawTP_SL(double tp1, double tp2, double sl1, double sl2)
|
|
{
|
|
string curr_time = "ENTRY" + TimeToString(iTime(_Symbol, _Period, 0));
|
|
datetime extension_time = iTime(_Symbol, _Period, 0) + (PeriodSeconds(PERIOD_CURRENT) * 15);
|
|
datetime text_time = extension_time + (PeriodSeconds(PERIOD_CURRENT) * 2);
|
|
// Print("SL1: " , sl1 , " SL2: " , sl2 , " TP1: " , tp1 , " TP2: " , tp2);
|
|
TrendCreate(0, curr_time + " TP1", 0, iTime(_Symbol, _Period, 0), tp1, extension_time, tp1, clrGreen, STYLE_DOT, 1, true, false);
|
|
TextCreate(0, curr_time + " TP1 - Text", 0, text_time, tp1, "TP1", "Arial", 8, clrGreen, 0.0, ANCHOR_CENTER);
|
|
TrendCreate(0, curr_time + " TP2", 0, iTime(_Symbol, _Period, 0), tp2, extension_time, tp2, clrGreen, STYLE_DOT, 1, true, false);
|
|
TextCreate(0, curr_time + " TP2 - Text", 0, text_time, tp2, "TP2", "Arial", 8, clrGreen, 0.0, ANCHOR_CENTER);
|
|
TrendCreate(0, curr_time + " SL1", 0, iTime(_Symbol, _Period, 0), sl1, extension_time, sl1, clrRed, STYLE_DOT, 1, true, false);
|
|
TextCreate(0, curr_time + " SL1 - Text", 0, text_time, sl1, "SL1", "Arial", 8, clrRed, 0.0, ANCHOR_CENTER);
|
|
TrendCreate(0, curr_time + " SL2", 0, iTime(_Symbol, _Period, 0), sl2, extension_time, sl2, clrRed, STYLE_DOT, 1, true, false);
|
|
TextCreate(0, curr_time + " SL2 - Text", 0, text_time, sl2, "SL2", "Arial", 8, clrRed, 0.0, ANCHOR_CENTER);
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| OrderBlocks |
|
|
//+------------------------------------------------------------------+
|
|
void ModificarColor()
|
|
{
|
|
for(int i = 0; i < ArraySize(bullish_ob) ; i++)
|
|
ObjectSetInteger(0, bullish_ob[i].name, OBJPROP_COLOR, color_of_bullish_ob);
|
|
|
|
for(int i = 0; i < ArraySize(bearish_ob) ; i++)
|
|
ObjectSetInteger(0, bearish_ob[i].name, OBJPROP_COLOR, color_of_bearish_ob);
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
void Eliminar_Objetos() //Function to delete objects
|
|
{
|
|
ObjectsDeleteAll(0, "ENTRY", -1, -1);
|
|
for(int i = 0; i < ArraySize(pricetwo_eliminados_oba) ; i++)
|
|
ObjectDelete(0, pricetwo_eliminados_oba[i]);
|
|
for(int i = 0; i < ArraySize(pricetwo_eliminados_obb) ; i++)
|
|
ObjectDelete(0, pricetwo_eliminados_obb[i]);
|
|
for(int i = 0; i < ArraySize(bullish_ob) ; i++)
|
|
ObjectDelete(0, bullish_ob[i].name);
|
|
for(int i = 0; i < ArraySize(bearish_ob) ; i++)
|
|
ObjectDelete(0, bearish_ob[i].name);
|
|
|
|
ArrayFree(pricetwo_eliminados_oba);
|
|
ArrayFree(pricetwo_eliminados_obb);
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Funciones para la creacion de objetos |
|
|
//+------------------------------------------------------------------+
|
|
void RectangleCreate(long chart_ID, string name, const int sub_window, datetime time1, double price1, datetime time2,
|
|
double price2, color clr, int width, bool fill, bool back, ENUM_LINE_STYLE style, bool select, string tooltip)
|
|
{
|
|
ResetLastError(); //we reset the last error
|
|
//verification and creation of the rectangle
|
|
if(!ObjectCreate(chart_ID, name, OBJ_RECTANGLE, sub_window, time1, price1, time2, price2))
|
|
{
|
|
ob_logger.LogError(StringFormat("Failed to create rectangle: %s, last error description = %s", name, ErrorDescription(GetLastError())), ORDER_BLOCK_IND_NAME);
|
|
}
|
|
ObjectSetString(chart_ID, name, OBJPROP_TOOLTIP, tooltip);
|
|
ObjectSetInteger(chart_ID, name, OBJPROP_COLOR, clr);
|
|
ObjectSetInteger(chart_ID, name, OBJPROP_STYLE, style);
|
|
ObjectSetInteger(chart_ID, name, OBJPROP_WIDTH, width);
|
|
ObjectSetInteger(chart_ID, name, OBJPROP_FILL, fill);
|
|
ObjectSetInteger(chart_ID, name, OBJPROP_BACK, back);
|
|
ObjectSetInteger(chart_ID, name, OBJPROP_SELECTABLE, select);
|
|
ObjectSetInteger(chart_ID, name, OBJPROP_SELECTED, select);
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
bool TrendCreate(long chart_ID,
|
|
string name,
|
|
int sub_window,
|
|
datetime time1,
|
|
double price1,
|
|
datetime time2,
|
|
double price2,
|
|
color clr,
|
|
ENUM_LINE_STYLE style,
|
|
int width,
|
|
bool back,
|
|
bool selection
|
|
)
|
|
{
|
|
ResetLastError();
|
|
//--- We create the trend line according to the established coordinates
|
|
if(!ObjectCreate(chart_ID, name, OBJ_TREND, sub_window, time1, price1, time2, price2))
|
|
{
|
|
ob_logger.LogError(StringFormat("Failed to create trend_line: %s, last error description = %s", name, ErrorDescription(GetLastError())), ORDER_BLOCK_IND_NAME);
|
|
return(false);
|
|
}
|
|
ObjectSetInteger(chart_ID, name, OBJPROP_COLOR, clr);
|
|
ObjectSetInteger(chart_ID, name, OBJPROP_STYLE, style);
|
|
ObjectSetInteger(chart_ID, name, OBJPROP_WIDTH, width);
|
|
ObjectSetInteger(chart_ID, name, OBJPROP_BACK, back);
|
|
ObjectSetInteger(chart_ID, name, OBJPROP_SELECTABLE, selection);
|
|
ObjectSetInteger(chart_ID, name, OBJPROP_SELECTED, selection);
|
|
|
|
//---
|
|
return(true);
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
bool TextCreate(long chart_ID,
|
|
string name,
|
|
int sub_window,
|
|
datetime time,
|
|
double price,
|
|
string text,
|
|
string font,
|
|
int font_size,
|
|
color clr,
|
|
double angle,
|
|
ENUM_ANCHOR_POINT anchor,
|
|
bool back = false,
|
|
bool selection = false)
|
|
|
|
|
|
{
|
|
ResetLastError();
|
|
//--- we create the "Text" object
|
|
if(!ObjectCreate(chart_ID, name, OBJ_TEXT, sub_window, time, price))
|
|
{
|
|
ob_logger.LogError(StringFormat("Failed to create text: %s, last error description = %s", name, ErrorDescription(GetLastError())), ORDER_BLOCK_IND_NAME);
|
|
return(false);
|
|
}
|
|
ObjectSetString(chart_ID, name, OBJPROP_TEXT, text);
|
|
ObjectSetString(chart_ID, name, OBJPROP_FONT, font);
|
|
ObjectSetInteger(chart_ID, name, OBJPROP_FONTSIZE, font_size);
|
|
ObjectSetDouble(chart_ID, name, OBJPROP_ANGLE, angle);
|
|
ObjectSetInteger(chart_ID, name, OBJPROP_ANCHOR, anchor);
|
|
ObjectSetInteger(chart_ID, name, OBJPROP_COLOR, clr);
|
|
ObjectSetInteger(chart_ID, name, OBJPROP_BACK, back);
|
|
ObjectSetInteger(chart_ID, name, OBJPROP_SELECTABLE, selection);
|
|
ObjectSetInteger(chart_ID, name, OBJPROP_SELECTED, selection);
|
|
return(true);
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Transparencia |
|
|
//+------------------------------------------------------------------+
|
|
color ApplyTransparency(color fg, double alpha)
|
|
{
|
|
// Clamp alpha between 0.0 and 1.0
|
|
alpha = MathMax(0.0, MathMin(1.0, alpha));
|
|
|
|
// Get background color of the current chart
|
|
long bg_long;
|
|
if(!ChartGetInteger(0, CHART_COLOR_BACKGROUND, 0, bg_long))
|
|
bg_long = clrWhite; // Fallback if it fails
|
|
|
|
color bg = (color)bg_long;
|
|
|
|
// Decompose foreground color
|
|
int r_fg = (fg >> 16) & 0xFF;
|
|
int g_fg = (fg >> 8) & 0xFF;
|
|
int b_fg = fg & 0xFF;
|
|
|
|
// Decompose background color
|
|
int r_bg = (bg >> 16) & 0xFF;
|
|
int g_bg = (bg >> 8) & 0xFF;
|
|
int b_bg = bg & 0xFF;
|
|
|
|
// Blend each channel
|
|
int r = (int)(r_fg * alpha + r_bg * (1.0 - alpha));
|
|
int g = (int)(g_fg * alpha + g_bg * (1.0 - alpha));
|
|
int b = (int)(b_fg * alpha + b_bg * (1.0 - alpha));
|
|
|
|
// Compose final color
|
|
return (color)((r << 16) | (g << 8) | b);
|
|
}
|
|
//+------------------------------------------------------------------+
|