How to check 3 RSI values against the Bollinger Bands? - mql4

There are Bollinger Bands with three RSI running in the basement.
I want to do a check on the signal in such a way that when 3 RSI struck the zone of the upper Bbands, there was a signal down and vice versa:
int start(){
double ma, stdev;
int i, limit, count=IndicatorCounted();
if(count<0) return(0);
limit=Bars-count;
if(limit>1) limit=Bars-1;
for(i=limit; i>=0; i--) {
RSI[i] =iRSI(Symbol(),Period(),rsi_period, PRICE_CLOSE,i);
RSI2[i]=iRSI(Symbol(),Period(),rsi_period_2,PRICE_CLOSE,i);
RSI3[i]=iRSI(Symbol(),Period(),rsi_period_3,PRICE_CLOSE,i);
}
for(i=limit; i>=0; i--) {
ma=iMAOnArray(RSI3,0,bb_period,0,0,i); // midle line
stdev=iStdDevOnArray(RSI3,0,bb_period,0,0,i); // dev
BBUP[i]=ma+bb_dev*stdev; // up line
BBDOWN[i]=ma-bb_dev*stdev; // down line
UP[i]=0;
DOWN[i]=0;
}
if(limit<Bars-1) limit++;
for(i=limit; i>0; i--) {
if(RSI[i] <= BBDOWN[i] && RSI[i+1] > BBDOWN[i+1] && RSI2[i] <= BBDOWN[i] && RSI2[i+1] > BBDOWN[i+1] && RSI3[i] <= BBDOWN[i] && RSI3[i+1] > BBDOWN[i+1]){
DOWN[i] = iLow(_Symbol, _Period, i);
}
if(RSI[i] >= BBUP[i] && RSI[i+1] < BBUP[i+1] &&W RSI2[i] >= BBUP[i] && RSI2[i+1] < BBUP[i+1] && RSI3[i] >= BBUP[i] && RSI3[i+1] < BBUP[i+1]){
UP[i]= iHigh(_Symbol, _Period, i);
}
}
The whole problem is that I have very crooked signals.
Appear where they should not be, and there is no where to be.

THE BEST PRACTICE:
Step 0: Let's first agree in written WHAT is the actual TARGET:
If the TARGET is to compute & paint on GUI the Bollinger Bands on RSI3[] values, the best way to do this is to use:
UPPER[i] = iBandsOnArray( RSI3, // ArrayAsSeries[]
array_calculation_depth, // reduce overheads
BB_MA_period, // BBands period
BB_StDev_MUL, // how many sigmas
BB_Zero_Shift, // #DEFINE BB_Zero_Shift 0
MODE_UPPER, // BBands upper line
i // shifting operator[i]
);
This way one may efficiently produce each of the { MODE_UPPER | MODE_MAIN | MODE_LOWER } Bollinger Bands lines here, consistently generated over dimension-less RSI3[] data, thus protecting the sense of any additive operations in signal-composition(s) with other, dimension-less data, as in { RSI2[], RSI[] }.
Step 1: visually check the lines to validate any signal-conditions:
Given the GUI shows lines accordingly, one may try to compose signal-conditions. The "hot"-bar [0] is a live-bar, where novice may encounter tricking signalling situations, if not handled with due professional care.
Step 2: implement signal-conditions in code:
Only after Step 0) & 1) took place and both meet one's own prior expectations, any code starts to make sense to get built.

From MQL4 docs https://docs.mql4.com/indicators/imaonarray
Unlike iMA(...), the iMAOnArray() function does not take data by
symbol name, timeframe, the applied price. The price data must be
previously prepared. The indicator is calculated from left to right.
To access to the array elements as to a series array (i.e., from right
to left), one has to use the ArraySetAsSeries() function.
RSI3 is currently orientated right to left (0 is most recent time point, limit is furthest element).
Same issue with iStdDevOnArray()
Fix those issues and it should work as you want. Whether there is any value in drawing Bollinger bands on RSI is another matter
Update
The function ArraySetAsSeries() can be used to swap the array between left-to-right and right-to-left
When you first initialise the RSI arrays ( in the OnInit() ) tell MetaTrader Terminal that they are timeseries.
ArraySetAsSeries(RSI1,True);
ArraySetAsSeries(RSI2,True);
ArraySetAsSeries(RSI3,True);
Then in main body, add ArraySetAsSeries(RSI3,False); before your second for loop to swap the array orientation. Then ArraySetAsSeries(RSI3,True); after the loop to restore the array orientation.
for(i=limit; i>=0; i--) {
RSI[i ] = iRSI(Symbol(),Period(),rsi_period,PRICE_CLOSE,i);
RSI2[i] = iRSI(Symbol(),Period(),rsi_period_2,PRICE_CLOSE,i);
RSI3[i] = iRSI(Symbol(),Period(),rsi_period_3,PRICE_CLOSE,i);
}
ArraySetAsSeries(RSI3,False);
for(i=limit; i>=0; i--) {
ma=iMAOnArray(RSI3,0,bb_period,0,0,i); // midle line
stdev=iStdDevOnArray(RSI3,0,bb_period,0,0,i); // dev
BBUP[i]=ma+bb_dev*stdev; // up line
BBDOWN[i]=ma-bb_dev*stdev; // down line
UP[i]=0;
DOWN[i]=0;
}
ArraySetAsSeries(RSI3,True);
if(limit<Bars-1) limit++;
for(i=limit; i>0; i--) {
if( RSI[i] <= BBDOWN[i] &&
RSI[i+1] > BBDOWN[i] &&
RSI2[i] <= BBDOWN[i] &&
RSI2[i+1] > BBDOWN[i] &&
RSI3[i] <= BBDOWN[i] &&
RSI3[i+1] > BBDOWN[i]) {
DOWN[i] = iLow(_Symbol, _Period, i);
}
if( RSI[i] >= BBUP[i] &&
RSI[i+1] < BBUP[i+1] &&
RSI2[i] >= BBUP[i] &&
RSI2[i+1] < BBUP[i+1] &&
RSI3[i] >= BBUP[i] &&
RSI3[i+1] < BBUP[i+1]) {
UP[i]= iHigh(_Symbol, _Period, i);
}
}
Basic indicator structure
You need to go through the MQL4 Documentation and learn the proper structure of an indicator. There needs to be an OnInit() function where you initialise values. Then an OnCalculate() function where you fill the indicator buffers.
//+-----------------------------------------------------------------+
//| Custom indicator initialization function |
//+-----------------------------------------------------------------+
int OnInit()
{
//--- indicator buffers mapping
ArraySetAsSeries(RSI3,True);
//---
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[])
{
// Do your calculations here
//--- return value of prev_calculated for next call
return(rates_total);
}
If you use iBandsOnArray() to calculate Bollinger bands you won't need to swap the array direction after it is set in OnInit()
If the indicator is compiling but crashing, you will need to debug it. Simplest way is to look at the errors in the log and add PrintFormat() statements throughout your code so you can see what the indicator is doing at different points and see where it crashes.

Related

Why Buy order is not placed when calculated Stoploss and Take profit are used

I have a simple BUY order that, when the Take Profit and Stoploss are in points (ie: Ask+10*_Point), operates correctly. But when I change the take profit and stop loss from points to my own calculated values (CL_OP), the BUY order is not placing trades. How can I solve the issue:
input int _Hour =16;
input int _Minute =30;
bool NewBar()
{
static datetime OldTime = 0;
if(OldTime < Time[0])
{
OldTime = Time[0];
return(true);
}
else
{
return(false);
}
}
void OnTick()
{
int Hour_Int = Hour();
int Minute_Int = Minute();
double CL_OP = (Close[1] - Open[1]);
bool LastBearHiLoEngulf = (Close[1] < Open[1] && High[1] > High[2] && Low[1] < Low[2] );
if(NewBar())
if(OrdersTotal()==0)
// Apply signals on Buy opportunities
if( Hour_Int == _Hour && Minute_Int == _Minute && LastBearHiLoEngulf == TRUE)
{
int buyticket = OrderSend
(
Symbol(), // all symbols
OP_BUY, // Buy without delay
1, // 1 Microlots
Ask, // for market price
3, // 3 pips slippage
Ask - CL_OP, // Stop Loss - 1000*_Point
Ask + CL_OP , // Take profitworks with 100*_Point
"Buy LastBearHiLoEngulf Target: ", // comment
144, // Magic number
0, // no experiation day
Green // draw green arrow
);
}
}
double CL_OP = (Close[1] - Open[1]);
CL_OP is not a normal price to open trade. Actually, it is the Size of the Candle 1!
It should be something like this:
double CL_OP = Close[1] + (Close[1] - Open[1]);

How can open orders continue in same trading condition

I want to open orders by orders whenever a certain trading condition is met.
I want to open pending orders in previous highest and lowest price.
So, I tried like this:
upper=iHigh(Symbol(),Period(),iHighest(Symbol(),Period(),MODE_HIGH,periods,0));
lower=iLow(Symbol(),Period(),iLowest(Symbol(),Period(),MODE_LOW,periods,0));
Comment("Upper: ",upper,"\nLower: ",lower);
int openCount=0;
int openpendCount=0;
for( int i = OrdersTotal()-1; i >= 0 ; i--)
{
if (OrderSelect(i, SELECT_BY_POS) && // Only my orders :
OrderMagicNumber() == 0 && // my magic number
OrderSymbol() == _Symbol) // and my symbol
{
if(OrderType() == OP_SELL && OrderType() ==OP_BUY) // count market orders
openCount++;
if(OrderType() == OP_SELLLIMIT && OrderType() ==OP_BUYLIMIT) // count market orders
openpendCount++;
}
}
if(openCount ==0 && openpendCount == 0 )
{ OrderSend(Symbol(), OP_SELLLIMIT,1,Ask+(upper-Ask), 3,0,0,"Sub Buy", MAGIC,0, Blue);
OrderSend(Symbol(), OP_BUYLIMIT,1,Ask-(Bid-lower), 3,0,0,"Sub Buy", MAGIC,0, Blue);
}
But no success,
Q: How can I make multiple new orders at the same time, and no more new orders when trade condition meet.
There are a number of problems with your code and it is difficult to know all the problems as you have not included your full code. However, try the following, it addresses the main issues I can see which are.
You should only check once on the close of each new bar
You need to check for successful selection of orders before working with them
Do not check for a magic number of 0, this indicates manually placed orders
You are mixing up && and || when checking your order types
You are placing your orders at strange levels. You need to set them at the previously found levels (adjusted for spread for buy orders).
int MAGIC=123;
datetime TimeBar;
int periods=50;
int start()
{
if(TimeBar==Time[0]) return(0);
double upper=iHigh(NULL, 0, iHighest(NULL, 0, MODE_HIGH, periods, 0));
double lower=iLow (NULL, 0, iLowest (NULL, 0, MODE_LOW , periods, 0));
Comment("Upper: ",upper,"\r\nLower: ",lower);
int openOrders=0;
int limitOrders=0;
for(int i=OrdersTotal()-1; i>=0; i--)
{
if(OrderSelect(i, SELECT_BY_POS))
{
if(OrderMagicNumber()!=MAGIC || OrderSymbol()!=Symbol()) continue;
if(OrderType()==OP_SELL || OrderType()==OP_BUY) openOrders++;
if(OrderType()==OP_SELLLIMIT || OrderType()==OP_BUYLIMIT) limitOrders++;
}
}
if(openOrders==0 && limitOrders==0)
{
int res;
res=OrderSend(Symbol(), OP_SELLLIMIT, 1, upper, 3, 0, 0, "Sub Sell", MAGIC, 0, clrBlue);
res=OrderSend(Symbol(), OP_BUYLIMIT, 1, lower+(Ask-Bid), 3, 0, 0, "Sub Buy", MAGIC, 0, clrBlue);
}
TimeBar=Time[0];
return(0);
}
You will also need to address the problem that the EA could potentially try to open an order within MarketInfo(Symbol(), MODE_STOPLEVEL) of the current price which would cause the order to be rejected by the trade server.
It is also good practice to check your OrderSend for errors.

Array out of range mql4

I am trying to add indicator code, which works perfectly on its own, to an EA MQL4 source. While everything compiles just fine, the terminal tab shows the above error.
Both errors occuring relate to tick[i+k].
double ticks[];
double tick[];
int init() {
ArrayResize(ticks,TotalBars); ArraySetAsSeries(ticks,true);
ArrayResize(tick,TotalBars); ArraySetAsSeries(tick,true);
return(0);
}
int start() {
for (i=TotalBars-1; i>=0; i--)
{
avg = tick[i];
for (k=1; k<AveragePeriod && tick[i+k]!=0; k++) avg += tick[i+k];
avg /= k;
....
I want to prevent iCustom calls. What could be the issue?
Thank you.

Find middle element of a double linked list in constant time complexity

I am trying to find the middle element of a double linked list in constant time complexity .
I came across the following http://www.geeksforgeeks.org/design-a-stack-with-find-middle-operation/ solution.
But I don't understand how to use the middle pointer.
Can anyone please help me understand this or give me a better solution .
I've re-written this code in C++ for explanation purposes:
#include <iostream>
typedef class Node* PNode;
class Node{
public:
PNode next;
PNode prev;
int data;
Node(){
next = nullptr;
prev = nullptr;
data = 0;
}
};
class List{
private:
//Attributes
PNode head;
PNode mid;
int count;
//Methods
void UpdateMiddle( bool _add );
public:
//Constructors
List(){
head = nullptr;
mid = nullptr;
count = 0;
}
~List(){
while( head != nullptr ){
this->delmiddle();
std::cout << count << std::endl;
}
}
//Methods
void push( int _data );
void pop();
int findmiddle();
void delmiddle();
};
void List::UpdateMiddle( bool _add ){
if( count == 0 ){
mid = nullptr;
}
else if( count == 1 ){
mid = head;
}
else{
int remainder = count%2;
if(_add){
if( remainder == 0 ){
mid = mid->prev;
}
}
else{
if( remainder == 1 ){
mid = mid->next;
}
}
}
}
void List::push( int _data ){
PNode new_node = new Node();
new_node->data = _data;
new_node->prev = nullptr;
new_node->next = head;
if( head != nullptr ) head->prev = new_node;
head = new_node;
count++;
UpdateMiddle( true );
}
void List::pop(){
if( head != nullptr ){
PNode del_node = head;
head = head->next;
if( head != nullptr ) head->prev = nullptr;
delete del_node;
count--;
UpdateMiddle(false);
}
else if( count != 0 ){
std::cout << "ERROR";
return;
}
}
int List::findmiddle(){
if( count > 0 ) return mid->data;
else return -1;
}
void List::delmiddle(){
if( mid != nullptr ){
if( count == 1 || count == 2){
this->pop();
}
else{
PNode del_mid = mid;
int remainder = count%2;
if( remainder == 0 ){
mid = del_mid->next;
mid->prev = del_mid->prev;
del_mid->prev->next = mid;
delete del_mid;
count--;
}
else{
mid = del_mid->prev;
mid->next = del_mid->next;
del_mid->next->prev = mid;
delete del_mid;
count--;
}
}
}
}
The push and pop functions are self-explanatory, they add nodes on top of the stack and delete the node on the top. In this code, the function UpdateMiddle is in charge of managing the mid pointer whenever a node is added or deleted. Its parameter _add tells it whether a node has been added or deleted. This info is important when there is more than two nodes.
Note that when the UpdateMiddle is called within push or pop, the counter has already been increased or decreased respectively. Let's start with the base case, where there is 0 nodes. mid will simply be a nullptr. When there is one node, mid will be that one node.
Now let's take the list of numbers "5,4,3,2,1". Currently the mid is 3 and count, the amount of nodes, is 5 an odd number. Let's add a 6. It will now be "6,5,4,3,2,1" and count will now be 6 an even number. The mid should also now be 4, as it is the first in the middle, but it still hasn't updated. However, now if we add 7 it will be "7,6,5,4,3,2,1", the count will be 7, an odd number, but notice that the mid wont change, it should still be 4.
A pattern can be observed from this. When adding a node, and count changes from even to odd, the mid stays the same, but from odd to even mid changes position. More specifically, it moves one position to the left. That is basically what UpdateMiddle does. By checking whether count is currently odd or even after adding or deleting a node, it decides if mid should be repositioned or not. It is also important to tell whether a node is added or deleted because the logic works in reverse to adding when deleting. This is basically the logic that is being applied in the code you linked.
This algorith works because the position of mid should be correct at all times before adding or deleting, and function UpdateMiddle assumes that the only changes were the addition or deletion of a node, and that prior to this addition or deletion the position of mid was correct. However, we make sure of this by making the attributes and our function UpdateMiddle private, and making it modifiable through the public functions.
The trick is that you don't find it via a search, rather you constantly maintain it as a property of the list. In your link, they define a structure that contains the head node, the middle node, and the number of nodes; since the middle node is a property of the structure, you can return it by simply accessing it directly at any time. From there, the trick is to maintain it: so the push and pop functions have to adjust the middle node, which is also shown in the code.
More depth: maintaining the middle node: we know given the count that for an odd number of nodes (say 9), the middle node is "number of nodes divided by 2 rounded up," so 9/2 = 4.5 rounded up = the 5th node. So if you start with a list of 8 nodes, and add a node, the new count is 9, and you'll need to shift the middle node to the "next" node. That is what they are doing when they check if the new count is even.

Checking if removing an edge in a graph will result in the graph splitting

I have a graph structure where I am removing edges one by one until some conditions are met. My brain has totally stopped and i can't find an efficient way to detect if removing an edge will result in my graph splitting in two or more graphs.
The bruteforce solution would be to do an bfs until one can reach all the nodes from a random node, but that will take too much time with large graphs...
Any ideas?
Edit: After a bit of search it seems what I am trying to do is very similar to the fleury's algorithm, where I need to find if an edge is a "bridge" or not.
Edges that make a graph disconnected when removed are called 'bridges'. You can find them in O(|V|+|E|) with a single depth-first search over the whole graph. A related algorithm finds all 'articulation points' (nodes that, if removed, makes the graph disconnected) follows. Any edge between two articulation-points is a bridge (you can test that in a second pass over all edges).
//
// g: graph; v: current vertex id;
// r_p: parents (r/w); r_a: ascents (r/w); r_ap: art. points, bool array (r/w)
// n_v: bfs order-of-visit
//
void dfs_art_i(graph *g, int v, int *r_p, int *r_v, int *r_a, int *r_ap, int *n_v) {
int i;
r_v[v] = *n_v;
r_a[v] = *n_v;
(*n_v) ++;
// printf("entering %d (nv = %d)\n", v, *n_v);
for (i=0; i<g->vertices[v].n_edges; i++) {
int w = g->vertices[v].edges[i].target;
// printf("\t evaluating %d->%d: ", v, w);
if (r_v[w] == -1) {
// printf("...\n");
// This is the first time we find this vertex
r_p[w] = v;
dfs_art_i(g, w, r_p, r_v, r_a, r_ap, n_v);
// printf("\n\t ... back in %d->%d", v, w);
if (r_a[w] >= r_v[v]) {
// printf(" - a[%d] %d >= v[%d] %d", w, r_a[w], v, r_v[v]);
// Articulation point found
r_ap[i] = 1;
}
if (r_a[w] < r_a[v]) {
// printf(" - a[%d] %d < a[%d] %d", w, r_a[w], v, r_a[v]);
r_a[v] = r_a[w];
}
// printf("\n");
}
else {
// printf("back");
// We have already found this vertex before
if (r_v[w] < r_a[v]) {
// printf(" - updating ascent to %d", r_v[w]);
r_a[v] = r_v[w];
}
// printf("\n");
}
}
}
int dfs_art(graph *g, int root, int *r_p, int *r_v, int *r_a, int *r_ap) {
int i, n_visited = 0, n_root_children = 0;
for (i=0; i<g->n_vertices; i++) {
r_p[i] = r_v[i] = r_a[i] = -1;
r_ap[i] = 0;
}
dfs_art_i(g, root, r_p, r_v, r_a, r_ap, &n_visitados);
// the root can only be an AP if it has more than 1 child
for (i=0; i<g->n_vertices; i++) {
if (r_p[i] == root) {
n_root_children ++;
}
}
r_ap[root] = n_root_children > 1 ? 1 : 0;
return 1;
}
If you remove the link between vertices A and B, can't you just check that you can still reach A from B after the edge removal? That's a little better than getting to all nodes from a random node.
How do you choose the edges to be removed?
Can you tell more about your problem domain?
Just how large Is your graph? maybe BFS is just fine!
After you wrote that you are trying to find out whether an edge is a bridge or not, I suggest
you remove edges in decreasing order of their betweenness measure.
Essentially, betweenness is a measure of an edges (or vertices) centrality in a graph.
Edges with higher value of betweenness have greater potential of being a bridge in a graph.
Look it up on the web, the algorithm is called 'Girvan-Newman algorithm'.

Resources