Skip to content

Commit

Permalink
Merge pull request #708 from EA31337/dev-v2013
Browse files Browse the repository at this point in the history
Order fixes for v2.013.1
  • Loading branch information
kenorb authored Aug 12, 2023
2 parents b43f990 + f99f420 commit a723dd7
Show file tree
Hide file tree
Showing 6 changed files with 116 additions and 27 deletions.
15 changes: 14 additions & 1 deletion EA.mqh
Original file line number Diff line number Diff line change
Expand Up @@ -804,8 +804,21 @@ class EA : public Taskable<DataParamEntry> {
* Loads existing trades for the given strategy.
*/
bool StrategyLoadTrades(Strategy *_strat) {
bool _result = true;
Trade *_trade = trade.GetByKey(_Symbol);
return _trade.OrdersLoadByMagic(_strat.Get<long>(STRAT_PARAM_ID));
// Load active trades.
_result &= _trade.OrdersLoadByMagic(_strat.Get<long>(STRAT_PARAM_ID));
// Load strategy-specific order parameters (e.g. conditions).
// This is a temporary workaround for GH-705.
// @todo: To move to Strategy class.
Ref<Order> _order;
for (DictStructIterator<long, Ref<Order>> iter = _trade.GetOrdersActive().Begin(); iter.IsValid(); ++iter) {
_order = iter.Value();
if (_order.IsSet() && _order.Ptr().IsOpen()) {
_strat.OnOrderLoad(_order.Ptr());
}
}
return _result;
}

/* Trade methods */
Expand Down
1 change: 1 addition & 0 deletions Order.enum.h
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ enum ENUM_ORDER_PARAM {
*/
enum ENUM_ORDER_PROPERTY_CUSTOM {
ORDER_PROP_NONE = 0,
ORDER_PROP_CLOSE_TRIES, // Close tries.
ORDER_PROP_COMMISSION, // Commission.
ORDER_PROP_LAST_ERROR, // Last error code.
ORDER_PROP_PRICE_CLOSE, // Close price.
Expand Down
25 changes: 14 additions & 11 deletions Order.mqh
Original file line number Diff line number Diff line change
Expand Up @@ -932,10 +932,11 @@ class Order : public SymbolInfo {
_request.symbol = odata.Get(ORDER_SYMBOL);
_request.type = NegateOrderType(odata.Get<ENUM_ORDER_TYPE>(ORDER_TYPE));
_request.type_filling = GetOrderFilling(odata.Get(ORDER_SYMBOL));
_request.position = oresult.deal;
_request.position = odata.Get<ulong>(ORDER_PROP_TICKET);
_request.price = SymbolInfo::GetCloseOffer(odata.Get<ENUM_ORDER_TYPE>(ORDER_TYPE));
_request.volume = odata.Get<double>(ORDER_VOLUME_CURRENT);
Order::OrderSend(_request, oresult, oresult_check);
odata.IncCloseTries(); // Increases number of closures tries.
switch (oresult.retcode) {
case TRADE_RETCODE_DONE:
// For now, sets the current time.
Expand All @@ -952,18 +953,19 @@ class Order : public SymbolInfo {
// break;
case TRADE_RETCODE_INVALID:
default:
odata.Set<unsigned int>(ORDER_PROP_LAST_ERROR, fmax(oresult.retcode, oresult_check.retcode));
if (OrderSelect()) {
Refresh(true);
if (!IsClosed()) {
ologger.Error(StringFormat("Failed to send order request %d! Error: %d (%s)", oresult.deal,
oresult_check.retcode, oresult_check.comment),
__FUNCTION_LINE__);
if (logger.GetLevel() >= V_DEBUG) {
ologger.Error(
StringFormat("Failed to send order request %u for position %d! Error: %d (%s)", oresult.request_id,
_request.position, fmax(oresult.retcode, oresult_check.retcode), oresult_check.comment),
__FUNCTION_LINE__);
if (ologger.GetLevel() >= V_DEBUG) {
ologger.Debug(StringFormat("Failed request: %s", ToString()), __FUNCTION_LINE__);
}
}
}
odata.Set<unsigned int>(ORDER_PROP_LAST_ERROR, fmax(oresult.retcode, oresult_check.retcode));
}
return false;
}
Expand All @@ -975,6 +977,7 @@ class Order : public SymbolInfo {
* Returns true if successful.
*/
bool OrderCloseDummy(ENUM_ORDER_REASON_CLOSE _reason = ORDER_REASON_CLOSED_UNKNOWN, string _comment = "") {
odata.IncCloseTries(); // Increases number of closures tries.
odata.Set(ORDER_PROP_LAST_ERROR, ERR_NO_ERROR);
odata.Set(ORDER_PROP_PRICE_CLOSE, SymbolInfoStatic::GetCloseOffer(symbol, odata.Get<ENUM_ORDER_TYPE>(ORDER_TYPE)));
odata.Set(ORDER_PROP_REASON_CLOSE, _reason);
Expand Down Expand Up @@ -1177,9 +1180,9 @@ class Order : public SymbolInfo {
}
static bool OrderSend(const MqlTradeRequest &_request, MqlTradeResult &_result, MqlTradeCheckResult &_result_check,
color _color = clrNONE) {
_result.retcode = TRADE_RETCODE_ERROR;
#ifdef __MQL4__
// Convert Trade Request Structure to function parameters.
_result.retcode = TRADE_RETCODE_ERROR;
if (_request.position > 0) {
if (_request.action == TRADE_ACTION_SLTP) {
if (Order::OrderModify(_request.position, _request.price, _request.sl, _request.tp, _request.expiration,
Expand Down Expand Up @@ -1288,6 +1291,8 @@ class Order : public SymbolInfo {
long OrderSend() {
long _result = -1;
odata.ResetError();
oresult.retcode = ERR_NO_ERROR;
oresult_check.retcode = ERR_NO_ERROR;
#ifdef __MQL4__
_result = Order::OrderSend(orequest.symbol, // Symbol.
orequest.type, // Operation.
Expand Down Expand Up @@ -2606,14 +2611,12 @@ class Order : public SymbolInfo {
*/
bool ProcessConditions(bool _refresh = false) {
bool _result = true;
if (IsOpen(_refresh) && ShouldCloseOrder()) {
#ifdef __MQL__
// _reason += StringFormat(": %s", EnumToString(oparams.cond_close));
#endif
if (IsOpen(_refresh) && (odata.Get<long>(ORDER_PROP_CLOSE_TRIES) > 0 || ShouldCloseOrder())) {
ARRAY(DataParamEntry, _args);
DataParamEntry _cond = ORDER_REASON_CLOSED_BY_CONDITION;
ArrayPushObject(_args, _cond);
_result &= Order::ExecuteAction(ORDER_ACTION_CLOSE, _args);
odata.IncCloseTries();
}
return _result;
}
Expand Down
12 changes: 11 additions & 1 deletion Order.struct.h
Original file line number Diff line number Diff line change
Expand Up @@ -254,6 +254,7 @@ struct OrderData {
ENUM_ORDER_TYPE_TIME type_time; // Lifetime (the order validity period).
ENUM_ORDER_REASON reason; // Reason or source for placing an order.
ENUM_ORDER_REASON_CLOSE reason_close; // Reason or source for closing an order.
unsigned int close_tries; // Number of close tries.
unsigned int last_error; // Last error code.
double volume_curr; // Current volume.
double volume_init; // Initial volume.
Expand All @@ -262,7 +263,8 @@ struct OrderData {
string symbol; // Symbol of the order.
public:
OrderData()
: magic(0),
: close_tries(0),
magic(0),
position_id(0),
position_by_id(0),
ticket(0),
Expand Down Expand Up @@ -296,6 +298,8 @@ struct OrderData {
T Get(ENUM_ORDER_PROPERTY_CUSTOM _prop_name) {
double _tick_value = SymbolInfoStatic::GetTickValue(symbol);
switch (_prop_name) {
case ORDER_PROP_CLOSE_TRIES:
return (T)close_tries;
case ORDER_PROP_COMMISSION:
return (T)commission;
case ORDER_PROP_LAST_ERROR:
Expand Down Expand Up @@ -498,9 +502,15 @@ struct OrderData {
return "???";
}
// Setters.
void IncCloseTries() {
close_tries++;
}
template <typename T>
void Set(ENUM_ORDER_PROPERTY_CUSTOM _prop_name, T _value) {
switch (_prop_name) {
case ORDER_PROP_CLOSE_TRIES:
close_tries = (unsigned int)_value;
return;
case ORDER_PROP_COMMISSION:
commission = (double)_value;
return;
Expand Down
43 changes: 43 additions & 0 deletions Strategy.mqh
Original file line number Diff line number Diff line change
Expand Up @@ -670,6 +670,49 @@ class Strategy : public Taskable<DataParamEntry> {
// trade.SetStrategy(&this); // @fixme
// Sets strategy's trade spread limit.
trade.Set<float>(TRADE_PARAM_MAX_SPREAD, sparams.Get<float>(STRAT_PARAM_MAX_SPREAD));
// Load active trades.
if (Get<long>(STRAT_PARAM_ID) > 0) {
trade.OrdersLoadByMagic(Get<long>(STRAT_PARAM_ID));
}
Ref<Order> _order;
for (DictStructIterator<long, Ref<Order>> iter = trade.GetOrdersActive().Begin(); iter.IsValid(); ++iter) {
_order = iter.Value();
if (_order.IsSet() && _order.Ptr().IsOpen()) {
Strategy::OnOrderLoad(_order.Ptr());
}
}
}

/**
* Event on strategy's order load.
*
* @param
* _oparams Order parameters to update.
*/
virtual void OnOrderLoad(Order *_order) {
int _index = 0;
ENUM_TIMEFRAMES _stf = Get<ENUM_TIMEFRAMES>(STRAT_PARAM_TF);
unsigned int _stf_secs = ChartTf::TfToSeconds(_stf);
if (sparams.order_close_time != 0) {
long _close_time_arg = sparams.order_close_time > 0 ? sparams.order_close_time * 60
: (int)round(-sparams.order_close_time * _stf_secs);
_order.Set(ORDER_PARAM_COND_CLOSE, ORDER_COND_LIFETIME_GT_ARG, _index);
_order.Set(ORDER_PARAM_COND_CLOSE_ARG_VALUE, _close_time_arg, _index);
_index++;
}
if (sparams.order_close_loss != 0.0f) {
float _loss_limit = sparams.order_close_loss;
_order.Set(ORDER_PARAM_COND_CLOSE, ORDER_COND_IN_LOSS, _index);
_order.Set(ORDER_PARAM_COND_CLOSE_ARG_VALUE, _loss_limit, _index);
_index++;
}
if (sparams.order_close_profit != 0.0f) {
float _profit_limit = sparams.order_close_profit;
_order.Set(ORDER_PARAM_COND_CLOSE, ORDER_COND_IN_PROFIT, _index);
_order.Set(ORDER_PARAM_COND_CLOSE_ARG_VALUE, _profit_limit, _index);
_index++;
}
_order.Set(ORDER_PARAM_UPDATE_FREQ, _stf_secs);
}

/**
Expand Down
47 changes: 33 additions & 14 deletions Trade.mqh
Original file line number Diff line number Diff line change
Expand Up @@ -651,6 +651,7 @@ HistorySelect(0, TimeCurrent()); // Select history for access.
bool _result = false;
unsigned int _last_error = _order.Get<unsigned int>(ORDER_PROP_LAST_ERROR);
logger.Link(_order.GetLogger());
_order.GetLogger().SetLevel(tparams.Get<ENUM_LOG_LEVEL>(TRADE_PARAM_LOG_LEVEL));
Ref<Order> _ref_order = _order;
switch (_last_error) {
case 69539:
Expand Down Expand Up @@ -800,6 +801,8 @@ HistorySelect(0, TimeCurrent()); // Select history for access.
if (_order.IsOpen()) {
// @todo: _order.IsPending()?
_result &= orders_active.Set(_order.Get<long>(ORDER_PROP_TICKET), _order_ref);
logger.Link(_order.GetLogger());
_order.GetLogger().SetLevel(tparams.Get<ENUM_LOG_LEVEL>(TRADE_PARAM_LOG_LEVEL));
} else {
_result &= orders_history.Set(_order.Get<long>(ORDER_PROP_TICKET), _order_ref);
}
Expand All @@ -817,7 +820,7 @@ HistorySelect(0, TimeCurrent()); // Select history for access.
if (OrderStatic::MagicNumber() == _magic_no) {
unsigned long _ticket = OrderStatic::Ticket();
Ref<Order> _order = new Order(_ticket);
orders_active.Set(_ticket, _order);
OrderLoad(_order.Ptr());
}
}
}
Expand Down Expand Up @@ -862,13 +865,18 @@ HistorySelect(0, TimeCurrent()); // Select history for access.
OrderMoveToHistory(_order.Ptr());
order_last = _order;
} else {
logger.AddLastError(__FUNCTION_LINE__, _order.Ptr().Get<unsigned long>(ORDER_PROP_LAST_ERROR));
return -1;
logger.Error(
StringFormat("Failed to close the order: %d! Error: %d (%s)", _order.Ptr().Get<long>(ORDER_PROP_TICKET),
_order.Ptr().Get<unsigned int>(ORDER_PROP_LAST_ERROR),
Terminal::GetErrorText(_order.Ptr().Get<unsigned int>(ORDER_PROP_LAST_ERROR))),
__FUNCTION_LINE__);
continue;
}
} else {
OrderMoveToHistory(_order.Ptr());
}
}
logger.Flush();
return _closed;
}

Expand All @@ -894,16 +902,20 @@ HistorySelect(0, TimeCurrent()); // Select history for access.
OrderMoveToHistory(_order.Ptr());
order_last = _order;
} else {
logger.Error("Error while closing order!", __FUNCTION_LINE__,
StringFormat("Code: %d", _order.Ptr().Get<unsigned long>(ORDER_PROP_LAST_ERROR)));
return -1;
logger.Error(
StringFormat("Failed to close the order: %d! Error: %d (%s)", _order.Ptr().Get<long>(ORDER_PROP_TICKET),
_order.Ptr().Get<unsigned int>(ORDER_PROP_LAST_ERROR),
Terminal::GetErrorText(_order.Ptr().Get<unsigned int>(ORDER_PROP_LAST_ERROR))),
__FUNCTION_LINE__);
continue;
}
order_last = _order;
}
} else {
OrderMoveToHistory(_order.Ptr());
}
}
logger.Flush();
return _closed;
}

Expand Down Expand Up @@ -932,14 +944,19 @@ HistorySelect(0, TimeCurrent()); // Select history for access.
OrderMoveToHistory(_order.Ptr());
order_last = _order;
} else {
logger.AddLastError(__FUNCTION_LINE__, _order.Ptr().Get<unsigned long>(ORDER_PROP_LAST_ERROR));
return -1;
logger.Error(
StringFormat("Failed to close the order: %d! Error: %d (%s)", _order.Ptr().Get<long>(ORDER_PROP_TICKET),
_order.Ptr().Get<unsigned int>(ORDER_PROP_LAST_ERROR),
Terminal::GetErrorText(_order.Ptr().Get<unsigned int>(ORDER_PROP_LAST_ERROR))),
__FUNCTION_LINE__);
continue;
}
}
} else {
OrderMoveToHistory(_order.Ptr());
}
}
logger.Flush();
return _closed;
}

Expand All @@ -966,14 +983,15 @@ HistorySelect(0, TimeCurrent()); // Select history for access.
Math::Compare(_order.Ptr().Get<T>((E)_prop2), _value2, _op)) {
if (!_order.Ptr().OrderClose(_reason, _comment)) {
#ifndef __MQL4__
// @fixme: GH-571.
// @fixme: GH-571 & GH-706.
logger.Info(__FUNCTION_LINE__, _order.Ptr().ToString());
#endif
// @fixme: GH-570.
// logger.AddLastError(__FUNCTION_LINE__, _order.Ptr().Get<unsigned int>(ORDER_PROP_LAST_ERROR));
logger.Warning("Issue with closing the order!", __FUNCTION_LINE__);
ResetLastError();
return -1;
logger.Error(
StringFormat("Failed to close the order: %d! Error: %d (%s)", _order.Ptr().Get<long>(ORDER_PROP_TICKET),
_order.Ptr().Get<unsigned int>(ORDER_PROP_LAST_ERROR),
Terminal::GetErrorText(_order.Ptr().Get<unsigned int>(ORDER_PROP_LAST_ERROR))),
__FUNCTION_LINE__);
continue;
}
order_last = _order;
_closed++;
Expand All @@ -982,6 +1000,7 @@ HistorySelect(0, TimeCurrent()); // Select history for access.
OrderMoveToHistory(_order.Ptr());
}
}
logger.Flush();
return _closed;
}

Expand Down

0 comments on commit a723dd7

Please sign in to comment.