0% found this document useful (0 votes)
13 views7 pages

xm

The document describes a UK100 Latency Arbitrage Expert Advisor (EA) designed for trading between a fast broker and a slow broker with an initial capital of $1,000 and a target of $6,000. It includes parameters for managing risks, calculating lot sizes, and handling trades, including opening and closing positions based on price differences and trailing stops. The EA also features mechanisms for reading fast broker prices from a file and managing trading conditions, with a maximum loss limit of 20% and a cap on the number of trades.

Uploaded by

Lobo S
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as TXT, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
13 views7 pages

xm

The document describes a UK100 Latency Arbitrage Expert Advisor (EA) designed for trading between a fast broker and a slow broker with an initial capital of $1,000 and a target of $6,000. It includes parameters for managing risks, calculating lot sizes, and handling trades, including opening and closing positions based on price differences and trailing stops. The EA also features mechanisms for reading fast broker prices from a file and managing trading conditions, with a maximum loss limit of 20% and a cap on the number of trades.

Uploaded by

Lobo S
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as TXT, PDF, TXT or read online on Scribd
You are on page 1/ 7

//+------------------------------------------------------------------+

//| UK100 Latency Arbitrage EA (Fast Broker vs Slow Broker) |


//| Starting Capital: $1,000, Target: $6,000, 20% Max Loss |
//| Spread on Slow Broker: $1.5 |
//| Fast Broker Price Feed: File-based (IC Markets) |
//+------------------------------------------------------------------+

#property copyright "Grok @ xAI"


#property link "https://x.ai"
#property version "1.04"

#include <Trade\Trade.mqh> // Include trading library

// Input Parameters
input double InitialCapital = 1000.0; // Starting capital in USD
input double TargetCapital = 6000.0; // Target capital in USD
input double MinLotSize = 0.1; // Minimum lot size
input double LossLimitPercent = 20.0; // Maximum loss limit in percentage
input double PriceDifferenceUSD = 5.0; // Minimum price difference to trigger
trade
input int ATRPeriod = 14; // ATR period for stop-loss
input double ATRMultiplier = 1.5; // ATR multiplier for initial stop-loss
input double TrailingStopUSD = 2.5; // Trailing stop in USD
input double Spread = 1.5; // Spread on slow broker for UK100Cash
input string FastPriceFilePath = "fastprice.txt"; // File path (relative to MQL5\
Files)
input int RetryAttempts = 3; // Number of retry attempts
input int RetryDelayMs = 200; // Delay between retries in milliseconds
input double RiskPercent = 1.0; // Risk per trade (%)

// Global Variables
CTrade trade; // Trading object
double currentCapital; // Current account balance
int tradeCount = 0; // Number of trades executed
bool isInitialized = false; // Initialization flag
datetime lastTradeTime = 0; // Track last trade time for delay
int atrHandle = INVALID_HANDLE; // Handle for ATR indicator
double atr[]; // Array for ATR values
ulong lastTicket = 0; // Track the last opened position ticket
double highestPriceSinceEntry = 0.0; // Track highest price for trailing stop
(buy)
double lowestPriceSinceEntry = 0.0; // Track lowest price for trailing stop
(sell)
double fastBrokerPrice = 0.0; // Fast broker price from IC Markets

//+------------------------------------------------------------------+
//| Expert Initialization Function |
//+------------------------------------------------------------------+
int OnInit()
{
// Ensure UK100Cash is available
if (!SymbolSelect("UK100Cash", true))
{
Print("Symbol UK100Cash not available!");
return(INIT_FAILED);
}

// Check initial capital requirement


currentCapital = AccountInfoDouble(ACCOUNT_BALANCE);
if (currentCapital < InitialCapital)
{
Print("Insufficient balance! Required: $", DoubleToString(InitialCapital, 2),
", Available: $", DoubleToString(currentCapital, 2));
return(INIT_FAILED);
}

// Initialize ATR indicator


atrHandle = iATR("UK100Cash", PERIOD_M1, ATRPeriod);
if (atrHandle == INVALID_HANDLE)
{
Print("Failed to initialize ATR indicator!");
return(INIT_FAILED);
}

// Log full file path for clarity


string fullPath = TerminalInfoString(TERMINAL_DATA_PATH) + "\\MQL5\\Files\\" +
FastPriceFilePath;
Print("Starting UK100 Latency Arbitrage EA");
Print("Initial Capital: $", DoubleToString(currentCapital, 2));
Print("Target Capital: $", DoubleToString(TargetCapital, 2));
Print("Maximum Loss Limit: ", DoubleToString(LossLimitPercent, 2), "% ($",
DoubleToString(InitialCapital * LossLimitPercent / 100, 2), ")");
Print("Assumed Spread on Slow Broker: $", DoubleToString(Spread, 2));
Print("Fast Price File Full Path: ", fullPath);
Print("Retry Attempts: ", RetryAttempts, " | Retry Delay: ", RetryDelayMs,
"ms");

// Check if auto-trading is enabled


if (TerminalInfoInteger(TERMINAL_TRADE_ALLOWED))
Print("Auto Trading is enabled.");
else
Print("Auto Trading is disabled. Please enable it in the MT5 toolbar!");

Print("--------------------------------------------------");

isInitialized = true;
return(INIT_SUCCEEDED);
}

//+------------------------------------------------------------------+
//| Expert Tick Function |
//+------------------------------------------------------------------+
void OnTick()
{
if (!isInitialized) return;

// Check termination conditions


double maxLoss = InitialCapital * (LossLimitPercent / 100);
if (currentCapital >= TargetCapital || currentCapital <= InitialCapital -
maxLoss || tradeCount >= 80)
{
Print("Stopping EA: Target reached, loss limit hit, or max trades
exceeded.");
PrintFinalStats();
ExpertRemove();
return;
}
// Enforce a 100ms delay between trades
if (TimeCurrent() - lastTradeTime < 0.1) return;

// Get slow broker prices


double slowBrokerBid = SymbolInfoDouble("UK100Cash", SYMBOL_BID);
double slowBrokerAsk = SymbolInfoDouble("UK100Cash", SYMBOL_ASK);
if (slowBrokerBid == 0 || slowBrokerAsk == 0)
{
Print("Failed to get prices for UK100Cash on slow broker!");
return;
}

// Read fast broker price from file


fastBrokerPrice = ReadFastBrokerPrice(slowBrokerAsk);

// Get ATR value for stop-loss calculation


ArraySetAsSeries(atr, true);
if (CopyBuffer(atrHandle, 0, 0, 3, atr) < 3) // Use 3 bars for smoother ATR
{
Print("Failed to copy ATR data!");
return;
}

// Calculate price differences


double priceDifferenceBuy = fastBrokerPrice - slowBrokerAsk;
double priceDifferenceSell = slowBrokerBid - fastBrokerPrice;

// Open new position if no positions exist


if (PositionsTotal() == 0 && tradeCount < 80)
{
double slDistance = atr[1] * ATRMultiplier; // Use previous bar's ATR for
stability
double lots = CalculateLotSize(RiskPercent, slDistance);

if (lots > 0)
{
double marginRequired;
if (!OrderCalcMargin(ORDER_TYPE_BUY, "UK100Cash", lots, slowBrokerAsk,
marginRequired))
{
Print("Margin calculation failed!");
return;
}
if (AccountInfoDouble(ACCOUNT_FREEMARGIN) < marginRequired)
{
Print("Insufficient margin for ", DoubleToString(lots, 2), " lots.");
return;
}

if (priceDifferenceBuy >= PriceDifferenceUSD)


{
double entry = slowBrokerAsk;
double sl = entry - slDistance;
if (trade.Buy(lots, "UK100Cash", entry, sl, 0, "Buy on Latency
Arbitrage"))
{
lastTradeTime = TimeCurrent();
tradeCount++;
lastTicket = trade.ResultDeal();
highestPriceSinceEntry = entry;
PrintTradeDetails("Buy", lots, entry, sl, 0, fastBrokerPrice);
}
}
else if (priceDifferenceSell >= PriceDifferenceUSD)
{
double entry = slowBrokerBid;
double sl = entry + slDistance;
if (trade.Sell(lots, "UK100Cash", entry, sl, 0, "Sell on Latency
Arbitrage"))
{
lastTradeTime = TimeCurrent();
tradeCount++;
lastTicket = trade.ResultDeal();
lowestPriceSinceEntry = entry;
PrintTradeDetails("Sell", lots, entry, sl, 0, fastBrokerPrice);
}
}
}
}

// Manage open positions with trailing stop


if (PositionsTotal() > 0)
{
if (PositionSelectByTicket(lastTicket))
{
double currentPrice = PositionGetDouble(POSITION_PRICE_CURRENT);
int positionType = PositionGetInteger(POSITION_TYPE);

if (positionType == POSITION_TYPE_BUY)
{
if (currentPrice > highestPriceSinceEntry)
highestPriceSinceEntry = currentPrice;
double trailingStop = highestPriceSinceEntry - TrailingStopUSD;
double currentSL = PositionGetDouble(POSITION_SL);
if (trailingStop > currentSL && currentPrice > trailingStop)
{
if (trade.PositionModify(lastTicket, trailingStop, 0))
Print("Trailing Stop updated for Buy: SL=",
DoubleToString(trailingStop, 2));
}
else if (currentPrice <= trailingStop)
{
ClosePosition(ticket, "Buy");
}
}
else if (positionType == POSITION_TYPE_SELL)
{
if (currentPrice < lowestPriceSinceEntry)
lowestPriceSinceEntry = currentPrice;
double trailingStop = lowestPriceSinceEntry + TrailingStopUSD;
double currentSL = PositionGetDouble(POSITION_SL);
if (trailingStop < currentSL && currentPrice < trailingStop)
{
if (trade.PositionModify(lastTicket, trailingStop, 0))
Print("Trailing Stop updated for Sell: SL=",
DoubleToString(trailingStop, 2));
}
else if (currentPrice >= trailingStop)
{
ClosePosition(ticket, "Sell");
}
}
}
}

currentCapital = AccountInfoDouble(ACCOUNT_BALANCE);
}

//+------------------------------------------------------------------+
//| Helper Functions |
//+------------------------------------------------------------------+

// Read fast broker price from file with retry mechanism


double ReadFastBrokerPrice(double slowBrokerAsk)
{
if (!FileIsExist(FastPriceFilePath))
{
Print("File does not exist at: ", FastPriceFilePath);
return slowBrokerAsk + 0.1; // Fallback price
}

int attempt = 0;
bool fileReadSuccess = false;
double price = 0.0;

while (attempt < RetryAttempts && !fileReadSuccess)


{
int fileHandle = FileOpen(FastPriceFilePath, FILE_READ | FILE_TXT |
FILE_SHARE_READ);
if (fileHandle != INVALID_HANDLE)
{
string priceStr = FileReadString(fileHandle);
FileClose(fileHandle);
if (priceStr != "" && StringToDouble(priceStr) > 0)
{
price = StringToDouble(priceStr);
fileReadSuccess = true;
Print("Fast Broker Price (IC Markets): ", DoubleToString(price, 2));
}
else
{
Print("Empty or invalid price data in file! Attempt ", attempt + 1, "
of ", RetryAttempts);
}
}
else
{
Print("Failed to read fast broker price file! Error: ", GetLastError(),
" Attempt ", attempt + 1, " of ", RetryAttempts);
}
if (!fileReadSuccess && attempt < RetryAttempts - 1)
Sleep(RetryDelayMs);
attempt++;
}

if (!fileReadSuccess)
{
Print("All attempts failed to read fast broker price file! Using fallback.");
price = slowBrokerAsk + 0.1;
}
return price;
}

// Calculate lot size based on risk percentage


double CalculateLotSize(double riskPercent, double slDistance)
{
double accountBalance = AccountInfoDouble(ACCOUNT_BALANCE);
double riskAmount = accountBalance * (riskPercent / 100);
double tickValue = SymbolInfoDouble("UK100Cash", SYMBOL_TRADE_TICK_VALUE);
double tickSize = SymbolInfoDouble("UK100Cash", SYMBOL_TRADE_TICK_SIZE);
if (tickValue == 0 || tickSize == 0)
{
Print("Failed to get tick value or size!");
return 0;
}

double slPoints = slDistance / tickSize;


double lots = riskAmount / (slPoints * tickValue);
return NormalizeDouble(MathMax(lots, MinLotSize), 2);
}

// Print trade details


void PrintTradeDetails(string direction, double lots, double entry, double sl,
double tp, double fastPrice)
{
Print("Trade ", tradeCount, " opened: ", direction,
", Lot=", DoubleToString(lots, 2),
", Entry=", DoubleToString(entry, 2),
", SL=", DoubleToString(sl, 2),
", Fast Price=", DoubleToString(fastPrice, 2),
", Spread Cost=$", DoubleToString(Spread, 2));
}

// Close position and log details


void ClosePosition(ulong ticket, string direction)
{
if (trade.PositionClose(ticket))
{
currentCapital = AccountInfoDouble(ACCOUNT_BALANCE);
double profit = PositionGetDouble(POSITION_PROFIT);
Print("Trade ", tradeCount, " closed (Trailing Stop): ",
direction, ", Capital=$", DoubleToString(currentCapital, 2),
", Profit=$", DoubleToString(profit, 2));
}
}

// Print final stats on termination


void PrintFinalStats()
{
Print("--------------------------------------------------");
Print("Final Capital: $", DoubleToString(currentCapital, 2));
Print("Total Profit: $", DoubleToString(currentCapital - InitialCapital, 2));
Print("Trades Executed: ", tradeCount);
}

//+------------------------------------------------------------------+
//| Expert Deinitialization Function |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
if (atrHandle != INVALID_HANDLE)
IndicatorRelease(atrHandle);
Print("EA stopped. Reason: ", reason);
}
//+------------------------------------------------------------------+
Print("Calculated Lot Size: ", DoubleToString(lots, 2));

You might also like