321 lines
25 KiB
Plaintext
321 lines
25 KiB
Plaintext
|
|
//+------------------------------------------------------------------+
|
|||
|
|
//| Exp_GStopLoss.mq5 |
|
|||
|
|
//| Copyright © 2016, Nikolay Kositsin |
|
|||
|
|
//| Khabarovsk, farria@mail.redcom.ru |
|
|||
|
|
//+------------------------------------------------------------------+
|
|||
|
|
#property copyright "Copyright © 2016, Nikolay Kositsin"
|
|||
|
|
#property link "farria@mail.redcom.ru"
|
|||
|
|
#property version "1.10"
|
|||
|
|
//+----------------------------------------------+
|
|||
|
|
//| Перечисление для вариантов расчёта убытка |
|
|||
|
|
//+----------------------------------------------+
|
|||
|
|
enum LossMode
|
|||
|
|
{
|
|||
|
|
ENUM_PERCENT, //убытки в процентах
|
|||
|
|
ENUM_CARRENCY //убытки в валюте депозита
|
|||
|
|
};
|
|||
|
|
//+----------------------------------------------+
|
|||
|
|
//| Входные параметры индикатора эксперта |
|
|||
|
|
//+----------------------------------------------+
|
|||
|
|
input LossMode LMode=ENUM_PERCENT; //способ определения убытков
|
|||
|
|
input double StopLoss=20.0; //размер стоплосса
|
|||
|
|
//+----------------------------------------------+
|
|||
|
|
bool Stop;
|
|||
|
|
//+------------------------------------------------------------------+
|
|||
|
|
//| Expert initialization function |
|
|||
|
|
//+------------------------------------------------------------------+
|
|||
|
|
int OnInit()
|
|||
|
|
{
|
|||
|
|
//----
|
|||
|
|
Stop=false;
|
|||
|
|
//---- завершение инициализации
|
|||
|
|
return(INIT_SUCCEEDED);
|
|||
|
|
}
|
|||
|
|
//+------------------------------------------------------------------+
|
|||
|
|
//| Expert deinitialization function |
|
|||
|
|
//+------------------------------------------------------------------+
|
|||
|
|
void OnDeinit(const int reason)
|
|||
|
|
{
|
|||
|
|
//----
|
|||
|
|
|
|||
|
|
//----
|
|||
|
|
}
|
|||
|
|
//+------------------------------------------------------------------+
|
|||
|
|
//| Expert tick function |
|
|||
|
|
//+------------------------------------------------------------------+
|
|||
|
|
void OnTick()
|
|||
|
|
{
|
|||
|
|
//----
|
|||
|
|
double balance=AccountInfoDouble(ACCOUNT_BALANCE);
|
|||
|
|
double profit=AccountInfoDouble(ACCOUNT_PROFIT);
|
|||
|
|
if(profit>0 && !Stop) return;
|
|||
|
|
|
|||
|
|
//---- проверка на глобальный стоплосс
|
|||
|
|
if(!Stop)
|
|||
|
|
switch(LMode)
|
|||
|
|
{
|
|||
|
|
case ENUM_PERCENT :
|
|||
|
|
{
|
|||
|
|
double LossRatio=MathAbs(100*profit/balance);
|
|||
|
|
if(LossRatio>=StopLoss) Stop=true;
|
|||
|
|
break;
|
|||
|
|
}
|
|||
|
|
case ENUM_CARRENCY :
|
|||
|
|
{
|
|||
|
|
if(MathAbs(profit)>StopLoss) Stop=true;
|
|||
|
|
break;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
//---- закрываем все открытые позиции
|
|||
|
|
if(Stop)
|
|||
|
|
{
|
|||
|
|
int total=PositionsTotal();
|
|||
|
|
if(!total)
|
|||
|
|
{
|
|||
|
|
Stop=false; // все позиции закрыты
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
for(int pos=total-1; pos>=0; pos--)
|
|||
|
|
{
|
|||
|
|
string symbol=PositionGetSymbol(pos);
|
|||
|
|
if(!PositionSelect(symbol)) continue;
|
|||
|
|
if(PositionGetInteger(POSITION_TYPE)==POSITION_TYPE_BUY)
|
|||
|
|
{
|
|||
|
|
bool BUY_Close=true;
|
|||
|
|
BuyPositionClose(BUY_Close,symbol,20);
|
|||
|
|
}
|
|||
|
|
if(PositionGetInteger(POSITION_TYPE)==POSITION_TYPE_SELL)
|
|||
|
|
{
|
|||
|
|
bool SELL_Close=true;
|
|||
|
|
SellPositionClose(SELL_Close,symbol,20);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
//----
|
|||
|
|
}
|
|||
|
|
//+------------------------------------------------------------------+
|
|||
|
|
//| Закрываем длинную позицию |
|
|||
|
|
//+------------------------------------------------------------------+
|
|||
|
|
bool BuyPositionClose
|
|||
|
|
(
|
|||
|
|
bool &Signal, // флаг разрешения на сделку
|
|||
|
|
const string symbol, // торговая пара сделки
|
|||
|
|
uint deviation // слиппаж
|
|||
|
|
)
|
|||
|
|
{
|
|||
|
|
//----
|
|||
|
|
if(!Signal) return(true);
|
|||
|
|
|
|||
|
|
//---- Объявление структур торгового запроса и результата торгового запроса
|
|||
|
|
MqlTradeRequest request;
|
|||
|
|
MqlTradeResult result;
|
|||
|
|
//---- Объявление структуры результата проверки торгового запроса
|
|||
|
|
MqlTradeCheckResult check;
|
|||
|
|
|
|||
|
|
//---- обнуление структур
|
|||
|
|
ZeroMemory(request);
|
|||
|
|
ZeroMemory(result);
|
|||
|
|
ZeroMemory(check);
|
|||
|
|
|
|||
|
|
//---- Проверка на наличие открытой BUY позиции
|
|||
|
|
if(PositionSelect(symbol))
|
|||
|
|
{
|
|||
|
|
if(PositionGetInteger(POSITION_TYPE)!=POSITION_TYPE_BUY) return(false);
|
|||
|
|
}
|
|||
|
|
else return(false);
|
|||
|
|
|
|||
|
|
double MaxLot,volume,Bid;
|
|||
|
|
//---- получение данных для расчёта
|
|||
|
|
if(!PositionGetDouble(POSITION_VOLUME,volume)) return(true);
|
|||
|
|
if(!SymbolInfoDouble(symbol,SYMBOL_VOLUME_MAX,MaxLot)) return(true);
|
|||
|
|
if(!SymbolInfoDouble(symbol,SYMBOL_BID,Bid)) return(true);
|
|||
|
|
|
|||
|
|
//---- проверка лота на максимальное допустимое значение
|
|||
|
|
if(volume>MaxLot) volume=MaxLot;
|
|||
|
|
|
|||
|
|
//---- Инициализация структуры торгового запроса MqlTradeRequest для закрывания BUY позиции
|
|||
|
|
request.type = ORDER_TYPE_SELL;
|
|||
|
|
request.price = Bid;
|
|||
|
|
request.action = TRADE_ACTION_DEAL;
|
|||
|
|
request.symbol = symbol;
|
|||
|
|
request.volume = volume;
|
|||
|
|
request.sl = 0.0;
|
|||
|
|
request.tp = 0.0;
|
|||
|
|
request.deviation=deviation;
|
|||
|
|
request.type_filling=ORDER_FILLING_FOK;
|
|||
|
|
request.position=PositionGetInteger(POSITION_TICKET);
|
|||
|
|
|
|||
|
|
//---- Проверка торгового запроса на корректность
|
|||
|
|
if(!OrderCheck(request,check))
|
|||
|
|
{
|
|||
|
|
Print(__FUNCTION__,"(): Неверные данные для структуры торгового запроса!");
|
|||
|
|
Print(__FUNCTION__,"(): OrderCheck(): ",ResultRetcodeDescription(check.retcode));
|
|||
|
|
return(false);
|
|||
|
|
}
|
|||
|
|
//----
|
|||
|
|
string comment="";
|
|||
|
|
StringConcatenate(comment,"<<< ============ ",__FUNCTION__,"(): Закрываем Buy позицию по ",symbol," ============ >>>");
|
|||
|
|
Print(comment);
|
|||
|
|
|
|||
|
|
//---- Отправка приказа на закрывание позиции на торговый сервер
|
|||
|
|
if(!OrderSend(request,result) || result.retcode!=TRADE_RETCODE_DONE)
|
|||
|
|
{
|
|||
|
|
Print(__FUNCTION__,"(): Невозможно закрыть позицию!");
|
|||
|
|
Print(__FUNCTION__,"(): OrderSend(): ",ResultRetcodeDescription(result.retcode));
|
|||
|
|
return(false);
|
|||
|
|
}
|
|||
|
|
else
|
|||
|
|
if(result.retcode==TRADE_RETCODE_DONE)
|
|||
|
|
{
|
|||
|
|
Signal=false;
|
|||
|
|
comment="";
|
|||
|
|
StringConcatenate(comment,"<<< ============ ",__FUNCTION__,"(): Buy позиция по ",symbol," закрыта ============ >>>");
|
|||
|
|
Print(comment);
|
|||
|
|
PlaySound("ok.wav");
|
|||
|
|
}
|
|||
|
|
else
|
|||
|
|
{
|
|||
|
|
Print(__FUNCTION__,"(): Невозможно закрыть позицию!");
|
|||
|
|
Print(__FUNCTION__,"(): OrderSend(): ",ResultRetcodeDescription(result.retcode));
|
|||
|
|
return(false);
|
|||
|
|
}
|
|||
|
|
//----
|
|||
|
|
return(true);
|
|||
|
|
}
|
|||
|
|
//+------------------------------------------------------------------+
|
|||
|
|
//| Закрываем короткую позицию |
|
|||
|
|
//+------------------------------------------------------------------+
|
|||
|
|
bool SellPositionClose
|
|||
|
|
(
|
|||
|
|
bool &Signal, // флаг разрешения на сделку
|
|||
|
|
const string symbol, // торговая пара сделки
|
|||
|
|
uint deviation // слиппаж
|
|||
|
|
)
|
|||
|
|
{
|
|||
|
|
//----
|
|||
|
|
if(!Signal) return(true);
|
|||
|
|
|
|||
|
|
//---- Объявление структур торгового запроса и результата торгового запроса
|
|||
|
|
MqlTradeRequest request;
|
|||
|
|
MqlTradeResult result;
|
|||
|
|
//---- Объявление структуры результата проверки торгового запроса
|
|||
|
|
MqlTradeCheckResult check;
|
|||
|
|
|
|||
|
|
//---- обнуление структур
|
|||
|
|
ZeroMemory(request);
|
|||
|
|
ZeroMemory(result);
|
|||
|
|
ZeroMemory(check);
|
|||
|
|
|
|||
|
|
//---- Проверка на наличие открытой SELL позиции
|
|||
|
|
if(PositionSelect(symbol))
|
|||
|
|
{
|
|||
|
|
if(PositionGetInteger(POSITION_TYPE)!=POSITION_TYPE_SELL)return(false);
|
|||
|
|
}
|
|||
|
|
else return(false);
|
|||
|
|
|
|||
|
|
double MaxLot,volume,Ask;
|
|||
|
|
//---- получение данных для расчёта
|
|||
|
|
if(!PositionGetDouble(POSITION_VOLUME,volume)) return(true);
|
|||
|
|
if(!SymbolInfoDouble(symbol,SYMBOL_VOLUME_MAX,MaxLot)) return(true);
|
|||
|
|
if(!SymbolInfoDouble(symbol,SYMBOL_ASK,Ask)) return(true);
|
|||
|
|
|
|||
|
|
//---- проверка лота на максимальное допустимое значение
|
|||
|
|
if(volume>MaxLot) volume=MaxLot;
|
|||
|
|
|
|||
|
|
//---- Инициализация структуры торгового запроса MqlTradeRequest для закрывания SELL позиции
|
|||
|
|
request.type = ORDER_TYPE_BUY;
|
|||
|
|
request.price = Ask;
|
|||
|
|
request.action = TRADE_ACTION_DEAL;
|
|||
|
|
request.symbol = symbol;
|
|||
|
|
request.volume = volume;
|
|||
|
|
request.sl = 0.0;
|
|||
|
|
request.tp = 0.0;
|
|||
|
|
request.deviation=deviation;
|
|||
|
|
request.type_filling=ORDER_FILLING_FOK;
|
|||
|
|
request.position=PositionGetInteger(POSITION_TICKET);
|
|||
|
|
|
|||
|
|
//---- Проверка торгового запроса на корректность
|
|||
|
|
if(!OrderCheck(request,check))
|
|||
|
|
{
|
|||
|
|
Print(__FUNCTION__,"(): Неверные данные для структуры торгового запроса!");
|
|||
|
|
Print(__FUNCTION__,"(): OrderCheck(): ",ResultRetcodeDescription(check.retcode));
|
|||
|
|
return(false);
|
|||
|
|
}
|
|||
|
|
//----
|
|||
|
|
string comment="";
|
|||
|
|
StringConcatenate(comment,"<<< ============ ",__FUNCTION__,"(): Закрываем Sell позицию по ",symbol," ============ >>>");
|
|||
|
|
Print(comment);
|
|||
|
|
|
|||
|
|
//---- Отправка приказа на закрывание позиции на торговый сервер
|
|||
|
|
if(!OrderSend(request,result) || result.retcode!=TRADE_RETCODE_DONE)
|
|||
|
|
{
|
|||
|
|
Print(__FUNCTION__,"(): Невозможно закрыть позицию!");
|
|||
|
|
Print(__FUNCTION__,"(): OrderSend(): ",ResultRetcodeDescription(result.retcode));
|
|||
|
|
return(false);
|
|||
|
|
}
|
|||
|
|
else
|
|||
|
|
if(result.retcode==TRADE_RETCODE_DONE)
|
|||
|
|
{
|
|||
|
|
Signal=false;
|
|||
|
|
comment="";
|
|||
|
|
StringConcatenate(comment,"<<< ============ ",__FUNCTION__,"(): Sell позиция по ",symbol," закрыта ============ >>>");
|
|||
|
|
Print(comment);
|
|||
|
|
PlaySound("ok.wav");
|
|||
|
|
}
|
|||
|
|
else
|
|||
|
|
{
|
|||
|
|
Print(__FUNCTION__,"(): Невозможно закрыть позицию!");
|
|||
|
|
Print(__FUNCTION__,"(): OrderSend(): ",ResultRetcodeDescription(result.retcode));
|
|||
|
|
return(false);
|
|||
|
|
}
|
|||
|
|
//----
|
|||
|
|
return(true);
|
|||
|
|
}
|
|||
|
|
//+------------------------------------------------------------------+
|
|||
|
|
//| возврат стрингового результата торговой операции по его коду |
|
|||
|
|
//+------------------------------------------------------------------+
|
|||
|
|
string ResultRetcodeDescription(int retcode)
|
|||
|
|
{
|
|||
|
|
string str;
|
|||
|
|
//----
|
|||
|
|
switch(retcode)
|
|||
|
|
{
|
|||
|
|
case TRADE_RETCODE_REQUOTE: str="Реквота"; break;
|
|||
|
|
case TRADE_RETCODE_REJECT: str="Запрос отвергнут"; break;
|
|||
|
|
case TRADE_RETCODE_CANCEL: str="Запрос отменен трейдером"; break;
|
|||
|
|
case TRADE_RETCODE_PLACED: str="Ордер размещен"; break;
|
|||
|
|
case TRADE_RETCODE_DONE: str="Заявка выполнена"; break;
|
|||
|
|
case TRADE_RETCODE_DONE_PARTIAL: str="Заявка выполнена частично"; break;
|
|||
|
|
case TRADE_RETCODE_ERROR: str="Ошибка обработки запроса"; break;
|
|||
|
|
case TRADE_RETCODE_TIMEOUT: str="Запрос отменен по истечению времени";break;
|
|||
|
|
case TRADE_RETCODE_INVALID: str="Неправильный запрос"; break;
|
|||
|
|
case TRADE_RETCODE_INVALID_VOLUME: str="Неправильный объем в запросе"; break;
|
|||
|
|
case TRADE_RETCODE_INVALID_PRICE: str="Неправильная цена в запросе"; break;
|
|||
|
|
case TRADE_RETCODE_INVALID_STOPS: str="Неправильные стопы в запросе"; break;
|
|||
|
|
case TRADE_RETCODE_TRADE_DISABLED: str="Торговля запрещена"; break;
|
|||
|
|
case TRADE_RETCODE_MARKET_CLOSED: str="Рынок закрыт"; break;
|
|||
|
|
case TRADE_RETCODE_NO_MONEY: str="Нет достаточных денежных средств для выполнения запроса"; break;
|
|||
|
|
case TRADE_RETCODE_PRICE_CHANGED: str="Цены изменились"; break;
|
|||
|
|
case TRADE_RETCODE_PRICE_OFF: str="Отсутствуют котировки для обработки запроса"; break;
|
|||
|
|
case TRADE_RETCODE_INVALID_EXPIRATION: str="Неверная дата истечения ордера в запросе"; break;
|
|||
|
|
case TRADE_RETCODE_ORDER_CHANGED: str="Состояние ордера изменилось"; break;
|
|||
|
|
case TRADE_RETCODE_TOO_MANY_REQUESTS: str="Слишком частые запросы"; break;
|
|||
|
|
case TRADE_RETCODE_NO_CHANGES: str="В запросе нет изменений"; break;
|
|||
|
|
case TRADE_RETCODE_SERVER_DISABLES_AT: str="Автотрейдинг запрещен сервером"; break;
|
|||
|
|
case TRADE_RETCODE_CLIENT_DISABLES_AT: str="Автотрейдинг запрещен клиентским терминалом"; break;
|
|||
|
|
case TRADE_RETCODE_LOCKED: str="Запрос заблокирован для обработки"; break;
|
|||
|
|
case TRADE_RETCODE_FROZEN: str="Ордер или позиция заморожены"; break;
|
|||
|
|
case TRADE_RETCODE_INVALID_FILL: str="Указан неподдерживаемый тип исполнения ордера по остатку "; break;
|
|||
|
|
case TRADE_RETCODE_CONNECTION: str="Нет соединения с торговым сервером"; break;
|
|||
|
|
case TRADE_RETCODE_ONLY_REAL: str="Операция разрешена только для реальных счетов"; break;
|
|||
|
|
case TRADE_RETCODE_LIMIT_ORDERS: str="Достигнут лимит на количество отложенных ордеров"; break;
|
|||
|
|
case TRADE_RETCODE_LIMIT_VOLUME: str="Достигнут лимит на объем ордеров и позиций для данного символа"; break;
|
|||
|
|
case TRADE_RETCODE_INVALID_ORDER: str="Неверный или запрещённый тип ордера"; break;
|
|||
|
|
case TRADE_RETCODE_POSITION_CLOSED: str="Позиция с указанным POSITION_IDENTIFIER уже закрыта"; break;
|
|||
|
|
default: str="Неизвестный результат";
|
|||
|
|
}
|
|||
|
|
//----
|
|||
|
|
return(str);
|
|||
|
|
}
|
|||
|
|
//+------------------------------------------------------------------+
|
|||
|
|
�
|