Kao sto sam danas i obecao, videcete kako i na koji nacin napraviti svoj sopstveni indikator , i iskoristiti ga za davanje buy i sell signala za robotica koji vam je dostupan za preuzimanje. Takodje ovaj indikator mozete koristi i samostalno. Da bi smo kreirali indikator otvorimo nasu mt5 platformu , kliknemo na MetaEditor, a zatim u gornjem levom uglu kliknemo na New ikonicu. Izaberemo trecu opciju odozgo : "Custom Indicator", kliknemo next, damo ime nasem indikatoru, a zatim next (ovde nista ne cekiramo), pa opet next (ni ovde nista ne cekiramo ), i na kraju finish. Obrisite sve i plusnite kod ispod. Zatim Kompajlujte kod klikom na Compile ikonicu. Ovo sam zaboravio da vam napomenem u tekstovima pre ovog. Notacija je samo za pocetnike! A zatim proverimo da nema slucajno koja greska ili upozorenje, mada ne bi trebalo da bude, jer kod mene je kod kompajlovan sa 0 error(s), i 0 warning(s). Klikom na Spojler mozete preuzeti ovaj trend indikator.
- custom_trend_indicator.mq5:
- Code:
//+------------------------------------------------------------------+
//| custom_trend_indicator.mq5 |
//| Copyright 2019, MetaQuotes Software Corp. |
//| [You must be registered and logged in to see this link.] |
//+------------------------------------------------------------------+
#property copyright "Copyright 2019, MetaQuotes Software Corp."
#property link "drenjanind@mail.ru"
#property version "1.00"
#property indicator_chart_window
#property indicator_buffers 2
#property indicator_plots 2
#property indicator_type1 DRAW_ARROW
#property indicator_type2 DRAW_ARROW
#property indicator_color1 clrGreen
#property indicator_color2 clrRed
double buff_up[];
double buff_down[];
int ArrowShift = -30;
//+------------------------------------------------------------------+
//| Custom indicator initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
SetIndexBuffer(0, buff_up, INDICATOR_DATA);
SetIndexBuffer(1, buff_down, INDICATOR_DATA);
IndicatorSetInteger(INDICATOR_DIGITS, _Digits);
PlotIndexSetInteger(0, PLOT_ARROW, 71);
PlotIndexSetInteger(1, PLOT_ARROW, 72);
PlotIndexSetInteger(0, PLOT_ARROW_SHIFT, ArrowShift);
PlotIndexSetInteger(1, PLOT_ARROW_SHIFT, -ArrowShift);
PlotIndexSetDouble(0, PLOT_EMPTY_VALUE, EMPTY_VALUE);
PlotIndexSetDouble(1, PLOT_EMPTY_VALUE, EMPTY_VALUE);
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[])
{
int i, limit;
if (rates_total < 5)
return(0);
if (prev_calculated < 7)
{
limit =2;
ArrayInitialize(buff_down, EMPTY_VALUE);
ArrayInitialize(buff_up, EMPTY_VALUE);
} else limit = rates_total - 5;
for(i = limit; i < rates_total - 3; i++)
{
if (close[i] > close[i+2] && close[i] > close[i+3] && close[i] >= close[i-1] && close[i] >+ close[i-2])
buff_up[i] = close[i];
else buff_up[i]= EMPTY_VALUE;
if (close[i] < close[i+2] && close[i] < close[i+3] && close[i] <= close[i-1] && close[i] <= close[i-2])
buff_down[i] = close[i];
else buff_down[i]= EMPTY_VALUE;
}
return(rates_total);
}
//+------------------------------------------------------------------+
Jos nesto da napomenem. Sistem automatski ubaci nas indikator u folder Indicators. Tako ne berite brigu oko toga. Sad je potrebno da generisemo templejts za naseg robotica. Kliknemo opet na ikonicu New izaberemo prvu opciju Expert Advisor (templates) , next (dajte ime ovom robotu ), next itd.. na kraju finish. I tako , posto smo generisali templejts , obrisite sve i plusnite kod iz spojlera ispod. Kompajlujte kod i pokrenite test.
- trendy_ea.mq5 :
- Code:
//+------------------------------------------------------------------+
//| trendy_ea.mq5 |
//| Copyright 2019, MetaQuotes Software Corp. |
//| [You must be registered and logged in to see this link.] |
//+------------------------------------------------------------------+
#property copyright "Copyright 2019, MetaQuotes Software Corp."
#property link "drenjanind@mail.ru"
#property version "1.00"
#include <Trade\PositionInfo.mqh>
#include <Trade\Trade.mqh>
#include <Trade\SymbolInfo.mqh>
CPositionInfo _pos;
CTrade _trade;
CSymbolInfo _symbol;
double Lot = 0.1;
int StopLoss = 30;
int TakeProfit = 50;
ulong MagicNumber = 5050;
ulong Slippage = 30;
double SL;
double TP;
int indi; // skaracenica od custum trend indikatora
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
if (!_symbol.Name(Symbol()))
return(INIT_FAILED);
RefreshRates();
_trade.SetExpertMagicNumber(MagicNumber);
// funkcija koja dozvoljava rad naseg EA sa svim tipovima racuna
if (IsFillingTypeAllowed(SYMBOL_FILLING_FOK))
_trade.SetTypeFilling(ORDER_FILLING_FOK);
else if (IsFillingTypeAllowed(SYMBOL_FILLING_IOC))
_trade.SetTypeFilling(ORDER_FILLING_IOC);
else _trade.SetTypeFilling(ORDER_FILLING_RETURN);
// slip page
_trade.SetDeviationInPoints(Slippage);
// tri ili pet decimala
if (_symbol.Digits() == 3 || _symbol.Digits() == 5){
SL = StopLoss *10;
TP = TakeProfit *10;
}
else{
SL = StopLoss;
TP = TakeProfit;
}
// inicijalizacija indikatora
indi =iCustom(_symbol.Name(), Period(), "custom_trend_indicator");
if (indi == INVALID_HANDLE){
Print("indi create failed");
return(INIT_FAILED);
}
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick()
{
static datetime last_time = 0;
datetime current_time = iTime(_symbol.Name(), _Period, 0);
if (current_time == last_time)
return;
if (!RefreshRates())
{
last_time =0;
return;
}
last_time = current_time;
// indi trend
int buffer_size = 30; // za trideset sveca
double buffer_open[];
double buffer_high[];
double buffer_low[];
double buffer_close[];
if (CopyBuffer(indi, LOWER_LINE, 0, buffer_size, buffer_open) != buffer_size || ArraySize(buffer_open) != buffer_size)
{
last_time =0;
return;
}
if (CopyBuffer(indi, UPPER_LINE, 0, buffer_size, buffer_high) != buffer_size || ArraySize(buffer_high) != buffer_size)
{
last_time =0;
return;
}
if (CopyBuffer(indi, LOWER_LINE, 0, buffer_size, buffer_low) != buffer_size || ArraySize(buffer_low) != buffer_size)
{
last_time =0;
return;
}
if (CopyBuffer(indi, LOWER_LINE, 0, buffer_size, buffer_close) != buffer_size || ArraySize(buffer_close) != buffer_size)
{
last_time =0;
return;
}
ArraySetAsSeries(buffer_open , true);
ArraySetAsSeries(buffer_high , true);
ArraySetAsSeries(buffer_low , true);
ArraySetAsSeries(buffer_close , true);
double current_open = EMPTY_VALUE;
double current_high = EMPTY_VALUE;
double current_low = EMPTY_VALUE;
double current_close = EMPTY_VALUE;
double last_open = EMPTY_VALUE;
double last_high = EMPTY_VALUE;
double last_low = EMPTY_VALUE;
double last_close = EMPTY_VALUE;
for (int i =1; i< buffer_size; i++)
{
if (buffer_open[i] != EMPTY_VALUE && buffer_open[i] != 0)
{
if (last_open == EMPTY_VALUE)
{
last_open = buffer_open[i];
continue;
}
}
if (buffer_high[i] != EMPTY_VALUE && buffer_high[i] != 0)
{
if (last_high == EMPTY_VALUE)
{
last_high = buffer_high[i];
continue;
}
}
if (buffer_low[i] != EMPTY_VALUE && buffer_low[i] != 0)
{
if (last_low == EMPTY_VALUE)
{
last_open = buffer_open[i];
continue;
}
}
if (current_close == EMPTY_VALUE)
{
current_close = buffer_close[i];
break;
}
}
for (int i =1; i< buffer_size; i++)
{
if (buffer_high[i] != EMPTY_VALUE && buffer_high[i] != 0)
{
if (last_high == EMPTY_VALUE)
{
last_high = buffer_high[i];
continue;
}
if (current_high == EMPTY_VALUE)
{
current_high = buffer_high[i];
break;
}
}
}
// provera za buy sell signal
if (last_low != EMPTY_VALUE && current_low != EMPTY_VALUE)
{
if (current_low < last_low)
{
CloseTrade(POSITION_TYPE_SELL);
if (PosCount(POSITION_TYPE_BUY) == 0)
{
double sl = _symbol.Ask() - SL * _Point;
double tp = _symbol.Ask() + TP * _Point;
OpenBuy(sl, tp);
}
}
}
if (last_high != EMPTY_VALUE && current_high != EMPTY_VALUE)
{
if (current_high < last_high)
{
CloseTrade(POSITION_TYPE_BUY);
if (PosCount(POSITION_TYPE_SELL) == 0)
{
double sl = _symbol.Ask() + SL * _Point;
double tp = _symbol.Ask() - TP * _Point;
OpenSell(sl, tp);
}
}
}
}
//+------------------------------------------------------------------+
bool IsFillingTypeAllowed(int fill_type)
{
int filling = _symbol.TradeFillFlags();
return((filling && fill_type) == fill_type);
}
//+------------------------------------------------------------------+
int PosCount (ENUM_POSITION_TYPE position_type)
{
int count =0;
for(int i = PositionsTotal()-1; i>0; i--)
{
if (_pos.SelectByIndex(i) &&
_pos.Symbol() == _symbol.Name() &&
_pos.Magic() == MagicNumber &&
_pos.PositionType() == position_type )
count ++;
}
return(count);
}
//+------------------------------------------------------------------+
void CloseTrade(ENUM_POSITION_TYPE position_type)
{
for (int i = PositionsTotal() -1; i>=0; i--)
{
if (_pos.SelectByIndex(i) &&
_pos.Symbol() == _symbol.Name() &&
_pos.Magic() == MagicNumber &&
_pos.PositionType() == position_type )
_trade.PositionClose(_pos.Ticket());
}
}
//+------------------------------------------------------------------+
bool RefreshRates()
{
if (!_symbol.RefreshRates()){
Print("quote update failed");
return(false);
}
if (_symbol.Ask() == 0 || _symbol.Bid() == 0){
return(false);
}
return(true);
}
//+------------------------------------------------------------------+
void OpenBuy(double sl, double tp)
{
sl = _symbol.NormalizePrice(sl);
tp = _symbol.NormalizePrice(tp);
if (_trade.Buy(Lot, _symbol.Name(), _symbol.Ask(), sl, tp))
{
if (_trade.ResultDeal() == 0)
{
Print("failed to open buy order");
}
}
else
{
Print("failed to open buy order");
}
}
//+------------------------------------------------------------------+
void OpenSell(double sl, double tp)
{
sl = _symbol.NormalizePrice(sl);
tp = _symbol.NormalizePrice(tp);
if (_trade.Sell(Lot, _symbol.Name(), _symbol.Bid(), sl, tp))
{
if (_trade.ResultDeal() == 0)
{
Print("failed to open sell order");
}
}
else
{
Print("failed to open sell order");
}
}
//+------------------------------------------------------------------+
Robota sam testirao na EURUSD, GBPUSD, EURJPY , dnevnom vremenskom opsegu, sa inicijalnim depozitom od samo 1000 USD, i polugom 1:33. Rezultati testiranja su sledeci:
- EURUSD:
- GBPUSD:
- EURJPY:
Robot je napravi profit na prva dva valutna para. A na eurjpy mali gubitak negde oko 40 dolara. Tako, sad preostaje samo da se igramo sa logikom koja daje/generise buy/sell signal. Zatim potrebno je da se dodaju jos neke stvarcice kao sto su trjeling stop ili break even za pocetak. Licno mislim da je pozeljno da se doda samo jedna od te dve opcije. Mozda je trejling stop bolja opcija bar za mene. I jedan i drugi primer imate vec odradjen , tako da vam preostaje samo da ih implementirate u ovaj EA.
Takodje nisam zaboravio moje obecanje koje sam dao ihihi, a odnosi se na jedan komplet operativan EA u kojem su implementirane obe opcije. Vec imam skuckanog robota pod nazivom "Portugalac", tako, eto ocekujte ga uskoro u ovoj sekciji.
Toliko ,odoh.