FractFactory/FormationsFinder.mqh

558 lines
36 KiB
MQL5
Raw Permalink Normal View History

2025-05-30 14:56:16 +02:00
<EFBFBD><EFBFBD>//+------------------------------------------------------------------+
//| Fomations.mqh |
//| Copyright 2024, MetaQuotes Ltd. |
//| https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2024, MetaQuotes Ltd."
#property link "https://www.mql5.com"
#include <FormationContainers.mqh>
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void FormationTesting(const string symbol,const ENUM_TIMEFRAMES tf,FormArray &array,const int index){
for(uint i = 0,size = array.size();i < size;i++){
if(::iTime(symbol,tf,index) <= array[i]._time)
continue;
if(array[i]._isTested)
continue;
if(array[i]._isUp){
if((::iLow(symbol,tf,index) > array[i]._low_level_renge && ::iLow(symbol,tf,index) < array[i]._high_level_renge) ||
(::iLow(symbol,tf,index) < array[i]._low_level_renge && ::iClose(symbol,tf,index) > array[i]._low_level_renge))
array[i]._isTested = true;
if(::iLow(symbol,tf,index) < array[i]._low_level_renge && ::iClose(symbol,tf,index) < array[i]._low_level_renge){
if(array[i]._type_formation == FORMATION_VALUE_GAP)
array[i]._isTested = true;
else
array[i]._isUp = false;
}
}
else{
if((::iHigh(symbol,tf,index) < array[i]._high_level_renge && ::iHigh(symbol,tf,index) > array[i]._low_level_renge) ||
(::iHigh(symbol,tf,index) > array[i]._high_level_renge && ::iClose(symbol,tf,index) < array[i]._high_level_renge))
array[i]._isTested = true;
if(::iHigh(symbol,tf,index) > array[i]._high_level_renge && ::iClose(symbol,tf,index) > array[i]._high_level_renge){
if(array[i]._type_formation == FORMATION_VALUE_GAP)
array[i]._isTested = true;
else
array[i]._isUp = true;
}
}
}
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void FormationCleaner(const double equator,
const double low,
const double high,
FormArray &array)
{
if(array.isEmpty())
return;
for(uint i = 0,size = array.size();i < size;i++) {
if(array[i]._isTested)
array.remove(i);
if(array[i]._isUp) {
if(array[i]._low_level_renge < low || array[i]._high_level_renge > equator)
array.remove(i);
}
if(!array[i]._isUp) {
if(array[i]._low_level_renge < equator || array[i]._high_level_renge > high)
array.remove(i);
}
if(array[i]._high_level_renge <= 0 || array[i]._low_level_renge <= 0 || array[i]._time == 0)
array.remove(i);
}
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void FormationFind(const string symbol,
const ENUM_TIMEFRAMES tf,
const datetime StartTime,
const datetime EndTime,
FormArray &array)
{
int start_index = 0;
int end_index = 0;
for(int i = 0,size = ::iBars(symbol,tf);i < size;i++) {
if(::iTime(symbol,tf,i) <= StartTime) {
start_index = i;
break;
}
}
for(int i = 0,size = ::iBars(symbol,tf);i < size;i++) {
if(::iTime(symbol,tf,i) <= EndTime) {
end_index = i;
break;
}
}
if(start_index <= 0 && end_index <= 0)
return;
// ?@>25@>G=K9 ?@8=B
// Print("StartIndex = ", start_index,"EndIndex = ",end_index);
double h_level = 0.0, l_level = 0.0;
for(int i = start_index; i > end_index; i--) {
if(!array.isEmpty()){
FormationTesting(symbol,tf,array,i);
}
if(IsBockenVolumeUp(symbol,tf,i,h_level,l_level)) {
Formation form;
form._type_formation = FORMATION_VALUE_GAP;
form._isUp = true;
form._isTested = false;
form._high_level_renge = h_level;
form._low_level_renge = l_level;
form._time = ::iTime(symbol,tf,i);
form.setEquator();
array.append(form);
}
if(IsBockenVolumeDn(symbol,tf,i,h_level,l_level)) {
Formation form;
form._type_formation = FORMATION_VALUE_GAP;
form._isUp = false;
form._isTested = false;
form._high_level_renge = h_level;
form._low_level_renge = l_level;
form._time = ::iTime(symbol,tf,i);
form.setEquator();
array.append(form);
}
if(IsInsideBarUp(symbol,tf,i,h_level,l_level)) {
Formation form;
form._type_formation = FORMATION_INSIDE_BAR;
form._isUp = true;
form._isTested = false;
form._high_level_renge = h_level;
form._low_level_renge = l_level;
form._time = ::iTime(symbol,tf,i);
form.setEquator();
array.append(form);
}
if(IsInsideBarDn(symbol,tf,i,h_level,l_level)) {
Formation form;
form._type_formation = FORMATION_INSIDE_BAR;
form._isUp = false;
form._isTested = false;
form._high_level_renge = h_level;
form._low_level_renge = l_level;
form._time = ::iTime(symbol,tf,i);
form.setEquator();
array.append(form);
}
if(IsAbsorbingDn(symbol,tf,i,h_level,l_level)) {
Formation form;
form._type_formation = FORMATION_ABSORBING;
form._isUp = false;
form._isTested = false;
form._high_level_renge = h_level;
form._low_level_renge = l_level;
form._time = ::iTime(symbol,tf,i);
form.setEquator();
array.append(form);
}
if(IsAbsorbingUp(symbol,tf,i,h_level,l_level)) {
Formation form;
form._type_formation = FORMATION_ABSORBING;
form._isUp = true;
form._isTested = false;
form._high_level_renge = h_level;
form._low_level_renge = l_level;
form._time = ::iTime(symbol,tf,i);
form.setEquator();
array.append(form);
}
}
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
/*void FormationFind(const string symbol,
const ENUM_TIMEFRAMES tf,
FormArray &array)
{
double h_level = 0.0, l_level = 0.0;
if(IsBockenVolumeUp(symbol,tf,1,h_level,l_level)) {
Formation form;
form._type_formation = FORMATION_VALUE_GAP;
form._isUp = true;
form._isTested = false;
form._high_level_renge = h_level;
form._low_level_renge = l_level;
form._time = ::iTime(symbol,tf,1);
form.setEquator();
array.append(form);
}
if(IsBockenVolumeDn(symbol,tf,1,h_level,l_level)) {
Formation form;
form._type_formation = FORMATION_VALUE_GAP;
form._isUp = false;
form._isTested = false;
form._high_level_renge = h_level;
form._low_level_renge = l_level;
form._time = ::iTime(symbol,tf,1);
form.setEquator();
array.append(form);
}
if(IsInsideBarUp(symbol,tf,1,h_level,l_level)) {
Formation form;
form._type_formation = FORMATION_INSIDE_BAR;
form._isUp = true;
form._isTested = false;
form._high_level_renge = h_level;
form._low_level_renge = l_level;
form._time = ::iTime(symbol,tf,1);
form.setEquator();
array.append(form);
}
if(IsInsideBarDn(symbol,tf,1,h_level,l_level)) {
Formation form;
form._type_formation = FORMATION_INSIDE_BAR;
form._isUp = false;
form._isTested = false;
form._high_level_renge = h_level;
form._low_level_renge = l_level;
form._time = ::iTime(symbol,tf,1);
form.setEquator();
array.append(form);
}
if(IsAbsorbingDn(symbol,tf,1,h_level,l_level)) {
Formation form;
form._type_formation = FORMATION_ABSORBING;
form._isUp = false;
form._isTested = false;
form._high_level_renge = h_level;
form._low_level_renge = l_level;
form._time = ::iTime(symbol,tf,1);
form.setEquator();
array.append(form);
}
if(IsAbsorbingUp(symbol,tf,1,h_level,l_level)) {
Formation form;
form._type_formation = FORMATION_ABSORBING;
form._isUp = true;
form._isTested = false;
form._high_level_renge = h_level;
form._low_level_renge = l_level;
form._time = ::iTime(symbol,tf,1);
form.setEquator();
array.append(form);
}
}*/
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool IsAbsorbingUp(const string symbol,const ENUM_TIMEFRAMES tf,const int index,double &h,double &l)
{
int end = index + 1;
if(!IsValidData(index,end,2))
return false;
double open,close,preOpen,preClose;
open = ::iOpen(symbol,tf,index);
close = ::iClose(symbol,tf,index);
preOpen = ::iOpen(symbol,tf,end);
preClose = ::iClose(symbol,tf,end);
if(preOpen > preClose && open < close) {
if(DistPrices(open,close,symbol) > DistPrices(preOpen,preClose,symbol)) {
if(preOpen <= close && preClose >= open) {
h = preOpen;
l = ::iLow(symbol,tf,index);
return true;
}
}
}
return false;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool IsAbsorbingDn(const string symbol,const ENUM_TIMEFRAMES tf,const int index,double &h,double &l)
{
int end = index + 1;
if(!IsValidData(index,end,2))
return false;
double open,close,preOpen,preClose;
open = ::iOpen(symbol,tf,index);
close = ::iClose(symbol,tf,index);
preOpen = ::iOpen(symbol,tf,end);
preClose = ::iClose(symbol,tf,end);
if(preOpen < preClose && open > close) {
if(DistPrices(open,close,symbol) > DistPrices(preOpen,preClose,symbol)) {
if(preOpen >= close && preClose <= open) {
h = ::iHigh(symbol,tf,index);
l = preOpen;
return true;
}
}
}
return false;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool IsBockenVolumeUp(const string symbol,
const ENUM_TIMEFRAMES tf,
const int index,
double &h,
double &l,
const int min = 0)
{
int end = index + 2;
if(!IsValidData(index,end,3))
return false;
h = ::iLow(symbol,tf,index);
l = ::iHigh(symbol,tf,end);
if(h > l) {
double point = ::SymbolInfoDouble(symbol,SYMBOL_POINT);
if(h - l >= min * point)
return true;
}
return false;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool IsBockenVolumeDn(const string symbol,
const ENUM_TIMEFRAMES tf,
const int index,
double &h,
double &l,
const int min = 0)
{
int end = index + 2;
if(!IsValidData(index,end,3))
return false;
l = ::iLow(symbol,tf,end);
h = ::iHigh(symbol,tf,index);
if(l > h) {
double point = ::SymbolInfoDouble(symbol,SYMBOL_POINT);
if(h - l >= min * point)
return true;
}
return false;
}
//+------------------------------------------------------------------+
/*bool isCloseGapClosingUp(const int begin,const int end){
if(!IsValidData(begin,end,4))
return false;
if(!IsBockenVolumeUp(begin))
return false;
for(int i = begin - 2;i >= end;i++){
if(IsBockenVolumeUp(i)){
double level = ::iHigh(_Symbol,PERIOD_CURRENT,i);
double volume= ::iHigh(_Symbol,PERIOD_CURRENT,i + 2);
for(int y = i - 1;y >= end;i--){
if(::iOpen(_Symbol,PERIOD_CURRENT,y) < ::iClose(_Symbol,PERIOD_CURRENT,y)){
if(::iLow(_Symbol,PERIOD_CURRENT,y) <= volume && ::iClose(_Symbol,PERIOD_CURRENT,y) > level)
return true;
else
continue;
}
else
continue;
}
}
else
continue;
}
return false;
}
//+------------------------------------------------------------------+
bool isCloseGapClosingDn(const int begin,const int end){
if(!IsValidData(begin,end,4))
return false;
if(!IsBockenVolumeDn(begin,end))
return false;
for(int i = begin - 2;i >= end;i++){
if(IsBockenVolumeDn(i,i+2)){
double level = ::iLow(_Symbol,PERIOD_CURRENT,i);
double volume= ::iLow(_Symbol,PERIOD_CURRENT,i + 2);
for(int y = i - 1;y >= end;i--){
if(::iOpen(_Symbol,PERIOD_CURRENT,y) > ::iClose(_Symbol,PERIOD_CURRENT,y)){
if(::iLow(_Symbol,PERIOD_CURRENT,y) >= volume && ::iClose(_Symbol,PERIOD_CURRENT,y) < level)
return true;
else
continue;
}
else
continue;
}
}
else
continue;
}
return false;
}*/
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool IsInsideBarDn(const string symbol,
const ENUM_TIMEFRAMES tf,
const int index,
double &h,
double &l)
{
int end = index + 2;
int bar = index + 1;
if(!IsValidData(index,end,3))
return false;
double open,close,open1,close1,open2,close2;
open = ::iOpen(symbol,tf,index);
close = ::iClose(symbol,tf,index);
open1 = ::iOpen(symbol,tf,bar);
close1 = ::iClose(symbol,tf,bar);
open2 = ::iOpen(symbol,tf,end);
close2 = ::iClose(symbol,tf,end);
if(open < close && open1 > close1 && open2 < close2) {
if(DistPrices(open1,close1,symbol) < DistPrices(open,close,symbol)
&& DistPrices(open1,close1,symbol) < DistPrices(open2,close2,symbol)) {
if(close1 >= open && close1 >= open2 && open1 <= close && open1 <= close2) {
h = ::iHigh(symbol,tf,bar);
l = ::iLow(symbol,tf,bar);
return true;
}
}
}
return false;
}
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool IsInsideBarUp(const string symbol,
const ENUM_TIMEFRAMES tf,
const int index,
double &h,
double &l)
{
int end = index + 2;
int bar = index + 1;
if(!IsValidData(index,end,3))
return false;
double open,close,open1,close1,open2,close2;
open = ::iOpen(symbol,tf,index);
close = ::iClose(symbol,tf,index);
open1 = ::iOpen(symbol,tf,bar);
close1 = ::iClose(symbol,tf,bar);
open2 = ::iOpen(symbol,tf,end);
close2 = ::iClose(symbol,tf,end);
if(open > close && open1 < close1 && open2 < close2) {
if(DistPrices(open1,close1,symbol) < DistPrices(open,close,symbol)
&& DistPrices(open1,close1,symbol) < DistPrices(open2,close2,symbol)) {
if(close1 <= open && close1 <= open2 && open1 >= close && open1 >= close2) {
h = ::iHigh(symbol,tf,bar);
l = ::iLow(symbol,tf,bar);
return true;
}
}
}
return false;
}
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool IsValidData(const int begin,const int end,const int formation)
{
if(begin <= 0) {
::Print("A5 A25G8 ?0BB5@=0 4>;6=K 1KBL ?>;=>ABLN AD>@<8@>20=K\n"5:CI0O =570:@KB0O A25G0 =5 4>?CA:05BAO");
return false;
}
if(begin >= end) {
::Print("#:070==K5 8=45:AK =5 A>>B25BA2CNB ;>38:5");
return false;
}
if(::MathAbs(end - begin) + 1 < formation) {
//::Print(end," - ",begin," = ",end - begin);
::Print("5E20B05B A25G59 4;O 0=0;870");
return false;
}
return true;
}
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
int DistPrices(double priceA, double priceB, string symbol = NULL)
{
return (int)(::MathAbs(priceA - priceB) / SymbolInfoDouble(symbol,SYMBOL_POINT));
}
//+------------------------------------------------------------------+