Skip to content

Instantly share code, notes, and snippets.

@tomas-rampas
Last active August 21, 2025 08:47
Show Gist options
  • Select an option

  • Save tomas-rampas/afc73134101e159b43354d83ad8b38cb to your computer and use it in GitHub Desktop.

Select an option

Save tomas-rampas/afc73134101e159b43354d83ad8b38cb to your computer and use it in GitHub Desktop.
//+------------------------------------------------------------------+
//| ATR_Position_Sizing.mq5 |
//| Equal Risk Allocation Based on ATR |
//+------------------------------------------------------------------+
#property copyright "2025"
#property version "1.02"
#property indicator_chart_window
#property indicator_plots 0
// Input parameters
input double InpCapitalThousands = 30.0; // Capital in thousands (e.g., 30 = $30,000)
input int InpATRPeriod = 13; // ATR Period
input color InpTableColor = clrWhite; // Table Text Color
input color InpHeaderColor = clrYellow; // Table Header Color
input color InpBgColor = clrBlack; // Table Background Color
input int InpFontSize = 10; // Font Size
input int InpXOffset = 20; // X Position from left
input int InpYOffset = 50; // Y Position from top
// Asset structure
struct AssetData
{
string symbol;
double price;
double atr;
double atr_usd;
double atr_percent;
double weight;
double allocation;
double units;
double risk_value;
};
// Global variables
AssetData assets[3];
int atr_handles[3];
double total_capital;
string display_text;
//+------------------------------------------------------------------+
//| Custom indicator initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
// Initialize capital
total_capital = InpCapitalThousands * 1000.0;
// Define assets
assets[0].symbol = "EURUSD";
assets[1].symbol = "GDAXI"; // DAX index
assets[2].symbol = "SP500"; // S&P 500
// Initialize ATR handles for each symbol
for(int i = 0; i < 3; i++)
{
atr_handles[i] = iATR(assets[i].symbol, PERIOD_CURRENT, InpATRPeriod);
if(atr_handles[i] == INVALID_HANDLE)
{
PrintFormat("Failed to create ATR handle for %s", assets[i].symbol);
return(INIT_FAILED);
}
}
// Set timer for regular updates (every 1 second)
EventSetTimer(1);
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Custom indicator deinitialization function |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
// Clean up ATR handles
for(int i = 0; i < 3; i++)
{
if(atr_handles[i] != INVALID_HANDLE)
IndicatorRelease(atr_handles[i]);
}
// Remove timer
EventKillTimer();
// Clear display
Comment("");
}
//+------------------------------------------------------------------+
//| Custom indicator iteration function |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total,
const int prev_calculated,
const datetime &time[],
const double &open[],
const double &high[],
const double &low[],
const double &close[],
const long &tick_volume[],
const long &volume[],
const int &spread[])
{
CalculatePositions();
DisplayTable();
return(rates_total);
}
//+------------------------------------------------------------------+
//| Timer function |
//+------------------------------------------------------------------+
void OnTimer()
{
CalculatePositions();
DisplayTable();
}
//+------------------------------------------------------------------+
//| Calculate position sizes |
//+------------------------------------------------------------------+
void CalculatePositions()
{
double eurusd_rate = 0;
// Get current EURUSD rate for conversion
if(SymbolInfoDouble("EURUSD", SYMBOL_BID, eurusd_rate))
{
if(eurusd_rate == 0) eurusd_rate = 1.1641; // Fallback value
}
else
{
eurusd_rate = 1.1641; // Use provided value as fallback
}
// Get prices and ATR values for each asset
for(int i = 0; i < 3; i++)
{
// Get current price
double bid = SymbolInfoDouble(assets[i].symbol, SYMBOL_BID);
if(bid > 0)
assets[i].price = bid;
else
{
// Use fallback values if symbols not available
if(assets[i].symbol == "EURUSD")
assets[i].price = 1.1641;
else if(assets[i].symbol == "GDAXI")
assets[i].price = 24270.6;
else if(assets[i].symbol == "SP500")
assets[i].price = 6396.7;
}
// Get ATR value
double atr_buffer[];
ArraySetAsSeries(atr_buffer, true);
if(CopyBuffer(atr_handles[i], 0, 0, 1, atr_buffer) > 0)
{
assets[i].atr = atr_buffer[0];
}
else
{
// Use fallback ATR values
if(assets[i].symbol == "EURUSD")
assets[i].atr = 0.00048;
else if(assets[i].symbol == "GDAXI")
assets[i].atr = 19.4;
else if(assets[i].symbol == "SP500")
assets[i].atr = 2.5;
}
// Convert to USD where necessary
if(assets[i].symbol == "GDAXI")
{
// DAX is in EUR, convert to USD
assets[i].atr_usd = assets[i].atr * eurusd_rate;
assets[i].price = assets[i].price * eurusd_rate; // Convert price to USD for calculations
}
else
{
assets[i].atr_usd = assets[i].atr;
}
// Calculate ATR as percentage of price
if(assets[i].price > 0)
assets[i].atr_percent = (assets[i].atr_usd / assets[i].price) * 100.0;
else
assets[i].atr_percent = 0;
}
// Calculate weights for equal risk allocation (inverse volatility)
double total_weight = 0;
for(int i = 0; i < 3; i++)
{
if(assets[i].atr_percent > 0)
assets[i].weight = 1.0 / (assets[i].atr_percent / 100.0);
else
assets[i].weight = 0;
total_weight += assets[i].weight;
}
// Calculate allocations and positions
for(int i = 0; i < 3; i++)
{
if(total_weight > 0)
{
// Calculate allocation percentage and dollar amount
double allocation_percent = assets[i].weight / total_weight;
assets[i].allocation = total_capital * allocation_percent;
// Calculate units to buy
if(assets[i].price > 0)
{
if(assets[i].symbol == "GDAXI")
{
// For DAX, we need to convert back to EUR price for unit calculation
double dax_eur_price = assets[i].price / eurusd_rate;
assets[i].units = assets[i].allocation / assets[i].price;
}
else
{
assets[i].units = assets[i].allocation / assets[i].price;
}
}
else
assets[i].units = 0;
// Calculate risk value (allocation * ATR%)
assets[i].risk_value = assets[i].allocation * (assets[i].atr_percent / 100.0);
}
}
}
//+------------------------------------------------------------------+
//| Pad string with underscores for consistent width |
//+------------------------------------------------------------------+
string PadString(string value, int targetWidth, bool padLeft = false)
{
int len = StringLen(value);
if(len >= targetWidth)
return StringSubstr(value, 0, targetWidth);
string result = value;
for(int i = len; i < targetWidth; i++)
{
if(padLeft)
result = "_" + result;
else
result = result + "_";
}
return result;
}
//+------------------------------------------------------------------+
//| Display table with results |
//+------------------------------------------------------------------+
void DisplayTable()
{
string text = "";
string separator = "================================================================================\n";
string separator2 = "--------------------------------------------------------------------------------\n";
// Title
text += separator;
text += StringFormat("ATR_POSITION_SIZING_-_CAPITAL:_$%,.0f\n", total_capital);
text += separator;
text += "\n";
// Create header row using tabs
text += "Symbol____Price_________ATR__________ATR%______Allocation____Units_________Risk____\n";
text += separator2;
// Data rows
for(int i = 0; i < 3; i++)
{
string symbol_col, price_col, atr_col, atr_pct_col, alloc_col, units_col, risk_col;
// Format symbol column (fixed width 10)
symbol_col = PadString(assets[i].symbol, 10);
// Format price column (fixed width 14)
if(assets[i].symbol == "EURUSD")
{
price_col = PadString(StringFormat("$%.5f", assets[i].price), 14);
}
else if(assets[i].symbol == "GDAXI")
{
double dax_eur_price = assets[i].price / 1.1641;
price_col = PadString(StringFormat("EUR%.1f", dax_eur_price), 14);
}
else // SP500
{
price_col = PadString(StringFormat("$%.1f", assets[i].price), 14);
}
// Format ATR column (fixed width 13)
if(assets[i].symbol == "EURUSD")
{
atr_col = PadString(StringFormat("%.6f", assets[i].atr), 13);
}
else
{
atr_col = PadString(StringFormat("%.2f", assets[i].atr), 13);
}
// Format ATR% column (fixed width 10)
atr_pct_col = PadString(StringFormat("%.4f%%", assets[i].atr_percent), 10);
// Format Allocation column (fixed width 14)
alloc_col = PadString(StringFormat("$%.2f", assets[i].allocation), 14);
// Format Units column (fixed width 14)
if(assets[i].symbol == "EURUSD")
{
units_col = PadString(StringFormat("%.2f", assets[i].units), 14);
}
else
{
units_col = PadString(StringFormat("%.4f", assets[i].units), 14);
}
// Format Risk column (fixed width 12)
risk_col = PadString(StringFormat("$%.2f", assets[i].risk_value), 12);
// Combine all columns
text += symbol_col + price_col + atr_col + atr_pct_col + alloc_col + units_col + risk_col + "\n";
}
text += separator2;
text += "\n";
// Allocation percentages
text += "ALLOCATION_PERCENTAGES:\n";
text += separator2;
double total_weight = 0;
for(int i = 0; i < 3; i++)
total_weight += assets[i].weight;
for(int i = 0; i < 3; i++)
{
double percent = (total_weight > 0) ? (assets[i].weight / total_weight * 100.0) : 0;
string symbol_name = PadString(assets[i].symbol + ":", 10);
string percent_str = StringFormat("%.2f%%", percent);
text += symbol_name + percent_str + "\n";
}
text += "\n";
text += separator2;
// Summary statistics
double total_risk = 0;
double total_alloc = 0;
for(int i = 0; i < 3; i++)
{
total_risk += assets[i].risk_value;
total_alloc += assets[i].allocation;
}
text += "SUMMARY_STATISTICS:\n";
text += separator2;
string label1 = PadString("Total_Allocated:", 25);
text += label1 + StringFormat("$%.2f\n", total_alloc);
string label2 = PadString("Average_Risk_per_Position:", 25);
text += label2 + StringFormat("$%.2f\n", total_risk/3.0);
string label3 = PadString("Total_Portfolio_Risk:", 25);
text += label3 + StringFormat("$%.2f\n", total_risk);
text += separator;
// Add timestamp
text += "Last_Update:_" + TimeToString(TimeCurrent(), TIME_DATE|TIME_SECONDS) + "\n";
// Display the formatted table
Comment(text);
}
//+------------------------------------------------------------------+
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment