666 lines
No EOL
35 KiB
MQL5
666 lines
No EOL
35 KiB
MQL5
// https://www.mql5.com/ru/forum/1111/page2336#comment_9660624
|
|
// Нужно для BestInterval
|
|
// #define TICKS_CORRECT_TIME // время тиков, кратное секунде, будет скорректировано на миллисекунду вперед
|
|
#ifndef ORDERS_MQH
|
|
#define ORDERS_MQH
|
|
#include "Order.mqh"
|
|
|
|
#ifdef __MQL5__
|
|
#ifndef SELECT_BY_POS
|
|
#define SELECT_BY_POS 0
|
|
#endif // SELECT_BY_POS
|
|
|
|
#ifndef SELECT_BY_TICKET
|
|
#define SELECT_BY_TICKET 1
|
|
#endif // SELECT_BY_TICKET
|
|
|
|
#ifndef MODE_TRADES
|
|
#define MODE_TRADES 0
|
|
#endif // MODE_TRADES
|
|
|
|
#ifndef MODE_HISTORY
|
|
#define MODE_HISTORY 1
|
|
#endif // MODE_HISTORY
|
|
|
|
#ifndef OP_SELL
|
|
#define OP_SELL ORDER_TYPE_SELL
|
|
#endif // OP_SELL
|
|
#endif // __MQL5__
|
|
|
|
#define MAX_ORDERS 100
|
|
#define RESERVE_HISTORY_ORDERS 2000
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
//class OrderCallBack
|
|
//{
|
|
//public:
|
|
// virtual void OnSuccess(TICKET_TYPE result, ORDER *order)
|
|
// {
|
|
// Print("Order success. Result: ",(string)result,order.ToString(TimeCurrent()));
|
|
// }
|
|
// virtual void OnFailure(TICKET_TYPE result, ORDER *order)
|
|
// {
|
|
// Print("Order failure. Result: ", (string)result, order.ToString(TimeCurrent()));
|
|
// }
|
|
// virtual void OnTimeout(TICKET_TYPE result, ORDER *order)
|
|
// {
|
|
// Print("Order timeout. Result: ", (string)result, order.ToString(TimeCurrent()));
|
|
// }
|
|
//};
|
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
|
|
class ORDERS
|
|
{
|
|
private:
|
|
bool Netting;
|
|
double Balance;
|
|
double Equity;
|
|
|
|
ORDER Orders[MAX_ORDERS];
|
|
int AmountOrders;
|
|
MqlTick CurrentTick;
|
|
|
|
int SelectIndex;
|
|
ORDER SelectOrder;
|
|
|
|
ORDER HistoryOrders[];
|
|
int AmountHistoryOrders;
|
|
int ReserveHistoryOrders;
|
|
|
|
//OrderCallBack *pCallBack;
|
|
|
|
static string GetTickFlag( uint tickflag )
|
|
{
|
|
string flag = " " + (string)tickflag;
|
|
|
|
#define TICKFLAG_MACRO(A) flag += ((bool)(tickflag & TICK_FLAG_##A)) ? " TICK_FLAG_" + #A : ""; \
|
|
tickflag -= tickflag & TICK_FLAG_##A;
|
|
TICKFLAG_MACRO(BID)
|
|
TICKFLAG_MACRO(ASK)
|
|
TICKFLAG_MACRO(LAST)
|
|
TICKFLAG_MACRO(VOLUME)
|
|
TICKFLAG_MACRO(BUY)
|
|
TICKFLAG_MACRO(SELL)
|
|
#undef TICKFLAG_MACRO
|
|
|
|
if (tickflag)
|
|
flag += " FLAG_UNKNOWN (" + (string)tickflag + ")";
|
|
|
|
return(flag);
|
|
}
|
|
|
|
#define TOSTR(A) " " + #A + " = " + (string)Tick.A
|
|
#define TOSTR2(A) " " + #A + " = " + ::DoubleToString(Tick.A, _Digits)
|
|
|
|
static string TickToString( const MqlTick &Tick )
|
|
{
|
|
return(TOSTR(time) + "." + ::IntegerToString(Tick.time_msc % 1000, 3, '0') +
|
|
TOSTR2(bid) + TOSTR2(ask) + TOSTR2(last)+ TOSTR(volume) + ORDERS::GetTickFlag(Tick.flags));
|
|
}
|
|
|
|
#undef TOSTR2
|
|
#undef TOSTR
|
|
|
|
void AddHistoryOrder( const ORDER &Order )
|
|
{
|
|
if (this.AmountHistoryOrders == this.ReserveHistoryOrders)
|
|
this.ReserveHistoryOrders = ::ArrayResize(this.HistoryOrders, this.ReserveHistoryOrders + RESERVE_HISTORY_ORDERS);
|
|
|
|
if (Order.IsNotNull())
|
|
this.HistoryOrders[this.AmountHistoryOrders++] = Order;
|
|
|
|
return;
|
|
}
|
|
|
|
bool IsChange( void )
|
|
{
|
|
bool Res = false;
|
|
double Profit = 0;
|
|
int j = 0;
|
|
|
|
for (int i = 0; i < this.AmountOrders; i++)
|
|
{
|
|
Res |= this.Orders[i].IsChange(this.CurrentTick) && !this.Orders[i].IsClosed();
|
|
|
|
if (this.Orders[i].IsClosed())
|
|
{
|
|
this.Balance += this.Orders[i].OrderProfit();
|
|
|
|
this.AddHistoryOrder(this.Orders[i]);
|
|
}
|
|
else
|
|
{
|
|
Profit += this.Orders[i].OrderProfit();
|
|
|
|
if (i != j)
|
|
this.Orders[j] = this.Orders[i];
|
|
|
|
j++;
|
|
}
|
|
}
|
|
|
|
this.AmountOrders = j;
|
|
|
|
this.Equity = this.Balance + Profit;
|
|
|
|
return(Res);
|
|
}
|
|
|
|
void CloseBy( void )
|
|
{
|
|
int j = -1;
|
|
|
|
for (int i = 0; i < this.AmountOrders; i++)
|
|
if (!this.Orders[i].IsClosed() && this.Orders[i].IsPosition())
|
|
{
|
|
if (j < 0)
|
|
j = i;
|
|
else if (this.Orders[j].CloseBy(this.Orders[i], this.CurrentTick, this.Netting) && this.Orders[j].IsClosed())
|
|
{
|
|
i = j;
|
|
|
|
j = -1;
|
|
}
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
void Check( void )
|
|
{
|
|
while (this.IsChange())
|
|
if (this.Netting)
|
|
this.CloseBy();
|
|
|
|
return;
|
|
}
|
|
|
|
int GetIndex( const long &Ticket ) const
|
|
{
|
|
int Res = -1;
|
|
|
|
if (this.SelectIndex < this.AmountOrders)
|
|
{
|
|
if (this.Orders[this.SelectIndex].OrderTicket() == Ticket)
|
|
Res = this.SelectIndex;
|
|
else
|
|
for (int i = 0; i < this.AmountOrders; i++)
|
|
if (this.Orders[i].OrderTicket() == Ticket)
|
|
{
|
|
Res = i;
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
return(Res);
|
|
}
|
|
|
|
bool SelectByPos( const int Index )
|
|
{
|
|
const bool Res = (Index >= 0) && (Index < this.AmountOrders);
|
|
|
|
if (Res)
|
|
{
|
|
this.SelectIndex = Index;
|
|
|
|
this.SelectOrder = this.Orders[this.SelectIndex];
|
|
}
|
|
|
|
return(Res);
|
|
}
|
|
|
|
bool SelectByTicket( const long Ticket, const long Pool )
|
|
{
|
|
const int Index = this.GetIndex(Ticket);
|
|
const bool Res = (Index >= 0);
|
|
|
|
if (Res)
|
|
{
|
|
this.SelectIndex = Index;
|
|
|
|
this.SelectOrder = this.Orders[this.SelectIndex];
|
|
}
|
|
|
|
return(Res);
|
|
|
|
}
|
|
|
|
bool SelectByPosHistory( const int Index )
|
|
{
|
|
const bool Res = (Index >= 0) && (Index < this.AmountHistoryOrders);
|
|
|
|
if (Res)
|
|
this.SelectOrder = this.HistoryOrders[Index];
|
|
|
|
return(Res);
|
|
}
|
|
|
|
public:
|
|
const int Handle;
|
|
|
|
ORDERS( const int iHandle, const datetime StartTime = 0 ) : Handle(iHandle), AmountOrders(0), SelectIndex(0), AmountHistoryOrders(0), ReserveHistoryOrders(0)
|
|
{
|
|
MqlTick Tick = {0};
|
|
|
|
Tick.time_msc = (long)StartTime * 1000;
|
|
|
|
this.NewTick(Tick);
|
|
|
|
//pCallBack = NULL;
|
|
}
|
|
|
|
void Set( const double dBalance = 0, const bool bNetting = false )
|
|
{
|
|
this.Balance = (dBalance > 0) ? dBalance : ::AccountInfoDouble(ACCOUNT_BALANCE);
|
|
this.Equity = this.Balance;
|
|
this.Netting = (dBalance > 0) ? bNetting :
|
|
#ifdef __MQL5__
|
|
!((ENUM_ACCOUNT_MARGIN_MODE)::AccountInfoInteger(ACCOUNT_MARGIN_MODE) == ACCOUNT_MARGIN_MODE_RETAIL_HEDGING)
|
|
#else // __MQL5__
|
|
bNetting
|
|
#endif //__MQL5__
|
|
;
|
|
|
|
this.AmountOrders = 0;
|
|
this.SelectIndex = 0;
|
|
|
|
this.AmountHistoryOrders = 0;
|
|
this.ReserveHistoryOrders = 0; // ::ArrayResize(this.HistoryOrders, RESERVE_HISTORY_ORDERS);
|
|
|
|
this.OrderDeposit(this.Balance);
|
|
|
|
return;
|
|
}
|
|
|
|
bool IsNetting( void ) const
|
|
{
|
|
return(this.Netting);
|
|
}
|
|
|
|
void NewTick( const MqlTick &Tick )
|
|
{
|
|
this.CurrentTick = Tick;
|
|
|
|
#ifdef TICKS_CORRECT_TIME
|
|
if (!(this.CurrentTick.time_msc % 1000))
|
|
this.CurrentTick.time_msc++;
|
|
#endif // TICKS_CORRECT_TIME
|
|
|
|
this.Check();
|
|
|
|
return;
|
|
}
|
|
|
|
void OrderDeposit( const double Deposit )
|
|
{
|
|
if (Deposit)
|
|
{
|
|
ORDER Order;
|
|
|
|
Order.Deposit(Deposit, this.CurrentTick);
|
|
|
|
this.AddHistoryOrder(Order);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
TICKET_TYPE OrderSend( const string&, const int &Type, const double dVolume, const double Price, const int &SlipPage, const double SL, const double TP,
|
|
const string &comment, const MAGIC_TYPE &magic, const datetime &dExpiration )
|
|
{
|
|
TICKET_TYPE Res = -1;
|
|
|
|
if (this.Orders[this.AmountOrders].Create((ENUM_ORDER_TYPE)Type, dVolume, Price, SL, TP, magic, comment, this.CurrentTick))
|
|
{
|
|
Res = this.Orders[this.AmountOrders].OrderTicket();
|
|
|
|
if (this.Orders[this.AmountOrders++].IsPosition())
|
|
{
|
|
if (Netting)
|
|
this.CloseBy();
|
|
|
|
this.IsChange();
|
|
}
|
|
else
|
|
this.Check();
|
|
}
|
|
|
|
//if (pCallBack != INVALID_HANDLE)
|
|
// if (Res > 0)
|
|
// pCallBack.OnSuccess(Res, this.Orders[this.AmountOrders]);
|
|
//if (Res < 0)
|
|
// pCallBack.OnFailure(Res,
|
|
|
|
return(Res);
|
|
}
|
|
|
|
void Stop( void )
|
|
{
|
|
for (int i = 0; i < this.AmountOrders; i++)
|
|
this.Orders[i].Stop(this.CurrentTick);
|
|
|
|
this.IsChange();
|
|
|
|
// Здесь можно ужать массив истории торгов для экономии памяти.
|
|
|
|
return;
|
|
}
|
|
|
|
bool OrderSelect( const long Index, const int Select, const int Pool = MODE_TRADES )
|
|
{
|
|
return((Select == SELECT_BY_POS) ?
|
|
((Pool == MODE_TRADES) ? this.SelectByPos((int)Index) : this.SelectByPosHistory((int)Index)) :
|
|
this.SelectByTicket(Index, Pool));
|
|
}
|
|
|
|
bool OrderClose( const long Ticket, const double dLots, const double Price )
|
|
{
|
|
bool Res = false;
|
|
const int Pos = this.GetIndex(Ticket);
|
|
|
|
if (Pos >= 0)
|
|
{
|
|
const double LeftLots = this.Orders[Pos].Close(dLots, this.CurrentTick);
|
|
|
|
Res = this.Orders[Pos].IsClosed();
|
|
|
|
if (Res)
|
|
{
|
|
if (LeftLots)
|
|
{
|
|
this.Orders[this.AmountOrders] = this.Orders[Pos];
|
|
|
|
this.Orders[this.AmountOrders++].SetLots(LeftLots);
|
|
}
|
|
|
|
this.IsChange();
|
|
}
|
|
}
|
|
//if (pCallBack != INVALID_HANDLE)
|
|
// if (Res > 0)
|
|
// pCallBack.OnSuccess(Res, this.Orders[this.AmountOrders]);
|
|
|
|
return(Res);
|
|
}
|
|
|
|
bool OrderModify( const long Ticket, const double Price, const double SL, const double TP, const datetime Expiration = 0 )
|
|
{
|
|
const int Pos = this.GetIndex(Ticket);
|
|
const bool Res = (Pos >= 0) ? this.Orders[Pos].Modify(Price, SL, TP, this.CurrentTick) : false;
|
|
|
|
if (Res)
|
|
this.Check();
|
|
|
|
return(Res);
|
|
}
|
|
|
|
bool OrderCloseBy( const long Ticket, const long Opposite )
|
|
{
|
|
bool Res = false;
|
|
const int Pos1 = (Ticket != Opposite) ? this.GetIndex(Ticket) : -1;
|
|
|
|
if (Pos1 >= 0)
|
|
{
|
|
const int Pos2 = this.GetIndex(Opposite);
|
|
|
|
if (Pos2 >= 0)
|
|
{
|
|
Res = this.Orders[Pos1].CloseBy(this.Orders[Pos2], this.CurrentTick);
|
|
|
|
if (Res)
|
|
this.IsChange();
|
|
}
|
|
}
|
|
|
|
return(Res);
|
|
}
|
|
|
|
bool OrderDelete( const long Ticket )
|
|
{
|
|
bool Res = false;
|
|
const int Pos = this.GetIndex(Ticket);
|
|
|
|
if (Pos >= 0)
|
|
{
|
|
Res = this.Orders[Pos].Delete(this.CurrentTick);
|
|
|
|
if (Res)
|
|
this.IsChange();
|
|
}
|
|
|
|
return(Res);
|
|
}
|
|
|
|
int OrdersTotal2( void ) const // 2 - MT4Orders
|
|
{
|
|
return(this.AmountOrders);
|
|
}
|
|
|
|
int OrdersHistoryTotal( void ) const
|
|
{
|
|
return(this.AmountHistoryOrders);
|
|
}
|
|
|
|
#define ORDERFUNCTION(NAME,T) \
|
|
T Order##NAME( void ) const \
|
|
{ \
|
|
return(this.SelectOrder.Order##NAME()); \
|
|
}
|
|
|
|
ORDERFUNCTION(Ticket, TICKET_TYPE)
|
|
ORDERFUNCTION(Type, int)
|
|
ORDERFUNCTION(Lots, double)
|
|
ORDERFUNCTION(OpenPrice, double)
|
|
ORDERFUNCTION(OpenTimeMsc, long)
|
|
ORDERFUNCTION(OpenTime, datetime)
|
|
ORDERFUNCTION(StopLoss, double)
|
|
ORDERFUNCTION(TakeProfit, double)
|
|
ORDERFUNCTION(ClosePrice, double)
|
|
ORDERFUNCTION(CloseTimeMsc, long)
|
|
ORDERFUNCTION(CloseTime, datetime)
|
|
ORDERFUNCTION(Expiration, datetime)
|
|
ORDERFUNCTION(MagicNumber, MAGIC_TYPE)
|
|
ORDERFUNCTION(Profit, double)
|
|
ORDERFUNCTION(Commission, double)
|
|
ORDERFUNCTION(Swap, double)
|
|
ORDERFUNCTION(Symbol, string)
|
|
ORDERFUNCTION(Comment, string)
|
|
ORDERFUNCTION(OpenPriceRequest, double)
|
|
ORDERFUNCTION(ClosePriceRequest, double)
|
|
ORDERFUNCTION(OpenReason, ENUM_DEAL_REASON)
|
|
ORDERFUNCTION(CloseReason, ENUM_DEAL_REASON)
|
|
|
|
#undef ORDERFUNCTION
|
|
|
|
void OrderPrint( void ) const
|
|
{
|
|
this.SelectOrder.OrderPrint(this.CurrentTick.time);
|
|
|
|
return;
|
|
}
|
|
|
|
double AccountBalance( void ) const
|
|
{
|
|
return(::NormalizeDouble(this.Balance, 2));
|
|
}
|
|
|
|
double AccountEquity( void ) const
|
|
{
|
|
return(::NormalizeDouble(this.Equity, 2));
|
|
}
|
|
|
|
double AccountProfit( void ) const
|
|
{
|
|
return(::NormalizeDouble(this.Equity - this.Balance, 2));
|
|
}
|
|
|
|
datetime TimeCurrent( void ) const
|
|
{
|
|
return(this.CurrentTick.time);
|
|
}
|
|
|
|
datetime TimeCurrent( MqlDateTime &StructTime ) const
|
|
{
|
|
::TimeToStruct(this.CurrentTick.time, StructTime);
|
|
|
|
return(this.CurrentTick.time);
|
|
}
|
|
|
|
bool SymbolInfoTick( const string, MqlTick &Tick ) const
|
|
{
|
|
Tick = this.CurrentTick;
|
|
|
|
return(true);
|
|
}
|
|
|
|
double SymbolInfoDouble( const string Symb, const ENUM_SYMBOL_INFO_DOUBLE Property ) const
|
|
{
|
|
return((Property == SYMBOL_BID) ? this.CurrentTick.bid
|
|
: ((Property == SYMBOL_ASK) ? this.CurrentTick.ask : ::SymbolInfoDouble(Symb, Property)));
|
|
}
|
|
|
|
bool SymbolInfoDouble( const string Symb, const ENUM_SYMBOL_INFO_DOUBLE Property, double &Value ) const
|
|
{
|
|
const bool Res = (Property == SYMBOL_BID) || (Property == SYMBOL_ASK);
|
|
|
|
if (Res)
|
|
{
|
|
if (Property == SYMBOL_BID)
|
|
Value = this.CurrentTick.bid;
|
|
else
|
|
Value = this.CurrentTick.ask;
|
|
}
|
|
|
|
return(Res ? true : ::SymbolInfoDouble(Symb, Property, Value));
|
|
}
|
|
|
|
long SymbolInfoInteger( const string Symb, const ENUM_SYMBOL_INFO_INTEGER Property ) const
|
|
{
|
|
return((Property == SYMBOL_TIME) ? this.CurrentTick.time
|
|
: ((Property == SYMBOL_SPREAD) ? (long)((this.CurrentTick.ask - this.CurrentTick.bid) / _Point + 0.1) : ::SymbolInfoInteger(Symb, Property)));
|
|
}
|
|
|
|
long SymbolInfoInteger( const string Symb, const ENUM_SYMBOL_INFO_INTEGER Property, long &Value ) const
|
|
{
|
|
const bool Res = (Property == SYMBOL_TIME) || (Property == SYMBOL_SPREAD);
|
|
|
|
if (Res)
|
|
{
|
|
if (Property == SYMBOL_TIME)
|
|
Value = this.CurrentTick.time;
|
|
else
|
|
Value = (long)((this.CurrentTick.ask - this.CurrentTick.bid) / _Point + 0.1);
|
|
}
|
|
|
|
return(Res ? true : ::SymbolInfoInteger(Symb, Property, Value));
|
|
}
|
|
|
|
long AccountInfoInteger( const ENUM_ACCOUNT_INFO_INTEGER Property ) const
|
|
{
|
|
#ifdef __MQL5__
|
|
return((Property == ACCOUNT_MARGIN_MODE) ? (this.Netting ? ACCOUNT_MARGIN_MODE_RETAIL_NETTING : ACCOUNT_MARGIN_MODE_RETAIL_HEDGING) : ::AccountInfoInteger(Property));
|
|
#else // __MQL5__
|
|
return(::AccountInfoInteger(Property));
|
|
#endif // __MQL5__
|
|
}
|
|
|
|
double AccountInfoDouble( const ENUM_ACCOUNT_INFO_DOUBLE Property ) const
|
|
{
|
|
double Res;
|
|
|
|
switch (Property)
|
|
{
|
|
case ACCOUNT_BALANCE:
|
|
Res = this.AccountBalance();
|
|
|
|
break;
|
|
case ACCOUNT_PROFIT:
|
|
Res = this.AccountProfit();
|
|
|
|
break;
|
|
case ACCOUNT_EQUITY:
|
|
Res = this.AccountEquity();
|
|
|
|
break;
|
|
case ACCOUNT_MARGIN:
|
|
Res = 0;
|
|
|
|
break;
|
|
default:
|
|
Res = ::AccountInfoDouble(Property);
|
|
}
|
|
|
|
return(Res);
|
|
}
|
|
|
|
string ToString( int LastHistoryOrders = 0, const bool Pending = true ) const
|
|
{
|
|
string Str = ORDERS::TickToString(this.CurrentTick) + "\n\n";
|
|
|
|
for (int i = 0; i < this.AmountOrders; i++)
|
|
Str += this.Orders[i].ToString(this.CurrentTick.time) + "\n";
|
|
|
|
Str += "\nBalance = " + ::DoubleToString(this.Balance, 2) +
|
|
", Equity = " + ::DoubleToString(this.Equity, 2) +
|
|
(this.AmountHistoryOrders && (this.HistoryOrders[0].OrderType() == OP_BALANCE)
|
|
? ", Profit = " + ::DoubleToString(this.Equity - this.HistoryOrders[0].OrderProfit(), 2) : NULL) +
|
|
(this.AmountHistoryOrders ? ", " + ::TimeToString(this.HistoryOrders[0].OrderOpenTime(), TIME_DATE) + " - " + (string)this.TimeCurrent() : NULL);
|
|
|
|
if (LastHistoryOrders > 0)
|
|
for (int i = this.AmountHistoryOrders - 1; (i >= 0) && LastHistoryOrders; i--)
|
|
if (Pending || (this.HistoryOrders[i].OrderType() <= OP_SELL) || (this.HistoryOrders[i].OrderType() == OP_BALANCE))
|
|
{
|
|
Str += "\n" + this.HistoryOrders[i].ToString(this.CurrentTick.time);
|
|
|
|
LastHistoryOrders--;
|
|
}
|
|
|
|
return(Str);
|
|
}
|
|
|
|
int ToFileCSV(const string fName = "orders\\orders.csv")
|
|
{
|
|
int fHandle = FileOpen(fName,FILE_WRITE|FILE_SHARE_WRITE|FILE_SHARE_READ|FILE_CSV,'\t',CP_UTF8);
|
|
if(fHandle == INVALID_HANDLE){
|
|
PrintFormat("Операция FileOpen неудачна, ошибка %s",GetLastError());
|
|
return -1;
|
|
}
|
|
for( int i = 0; i < this.AmountOrders; i++)
|
|
{
|
|
this.Orders[i].ToFileCSV(fHandle);
|
|
}
|
|
FileClose(fHandle);
|
|
return this.AmountOrders;
|
|
}
|
|
|
|
int FromFileCSV(const string fName = "orders\\orders.csv")
|
|
{
|
|
int fHandle = FileOpen(fName, FILE_SHARE_READ|FILE_READ|FILE_CSV,'\t',CP_UTF8);
|
|
if(fHandle == INVALID_HANDLE){
|
|
PrintFormat("Операция FileOpen неудачна, ошибка %s",GetLastError());
|
|
return -1;
|
|
}
|
|
this.AmountOrders = 0;
|
|
while( FileIsEnding(fHandle) )
|
|
{
|
|
if (this.Orders[this.AmountOrders].FromFileCSV(fHandle))
|
|
{
|
|
PrintFormat("Операция From FileCSV неудачна, ошибка %s",GetLastError());
|
|
break;
|
|
}
|
|
this.AmountOrders++;
|
|
}
|
|
FileClose(fHandle);
|
|
return this.AmountOrders;
|
|
}
|
|
};
|
|
|
|
#undef RESERVE_HISTORY_ORDERS
|
|
#undef MAX_ORDERS
|
|
#endif //ORDERS_MQH |