ÿþ//+------------------------------------------------------------------+
//| Breakeven Limit order triggered.mq5 |
//| Copyright © 2019, Vladimir Karputov |
//| http://wmua.ru/slesar/ |
//+------------------------------------------------------------------+
#property copyright "Copyright © 2019, Vladimir Karputov"
#property link "http://wmua.ru/slesar/"
#property version "1.000"
/*
barabashkakvn Trading engine 3.016
*/
#include <Trade\PositionInfo.mqh>
#include <Trade\Trade.mqh>
#include <Trade\SymbolInfo.mqh>
#include <Trade\AccountInfo.mqh>
CPositionInfo m_position; // trade position object
CTrade m_trade; // trading object
CSymbolInfo m_symbol; // symbol info object
CAccountInfo m_account; // account info wrapper
//--- input parameters
//---
input string m_hline_name_buy = "Buy net price";
input string m_hline_name_sell = "Sell net price";
//input string m_hline_name_breakeven = "Breakeven price";
//---
input bool InpPrintLog = false; // Print log
input ulong InpMagic = 351328551; // Magic number
//---
ulong ExtSlippage = 10; // Slippage
double ExtAdjustedPoint; // point value adjusted for 3 or 5 points
bool ExtNeedBreakeven = false; // Need Breakeven
//---
double total_price_multiply_volume_buy = 0.0;
double net_price_buy = 0.0;
double total_price_multiply_volume_sell = 0.0;
double net_price_sell = 0.0;
//double breakeven_price = 0.0;
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
//---
if(!m_symbol.Name(Symbol())) // sets symbol name
return(INIT_FAILED);
RefreshRates();
//---
m_trade.SetExpertMagicNumber(InpMagic);
m_trade.SetMarginMode();
m_trade.SetTypeFillingBySymbol(m_symbol.Name());
m_trade.SetDeviationInPoints(ExtSlippage);
//--- tuning for 3 or 5 digits
int digits_adjust=1;
if(m_symbol.Digits()==3 || m_symbol.Digits()==5)
digits_adjust=10;
ExtAdjustedPoint=m_symbol.Point()*digits_adjust;
//---
HLineCreate(0,m_hline_name_buy,0,0.0,clrBlue);
HLineCreate(0,m_hline_name_sell,0,0.0,clrRed);
//HLineCreate(0,m_hline_name_breakeven,0,0.0,clrDeepPink);
//---
if(MQLInfoInteger(MQL_TESTER))
{
//m_trade.BuyLimit(m_symbol.LotsMin(),1.13540);
//m_trade.BuyLimit(m_symbol.LotsMin(),1.13145);
//m_trade.BuyLimit(m_symbol.LotsMin(),1.12473);
//m_trade.SellLimit(m_symbol.LotsMin(),1.12368);
//m_trade.SellLimit(m_symbol.LotsMin(),1.12624);
//m_trade.SellLimit(m_symbol.LotsMin(),1.13796);
//m_trade.BuyStop(m_symbol.LotsMin(),1.12368);
//m_trade.BuyStop(m_symbol.LotsMin(),1.12624);
//m_trade.BuyStop(m_symbol.LotsMin(),1.13796);
}
//---
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Expert deinitialization function |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
//---
HLineDelete(0,m_hline_name_buy);
HLineDelete(0,m_hline_name_sell);
//HLineDelete(0,m_hline_name_breakeven);
}
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick()
{
if(ExtNeedBreakeven)
{
double level;
if(FreezeStopsLevels(level))
{
double price_lowest_buy = DBL_MAX; double lowest_buy_volume = 0.0;
double price_highest_sell = DBL_MIN; double highest_sell_volume = 0.0;
CalculationNetPrice(price_lowest_buy,lowest_buy_volume,
price_highest_sell,highest_sell_volume);
if(price_lowest_buy!=DBL_MAX && price_highest_sell!=DBL_MIN)
{
//---
Alert(__FUNCTION__,", ERROR: Wrong situation. On the symbol /"",m_symbol.Name(),/"" simultaneously open BUY and SELL!");
ExtNeedBreakeven=false;
return;
}
if(price_lowest_buy!=DBL_MAX && net_price_buy!=0.0)
{
Trailing(level,POSITION_TYPE_BUY,net_price_buy);
ExtNeedBreakeven=false;
return;
}
if(price_highest_sell!=DBL_MIN && net_price_sell!=0.0)
{
Trailing(level,POSITION_TYPE_SELL,net_price_sell);
ExtNeedBreakeven=false;
return;
}
ExtNeedBreakeven=false;
}
}
//---
}
//+------------------------------------------------------------------+
//| TradeTransaction function |
//+------------------------------------------------------------------+
void OnTradeTransaction(const MqlTradeTransaction &trans,
const MqlTradeRequest &request,
const MqlTradeResult &result)
{
//--- get transaction type as enumeration value
ENUM_TRADE_TRANSACTION_TYPE type=trans.type;
//--- if transaction is result of addition of the transaction in history
if(type==TRADE_TRANSACTION_DEAL_ADD)
{
long deal_ticket =0;
long deal_order =0;
long deal_time =0;
long deal_time_msc =0;
long deal_type =-1;
long deal_entry =-1;
long deal_magic =0;
long deal_reason =-1;
long deal_position_id =0;
double deal_volume =0.0;
double deal_price =0.0;
double deal_commission =0.0;
double deal_swap =0.0;
double deal_profit =0.0;
string deal_symbol ="";
string deal_comment ="";
string deal_external_id ="";
if(HistoryDealSelect(trans.deal))
{
deal_ticket =HistoryDealGetInteger(trans.deal,DEAL_TICKET);
deal_order =HistoryDealGetInteger(trans.deal,DEAL_ORDER);
deal_time =HistoryDealGetInteger(trans.deal,DEAL_TIME);
deal_time_msc =HistoryDealGetInteger(trans.deal,DEAL_TIME_MSC);
deal_type =HistoryDealGetInteger(trans.deal,DEAL_TYPE);
deal_entry =HistoryDealGetInteger(trans.deal,DEAL_ENTRY);
deal_magic =HistoryDealGetInteger(trans.deal,DEAL_MAGIC);
deal_reason =HistoryDealGetInteger(trans.deal,DEAL_REASON);
deal_position_id =HistoryDealGetInteger(trans.deal,DEAL_POSITION_ID);
deal_volume =HistoryDealGetDouble(trans.deal,DEAL_VOLUME);
deal_price =HistoryDealGetDouble(trans.deal,DEAL_PRICE);
deal_commission =HistoryDealGetDouble(trans.deal,DEAL_COMMISSION);
deal_swap =HistoryDealGetDouble(trans.deal,DEAL_SWAP);
deal_profit =HistoryDealGetDouble(trans.deal,DEAL_PROFIT);
deal_symbol =HistoryDealGetString(trans.deal,DEAL_SYMBOL);
deal_comment =HistoryDealGetString(trans.deal,DEAL_COMMENT);
deal_external_id =HistoryDealGetString(trans.deal,DEAL_EXTERNAL_ID);
}
else
return;
ENUM_DEAL_ENTRY enum_deal_entry=(ENUM_DEAL_ENTRY)deal_entry;
if(deal_symbol==m_symbol.Name() && deal_magic==InpMagic)
{
if(deal_type==DEAL_TYPE_BUY || deal_type==DEAL_TYPE_SELL)
{
if(deal_entry==DEAL_ENTRY_IN)
ExtNeedBreakeven=true;
}
}
}
}
//+------------------------------------------------------------------+
//| Refreshes the symbol quotes data |
//+------------------------------------------------------------------+
bool RefreshRates(void)
{
//--- refresh rates
if(!m_symbol.RefreshRates())
{
Print("RefreshRates error");
return(false);
}
//--- protection against the return value of "zero"
if(m_symbol.Ask()==0 || m_symbol.Bid()==0)
return(false);
//---
return(true);
}
//+------------------------------------------------------------------+
//| Check Freeze and Stops levels |
//+------------------------------------------------------------------+
bool FreezeStopsLevels(double &level)
{
//--- check Freeze and Stops levels
/*
Type of order/position | Activation price | Check
------------------------|--------------------|--------------------------------------------
Buy Limit order | Ask | Ask-OpenPrice >= SYMBOL_TRADE_FREEZE_LEVEL
Buy Stop order | Ask | OpenPrice-Ask >= SYMBOL_TRADE_FREEZE_LEVEL
Sell Limit order | Bid | OpenPrice-Bid >= SYMBOL_TRADE_FREEZE_LEVEL
Sell Stop order | Bid | Bid-OpenPrice >= SYMBOL_TRADE_FREEZE_LEVEL
Buy position | Bid | TakeProfit-Bid >= SYMBOL_TRADE_FREEZE_LEVEL
| | Bid-StopLoss >= SYMBOL_TRADE_FREEZE_LEVEL
Sell position | Ask | Ask-TakeProfit >= SYMBOL_TRADE_FREEZE_LEVEL
| | StopLoss-Ask >= SYMBOL_TRADE_FREEZE_LEVEL
Buying is done at the Ask price | Selling is done at the Bid price
------------------------------------------------|----------------------------------
TakeProfit >= Bid | TakeProfit <= Ask
StopLoss <= Bid | StopLoss >= Ask
TakeProfit - Bid >= SYMBOL_TRADE_STOPS_LEVEL | Ask - TakeProfit >= SYMBOL_TRADE_STOPS_LEVEL
Bid - StopLoss >= SYMBOL_TRADE_STOPS_LEVEL | StopLoss - Ask >= SYMBOL_TRADE_STOPS_LEVEL
*/
if(!RefreshRates() || !m_symbol.Refresh())
return(false);
//--- FreezeLevel -> for pending order and modification
double freeze_level=m_symbol.FreezeLevel()*m_symbol.Point();
if(freeze_level==0.0)
freeze_level=(m_symbol.Ask()-m_symbol.Bid())*3.0;
freeze_level*=1.1;
//--- StopsLevel -> for TakeProfit and StopLoss
double stop_level=m_symbol.StopsLevel()*m_symbol.Point();
if(stop_level==0.0)
stop_level=(m_symbol.Ask()-m_symbol.Bid())*3.0;
stop_level*=1.1;
if(freeze_level<=0.0 || stop_level<=0.0)
return(false);
level=(freeze_level>stop_level)?freeze_level:stop_level;
//---
return(true);
}
//+------------------------------------------------------------------+
//| Calculation Net Price |
//+------------------------------------------------------------------+
void CalculationNetPrice(double &price_lowest_buy,double &lowest_buy_volume,
double &price_highest_sell,double &highest_sell_volume)
{
price_lowest_buy = DBL_MAX; lowest_buy_volume = 0.0;
price_highest_sell= DBL_MIN; highest_sell_volume = 0.0;
total_price_multiply_volume_buy=0.0;
double total_volume_buy=0.0;
net_price_buy=0.0;
total_price_multiply_volume_sell=0.0;
double total_volume_sell=0.0;
net_price_sell=0.0;
int count_buys = 0;
int count_sells= 0;
for(int i=PositionsTotal()-1;i>=0;i--)
if(m_position.SelectByIndex(i)) // selects the position by index for further access to its properties
if(m_position.Symbol()==m_symbol.Name())
{
if(m_position.PositionType()==POSITION_TYPE_BUY)
{
total_price_multiply_volume_buy+=m_position.PriceOpen()*m_position.Volume();
total_volume_buy+=m_position.Volume();
if(m_position.PriceOpen()<price_lowest_buy)
{
price_lowest_buy=m_position.PriceOpen();
lowest_buy_volume=m_position.Volume();
}
count_buys++;
}
else
{
total_price_multiply_volume_sell+=m_position.PriceOpen()*m_position.Volume();
total_volume_sell+=m_position.Volume();
if(m_position.PriceOpen()>price_highest_sell)
{
price_highest_sell=m_position.PriceOpen();
highest_sell_volume=m_position.Volume();
}
count_sells++;
}
}
//---
if(total_price_multiply_volume_buy!=0 && total_volume_buy!=0 && count_buys>1)
{
net_price_buy=total_price_multiply_volume_buy/total_volume_buy;
HLineMove(0,m_hline_name_buy,net_price_buy);
}
else
HLineMove(0,m_hline_name_buy);
if(total_price_multiply_volume_sell!=0 && total_volume_sell!=0 && count_sells>1)
{
net_price_sell=total_price_multiply_volume_sell/total_volume_sell;
HLineMove(0,m_hline_name_sell,net_price_sell);
}
else
HLineMove(0,m_hline_name_sell);
//if(total_volume_buy-total_volume_sell!=0)
// {
// breakeven_price=(total_price_multiply_volume_buy-total_price_multiply_volume_sell)/
// (total_volume_buy+total_volume_sell*-1);
// HLineMove(0,m_hline_name_breakeven,breakeven_price);
// }
//else
// HLineMove(0,m_hline_name_breakeven);
//---
return;
}
//+------------------------------------------------------------------+
//| Create the horizontal line |
//+------------------------------------------------------------------+
bool HLineCreate(const long chart_ID=0, // chart's ID
const string name="HLine", // line name
const int sub_window=0, // subwindow index
double price=0, // line price
const color clr=clrRed, // line color
const ENUM_LINE_STYLE style=STYLE_SOLID, // line style
const int width=1, // line width
const bool back=false, // in the background
const bool selection=false, // highlight to move
const bool hidden=true, // hidden in the object list
const long z_order=0) // priority for mouse click
{
//--- if the price is not set, set it at the current Bid price level
if(!price)
price=SymbolInfoDouble(Symbol(),SYMBOL_BID);
//--- reset the error value
ResetLastError();
//--- create a horizontal line
if(!ObjectCreate(chart_ID,name,OBJ_HLINE,sub_window,0,price))
{
Print(__FUNCTION__,
": failed to create a horizontal line! Error code = ",GetLastError());
return(false);
}
//--- set line color
ObjectSetInteger(chart_ID,name,OBJPROP_COLOR,clr);
//--- set line display style
ObjectSetInteger(chart_ID,name,OBJPROP_STYLE,style);
//--- set line width
ObjectSetInteger(chart_ID,name,OBJPROP_WIDTH,width);
//--- display in the foreground (false) or background (true)
ObjectSetInteger(chart_ID,name,OBJPROP_BACK,back);
//--- enable (true) or disable (false) the mode of moving the line by mouse
//--- when creating a graphical object using ObjectCreate function, the object cannot be
//--- highlighted and moved by default. Inside this method, selection parameter
//--- is true by default making it possible to highlight and move the object
ObjectSetInteger(chart_ID,name,OBJPROP_SELECTABLE,selection);
ObjectSetInteger(chart_ID,name,OBJPROP_SELECTED,selection);
//--- hide (true) or display (false) graphical object name in the object list
ObjectSetInteger(chart_ID,name,OBJPROP_HIDDEN,hidden);
//--- set the priority for receiving the event of a mouse click in the chart
ObjectSetInteger(chart_ID,name,OBJPROP_ZORDER,z_order);
//--- successful execution
return(true);
}
//+------------------------------------------------------------------+
//| Move horizontal line |
//+------------------------------------------------------------------+
bool HLineMove(const long chart_ID=0, // chart's ID
const string name="HLine", // line name
double price=0) // line price
{
//--- if the line price is not set, move it to the current Bid price level
if(!price)
price=0.0;
//--- reset the error value
ResetLastError();
//--- move a horizontal line
if(!ObjectMove(chart_ID,name,0,0,price))
{
Print(__FUNCTION__,
": failed to move the horizontal line! Error code = ",GetLastError());
return(false);
}
//--- successful execution
return(true);
}
//+------------------------------------------------------------------+
//| Delete a horizontal line |
//+------------------------------------------------------------------+
bool HLineDelete(const long chart_ID=0, // chart's ID
const string name="HLine") // line name
{
//--- reset the error value
ResetLastError();
//--- delete a horizontal line
if(!ObjectDelete(chart_ID,name))
{
Print(__FUNCTION__,
": failed to delete a horizontal line! Error code = ",GetLastError());
return(false);
}
//--- successful execution
return(true);
}
//+------------------------------------------------------------------+
//| Trailing |
//| InpTrailingStop: min distance from price to Stop Loss |
//+------------------------------------------------------------------+
void Trailing(const double stop_level,const ENUM_POSITION_TYPE pos_type,const double price)
{
/*
Buying is done at the Ask price | Selling is done at the Bid price
------------------------------------------------|----------------------------------
TakeProfit >= Bid | TakeProfit <= Ask
StopLoss <= Bid | StopLoss >= Ask
TakeProfit - Bid >= SYMBOL_TRADE_STOPS_LEVEL | Ask - TakeProfit >= SYMBOL_TRADE_STOPS_LEVEL
Bid - StopLoss >= SYMBOL_TRADE_STOPS_LEVEL | StopLoss - Ask >= SYMBOL_TRADE_STOPS_LEVEL
*/
for(int i=PositionsTotal()-1;i>=0;i--) // returns the number of open positions
if(m_position.SelectByIndex(i))
if(m_position.Symbol()==m_symbol.Name() && m_position.PositionType()==pos_type)
{
if(m_position.PositionType()==POSITION_TYPE_BUY)
{
if(price-m_position.PriceCurrent()>=stop_level)
{
if(!m_trade.PositionModify(m_position.Ticket(),
m_position.StopLoss(),
m_symbol.NormalizePrice(price)))
Print("Modify ",m_position.Ticket(),
" Position BUY -> false. Result Retcode: ",m_trade.ResultRetcode(),
", description of result: ",m_trade.ResultRetcodeDescription());
RefreshRates();
m_position.SelectByIndex(i);
PrintResultModify(m_trade,m_symbol,m_position);
continue;
}
}
else
{
if(m_position.PriceCurrent()-price>=stop_level)
{
if(!m_trade.PositionModify(m_position.Ticket(),
m_position.StopLoss(),
m_symbol.NormalizePrice(price)))
Print("Modify ",m_position.Ticket(),
" Position SELL -> false. Result Retcode: ",m_trade.ResultRetcode(),
", description of result: ",m_trade.ResultRetcodeDescription());
RefreshRates();
m_position.SelectByIndex(i);
PrintResultModify(m_trade,m_symbol,m_position);
}
}
}
}
//+------------------------------------------------------------------+
//| Print CTrade result |
//+------------------------------------------------------------------+
void PrintResultModify(CTrade &trade,CSymbolInfo &symbol,CPositionInfo &position)
{
Print("File: ",__FILE__,", symbol: ",symbol.Name());
Print("Code of request result: "+IntegerToString(trade.ResultRetcode()));
Print("code of request result as a string: "+trade.ResultRetcodeDescription());
Print("Deal ticket: "+IntegerToString(trade.ResultDeal()));
Print("Order ticket: "+IntegerToString(trade.ResultOrder()));
Print("Volume of deal or order: "+DoubleToString(trade.ResultVolume(),2));
Print("Price, confirmed by broker: "+DoubleToString(trade.ResultPrice(),symbol.Digits()));
Print("Current bid price: "+DoubleToString(symbol.Bid(),symbol.Digits())+" (the requote): "+DoubleToString(trade.ResultBid(),symbol.Digits()));
Print("Current ask price: "+DoubleToString(symbol.Ask(),symbol.Digits())+" (the requote): "+DoubleToString(trade.ResultAsk(),symbol.Digits()));
Print("Broker comment: "+trade.ResultComment());
Print("Freeze Level: "+DoubleToString(symbol.FreezeLevel(),0),", Stops Level: "+DoubleToString(symbol.StopsLevel(),0));
Print("Price of position opening: "+DoubleToString(position.PriceOpen(),symbol.Digits()));
Print("Price of position's Stop Loss: "+DoubleToString(position.StopLoss(),symbol.Digits()));
Print("Price of position's Take Profit: "+DoubleToString(position.TakeProfit(),symbol.Digits()));
Print("Current price by position: "+DoubleToString(position.PriceCurrent(),symbol.Digits()));
}
//+------------------------------------------------------------------+
Comments