Skip to content

Commit

Permalink
ChartInfos: reparse unitsize cfg on toggle-(open-orders|trade-history)
Browse files Browse the repository at this point in the history
  • Loading branch information
rosasurfer committed Oct 10, 2024
1 parent 3a91567 commit e3c661d
Show file tree
Hide file tree
Showing 3 changed files with 133 additions and 126 deletions.
18 changes: 7 additions & 11 deletions config/global-config.example.ini
Original file line number Diff line number Diff line change
Expand Up @@ -206,22 +206,18 @@ TradeHistory.ConnectTrades = 1

;----------------------------------------------------------------------------------------------------------------------------
; Unit size calculation:
; The default settings apply if no symbol-specific settings are provided. For symbol-specific settings the term "Default"
; is replaced by the broker's symbol name or the symbol's standard name. The broker's symbol name has preference over the
; standard name. E.g. if a broker offers the symbol "EURUSDm" and the configuration provides the settings "Default.Leverage",
; "EURUSD.Leverage" and "EURUSDm.Leverage" the calculation uses the settings for "EURUSDm".
;
; If both risk and leverage settings are provided the resulting unitsize is the smaller of both calculations.
; Symbol-specific settings take precedence over default settings. If multiple settings are found for the same standard
; symbol (e.g. "EURUSDm.Leverage" and "EURUSD.Leverage"), the broker-specific settings take precedence.
;
; @see indicator ChartInfos::CalculateUnitSize()
;
[Unitsize]
Default.RiskPercent = 10 ; risked percent of account equity
Default.RiskRange = ADR ; price range for the risked percent (absolute or in pip, or value "ADR")
Default.Leverage = 4 ; leverage per unit
RiskRange = ADR ; range for risk calculation: absolute value or "ADR" = ADR(20)
RiskPercent = 10 ; max. risked percent per RiskRange and unit (0: no restriction)
Leverage = 0 ; max. leverage per unit (0: no restriction)

GBPUSD.RiskPercent = 6 ; per symbol setting
EURUSD.Leverage = 5 ; per symbol setting
GBPUSD.RiskPercent = 6 ; symbol-specific setting take precedence over default values
EURUSD.Leverage = 5


[Experts]
Expand Down
87 changes: 0 additions & 87 deletions mql4/include/rsf/functions/chartinfos/init.mqh
Original file line number Diff line number Diff line change
Expand Up @@ -45,13 +45,6 @@ int onInit() {
if (!InitTradeAccount()) return(last_error);
if (!UpdateAccountDisplay()) return(last_error);

if (mode.intern) {
// resolve unitsize configuration, after InitTradeAccount()
if (!ReadUnitSizeConfigValue("Leverage", sValue)) return(last_error); mm.cfgLeverage = StrToDouble(sValue);
if (!ReadUnitSizeConfigValue("RiskPercent", sValue)) return(last_error); mm.cfgRiskPercent = StrToDouble(sValue);
if (!ReadUnitSizeConfigValue("RiskRange", sValue)) return(last_error); mm.cfgRiskRange = StrToDouble(sValue);
mm.cfgRiskRangeIsADR = StrCompareI(sValue, "ADR");
}
return(catch("onInit(2)"));
}

Expand Down Expand Up @@ -180,83 +173,3 @@ int afterInit() {
}
return(catch("afterInit(3)"));
}

/**
* Find the applicable configuration for the [UnitSize] calculation and return the configured value.
*
* @param _In_ string name - unitsize configuration identifier
* @param _Out_ string &value - configuration value
*
* @return bool - success status
*/
bool ReadUnitSizeConfigValue(string name, string &value) {
string section="Unitsize", sValue="";
value = "";

string key = Symbol() +"."+ name;
if (IsConfigKey(section, key)) {
if (!ValidateUnitSizeConfigValue(section, key, sValue)) return(false);
value = sValue;
return(true);
}

key = StdSymbol() +"."+ name;
if (IsConfigKey(section, key)) {
if (!ValidateUnitSizeConfigValue(section, key, sValue)) return(false);
value = sValue;
return(true);
}

key = "Default."+ name;
if (IsConfigKey(section, key)) {
if (!ValidateUnitSizeConfigValue(section, key, sValue)) return(false);
value = sValue;
return(true);
}

return(true); // success also if no configuration was found (returns an empty string)
}


/**
* Validate the specified [UnitSize] configuration key and return the configured value.
*
* @param _In_ string section - configuration section
* @param _In_ string key - configuration key
* @param _Out_ string &value - configured value
*
* @return bool - success status
*/
bool ValidateUnitSizeConfigValue(string section, string key, string &value) {
string sValue = GetConfigString(section, key), sValueBak = sValue;

if (StrEndsWithI(key, ".RiskPercent") || StrEndsWithI(key, ".Leverage")) {
if (!StrIsNumeric(sValue)) return(!catch("GetUnitSizeConfigValue(1) invalid configuration value ["+ section +"]->"+ key +": \""+ sValueBak +"\" (non-numeric)", ERR_INVALID_CONFIG_VALUE));
double dValue = StrToDouble(sValue);
if (dValue < 0) return(!catch("GetUnitSizeConfigValue(2) invalid configuration value ["+ section +"]->"+ key +": "+ sValueBak +" (non-positive)", ERR_INVALID_CONFIG_VALUE));
value = sValue;
return(true);
}

if (StrEndsWithI(key, ".RiskRange")) {
if (StrCompareI(sValue, "ADR")) {
value = sValue;
return(true);
}
if (!StrEndsWith(sValue, "pip")) {
if (!StrIsNumeric(sValue)) return(!catch("GetUnitSizeConfigValue(3) invalid configuration value ["+ section +"]->"+ key +": \""+ sValueBak +"\" (non-numeric)", ERR_INVALID_CONFIG_VALUE));
dValue = StrToDouble(sValue);
if (dValue < 0) return(!catch("GetUnitSizeConfigValue(4) invalid configuration value ["+ section +"]->"+ key +": "+ sValueBak +" (non-positive)", ERR_INVALID_CONFIG_VALUE));
value = sValue;
return(true);
}
sValue = StrTrim(StrLeft(sValue, -3));
if (!StrIsNumeric(sValue)) return(!catch("GetUnitSizeConfigValue(5) invalid configuration value ["+ section +"]->"+ key +": \""+ sValueBak +"\" (non-numeric pip value)", ERR_INVALID_CONFIG_VALUE));
dValue = StrToDouble(sValue);
if (dValue < 0) return(!catch("GetUnitSizeConfigValue(6) invalid configuration value ["+ section +"]->"+ key +": "+ sValueBak +" (non-positive)", ERR_INVALID_CONFIG_VALUE));
value = dValue * Pip;
return(true);
}

return(!catch("GetUnitSizeConfigValue(7) unsupported [UnitSize] config key: \""+ key +"\"", ERR_INVALID_PARAMETER));
}
154 changes: 126 additions & 28 deletions mql4/indicators/ChartInfos.mq4
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,7 @@
*
* TODO:
* - CustomPosition()
* signal on new MFE/MAE: marker "MFES"... @see line 2233 ff.
*
* "L,S, O 2024.06.06 19:17-" counts open positions twice, "L,S, O 2024.06.06-, O 2024.06.06-" counts them thrice and so on...
* "L,S, O 2024.06.06 19:17-" counts open positions twice, "L,S, O 2024.06.06-, O 2024.06.06-" counts them thrice...
* history parsing/config term HT... freezes the terminal if the full history is active
* ExtractPosition()
* SortClosedTickets() time=0.271 sec => move to Expander
Expand All @@ -34,7 +32,7 @@ int __DeinitFlags[];

////////////////////////////////////////////////////// Configuration ////////////////////////////////////////////////////////

extern string UnitSize.Corner = "top | bottom*"; // can be shortened
extern string UnitSize.Corner = "top | bottom*"; // can be shortened to a single char
extern bool Track.Orders = true; // whether to track and signal position open/close events

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
Expand All @@ -61,10 +59,11 @@ double mm.externalAssets; // external as
bool mm.externalAssetsCached; // whether mm.externalAssets holds a valid cached value
double mm.equity; // equity value used for calculations, incl. external assets and floating losses (but w/o floating/unrealized profits)

double mm.cfgLeverage;
double mm.cfgRiskPercent;
double mm.cfgRiskRange;
bool mm.cfgIsValid; // whether the unitsize configuration is valid/initialized
double mm.cfgRiskRange; //
bool mm.cfgRiskRangeIsADR; // whether the price range is configured as "ADR"
double mm.cfgRiskPercent; //
double mm.cfgLeverage; //

double mm.lotValue; // value of 1 lot in account currency
double mm.unleveragedLots; // unleveraged unitsize
Expand Down Expand Up @@ -302,7 +301,7 @@ bool onCommand(string cmd, string params, int keys) {

// write updated value back to the config file
if (WriteIniString(GetAccountConfigPath(), "Account", "ExternalAssets", sConfigValue)) {
mm.externalAssetsCached = false; // invalidate cached value
mm.externalAssetsCached = false; // invalidate cached external assets
ArrayResize(configTerms, 0); // trigger reparsing of the configuration
}
PlaySoundEx("Bell 1.wav");
Expand All @@ -316,6 +315,7 @@ bool onCommand(string cmd, string params, int keys) {
flags = NULL;
if (keys & F_VK_SHIFT && 1) {
flags = F_SHOW_CUSTOM_POSITIONS; // with VK_SHIFT: show custom positions only
mm.cfgIsValid = false; // invalidate cached unitsize configuration
mm.externalAssetsCached = false; // invalidate cached external assets
ArrayResize(configTerms, 0); // trigger reparsing of the configuration
}
Expand All @@ -326,6 +326,7 @@ bool onCommand(string cmd, string params, int keys) {
flags = NULL;
if (keys & F_VK_SHIFT && 1) {
flags = F_SHOW_CUSTOM_HISTORY; // with VK_SHIFT: show custom history only
mm.cfgIsValid = false; // invalidate cached unitsize configuration
mm.externalAssetsCached = false; // invalidate cached external assets
ArrayResize(configTerms, 0); // trigger reparsing of the configuration
}
Expand All @@ -344,10 +345,13 @@ bool onCommand(string cmd, string params, int keys) {
string key = StrReplace(params, ",", ":");
if (!InitTradeAccount(key)) return(false);
if (!UpdateAccountDisplay()) return(false);
mm.cfgIsValid = false; // invalidate cached unitsize configuration
mm.externalAssetsCached = false; // invalidate cached external assets
ArrayResize(configTerms, 0); // trigger reparsing of the configuration
}
else return(!logNotice("onCommand(1) unsupported command: \""+ cmd +":"+ params +":"+ keys +"\""));
else {
return(!logNotice("onCommand(1) unsupported command: \""+ cmd +":"+ params +":"+ keys +"\""));
}

return(!catch("onCommand(2)"));
}
Expand Down Expand Up @@ -1951,27 +1955,19 @@ bool CustomPositions.LogTickets(int tickets[], int configLine, int flags = NULL)
/**
* Calculate the unitsize according to the configuration. Calculation is risk-based and/or leverage-based.
*
* - Default configuration settings for risk-based calculation:
* [Unitsize]
* Default.RiskPercent = <numeric> ; risked percent of account equity
* Default.RiskRange = (<numeric> [pip] | ADR) ; price range (absolute, in pip or the value "ADR") for the risked percent
*
* - Default configuration settings for leverage-based calculation:
* [Unitsize]
* Default.Leverage = <numeric> ; leverage per unit
*
* - Symbol-specific configuration:
* [Unitsize]
* GBPUSD.RiskPercent = <numeric> ; per symbol: risked percent of account equity
* EURUSD.Leverage = <numeric> ; per symbol: leverage per unit
*
* This default settings apply if no symbol-specific settings are provided. For symbol-specific settings the term "Default"
* gets replaced by the actual symbol.
* Default configuration
* [Unitsize]
* RiskRange = (<numeric> [pip] | ADR) ; range for risk calculation: absolute value or "ADR" = ADR(20)
* RiskPercent = <numeric> ; max. risked percent per RiskRange and unit (0: no restriction)
* Leverage = <numeric> ; max. leverage per unit (0: no restriction)
*
* If multiple settings are found for the same standard symbol (e.g. "EURUSDm.Leverage" and "EURUSD.Leverage"), then a broker
* specific settings is preferred.
* Symbol-specific configuration (merged with defaults)
* [Unitsize]
* GBPUSD.RiskPercent = <numeric>
* EURUSD.Leverage = <numeric>
*
* If both risk and leverage settings are configured the resulting unitsize is the smaller of both calculations.
* Symbol-specific settings take precedence over default settings. If multiple settings are found for the same standard
* symbol (e.g. "EURUSDm.Leverage" and "EURUSD.Leverage"), the broker-specific settings take precedence.
*
* @return bool - success status
*/
Expand Down Expand Up @@ -2008,6 +2004,11 @@ bool CalculateUnitSize() {
mm.lotValue = Close[0]/tickSize * tickValue; // value of 1 lot in account currency
mm.unleveragedLots = mm.equity/mm.lotValue; // unleveraged unitsize

// ensure a valid unitsize configuration
if (!mm.cfgIsValid) {
if (!ReadUnitSizeConfiguration()) return(last_error == ERS_TERMINAL_NOT_YET_READY);
}

// update the current ADR
if (mm.cfgRiskRangeIsADR) {
mm.cfgRiskRange = GetADR();
Expand Down Expand Up @@ -2063,6 +2064,103 @@ bool CalculateUnitSize() {
}


/**
* Read the unitsize configuration.
*
* @return bool - success status
*/
bool ReadUnitSizeConfiguration() {
string sValue = "";
if (!ReadUnitSizeConfigValue("Leverage", sValue)) return(false); mm.cfgLeverage = StrToDouble(sValue);
if (!ReadUnitSizeConfigValue("RiskPercent", sValue)) return(false); mm.cfgRiskPercent = StrToDouble(sValue);
if (!ReadUnitSizeConfigValue("RiskRange", sValue)) return(false); mm.cfgRiskRange = StrToDouble(sValue);
mm.cfgRiskRangeIsADR = StrCompareI(sValue, "ADR");

mm.cfgIsValid = true;
return(!catch("ReadUnitSizeConfiguration(1)"));
}


/**
* Find the applicable configuration value for the unitsize calculation.
*
* @param _In_ string name - unitsize configuration identifier
* @param _Out_ string &value - configuration value
*
* @return bool - success status
*/
bool ReadUnitSizeConfigValue(string name, string &value) {
string section="Unitsize", sValue="";
value = "";

string key = Symbol() +"."+ name;
if (IsConfigKey(section, key)) {
if (!ValidateUnitSizeConfigValue(section, key, sValue)) return(false);
value = sValue;
return(true);
}

key = StdSymbol() +"."+ name;
if (IsConfigKey(section, key)) {
if (!ValidateUnitSizeConfigValue(section, key, sValue)) return(false);
value = sValue;
return(true);
}

key = name;
if (IsConfigKey(section, key)) {
if (!ValidateUnitSizeConfigValue(section, key, sValue)) return(false);
value = sValue;
return(true);
}
return(true); // success also if no configuration was found (returns an empty string)
}


/**
* Validate the specified unitsize configuration value.
*
* @param _In_ string section - configuration section
* @param _In_ string key - configuration key
* @param _Out_ string &value - configured value
*
* @return bool - success status
*/
bool ValidateUnitSizeConfigValue(string section, string key, string &value) {
string sValue = GetConfigString(section, key), sValueBak = sValue;

if (StrEndsWithI(key, "RiskPercent") || StrEndsWithI(key, "Leverage")) {
if (!StrIsNumeric(sValue)) return(!catch("ValidateUnitSizeConfigValue(1) invalid configuration value ["+ section +"]->"+ key +": \""+ sValueBak +"\" (non-numeric)", ERR_INVALID_CONFIG_VALUE));
double dValue = StrToDouble(sValue);
if (dValue < 0) return(!catch("ValidateUnitSizeConfigValue(2) invalid configuration value ["+ section +"]->"+ key +": "+ sValueBak +" (non-positive)", ERR_INVALID_CONFIG_VALUE));
value = sValue;
return(true);
}

if (StrEndsWithI(key, "RiskRange")) {
if (StrCompareI(sValue, "ADR")) {
value = sValue;
return(true);
}
if (!StrEndsWith(sValue, "pip")) {
if (!StrIsNumeric(sValue)) return(!catch("ValidateUnitSizeConfigValue(3) invalid configuration value ["+ section +"]->"+ key +": \""+ sValueBak +"\" (non-numeric)", ERR_INVALID_CONFIG_VALUE));
dValue = StrToDouble(sValue);
if (dValue < 0) return(!catch("ValidateUnitSizeConfigValue(4) invalid configuration value ["+ section +"]->"+ key +": "+ sValueBak +" (non-positive)", ERR_INVALID_CONFIG_VALUE));
value = sValue;
return(true);
}
sValue = StrTrim(StrLeft(sValue, -3));
if (!StrIsNumeric(sValue)) return(!catch("ValidateUnitSizeConfigValue(5) invalid configuration value ["+ section +"]->"+ key +": \""+ sValueBak +"\" (non-numeric pip value)", ERR_INVALID_CONFIG_VALUE));
dValue = StrToDouble(sValue);
if (dValue < 0) return(!catch("ValidateUnitSizeConfigValue(6) invalid configuration value ["+ section +"]->"+ key +": "+ sValueBak +" (non-positive)", ERR_INVALID_CONFIG_VALUE));
value = dValue * Pip;
return(true);
}

return(!catch("ValidateUnitSizeConfigValue(7) unsupported [UnitSize] config key: \""+ key +"\"", ERR_INVALID_PARAMETER));
}


/**
* Resolve and cache the amount of externally hold assets.
*
Expand Down

0 comments on commit e3c661d

Please sign in to comment.