risk based volume (OrderCalcProfit) ?
-
Has anyone figured out how to calculate risk using custom code or an alternative method to the blocks available?
Reason being, lot calcs do not work properly when trading gold or indexs due to using MODE_TICKVALUE is unreliable.
I see on forums to use OrderCalcProfit but I cannot figure out how to implement this into my ea.
-
Link 1 basically tells you how to add to custom code:
OrderCalcProfit(ORDER_TYPE_BUY[OR SELL],NULL,[LOT SIZE],[OPENING PRICE, COULD BE CURRENT],[STOP LOSS PRICE],[VARIABLE FOR RECEIVING VAUE]; -
@jstap I’m not very good at understanding how the code works tbh, I’ll give it another go tomorrow.
If we could get this code working it theoretically should give us a working percent lot call on all pairs including metals and index’s. As only fx pairs are reliable in fxdreema risk based lot size.
Unless you know of another way to have a reliable gold percent lot calc?
-
I don't, but if you put it together as wanted, test it then add the shared link here if it's not working.
-
I can't get past this issue for now

-
Lets see how you have put it all together, not just the error. Add a shared link here.
-
TBH jstap I have been busy with work, made almost no progress at all but this is the code I intend to implement which is taken from the following link. I am going to pay someone on mql5 to attempt to implement the OrderCalcProfit to bypass my lack of ability then build it into my ea after if it works.
functions the volume calc code is in.
https://www.mql5.com/en/code/28029 -
When you have this much code things can be difficult. Some code can only be added in custom blocks, split this down into smaller sections, then add bits until you find what is causing an error, then fix and add more, until you get all working. V not allowed on current scope is common for something tat needs to be in a custom block.
-
So custom code works different from custom blocks in terms of the global scope error?
I have put an advert now on mql5 so I will see how that goes.
-
Work similarly, but works in areas that custom code doesn't.
-
I have a solution but for now it requires adjusting the code internally before compiling in the metaeditor. But it does allow accurate risk based volume calculations on all pairs, including metals etc.
You have to modify this part of the code from the // to the code below it:
if(mode=="equityRisk") { //size=((value/100)*AccountEquity())/(sl*TickValue*PipValue(symbol)); size = VolLongPoints(symbol,(value/100)*AccountEquity(),10*sl); } else if(mode=="balanceRisk") { //size=((value/100)*AccountBalance())/(sl*TickValue*PipValue(symbol)); size = VolLongPoints(symbol,(value/100)*AccountBalance(),10*sl); } else if(mode=="freemarginRisk") { //size=((value/100)*AccountFreeMargin())/(sl*TickValue*PipValue(symbol)); size = VolLongPoints(symbol,(value/100)*AccountFreeMargin(),10*sl); }Then insert this code below the Functions Box, "System and Custom functions used in the program".
double VolLongPoints(string pSymbol, double pMoney, double pSlp) { double Volstep = SymbolInfoDouble(pSymbol,SYMBOL_VOLUME_STEP); double Volmax = SymbolInfoDouble(pSymbol,SYMBOL_VOLUME_MAX); double Volmin = SymbolInfoDouble(pSymbol,SYMBOL_VOLUME_MIN); pMoney = floor(pMoney); double tickSize = SymbolInfoDouble(pSymbol,SYMBOL_TRADE_TICK_SIZE); double freeMargin = AccountInfoDouble(ACCOUNT_MARGIN_FREE); double point = SymbolInfoDouble(pSymbol,SYMBOL_POINT); double Price = SymbolInfoDouble(pSymbol,SYMBOL_ASK); Price = round(Price/tickSize)*tickSize; double slPrice = Price - pSlp * point; slPrice = round(slPrice/tickSize)*tickSize; double dbProfit = 0; double riskLots = 0; double OrderLots = 0; double reqMarg = 0; if(OrderCalcProfit(ORDER_TYPE_BUY, pSymbol, Volmax, Price, slPrice, dbProfit) == true) { OrderLots = fmin(fmax(round(pMoney * Volmax / (MathAbs(dbProfit) * Volstep)) * Volstep, Volmin), Volmax); } else if(!OrderCalcProfit(ORDER_TYPE_BUY, pSymbol, Volmax, Price, slPrice, dbProfit)) { Print("Volume calc Failed: ", GetLastError()); } //------ if(OrderCalcMargin(ORDER_TYPE_BUY,pSymbol,OrderLots,Price,reqMarg) == true) { double R = MathAbs(floor(freeMargin) / round(reqMarg)); // Calculate the ratio double OrderLotsAdjusted = 0; if(R < 1) // Check if the free margin is less than the required margin { OrderLotsAdjusted = OrderLots * R; // Reduce the order volume proportionally Print("Not enough money to execute trades with : ",DoubleToString(OrderLots)," Volume adjusted based on free margin to required margin ratio to : ",DoubleToString(OrderLotsAdjusted)); OrderLots = OrderLotsAdjusted; } } if(OrderLots < Volmin) { OrderLots = Volmin; } riskLots = floor(OrderLots/Volstep)*Volstep; return riskLots; } -
I created a script, so if you are using Equity, Balance, or Free Margin risk based lot size as per the below picture and block. So if you export your code to mq5, then load my script it will automatically replace the necessary code to give accurate volume size on pairs like gold that never used to calculate correctly.
You still need tp specify your Risk in %, Max lot and Stop loss either in distance or price level but other than that it should work.


Also a warning I do run these project options, 0.01 = 0.1 is an extra addition.

Below is a Python script, so make a text file and put this code into it and then change the file etension to .py when you run the code it will request a file to open, select desired mql5 and it will change the code internally automatically. Python is required on your pc for script to work.
import tkinter as tk from tkinter import filedialog def replace_and_add_code(file_path): try: # Open the file with UTF-16 Little Endian encoding with open(file_path, 'r', encoding='utf-16-le') as file: content = file.read() # Replace the size calculations old_code = [ 'else if (mode=="equityRisk") {size=((value/100)*AccountEquity())/(sl*TickValue*PipValue(symbol));}', 'else if (mode=="balanceRisk"){size=((value/100)*AccountBalance())/(sl*TickValue*PipValue(symbol));}', 'else if (mode=="freemarginRisk") {size=((value/100)*AccountFreeMargin())/(sl*TickValue*PipValue(symbol));}' ] new_code = [ 'else if (mode=="equityRisk") {size = VolLongPoints(symbol,(value/100)*AccountEquity(),10*sl);}', 'else if (mode=="balanceRisk"){size = VolLongPoints(symbol,(value/100)*AccountBalance(),10*sl);}', 'else if (mode=="freemarginRisk") {size = VolLongPoints(symbol,(value/100)*AccountFreeMargin(),10*sl);}' ] for j in range(len(old_code)): content = content.replace(old_code[j], new_code[j]) # Define the new function to add function_to_add = ''' double VolLongPoints(string pSymbol, double pMoney, double pSlp) { double Volstep = SymbolInfoDouble(pSymbol,SYMBOL_VOLUME_STEP); double Volmax = SymbolInfoDouble(pSymbol,SYMBOL_VOLUME_MAX); double Volmin = SymbolInfoDouble(pSymbol,SYMBOL_VOLUME_MIN); pMoney = floor(pMoney); double tickSize = SymbolInfoDouble(pSymbol,SYMBOL_TRADE_TICK_SIZE); double freeMargin = AccountInfoDouble(ACCOUNT_MARGIN_FREE); double point = SymbolInfoDouble(pSymbol,SYMBOL_POINT); double Price = SymbolInfoDouble(pSymbol,SYMBOL_ASK); Price = round(Price/tickSize)*tickSize; double slPrice = Price - pSlp * point; slPrice = round(slPrice/tickSize)*tickSize; double dbProfit = 0; double riskLots = 0; double OrderLots = 0; double reqMarg = 0; if(OrderCalcProfit(ORDER_TYPE_BUY, pSymbol, Volmax, Price, slPrice, dbProfit) == true) { OrderLots = fmin(fmax(round(pMoney * Volmax / (MathAbs(dbProfit) * Volstep)) * Volstep, Volmin), Volmax); } else if(!OrderCalcProfit(ORDER_TYPE_BUY, pSymbol, Volmax, Price, slPrice, dbProfit)) { Print("Volume calc Failed: ", GetLastError()); } //------ if(OrderCalcMargin(ORDER_TYPE_BUY,pSymbol,OrderLots,Price,reqMarg) == true) { double R = MathAbs(floor(freeMargin) / round(reqMarg)); // Calculate the ratio double OrderLotsAdjusted = 0; if(R < 1) // Check if the free margin is less than the required margin { OrderLotsAdjusted = OrderLots * R; // Reduce the order volume proportionally Print("Not enough money to execute trades with : ",DoubleToString(OrderLots)," Volume adjusted based on free margin to required margin ratio to : ",DoubleToString(OrderLotsAdjusted)); OrderLots = OrderLotsAdjusted; } } if(OrderLots < Volmin) { OrderLots = Volmin; } riskLots = floor(OrderLots/Volstep)*Volstep; return riskLots; } ''' # Insert the new function above 'double AccountBalance()' insert_index = content.find('double AccountBalance()') if insert_index != -1: content = content[:insert_index] + function_to_add + content[insert_index:] # Write the changes back to the file with open(file_path, 'w', encoding='utf-16-le') as file: file.write(content) print("File updated successfully.") except Exception as e: print(f"An error occurred: {e}") def main(): root = tk.Tk() root.title("File Selector") root.geometry('300x150') def select_file(): file_path = filedialog.askopenfilename( title="Select the .mq5 file", filetypes=[("MQL5 files", "*.mq5")] ) if file_path: replace_and_add_code(file_path) label.config(text="File Processed") else: label.config(text="No file selected.") label = tk.Label(root, text="Please select your .mq5 file") label.pack(pady=10) btn = tk.Button(root, text="Select File", command=select_file) btn.pack(pady=10) root.mainloop() if __name__ == "__main__": main()