Skip to content

Commit 4b6e1ac

Browse files
author
EarnForex
authored
1.11
Minor improvements of position size calculation.
1 parent 0a348b9 commit 4b6e1ac

2 files changed

Lines changed: 99 additions & 13 deletions

File tree

ChartPatternHelper.mq4

Lines changed: 91 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
//+------------------------------------------------------------------+
66
#property copyright "Copyright © 2013-2022, EarnForex"
77
#property link "https://www.earnforex.com/metatrader-expert-advisors/ChartPatternHelper/"
8-
#property version "1.10"
8+
#property version "1.11"
99
#property strict
1010

1111
#include <stdlib.mqh>
@@ -71,8 +71,8 @@ bool HaveSell = false;
7171
bool TCBusy = false;
7272
bool PostBuySLAdjustmentDone = false, PostSellSLAdjustmentDone = false;
7373
// For tick value adjustment:
74-
string ProfitCurrency = "", account_currency = "", BaseCurrency = "", ReferenceSymbol = NULL;
75-
bool ReferenceSymbolMode;
74+
string ProfitCurrency = "", account_currency = "", BaseCurrency = "", ReferenceSymbol = NULL, AdditionalReferenceSymbol = NULL;
75+
bool ReferenceSymbolMode, AdditionalReferenceSymbolMode;
7676
int ProfitCalcMode;
7777
double TickSize;
7878

@@ -1226,6 +1226,7 @@ void SetComment(string c)
12261226
#define NONFOREX_SYMBOLS_ONLY 1
12271227
double CalculateAdjustment()
12281228
{
1229+
double add_coefficient = 1; // Might be necessary for correction coefficient calculation if two pairs are used for profit currency to account currency conversion. This is handled differently in MT5 version.
12291230
if (ReferenceSymbol == NULL)
12301231
{
12311232
ReferenceSymbol = GetSymbolByCurrencies(ProfitCurrency, account_currency, FOREX_SYMBOLS_ONLY);
@@ -1241,13 +1242,34 @@ double CalculateAdjustment()
12411242
}
12421243
if (ReferenceSymbol == NULL)
12431244
{
1244-
Print("Error. Cannot detect proper currency pair for adjustment calculation. Profit currency: ", ProfitCurrency, ". Account currency: ", account_currency, ".");
1245-
return 1;
1245+
// The condition checks whether we are caclulating conversion coefficient for the chart's symbol or for some other.
1246+
// The error output is OK for the current symbol only because it won't be repeated ad infinitum.
1247+
// It should be avoided for non-chart symbols because it will just flood the log.
1248+
Print("Couldn't detect proper currency pair for adjustment calculation. Profit currency: ", ProfitCurrency, ". Account currency: ", account_currency, ". Trying to find a possible two-symbol combination.");
1249+
if ((FindDoubleReferenceSymbol("USD")) // USD should work in 99.9% of cases.
1250+
|| (FindDoubleReferenceSymbol("EUR")) // For very rare cases.
1251+
|| (FindDoubleReferenceSymbol("GBP")) // For extremely rare cases.
1252+
|| (FindDoubleReferenceSymbol("JPY"))) // For extremely rare cases.
1253+
{
1254+
Print("Converting via ", ReferenceSymbol, " and ", AdditionalReferenceSymbol, ".");
1255+
}
1256+
else
1257+
{
1258+
Print("Adjustment calculation critical failure. Failed both simple and two-pair conversion methods.");
1259+
return 1;
1260+
}
12461261
}
12471262
}
1263+
if (AdditionalReferenceSymbol != NULL) // If two reference pairs are used.
1264+
{
1265+
// Calculate just the additional symbol's coefficient and then use it in final return's multiplication.
1266+
MqlTick tick;
1267+
SymbolInfoTick(AdditionalReferenceSymbol, tick);
1268+
add_coefficient = GetCurrencyCorrectionCoefficient(tick, AdditionalReferenceSymbolMode);
1269+
}
12481270
MqlTick tick;
12491271
SymbolInfoTick(ReferenceSymbol, tick);
1250-
return GetCurrencyCorrectionCoefficient(tick);
1272+
return GetCurrencyCorrectionCoefficient(tick, ReferenceSymbolMode) * add_coefficient;
12511273
}
12521274

12531275
//+---------------------------------------------------------------------------+
@@ -1268,6 +1290,7 @@ string GetSymbolByCurrencies(const string base_currency, const string profit_cur
12681290
if (symbol_type == NONFOREX_SYMBOLS_ONLY) continue; // Avoid checking symbols of a wrong type.
12691291
// Get its base currency.
12701292
b_cur = SymbolInfoString(symbolname, SYMBOL_CURRENCY_BASE);
1293+
if (b_cur == "RUR") b_cur = "RUB";
12711294
}
12721295
else // Weird case for brokers that set conversion pairs as CFDs.
12731296
{
@@ -1278,6 +1301,7 @@ string GetSymbolByCurrencies(const string base_currency, const string profit_cur
12781301

12791302
// Get its profit currency.
12801303
string p_cur = SymbolInfoString(symbolname, SYMBOL_CURRENCY_PROFIT);
1304+
if (p_cur == "RUR") p_cur = "RUB";
12811305

12821306
// If the currency pair matches both currencies, select it in Market Watch and return its name.
12831307
if ((b_cur == base_currency) && (p_cur == profit_currency))
@@ -1291,15 +1315,68 @@ string GetSymbolByCurrencies(const string base_currency, const string profit_cur
12911315
return NULL;
12921316
}
12931317

1318+
//+----------------------------------------------------------------------------+
1319+
//| Finds reference symbols using 2-pair method. |
1320+
//| Results are returned via reference parameters. |
1321+
//| Returns true if found the pairs, false otherwise. |
1322+
//+----------------------------------------------------------------------------+
1323+
bool FindDoubleReferenceSymbol(const string cross_currency)
1324+
{
1325+
// A hypothetical example for better understanding:
1326+
// The trader buys CAD/CHF.
1327+
// account_currency is known = SEK.
1328+
// cross_currency = USD.
1329+
// profit_currency = CHF.
1330+
// I.e., we have to buy dollars with francs (using the Ask price) and then sell those for SEKs (using the Bid price).
1331+
1332+
ReferenceSymbol = GetSymbolByCurrencies(cross_currency, account_currency, FOREX_SYMBOLS_ONLY);
1333+
if (ReferenceSymbol == NULL) ReferenceSymbol = GetSymbolByCurrencies(cross_currency, account_currency, NONFOREX_SYMBOLS_ONLY);
1334+
ReferenceSymbolMode = true; // If found, we've got USD/SEK.
1335+
1336+
// Failed.
1337+
if (ReferenceSymbol == NULL)
1338+
{
1339+
// Reversing currencies.
1340+
ReferenceSymbol = GetSymbolByCurrencies(account_currency, cross_currency, FOREX_SYMBOLS_ONLY);
1341+
if (ReferenceSymbol == NULL) ReferenceSymbol = GetSymbolByCurrencies(account_currency, cross_currency, NONFOREX_SYMBOLS_ONLY);
1342+
ReferenceSymbolMode = false; // If found, we've got SEK/USD.
1343+
}
1344+
if (ReferenceSymbol == NULL)
1345+
{
1346+
Print("Error. Couldn't detect proper currency pair for 2-pair adjustment calculation. Cross currency: ", cross_currency, ". Account currency: ", account_currency, ".");
1347+
return false;
1348+
}
1349+
1350+
AdditionalReferenceSymbol = GetSymbolByCurrencies(cross_currency, ProfitCurrency, FOREX_SYMBOLS_ONLY);
1351+
if (AdditionalReferenceSymbol == NULL) AdditionalReferenceSymbol = GetSymbolByCurrencies(cross_currency, ProfitCurrency, NONFOREX_SYMBOLS_ONLY);
1352+
AdditionalReferenceSymbolMode = false; // If found, we've got USD/CHF. Notice that mode is swapped for cross/profit compared to cross/acc, because it is used in the opposite way.
1353+
1354+
// Failed.
1355+
if (AdditionalReferenceSymbol == NULL)
1356+
{
1357+
// Reversing currencies.
1358+
AdditionalReferenceSymbol = GetSymbolByCurrencies(ProfitCurrency, cross_currency, FOREX_SYMBOLS_ONLY);
1359+
if (AdditionalReferenceSymbol == NULL) AdditionalReferenceSymbol = GetSymbolByCurrencies(ProfitCurrency, cross_currency, NONFOREX_SYMBOLS_ONLY);
1360+
AdditionalReferenceSymbolMode = true; // If found, we've got CHF/USD. Notice that mode is swapped for profit/cross compared to acc/cross, because it is used in the opposite way.
1361+
}
1362+
if (AdditionalReferenceSymbol == NULL)
1363+
{
1364+
Print("Error. Couldn't detect proper currency pair for 2-pair adjustment calculation. Cross currency: ", cross_currency, ". Chart's pair currency: ", ProfitCurrency, ".");
1365+
return false;
1366+
}
1367+
1368+
return true;
1369+
}
1370+
12941371
//+------------------------------------------------------------------+
12951372
//| Get profit correction coefficient based on current prices. |
12961373
//| Valid for loss calculation only. |
12971374
//+------------------------------------------------------------------+
1298-
double GetCurrencyCorrectionCoefficient(MqlTick &tick)
1375+
double GetCurrencyCorrectionCoefficient(MqlTick &tick, const bool ref_symbol_mode)
12991376
{
13001377
if ((tick.ask == 0) || (tick.bid == 0)) return -1; // Data is not yet ready.
13011378
// Reverse quote.
1302-
if (ReferenceSymbolMode)
1379+
if (ref_symbol_mode)
13031380
{
13041381
// Using Buy price for reverse quote.
13051382
return tick.ask;
@@ -1320,6 +1397,12 @@ double GetPositionSize(double Entry, double StopLoss)
13201397
BaseCurrency = SymbolInfoString(Symbol(), SYMBOL_CURRENCY_BASE);
13211398
ProfitCalcMode = (int)MarketInfo(Symbol(), MODE_PROFITCALCMODE);
13221399
account_currency = AccountCurrency();
1400+
1401+
// A rough patch for cases when account currency is set as RUR instead of RUB.
1402+
if (account_currency == "RUR") account_currency = "RUB";
1403+
if (ProfitCurrency == "RUR") ProfitCurrency = "RUB";
1404+
if (BaseCurrency == "RUR") BaseCurrency = "RUB";
1405+
13231406
double LotStep = MarketInfo(Symbol(), MODE_LOTSTEP);
13241407
int LotStep_digits = CountDecimalPlaces(LotStep);
13251408

ChartPatternHelper.mq5

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
//+------------------------------------------------------------------+
66
#property copyright "Copyright © 2013-2022, EarnForex"
77
#property link "https://www.earnforex.com/metatrader-expert-advisors/ChartPatternHelper/"
8-
#property version "1.10"
8+
#property version "1.11"
99

1010
#property description "Uses graphic objects (horizontal/trend lines, channels) to enter trades."
1111
#property description "Works in two modes:"
@@ -1258,8 +1258,7 @@ void SetComment(string c)
12581258
}
12591259

12601260
//+------------------------------------------------------------------+
1261-
//| Calculates symbol leverage value based on required margin |
1262-
//| and current rates. |
1261+
//| Calculates unit cost based on profit calculation mode. |
12631262
//+------------------------------------------------------------------+
12641263
double CalculateUnitCost()
12651264
{
@@ -1317,9 +1316,11 @@ string GetSymbolByCurrencies(string base_currency, string profit_currency)
13171316

13181317
// Get its base currency.
13191318
string b_cur = SymbolInfoString(symbolname, SYMBOL_CURRENCY_BASE);
1319+
if (b_cur == "RUR") b_cur = "RUB";
13201320

13211321
// Get its profit currency.
13221322
string p_cur = SymbolInfoString(symbolname, SYMBOL_CURRENCY_PROFIT);
1323+
if (p_cur == "RUR") p_cur = "RUB";
13231324

13241325
// If the currency pair matches both currencies, select it in Market Watch and return its name.
13251326
if ((b_cur == base_currency) && (p_cur == profit_currency))
@@ -1367,7 +1368,9 @@ double GetPositionSize(double Entry, double StopLoss, ENUM_ORDER_TYPE dir)
13671368
if (AccountCurrency == "RUR") AccountCurrency = "RUB";
13681369

13691370
ProfitCurrency = SymbolInfoString(Symbol(), SYMBOL_CURRENCY_PROFIT);
1371+
if (ProfitCurrency == "RUR") ProfitCurrency = "RUB";
13701372
BaseCurrency = SymbolInfoString(Symbol(), SYMBOL_CURRENCY_BASE);
1373+
if (BaseCurrency == "RUR") BaseCurrency = "RUB";
13711374
CalcMode = (ENUM_SYMBOL_CALC_MODE)SymbolInfoInteger(Symbol(), SYMBOL_TRADE_CALC_MODE);
13721375
double LotStep = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_STEP);
13731376
int LotStep_digits = CountDecimalPlaces(LotStep);
@@ -1395,8 +1398,8 @@ double GetPositionSize(double Entry, double StopLoss, ENUM_ORDER_TYPE dir)
13951398

13961399
double UnitCost = CalculateUnitCost();
13971400

1398-
// If profit currency is different from account currency and Symbol is not a Forex pair (CFD, futures, and so on).
1399-
if ((ProfitCurrency != AccountCurrency) && (CalcMode != SYMBOL_CALC_MODE_FOREX) && (CalcMode != SYMBOL_CALC_MODE_FOREX_NO_LEVERAGE))
1401+
// If profit currency is different from account currency and Symbol is not a Forex pair or futures (CFD, and so on).
1402+
if ((ProfitCurrency != AccountCurrency) && (CalcMode != SYMBOL_CALC_MODE_FOREX) && (CalcMode != SYMBOL_CALC_MODE_FOREX_NO_LEVERAGE) && (CalcMode != SYMBOL_CALC_MODE_FUTURES) && (CalcMode != SYMBOL_CALC_MODE_EXCH_FUTURES) && (CalcMode != SYMBOL_CALC_MODE_EXCH_FUTURES_FORTS))
14001403
{
14011404
double CCC = CalculateAdjustment(); // Valid only for loss calculation.
14021405
// Adjust the unit cost.

0 commit comments

Comments
 (0)