237 lines
7.7 KiB
MQL5
237 lines
7.7 KiB
MQL5
|
//+------------------------------------------------------------------+
|
||
|
//| Multitrade_w_Levels.mq5 |
|
||
|
//| Copyright 2018, MetaQuotes Software Corp. |
|
||
|
//| https://www.mql5.com |
|
||
|
//+------------------------------------------------------------------+
|
||
|
#property copyright "Copyright 2018, MetaQuotes Software Corp."
|
||
|
#property link "https://www.mql5.com"
|
||
|
#property version "1.00"
|
||
|
//+------------------------------------------------------------------+
|
||
|
//| Script program start function |
|
||
|
//+------------------------------------------------------------------+
|
||
|
|
||
|
|
||
|
#include <Trade\Trade.mqh>
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
input int max_band_size = 10;
|
||
|
input int number_of_levels = 2;
|
||
|
input double testing_volume = 0.1;
|
||
|
input double win_multiplier = 0.5;
|
||
|
input double lose_multiplier = 0.5;
|
||
|
input int box_height = 10;
|
||
|
input int box_length = 5;
|
||
|
|
||
|
|
||
|
#define BASE_MULT 0.5
|
||
|
#define POS_W_SHORT 1
|
||
|
#define POS_W_LONG 2
|
||
|
#define POS_W_BASE 0
|
||
|
|
||
|
struct Band
|
||
|
{
|
||
|
double top;
|
||
|
double bottom;
|
||
|
int number_levels;
|
||
|
int quanta; // @Init : round(max_band_size/ number of levels)
|
||
|
bool reset_limits;
|
||
|
double base_price;
|
||
|
};
|
||
|
|
||
|
struct Box
|
||
|
{
|
||
|
double top;
|
||
|
double bottom;
|
||
|
int length;
|
||
|
bool first_box;
|
||
|
|
||
|
};
|
||
|
//+------------------------------------------------------------------+
|
||
|
//| Global Space |
|
||
|
//+------------------------------------------------------------------+
|
||
|
Band band;
|
||
|
Box box;
|
||
|
CTrade trader;
|
||
|
double Ask;
|
||
|
double Bid;
|
||
|
//+------------------------------------------------------------------+
|
||
|
//| |
|
||
|
//+------------------------------------------------------------------+
|
||
|
void OnInit()
|
||
|
{
|
||
|
// init the Bands
|
||
|
band.top = max_band_size;
|
||
|
band.bottom = max_band_size;
|
||
|
band.number_levels = number_of_levels;
|
||
|
band.quanta = round(max_band_size/number_of_levels);
|
||
|
band.reset_limits = true;
|
||
|
|
||
|
box.first_box = true;
|
||
|
}
|
||
|
|
||
|
//+------------------------------------------------------------------+
|
||
|
//| |
|
||
|
//+------------------------------------------------------------------+
|
||
|
void OnTick()
|
||
|
{
|
||
|
//---
|
||
|
Ask = NormalizeDouble(SymbolInfoDouble(_Symbol, SYMBOL_ASK), _Digits);
|
||
|
Bid = NormalizeDouble(SymbolInfoDouble(_Symbol, SYMBOL_BID), _Digits);
|
||
|
double price = NormalizeDouble((Ask + Bid) / 2, _Digits);
|
||
|
|
||
|
if(box.first_box)
|
||
|
{
|
||
|
update_box(price);
|
||
|
update_bands(price);
|
||
|
band.reset_limits = true;
|
||
|
box.first_box = false;
|
||
|
}
|
||
|
|
||
|
if(Ask>=box.top)
|
||
|
{
|
||
|
place_long(Ask, round(box_height*win_multiplier));
|
||
|
update_box(Ask, POS_W_LONG);
|
||
|
} // guide box goes long
|
||
|
else
|
||
|
if(Bid <= box.bottom)
|
||
|
{
|
||
|
place_short(Bid,round(box_height*win_multiplier));
|
||
|
update_box(Bid, POS_W_SHORT);
|
||
|
} // guide box goes short
|
||
|
else
|
||
|
if(box.length<= 0)
|
||
|
{
|
||
|
update_box(price, POS_W_BASE);
|
||
|
} // box needs update
|
||
|
|
||
|
if(price >= band.top || price <= band.bottom)
|
||
|
{
|
||
|
close_all_open_trades();
|
||
|
} // price left the max_side (from either side)
|
||
|
else
|
||
|
if(band.reset_limits)
|
||
|
{
|
||
|
place_all_trade_levels(price);
|
||
|
} // all positions where closed (Set levels UP!)
|
||
|
|
||
|
|
||
|
|
||
|
box.length--;
|
||
|
Comment("Band: Top= "+band.top+" Bottom= "+band.bottom+" Quant= "+band.quanta+"\n"
|
||
|
+"Box: Top= "+box.top+" Bottom= "+box.bottom);
|
||
|
|
||
|
}
|
||
|
//+------------------------------------------------------------------+
|
||
|
|
||
|
//+------------------------------------------------------------------+
|
||
|
//| |
|
||
|
//+------------------------------------------------------------------+
|
||
|
void place_all_trade_levels(double price, double volume=0.1)
|
||
|
{
|
||
|
for(int i=1; i<band.number_levels; i++)
|
||
|
{
|
||
|
place_long(price+(band.quanta*i*_Point), band.quanta*(i+1), volume*(band.number_levels-i), false); // place the long
|
||
|
place_short(price-(band.quanta*i*_Point), band.quanta*(i+1), volume*(band.number_levels-i), false); // place the short
|
||
|
|
||
|
}
|
||
|
update_bands(price);
|
||
|
}
|
||
|
//+------------------------------------------------------------------+
|
||
|
//| |
|
||
|
//+------------------------------------------------------------------+
|
||
|
void place_long(double price, int take_profit, double volume=0.1, bool is_stop=true)
|
||
|
{
|
||
|
if(is_stop)
|
||
|
{
|
||
|
trader.Buy(volume, NULL, price, 0, price+(take_profit*_Point), NULL);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
trader.BuyStop(volume, price, NULL, 0, price+take_profit*_Point, ORDER_TIME_GTC, 0, NULL);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//+------------------------------------------------------------------+
|
||
|
//| |
|
||
|
//+------------------------------------------------------------------+
|
||
|
void place_short(double price, int take_profit, double volume=0.1, bool is_stop=true)
|
||
|
{
|
||
|
if(is_stop)
|
||
|
{
|
||
|
trader.Sell(volume, NULL, price, 0, price-(take_profit*_Point), NULL);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
trader.SellStop(volume, price, NULL, 0, price-take_profit*_Point, ORDER_TIME_GTC, 0, NULL);
|
||
|
}
|
||
|
}
|
||
|
//+------------------------------------------------------------------+
|
||
|
|
||
|
//+------------------------------------------------------------------+
|
||
|
//| |
|
||
|
//+------------------------------------------------------------------+
|
||
|
void close_all_open_trades()
|
||
|
{
|
||
|
for(int i=0; i<PositionsTotal(); i++)
|
||
|
{
|
||
|
ulong position_ticket = PositionGetTicket(i);
|
||
|
trader.PositionClose(position_ticket);
|
||
|
}
|
||
|
for(int j=0; j<OrdersTotal(); j++)
|
||
|
{
|
||
|
ulong order_ticket = OrderGetTicket(j);
|
||
|
trader.OrderDelete(order_ticket);
|
||
|
|
||
|
}
|
||
|
band.reset_limits = true;
|
||
|
}
|
||
|
|
||
|
//+------------------------------------------------------------------+
|
||
|
//| |
|
||
|
//+------------------------------------------------------------------+
|
||
|
void update_bands(double price)
|
||
|
{
|
||
|
band.top = price + NormalizeDouble(max_band_size*_Point, _Digits);
|
||
|
band.bottom = price - NormalizeDouble(max_band_size*_Point, _Digits);
|
||
|
band.reset_limits = false;
|
||
|
}
|
||
|
|
||
|
//+------------------------------------------------------------------+
|
||
|
//| |
|
||
|
//+------------------------------------------------------------------+
|
||
|
void update_box(double price, int direction=POS_W_BASE)
|
||
|
{
|
||
|
|
||
|
double top_mult;
|
||
|
double bottom_mult;
|
||
|
|
||
|
switch(direction)
|
||
|
{
|
||
|
case POS_W_BASE:
|
||
|
top_mult = BASE_MULT;
|
||
|
bottom_mult = BASE_MULT;
|
||
|
break;
|
||
|
case POS_W_LONG:
|
||
|
top_mult = win_multiplier;
|
||
|
bottom_mult = lose_multiplier;
|
||
|
break;
|
||
|
case POS_W_SHORT:
|
||
|
top_mult = lose_multiplier;
|
||
|
bottom_mult = win_multiplier;
|
||
|
break;
|
||
|
}
|
||
|
box.top = price + NormalizeDouble(top_mult*box_height*_Point, _Digits);
|
||
|
box.bottom = price - NormalizeDouble(bottom_mult*box_height*_Point, _Digits);
|
||
|
box.length = box_length;
|
||
|
|
||
|
}
|
||
|
//+------------------------------------------------------------------+
|
||
|
|
||
|
//+------------------------------------------------------------------+
|
||
|
|
||
|
//+------------------------------------------------------------------+
|
||
|
|
||
|
//+------------------------------------------------------------------+
|