Skip to content

Commit

Permalink
Merge pull request #517 from EA31337/dev
Browse files Browse the repository at this point in the history
Improves actions, orders and tasks processing
  • Loading branch information
kenorb authored Jul 29, 2021
2 parents 8007307 + 9506493 commit 138cf93
Show file tree
Hide file tree
Showing 10 changed files with 91 additions and 36 deletions.
8 changes: 4 additions & 4 deletions Account.mqh
Original file line number Diff line number Diff line change
Expand Up @@ -553,19 +553,19 @@ class Account {
case ACCOUNT_COND_EQUITY_01PC_HIGH:
return AccountEquity() > (AccountBalance() + AccountCredit()) / 100 * 101;
case ACCOUNT_COND_EQUITY_01PC_LOW:
return AccountEquity() > (AccountBalance() + AccountCredit()) / 100 * 99;
return AccountEquity() < (AccountBalance() + AccountCredit()) / 100 * 99;
case ACCOUNT_COND_EQUITY_05PC_HIGH:
return AccountEquity() > (AccountBalance() + AccountCredit()) / 100 * 105;
case ACCOUNT_COND_EQUITY_05PC_LOW:
return AccountEquity() > (AccountBalance() + AccountCredit()) / 100 * 95;
return AccountEquity() < (AccountBalance() + AccountCredit()) / 100 * 95;
case ACCOUNT_COND_EQUITY_10PC_HIGH:
return AccountEquity() > (AccountBalance() + AccountCredit()) / 100 * 110;
case ACCOUNT_COND_EQUITY_10PC_LOW:
return AccountEquity() > (AccountBalance() + AccountCredit()) / 100 * 90;
return AccountEquity() < (AccountBalance() + AccountCredit()) / 100 * 90;
case ACCOUNT_COND_EQUITY_20PC_HIGH:
return AccountEquity() > (AccountBalance() + AccountCredit()) / 100 * 120;
case ACCOUNT_COND_EQUITY_20PC_LOW:
return AccountEquity() > (AccountBalance() + AccountCredit()) / 100 * 80;
return AccountEquity() < (AccountBalance() + AccountCredit()) / 100 * 80;
case ACCOUNT_COND_EQUITY_IN_LOSS:
return GetEquity() < GetTotalBalance();
case ACCOUNT_COND_EQUITY_IN_PROFIT:
Expand Down
2 changes: 1 addition & 1 deletion Action.struct.h
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ struct ActionEntry {
bool IsInvalid() { return HasFlag(ACTION_ENTRY_FLAG_IS_INVALID); }
bool IsValid() { return !IsInvalid(); }
// Getters.
long GetId() { return action_id; }
ENUM_ACTION_TYPE GetType() { return type; }
// Setter methods.
void AddArg(MqlParam &_arg) {
Expand All @@ -101,7 +102,6 @@ struct ActionEntry {
// @todo: for().
}
void SetObject(void *_obj) {
Object::Delete(obj);
obj = _obj;
}
void SetTries(short _count) { tries = _count; }
Expand Down
4 changes: 2 additions & 2 deletions Chart.mqh
Original file line number Diff line number Diff line change
Expand Up @@ -112,8 +112,8 @@ class Chart : public Market {
/**
* Class constructor.
*/
Chart(ChartParams &_cparams, string _symbol = NULL)
: cparams(_cparams), Market(_symbol), last_bar_time(GetBarTime()), tick_index(-1), bar_index(-1) {
Chart(ChartParams &_cparams)
: cparams(_cparams), Market(_cparams.symbol), last_bar_time(GetBarTime()), tick_index(-1), bar_index(-1) {
// Save the first BarOHLC values.
SaveChartEntry();
cparams.Set(CHART_PARAM_ID, ChartStatic::ID());
Expand Down
2 changes: 1 addition & 1 deletion Condition.struct.h
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ struct ConditionEntry {
bool IsInvalid() { return HasFlag(COND_ENTRY_FLAG_IS_INVALID); }
bool IsValid() { return !IsInvalid(); }
// Getters.
long GetId() { return cond_id; }
ENUM_CONDITION_TYPE GetType() { return type; }
// Setters.
void AddArg(MqlParam &_arg) {
Expand All @@ -105,7 +106,6 @@ struct ConditionEntry {
// @todo: for().
}
void SetObject(void *_obj) {
Object::Delete(obj);
obj = _obj;
}
void SetTries(short _count) { tries = _count; }
Expand Down
32 changes: 31 additions & 1 deletion EA.mqh
Original file line number Diff line number Diff line change
Expand Up @@ -527,7 +527,37 @@ class EA {
for (DictStructIterator<short, TaskEntry> iter = tasks.Begin(); iter.IsValid(); ++iter) {
bool _is_processed = false;
TaskEntry _entry = iter.Value();
_is_processed = Task::Process(_entry);
switch (_entry.GetConditionType()) {
case COND_TYPE_ACCOUNT:
_entry.SetConditionObject(account);
break;
case COND_TYPE_EA:
_entry.SetConditionObject(THIS_PTR);
break;
case COND_TYPE_TRADE:
// Not supported (yet).
// _entry.SetConditionObject(trade);
break;
}
switch (_entry.GetActionType()) {
case ACTION_TYPE_EA:
_entry.SetActionObject(THIS_PTR);
break;
case ACTION_TYPE_TRADE:
if (Condition::Test(_entry.GetCondition())) {
for (DictObjectIterator<ENUM_TIMEFRAMES, DictStruct<long, Ref<Strategy>>> iter_tf = strats.Begin();
iter_tf.IsValid(); ++iter_tf) {
ENUM_TIMEFRAMES _tf = iter_tf.Key();
for (DictStructIterator<long, Ref<Strategy>> iter_strat = strats[_tf].Begin(); iter_strat.IsValid();
++iter_strat) {
Strategy *_strat = iter_strat.Value().Ptr();
_is_processed |= _strat.ExecuteAction(STRAT_ACTION_TRADE_EXE, _entry.GetActionId());
}
}
}
break;
}
_is_processed = _is_processed || Task::Process(_entry);
_counter += (unsigned short)_is_processed;
}
return _counter;
Expand Down
47 changes: 24 additions & 23 deletions Order.mqh
Original file line number Diff line number Diff line change
Expand Up @@ -1226,7 +1226,7 @@ class Order : public SymbolInfo {
return Order::OrderSend(_request, _result, _result_check);
}
long OrderSend() {
long _result = false;
long _result = -1;
odata.ResetError();
#ifdef __MQL4__
_result = Order::OrderSend(orequest.symbol, // Symbol.
Expand All @@ -1246,36 +1246,35 @@ class Order : public SymbolInfo {
orequest.type_filling = orequest.type_filling ? orequest.type_filling : GetOrderFilling(orequest.symbol);
// The trade requests go through several stages of checking on a trade server.
// First of all, it checks if all the required fields of the request parameter are filled out correctly.
if (!OrderCheck(orequest, oresult_check)) {
// If funds are not enough for the operation,
// or parameters are filled out incorrectly, the function returns false.
// In order to obtain information about the error, call the GetLastError() function.
// @see: https://www.mql5.com/en/docs/trading/ordercheck
odata.last_error = oresult_check.retcode;
_result = -1;
} else {
if (OrderCheck(orequest, oresult_check)) {
// If there are no errors, the server accepts the order for further processing.
// The check results are placed to the fields of the MqlTradeCheckResult structure.
// For a more detailed description of the function execution result,
// analyze the fields of the result structure.
// In order to obtain information about the error, call the GetLastError() function.
}
// Sends trade requests to a server.
if (::OrderSend(orequest, oresult)) {
// In case of a successful basic check of structures (index checking) returns true.
// However, this is not a sign of successful execution of a trade operation.
// @see: https://www.mql5.com/en/docs/trading/ordersend
// In order to obtain information about the error, call the GetLastError() function.
odata.ticket = oresult.order;
_result = (long)oresult.order;
// After trade request is accepted, send it to a server.
if (::OrderSend(orequest, oresult)) {
// In case of a successful basic check of structures (index checking) returns true.
// However, this is not a sign of successful execution of a trade operation.
// @see: https://www.mql5.com/en/docs/trading/ordersend
// In order to obtain information about the error, call the GetLastError() function.
odata.ticket = oresult.order;
_result = (long)oresult.order;
} else {
// The function execution result is placed to structure MqlTradeResult,
// whose retcode field contains the trade server return code.
// @see: https://www.mql5.com/en/docs/constants/errorswarnings/enum_trade_return_codes
// In order to obtain information about the error, call the GetLastError() function.
odata.last_error = oresult.retcode;
_result = -1;
}
} else {
// The function execution result is placed to structure MqlTradeResult,
// whose retcode field contains the trade server return code.
// @see: https://www.mql5.com/en/docs/constants/errorswarnings/enum_trade_return_codes
// If funds are not enough for the operation,
// or parameters are filled out incorrectly, the function returns false.
// In order to obtain information about the error, call the GetLastError() function.
// @see: https://www.mql5.com/en/docs/trading/ordercheck
odata.last_error = oresult_check.retcode;
_result = -1;
}
odata.last_error = oresult.retcode;
#endif
if (_result >= 0) {
#ifdef __MQL4__
Expand All @@ -1297,6 +1296,8 @@ class Order : public SymbolInfo {
odata.Set(ORDER_VOLUME_INITIAL, orequest.volume);
Update();
ResetLastError();
} else {
odata.last_error = fmax(odata.last_error, GetLastError());
}
return _result;
}
Expand Down
4 changes: 2 additions & 2 deletions SerializerConverter.mqh
Original file line number Diff line number Diff line change
Expand Up @@ -49,13 +49,13 @@ class SerializerConverter {

template <typename X>
static SerializerConverter FromObject(X& _value, int serializer_flags = SERIALIZER_FLAG_INCLUDE_ALL) {
Print("FromObject serializer flags: ", serializer_flags);
Serializer _serializer(NULL, Serialize, serializer_flags);
_serializer.FreeRootNodeOwnership();
_serializer.PassObject(_value, "", _value, SERIALIZER_FIELD_FLAG_VISIBLE);
SerializerConverter _converter(_serializer.GetRoot(), serializer_flags);
#ifdef __debug__
Print("FromObject() result: ", _serializer.GetRoot() != NULL ? _serializer.GetRoot().ToString() : "NULL");
Print("FromObject(): serializer flags: ", serializer_flags);
Print("FromObject(): result: ", _serializer.GetRoot() != NULL ? _serializer.GetRoot().ToString() : "NULL");
#endif
return _converter;
}
Expand Down
5 changes: 4 additions & 1 deletion SymbolInfo.mqh
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ class SymbolInfo : public Object {
*/
SymbolInfo(string _symbol = NULL, Log *_logger = NULL)
: logger(_logger != NULL ? _logger : new Log),
symbol(_symbol == "" ? _Symbol : _symbol),
symbol(_symbol),
pip_size(GetPipSize()),
symbol_digits(GetDigits()) {
Select();
Expand All @@ -71,6 +71,9 @@ class SymbolInfo : public Object {
sprops.pip_value = SymbolInfoStatic::GetPipValue(_symbol);
sprops.pts_per_pip = SymbolInfoStatic::GetPointsPerPip(_symbol);
sprops.vol_digits = SymbolInfoStatic::GetVolumeDigits(_symbol);
if (StringLen(symbol) == 0) {
symbol = _Symbol;
}
}

~SymbolInfo() {}
Expand Down
4 changes: 4 additions & 0 deletions Task.struct.h
Original file line number Diff line number Diff line change
Expand Up @@ -76,8 +76,12 @@ struct TaskEntry {
bool IsFailed() { return HasFlag(ACTION_ENTRY_FLAG_IS_FAILED); }
bool IsValid() { return !HasFlag(ACTION_ENTRY_FLAG_IS_INVALID); }
// Getters.
long GetActionId() { return action.GetId(); }
long GetConditionId() { return cond.GetId(); }
ActionEntry GetAction() { return action; }
ConditionEntry GetCondition() { return cond; }
ENUM_ACTION_TYPE GetActionType() { return action.GetType(); }
ENUM_CONDITION_TYPE GetConditionType() { return cond.GetType(); }
// Setters.
void SetActionObject(void *_obj) { action.SetObject(_obj); }
void SetConditionObject(void *_obj) { cond.SetObject(_obj); }
Expand Down
19 changes: 18 additions & 1 deletion Trade.mqh
Original file line number Diff line number Diff line change
Expand Up @@ -481,24 +481,37 @@ HistorySelect(0, TimeCurrent()); // Select history for access.

/**
* Calculate size of the lot based on the free margin or balance.
*
* @param
* _risk_margin (double) Risk margin in %.
* ...
*
* @return
* Returns calculated lot size (volume).
*/
float CalcLotSize(float _risk_margin = 1, // Risk margin in %.
float _risk_ratio = 1.0, // Risk ratio factor.
uint _orders_avg = 10, // Number of orders to use for the calculation.
uint _method = 0 // Method of calculation (0-3).
) {
float _avail_amount = _method % 2 == 0 ? account.GetMarginAvail() : account.GetTotalBalance();
float _lot_size_min = (float)chart.GetVolumeMin();
float _lot_size = _lot_size_min;
float _risk_value = (float)account.GetLeverage();
if (_method == 0 || _method == 1) {
_lot_size = _avail_amount / fmax(_lot_size_min, GetMarginRequired() * _risk_ratio) / _risk_value * _risk_ratio;
float _margin_req = GetMarginRequired();
if (_margin_req > 0) {
_lot_size = _avail_amount / _margin_req * _risk_ratio;
_lot_size /= _risk_value * _risk_ratio * _orders_avg;
}
} else {
float _risk_amount = _avail_amount / 100 * _risk_margin;
float _money_value = Convert::MoneyToValue(_risk_amount, _lot_size_min, chart.GetSymbol());
float _tick_value = chart.GetTickSize();
// @todo: Improves calculation logic.
_lot_size = _money_value * _tick_value * _risk_ratio / _risk_value / 100;
}
_lot_size = (float)fmin(_lot_size, chart.GetVolumeMax());
return (float)NormalizeLots(_lot_size);
}

Expand Down Expand Up @@ -526,6 +539,10 @@ HistorySelect(0, TimeCurrent()); // Select history for access.
// Trigger: OnOrder();
_result = true;
break;
case TRADE_RETCODE_INVALID:
logger.Error("Cannot process order!", __FUNCTION_LINE__,
StringFormat("Code: %d, Msg: %s", _last_error, Terminal::GetErrorText(_last_error)));
break;
default:
logger.Error("Cannot add order!", __FUNCTION_LINE__,
StringFormat("Code: %d, Msg: %s", _last_error, Terminal::GetErrorText(_last_error)));
Expand Down

0 comments on commit 138cf93

Please sign in to comment.