801 lines
No EOL
42 KiB
MQL5
801 lines
No EOL
42 KiB
MQL5
#ifndef ORDER_MQH
|
|
#define ORDER_MQH
|
|
#property strict
|
|
|
|
#include "String.mqh"
|
|
|
|
#define ORDER_COMMISSION (0)
|
|
//#define ORDER_COMMISSION (-5)
|
|
|
|
#ifdef __MQL5__
|
|
#ifndef TICKET_TYPE
|
|
#define TICKET_TYPE long
|
|
#endif // TICKET_TYPE
|
|
|
|
#ifndef MAGIC_TYPE
|
|
#define MAGIC_TYPE long
|
|
#endif // MAGIC_TYPE
|
|
|
|
#ifndef OP_SELL
|
|
#define OP_SELL ORDER_TYPE_SELL
|
|
#endif // OP_SELL
|
|
#else // __MQL5__
|
|
#ifndef TICKET_TYPE
|
|
#define TICKET_TYPE int
|
|
#endif // TICKET_TYPE
|
|
|
|
#ifndef MAGIC_TYPE
|
|
#define MAGIC_TYPE int
|
|
#endif // MAGIC_TYPE
|
|
|
|
// https://www.mql5.com/ru/docs/constants/tradingconstants/dealproperties#enum_deal_reason
|
|
enum ENUM_DEAL_REASON
|
|
{
|
|
DEAL_REASON_CLIENT,
|
|
DEAL_REASON_MOBILE,
|
|
DEAL_REASON_WEB,
|
|
DEAL_REASON_EXPERT,
|
|
DEAL_REASON_SL,
|
|
DEAL_REASON_TP,
|
|
DEAL_REASON_SO,
|
|
DEAL_REASON_ROLLOVER,
|
|
DEAL_REASON_VMARGIN,
|
|
DEAL_REASON_SPLIT
|
|
};
|
|
|
|
#endif // __MQL5__
|
|
|
|
#ifndef OP_BALANCE
|
|
#define OP_BALANCE 6
|
|
#endif // OP_BALANCE
|
|
|
|
struct ORDER
|
|
{
|
|
private:
|
|
static TICKET_TYPE TicketCount;
|
|
|
|
TICKET_TYPE Ticket;
|
|
ENUM_ORDER_TYPE Type;
|
|
|
|
double Lots;
|
|
|
|
string oSymbol;
|
|
string comment;
|
|
|
|
double OpenPrice;
|
|
|
|
long OpenTimeMsc;
|
|
|
|
double StopLoss;
|
|
double TakeProfit;
|
|
|
|
double ClosePrice;
|
|
|
|
long CloseTimeMsc;
|
|
|
|
// datetime Expiration;
|
|
|
|
long MagicNumber;
|
|
|
|
double Profit;
|
|
|
|
// double Commission;
|
|
// double Swap;
|
|
|
|
ENUM_DEAL_REASON OpenReason;
|
|
ENUM_DEAL_REASON CloseReason;
|
|
|
|
double OpenPriceRequest;
|
|
double ClosePriceRequest;
|
|
|
|
static int PriceToPips( const double Price, const double point )
|
|
{
|
|
return(point ? ((int)(Price / point + 0.1)) : 0);
|
|
}
|
|
|
|
static int ProfitToPips( const double PriceClose, const double PriceOpen, const double point )
|
|
{
|
|
return(ORDER::PriceToPips(PriceClose, point) - ORDER::PriceToPips(PriceOpen , point));
|
|
}
|
|
|
|
static string LengthToString( const datetime Length )
|
|
{
|
|
const int Days = (int)(Length / (24 * 3600));
|
|
|
|
return(((Days) ? (string)Days + "d ": "") + ::TimeToString(Length, TIME_SECONDS));
|
|
}
|
|
|
|
template <typename T>
|
|
string NumToString( T Num, const bool CheckType = true, const int digits = 2 ) const // Report.mqh
|
|
{
|
|
if (CheckType && (this.OrderType() == OP_SELL))
|
|
Num = -Num;
|
|
|
|
return(((Num > 0) ? "+" : "") + ((typename(T) == "double") ? ::DoubleToString(Num, digits) : (string)Num));
|
|
}
|
|
|
|
TICKET_TYPE GetNewTicket( void ) const
|
|
{
|
|
return(++ORDER::TicketCount);
|
|
}
|
|
|
|
bool Reset( void )
|
|
{
|
|
this.StopLoss = -1; // Чтобы при создании ордера сработало условие (this.StopLoss != SL) в Check.
|
|
|
|
return(true);
|
|
}
|
|
|
|
bool Check( double &Price, double &SL, double &TP, const MqlTick &Tick ) const
|
|
{
|
|
bool Res = false;
|
|
|
|
if (SL)
|
|
SL = ::NormalizeDouble(SL, _Digits);
|
|
|
|
if (TP)
|
|
TP = ::NormalizeDouble(TP, _Digits);
|
|
|
|
switch (this.Type)
|
|
{
|
|
case ORDER_TYPE_BUY:
|
|
Res = ((this.StopLoss != SL) || (this.TakeProfit != TP)) &&
|
|
(SL >= 0) && (SL <= Tick.bid) &&
|
|
((!TP) || (TP >= Tick.bid));
|
|
|
|
break;
|
|
|
|
case ORDER_TYPE_SELL:
|
|
Res = ((this.StopLoss != SL) || (this.TakeProfit != TP)) &&
|
|
(TP >= 0) && (TP <= Tick.ask) &&
|
|
(!SL || (SL >= Tick.ask));
|
|
|
|
break;
|
|
|
|
case ORDER_TYPE_BUY_LIMIT:
|
|
/*
|
|
if (TimeCurrent() >= D'2019.01.11 11:50:58')
|
|
DebugBreak();
|
|
*/
|
|
Price = ::NormalizeDouble(Price, _Digits);
|
|
/*
|
|
#ifdef BESTINTERVAL_ONTESTER
|
|
if (Price == Tick.ask) // Для применения BestInterval пока нельзя выставлять лимитник по текущей цене.
|
|
Price = Tick.ask - _Point;
|
|
#endif // BESTINTERVAL_ONTESTER
|
|
*/
|
|
Res = ((this.OpenPrice != Price) || (this.StopLoss != SL) || (this.TakeProfit != TP)) &&
|
|
(Price > 0) && (Price <= Tick.ask) &&
|
|
(SL >= 0) && (SL <= Price) &&
|
|
(!TP || (TP >= Price));
|
|
|
|
break;
|
|
|
|
case ORDER_TYPE_SELL_LIMIT:
|
|
Price = ::NormalizeDouble(Price, _Digits);
|
|
/*
|
|
#ifdef BESTINTERVAL_ONTESTER
|
|
if (Price == Tick.bid) // Для применения BestInterval пока нельзя выставлять лимитник по текущей цене.
|
|
Price = Tick.bid + _Point;
|
|
#endif // BESTINTERVAL_ONTESTER
|
|
*/
|
|
Res = ((this.OpenPrice != Price) || (this.StopLoss != SL) || (this.TakeProfit != TP)) &&
|
|
(Price >= Tick.bid) &&
|
|
(TP >= 0) && (TP <= Price) &&
|
|
(!SL || (SL >= Price));
|
|
|
|
break;
|
|
|
|
case ORDER_TYPE_BUY_STOP:
|
|
Price = ::NormalizeDouble(Price, _Digits);
|
|
|
|
Res = ((this.OpenPrice != Price) || (this.StopLoss != SL) || (this.TakeProfit != TP)) &&
|
|
(Price >= Tick.ask) &&
|
|
(SL >= 0) && (SL <= Price) &&
|
|
(!TP || (TP >= Price));
|
|
|
|
break;
|
|
|
|
case ORDER_TYPE_SELL_STOP:
|
|
Price = ::NormalizeDouble(Price, _Digits);
|
|
|
|
Res = ((this.OpenPrice != Price) || (this.StopLoss != SL) || (this.TakeProfit != TP)) &&
|
|
(Price > 0) && (Price <= Tick.bid) &&
|
|
(TP >= 0) && (TP <= Price) &&
|
|
(!SL || (SL >= Price));
|
|
;
|
|
}
|
|
|
|
return(Res);
|
|
}
|
|
|
|
void ToClose( const MqlTick &Tick )
|
|
{
|
|
if (!this.IsClosed())
|
|
{
|
|
this.Ticket = -this.Ticket;
|
|
|
|
this.CloseTimeMsc = Tick.time_msc;
|
|
|
|
if (this.IsPosition())
|
|
this.Profit = this.GetProfit();
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
void ToNull( void )
|
|
{
|
|
this.Ticket = 0;
|
|
this.Profit = 0;
|
|
|
|
return;
|
|
}
|
|
|
|
double GetClosePrice( const MqlTick &Tick ) const
|
|
{
|
|
double Price = this.ClosePrice;
|
|
|
|
if (!this.IsClosed())
|
|
switch (this.Type)
|
|
{
|
|
case ORDER_TYPE_BUY:
|
|
case ORDER_TYPE_SELL_LIMIT:
|
|
case ORDER_TYPE_SELL_STOP:
|
|
Price = Tick.bid;
|
|
|
|
break;
|
|
case ORDER_TYPE_SELL:
|
|
case ORDER_TYPE_BUY_LIMIT:
|
|
case ORDER_TYPE_BUY_STOP:
|
|
Price = Tick.ask;
|
|
}
|
|
|
|
return(Price);
|
|
}
|
|
|
|
double GetProfit( void ) const
|
|
{
|
|
return((this.Type == ORDER_TYPE_BUY) ? this.Lots * (this.ClosePrice - this.OpenPrice) / _Point
|
|
: ((this.Type == ORDER_TYPE_SELL) ? this.Lots * (this.OpenPrice - this.ClosePrice) / _Point : 0));
|
|
}
|
|
|
|
static void CloseBy( ORDER &Order1, ORDER &Order2, const MqlTick &Tick )
|
|
{
|
|
Order2.ClosePrice = Order1.OpenPrice;
|
|
|
|
Order2.CloseReason = Order2.OpenReason;
|
|
Order2.ClosePriceRequest = Order1.OpenPriceRequest;
|
|
|
|
Order2.ToClose(Tick);
|
|
|
|
Order1.Lots = ::NormalizeDouble(Order1.Lots - Order2.Lots, 2);
|
|
Order1.Profit = Order1.GetProfit();
|
|
|
|
return;
|
|
}
|
|
|
|
public:
|
|
bool IsPosition( void ) const
|
|
{
|
|
return(this.Type <= ORDER_TYPE_SELL);
|
|
}
|
|
|
|
bool Modify( double Price, double SL, double TP, const MqlTick &Tick )
|
|
{
|
|
const bool Res = this.Check(Price, SL, TP, Tick);
|
|
|
|
if (Res)
|
|
{
|
|
this.TakeProfit = TP;
|
|
this.StopLoss = SL;
|
|
|
|
if (!this.IsPosition())
|
|
{
|
|
this.OpenPrice = Price;
|
|
|
|
this.OpenPriceRequest = this.OpenPrice;
|
|
}
|
|
}
|
|
|
|
return(Res);
|
|
}
|
|
|
|
bool IsClosed( void ) const
|
|
{
|
|
return(this.Ticket <= 0);
|
|
}
|
|
|
|
bool IsNotNull( void ) const
|
|
{
|
|
return((bool)this.Ticket);
|
|
}
|
|
|
|
bool IsChange( const MqlTick &Tick )
|
|
{
|
|
bool Res = false;
|
|
const ENUM_ORDER_TYPE PrevType = this.Type;
|
|
|
|
if (!this.IsClosed())
|
|
{
|
|
switch (this.Type)
|
|
{
|
|
case ORDER_TYPE_BUY:
|
|
if (Tick.bid <= this.StopLoss)
|
|
{
|
|
this.CloseReason = DEAL_REASON_SL;
|
|
this.ClosePriceRequest = this.StopLoss;
|
|
|
|
this.ClosePrice = Tick.bid;
|
|
|
|
Res = true;
|
|
}
|
|
else if (TakeProfit && (Tick.bid >= this.TakeProfit))
|
|
{
|
|
this.CloseReason = DEAL_REASON_TP;
|
|
this.ClosePriceRequest = this.TakeProfit;
|
|
|
|
#ifdef VIRTUAL_LIMITS_TP_SLIPPAGE
|
|
this.ClosePrice = Tick.bid;
|
|
#else // VIRTUAL_LIMITS_TP_SLIPPAGE
|
|
this.ClosePrice = this.TakeProfit;
|
|
#endif // VIRTUAL_LIMITS_TP_SLIPPAGE
|
|
|
|
Res = true;
|
|
}
|
|
|
|
break;
|
|
|
|
case ORDER_TYPE_SELL:
|
|
if (this.StopLoss && Tick.ask >= this.StopLoss)
|
|
{
|
|
this.CloseReason = DEAL_REASON_SL;
|
|
this.ClosePriceRequest = this.StopLoss;
|
|
|
|
this.ClosePrice = Tick.ask;
|
|
|
|
Res = true;
|
|
}
|
|
else if (Tick.ask <= this.TakeProfit)
|
|
{
|
|
this.CloseReason = DEAL_REASON_TP;
|
|
this.ClosePriceRequest = this.TakeProfit;
|
|
|
|
#ifdef VIRTUAL_LIMITS_TP_SLIPPAGE
|
|
this.ClosePrice = Tick.ask;
|
|
#else // VIRTUAL_LIMITS_TP_SLIPPAGE
|
|
this.ClosePrice = this.TakeProfit;
|
|
#endif // VIRTUAL_LIMITS_TP_SLIPPAGE
|
|
|
|
Res = true;
|
|
}
|
|
|
|
break;
|
|
|
|
case ORDER_TYPE_BUY_LIMIT:
|
|
if (Res = (Tick.ask <= this.OpenPrice))
|
|
{
|
|
this.Type = ORDER_TYPE_BUY;
|
|
|
|
#ifdef VIRTUAL_LIMITS_TP_SLIPPAGE
|
|
this.OpenPrice = Tick.ask;
|
|
#endif // VIRTUAL_LIMITS_TP_SLIPPAGE
|
|
}
|
|
|
|
break;
|
|
|
|
case ORDER_TYPE_SELL_LIMIT:
|
|
if (Res = (Tick.bid >= this.OpenPrice))
|
|
{
|
|
this.Type = ORDER_TYPE_SELL;
|
|
|
|
#ifdef VIRTUAL_LIMITS_TP_SLIPPAGE
|
|
this.OpenPrice = Tick.bid;
|
|
#endif // VIRTUAL_LIMITS_TP_SLIPPAGE
|
|
}
|
|
|
|
break;
|
|
|
|
case ORDER_TYPE_BUY_STOP:
|
|
if (Res = (Tick.ask >= this.OpenPrice))
|
|
{
|
|
this.Type = ORDER_TYPE_BUY;
|
|
|
|
this.OpenPrice = Tick.ask;
|
|
}
|
|
|
|
break;
|
|
|
|
case ORDER_TYPE_SELL_STOP:
|
|
if (Res = (Tick.bid <= this.OpenPrice))
|
|
{
|
|
this.Type = ORDER_TYPE_SELL;
|
|
|
|
this.OpenPrice = Tick.bid;
|
|
}
|
|
}
|
|
|
|
if (Res)
|
|
{
|
|
if (this.Type == PrevType)
|
|
this.ToClose(Tick);
|
|
else
|
|
{
|
|
this.OpenTimeMsc = Tick.time_msc;
|
|
|
|
this.ClosePrice = this.GetClosePrice(Tick);
|
|
|
|
this.Profit = this.GetProfit();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
this.ClosePrice = this.GetClosePrice(Tick);
|
|
|
|
this.Profit = this.GetProfit();
|
|
}
|
|
|
|
}
|
|
|
|
return(Res);
|
|
}
|
|
|
|
bool Delete( const MqlTick &Tick )
|
|
{
|
|
const bool Res = !this.IsPosition();
|
|
|
|
if (Res)
|
|
{
|
|
this.ClosePrice = this.GetClosePrice(Tick);
|
|
this.CloseReason = this.OpenReason;
|
|
|
|
this.ToClose(Tick);
|
|
}
|
|
|
|
return(Res);
|
|
}
|
|
|
|
bool Create( const ENUM_ORDER_TYPE inType, double dLots, double inPrice, double inSL, double inTP,
|
|
const MAGIC_TYPE &iMagicNumber, const string &sComment, const MqlTick &Tick )
|
|
{
|
|
this.Lots = ::NormalizeDouble(dLots, 2);
|
|
this.Type = inType;
|
|
|
|
const bool Res = (this.Lots > 0) && this.Reset() && this.Check(inPrice, inSL, inTP, Tick);
|
|
|
|
if (Res)
|
|
{
|
|
this.Ticket = this.GetNewTicket();
|
|
|
|
this.OpenPrice = (this.Type == ORDER_TYPE_BUY) ? Tick.ask : ((this.Type == ORDER_TYPE_SELL) ? Tick.bid : inPrice);
|
|
this.OpenTimeMsc = Tick.time_msc;
|
|
|
|
this.StopLoss = inSL;
|
|
this.TakeProfit = inTP;
|
|
|
|
this.MagicNumber = iMagicNumber;
|
|
|
|
this.ClosePrice = this.GetClosePrice(Tick);
|
|
this.Profit = this.GetProfit();
|
|
|
|
this.CloseTimeMsc = 0;
|
|
|
|
this.comment = sComment;
|
|
|
|
this.OpenReason = DEAL_REASON_EXPERT;
|
|
this.CloseReason = DEAL_REASON_CLIENT;
|
|
|
|
this.OpenPriceRequest = this.OpenPrice;
|
|
// this.ClosePriceRequest = this.ClosePrice;
|
|
}
|
|
|
|
return(Res);
|
|
}
|
|
|
|
void Deposit( const double dDeposit, const MqlTick &Tick )
|
|
{
|
|
this.Ticket = this.GetNewTicket();
|
|
this.Type = OP_BALANCE;
|
|
|
|
this.Lots = 0;
|
|
|
|
// this.Symbol = NULL;
|
|
const string Str = NULL;
|
|
this.comment = Str;
|
|
|
|
this.OpenPrice = 0;
|
|
|
|
this.OpenTimeMsc = Tick.time_msc;
|
|
|
|
this.StopLoss = 0;
|
|
this.TakeProfit = 0;
|
|
|
|
this.ClosePrice = this.OpenPrice;
|
|
|
|
// this.Expiration = 0;
|
|
|
|
this.MagicNumber = 0;
|
|
|
|
this.Profit = dDeposit;
|
|
|
|
// this.Commission = 0;
|
|
// this.Swap = 0;
|
|
|
|
this.OpenReason = DEAL_REASON_CLIENT;
|
|
this.CloseReason = this.OpenReason;
|
|
|
|
this.OpenPriceRequest = this.OpenPrice;
|
|
this.ClosePriceRequest = this.OpenPriceRequest;
|
|
|
|
this.ToClose(Tick);
|
|
|
|
return;
|
|
}
|
|
|
|
static void CloseByNetting( ORDER &Order1, ORDER &Order2, const MqlTick &Tick )
|
|
{
|
|
Order1.ClosePrice = Order2.OpenPrice;
|
|
Order1.CloseReason = Order2.OpenReason;
|
|
|
|
Order1.ClosePriceRequest = Order2.OpenPriceRequest;
|
|
|
|
Order1.ToClose(Tick);
|
|
|
|
Order2.ToNull();
|
|
|
|
return;
|
|
}
|
|
|
|
bool CloseBy( ORDER &Order, const MqlTick &Tick, const bool Netting = false )
|
|
{
|
|
const bool Res = (this.Ticket != Order.Ticket) && (this.Type == ORDER_TYPE_SELL - Order.Type) && !this.IsClosed() && !Order.IsClosed();
|
|
|
|
if (Res)
|
|
{
|
|
if (this.Lots == Order.Lots)
|
|
{
|
|
if (!Netting)
|
|
{
|
|
this.ClosePrice = Order.OpenPrice;
|
|
this.CloseReason = this.OpenReason;
|
|
|
|
this.ClosePriceRequest = Order.OpenPriceRequest;
|
|
|
|
this.ToClose(Tick);
|
|
|
|
Order.ClosePrice = Order.OpenPrice;
|
|
Order.CloseReason = Order.OpenReason;
|
|
|
|
Order.OpenPriceRequest = Order.OpenPrice;
|
|
Order.ClosePriceRequest = Order.ClosePrice;
|
|
|
|
Order.ToClose(Tick);
|
|
}
|
|
else if (this.OpenTimeMsc <= Order.OpenTimeMsc)
|
|
ORDER::CloseByNetting(this, Order, Tick);
|
|
else
|
|
ORDER::CloseByNetting(Order, this, Tick);
|
|
}
|
|
else if (this.Lots > Order.Lots)
|
|
ORDER::CloseBy(this, Order, Tick);
|
|
else
|
|
ORDER::CloseBy(Order, this, Tick);
|
|
}
|
|
|
|
return(Res);
|
|
}
|
|
|
|
double Close( double dLots, const MqlTick &Tick )
|
|
{
|
|
double Res = 0;
|
|
|
|
if (this.IsPosition() && !this.IsClosed())
|
|
{
|
|
dLots = ::NormalizeDouble(dLots, 2);
|
|
|
|
if ((dLots > 0) && (dLots <= this.Lots))
|
|
{
|
|
Res = this.Lots - dLots;
|
|
|
|
this.Lots = dLots;
|
|
|
|
this.CloseReason = this.OpenReason;
|
|
this.ClosePriceRequest = this.ClosePrice;
|
|
|
|
this.ToClose(Tick);
|
|
}
|
|
}
|
|
|
|
return(Res);
|
|
}
|
|
|
|
void SetLots( const double dLots )
|
|
{
|
|
this.Ticket = this.GetNewTicket();
|
|
|
|
this.Lots = ::NormalizeDouble(dLots, _Digits);
|
|
|
|
this.CloseTimeMsc = 0;
|
|
this.Profit = this.GetProfit();
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
#define ORDERFUNCTION(NAME,T) \
|
|
T Order##NAME( void ) const \
|
|
{ \
|
|
return((T)this.NAME); \
|
|
}
|
|
|
|
ORDERFUNCTION(Ticket, TICKET_TYPE)
|
|
ORDERFUNCTION(Type, int)
|
|
ORDERFUNCTION(Lots, double)
|
|
ORDERFUNCTION(OpenPrice, double)
|
|
ORDERFUNCTION(OpenTimeMsc, long)
|
|
ORDERFUNCTION(StopLoss, double)
|
|
ORDERFUNCTION(TakeProfit, double)
|
|
ORDERFUNCTION(ClosePrice, double)
|
|
ORDERFUNCTION(CloseTimeMsc, long)
|
|
ORDERFUNCTION(MagicNumber, MAGIC_TYPE)
|
|
ORDERFUNCTION(Profit, double)
|
|
ORDERFUNCTION(OpenReason, ENUM_DEAL_REASON)
|
|
ORDERFUNCTION(CloseReason, ENUM_DEAL_REASON)
|
|
ORDERFUNCTION(OpenPriceRequest, double)
|
|
|
|
#undef ORDERFUNCTION
|
|
|
|
datetime OrderOpenTime( void ) const
|
|
{
|
|
return((datetime)(this.OpenTimeMsc / 1000));
|
|
}
|
|
|
|
datetime OrderCloseTime( void ) const
|
|
{
|
|
return((datetime)(this.CloseTimeMsc / 1000));
|
|
}
|
|
|
|
datetime OrderExpiration( void ) const
|
|
{
|
|
return(0);
|
|
}
|
|
|
|
double OrderCommission( void ) const
|
|
{
|
|
return(this.Lots * ORDER_COMMISSION);
|
|
}
|
|
|
|
double OrderSwap( void ) const
|
|
{
|
|
return(0);
|
|
}
|
|
|
|
string OrderSymbol( void ) const
|
|
{
|
|
return(_Symbol);
|
|
}
|
|
|
|
string OrderComment( void ) const
|
|
{
|
|
return(this.comment);
|
|
}
|
|
|
|
void OrderPrint( const datetime timeCurrent ) const
|
|
{
|
|
::Print(this.ToString(timeCurrent));
|
|
}
|
|
|
|
double OrderClosePriceRequest( void ) const
|
|
{
|
|
return(this.IsClosed() ? this.ClosePriceRequest : this.OrderClosePrice());
|
|
}
|
|
|
|
string ToString( const datetime tTimeCurrent ) const
|
|
{
|
|
static const string Types[] = {"buy", "sell", "buy limit", "sell limit", "buy stop", "sell stop", "balance"};
|
|
|
|
return(("#" + (string)this.OrderTicket() + " " +
|
|
(string)this.OrderOpenTime() + "." + ::IntegerToString(this.OrderOpenTimeMsc() % 1000, 3, '0') + " " +
|
|
((this.Type < ::ArraySize(Types)) ? Types[this.Type] : "unknown") + " " +
|
|
::DoubleToString(this.OrderLots(), 2) + " " +
|
|
this.OrderSymbol() + " " +
|
|
::DoubleToString(this.OrderOpenPrice(), _Digits) + " " +
|
|
::DoubleToString(this.OrderStopLoss(), _Digits) + " " +
|
|
::DoubleToString(this.OrderTakeProfit(), _Digits) + " " +
|
|
((this.OrderCloseTime() > 0) ? ((string)this.OrderCloseTime() + "." + ::IntegerToString(this.OrderCloseTimeMsc() % 1000, 3, '0') + " ") : NULL) +
|
|
::DoubleToString(this.OrderClosePrice(), _Digits) + " " +
|
|
::DoubleToString(this.OrderCommission(), 2) + " " +
|
|
::DoubleToString(this.OrderSwap(), 2) + " " +
|
|
::DoubleToString(this.OrderProfit(), 2) + " " +
|
|
((this.OrderComment() == "") ? NULL : (this.OrderComment() + " ")) +
|
|
(string)this.OrderMagicNumber() +
|
|
(((this.OrderExpiration() > 0) ? (" expiration " + (string)this.OrderExpiration()): NULL))) +
|
|
((this.OrderType() <= OP_SELL) ? ": " + this.NumToString(ORDER::ProfitToPips(this.OrderClosePrice(), this.OrderOpenPrice(), _Point)) +
|
|
" (" + this.NumToString(ORDER::ProfitToPips(this.OrderClosePriceRequest(), this.OrderOpenPriceRequest(), _Point)) + ")" : NULL) +
|
|
" - " + ORDER::LengthToString((this.OrderCloseTime() ? this.OrderCloseTime() : tTimeCurrent) - this.OrderOpenTime()));
|
|
}
|
|
|
|
string ToStringCSV( const string delim = "\t") const
|
|
{
|
|
static const string Types[] = {"buy", "sell", "buy limit", "sell limit", "buy stop", "sell stop", "balance"};
|
|
|
|
return((string)this.OrderTicket() + delim +
|
|
(string)this.OrderOpenTime() + delim +
|
|
IntegerToString(this.Type) + delim +
|
|
::DoubleToString(this.OrderLots(), 2) + delim +
|
|
this.OrderSymbol() + delim +
|
|
::DoubleToString(this.OrderOpenPrice(), _Digits) + delim +
|
|
::DoubleToString(this.OrderStopLoss(), _Digits) + delim +
|
|
::DoubleToString(this.OrderTakeProfit(), _Digits) + delim +
|
|
((this.OrderCloseTime() > 0) ? ((string)this.OrderCloseTime() + delim) : delim) +
|
|
::DoubleToString(this.OrderClosePrice(), _Digits) + delim +
|
|
::DoubleToString(this.OrderCommission(), 2) + delim +
|
|
::DoubleToString(this.OrderSwap(), 2) + delim +
|
|
::DoubleToString(this.OrderProfit(), 2) + delim +
|
|
((this.OrderComment() == "") ? delim : (this.OrderComment() + delim)) +
|
|
(string)this.OrderMagicNumber() + delim +
|
|
((this.OrderExpiration() > 0) ? ((string)this.OrderExpiration() + delim): delim) + "\r\n");
|
|
|
|
}
|
|
|
|
int ToFileCSV(const int fHandle) const
|
|
{
|
|
return((int)FileWrite(fHandle,this.OrderTicket(),
|
|
this.OrderOpenTime(),
|
|
this.Type,
|
|
::DoubleToString(this.OrderLots(), 2),
|
|
this.OrderSymbol(),
|
|
::DoubleToString(this.OrderOpenPrice(), _Digits),
|
|
::DoubleToString(this.OrderStopLoss(), _Digits),
|
|
::DoubleToString(this.OrderTakeProfit(), _Digits),
|
|
this.OrderCloseTime(),
|
|
::DoubleToString(this.OrderClosePrice(), _Digits),
|
|
//::DoubleToString(this.OrderCommission(), 2),
|
|
//::DoubleToString(this.OrderSwap(), 2),
|
|
//::DoubleToString(this.OrderProfit(), 2),
|
|
this.OrderComment(),
|
|
this.OrderMagicNumber()));
|
|
//this.OrderExpiration()));
|
|
}
|
|
|
|
bool FromFileCSV(const int fHandle)
|
|
{
|
|
this.Ticket = (TICKET_TYPE) FileReadNumber(fHandle);
|
|
this.OpenTimeMsc = 1000 * FileReadDatetime(fHandle);
|
|
this.Type = (ENUM_ORDER_TYPE)FileReadNumber(fHandle);
|
|
this.Lots = FileReadNumber(fHandle);
|
|
this.oSymbol = FileReadString(fHandle);
|
|
this.OpenPrice = FileReadNumber(fHandle);
|
|
this.StopLoss = FileReadNumber(fHandle);
|
|
this.TakeProfit = FileReadNumber(fHandle);
|
|
this.CloseTimeMsc = FileReadDatetime(fHandle);
|
|
this.ClosePrice = FileReadNumber(fHandle);
|
|
//this.Commission = FileReadNumber(fHandle);
|
|
//this.Swap = FileReadNumber(fHandle);
|
|
//this.OrderProfit = FileReadNumber(fHandle);
|
|
this.comment = FileReadString(fHandle);
|
|
this.MagicNumber = (MAGIC_TYPE)FileReadNumber(fHandle);
|
|
//this.Expiration = FileReadDatetime(fHandle);
|
|
if(!FileIsLineEnding(fHandle))
|
|
return false;
|
|
if (this.TicketCount < this.Ticket)
|
|
this.TicketCount = this.OrderTicket();
|
|
return true;
|
|
}
|
|
|
|
void Stop( const MqlTick &Tick )
|
|
{
|
|
if (!this.Delete(Tick) && !this.Close(this.Lots, Tick))
|
|
{
|
|
const string Str = "end of test";
|
|
|
|
this.comment = Str;
|
|
}
|
|
|
|
return;
|
|
}
|
|
};
|
|
|
|
static TICKET_TYPE ORDER::TicketCount = 0; // https://www.mql5.com/ru/forum/1111/page2302#comment_8891928
|
|
|
|
#endif //ORDER_MQH |