Untitled
unknown
plain_text
7 months ago
26 kB
11
Indexable
//+------------------------------------------------------------------+
//| Determine trade direction based on indicators |
//+------------------------------------------------------------------+
int GetTradeDirection() {
if(UseRandomDirection) {
// Randomly choose direction
return MathRand() % 2;
}
// Use indicators for direction decision
// MACD
double macdMain = iMACD(Symbol(), 0, MACDFast, MACDSlow, MACDSignal, PRICE_CLOSE, MODE_MAIN, 0);
double macdSignal = iMACD(Symbol(), 0, MACDFast, MACDSlow, MACDSignal, PRICE_CLOSE, MODE_SIGNAL, 0);
double macdMain1 = iMACD(Symbol(), 0, MACDFast, MACDSlow, MACDSignal, PRICE_CLOSE, MODE_MAIN, 1);
double macdSignal1 = iMACD(Symbol(), 0, MACDFast, MACDSlow, MACDSignal, PRICE_CLOSE, MODE_SIGNAL, 1);
// EMA
double fastEMA = iMA(Symbol(), 0, FastEMA, 0, MODE_EMA, PRICE_CLOSE, 0);
double slowEMA = iMA(Symbol(), 0, SlowEMA, 0, MODE_EMA, PRICE_CLOSE, 0);
// RSI
double rsi = iRSI(Symbol(), 0, RSIPeriod, PRICE_CLOSE, 0);
// Calculate trend score
int trendScore = 0;
// MACD crossing up
if(macdMain > macdSignal && macdMain1 <= macdSignal1) trendScore++;
// MACD above zero
if(macdMain > 0) trendScore++;
// MACD above signal
if(macdMain > macdSignal) trendScore++;
// EMA trend
if(fastEMA > slowEMA) trendScore++;
// RSI trend
if(rsi < RSIOversold) trendScore++;
if(rsi > 50) trendScore++;
// Determine direction based on trend score (0-6)
// 0-2: Bearish, 3: Neutral, 4-6: Bullish
if(trendScore >= 4)
return 0; // Buy
else if(trendScore <= 2)
return 1; // Sell
else
return MathRand() % 2; // Neutral, random direction
}//+------------------------------------------------------------------+
//| XAUUSD Rebate Harvester |
//| Copyright 2025 |
//+------------------------------------------------------------------+
// Input Parameters
extern string RebateInfo = "--- Rebate Settings ---";
extern double RebatePerLot = 20.0; // USD Rebate per lot
extern bool IsSwapFree = true; // Set to true for swap-free accounts
extern bool CloseOnlyAtBreakeven = true; // Only close trades at breakeven or profit
extern bool UseRealTimeSpread = true; // Monitor spread in real-time for information
extern string TradingSettings = "--- Trading Settings ---";
extern double BaseLotSize = 0.01; // Starting lot size per trade
extern bool UseMaringale = true; // Use martingale strategy for losing trades
extern double MartingaleMultiplier = 2.0;// Multiplier for martingale strategy
extern int MaxMartingaleLevels = 5; // Maximum martingale levels allowed
extern int MinutesBetweenTrades = 1; // Wait time between trades
extern double MaxDailyLoss = 100.0; // Maximum daily loss in USD
extern bool UseRandomDirection = false; // Set to false to use trend indicator direction
extern bool CloseTradesEndOfDay = false; // No need to close at end of day for swap-free accounts
extern int MaxLossPips = 20; // Maximum loss in pips before martingale kicks in
extern string TimeFrameInfo = "EA optimized for M1 or M5 timeframes";
extern string DashboardSettings = "--- Dashboard Settings ---";
extern int DashboardCorner = 1; // Corner to display dashboard (0-3)
extern int DashboardXOffset = 10; // X offset from corner
extern int DashboardYOffset = 10; // Y offset from corner
extern color TextColor = clrWhite; // Dashboard text color
extern color ProfitColor = clrLimeGreen; // Profit color
extern color LossColor = clrRed; // Loss color
extern int FontSize = 9; // Dashboard font size
extern int MalaysiaGMTOffset = 8; // Malaysia time is GMT+8
extern int DailyResetHour = 7; // Hour to reset daily tracking (7am Malaysia time)
// Global Variables
datetime lastTradeTime = 0;
double dailyLoss = 0.0;
double dailyRebateTotal = 0.0;
double totalRebateCollected = 0.0;
int totalTradesTaken = 0;
int winningTrades = 0;
int losingTrades = 0;
int breakEvenTrades = 0;
double currentLotSize = 0.0;
int martingaleLevel = 0;
int lastTradeTicket = 0;
bool inMaringaleSequence = false;
datetime lastDayChecked = 0;
int magicNumber = 8675309;
string currentStatus = "Initializing...";
// Objects for dashboard
string objPrefix = "RebateEA_";
string dashboardLabels[10];
string dashboardValues[10];
int dashboardCount = 0;
//+------------------------------------------------------------------+
//| Calculate required number of lots to break even |
//+------------------------------------------------------------------+
double CalculateBreakEvenLots() {
// If BrokerSpread is $0.50 and RebatePerLot is $20
// We need to trade at least BrokerSpread/RebatePerLot = 0.025 lots to break even
if(RebatePerLot <= 0) return 0;
// For XAUUSD, we need to convert the spread from points to USD value
double spreadInUSD = BrokerSpread * 0.01; // Rough approximation: 1 point ≈ $0.01 for XAUUSD
return spreadInUSD / RebatePerLot;
}
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int OnInit() {
// Get current spread
double currentSpread = GetCurrentSpread();
// Display information
Print("Rebate EA initialized for XAUUSD");
Print("Rebate per lot: $", RebatePerLot);
Print("Current spread: ", currentSpread, " points");
Print("Every trade will earn $", RebatePerLot * BaseLotSize, " in rebate for ", BaseLotSize, " lot");
// Verify symbol is XAUUSD
if(Symbol() != "XAUUSD") {
Print("WARNING: This EA is designed for XAUUSD. Current symbol: ", Symbol());
}
// Verify timeframe is M1 or M5
if(Period() != PERIOD_M1 && Period() != PERIOD_M5) {
Print("WARNING: This EA is optimized for M1 or M5 timeframes. Current timeframe: ", PeriodToString(Period()));
}
// Initialize dashboard
currentStatus = "Trading for rebate";
CreateDashboard();
// Reset daily tracking
lastDayChecked = TimeCurrent();
dailyLoss = 0.0;
dailyRebateTotal = 0.0;
// Reset martingale settings
inMaringaleSequence = false;
martingaleLevel = 0;
currentLotSize = BaseLotSize;
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Convert period constant to string |
//+------------------------------------------------------------------+
string PeriodToString(int period) {
switch(period) {
case PERIOD_M1: return "M1";
case PERIOD_M5: return "M5";
case PERIOD_M15: return "M15";
case PERIOD_M30: return "M30";
case PERIOD_H1: return "H1";
case PERIOD_H4: return "H4";
case PERIOD_D1: return "D1";
case PERIOD_W1: return "W1";
case PERIOD_MN1: return "MN1";
default: return "Unknown";
}
}
//+------------------------------------------------------------------+
//| Convert server time to Malaysia time |
//+------------------------------------------------------------------+
datetime ServerToMalaysiaTime(datetime serverTime) {
// Get GMT time first
int serverGMTOffset = TimeGMTOffset() / 3600; // Convert seconds to hours
datetime gmtTime = serverTime - serverGMTOffset * 3600;
// Convert GMT to Malaysia time (GMT+8)
datetime malaysiaTime = gmtTime + MalaysiaGMTOffset * 3600;
return malaysiaTime;
}
//+------------------------------------------------------------------+
//| Check for day reset |
//+------------------------------------------------------------------+
void CheckDayReset() {
datetime currentServerTime = TimeCurrent();
datetime malaysiaTime = ServerToMalaysiaTime(currentServerTime);
// Extract hour in Malaysia time
int malaysiaHour = TimeHour(malaysiaTime);
int malaysiaDay = TimeDay(malaysiaTime);
int lastCheckedMalaysiaDay = TimeDay(ServerToMalaysiaTime(lastDayChecked));
// Reset at specified hour (7am Malaysia time)
if(malaysiaDay != lastCheckedMalaysiaDay && malaysiaHour >= DailyResetHour) {
// Calculate yesterday's rebate
double yesterdayRebate = dailyRebateTotal;
totalRebateCollected += yesterdayRebate;
// Reset daily tracking
dailyLoss = 0.0;
dailyRebateTotal = 0.0;
lastDayChecked = currentServerTime;
Print("New day - Reset daily tracking at ",
TimeHour(malaysiaTime), ":", TimeMinute(malaysiaTime), " Malaysia time. ",
"Yesterday's rebate: $", yesterdayRebate);
}
}
//+------------------------------------------------------------------+
//| Create and update dashboard |
//+------------------------------------------------------------------+
void CreateDashboard() {
// Clear any existing dashboard
for(int i = 0; i < dashboardCount; i++) {
ObjectDelete(dashboardLabels[i]);
ObjectDelete(dashboardValues[i]);
}
dashboardCount = 0;
// Font and colors defined in settings
// Start positions
int x = DashboardXOffset;
int y = DashboardYOffset;
int lineHeight = FontSize + 4;
// Get current spread
double currentSpread = GetCurrentSpread();
// Get Malaysia time
datetime malaysiaTime = ServerToMalaysiaTime(TimeCurrent());
string timeStr = TimeHour(malaysiaTime) + ":" +
(TimeMinute(malaysiaTime) < 10 ? "0" + TimeMinute(malaysiaTime) :
IntegerToString(TimeMinute(malaysiaTime))) + " MYT";
// Add current status at the top
AddDashboardRow("Status:", currentStatus, x, y, currentStatus == "Trading for rebate" ? ProfitColor :
StringFind(currentStatus, "Martingale") >= 0 ? clrOrange : TextColor);
y += lineHeight;
// Add Malaysia time
AddDashboardRow("Malaysia Time:", timeStr, x, y);
y += lineHeight;
// Add current spread
AddDashboardRow("Current Spread:", DoubleToString(currentSpread, 1) + " points", x, y);
y += lineHeight;
// Add rebate per trade
AddDashboardRow("Rebate per Trade:", "$" + DoubleToString(RebatePerLot * currentLotSize, 2), x, y, ProfitColor);
y += lineHeight;
// Add labels to dashboard
AddDashboardRow("Total Rebate:", DoubleToString(totalRebateCollected, 2) + " USD", x, y);
y += lineHeight;
AddDashboardRow("Today's Rebate:", DoubleToString(dailyRebateTotal, 2) + " USD", x, y);
y += lineHeight;
AddDashboardRow("Total Trades:", IntegerToString(totalTradesTaken), x, y);
y += lineHeight;
AddDashboardRow("Win/Loss/BE:", IntegerToString(winningTrades) + "/" +
IntegerToString(losingTrades) + "/" +
IntegerToString(breakEvenTrades), x, y);
y += lineHeight;
if(inMaringaleSequence) {
AddDashboardRow("Martingale Level:", IntegerToString(martingaleLevel) + " of " + IntegerToString(MaxMartingaleLevels), x, y, clrOrange);
y += lineHeight;
AddDashboardRow("Current Lot Size:", DoubleToString(currentLotSize, 2), x, y);
y += lineHeight;
}
// Add rebate calculation
double estimatedDailyRebate = RebatePerLot * totalTradesTaken * BaseLotSize / (MathMax(1, TimeDiffDays(TimeCurrent(), GetAccountOpenTime())));
AddDashboardRow("Est. Daily Rebate:", DoubleToString(estimatedDailyRebate, 2) + " USD", x, y);
}
//+------------------------------------------------------------------+
//| Add a row to the dashboard |
//+------------------------------------------------------------------+
void AddDashboardRow(string label, string value, int x, int y, color valueColor = CLR_NONE) {
string labelName = objPrefix + "Label" + IntegerToString(dashboardCount);
string valueName = objPrefix + "Value" + IntegerToString(dashboardCount);
// Default color handling
if(valueColor == CLR_NONE) {
valueColor = StringFind(value, "-") >= 0 ? LossColor : ProfitColor;
}
// Save names for later deletion
dashboardLabels[dashboardCount] = labelName;
dashboardValues[dashboardCount] = valueName;
// Create label object
ObjectCreate(labelName, OBJ_LABEL, 0, 0, 0);
ObjectSetText(labelName, label, FontSize, "Arial", TextColor);
ObjectSet(labelName, OBJPROP_CORNER, DashboardCorner);
ObjectSet(labelName, OBJPROP_XDISTANCE, x);
ObjectSet(labelName, OBJPROP_YDISTANCE, y);
// Create value object
ObjectCreate(valueName, OBJ_LABEL, 0, 0, 0);
ObjectSetText(valueName, value, FontSize, "Arial", valueColor);
ObjectSet(valueName, OBJPROP_CORNER, DashboardCorner);
ObjectSet(valueName, OBJPROP_XDISTANCE, x + 150);
ObjectSet(valueName, OBJPROP_YDISTANCE, y);
dashboardCount++;
}
//+------------------------------------------------------------------+
//| Update the dashboard |
//+------------------------------------------------------------------+
void UpdateDashboard() {
// Just recreate the dashboard
CreateDashboard();
}
//+------------------------------------------------------------------+
//| Get account open time (or use a default if not available) |
//+------------------------------------------------------------------+
datetime GetAccountOpenTime() {
// MT4 doesn't have a direct way to get account open time
// Using a fallback of 30 days if not explicitly tracked
datetime fallbackTime = TimeCurrent() - 30 * 24 * 60 * 60; // 30 days ago
return fallbackTime;
}
//+------------------------------------------------------------------+
//| Calculate difference in days between two dates |
//+------------------------------------------------------------------+
int TimeDiffDays(datetime time1, datetime time2) {
return (int)((time1 - time2) / (24 * 60 * 60));
}
//+------------------------------------------------------------------+
//| Check if we should close all trades (end of day) |
//+------------------------------------------------------------------+
void CheckEndOfDayClose() {
if(!CloseTradesEndOfDay) return;
datetime currentTime = TimeCurrent();
int currentHour = TimeHour(currentTime);
// Close all trades at the end of trading day (adjust times as needed)
if(currentHour == 23 && TimeMinute(currentTime) >= 45) {
CloseAllTrades();
Print("End of day - Closed all trades");
}
}
//+------------------------------------------------------------------+
//| Close all open trades |
//+------------------------------------------------------------------+
void CloseAllTrades() {
for(int i = OrdersTotal() - 1; i >= 0; i--) {
if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES)) {
if(OrderSymbol() == Symbol() && OrderMagicNumber() == magicNumber) {
bool result = false;
if(OrderType() == OP_BUY) {
result = OrderClose(OrderTicket(), OrderLots(), Bid, MaxSlippage, clrRed);
}
else if(OrderType() == OP_SELL) {
result = OrderClose(OrderTicket(), OrderLots(), Ask, MaxSlippage, clrRed);
}
if(!result) {
Print("Error closing order: ", GetLastError());
} else {
// Calculate rebate earned
double rebateEarned = RebatePerLot * OrderLots();
dailyRebateTotal += rebateEarned;
Print("Earned rebate from closed trade: $", rebateEarned);
}
}
}
}
// Reset martingale sequence
inMaringaleSequence = false;
martingaleLevel = 0;
currentLotSize = BaseLotSize;
// Update dashboard
UpdateDashboard();
}
//+------------------------------------------------------------------+
//| Update trailing stops for open trades |
//+------------------------------------------------------------------+
void UpdateTrailingStops() {
if(!UseTrailingStop) return;
for(int i = 0; i < OrdersTotal(); i++) {
if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES)) {
if(OrderSymbol() == Symbol() && OrderMagicNumber() == magicNumber) {
double currentStop = OrderStopLoss();
// For buy orders
if(OrderType() == OP_BUY) {
// Move to breakeven first if enough profit
if(BreakevenAfterPips > 0 &&
Bid - OrderOpenPrice() >= Point * BreakevenAfterPips * 10 &&
(currentStop < OrderOpenPrice() || currentStop == 0)) {
bool moved = OrderModify(OrderTicket(), OrderOpenPrice(), OrderOpenPrice(),
OrderTakeProfit(), 0, clrBlue);
if(moved) {
Print("Moved stop to breakeven for order #", OrderTicket());
}
}
// Then apply trailing stop
else if(Bid - OrderOpenPrice() > Point * TrailingStop * 10) {
double newStop = Bid - Point * TrailingStop * 10;
if(currentStop < newStop - Point) { // Only modify if significant difference
bool trailed = OrderModify(OrderTicket(), OrderOpenPrice(), newStop,
OrderTakeProfit(), 0, clrBlue);
if(trailed) {
Print("Updated trailing stop for order #", OrderTicket());
}
}
}
}
// For sell orders
else if(OrderType() == OP_SELL) {
// Move to breakeven first if enough profit
if(BreakevenAfterPips > 0 &&
OrderOpenPrice() - Ask >= Point * BreakevenAfterPips * 10 &&
(currentStop > OrderOpenPrice() || currentStop == 0)) {
bool moved = OrderModify(OrderTicket(), OrderOpenPrice(), OrderOpenPrice(),
OrderTakeProfit(), 0, clrRed);
if(moved) {
Print("Moved stop to breakeven for order #", OrderTicket());
}
}
// Then apply trailing stop
else if(OrderOpenPrice() - Ask > Point * TrailingStop * 10) {
double newStop = Ask + Point * TrailingStop * 10;
if(currentStop > newStop + Point || currentStop == 0) { // Only modify if significant difference
bool trailed = OrderModify(OrderTicket(), OrderOpenPrice(), newStop,
OrderTakeProfit(), 0, clrRed);
if(trailed) {
Print("Updated trailing stop for order #", OrderTicket());
}
}
}
}
}
}
}
}
//+------------------------------------------------------------------+
//| Check for trades that should be closed |
//+------------------------------------------------------------------+
void CheckAndCloseHeldTrades() {
for(int i = OrdersTotal() - 1; i >= 0; i--) {
if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES)) {
if(OrderSymbol() == Symbol() && OrderMagicNumber() == magicNumber) {
// Check for maximum hold time (prevent trades staying open forever)
if(TimeCurrent() - OrderOpenTime() >= MaxTradeHoldTimeHours * 3600) {
// Only close if at breakeven or profit when CloseOnlyAtBreakeven is true
if(!CloseOnlyAtBreakeven || OrderProfit() >= 0) {
bool result = false;
if(OrderType() == OP_BUY) {
result = OrderClose(OrderTicket(), OrderLots(), Bid, MaxSlippage, clrRed);
}
else if(OrderType() == OP_SELL) {
result = OrderClose(OrderTicket(), OrderLots(), Ask, MaxSlippage, clrRed);
}
if(result) {
Print("Closed trade #", OrderTicket(), " after maximum hold time with profit: ", OrderProfit());
} else {
Print("Error closing order after hold time: ", GetLastError());
}
}
}
}
}
}
}
//+------------------------------------------------------------------+
//| Update daily profit/loss tracking |
//+------------------------------------------------------------------+
void UpdateDailyPnL() {
static double lastAccountBalance = AccountBalance();
double currentBalance = AccountBalance();
// If balance decreased, update daily loss
if(currentBalance < lastAccountBalance) {
dailyLoss += (lastAccountBalance - currentBalance);
}
lastAccountBalance = currentBalance;
// Check if we hit maximum daily loss
if(dailyLoss >= MaxDailyLoss) {
Print("Maximum daily loss reached. Stopping trading for today.");
CloseAllTrades();
}
// Update dashboard
UpdateDashboard();
}
//+------------------------------------------------------------------+
//| Open a new trade |
//+------------------------------------------------------------------+
void OpenNewTrade() {
// If we're already in a martingale sequence, don't open a new trade
if(inMaringaleSequence) return;
// If we already have an open trade, don't open another one
if(CountOpenTrades() > 0) return;
// Determine trade direction based on indicators
int direction = GetTradeDirection();
// Use base lot size for new trades
currentLotSize = BaseLotSize;
// Open the trade and store its ticket number
lastTradeTicket = OpenSpecificTrade(direction, currentLotSize);
} direction (based on indicators or random)
int direction = GetTradeDirection();
int ticket = -1;
if(direction == 0) {
// Buy order
ticket = OrderSend(Symbol(), OP_BUY, LotSize, Ask, MaxSlippage,
StopLoss > 0 ? Ask - Point * StopLoss * 10 : 0,
TakeProfit > 0 ? Ask + Point * TakeProfit * 10 : 0,
"RebateHarvester", magicNumber, 0, clrBlue);
} else {
// Sell order
ticket = OrderSend(Symbol(), OP_SELL, LotSize, Bid, MaxSlippage,
StopLoss > 0 ? Bid + Point * StopLoss * 10 : 0,
TakeProfit > 0 ? Bid - Point * TakeProfit * 10 : 0,
"RebateHarvester", magicNumber, 0, clrRed);
}
if(ticket < 0) {
Print("Error opening trade: ", GetLastError());
} else {
lastTradeTime = TimeCurrent();
Print("Opened trade #", ticket, " Direction: ", (direction == 0 ? "Buy" : "Sell"));
}
}
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick() {
// Check for day reset (based on Malaysia time)
CheckDayReset();
// Update trailing stops
UpdateTrailingStops();
// Update daily P&L
UpdateDailyPnL();
// Update current status if not in special mode
if(!inMaringaleSequence && CountOpenTrades() > 0) {
currentStatus = "Trading for rebate";
} else if(CountOpenTrades() == 0 && !inMaringaleSequence) {
currentStatus = "Waiting to open trade";
}
// Check trades that need to be closed or martingaled
CheckAndCloseHeldTrades();
// Check for end of day closing (if enabled)
if(!IsSwapFree) {
CheckEndOfDayClose();
}
// If we've hit maximum daily loss, don't open new trades
if(dailyLoss >= MaxDailyLoss) {
currentStatus = "Daily loss limit reached";
UpdateDashboard();
return;
}
// Check for time between trades
if(TimeCurrent() - lastTradeTime < MinutesBetweenTrades * 60) return;
// Open a new trade if we don't have any open
if(CountOpenTrades() == 0) {
currentStatus = "Opening new trade";
UpdateDashboard();
OpenNewTrade();
}
}
//+------------------------------------------------------------------+
//| Expert deinitialization function |
//+------------------------------------------------------------------+
void OnDeinit(const int reason) {
// Clean up dashboard objects
for(int i = 0; i < dashboardCount; i++) {
ObjectDelete(dashboardLabels[i]);
ObjectDelete(dashboardValues[i]);
}
Print("Rebate Harvester EA stopped");
Print("Total rebate collected: $", totalRebateCollected + dailyRebateTotal);
Print("Total trades taken: ", totalTradesTaken);
Print("Winning/Losing/Breakeven trades: ", winningTrades, "/", losingTrades, "/", breakEvenTrades);
}
//+------------------------------------------------------------------+Editor is loading...
Leave a Comment