Update
This commit is contained in:
@@ -0,0 +1,75 @@
|
||||
# Pepperstone US - Symbol Setup Guide
|
||||
|
||||
## Finding Correct Symbol Names in MetaTrader 5
|
||||
|
||||
### Step-by-Step Instructions:
|
||||
|
||||
1. **Open Market Watch Window**
|
||||
- Press `Ctrl+M` or go to `View > Market Watch`
|
||||
|
||||
2. **Show All Symbols**
|
||||
- Right-click in the Market Watch window
|
||||
- Select `Show All` or `Symbols`
|
||||
- This shows all available symbols from your broker
|
||||
|
||||
3. **Search for Your Symbols**
|
||||
- Use the search box in the Market Watch window
|
||||
- Search for: "AAPL", "MSFT", "NVDA", "TSLA", "BTCUSD", "XAUUSD"
|
||||
|
||||
4. **Note the Exact Symbol Name**
|
||||
- The symbol name shown in Market Watch is what you need to use
|
||||
- Common formats for Pepperstone US:
|
||||
- Stocks: `AAPL.US`, `MSFT.US`, `NVDA.US`, `TSLA.US`
|
||||
- Or: `NASDAQ:AAPL`, `NASDAQ:MSFT`, etc.
|
||||
- Or: Just `AAPL`, `MSFT`, etc. (if available)
|
||||
|
||||
5. **Add to Market Watch**
|
||||
- Double-click the symbol to add it to your Market Watch
|
||||
- Or right-click and select `Show`
|
||||
|
||||
6. **Update EA Inputs**
|
||||
- Open the EA inputs in MetaTrader 5
|
||||
- Update each symbol parameter with the exact name from Market Watch
|
||||
|
||||
## Common Pepperstone US Symbol Formats
|
||||
|
||||
### US Stocks:
|
||||
- **Apple**: `AAPL.US` or `NASDAQ:AAPL` or `AAPL`
|
||||
- **Microsoft**: `MSFT.US` or `NASDAQ:MSFT` or `MSFT`
|
||||
- **NVIDIA**: `NVDA.US` or `NASDAQ:NVDA` or `NVDA`
|
||||
- **Tesla**: `TSLA.US` or `NASDAQ:TSLA` or `TSLA`
|
||||
|
||||
### Cryptocurrencies:
|
||||
- **Bitcoin**: `BTCUSD` or `BTC/USD` or `BTCUSD.c`
|
||||
|
||||
### Precious Metals:
|
||||
- **Gold**: `XAUUSD` or `GOLD` or `XAU/USD`
|
||||
|
||||
## Important Notes:
|
||||
|
||||
1. **Symbol Names are Case-Sensitive**: Use exact capitalization
|
||||
2. **Add Symbols to Market Watch**: Symbols must be in Market Watch for the EA to access them
|
||||
3. **Check Trading Hours**: US stocks trade during US market hours (9:30 AM - 4:00 PM ET)
|
||||
4. **CFD vs Stock**: Pepperstone offers CFDs on stocks, not actual stocks
|
||||
5. **Spread**: Check the spread for each symbol - some may have wider spreads
|
||||
|
||||
## Troubleshooting:
|
||||
|
||||
### If Symbol Not Found:
|
||||
1. Check if you're connected to Pepperstone US server
|
||||
2. Verify your account type supports the symbol
|
||||
3. Contact Pepperstone support for symbol availability
|
||||
4. Check if symbol requires special account permissions
|
||||
|
||||
### If EA Shows "Symbol Not Available":
|
||||
1. Make sure symbol is added to Market Watch
|
||||
2. Verify symbol name matches exactly (including dots, colons, etc.)
|
||||
3. Check broker connection status
|
||||
4. Try different symbol format variations
|
||||
|
||||
## Testing Symbols:
|
||||
|
||||
You can test if a symbol works by:
|
||||
1. Opening a chart with that symbol
|
||||
2. If chart opens successfully, the symbol name is correct
|
||||
3. Use that exact symbol name in the EA inputs
|
||||
@@ -0,0 +1,607 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| PerformanceEvaluator.mqh |
|
||||
//| Copyright 2025, MetaQuotes Ltd. |
|
||||
//| https://www.mql5.com |
|
||||
//+------------------------------------------------------------------+
|
||||
#property copyright "Copyright 2025, MetaQuotes Ltd."
|
||||
#property link "https://www.mql5.com"
|
||||
#property version "1.00"
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Performance Metrics Structure |
|
||||
//+------------------------------------------------------------------+
|
||||
struct StrategyPerformance {
|
||||
string strategyName;
|
||||
string symbol; // Store symbol to determine if it's a stock
|
||||
int magicNumber;
|
||||
double initialLotSize;
|
||||
double currentLotSize;
|
||||
double quarterProfit;
|
||||
double quarterTrades;
|
||||
double quarterWins;
|
||||
double quarterLosses;
|
||||
double maxDrawdown;
|
||||
double winRate;
|
||||
datetime quarterStart;
|
||||
datetime quarterEnd;
|
||||
bool isActive;
|
||||
bool inPenaltyMode; // True if strategy is in penalty (worst performer)
|
||||
double lotSizeBeforePenalty; // Store lot size before penalty
|
||||
datetime penaltyStartTime; // When penalty started
|
||||
};
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Global Performance Tracking |
|
||||
//+------------------------------------------------------------------+
|
||||
StrategyPerformance strategyPerformances[];
|
||||
int totalStrategies = 0;
|
||||
datetime lastMonthCheck = 0;
|
||||
datetime currentMonthStart = 0;
|
||||
datetime currentMonthEnd = 0;
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Performance Adjustment Parameters |
|
||||
//+------------------------------------------------------------------+
|
||||
input group "=== Performance Evaluation Settings ==="
|
||||
input bool PE_EnableAutoAdjustment = true; // Enable automatic lot size adjustment
|
||||
input double PE_LotSizeIncreasePercent = 10.0; // % increase for top-ranked strategies
|
||||
input double PE_LotSizeDecreasePercent = 10.0; // % decrease for bottom-ranked strategies
|
||||
input double PE_MinLotSize = 0.01; // Minimum lot size for forex/crypto
|
||||
input double PE_MinLotSizeStocks = 5.0; // Minimum lot size for stocks (5-10 range)
|
||||
input double PE_MaxLotSize = 100.0; // Maximum lot size after adjustment
|
||||
input int PE_TopPerformersCount = 3; // Number of top strategies to increase lot size
|
||||
input int PE_BottomPerformersCount = 3; // Number of bottom strategies to decrease lot size
|
||||
input bool PE_UseWinRateWeight = true; // Consider win rate in ranking (50% profit, 50% win rate)
|
||||
input bool PE_EnableBlitzPlay = true; // Enable blitz play: worst performer gets minimum lot size penalty
|
||||
input bool PE_EnableLogging = true; // Enable performance logging
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Initialize Performance Tracking |
|
||||
//+------------------------------------------------------------------+
|
||||
void InitPerformanceTracking()
|
||||
{
|
||||
// Calculate current month dates
|
||||
MqlDateTime dt;
|
||||
TimeToStruct(TimeCurrent(), dt);
|
||||
|
||||
// Determine month start (first day of current month)
|
||||
dt.day = 1;
|
||||
dt.hour = 0;
|
||||
dt.min = 0;
|
||||
dt.sec = 0;
|
||||
currentMonthStart = StructToTime(dt);
|
||||
|
||||
// Calculate month end (first day of next month - 1 second)
|
||||
dt.mon += 1;
|
||||
if(dt.mon > 12)
|
||||
{
|
||||
dt.mon = 1;
|
||||
dt.year++;
|
||||
}
|
||||
currentMonthEnd = StructToTime(dt) - 1; // End of last day of month
|
||||
|
||||
lastMonthCheck = TimeCurrent();
|
||||
|
||||
if(PE_EnableLogging)
|
||||
{
|
||||
Print("Performance Evaluator: Initialized");
|
||||
Print("Current Month Start: ", TimeToString(currentMonthStart));
|
||||
Print("Current Month End: ", TimeToString(currentMonthEnd));
|
||||
}
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Check if Symbol is a Stock |
|
||||
//+------------------------------------------------------------------+
|
||||
bool IsStockSymbol(string symbol)
|
||||
{
|
||||
// Check if symbol contains common stock indicators
|
||||
if(StringFind(symbol, ".US") >= 0) return true;
|
||||
if(StringFind(symbol, "NASDAQ:") >= 0) return true;
|
||||
if(StringFind(symbol, "NYSE:") >= 0) return true;
|
||||
|
||||
// Note: Symbol category check removed to avoid enum conversion issues
|
||||
// String-based checks (.US, NASDAQ:, NYSE:, common tickers) are sufficient
|
||||
|
||||
// Common stock tickers (without .US suffix)
|
||||
string commonStocks[] = {"AAPL", "MSFT", "NVDA", "TSLA", "GOOGL", "AMZN", "META", "NFLX"};
|
||||
for(int i = 0; i < ArraySize(commonStocks); i++)
|
||||
{
|
||||
if(StringFind(symbol, commonStocks[i]) == 0) return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get Minimum Lot Size for Symbol |
|
||||
//+------------------------------------------------------------------+
|
||||
double GetMinLotSizeForSymbol(string symbol)
|
||||
{
|
||||
if(IsStockSymbol(symbol))
|
||||
return PE_MinLotSizeStocks;
|
||||
else
|
||||
return PE_MinLotSize;
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Register Strategy for Performance Tracking |
|
||||
//+------------------------------------------------------------------+
|
||||
void RegisterStrategy(string strategyName, int magicNumber, double initialLotSize, string symbol = "")
|
||||
{
|
||||
// Check if strategy already registered
|
||||
for(int i = 0; i < ArraySize(strategyPerformances); i++)
|
||||
{
|
||||
if(strategyPerformances[i].strategyName == strategyName &&
|
||||
strategyPerformances[i].magicNumber == magicNumber)
|
||||
{
|
||||
if(PE_EnableLogging)
|
||||
Print("Performance Evaluator: Strategy '", strategyName, "' already registered");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Add new strategy
|
||||
int newSize = ArraySize(strategyPerformances) + 1;
|
||||
ArrayResize(strategyPerformances, newSize);
|
||||
|
||||
strategyPerformances[newSize - 1].strategyName = strategyName;
|
||||
strategyPerformances[newSize - 1].symbol = symbol;
|
||||
strategyPerformances[newSize - 1].magicNumber = magicNumber;
|
||||
strategyPerformances[newSize - 1].initialLotSize = initialLotSize;
|
||||
// Start with minimum lot size for safety (symbol-specific minimum)
|
||||
double minLot = GetMinLotSizeForSymbol(symbol);
|
||||
strategyPerformances[newSize - 1].currentLotSize = minLot;
|
||||
strategyPerformances[newSize - 1].quarterProfit = 0.0;
|
||||
strategyPerformances[newSize - 1].quarterTrades = 0;
|
||||
strategyPerformances[newSize - 1].quarterWins = 0;
|
||||
strategyPerformances[newSize - 1].quarterLosses = 0;
|
||||
strategyPerformances[newSize - 1].maxDrawdown = 0.0;
|
||||
strategyPerformances[newSize - 1].winRate = 0.0;
|
||||
strategyPerformances[newSize - 1].quarterStart = currentMonthStart;
|
||||
strategyPerformances[newSize - 1].quarterEnd = currentMonthEnd;
|
||||
strategyPerformances[newSize - 1].isActive = true;
|
||||
strategyPerformances[newSize - 1].inPenaltyMode = false;
|
||||
strategyPerformances[newSize - 1].lotSizeBeforePenalty = initialLotSize;
|
||||
strategyPerformances[newSize - 1].penaltyStartTime = 0;
|
||||
|
||||
totalStrategies = newSize;
|
||||
|
||||
if(PE_EnableLogging)
|
||||
Print("Performance Evaluator: Registered strategy '", strategyName,
|
||||
"' (Magic: ", magicNumber, ", Initial Lot: ", initialLotSize, ")");
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Update Strategy Performance Metrics |
|
||||
//+------------------------------------------------------------------+
|
||||
void UpdateStrategyPerformance(string strategyName, int magicNumber)
|
||||
{
|
||||
for(int i = 0; i < ArraySize(strategyPerformances); i++)
|
||||
{
|
||||
if(strategyPerformances[i].strategyName == strategyName &&
|
||||
strategyPerformances[i].magicNumber == magicNumber &&
|
||||
strategyPerformances[i].isActive)
|
||||
{
|
||||
// Calculate performance for current quarter
|
||||
double totalProfit = 0.0;
|
||||
int totalTrades = 0;
|
||||
int wins = 0;
|
||||
int losses = 0;
|
||||
double maxDD = 0.0;
|
||||
double peakBalance = 0.0;
|
||||
|
||||
// Scan all closed deals in current quarter
|
||||
datetime quarterStart = strategyPerformances[i].quarterStart;
|
||||
datetime quarterEnd = strategyPerformances[i].quarterEnd;
|
||||
|
||||
// Select history for the quarter
|
||||
if(HistorySelect(quarterStart, quarterEnd))
|
||||
{
|
||||
int totalDeals = HistoryDealsTotal();
|
||||
for(int j = 0; j < totalDeals; j++)
|
||||
{
|
||||
ulong ticket = HistoryDealGetTicket(j);
|
||||
if(ticket > 0)
|
||||
{
|
||||
long dealMagic = HistoryDealGetInteger(ticket, DEAL_MAGIC);
|
||||
if(dealMagic == magicNumber)
|
||||
{
|
||||
double profit = HistoryDealGetDouble(ticket, DEAL_PROFIT);
|
||||
double swap = HistoryDealGetDouble(ticket, DEAL_SWAP);
|
||||
double commission = HistoryDealGetDouble(ticket, DEAL_COMMISSION);
|
||||
double totalDealProfit = profit + swap + commission;
|
||||
|
||||
totalProfit += totalDealProfit;
|
||||
totalTrades++;
|
||||
|
||||
if(totalDealProfit > 0)
|
||||
wins++;
|
||||
else if(totalDealProfit < 0)
|
||||
losses++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Calculate win rate
|
||||
double winRate = 0.0;
|
||||
if(totalTrades > 0)
|
||||
winRate = (double)wins / (double)totalTrades * 100.0;
|
||||
|
||||
// Update metrics
|
||||
strategyPerformances[i].quarterProfit = totalProfit;
|
||||
strategyPerformances[i].quarterTrades = totalTrades;
|
||||
strategyPerformances[i].quarterWins = wins;
|
||||
strategyPerformances[i].quarterLosses = losses;
|
||||
strategyPerformances[i].winRate = winRate;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Strategy Ranking Structure |
|
||||
//+------------------------------------------------------------------+
|
||||
struct StrategyRank {
|
||||
int index;
|
||||
double score;
|
||||
};
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Calculate Strategy Score for Ranking |
|
||||
//+------------------------------------------------------------------+
|
||||
double CalculateStrategyScore(int strategyIndex)
|
||||
{
|
||||
double profit = strategyPerformances[strategyIndex].quarterProfit;
|
||||
double winRate = strategyPerformances[strategyIndex].winRate;
|
||||
double trades = strategyPerformances[strategyIndex].quarterTrades;
|
||||
|
||||
// Normalize profit (scale to 0-100 range, assuming max profit of $1000)
|
||||
double normalizedProfit = MathMin(profit / 10.0, 100.0);
|
||||
if(profit < 0) normalizedProfit = profit / 5.0; // Penalize losses more
|
||||
|
||||
// Calculate score
|
||||
double score = 0.0;
|
||||
if(PE_UseWinRateWeight)
|
||||
{
|
||||
// 50% profit, 50% win rate (if enough trades)
|
||||
if(trades >= 5)
|
||||
score = (normalizedProfit * 0.5) + (winRate * 0.5);
|
||||
else
|
||||
score = normalizedProfit; // Not enough trades, use profit only
|
||||
}
|
||||
else
|
||||
{
|
||||
// Profit only
|
||||
score = normalizedProfit;
|
||||
}
|
||||
|
||||
return score;
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Check if Month Ended and Evaluate Performance |
|
||||
//+------------------------------------------------------------------+
|
||||
void CheckMonthEnd()
|
||||
{
|
||||
datetime now = TimeCurrent();
|
||||
|
||||
// Check if we've entered a new month
|
||||
if(now >= currentMonthEnd)
|
||||
{
|
||||
if(PE_EnableLogging)
|
||||
Print("Performance Evaluator: Month ended. Evaluating and ranking strategies...");
|
||||
|
||||
// Update performance metrics for all strategies
|
||||
for(int i = 0; i < ArraySize(strategyPerformances); i++)
|
||||
{
|
||||
if(strategyPerformances[i].isActive)
|
||||
{
|
||||
UpdateStrategyPerformance(strategyPerformances[i].strategyName,
|
||||
strategyPerformances[i].magicNumber);
|
||||
}
|
||||
}
|
||||
|
||||
// Rank strategies
|
||||
int activeCount = 0;
|
||||
for(int i = 0; i < ArraySize(strategyPerformances); i++)
|
||||
{
|
||||
if(strategyPerformances[i].isActive)
|
||||
activeCount++;
|
||||
}
|
||||
|
||||
if(activeCount > 0)
|
||||
{
|
||||
// Create ranking array
|
||||
StrategyRank ranks[];
|
||||
ArrayResize(ranks, activeCount);
|
||||
int rankIndex = 0;
|
||||
|
||||
for(int i = 0; i < ArraySize(strategyPerformances); i++)
|
||||
{
|
||||
if(strategyPerformances[i].isActive)
|
||||
{
|
||||
ranks[rankIndex].index = i;
|
||||
ranks[rankIndex].score = CalculateStrategyScore(i);
|
||||
rankIndex++;
|
||||
}
|
||||
}
|
||||
|
||||
// Sort by score (descending - highest score first)
|
||||
for(int i = 0; i < activeCount - 1; i++)
|
||||
{
|
||||
for(int j = i + 1; j < activeCount; j++)
|
||||
{
|
||||
if(ranks[j].score > ranks[i].score)
|
||||
{
|
||||
StrategyRank temp = ranks[i];
|
||||
ranks[i] = ranks[j];
|
||||
ranks[j] = temp;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Adjust lot sizes based on ranking
|
||||
if(PE_EnableAutoAdjustment)
|
||||
{
|
||||
// Increase top performers (skip if in penalty mode)
|
||||
int topCount = MathMin(PE_TopPerformersCount, activeCount);
|
||||
for(int i = 0; i < topCount; i++)
|
||||
{
|
||||
int strategyIdx = ranks[i].index;
|
||||
|
||||
// Skip if strategy is in penalty mode
|
||||
if(strategyPerformances[strategyIdx].inPenaltyMode)
|
||||
continue;
|
||||
|
||||
double oldLotSize = strategyPerformances[strategyIdx].currentLotSize;
|
||||
double newLotSize = oldLotSize * (1.0 + PE_LotSizeIncreasePercent / 100.0);
|
||||
|
||||
if(newLotSize > PE_MaxLotSize)
|
||||
newLotSize = PE_MaxLotSize;
|
||||
|
||||
strategyPerformances[strategyIdx].currentLotSize = newLotSize;
|
||||
|
||||
if(PE_EnableLogging)
|
||||
Print("Performance Evaluator: Rank #", (i+1), " - Increasing '",
|
||||
strategyPerformances[strategyIdx].strategyName,
|
||||
"' lot size from ", oldLotSize, " to ", newLotSize,
|
||||
" (Score: ", DoubleToString(ranks[i].score, 2),
|
||||
", Profit: $", DoubleToString(strategyPerformances[strategyIdx].quarterProfit, 2),
|
||||
", Win Rate: ", DoubleToString(strategyPerformances[strategyIdx].winRate, 2), "%)");
|
||||
}
|
||||
|
||||
// Decrease bottom performers (skip worst one if blitz play is enabled)
|
||||
int bottomCount = MathMin(PE_BottomPerformersCount, activeCount);
|
||||
int startIdx = activeCount - bottomCount;
|
||||
|
||||
// If blitz play is enabled, skip the worst performer (it will get minimum penalty)
|
||||
if(PE_EnableBlitzPlay && activeCount > 0)
|
||||
startIdx = activeCount - bottomCount + 1;
|
||||
|
||||
for(int i = startIdx; i < activeCount; i++)
|
||||
{
|
||||
int strategyIdx = ranks[i].index;
|
||||
|
||||
// Skip if strategy is in penalty mode
|
||||
if(strategyPerformances[strategyIdx].inPenaltyMode)
|
||||
continue;
|
||||
|
||||
double oldLotSize = strategyPerformances[strategyIdx].currentLotSize;
|
||||
double newLotSize = oldLotSize * (1.0 - PE_LotSizeDecreasePercent / 100.0);
|
||||
|
||||
// Use symbol-specific minimum lot size
|
||||
double minLot = GetMinLotSizeForSymbol(strategyPerformances[strategyIdx].symbol);
|
||||
if(newLotSize < minLot)
|
||||
newLotSize = minLot;
|
||||
|
||||
strategyPerformances[strategyIdx].currentLotSize = newLotSize;
|
||||
|
||||
if(PE_EnableLogging)
|
||||
Print("Performance Evaluator: Rank #", (i+1), " - Decreasing '",
|
||||
strategyPerformances[strategyIdx].strategyName,
|
||||
"' lot size from ", oldLotSize, " to ", newLotSize,
|
||||
" (Score: ", DoubleToString(ranks[i].score, 2),
|
||||
", Profit: $", DoubleToString(strategyPerformances[strategyIdx].quarterProfit, 2),
|
||||
", Win Rate: ", DoubleToString(strategyPerformances[strategyIdx].winRate, 2), "%)");
|
||||
}
|
||||
}
|
||||
|
||||
// Blitz Play: Apply penalty to worst performer
|
||||
if(PE_EnableBlitzPlay && activeCount > 0)
|
||||
{
|
||||
// Find worst performer (last in ranking)
|
||||
int worstIdx = ranks[activeCount - 1].index;
|
||||
|
||||
// Remove penalty from previous worst performer (if any)
|
||||
for(int i = 0; i < ArraySize(strategyPerformances); i++)
|
||||
{
|
||||
if(strategyPerformances[i].isActive && strategyPerformances[i].inPenaltyMode)
|
||||
{
|
||||
// Check if penalty period has passed (one month)
|
||||
if(now - strategyPerformances[i].penaltyStartTime >= 2592000) // ~30 days
|
||||
{
|
||||
// Restore lot size to before penalty
|
||||
strategyPerformances[i].currentLotSize = strategyPerformances[i].lotSizeBeforePenalty;
|
||||
strategyPerformances[i].inPenaltyMode = false;
|
||||
strategyPerformances[i].penaltyStartTime = 0;
|
||||
|
||||
if(PE_EnableLogging)
|
||||
Print("Blitz Play: Penalty removed from '", strategyPerformances[i].strategyName,
|
||||
"'. Lot size restored to ", strategyPerformances[i].currentLotSize);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Apply penalty to new worst performer
|
||||
if(!strategyPerformances[worstIdx].inPenaltyMode)
|
||||
{
|
||||
strategyPerformances[worstIdx].lotSizeBeforePenalty = strategyPerformances[worstIdx].currentLotSize;
|
||||
// Use symbol-specific minimum lot size
|
||||
double minLot = GetMinLotSizeForSymbol(strategyPerformances[worstIdx].symbol);
|
||||
strategyPerformances[worstIdx].currentLotSize = minLot;
|
||||
strategyPerformances[worstIdx].inPenaltyMode = true;
|
||||
strategyPerformances[worstIdx].penaltyStartTime = now;
|
||||
|
||||
if(PE_EnableLogging)
|
||||
Print("Blitz Play: WORST PERFORMER - '", strategyPerformances[worstIdx].strategyName,
|
||||
"' penalized! Lot size reduced from ", strategyPerformances[worstIdx].lotSizeBeforePenalty,
|
||||
" to minimum ", minLot, " (Score: ", DoubleToString(ranks[activeCount - 1].score, 2),
|
||||
", Profit: $", DoubleToString(strategyPerformances[worstIdx].quarterProfit, 2), ")");
|
||||
}
|
||||
}
|
||||
|
||||
// Log performance report
|
||||
if(PE_EnableLogging)
|
||||
{
|
||||
Print("=== Monthly Performance Ranking ===");
|
||||
for(int i = 0; i < activeCount; i++)
|
||||
{
|
||||
int strategyIdx = ranks[i].index;
|
||||
Print("Rank #", (i+1), ": ", strategyPerformances[strategyIdx].strategyName,
|
||||
" - Score: ", DoubleToString(ranks[i].score, 2),
|
||||
", Profit: $", DoubleToString(strategyPerformances[strategyIdx].quarterProfit, 2),
|
||||
", Win Rate: ", DoubleToString(strategyPerformances[strategyIdx].winRate, 2), "%",
|
||||
", Trades: ", (int)strategyPerformances[strategyIdx].quarterTrades,
|
||||
", Lot Size: ", DoubleToString(strategyPerformances[strategyIdx].currentLotSize, 2));
|
||||
}
|
||||
Print("===================================");
|
||||
}
|
||||
}
|
||||
|
||||
// Reset month metrics for all strategies
|
||||
for(int i = 0; i < ArraySize(strategyPerformances); i++)
|
||||
{
|
||||
if(strategyPerformances[i].isActive)
|
||||
{
|
||||
strategyPerformances[i].quarterProfit = 0.0;
|
||||
strategyPerformances[i].quarterTrades = 0;
|
||||
strategyPerformances[i].quarterWins = 0;
|
||||
strategyPerformances[i].quarterLosses = 0;
|
||||
strategyPerformances[i].maxDrawdown = 0.0;
|
||||
strategyPerformances[i].winRate = 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
// Update month dates
|
||||
MqlDateTime dt;
|
||||
TimeToStruct(now, dt);
|
||||
|
||||
// First day of current month
|
||||
dt.day = 1;
|
||||
dt.hour = 0;
|
||||
dt.min = 0;
|
||||
dt.sec = 0;
|
||||
currentMonthStart = StructToTime(dt);
|
||||
|
||||
// First day of next month - 1 second
|
||||
dt.mon += 1;
|
||||
if(dt.mon > 12)
|
||||
{
|
||||
dt.mon = 1;
|
||||
dt.year++;
|
||||
}
|
||||
currentMonthEnd = StructToTime(dt) - 1;
|
||||
|
||||
// Update month dates for all strategies
|
||||
for(int i = 0; i < ArraySize(strategyPerformances); i++)
|
||||
{
|
||||
strategyPerformances[i].quarterStart = currentMonthStart;
|
||||
strategyPerformances[i].quarterEnd = currentMonthEnd;
|
||||
}
|
||||
|
||||
lastMonthCheck = now;
|
||||
}
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get Current Lot Size for Strategy |
|
||||
//+------------------------------------------------------------------+
|
||||
double GetStrategyLotSize(string strategyName, int magicNumber)
|
||||
{
|
||||
for(int i = 0; i < ArraySize(strategyPerformances); i++)
|
||||
{
|
||||
if(strategyPerformances[i].strategyName == strategyName &&
|
||||
strategyPerformances[i].magicNumber == magicNumber &&
|
||||
strategyPerformances[i].isActive)
|
||||
{
|
||||
return strategyPerformances[i].currentLotSize;
|
||||
}
|
||||
}
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Process Performance Evaluation (call from OnTick) |
|
||||
//+------------------------------------------------------------------+
|
||||
void ProcessPerformanceEvaluation()
|
||||
{
|
||||
// Check if month ended
|
||||
CheckMonthEnd();
|
||||
|
||||
// Check for penalty expiration (blitz play)
|
||||
if(PE_EnableBlitzPlay)
|
||||
{
|
||||
datetime now = TimeCurrent();
|
||||
for(int i = 0; i < ArraySize(strategyPerformances); i++)
|
||||
{
|
||||
if(strategyPerformances[i].isActive && strategyPerformances[i].inPenaltyMode)
|
||||
{
|
||||
// Check if penalty period has passed (one month = ~30 days)
|
||||
if(now - strategyPerformances[i].penaltyStartTime >= 2592000)
|
||||
{
|
||||
// Restore lot size to before penalty
|
||||
strategyPerformances[i].currentLotSize = strategyPerformances[i].lotSizeBeforePenalty;
|
||||
strategyPerformances[i].inPenaltyMode = false;
|
||||
strategyPerformances[i].penaltyStartTime = 0;
|
||||
|
||||
if(PE_EnableLogging)
|
||||
Print("Blitz Play: Penalty expired for '", strategyPerformances[i].strategyName,
|
||||
"'. Lot size restored to ", strategyPerformances[i].currentLotSize);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Update performance metrics periodically (every hour)
|
||||
static datetime lastUpdate = 0;
|
||||
if(TimeCurrent() - lastUpdate >= 3600)
|
||||
{
|
||||
for(int i = 0; i < ArraySize(strategyPerformances); i++)
|
||||
{
|
||||
if(strategyPerformances[i].isActive)
|
||||
{
|
||||
UpdateStrategyPerformance(strategyPerformances[i].strategyName,
|
||||
strategyPerformances[i].magicNumber);
|
||||
}
|
||||
}
|
||||
lastUpdate = TimeCurrent();
|
||||
}
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get Performance Summary |
|
||||
//+------------------------------------------------------------------+
|
||||
string GetPerformanceSummary()
|
||||
{
|
||||
string summary = "\n=== Performance Summary ===\n";
|
||||
summary += "Current Month: " + TimeToString(currentMonthStart) + " to " + TimeToString(currentMonthEnd) + "\n\n";
|
||||
|
||||
for(int i = 0; i < ArraySize(strategyPerformances); i++)
|
||||
{
|
||||
if(strategyPerformances[i].isActive)
|
||||
{
|
||||
summary += strategyPerformances[i].strategyName + ":\n";
|
||||
summary += " Profit: $" + DoubleToString(strategyPerformances[i].quarterProfit, 2) + "\n";
|
||||
summary += " Trades: " + IntegerToString((int)strategyPerformances[i].quarterTrades) + "\n";
|
||||
summary += " Win Rate: " + DoubleToString(strategyPerformances[i].winRate, 2) + "%\n";
|
||||
summary += " Lot Size: " + DoubleToString(strategyPerformances[i].currentLotSize, 2) + "\n\n";
|
||||
}
|
||||
}
|
||||
|
||||
return summary;
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
@@ -0,0 +1,76 @@
|
||||
# United EA Strategy Configuration Summary
|
||||
|
||||
## Strategy Symbols and Magic Numbers
|
||||
|
||||
### Strategy 1: DarvasBox
|
||||
- **Symbol**: XAUUSD (Gold/USD)
|
||||
- **Magic Number**: 135790
|
||||
|
||||
### Strategy 2: EMASlopeDistance
|
||||
- **Symbol**: XAUUSD (Gold/USD)
|
||||
- **Magic Number**: 12350
|
||||
|
||||
### Strategy 3: RSICrossOverReversal
|
||||
- **Symbol**: XAUUSD (Gold/USD)
|
||||
- **Magic Number**: 7
|
||||
|
||||
### Strategy 4: RSIMidPointHijack
|
||||
- **Symbol**: XAUUSD (Gold/USD)
|
||||
- **Magic Numbers**:
|
||||
- RSIFollow: 1001
|
||||
- RSIReverse: 1002
|
||||
- EMACross: 1003
|
||||
|
||||
### Strategy 5: RSI Scalping APPL (Apple)
|
||||
- **Symbol**: AAPL (Apple stock)
|
||||
- **Magic Number**: 20001
|
||||
- **Note**: Changed from "APPL" to "AAPL" (correct ticker symbol)
|
||||
|
||||
### Strategy 6: RSI Scalping BTCUSD
|
||||
- **Symbol**: BTCUSD (Bitcoin/USD)
|
||||
- **Magic Number**: 123459123
|
||||
|
||||
### Strategy 7: RSI Scalping MSFT
|
||||
- **Symbol**: MSFT (Microsoft stock)
|
||||
- **Magic Number**: 20002
|
||||
|
||||
### Strategy 8: RSI Scalping NVDA
|
||||
- **Symbol**: NVDA (NVIDIA stock)
|
||||
- **Magic Number**: 20003
|
||||
|
||||
### Strategy 9: RSI Scalping TSLA
|
||||
- **Symbol**: TSLA (Tesla stock)
|
||||
- **Magic Number**: 125421321
|
||||
|
||||
### Strategy 10: RSI Scalping XAUUSD
|
||||
- **Symbol**: XAUUSD (Gold/USD)
|
||||
- **Magic Number**: 129102315
|
||||
|
||||
## Important Notes
|
||||
|
||||
1. **Stock Symbols**: Stock symbols (AAPL, MSFT, NVDA, TSLA) must be:
|
||||
- Added to Market Watch in MetaTrader 5
|
||||
- Available from your broker
|
||||
- Use the correct ticker symbol (e.g., "AAPL" not "APPL")
|
||||
|
||||
2. **Magic Numbers**: All strategies have unique magic numbers to prevent interference:
|
||||
- Each strategy can be identified by its magic number
|
||||
- RSIMidPointHijack uses 3 magic numbers (one for each sub-strategy)
|
||||
|
||||
3. **Symbol Configuration**: Each strategy trades on its own symbol:
|
||||
- You can change symbols in the input parameters
|
||||
- The EA will log warnings if a symbol is not available
|
||||
- Strategies with unavailable symbols will be skipped (EA continues running)
|
||||
|
||||
4. **RSI Scalping Strategies**:
|
||||
- Each RSI Scalping variant trades on a different symbol
|
||||
- They all use the same strategy logic but with different parameters
|
||||
- Buy and sell signals are generated based on RSI levels for each symbol
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
If stock symbols are not working:
|
||||
1. Check if the symbol exists in your broker's symbol list
|
||||
2. Add the symbol to Market Watch in MetaTrader 5
|
||||
3. Verify the symbol name matches your broker's naming convention
|
||||
4. Some brokers use prefixes/suffixes (e.g., "NASDAQ:AAPL" or "AAPL.US")
|
||||
@@ -0,0 +1,300 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| DarvasBoxStrategy.mqh |
|
||||
//+------------------------------------------------------------------+
|
||||
|
||||
bool InitDarvasBox(string symbol)
|
||||
{
|
||||
dbData.symbol = symbol;
|
||||
dbData.boxHigh = 0;
|
||||
dbData.boxLow = 0;
|
||||
dbData.boxFormed = false;
|
||||
dbData.lastBoxTime = 0;
|
||||
dbData.boxName = "DarvasBox_" + IntegerToString(DB_MagicNumber) + "_";
|
||||
|
||||
// Check if symbol exists
|
||||
if(!SymbolSelect(symbol, true))
|
||||
{
|
||||
Print("DarvasBox: Symbol '", symbol, "' not available in Market Watch. Please add it to Market Watch or check symbol name.");
|
||||
return false;
|
||||
}
|
||||
|
||||
Sleep(100); // Wait for symbol to be ready
|
||||
|
||||
dbData.point = SymbolInfoDouble(symbol, SYMBOL_POINT);
|
||||
dbData.minStopLevel = SymbolInfoInteger(symbol, SYMBOL_TRADE_STOPS_LEVEL) * dbData.point;
|
||||
|
||||
dbData.maHandle = iMA(symbol, DB_TrendTimeframe, DB_MA_Period, 0, DB_MA_Method, DB_MA_Price);
|
||||
dbData.volumeHandle = iVolumes(symbol, PERIOD_CURRENT, VOLUME_TICK);
|
||||
|
||||
if(dbData.maHandle == INVALID_HANDLE || dbData.volumeHandle == INVALID_HANDLE)
|
||||
{
|
||||
Print("DarvasBox: Error creating indicators for '", symbol, "'");
|
||||
return false;
|
||||
}
|
||||
|
||||
dbData.trade.SetDeviationInPoints(10);
|
||||
dbData.trade.SetTypeFilling(ORDER_FILLING_IOC);
|
||||
dbData.trade.SetAsyncMode(false);
|
||||
dbData.trade.SetExpertMagicNumber(DB_MagicNumber);
|
||||
|
||||
ObjectsDeleteAll(0, dbData.boxName);
|
||||
dbData.isInitialized = true;
|
||||
Print("DarvasBox: Successfully initialized for symbol '", symbol, "'");
|
||||
return true;
|
||||
}
|
||||
|
||||
void DeinitDarvasBox()
|
||||
{
|
||||
if(dbData.maHandle != INVALID_HANDLE) IndicatorRelease(dbData.maHandle);
|
||||
if(dbData.volumeHandle != INVALID_HANDLE) IndicatorRelease(dbData.volumeHandle);
|
||||
ObjectsDeleteAll(0, dbData.boxName);
|
||||
}
|
||||
|
||||
void DrawDarvasBox()
|
||||
{
|
||||
if(!dbData.boxFormed) return;
|
||||
|
||||
datetime time1 = iTime(dbData.symbol, PERIOD_H1, DB_BoxPeriod);
|
||||
datetime time2 = iTime(dbData.symbol, PERIOD_H1, 0);
|
||||
|
||||
ObjectsDeleteAll(0, dbData.boxName);
|
||||
|
||||
ObjectCreate(0, dbData.boxName + "Top", OBJ_TREND, 0, time1, dbData.boxHigh, time2, dbData.boxHigh);
|
||||
ObjectCreate(0, dbData.boxName + "Bottom", OBJ_TREND, 0, time1, dbData.boxLow, time2, dbData.boxLow);
|
||||
|
||||
ObjectSetInteger(0, dbData.boxName + "Top", OBJPROP_COLOR, DB_BoxColor);
|
||||
ObjectSetInteger(0, dbData.boxName + "Bottom", OBJPROP_COLOR, DB_BoxColor);
|
||||
ObjectSetInteger(0, dbData.boxName + "Top", OBJPROP_WIDTH, DB_BoxWidth);
|
||||
ObjectSetInteger(0, dbData.boxName + "Bottom", OBJPROP_WIDTH, DB_BoxWidth);
|
||||
ObjectSetInteger(0, dbData.boxName + "Top", OBJPROP_RAY_RIGHT, true);
|
||||
ObjectSetInteger(0, dbData.boxName + "Bottom", OBJPROP_RAY_RIGHT, true);
|
||||
}
|
||||
|
||||
void CalculateDarvasBox()
|
||||
{
|
||||
double high = 0;
|
||||
double low = DBL_MAX;
|
||||
|
||||
// Find highest high and lowest low in the period - EXACTLY like original
|
||||
for(int i = 0; i < DB_BoxPeriod; i++)
|
||||
{
|
||||
high = MathMax(high, iHigh(dbData.symbol, PERIOD_H1, i));
|
||||
low = MathMin(low, iLow(dbData.symbol, PERIOD_H1, i));
|
||||
}
|
||||
|
||||
double range = high - low;
|
||||
double allowedRange = DB_BoxDeviation * dbData.point; // Use dbData.point instead of _Point
|
||||
|
||||
if(DB_EnableLogging)
|
||||
{
|
||||
Print("DarvasBox: Box Calculation - High: ", high, " Low: ", low, " Range: ", range, " Allowed Range: ", allowedRange);
|
||||
}
|
||||
|
||||
// Check if box is formed - EXACTLY like original
|
||||
if(range <= allowedRange)
|
||||
{
|
||||
dbData.boxHigh = high;
|
||||
dbData.boxLow = low;
|
||||
dbData.boxFormed = true;
|
||||
dbData.lastBoxTime = iTime(dbData.symbol, PERIOD_CURRENT, 0);
|
||||
|
||||
// Draw the box
|
||||
DrawDarvasBox();
|
||||
|
||||
if(DB_EnableLogging)
|
||||
Print("DarvasBox: Box Formed - High: ", dbData.boxHigh, " Low: ", dbData.boxLow, " Time: ", dbData.lastBoxTime);
|
||||
}
|
||||
else
|
||||
{
|
||||
dbData.boxFormed = false;
|
||||
// Delete box if it exists
|
||||
ObjectsDeleteAll(0, dbData.boxName);
|
||||
}
|
||||
}
|
||||
|
||||
bool ValidateStopLevels(double price, double &sl, double &tp, ENUM_ORDER_TYPE orderType)
|
||||
{
|
||||
double minSlDistance = MathMax(dbData.minStopLevel, DB_StopLoss * dbData.point);
|
||||
double minTpDistance = MathMax(dbData.minStopLevel, DB_TakeProfit * dbData.point);
|
||||
|
||||
if(orderType == ORDER_TYPE_BUY)
|
||||
{
|
||||
sl = price - minSlDistance;
|
||||
tp = price + minTpDistance;
|
||||
}
|
||||
else
|
||||
{
|
||||
sl = price + minSlDistance;
|
||||
tp = price - minTpDistance;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IsTrendFavorable(ENUM_ORDER_TYPE orderType)
|
||||
{
|
||||
double ma[];
|
||||
ArraySetAsSeries(ma, true);
|
||||
|
||||
if(CopyBuffer(dbData.maHandle, 0, 0, 2, ma) <= 0)
|
||||
return false;
|
||||
|
||||
double currentPrice = SymbolInfoDouble(dbData.symbol, SYMBOL_ASK);
|
||||
double trendStrength = MathAbs(currentPrice - ma[0]) / dbData.point;
|
||||
|
||||
if(orderType == ORDER_TYPE_BUY)
|
||||
return (currentPrice > ma[0] && trendStrength > DB_TrendThreshold);
|
||||
else
|
||||
return (currentPrice < ma[0] && trendStrength > DB_TrendThreshold);
|
||||
}
|
||||
|
||||
bool CheckVolumeConditions()
|
||||
{
|
||||
double volumes[];
|
||||
ArraySetAsSeries(volumes, true);
|
||||
|
||||
if(CopyBuffer(dbData.volumeHandle, 0, 0, DB_VolumeMA_Period + 1, volumes) <= 0)
|
||||
return false;
|
||||
|
||||
double volumeMA = 0;
|
||||
for(int i = 1; i <= DB_VolumeMA_Period; i++)
|
||||
volumeMA += volumes[i];
|
||||
volumeMA /= DB_VolumeMA_Period;
|
||||
|
||||
double currentVolume = volumes[0];
|
||||
double volumeRatio = currentVolume / volumeMA;
|
||||
|
||||
return (volumeRatio > DB_VolumeThresholdMultiplier);
|
||||
}
|
||||
|
||||
bool PlaceOrder(ENUM_ORDER_TYPE orderType, double price, double sl, double tp)
|
||||
{
|
||||
if(!ValidateStopLevels(price, sl, tp, orderType))
|
||||
{
|
||||
if(DB_EnableLogging)
|
||||
Print("DarvasBox: Order rejected - Stop levels validation failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!IsTrendFavorable(orderType))
|
||||
{
|
||||
if(DB_EnableLogging)
|
||||
Print("DarvasBox: Order rejected - Trend not favorable for ", EnumToString(orderType));
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!CheckVolumeConditions())
|
||||
{
|
||||
if(DB_EnableLogging)
|
||||
Print("DarvasBox: Order rejected - Volume conditions not met");
|
||||
return false;
|
||||
}
|
||||
|
||||
bool result = false;
|
||||
|
||||
// Use market price (0) instead of explicit price - this ensures market order execution
|
||||
// In backtesting, explicit price might fail if price has moved
|
||||
if(orderType == ORDER_TYPE_BUY)
|
||||
result = dbData.trade.Buy(0.01, dbData.symbol, 0, sl, tp, "Darvas Box Breakout");
|
||||
else
|
||||
result = dbData.trade.Sell(0.01, dbData.symbol, 0, sl, tp, "Darvas Box Breakdown");
|
||||
|
||||
// Always log errors, success only if logging enabled
|
||||
if(result)
|
||||
{
|
||||
if(DB_EnableLogging)
|
||||
Print("DarvasBox: ", (orderType == ORDER_TYPE_BUY ? "Buy" : "Sell"), " Order Placed Successfully");
|
||||
}
|
||||
else
|
||||
{
|
||||
// Always log failures with detailed info
|
||||
uint retcode_uint = dbData.trade.ResultRetcode();
|
||||
int retcode = (int)retcode_uint;
|
||||
string desc = dbData.trade.ResultRetcodeDescription();
|
||||
ulong deal = dbData.trade.ResultDeal();
|
||||
ulong order = dbData.trade.ResultOrder();
|
||||
Print("DarvasBox: ", (orderType == ORDER_TYPE_BUY ? "Buy" : "Sell"),
|
||||
" Order Failed - Retcode: ", retcode,
|
||||
", Description: ", desc,
|
||||
", Deal: ", deal,
|
||||
", Order: ", order,
|
||||
", Symbol: ", dbData.symbol,
|
||||
", Requested Price: ", price,
|
||||
", SL: ", sl,
|
||||
", TP: ", tp);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void ProcessDarvasBox(string symbol)
|
||||
{
|
||||
// Skip if not initialized (symbol not available)
|
||||
if(!dbData.isInitialized)
|
||||
return;
|
||||
|
||||
dbData.symbol = symbol; // Update symbol in case it changed
|
||||
|
||||
// Calculate new box levels - EXACTLY like original (called every tick)
|
||||
CalculateDarvasBox();
|
||||
|
||||
// Check for trading signals - EXACTLY like original (checked every tick)
|
||||
if(dbData.boxFormed)
|
||||
{
|
||||
double currentPrice = SymbolInfoDouble(dbData.symbol, SYMBOL_ASK);
|
||||
long currentVolume_long = iVolume(dbData.symbol, PERIOD_CURRENT, 0);
|
||||
double currentVolume = (double)currentVolume_long;
|
||||
|
||||
if(DB_EnableLogging)
|
||||
{
|
||||
Print("DarvasBox: Current Price: ", currentPrice, " Box High: ", dbData.boxHigh, " Box Low: ", dbData.boxLow);
|
||||
Print("DarvasBox: Current Volume: ", currentVolume, " Volume Threshold: ", DB_VolumeThreshold);
|
||||
}
|
||||
|
||||
// Check for breakout above box - EXACTLY like original
|
||||
if(currentPrice > dbData.boxHigh && currentVolume > DB_VolumeThreshold)
|
||||
{
|
||||
if(DB_EnableLogging)
|
||||
Print("DarvasBox: Breakout Signal Detected - Price above box high");
|
||||
|
||||
// Buy signal
|
||||
if(!PositionExistsByMagic(dbData.symbol, (ulong)DB_MagicNumber)) // No existing positions with our magic number
|
||||
{
|
||||
double sl = currentPrice - DB_StopLoss * dbData.point;
|
||||
double tp = currentPrice + DB_TakeProfit * dbData.point;
|
||||
|
||||
if(DB_EnableLogging)
|
||||
Print("DarvasBox: Preparing Buy Order - Price: ", currentPrice, " SL: ", sl, " TP: ", tp);
|
||||
|
||||
PlaceOrder(ORDER_TYPE_BUY, currentPrice, sl, tp);
|
||||
}
|
||||
else if(DB_EnableLogging)
|
||||
Print("DarvasBox: Skipping Buy Signal - Position already exists");
|
||||
}
|
||||
|
||||
// Check for breakdown below box - EXACTLY like original
|
||||
if(currentPrice < dbData.boxLow && currentVolume > DB_VolumeThreshold)
|
||||
{
|
||||
if(DB_EnableLogging)
|
||||
Print("DarvasBox: Breakdown Signal Detected - Price below box low");
|
||||
|
||||
// Sell signal
|
||||
if(!PositionExistsByMagic(dbData.symbol, (ulong)DB_MagicNumber)) // No existing positions with our magic number
|
||||
{
|
||||
double sl = currentPrice + DB_StopLoss * dbData.point;
|
||||
double tp = currentPrice - DB_TakeProfit * dbData.point;
|
||||
|
||||
if(DB_EnableLogging)
|
||||
Print("DarvasBox: Preparing Sell Order - Price: ", currentPrice, " SL: ", sl, " TP: ", tp);
|
||||
|
||||
PlaceOrder(ORDER_TYPE_SELL, currentPrice, sl, tp);
|
||||
}
|
||||
else if(DB_EnableLogging)
|
||||
Print("DarvasBox: Skipping Sell Signal - Position already exists");
|
||||
}
|
||||
}
|
||||
else if(DB_EnableLogging)
|
||||
Print("DarvasBox: No Box Formed - Waiting for consolidation");
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
@@ -0,0 +1,496 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| EMASlopeDistanceStrategy.mqh |
|
||||
//+------------------------------------------------------------------+
|
||||
|
||||
bool InitEMASlopeDistance(string symbol)
|
||||
{
|
||||
esData.symbol = symbol;
|
||||
esData.letzte_überwachung_zeit = 0;
|
||||
esData.überwachung_aktiv = false;
|
||||
esData.preis_trigger_aktiv = false;
|
||||
esData.steigung_trigger_aktiv = false;
|
||||
esData.ticket = 0;
|
||||
esData.trades_in_current_crossover = 0;
|
||||
esData.crossover_detected = false;
|
||||
esData.trade_open_time = 0;
|
||||
esData.last_bar_time = 0;
|
||||
|
||||
// Check if symbol exists
|
||||
if(!SymbolSelect(symbol, true))
|
||||
{
|
||||
Print("EMASlopeDistance: Symbol '", symbol, "' not available in Market Watch. Please add it to Market Watch or check symbol name.");
|
||||
return false;
|
||||
}
|
||||
|
||||
Sleep(100); // Wait for symbol to be ready
|
||||
|
||||
esData.trade.SetExpertMagicNumber(ES_MagicNumber);
|
||||
esData.trade.SetDeviationInPoints(10);
|
||||
esData.trade.SetTypeFilling(ORDER_FILLING_IOC);
|
||||
|
||||
esData.ema_handle = iMA(symbol, ES_Timeframe, ES_EMA_Periode, 0, MODE_EMA, PRICE_CLOSE);
|
||||
|
||||
if(esData.ema_handle == INVALID_HANDLE)
|
||||
{
|
||||
Print("EMASlopeDistance: Error creating EMA indicator for '", symbol, "'");
|
||||
return false;
|
||||
}
|
||||
|
||||
ArraySetAsSeries(esData.ema_array, true);
|
||||
esData.isInitialized = true;
|
||||
Print("EMASlopeDistance: Successfully initialized for symbol '", symbol, "'");
|
||||
return true;
|
||||
}
|
||||
|
||||
void DeinitEMASlopeDistance()
|
||||
{
|
||||
if(esData.ema_handle != INVALID_HANDLE)
|
||||
IndicatorRelease(esData.ema_handle);
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| EMA Berechnung (EMA Calculation) |
|
||||
//+------------------------------------------------------------------+
|
||||
void BerechneEMA()
|
||||
{
|
||||
//--- EMA Werte vom Indicator kopieren (Copy EMA values from indicator)
|
||||
int copied = CopyBuffer(esData.ema_handle, 0, 0, 3, esData.ema_array);
|
||||
|
||||
if(copied <= 0)
|
||||
{
|
||||
Print("TRACE: Fehler beim Kopieren der EMA Werte - Copied: ", copied);
|
||||
return;
|
||||
}
|
||||
|
||||
Print("TRACE: EMA Werte kopiert: ", copied, " Bars");
|
||||
Print("TRACE: EMA [0]: ", esData.ema_array[0], " [1]: ", esData.ema_array[1], " [2]: ", esData.ema_array[2]);
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Trigger-Bedingungen prüfen (Check trigger conditions) |
|
||||
//+------------------------------------------------------------------+
|
||||
void PrüfeTrigger()
|
||||
{
|
||||
if(ArraySize(esData.ema_array) < 2)
|
||||
{
|
||||
Print("TRACE: Array zu klein - Größe: ", ArraySize(esData.ema_array));
|
||||
return;
|
||||
}
|
||||
|
||||
//--- Aktuelle Werte (Current values)
|
||||
double aktueller_preis = SymbolInfoDouble(esData.symbol, SYMBOL_BID);
|
||||
double aktueller_ask = SymbolInfoDouble(esData.symbol, SYMBOL_ASK);
|
||||
double aktueller_close = iClose(esData.symbol, ES_Timeframe, 0);
|
||||
int digits = (int)SymbolInfoInteger(esData.symbol, SYMBOL_DIGITS);
|
||||
double point = SymbolInfoDouble(esData.symbol, SYMBOL_POINT);
|
||||
double pips_multiplier = (digits == 3 || digits == 5) ? 10.0 : 1.0;
|
||||
|
||||
//--- EMA Werte in Variablen (EMA values in variables)
|
||||
double ema_aktuell = esData.ema_array[0];
|
||||
double ema_vorher = esData.ema_array[1];
|
||||
|
||||
//--- EMA Crossover Erkennung (EMA Crossover Detection)
|
||||
// Prüfe ob Preis die EMA kreuzt (Check if price crosses EMA)
|
||||
static double last_close = 0;
|
||||
static double last_ema = 0;
|
||||
|
||||
if(last_close != 0 && last_ema != 0)
|
||||
{
|
||||
bool crossover_bullish = (last_close <= last_ema) && (aktueller_close > ema_aktuell);
|
||||
bool crossover_bearish = (last_close >= last_ema) && (aktueller_close < ema_aktuell);
|
||||
|
||||
//--- Neues Crossover-Ereignis erkannt (New crossover event detected)
|
||||
if(crossover_bullish || crossover_bearish)
|
||||
{
|
||||
esData.trades_in_current_crossover = 0; // Reset trade counter
|
||||
Print("TRACE: EMA Crossover erkannt - ", (crossover_bullish ? "BULLISH" : "BEARISH"), " - Trade-Counter zurückgesetzt");
|
||||
Print("TRACE: Vorher: Close=", last_close, " EMA=", last_ema, " Jetzt: Close=", aktueller_close, " EMA=", ema_aktuell);
|
||||
}
|
||||
}
|
||||
|
||||
//--- Aktuelle Werte für nächsten Vergleich speichern (Save current values for next comparison)
|
||||
last_close = aktueller_close;
|
||||
last_ema = ema_aktuell;
|
||||
|
||||
//--- Preisbewegung zur EMA prüfen (Check price action to EMA)
|
||||
double preis_abstand = MathAbs(aktueller_close - ema_aktuell) / point / pips_multiplier;
|
||||
|
||||
Print("TRACE: Preis-Abstand: ", preis_abstand, " Pips (Schwelle: ", ES_PreisSchwelle, ")");
|
||||
Print("TRACE: Close: ", aktueller_close, " EMA: ", ema_aktuell);
|
||||
Print("TRACE: Trades im aktuellen Crossover: ", esData.trades_in_current_crossover, "/", ES_MaxTradesPerCrossover);
|
||||
|
||||
if(preis_abstand > ES_PreisSchwelle && !esData.preis_trigger_aktiv)
|
||||
{
|
||||
esData.preis_trigger_aktiv = true;
|
||||
Print("TRACE: Preis-Trigger aktiviert: ", preis_abstand, " Pips");
|
||||
}
|
||||
|
||||
//--- EMA Steigung prüfen (Check EMA slope)
|
||||
double steigung = (ema_aktuell - ema_vorher) / point / pips_multiplier;
|
||||
|
||||
Print("TRACE: EMA Steigung: ", steigung, " Pips (Schwelle: ", ES_SteigungSchwelle, ")");
|
||||
|
||||
if(MathAbs(steigung) > ES_SteigungSchwelle && !esData.steigung_trigger_aktiv)
|
||||
{
|
||||
esData.steigung_trigger_aktiv = true;
|
||||
Print("TRACE: Steigungs-Trigger aktiviert: ", steigung, " Pips");
|
||||
}
|
||||
|
||||
//--- Überwachung starten wenn beide Trigger aktiv sind (Start monitoring when both triggers are active)
|
||||
if(esData.preis_trigger_aktiv && esData.steigung_trigger_aktiv && !esData.überwachung_aktiv)
|
||||
{
|
||||
esData.überwachung_aktiv = true;
|
||||
|
||||
if(ES_UseBarData)
|
||||
{
|
||||
esData.letzte_überwachung_zeit = iTime(esData.symbol, ES_Timeframe, 0); // Aktuelle Bar-Zeit
|
||||
Print("TRACE: Überwachung gestartet - Beide Trigger aktiv (Bar: ", TimeToString(esData.letzte_überwachung_zeit), ")");
|
||||
}
|
||||
else
|
||||
{
|
||||
esData.letzte_überwachung_zeit = TimeCurrent(); // Aktuelle Tick-Zeit
|
||||
Print("TRACE: Überwachung gestartet - Beide Trigger aktiv (Tick)");
|
||||
}
|
||||
}
|
||||
|
||||
//--- Trade platzieren wenn Überwachung aktiv und Preis über/unter EMA (Place trade when monitoring active and price above/below EMA)
|
||||
if(esData.überwachung_aktiv)
|
||||
{
|
||||
bool bullish_signal = aktueller_close > ema_aktuell;
|
||||
bool bearish_signal = aktueller_close < ema_aktuell;
|
||||
|
||||
Print("TRACE: Signal Check - Bullish: ", bullish_signal, " Bearish: ", bearish_signal);
|
||||
Print("TRACE: Close: ", aktueller_close, " EMA: ", ema_aktuell);
|
||||
Print("TRACE: Differenz: ", aktueller_close - ema_aktuell);
|
||||
|
||||
//--- Trade-Limit prüfen (Check trade limit)
|
||||
if(esData.trades_in_current_crossover >= ES_MaxTradesPerCrossover)
|
||||
{
|
||||
Print("TRACE: Trade-Limit erreicht (", ES_MaxTradesPerCrossover, ") - Kein neuer Trade");
|
||||
return;
|
||||
}
|
||||
|
||||
if(bullish_signal && !PositionExistsByMagic(esData.symbol, (ulong)ES_MagicNumber))
|
||||
{
|
||||
Print("TRACE: Versuche KAUF-Trade zu platzieren (Trade #", esData.trades_in_current_crossover + 1, ")");
|
||||
if(PlatziereTrade(ORDER_TYPE_BUY))
|
||||
{
|
||||
esData.trades_in_current_crossover++;
|
||||
}
|
||||
}
|
||||
else if(bearish_signal && !PositionExistsByMagic(esData.symbol, (ulong)ES_MagicNumber))
|
||||
{
|
||||
Print("TRACE: Versuche VERKAUF-Trade zu platzieren (Trade #", esData.trades_in_current_crossover + 1, ")");
|
||||
if(PlatziereTrade(ORDER_TYPE_SELL))
|
||||
{
|
||||
esData.trades_in_current_crossover++;
|
||||
}
|
||||
}
|
||||
else if(PositionExistsByMagic(esData.symbol, (ulong)ES_MagicNumber))
|
||||
{
|
||||
Print("TRACE: Position bereits offen - kein neuer Trade");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Trade platzieren (Place trade) |
|
||||
//+------------------------------------------------------------------+
|
||||
bool PlatziereTrade(ENUM_ORDER_TYPE order_type)
|
||||
{
|
||||
Print("TRACE: Versuche Trade zu platzieren - Typ: ", (order_type == ORDER_TYPE_BUY) ? "KAUF" : "VERKAUF");
|
||||
Print("TRACE: Lot: ", g_ES_LotSize);
|
||||
|
||||
bool success = false;
|
||||
|
||||
if(order_type == ORDER_TYPE_BUY)
|
||||
{
|
||||
success = esData.trade.Buy(g_ES_LotSize, esData.symbol, 0, 0, 0, "EMA Crossover Trade");
|
||||
}
|
||||
else
|
||||
{
|
||||
success = esData.trade.Sell(g_ES_LotSize, esData.symbol, 0, 0, 0, "EMA Crossover Trade");
|
||||
}
|
||||
|
||||
if(success)
|
||||
{
|
||||
esData.ticket = (int)esData.trade.ResultOrder();
|
||||
Print("TRACE: Trade erfolgreich platziert: ", (order_type == ORDER_TYPE_BUY) ? "KAUF" : "VERKAUF", " Ticket: ", esData.ticket);
|
||||
|
||||
//--- Trade-Öffnungszeit speichern (Save trade opening time)
|
||||
esData.trade_open_time = iTime(esData.symbol, ES_Timeframe, 0);
|
||||
Print("TRACE: Trade-Öffnungszeit: ", TimeToString(esData.trade_open_time));
|
||||
|
||||
//--- Überwachung zurücksetzen (Reset monitoring)
|
||||
esData.überwachung_aktiv = false;
|
||||
esData.preis_trigger_aktiv = false;
|
||||
esData.steigung_trigger_aktiv = false;
|
||||
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
Print("TRACE: Fehler beim Platzieren des Trades - Retcode: ", esData.trade.ResultRetcode());
|
||||
Print("TRACE: Fehlerbeschreibung: ", esData.trade.ResultRetcodeDescription());
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Trades verwalten (Manage trades) |
|
||||
//+------------------------------------------------------------------+
|
||||
void VerwalteTrades()
|
||||
{
|
||||
if(!PositionSelectByMagic(esData.symbol, (ulong)ES_MagicNumber))
|
||||
return;
|
||||
|
||||
double position_profit = PositionGetDouble(POSITION_PROFIT);
|
||||
double position_open_price = PositionGetDouble(POSITION_PRICE_OPEN);
|
||||
double current_price = PositionGetDouble(POSITION_PRICE_CURRENT);
|
||||
ENUM_POSITION_TYPE position_type = (ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);
|
||||
|
||||
int digits = (int)SymbolInfoInteger(esData.symbol, SYMBOL_DIGITS);
|
||||
double point = SymbolInfoDouble(esData.symbol, SYMBOL_POINT);
|
||||
double pips_multiplier = (digits == 3 || digits == 5) ? 10.0 : 1.0;
|
||||
double trailing_stop_pips = ES_TrailingStop;
|
||||
|
||||
//--- Gleitender Stop (Trailing Stop) - nur wenn Position im Profit ist
|
||||
if(position_profit > 0) // Only apply trailing stop when in profit
|
||||
{
|
||||
if(position_type == POSITION_TYPE_BUY)
|
||||
{
|
||||
double new_stop_loss = current_price - (trailing_stop_pips * point * pips_multiplier);
|
||||
double current_stop_loss = PositionGetDouble(POSITION_SL);
|
||||
|
||||
// Only move stop loss if new stop is higher than current stop
|
||||
if(new_stop_loss > current_stop_loss)
|
||||
{
|
||||
ÄndereStopLoss(new_stop_loss);
|
||||
}
|
||||
}
|
||||
else if(position_type == POSITION_TYPE_SELL)
|
||||
{
|
||||
double new_stop_loss = current_price + (trailing_stop_pips * point * pips_multiplier);
|
||||
double current_stop_loss = PositionGetDouble(POSITION_SL);
|
||||
|
||||
// Only move stop loss if new stop is lower than current stop
|
||||
if(new_stop_loss < current_stop_loss || current_stop_loss == 0)
|
||||
{
|
||||
ÄndereStopLoss(new_stop_loss);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//--- Ausstieg bei Preis unter/über EMA (Exit when price below/above EMA)
|
||||
if(ArraySize(esData.ema_array) >= 1)
|
||||
{
|
||||
double aktueller_close = iClose(esData.symbol, ES_Timeframe, 0);
|
||||
double ema_aktuell = esData.ema_array[0];
|
||||
bool exit_bullish = (position_type == POSITION_TYPE_SELL && aktueller_close > ema_aktuell);
|
||||
bool exit_bearish = (position_type == POSITION_TYPE_BUY && aktueller_close < ema_aktuell);
|
||||
|
||||
if(exit_bullish || exit_bearish)
|
||||
{
|
||||
Print("TRACE: Ausstiegssignal - Close: ", aktueller_close, " EMA: ", ema_aktuell);
|
||||
SchließePosition("EMA Crossover Exit");
|
||||
|
||||
Print("TRACE: Position geschlossen - Trade-Counter bleibt bei ", esData.trades_in_current_crossover);
|
||||
}
|
||||
}
|
||||
|
||||
//--- Profit-Prüfung nach X Bars (Profit check after X bars)
|
||||
if(ES_CloseUnprofitableTrades && esData.trade_open_time != 0 && PositionExistsByMagic(esData.symbol, (ulong)ES_MagicNumber))
|
||||
{
|
||||
Print("TRACE: Profit-Prüfung aktiviert - CloseUnprofitableTrades: ", ES_CloseUnprofitableTrades);
|
||||
PrüfeProfitNachBars();
|
||||
}
|
||||
else if(!ES_CloseUnprofitableTrades)
|
||||
{
|
||||
Print("TRACE: Profit-Prüfung deaktiviert - CloseUnprofitableTrades: ", ES_CloseUnprofitableTrades);
|
||||
}
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Profit-Prüfung nach X Bars (Profit check after X bars) |
|
||||
//+------------------------------------------------------------------+
|
||||
void PrüfeProfitNachBars()
|
||||
{
|
||||
if(!PositionSelectByMagic(esData.symbol, (ulong)ES_MagicNumber))
|
||||
{
|
||||
return; // Keine Position offen
|
||||
}
|
||||
|
||||
datetime current_bar_time = iTime(esData.symbol, ES_Timeframe, 0);
|
||||
int bars_since_trade_open = iBarShift(esData.symbol, ES_Timeframe, esData.trade_open_time);
|
||||
|
||||
Print("TRACE: Bars seit Trade-Öffnung: ", bars_since_trade_open, "/", ES_ProfitCheckBars);
|
||||
|
||||
//--- Prüfe ob genügend Bars vergangen sind (Check if enough bars have passed)
|
||||
if(bars_since_trade_open >= ES_ProfitCheckBars)
|
||||
{
|
||||
double position_profit = PositionGetDouble(POSITION_PROFIT);
|
||||
double position_volume = PositionGetDouble(POSITION_VOLUME);
|
||||
ENUM_POSITION_TYPE position_type = (ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);
|
||||
|
||||
Print("TRACE: Profit-Prüfung nach ", ES_ProfitCheckBars, " Bars");
|
||||
Print("TRACE: Position Profit: ", position_profit, " USD");
|
||||
|
||||
//--- Schließe Position wenn nicht im Profit (Close position if not in profit)
|
||||
if(position_profit <= 0)
|
||||
{
|
||||
Print("TRACE: Position nicht im Profit - Schließe Position");
|
||||
SchließePosition("Profit Check - Unprofitable");
|
||||
|
||||
//--- Trade-Öffnungszeit zurücksetzen (Reset trade opening time)
|
||||
esData.trade_open_time = 0;
|
||||
Print("TRACE: Trade-Öffnungszeit zurückgesetzt");
|
||||
}
|
||||
else
|
||||
{
|
||||
Print("TRACE: Position im Profit - Behalte Position");
|
||||
//--- Trade-Öffnungszeit zurücksetzen um weitere Prüfungen zu vermeiden (Reset to avoid further checks)
|
||||
esData.trade_open_time = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Stop Loss ändern (Modify Stop Loss) |
|
||||
//+------------------------------------------------------------------+
|
||||
void ÄndereStopLoss(double new_stop_loss)
|
||||
{
|
||||
Print("TRACE: Versuche Stop Loss zu ändern auf: ", new_stop_loss);
|
||||
|
||||
bool success = ModifyPositionByMagic(esData.trade, esData.symbol, (ulong)ES_MagicNumber, new_stop_loss, PositionGetDouble(POSITION_TP));
|
||||
|
||||
if(success)
|
||||
{
|
||||
Print("TRACE: Stop Loss erfolgreich geändert auf: ", new_stop_loss);
|
||||
}
|
||||
else
|
||||
{
|
||||
Print("TRACE: Fehler beim Ändern des Stop Loss - Retcode: ", esData.trade.ResultRetcode());
|
||||
Print("TRACE: Fehlerbeschreibung: ", esData.trade.ResultRetcodeDescription());
|
||||
}
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Position schließen (Close position) |
|
||||
//+------------------------------------------------------------------+
|
||||
void SchließePosition(string reason = "Unbekannt")
|
||||
{
|
||||
Print("TRACE: Versuche Position zu schließen - Grund: ", reason);
|
||||
|
||||
bool success = ClosePositionByMagic(esData.trade, esData.symbol, (ulong)ES_MagicNumber);
|
||||
|
||||
if(success)
|
||||
{
|
||||
Print("TRACE: Position erfolgreich geschlossen - Grund: ", reason);
|
||||
}
|
||||
else
|
||||
{
|
||||
Print("TRACE: Fehler beim Schließen der Position - Retcode: ", esData.trade.ResultRetcode());
|
||||
Print("TRACE: Fehlerbeschreibung: ", esData.trade.ResultRetcodeDescription());
|
||||
}
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Expert tick function |
|
||||
//+------------------------------------------------------------------+
|
||||
void ProcessEMASlopeDistance(string symbol)
|
||||
{
|
||||
// Skip if not initialized (symbol not available)
|
||||
if(!esData.isInitialized)
|
||||
return;
|
||||
|
||||
esData.symbol = symbol; // Update symbol in case it changed
|
||||
|
||||
//--- Bar-Daten oder Tick-Daten verwenden (Use bar data or tick data)
|
||||
if(ES_UseBarData)
|
||||
{
|
||||
//--- Nur bei neuen Bars ausführen (Only execute on new bars)
|
||||
datetime current_bar_time = iTime(esData.symbol, ES_Timeframe, 0);
|
||||
|
||||
if(current_bar_time == esData.last_bar_time)
|
||||
{
|
||||
return; // Kein neuer Bar, nichts tun
|
||||
}
|
||||
|
||||
esData.last_bar_time = current_bar_time;
|
||||
}
|
||||
|
||||
//--- EMA Werte berechnen (Calculate EMA values)
|
||||
BerechneEMA();
|
||||
|
||||
//--- Debug: Aktuelle Werte ausgeben (Debug: Output current values)
|
||||
if(ArraySize(esData.ema_array) > 0)
|
||||
{
|
||||
double aktueller_close = iClose(esData.symbol, ES_Timeframe, 0);
|
||||
double ema_aktuell = esData.ema_array[0];
|
||||
double ema_vorher = esData.ema_array[1];
|
||||
int digits = (int)SymbolInfoInteger(esData.symbol, SYMBOL_DIGITS);
|
||||
double point = SymbolInfoDouble(esData.symbol, SYMBOL_POINT);
|
||||
double preis_abstand = MathAbs(aktueller_close - ema_aktuell) / point;
|
||||
double steigung = (ema_aktuell - ema_vorher) / point;
|
||||
|
||||
if(ES_UseBarData)
|
||||
{
|
||||
Print("=== DEBUG INFO (Neuer Bar) ===");
|
||||
Print("Bar Zeit: ", TimeToString(iTime(esData.symbol, ES_Timeframe, 0)));
|
||||
}
|
||||
else
|
||||
{
|
||||
Print("=== DEBUG INFO (Tick) ===");
|
||||
}
|
||||
|
||||
Print("Aktueller Close: ", aktueller_close);
|
||||
Print("EMA: ", ema_aktuell);
|
||||
Print("Preis-Abstand: ", preis_abstand, " Pips");
|
||||
Print("EMA Steigung: ", steigung, " Pips");
|
||||
Print("Differenz Close-EMA: ", aktueller_close - ema_aktuell);
|
||||
Print("Preis-Trigger: ", esData.preis_trigger_aktiv, " Steigungs-Trigger: ", esData.steigung_trigger_aktiv);
|
||||
Print("Überwachung aktiv: ", esData.überwachung_aktiv);
|
||||
Print("Position offen: ", PositionExistsByMagic(esData.symbol, (ulong)ES_MagicNumber));
|
||||
Print("Trades im aktuellen Crossover: ", esData.trades_in_current_crossover, "/", ES_MaxTradesPerCrossover);
|
||||
Print("==================");
|
||||
}
|
||||
|
||||
//--- Überwachung prüfen (Check monitoring)
|
||||
if(esData.überwachung_aktiv)
|
||||
{
|
||||
if(ES_UseBarData)
|
||||
{
|
||||
// Bar-basierte Überwachungszeit
|
||||
int bars_since_monitoring = iBarShift(esData.symbol, ES_Timeframe, esData.letzte_überwachung_zeit);
|
||||
int timeout_bars = (int)(ES_ÜberwachungTimeout / PeriodSeconds(ES_Timeframe));
|
||||
|
||||
if(bars_since_monitoring > timeout_bars)
|
||||
{
|
||||
esData.überwachung_aktiv = false;
|
||||
esData.preis_trigger_aktiv = false;
|
||||
esData.steigung_trigger_aktiv = false;
|
||||
Print("Überwachung beendet - Bar-basierte Zeitüberschreitung (", bars_since_monitoring, " Bars)");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Tick-basierte Überwachungszeit
|
||||
if(TimeCurrent() - esData.letzte_überwachung_zeit > ES_ÜberwachungTimeout)
|
||||
{
|
||||
esData.überwachung_aktiv = false;
|
||||
esData.preis_trigger_aktiv = false;
|
||||
esData.steigung_trigger_aktiv = false;
|
||||
Print("Überwachung beendet - Tick-basierte Zeitüberschreitung");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//--- Trigger-Bedingungen prüfen (Check trigger conditions)
|
||||
PrüfeTrigger();
|
||||
|
||||
//--- Trade Management (Trade management)
|
||||
VerwalteTrades();
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
@@ -0,0 +1,240 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| RSICrossOverReversalStrategy.mqh |
|
||||
//+------------------------------------------------------------------+
|
||||
|
||||
void WeekDays_Init()
|
||||
{
|
||||
rcData.WeekDays[0] = RC_Sunday;
|
||||
rcData.WeekDays[1] = RC_Monday;
|
||||
rcData.WeekDays[2] = RC_Tuesday;
|
||||
rcData.WeekDays[3] = RC_Wednesday;
|
||||
rcData.WeekDays[4] = RC_Thursday;
|
||||
rcData.WeekDays[5] = RC_Friday;
|
||||
rcData.WeekDays[6] = RC_Saturday;
|
||||
}
|
||||
|
||||
bool WeekDays_Check(datetime aTime)
|
||||
{
|
||||
MqlDateTime stm;
|
||||
TimeToStruct(aTime, stm);
|
||||
return(rcData.WeekDays[stm.day_of_week]);
|
||||
}
|
||||
|
||||
int TimeHour(datetime when = 0)
|
||||
{
|
||||
if(when == 0) when = TimeCurrent();
|
||||
MqlDateTime dt;
|
||||
TimeToStruct(when, dt);
|
||||
return dt.hour;
|
||||
}
|
||||
|
||||
bool InitRSICrossOverReversal(string symbol)
|
||||
{
|
||||
WeekDays_Init();
|
||||
|
||||
rcData.symbol = symbol;
|
||||
rcData.previousRSIDef = 0;
|
||||
rcData.lastTradeTime = 0;
|
||||
rcData.bartime = 0;
|
||||
rcData.lastBarTime = 0;
|
||||
|
||||
// Check if symbol exists
|
||||
if(!SymbolSelect(symbol, true))
|
||||
{
|
||||
Print("RSICrossOverReversal: Symbol '", symbol, "' not available in Market Watch. Please add it to Market Watch or check symbol name.");
|
||||
return false;
|
||||
}
|
||||
|
||||
Sleep(100); // Wait for symbol to be ready
|
||||
|
||||
rcData.rsiHandle = iRSI(symbol, RC_TimeFrame1, RC_rsiPeriod, PRICE_CLOSE);
|
||||
if(rcData.rsiHandle == INVALID_HANDLE)
|
||||
{
|
||||
Print("RSICrossOverReversal: Error creating RSI handle for '", symbol, "'");
|
||||
return false;
|
||||
}
|
||||
|
||||
rcData.emaHandle = iMA(symbol, RC_TimeFrame2, RC_emaPeriod, 0, MODE_EMA, PRICE_CLOSE);
|
||||
if(rcData.emaHandle == INVALID_HANDLE)
|
||||
{
|
||||
Print("RSICrossOverReversal: Error creating EMA handle for '", symbol, "'");
|
||||
return false;
|
||||
}
|
||||
|
||||
rcData.trade.SetExpertMagicNumber(RC_MagicNumber);
|
||||
rcData.isInitialized = true;
|
||||
Print("RSICrossOverReversal: Successfully initialized for symbol '", symbol, "'");
|
||||
return true;
|
||||
}
|
||||
|
||||
void DeinitRSICrossOverReversal()
|
||||
{
|
||||
if(rcData.rsiHandle != INVALID_HANDLE)
|
||||
IndicatorRelease(rcData.rsiHandle);
|
||||
if(rcData.emaHandle != INVALID_HANDLE)
|
||||
IndicatorRelease(rcData.emaHandle);
|
||||
}
|
||||
|
||||
void Close_Position_MN(ulong magicNumber)
|
||||
{
|
||||
ClosePositionByMagic(rcData.trade, rcData.symbol, (int)magicNumber);
|
||||
}
|
||||
|
||||
void ApplyTrailingStop()
|
||||
{
|
||||
if(!PositionSelectByMagic(rcData.symbol, RC_MagicNumber))
|
||||
return;
|
||||
|
||||
ulong PositionTicket = PositionGetInteger(POSITION_TICKET);
|
||||
ENUM_POSITION_TYPE trade_type = (ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);
|
||||
string symbol = rcData.symbol;
|
||||
|
||||
double POINT = SymbolInfoDouble(symbol, SYMBOL_POINT);
|
||||
int DIGIT = (int)SymbolInfoInteger(symbol, SYMBOL_DIGITS);
|
||||
|
||||
if(trade_type == POSITION_TYPE_BUY)
|
||||
{
|
||||
double Bid = NormalizeDouble(SymbolInfoDouble(symbol, SYMBOL_BID), DIGIT);
|
||||
|
||||
if(Bid - PositionGetDouble(POSITION_PRICE_OPEN) > NormalizeDouble(POINT * RC_TrailingStop, DIGIT))
|
||||
{
|
||||
if(PositionGetDouble(POSITION_SL) < NormalizeDouble(Bid - POINT * RC_TrailingStop, DIGIT))
|
||||
{
|
||||
ModifyPositionByMagic(rcData.trade, symbol, RC_MagicNumber,
|
||||
NormalizeDouble(Bid - POINT * RC_TrailingStop, DIGIT),
|
||||
PositionGetDouble(POSITION_TP));
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(trade_type == POSITION_TYPE_SELL)
|
||||
{
|
||||
double Ask = NormalizeDouble(SymbolInfoDouble(symbol, SYMBOL_ASK), DIGIT);
|
||||
|
||||
if((PositionGetDouble(POSITION_PRICE_OPEN) - Ask) > NormalizeDouble(POINT * RC_TrailingStop, DIGIT))
|
||||
{
|
||||
if((PositionGetDouble(POSITION_SL) > NormalizeDouble(Ask + POINT * RC_TrailingStop, DIGIT)) ||
|
||||
(PositionGetDouble(POSITION_SL) == 0))
|
||||
{
|
||||
ModifyPositionByMagic(rcData.trade, symbol, RC_MagicNumber,
|
||||
NormalizeDouble(Ask + POINT * RC_TrailingStop, DIGIT),
|
||||
PositionGetDouble(POSITION_TP));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ProcessRSICrossOverReversal(string symbol)
|
||||
{
|
||||
// Skip if not initialized (symbol not available)
|
||||
if(!rcData.isInitialized)
|
||||
return;
|
||||
|
||||
rcData.symbol = symbol; // Update symbol in case it changed
|
||||
if(rcData.bartime == iTime(rcData.symbol, RC_BarTimeFrame, 0))
|
||||
return;
|
||||
rcData.bartime = iTime(rcData.symbol, RC_BarTimeFrame, 0);
|
||||
|
||||
double rsi[];
|
||||
if(CopyBuffer(rcData.rsiHandle, 0, 0, 2, rsi) <= 0)
|
||||
return;
|
||||
|
||||
double ema[];
|
||||
if(CopyBuffer(rcData.emaHandle, 0, 0, 2, ema) <= 0)
|
||||
return;
|
||||
|
||||
datetime currentTime = TimeCurrent();
|
||||
int currentHour = TimeHour(TimeCurrent());
|
||||
|
||||
if(!WeekDays_Check(TimeTradeServer()))
|
||||
{
|
||||
Close_Position_MN(RC_MagicNumber);
|
||||
return;
|
||||
}
|
||||
|
||||
if(!((currentHour < RC_tradingHourOneEnd && currentHour > RC_tradingHourOneBegin) ||
|
||||
(currentHour < RC_tradingHourTwoEnd && currentHour > RC_tradingHourTwoBegin)))
|
||||
{
|
||||
Close_Position_MN(RC_MagicNumber);
|
||||
return;
|
||||
}
|
||||
|
||||
bool hasPosition = PositionExistsByMagic(rcData.symbol, RC_MagicNumber);
|
||||
|
||||
double currentRSI = rsi[0];
|
||||
double previousRSI = rsi[1];
|
||||
|
||||
if(rcData.previousRSIDef == 0)
|
||||
{
|
||||
rcData.previousRSIDef = currentRSI;
|
||||
return;
|
||||
}
|
||||
|
||||
double currentEMA = ema[0];
|
||||
double previousEMA = ema[1];
|
||||
|
||||
double emaSlope = (currentEMA - previousEMA) * 100;
|
||||
double closeCurr = iClose(Symbol(), Period(), 0);
|
||||
double priceToEmaDistance = (closeCurr - currentEMA) * 10;
|
||||
|
||||
bool isBuyPosition = false;
|
||||
bool isSellPosition = false;
|
||||
if(hasPosition)
|
||||
{
|
||||
if(PositionSelectByMagic(rcData.symbol, RC_MagicNumber))
|
||||
{
|
||||
ENUM_POSITION_TYPE positionType = (ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);
|
||||
if(positionType == POSITION_TYPE_BUY)
|
||||
isBuyPosition = true;
|
||||
else if(positionType == POSITION_TYPE_SELL)
|
||||
isSellPosition = true;
|
||||
}
|
||||
}
|
||||
|
||||
ApplyTrailingStop();
|
||||
|
||||
bool cooldownPassed = (currentTime - rcData.lastTradeTime) >= RC_cooldownSeconds;
|
||||
bool isTrendStrong = MathAbs(emaSlope) > RC_emaSlopeThreshold || MathAbs(priceToEmaDistance) > RC_emaDistanceThreshold;
|
||||
|
||||
if(isBuyPosition && currentRSI > RC_exitBuyRSI)
|
||||
{
|
||||
Close_Position_MN(RC_MagicNumber);
|
||||
rcData.lastTradeTime = currentTime;
|
||||
}
|
||||
|
||||
if(isSellPosition && currentRSI < RC_exitSellRSI)
|
||||
{
|
||||
Close_Position_MN(RC_MagicNumber);
|
||||
rcData.lastTradeTime = currentTime;
|
||||
}
|
||||
|
||||
if(isTrendStrong)
|
||||
{
|
||||
Close_Position_MN(RC_MagicNumber);
|
||||
rcData.lastTradeTime = currentTime;
|
||||
return;
|
||||
}
|
||||
|
||||
if(currentRSI < RC_overboughtLevel - RC_entryRSISellSpread && rcData.previousRSIDef >= RC_overboughtLevel &&
|
||||
!isSellPosition && !hasPosition && cooldownPassed)
|
||||
{
|
||||
rcData.trade.SetExpertMagicNumber(RC_MagicNumber);
|
||||
if(rcData.trade.Sell(g_RC_LotSize, rcData.symbol, 0.0, 0.0, 0.0, "Sell Order"))
|
||||
{
|
||||
rcData.lastTradeTime = currentTime;
|
||||
}
|
||||
}
|
||||
|
||||
if(currentRSI > RC_oversoldLevel + RC_entryRSIBuySpread && rcData.previousRSIDef <= RC_oversoldLevel &&
|
||||
!isBuyPosition && !hasPosition && cooldownPassed)
|
||||
{
|
||||
rcData.trade.SetExpertMagicNumber(RC_MagicNumber);
|
||||
if(rcData.trade.Buy(g_RC_LotSize, rcData.symbol, 0.0, 0.0, 0.0, "Buy Order"))
|
||||
{
|
||||
rcData.lastTradeTime = currentTime;
|
||||
}
|
||||
}
|
||||
|
||||
rcData.previousRSIDef = currentRSI;
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
@@ -0,0 +1,471 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| RSIMidPointHijackStrategy.mqh |
|
||||
//+------------------------------------------------------------------+
|
||||
|
||||
bool IsNewBar(string symbol)
|
||||
{
|
||||
datetime time[];
|
||||
if(CopyTime(symbol, RM_InpTimeframe, 0, 1, time) > 0)
|
||||
{
|
||||
if(time[0] != rmData.lastBarTime)
|
||||
{
|
||||
rmData.lastBarTime = time[0];
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool IsWithinTradingHours(int startHour, int endHour)
|
||||
{
|
||||
MqlDateTime currentTime;
|
||||
TimeToStruct(TimeCurrent(), currentTime);
|
||||
|
||||
if(startHour <= endHour)
|
||||
return (currentTime.hour >= startHour && currentTime.hour < endHour);
|
||||
else
|
||||
return (currentTime.hour >= startHour || currentTime.hour < endHour);
|
||||
}
|
||||
|
||||
bool HasPosition(string symbol, int magic)
|
||||
{
|
||||
return PositionExistsByMagic(symbol, magic);
|
||||
}
|
||||
|
||||
bool HasProfitablePosition(int excludeMagic)
|
||||
{
|
||||
bool hasProfitable = false;
|
||||
for(int i = PositionsTotal() - 1; i >= 0; i--)
|
||||
{
|
||||
if(rmData.positionInfo.SelectByIndex(i))
|
||||
{
|
||||
if(rmData.positionInfo.Magic() != excludeMagic)
|
||||
{
|
||||
double profit = rmData.positionInfo.Profit();
|
||||
if(profit > RM_InpLockProfitThreshold * _Point)
|
||||
{
|
||||
hasProfitable = true;
|
||||
if(RM_InpCloseOppositeTrades)
|
||||
{
|
||||
if((excludeMagic == RM_InpMagicNumberRSIFollow && rmData.positionInfo.Magic() == RM_InpMagicNumberRSIReverse) ||
|
||||
(excludeMagic == RM_InpMagicNumberRSIReverse && rmData.positionInfo.Magic() == RM_InpMagicNumberRSIFollow) ||
|
||||
(excludeMagic == RM_InpMagicNumberEMACross && (rmData.positionInfo.Magic() == RM_InpMagicNumberRSIReverse || rmData.positionInfo.Magic() == RM_InpMagicNumberRSIFollow)) ||
|
||||
((excludeMagic == RM_InpMagicNumberRSIFollow || excludeMagic == RM_InpMagicNumberRSIReverse) && rmData.positionInfo.Magic() == RM_InpMagicNumberEMACross))
|
||||
{
|
||||
ClosePosition(rmData.symbol, (int)rmData.positionInfo.Magic());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return hasProfitable;
|
||||
}
|
||||
|
||||
bool IsRSIReverseInCooldown(string symbol)
|
||||
{
|
||||
if(RM_InpRSIReverseCooldownBars <= 0)
|
||||
return false;
|
||||
|
||||
if(!rmData.rsiReverseInCooldown)
|
||||
return false;
|
||||
|
||||
datetime time[];
|
||||
if(CopyTime(symbol, RM_InpTimeframe, 0, 1, time) > 0)
|
||||
{
|
||||
datetime currentBarTime = time[0];
|
||||
datetime cooldownEndTime = rmData.rsiReverseLastCloseTime + RM_InpRSIReverseCooldownBars * PeriodSeconds(RM_InpTimeframe);
|
||||
|
||||
if(currentBarTime >= cooldownEndTime)
|
||||
{
|
||||
rmData.rsiReverseInCooldown = false;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void CheckRSIFollowStrategy(string symbol)
|
||||
{
|
||||
if(!IsWithinTradingHours(RM_InpRSIFollowStartHour, RM_InpRSIFollowEndHour))
|
||||
{
|
||||
if(RM_InpRSIFollowCloseOutsideHours)
|
||||
{
|
||||
if(HasPosition(symbol, RM_InpMagicNumberRSIFollow))
|
||||
ClosePosition(symbol, RM_InpMagicNumberRSIFollow);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if(RM_InpEnableStrategyLock && HasProfitablePosition(RM_InpMagicNumberRSIFollow))
|
||||
return;
|
||||
|
||||
if(rmData.lastBarRSI > RM_InpRSIOverbought)
|
||||
rmData.rsiOverbought = true;
|
||||
else if(rmData.lastBarRSI < RM_InpRSIOversold)
|
||||
rmData.rsiOversold = true;
|
||||
|
||||
if(rmData.rsiOverbought && rmData.lastBarRSI < RM_InpRSIExitLevel)
|
||||
{
|
||||
if(!HasPosition(symbol, RM_InpMagicNumberRSIFollow))
|
||||
{
|
||||
rmData.trade.SetExpertMagicNumber(RM_InpMagicNumberRSIFollow);
|
||||
rmData.trade.Sell(g_RM_LotSize, symbol, 0, 0, 0, "RSI Follow");
|
||||
}
|
||||
rmData.rsiOverbought = false;
|
||||
}
|
||||
else if(rmData.rsiOversold && rmData.lastBarRSI > RM_InpRSIExitLevel)
|
||||
{
|
||||
if(!HasPosition(symbol, RM_InpMagicNumberRSIFollow))
|
||||
{
|
||||
rmData.trade.SetExpertMagicNumber(RM_InpMagicNumberRSIFollow);
|
||||
rmData.trade.Buy(g_RM_LotSize, symbol, 0, 0, 0, "RSI Follow");
|
||||
}
|
||||
rmData.rsiOversold = false;
|
||||
}
|
||||
}
|
||||
|
||||
void CheckRSIReverseStrategy(string symbol)
|
||||
{
|
||||
if(!IsWithinTradingHours(RM_InpRSIReverseStartHour, RM_InpRSIReverseEndHour))
|
||||
{
|
||||
if(RM_InpRSIReverseCloseOutsideHours)
|
||||
{
|
||||
if(HasPosition(symbol, RM_InpMagicNumberRSIReverse))
|
||||
ClosePosition(symbol, RM_InpMagicNumberRSIReverse);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if(RM_InpEnableStrategyLock && HasProfitablePosition(RM_InpMagicNumberRSIReverse))
|
||||
return;
|
||||
|
||||
if(IsRSIReverseInCooldown(symbol))
|
||||
return;
|
||||
|
||||
if(rmData.lastBarRSIReverse > RM_InpRSIReverseOverbought)
|
||||
rmData.rsiReverseOverbought = true;
|
||||
else if(rmData.lastBarRSIReverse < RM_InpRSIReverseOversold)
|
||||
rmData.rsiReverseOversold = true;
|
||||
|
||||
if(rmData.rsiReverseOverbought && rmData.lastBarRSIReverse < RM_InpRSIReverseCrossLevel)
|
||||
{
|
||||
if(!HasPosition(symbol, RM_InpMagicNumberRSIReverse))
|
||||
{
|
||||
rmData.trade.SetExpertMagicNumber(RM_InpMagicNumberRSIReverse);
|
||||
rmData.trade.Sell(g_RM_LotSize, symbol, 0, 0, 0, "RSI Reverse");
|
||||
}
|
||||
rmData.rsiReverseOverbought = false;
|
||||
}
|
||||
else if(rmData.rsiReverseOversold && rmData.lastBarRSIReverse > RM_InpRSIReverseCrossLevel)
|
||||
{
|
||||
if(!HasPosition(symbol, RM_InpMagicNumberRSIReverse))
|
||||
{
|
||||
rmData.trade.SetExpertMagicNumber(RM_InpMagicNumberRSIReverse);
|
||||
rmData.trade.Buy(g_RM_LotSize, symbol, 0, 0, 0, "RSI Reverse");
|
||||
}
|
||||
rmData.rsiReverseOversold = false;
|
||||
}
|
||||
}
|
||||
|
||||
void CheckEMACrossStrategy(string symbol)
|
||||
{
|
||||
if(!IsWithinTradingHours(RM_InpEMACrossStartHour, RM_InpEMACrossEndHour))
|
||||
{
|
||||
if(RM_InpEMACrossCloseOutsideHours)
|
||||
{
|
||||
if(HasPosition(symbol, RM_InpMagicNumberEMACross))
|
||||
ClosePosition(symbol, RM_InpMagicNumberEMACross);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if(RM_InpEnableStrategyLock && HasProfitablePosition(RM_InpMagicNumberEMACross))
|
||||
return;
|
||||
|
||||
if(rmData.lastBarEMAPrev < rmData.lastBarClosePrev && rmData.lastBarEMA > rmData.lastBarClose)
|
||||
{
|
||||
rmData.emaCrossBuySignal = true;
|
||||
rmData.emaCrossSellSignal = false;
|
||||
rmData.emaCrossSignalBar = 0;
|
||||
}
|
||||
else if(rmData.lastBarEMAPrev > rmData.lastBarClosePrev && rmData.lastBarEMA < rmData.lastBarClose)
|
||||
{
|
||||
rmData.emaCrossSellSignal = true;
|
||||
rmData.emaCrossBuySignal = false;
|
||||
rmData.emaCrossSignalBar = 0;
|
||||
}
|
||||
|
||||
if(RM_InpUseEMADistanceEntry)
|
||||
{
|
||||
if(rmData.emaCrossBuySignal)
|
||||
{
|
||||
bool distanceConditionMet = true;
|
||||
double emaHistory[], closeHistory[];
|
||||
ArraySetAsSeries(emaHistory, true);
|
||||
ArraySetAsSeries(closeHistory, true);
|
||||
|
||||
if(CopyBuffer(rmData.emaHandle, 0, 0, RM_InpEMADistancePeriod, emaHistory) > 0 &&
|
||||
CopyClose(symbol, RM_InpTimeframe, 0, RM_InpEMADistancePeriod, closeHistory) > 0)
|
||||
{
|
||||
double point = SymbolInfoDouble(symbol, SYMBOL_POINT);
|
||||
for(int i = 0; i < RM_InpEMADistancePeriod; i++)
|
||||
{
|
||||
double distance = (closeHistory[i] - emaHistory[i]) / point;
|
||||
if(distance < RM_InpEMADistancePips)
|
||||
{
|
||||
distanceConditionMet = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(distanceConditionMet && !HasPosition(symbol, RM_InpMagicNumberEMACross))
|
||||
{
|
||||
rmData.trade.SetExpertMagicNumber(RM_InpMagicNumberEMACross);
|
||||
rmData.trade.Buy(g_RM_LotSize, symbol, 0, 0, 0, "EMA Cross Distance");
|
||||
rmData.emaCrossBuySignal = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(rmData.emaCrossSellSignal)
|
||||
{
|
||||
bool distanceConditionMet = true;
|
||||
double emaHistory[], closeHistory[];
|
||||
ArraySetAsSeries(emaHistory, true);
|
||||
ArraySetAsSeries(closeHistory, true);
|
||||
|
||||
if(CopyBuffer(rmData.emaHandle, 0, 0, RM_InpEMADistancePeriod, emaHistory) > 0 &&
|
||||
CopyClose(symbol, RM_InpTimeframe, 0, RM_InpEMADistancePeriod, closeHistory) > 0)
|
||||
{
|
||||
double point = SymbolInfoDouble(symbol, SYMBOL_POINT);
|
||||
for(int i = 0; i < RM_InpEMADistancePeriod; i++)
|
||||
{
|
||||
double distance = (emaHistory[i] - closeHistory[i]) / point;
|
||||
if(distance < RM_InpEMADistancePips)
|
||||
{
|
||||
distanceConditionMet = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(distanceConditionMet && !HasPosition(symbol, RM_InpMagicNumberEMACross))
|
||||
{
|
||||
rmData.trade.SetExpertMagicNumber(RM_InpMagicNumberEMACross);
|
||||
rmData.trade.Sell(g_RM_LotSize, symbol, 0, 0, 0, "EMA Cross Distance");
|
||||
rmData.emaCrossSellSignal = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(rmData.lastBarEMAPrev < rmData.lastBarClosePrev && rmData.lastBarEMA > rmData.lastBarClose)
|
||||
{
|
||||
if(!HasPosition(symbol, RM_InpMagicNumberEMACross))
|
||||
{
|
||||
rmData.trade.SetExpertMagicNumber(RM_InpMagicNumberEMACross);
|
||||
rmData.trade.Buy(g_RM_LotSize, symbol, 0, 0, 0, "EMA Cross");
|
||||
}
|
||||
}
|
||||
else if(rmData.lastBarEMAPrev > rmData.lastBarClosePrev && rmData.lastBarEMA < rmData.lastBarClose)
|
||||
{
|
||||
if(!HasPosition(symbol, RM_InpMagicNumberEMACross))
|
||||
{
|
||||
rmData.trade.SetExpertMagicNumber(RM_InpMagicNumberEMACross);
|
||||
rmData.trade.Sell(g_RM_LotSize, symbol, 0, 0, 0, "EMA Cross");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(rmData.emaCrossBuySignal || rmData.emaCrossSellSignal)
|
||||
{
|
||||
rmData.emaCrossSignalBar++;
|
||||
if(rmData.emaCrossSignalBar > RM_InpEMADistancePeriod * 2)
|
||||
{
|
||||
rmData.emaCrossBuySignal = false;
|
||||
rmData.emaCrossSellSignal = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CheckExitConditions(string symbol)
|
||||
{
|
||||
if(RM_InpEnableRSIFollow)
|
||||
{
|
||||
if(HasPosition(symbol, RM_InpMagicNumberRSIFollow))
|
||||
{
|
||||
if(PositionSelectByMagic(symbol, RM_InpMagicNumberRSIFollow))
|
||||
{
|
||||
ENUM_POSITION_TYPE posType = (ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);
|
||||
if((posType == POSITION_TYPE_BUY && rmData.lastBarRSI < RM_InpRSIExitLevel) ||
|
||||
(posType == POSITION_TYPE_SELL && rmData.lastBarRSI > RM_InpRSIExitLevel))
|
||||
{
|
||||
ClosePosition(symbol, RM_InpMagicNumberRSIFollow);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(RM_InpEnableRSIReverse)
|
||||
{
|
||||
if(HasPosition(symbol, RM_InpMagicNumberRSIReverse))
|
||||
{
|
||||
if(PositionSelectByMagic(symbol, RM_InpMagicNumberRSIReverse))
|
||||
{
|
||||
ENUM_POSITION_TYPE posType = (ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);
|
||||
if((posType == POSITION_TYPE_BUY && rmData.lastBarRSIReverse < RM_InpRSIReverseExitLevel) ||
|
||||
(posType == POSITION_TYPE_SELL && rmData.lastBarRSIReverse > RM_InpRSIReverseExitLevel))
|
||||
{
|
||||
ClosePosition(symbol, RM_InpMagicNumberRSIReverse);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(RM_InpEnableEMACross)
|
||||
{
|
||||
if(HasPosition(symbol, RM_InpMagicNumberEMACross))
|
||||
{
|
||||
if(PositionSelectByMagic(symbol, RM_InpMagicNumberEMACross))
|
||||
{
|
||||
ENUM_POSITION_TYPE posType = (ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);
|
||||
if((posType == POSITION_TYPE_BUY && rmData.lastBarEMA > rmData.lastBarClose) ||
|
||||
(posType == POSITION_TYPE_SELL && rmData.lastBarEMA < rmData.lastBarClose))
|
||||
{
|
||||
ClosePosition(symbol, RM_InpMagicNumberEMACross);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ClosePosition(string symbol, int magic)
|
||||
{
|
||||
if(!PositionExistsByMagic(symbol, magic))
|
||||
return;
|
||||
|
||||
ulong ticket = GetPositionTicketByMagic(symbol, magic);
|
||||
if(ticket == 0)
|
||||
return;
|
||||
|
||||
if(magic == RM_InpMagicNumberRSIReverse)
|
||||
{
|
||||
if(PositionSelectByTicketSymbolAndMagic(ticket, symbol, magic))
|
||||
{
|
||||
datetime time[];
|
||||
if(CopyTime(symbol, RM_InpTimeframe, 0, 1, time) > 0)
|
||||
{
|
||||
rmData.rsiReverseLastCloseTime = time[0];
|
||||
double profit = PositionGetDouble(POSITION_PROFIT);
|
||||
if(!RM_InpRSIReverseCooldownOnLoss || profit < 0)
|
||||
{
|
||||
rmData.rsiReverseInCooldown = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ClosePositionByMagic(rmData.trade, symbol, magic);
|
||||
}
|
||||
|
||||
bool InitRSIMidPointHijack(string symbol)
|
||||
{
|
||||
rmData.symbol = symbol;
|
||||
rmData.rsiOverbought = false;
|
||||
rmData.rsiOversold = false;
|
||||
rmData.rsiReverseOverbought = false;
|
||||
rmData.rsiReverseOversold = false;
|
||||
rmData.emaCrossBuySignal = false;
|
||||
rmData.emaCrossSellSignal = false;
|
||||
rmData.emaCrossSignalBar = 0;
|
||||
rmData.rsiReverseInCooldown = false;
|
||||
rmData.lastBarRSI = 0;
|
||||
rmData.lastBarRSIReverse = 0;
|
||||
rmData.lastBarEMA = 0;
|
||||
rmData.lastBarClose = 0;
|
||||
rmData.lastBarEMAPrev = 0;
|
||||
rmData.lastBarClosePrev = 0;
|
||||
|
||||
// Check if symbol exists
|
||||
if(!SymbolSelect(symbol, true))
|
||||
{
|
||||
Print("RSIMidPointHijack: Symbol '", symbol, "' not available in Market Watch. Please add it to Market Watch or check symbol name.");
|
||||
return false;
|
||||
}
|
||||
|
||||
Sleep(100); // Wait for symbol to be ready
|
||||
|
||||
rmData.rsiHandle = iRSI(symbol, RM_InpTimeframe, RM_InpRSIPeriod, PRICE_CLOSE);
|
||||
rmData.rsiReverseHandle = iRSI(symbol, RM_InpTimeframe, RM_InpRSIReversePeriod, PRICE_CLOSE);
|
||||
rmData.emaHandle = iMA(symbol, RM_InpTimeframe, RM_InpEMAPeriod, 0, MODE_EMA, PRICE_CLOSE);
|
||||
|
||||
if(rmData.rsiHandle == INVALID_HANDLE || rmData.rsiReverseHandle == INVALID_HANDLE || rmData.emaHandle == INVALID_HANDLE)
|
||||
{
|
||||
Print("RSIMidPointHijack: Error creating indicators for '", symbol, "'");
|
||||
return false;
|
||||
}
|
||||
|
||||
rmData.trade.SetExpertMagicNumber(RM_InpMagicNumberRSIFollow);
|
||||
rmData.trade.SetMarginMode();
|
||||
rmData.trade.SetTypeFillingBySymbol(symbol);
|
||||
rmData.trade.SetDeviationInPoints(10);
|
||||
|
||||
datetime time[];
|
||||
if(CopyTime(symbol, RM_InpTimeframe, 0, 1, time) > 0)
|
||||
rmData.lastBarTime = time[0];
|
||||
|
||||
rmData.isInitialized = true;
|
||||
Print("RSIMidPointHijack: Successfully initialized for symbol '", symbol, "'");
|
||||
return true;
|
||||
}
|
||||
|
||||
void DeinitRSIMidPointHijack()
|
||||
{
|
||||
if(rmData.rsiHandle != INVALID_HANDLE) IndicatorRelease(rmData.rsiHandle);
|
||||
if(rmData.rsiReverseHandle != INVALID_HANDLE) IndicatorRelease(rmData.rsiReverseHandle);
|
||||
if(rmData.emaHandle != INVALID_HANDLE) IndicatorRelease(rmData.emaHandle);
|
||||
}
|
||||
|
||||
void ProcessRSIMidPointHijack(string symbol)
|
||||
{
|
||||
// Skip if not initialized (symbol not available)
|
||||
if(!rmData.isInitialized)
|
||||
return;
|
||||
|
||||
rmData.symbol = symbol; // Update symbol in case it changed
|
||||
if(!IsNewBar(rmData.symbol))
|
||||
return;
|
||||
|
||||
double rsi[], rsiReverse[], ema[], close[];
|
||||
ArraySetAsSeries(rsi, true);
|
||||
ArraySetAsSeries(rsiReverse, true);
|
||||
ArraySetAsSeries(ema, true);
|
||||
ArraySetAsSeries(close, true);
|
||||
|
||||
rmData.lastBarEMAPrev = rmData.lastBarEMA;
|
||||
rmData.lastBarClosePrev = rmData.lastBarClose;
|
||||
|
||||
if(CopyBuffer(rmData.rsiHandle, 0, 0, 1, rsi) > 0)
|
||||
rmData.lastBarRSI = rsi[0];
|
||||
|
||||
if(CopyBuffer(rmData.rsiReverseHandle, 0, 0, 1, rsiReverse) > 0)
|
||||
rmData.lastBarRSIReverse = rsiReverse[0];
|
||||
|
||||
if(CopyBuffer(rmData.emaHandle, 0, 0, 1, ema) > 0)
|
||||
rmData.lastBarEMA = ema[0];
|
||||
|
||||
if(CopyClose(rmData.symbol, RM_InpTimeframe, 0, 1, close) > 0)
|
||||
rmData.lastBarClose = close[0];
|
||||
|
||||
if(RM_InpEnableRSIFollow)
|
||||
CheckRSIFollowStrategy(rmData.symbol);
|
||||
if(RM_InpEnableRSIReverse)
|
||||
CheckRSIReverseStrategy(rmData.symbol);
|
||||
if(RM_InpEnableEMACross)
|
||||
CheckEMACrossStrategy(rmData.symbol);
|
||||
|
||||
CheckExitConditions(rmData.symbol);
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
@@ -0,0 +1,493 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| RSIReversalAsianStrategy.mqh |
|
||||
//+------------------------------------------------------------------+
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| RSI Reversal Asian Strategy Data Structure |
|
||||
//+------------------------------------------------------------------+
|
||||
struct RSIReversalAsianData {
|
||||
string symbol;
|
||||
bool isInitialized;
|
||||
int rsiHandle;
|
||||
CTrade trade;
|
||||
bool isPositionOpen;
|
||||
double positionOpenPrice;
|
||||
datetime positionOpenTime;
|
||||
ENUM_POSITION_TYPE lastPositionType;
|
||||
bool sessionCloseAttempted;
|
||||
|
||||
// RSI crossover variables
|
||||
double rsiCurrent;
|
||||
double rsiPrevious;
|
||||
double rsiPrevious2;
|
||||
bool rsiCrossedOverbought;
|
||||
bool rsiCrossedOversold;
|
||||
bool rsiCrossedExitLevel;
|
||||
|
||||
// Strategy parameters
|
||||
int RSIPeriod;
|
||||
double OverboughtLevel;
|
||||
double OversoldLevel;
|
||||
int TakeProfitPips;
|
||||
int StopLossPips;
|
||||
double MaxLotSize;
|
||||
int MaxSpread;
|
||||
int MaxDuration;
|
||||
bool UseStopLoss;
|
||||
bool UseTakeProfit;
|
||||
bool UseRSIExit;
|
||||
double RSIExitLevel;
|
||||
bool CloseOutsideSession;
|
||||
ENUM_TIMEFRAMES TimeFrame;
|
||||
int MagicNumber;
|
||||
int Slippage;
|
||||
double point;
|
||||
};
|
||||
|
||||
// Session times (UTC)
|
||||
const int AsianSessionStart = 0; // 00:00 UTC
|
||||
const int AsianSessionEnd = 8; // 08:00 UTC
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Check if current time is in Asian session |
|
||||
//+------------------------------------------------------------------+
|
||||
bool IsAsianSession()
|
||||
{
|
||||
datetime currentTime = TimeCurrent();
|
||||
MqlDateTime timeStruct;
|
||||
TimeToStruct(currentTime, timeStruct);
|
||||
|
||||
return (timeStruct.hour >= AsianSessionStart && timeStruct.hour < AsianSessionEnd);
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Check if trading is allowed for symbol |
|
||||
//+------------------------------------------------------------------+
|
||||
bool IsTradingAllowed(RSIReversalAsianData& data)
|
||||
{
|
||||
// Check if market is open
|
||||
long tradeMode = SymbolInfoInteger(data.symbol, SYMBOL_TRADE_MODE);
|
||||
if(tradeMode != SYMBOL_TRADE_MODE_FULL)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check if we have enough money
|
||||
if(AccountInfoDouble(ACCOUNT_MARGIN_FREE) <= 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Check RSI crossover conditions |
|
||||
//+------------------------------------------------------------------+
|
||||
void CheckRSICrossover(RSIReversalAsianData& data)
|
||||
{
|
||||
// Reset crossover flags
|
||||
data.rsiCrossedOverbought = false;
|
||||
data.rsiCrossedOversold = false;
|
||||
data.rsiCrossedExitLevel = false;
|
||||
|
||||
// Check for overbought crossover (RSI crosses above overbought level)
|
||||
if(data.rsiPrevious < data.OverboughtLevel && data.rsiCurrent >= data.OverboughtLevel)
|
||||
{
|
||||
data.rsiCrossedOverbought = true;
|
||||
}
|
||||
|
||||
// Check for oversold crossover (RSI crosses below oversold level)
|
||||
if(data.rsiPrevious > data.OversoldLevel && data.rsiCurrent <= data.OversoldLevel)
|
||||
{
|
||||
data.rsiCrossedOversold = true;
|
||||
}
|
||||
|
||||
// Check for exit level crossover
|
||||
if(data.rsiPrevious < data.RSIExitLevel && data.rsiCurrent >= data.RSIExitLevel)
|
||||
{
|
||||
data.rsiCrossedExitLevel = true;
|
||||
}
|
||||
else if(data.rsiPrevious > data.RSIExitLevel && data.rsiCurrent <= data.RSIExitLevel)
|
||||
{
|
||||
data.rsiCrossedExitLevel = true;
|
||||
}
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Close all trades for the symbol |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CloseAllTrades(RSIReversalAsianData& data, string reason = "")
|
||||
{
|
||||
bool allClosed = true;
|
||||
int totalPositions = PositionsTotal();
|
||||
|
||||
if(totalPositions == 0)
|
||||
return true;
|
||||
|
||||
for(int i = totalPositions - 1; i >= 0; i--)
|
||||
{
|
||||
if(PositionGetSymbol(i) == data.symbol)
|
||||
{
|
||||
ulong ticket = PositionGetTicket(i);
|
||||
if(ticket > 0 && PositionSelectByTicket(ticket))
|
||||
{
|
||||
if(PositionGetInteger(POSITION_MAGIC) == (ulong)data.MagicNumber)
|
||||
{
|
||||
// Try to close position with retry logic
|
||||
int retryCount = 0;
|
||||
bool positionClosed = false;
|
||||
|
||||
while(retryCount < 3 && !positionClosed)
|
||||
{
|
||||
if(data.trade.PositionClose(ticket))
|
||||
{
|
||||
data.isPositionOpen = false;
|
||||
positionClosed = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
int error = GetLastError();
|
||||
|
||||
// If error is 4756 (Trade disabled), wait longer before retry
|
||||
if(error == 4756)
|
||||
{
|
||||
Sleep(5000); // Wait 5 seconds before retry
|
||||
retryCount++;
|
||||
}
|
||||
else
|
||||
{
|
||||
// For other errors, break the loop
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(!positionClosed)
|
||||
{
|
||||
allClosed = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return allClosed;
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Initialize RSI Reversal Asian Strategy |
|
||||
//+------------------------------------------------------------------+
|
||||
bool InitRSIReversalAsian(RSIReversalAsianData& data, string symbol,
|
||||
int RSIPeriod, double OverboughtLevel, double OversoldLevel,
|
||||
int TakeProfitPips, int StopLossPips, double MaxLotSize,
|
||||
int MaxSpread, int MaxDuration, bool UseStopLoss,
|
||||
bool UseTakeProfit, bool UseRSIExit, double RSIExitLevel,
|
||||
bool CloseOutsideSession, ENUM_TIMEFRAMES TimeFrame,
|
||||
int MagicNumber, int Slippage)
|
||||
{
|
||||
data.symbol = symbol;
|
||||
data.isInitialized = false;
|
||||
|
||||
// Check if symbol exists
|
||||
if(!SymbolSelect(symbol, true))
|
||||
{
|
||||
Print("RSIReversalAsian: Symbol '", symbol, "' not available in Market Watch. Please add it to Market Watch or check symbol name.");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Wait a bit for symbol to be ready
|
||||
Sleep(100);
|
||||
|
||||
// Get symbol point
|
||||
data.point = SymbolInfoDouble(symbol, SYMBOL_POINT);
|
||||
|
||||
// Store parameters
|
||||
data.RSIPeriod = RSIPeriod;
|
||||
data.OverboughtLevel = OverboughtLevel;
|
||||
data.OversoldLevel = OversoldLevel;
|
||||
data.TakeProfitPips = TakeProfitPips;
|
||||
data.StopLossPips = StopLossPips;
|
||||
data.MaxLotSize = MaxLotSize;
|
||||
data.MaxSpread = MaxSpread;
|
||||
data.MaxDuration = MaxDuration;
|
||||
data.UseStopLoss = UseStopLoss;
|
||||
data.UseTakeProfit = UseTakeProfit;
|
||||
data.UseRSIExit = UseRSIExit;
|
||||
data.RSIExitLevel = RSIExitLevel;
|
||||
data.CloseOutsideSession = CloseOutsideSession;
|
||||
data.TimeFrame = TimeFrame;
|
||||
data.MagicNumber = MagicNumber;
|
||||
data.Slippage = Slippage;
|
||||
|
||||
// Initialize RSI indicator with retry logic (for insufficient history in backtesting)
|
||||
data.rsiHandle = INVALID_HANDLE;
|
||||
int retryCount = 0;
|
||||
int maxRetries = 5;
|
||||
|
||||
while(retryCount < maxRetries && data.rsiHandle == INVALID_HANDLE)
|
||||
{
|
||||
data.rsiHandle = iRSI(symbol, TimeFrame, RSIPeriod, PRICE_CLOSE);
|
||||
|
||||
if(data.rsiHandle == INVALID_HANDLE)
|
||||
{
|
||||
int error = GetLastError();
|
||||
|
||||
// Error 4805 = insufficient history - wait longer and retry
|
||||
if(error == 4805 && retryCount < maxRetries - 1)
|
||||
{
|
||||
Sleep(1000); // Wait 1 second for history to load
|
||||
retryCount++;
|
||||
continue;
|
||||
}
|
||||
|
||||
Print("RSIReversalAsian: Error creating RSI indicator for '", symbol, "' - Error: ", error, " (", error == 4805 ? "Insufficient history data" : "Unknown", ")");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if(data.rsiHandle == INVALID_HANDLE)
|
||||
{
|
||||
Print("RSIReversalAsian: Failed to create RSI indicator for '", symbol, "' after ", maxRetries, " retries");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Wait a bit for the indicator to be ready
|
||||
Sleep(100);
|
||||
|
||||
// Initialize RSI values with retry logic
|
||||
double rsi[];
|
||||
ArraySetAsSeries(rsi, true);
|
||||
|
||||
int retryCount = 0;
|
||||
bool rsiInitialized = false;
|
||||
|
||||
while(retryCount < 10 && !rsiInitialized)
|
||||
{
|
||||
int copied = CopyBuffer(data.rsiHandle, 0, 0, 3, rsi);
|
||||
if(copied >= 3)
|
||||
{
|
||||
data.rsiCurrent = rsi[0];
|
||||
data.rsiPrevious = rsi[1];
|
||||
data.rsiPrevious2 = rsi[2];
|
||||
rsiInitialized = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
retryCount++;
|
||||
Sleep(100);
|
||||
}
|
||||
}
|
||||
|
||||
if(!rsiInitialized)
|
||||
{
|
||||
// Don't fail initialization, just set default values
|
||||
data.rsiCurrent = 50.0;
|
||||
data.rsiPrevious = 50.0;
|
||||
data.rsiPrevious2 = 50.0;
|
||||
}
|
||||
|
||||
// Set trade parameters
|
||||
data.trade.SetExpertMagicNumber(MagicNumber);
|
||||
data.trade.SetDeviationInPoints(Slippage);
|
||||
data.trade.SetTypeFilling(ORDER_FILLING_IOC);
|
||||
|
||||
// Initialize state
|
||||
data.isPositionOpen = false;
|
||||
data.positionOpenPrice = 0;
|
||||
data.positionOpenTime = 0;
|
||||
data.lastPositionType = POSITION_TYPE_BUY;
|
||||
data.sessionCloseAttempted = false;
|
||||
data.rsiCrossedOverbought = false;
|
||||
data.rsiCrossedOversold = false;
|
||||
data.rsiCrossedExitLevel = false;
|
||||
|
||||
data.isInitialized = true;
|
||||
|
||||
Print("RSIReversalAsian: Successfully initialized for symbol '", symbol, "'");
|
||||
return true;
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Deinitialize RSI Reversal Asian Strategy |
|
||||
//+------------------------------------------------------------------+
|
||||
void DeinitRSIReversalAsian(RSIReversalAsianData& data)
|
||||
{
|
||||
if(data.rsiHandle != INVALID_HANDLE)
|
||||
IndicatorRelease(data.rsiHandle);
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Process RSI Reversal Asian Strategy |
|
||||
//+------------------------------------------------------------------+
|
||||
void ProcessRSIReversalAsian(RSIReversalAsianData& data, double lotSize)
|
||||
{
|
||||
if(!data.isInitialized)
|
||||
return;
|
||||
|
||||
// Check if trading is allowed
|
||||
if(!IsTradingAllowed(data))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if we're in Asian session
|
||||
if(!IsAsianSession())
|
||||
{
|
||||
// Close all positions if outside Asian session and CloseOutsideSession is true
|
||||
if(data.CloseOutsideSession && !data.sessionCloseAttempted)
|
||||
{
|
||||
CloseAllTrades(data, "Outside Asian session");
|
||||
data.sessionCloseAttempted = true;
|
||||
}
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Reset the session close attempt flag when we enter Asian session
|
||||
data.sessionCloseAttempted = false;
|
||||
}
|
||||
|
||||
// Get current spread
|
||||
double spread = SymbolInfoDouble(data.symbol, SYMBOL_ASK) - SymbolInfoDouble(data.symbol, SYMBOL_BID);
|
||||
int spreadInPips = (int)(spread / data.point);
|
||||
|
||||
// Check if spread is too high
|
||||
if(spreadInPips > data.MaxSpread)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Get RSI values from bar data
|
||||
double rsi[];
|
||||
ArraySetAsSeries(rsi, true);
|
||||
|
||||
int copied = CopyBuffer(data.rsiHandle, 0, 0, 3, rsi);
|
||||
if(copied < 3)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Update RSI values
|
||||
data.rsiPrevious2 = data.rsiPrevious;
|
||||
data.rsiPrevious = data.rsiCurrent;
|
||||
data.rsiCurrent = rsi[0];
|
||||
|
||||
// Validate RSI values
|
||||
if(data.rsiCurrent == 0 || data.rsiPrevious == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Check for RSI crossovers
|
||||
CheckRSICrossover(data);
|
||||
|
||||
// Get current prices
|
||||
double currentBid = SymbolInfoDouble(data.symbol, SYMBOL_BID);
|
||||
double currentAsk = SymbolInfoDouble(data.symbol, SYMBOL_ASK);
|
||||
|
||||
// Check for open position
|
||||
bool hasOpenPosition = PositionExistsByMagic(data.symbol, (ulong)data.MagicNumber);
|
||||
|
||||
if(hasOpenPosition)
|
||||
{
|
||||
// Get position details
|
||||
ulong ticket = GetPositionTicketByMagic(data.symbol, (ulong)data.MagicNumber);
|
||||
if(ticket > 0 && PositionSelectByTicket(ticket))
|
||||
{
|
||||
ENUM_POSITION_TYPE posType = (ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);
|
||||
datetime openTime = (datetime)PositionGetInteger(POSITION_TIME);
|
||||
|
||||
// Check for RSI exit if enabled
|
||||
if(data.UseRSIExit && data.rsiCrossedExitLevel)
|
||||
{
|
||||
bool shouldExit = false;
|
||||
|
||||
// For long positions, exit when RSI crosses above exit level
|
||||
if(posType == POSITION_TYPE_BUY && data.rsiCurrent >= data.RSIExitLevel && data.rsiPrevious < data.RSIExitLevel)
|
||||
{
|
||||
shouldExit = true;
|
||||
}
|
||||
// For short positions, exit when RSI crosses below exit level
|
||||
else if(posType == POSITION_TYPE_SELL && data.rsiCurrent <= data.RSIExitLevel && data.rsiPrevious > data.RSIExitLevel)
|
||||
{
|
||||
shouldExit = true;
|
||||
}
|
||||
|
||||
if(shouldExit)
|
||||
{
|
||||
CloseAllTrades(data, "RSI Exit Crossover");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Check for timeout
|
||||
if(TimeCurrent() - openTime > data.MaxDuration * 3600)
|
||||
{
|
||||
CloseAllTrades(data, "Timeout");
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If no position is open, look for entry signals based on RSI crossover
|
||||
if(!hasOpenPosition)
|
||||
{
|
||||
// Place buy order if RSI crosses below oversold level (oversold crossover)
|
||||
if(data.rsiCrossedOversold)
|
||||
{
|
||||
double sl = data.UseStopLoss ? currentBid - data.StopLossPips * data.point : 0;
|
||||
double tp = data.UseTakeProfit ? currentBid + data.TakeProfitPips * data.point : 0;
|
||||
|
||||
if(data.UseStopLoss && sl >= currentBid)
|
||||
return;
|
||||
if(data.UseTakeProfit && tp <= currentBid)
|
||||
return;
|
||||
|
||||
// Set trade parameters
|
||||
data.trade.SetDeviationInPoints(data.Slippage);
|
||||
data.trade.SetTypeFilling(ORDER_FILLING_IOC);
|
||||
data.trade.SetExpertMagicNumber(data.MagicNumber);
|
||||
|
||||
// Use dynamic lot size
|
||||
double tradeLotSize = lotSize > 0 ? lotSize : data.MaxLotSize;
|
||||
|
||||
// Place buy order using CTrade
|
||||
if(data.trade.Buy(tradeLotSize, data.symbol, currentAsk, sl, tp, "RSI Oversold Crossover Buy"))
|
||||
{
|
||||
data.isPositionOpen = true;
|
||||
data.positionOpenPrice = currentAsk;
|
||||
data.positionOpenTime = TimeCurrent();
|
||||
data.lastPositionType = POSITION_TYPE_BUY;
|
||||
}
|
||||
}
|
||||
// Place sell order if RSI crosses above overbought level (overbought crossover)
|
||||
else if(data.rsiCrossedOverbought)
|
||||
{
|
||||
double sl = data.UseStopLoss ? currentAsk + data.StopLossPips * data.point : 0;
|
||||
double tp = data.UseTakeProfit ? currentAsk - data.TakeProfitPips * data.point : 0;
|
||||
|
||||
if(data.UseStopLoss && sl <= currentAsk)
|
||||
return;
|
||||
if(data.UseTakeProfit && tp >= currentAsk)
|
||||
return;
|
||||
|
||||
// Set trade parameters
|
||||
data.trade.SetDeviationInPoints(data.Slippage);
|
||||
data.trade.SetTypeFilling(ORDER_FILLING_IOC);
|
||||
data.trade.SetExpertMagicNumber(data.MagicNumber);
|
||||
|
||||
// Use dynamic lot size
|
||||
double tradeLotSize = lotSize > 0 ? lotSize : data.MaxLotSize;
|
||||
|
||||
// Place sell order using CTrade
|
||||
if(data.trade.Sell(tradeLotSize, data.symbol, currentBid, sl, tp, "RSI Overbought Crossover Sell"))
|
||||
{
|
||||
data.isPositionOpen = true;
|
||||
data.positionOpenPrice = currentBid;
|
||||
data.positionOpenTime = TimeCurrent();
|
||||
data.lastPositionType = POSITION_TYPE_SELL;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,451 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| RSIScalpingStrategy.mqh |
|
||||
//+------------------------------------------------------------------+
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| RSI Scalping Strategy Data Structure |
|
||||
//+------------------------------------------------------------------+
|
||||
struct RSIScalpingData {
|
||||
string symbol;
|
||||
bool isInitialized;
|
||||
CTrade trade;
|
||||
int rsi_handle;
|
||||
double rsi_buffer[];
|
||||
double rsi_prev;
|
||||
double rsi_current;
|
||||
double rsi_two_bars_ago;
|
||||
bool position_open;
|
||||
ulong position_ticket;
|
||||
ENUM_POSITION_TYPE current_position_type;
|
||||
datetime last_bar_time;
|
||||
bool rsi_against_position;
|
||||
int bars_against_count;
|
||||
};
|
||||
|
||||
string ErrorDescription(int errorCode)
|
||||
{
|
||||
switch(errorCode)
|
||||
{
|
||||
case 4801: return "Symbol not found";
|
||||
case 4802: return "Symbol not selected";
|
||||
case 4803: return "Symbol not visible";
|
||||
case 4804: return "Symbol not available";
|
||||
case 4805: return "Cannot load indicator - insufficient history data";
|
||||
default: return "Unknown error " + IntegerToString(errorCode);
|
||||
}
|
||||
}
|
||||
|
||||
bool InitRSIScalping(RSIScalpingData& data, string symbol, ENUM_TIMEFRAMES TimeFrame, int RSI_Period,
|
||||
ENUM_APPLIED_PRICE RSI_Applied_Price, int MagicNumber, int Slippage)
|
||||
{
|
||||
data.symbol = symbol;
|
||||
data.isInitialized = false;
|
||||
|
||||
// Check if symbol exists
|
||||
if(!SymbolSelect(symbol, true))
|
||||
{
|
||||
Print("RSIScalping: Symbol '", symbol, "' not available in Market Watch. Please add it to Market Watch or check symbol name.");
|
||||
return false; // Return false but don't fail entire EA
|
||||
}
|
||||
|
||||
// Wait a bit for symbol to be ready
|
||||
Sleep(100);
|
||||
|
||||
// Try to create RSI indicator with retry logic (for insufficient history in backtesting)
|
||||
data.rsi_handle = INVALID_HANDLE;
|
||||
int retryCount = 0;
|
||||
int maxRetries = 5;
|
||||
|
||||
while(retryCount < maxRetries && data.rsi_handle == INVALID_HANDLE)
|
||||
{
|
||||
data.rsi_handle = iRSI(symbol, TimeFrame, RSI_Period, RSI_Applied_Price);
|
||||
|
||||
if(data.rsi_handle == INVALID_HANDLE)
|
||||
{
|
||||
int error = GetLastError();
|
||||
|
||||
// Error 4805 = insufficient history - wait longer and retry
|
||||
if(error == 4805 && retryCount < maxRetries - 1)
|
||||
{
|
||||
Sleep(1000); // Wait 1 second for history to load
|
||||
retryCount++;
|
||||
continue;
|
||||
}
|
||||
|
||||
Print("RSIScalping: Error creating RSI indicator for '", symbol, "' - Error: ", error, " (", ErrorDescription(error), ")");
|
||||
return false; // Return false but don't fail entire EA
|
||||
}
|
||||
}
|
||||
|
||||
if(data.rsi_handle == INVALID_HANDLE)
|
||||
{
|
||||
Print("RSIScalping: Failed to create RSI indicator for '", symbol, "' after ", maxRetries, " retries");
|
||||
return false;
|
||||
}
|
||||
|
||||
data.trade.SetExpertMagicNumber(MagicNumber);
|
||||
data.trade.SetDeviationInPoints(Slippage);
|
||||
data.trade.SetTypeFilling(ORDER_FILLING_FOK);
|
||||
|
||||
ArraySetAsSeries(data.rsi_buffer, true);
|
||||
data.position_open = false;
|
||||
data.position_ticket = 0;
|
||||
data.rsi_against_position = false;
|
||||
data.bars_against_count = 0;
|
||||
data.isInitialized = true;
|
||||
|
||||
Print("RSIScalping: Successfully initialized for symbol '", symbol, "'");
|
||||
return true;
|
||||
}
|
||||
|
||||
void DeinitRSIScalping(RSIScalpingData& data)
|
||||
{
|
||||
if(data.rsi_handle != INVALID_HANDLE)
|
||||
IndicatorRelease(data.rsi_handle);
|
||||
}
|
||||
|
||||
bool UpdateRSI(RSIScalpingData& data)
|
||||
{
|
||||
if(CopyBuffer(data.rsi_handle, 0, 0, 3, data.rsi_buffer) < 3)
|
||||
return false;
|
||||
|
||||
data.rsi_current = data.rsi_buffer[0];
|
||||
data.rsi_prev = data.rsi_buffer[1];
|
||||
data.rsi_two_bars_ago = data.rsi_buffer[2];
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void CheckExistingPosition(RSIScalpingData& data, ENUM_TIMEFRAMES TimeFrame, int MagicNumber,
|
||||
double RSI_Oversold, double RSI_Overbought, double RSI_Target_Buy,
|
||||
double RSI_Target_Sell, int BarsToWait)
|
||||
{
|
||||
// Always check if position exists, even if tracking says it doesn't
|
||||
bool positionExists = PositionExistsByMagic(data.symbol, MagicNumber);
|
||||
|
||||
if(!positionExists && data.position_open)
|
||||
{
|
||||
// Position was closed externally, reset tracking
|
||||
data.position_open = false;
|
||||
data.position_ticket = 0;
|
||||
data.rsi_against_position = false;
|
||||
data.bars_against_count = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
if(!positionExists)
|
||||
return;
|
||||
|
||||
// Update tracking if we have a position but tracking was lost
|
||||
if(!data.position_open && positionExists)
|
||||
{
|
||||
ulong ticket = GetPositionTicketByMagic(data.symbol, MagicNumber);
|
||||
if(ticket > 0 && PositionSelectByTicketSymbolAndMagic(ticket, data.symbol, MagicNumber))
|
||||
{
|
||||
data.position_ticket = ticket;
|
||||
data.position_open = true;
|
||||
data.current_position_type = (ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);
|
||||
}
|
||||
}
|
||||
|
||||
// Verify our tracked position still exists
|
||||
if(data.position_open && data.position_ticket > 0)
|
||||
{
|
||||
if(!PositionSelectByTicketSymbolAndMagic(data.position_ticket, data.symbol, MagicNumber))
|
||||
{
|
||||
// Try to find the position again
|
||||
ulong ticket = GetPositionTicketByMagic(data.symbol, MagicNumber);
|
||||
if(ticket > 0 && PositionSelectByTicketSymbolAndMagic(ticket, data.symbol, MagicNumber))
|
||||
{
|
||||
data.position_ticket = ticket;
|
||||
data.current_position_type = (ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Position doesn't exist, reset tracking
|
||||
data.position_open = false;
|
||||
data.position_ticket = 0;
|
||||
data.rsi_against_position = false;
|
||||
data.bars_against_count = 0;
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Update position type in case it changed (shouldn't happen, but be safe)
|
||||
data.current_position_type = (ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);
|
||||
}
|
||||
}
|
||||
|
||||
if(data.current_position_type == POSITION_TYPE_BUY)
|
||||
{
|
||||
if(data.rsi_current < RSI_Oversold)
|
||||
{
|
||||
if(!data.rsi_against_position)
|
||||
{
|
||||
data.rsi_against_position = true;
|
||||
data.bars_against_count = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
data.bars_against_count++;
|
||||
}
|
||||
|
||||
if(data.bars_against_count >= BarsToWait)
|
||||
{
|
||||
ClosePosition(data, MagicNumber);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(data.rsi_against_position)
|
||||
{
|
||||
data.rsi_against_position = false;
|
||||
data.bars_against_count = 0;
|
||||
}
|
||||
|
||||
if(data.rsi_current >= RSI_Target_Buy)
|
||||
{
|
||||
ClosePosition(data, MagicNumber);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(data.current_position_type == POSITION_TYPE_SELL)
|
||||
{
|
||||
if(data.rsi_current > RSI_Overbought)
|
||||
{
|
||||
if(!data.rsi_against_position)
|
||||
{
|
||||
data.rsi_against_position = true;
|
||||
data.bars_against_count = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
data.bars_against_count++;
|
||||
}
|
||||
|
||||
if(data.bars_against_count >= BarsToWait)
|
||||
{
|
||||
ClosePosition(data, MagicNumber);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(data.rsi_against_position)
|
||||
{
|
||||
data.rsi_against_position = false;
|
||||
data.bars_against_count = 0;
|
||||
}
|
||||
|
||||
if(data.rsi_current <= RSI_Target_Sell)
|
||||
{
|
||||
ClosePosition(data, MagicNumber);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CheckEntrySignals(RSIScalpingData& data, ENUM_TIMEFRAMES TimeFrame, int MagicNumber,
|
||||
double RSI_Oversold, double RSI_Overbought, double LotSize)
|
||||
{
|
||||
if(data.rsi_two_bars_ago <= RSI_Oversold && data.rsi_prev > RSI_Oversold)
|
||||
{
|
||||
OpenBuyPosition(data, MagicNumber, LotSize);
|
||||
}
|
||||
|
||||
if(data.rsi_two_bars_ago >= RSI_Overbought && data.rsi_prev < RSI_Overbought)
|
||||
{
|
||||
OpenSellPosition(data, MagicNumber, LotSize);
|
||||
}
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Normalize Lot Size According to Symbol Properties |
|
||||
//+------------------------------------------------------------------+
|
||||
double NormalizeLotSize(string symbol, double lotSize)
|
||||
{
|
||||
double minLot = SymbolInfoDouble(symbol, SYMBOL_VOLUME_MIN);
|
||||
double maxLot = SymbolInfoDouble(symbol, SYMBOL_VOLUME_MAX);
|
||||
double lotStep = SymbolInfoDouble(symbol, SYMBOL_VOLUME_STEP);
|
||||
|
||||
// Round to lot step
|
||||
if(lotStep > 0)
|
||||
lotSize = MathFloor(lotSize / lotStep) * lotStep;
|
||||
|
||||
// Apply min/max constraints
|
||||
if(lotSize < minLot)
|
||||
lotSize = minLot;
|
||||
if(lotSize > maxLot)
|
||||
lotSize = maxLot;
|
||||
|
||||
return lotSize;
|
||||
}
|
||||
|
||||
void OpenBuyPosition(RSIScalpingData& data, int MagicNumber, double LotSize)
|
||||
{
|
||||
if(PositionExistsByMagic(data.symbol, MagicNumber))
|
||||
return;
|
||||
|
||||
// Normalize lot size according to symbol properties
|
||||
double normalizedLot = NormalizeLotSize(data.symbol, LotSize);
|
||||
|
||||
double ask = SymbolInfoDouble(data.symbol, SYMBOL_ASK);
|
||||
|
||||
if(data.trade.Buy(normalizedLot, data.symbol, ask, 0, 0, "RSI Scalping Buy"))
|
||||
{
|
||||
ulong new_ticket = data.trade.ResultOrder();
|
||||
if(new_ticket > 0)
|
||||
{
|
||||
if(PositionSelectByTicketSymbolAndMagic(new_ticket, data.symbol, MagicNumber))
|
||||
{
|
||||
data.position_ticket = new_ticket;
|
||||
data.position_open = true;
|
||||
data.current_position_type = POSITION_TYPE_BUY;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void OpenSellPosition(RSIScalpingData& data, int MagicNumber, double LotSize)
|
||||
{
|
||||
if(PositionExistsByMagic(data.symbol, MagicNumber))
|
||||
return;
|
||||
|
||||
// Normalize lot size according to symbol properties
|
||||
double normalizedLot = NormalizeLotSize(data.symbol, LotSize);
|
||||
|
||||
double bid = SymbolInfoDouble(data.symbol, SYMBOL_BID);
|
||||
|
||||
if(data.trade.Sell(normalizedLot, data.symbol, bid, 0, 0, "RSI Scalping Sell"))
|
||||
{
|
||||
ulong new_ticket = data.trade.ResultOrder();
|
||||
if(new_ticket > 0)
|
||||
{
|
||||
if(PositionSelectByTicketSymbolAndMagic(new_ticket, data.symbol, MagicNumber))
|
||||
{
|
||||
data.position_ticket = new_ticket;
|
||||
data.position_open = true;
|
||||
data.current_position_type = POSITION_TYPE_SELL;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ClosePosition(RSIScalpingData& data, int MagicNumber)
|
||||
{
|
||||
// First verify position still exists
|
||||
if(!PositionExistsByMagic(data.symbol, MagicNumber))
|
||||
{
|
||||
// Position doesn't exist, reset tracking
|
||||
data.position_open = false;
|
||||
data.position_ticket = 0;
|
||||
data.rsi_against_position = false;
|
||||
data.bars_against_count = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
// Try to close by ticket first (more reliable)
|
||||
bool closed = false;
|
||||
if(data.position_ticket > 0)
|
||||
{
|
||||
if(PositionSelectByTicket(data.position_ticket))
|
||||
{
|
||||
// Verify it's our position
|
||||
if(PositionGetString(POSITION_SYMBOL) == data.symbol &&
|
||||
PositionGetInteger(POSITION_MAGIC) == MagicNumber)
|
||||
{
|
||||
closed = data.trade.PositionClose(data.position_ticket);
|
||||
if(!closed)
|
||||
{
|
||||
Print("RSIScalping: Failed to close position by ticket ", data.position_ticket,
|
||||
" - Error: ", data.trade.ResultRetcode(), " (", data.trade.ResultRetcodeDescription(), ")");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If ticket method failed, try magic number method
|
||||
if(!closed)
|
||||
{
|
||||
closed = ClosePositionByMagic(data.trade, data.symbol, MagicNumber);
|
||||
if(!closed)
|
||||
{
|
||||
Print("RSIScalping: Failed to close position by magic number for '", data.symbol,
|
||||
"' - Error: ", data.trade.ResultRetcode(), " (", data.trade.ResultRetcodeDescription(), ")");
|
||||
}
|
||||
}
|
||||
|
||||
// Verify position is actually closed
|
||||
if(closed)
|
||||
{
|
||||
// Wait a moment and verify
|
||||
Sleep(50);
|
||||
if(!PositionExistsByMagic(data.symbol, MagicNumber))
|
||||
{
|
||||
data.position_open = false;
|
||||
data.position_ticket = 0;
|
||||
data.rsi_against_position = false;
|
||||
data.bars_against_count = 0;
|
||||
Print("RSIScalping: Position successfully closed for '", data.symbol, "'");
|
||||
}
|
||||
else
|
||||
{
|
||||
Print("RSIScalping: Warning - Close returned success but position still exists for '", data.symbol, "'");
|
||||
// Try one more time
|
||||
Sleep(100);
|
||||
if(PositionExistsByMagic(data.symbol, MagicNumber))
|
||||
{
|
||||
ClosePositionByMagic(data.trade, data.symbol, MagicNumber);
|
||||
}
|
||||
// Reset tracking anyway to prevent getting stuck
|
||||
data.position_open = false;
|
||||
data.position_ticket = 0;
|
||||
data.rsi_against_position = false;
|
||||
data.bars_against_count = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Close failed, but reset tracking to prevent getting stuck
|
||||
// The position might have been closed externally
|
||||
data.position_open = false;
|
||||
data.position_ticket = 0;
|
||||
data.rsi_against_position = false;
|
||||
data.bars_against_count = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void ProcessRSIScalping(RSIScalpingData& data, string symbol, ENUM_TIMEFRAMES TimeFrame, int RSI_Period,
|
||||
ENUM_APPLIED_PRICE RSI_Applied_Price, double RSI_Overbought,
|
||||
double RSI_Oversold, double RSI_Target_Buy, double RSI_Target_Sell,
|
||||
int BarsToWait, double LotSize, int MagicNumber)
|
||||
{
|
||||
// Skip if not initialized (symbol not available)
|
||||
if(!data.isInitialized)
|
||||
return;
|
||||
|
||||
data.symbol = symbol; // Update symbol in case it changed
|
||||
if(Bars(data.symbol, TimeFrame) < RSI_Period + 2)
|
||||
return;
|
||||
|
||||
datetime current_bar_time = iTime(data.symbol, TimeFrame, 0);
|
||||
if(current_bar_time == data.last_bar_time)
|
||||
return;
|
||||
|
||||
data.last_bar_time = current_bar_time;
|
||||
|
||||
if(!UpdateRSI(data))
|
||||
return;
|
||||
|
||||
CheckExistingPosition(data, TimeFrame, MagicNumber, RSI_Oversold, RSI_Overbought,
|
||||
RSI_Target_Buy, RSI_Target_Sell, BarsToWait);
|
||||
|
||||
if(!data.position_open && !PositionExistsByMagic(data.symbol, MagicNumber))
|
||||
{
|
||||
CheckEntrySignals(data, TimeFrame, MagicNumber, RSI_Oversold, RSI_Overbought, LotSize);
|
||||
}
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
+531
-895
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,683 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| UnitedEA.mq5 |
|
||||
//| Copyright 2025, MetaQuotes Ltd. |
|
||||
//| https://www.mql5.com |
|
||||
//+------------------------------------------------------------------+
|
||||
#property copyright "Copyright 2025, MetaQuotes Ltd."
|
||||
#property link "https://www.mql5.com"
|
||||
#property version "1.00"
|
||||
#property strict
|
||||
|
||||
#include <Trade\Trade.mqh>
|
||||
#include <Trade\PositionInfo.mqh>
|
||||
#include <Indicators\Trend.mqh>
|
||||
#include <Indicators\Volumes.mqh>
|
||||
#include "MagicNumberHelpers.mqh"
|
||||
#include "PerformanceEvaluator.mqh"
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Strategy Enable/Disable Switches |
|
||||
//+------------------------------------------------------------------+
|
||||
input group "=== Strategy Enable/Disable ==="
|
||||
input bool EnableDarvasBox = true;
|
||||
input bool EnableEMASlopeDistance = true;
|
||||
input bool EnableRSICrossOverReversal = true;
|
||||
input bool EnableRSIMidPointHijack = true;
|
||||
input bool EnableRSIScalpingAPPL = true;
|
||||
input bool EnableRSIScalpingBTCUSD = true;
|
||||
input bool EnableRSIScalpingMSFT = true;
|
||||
input bool EnableRSIScalpingNVDA = true;
|
||||
input bool EnableRSIScalpingTSLA = true;
|
||||
input bool EnableRSIScalpingXAUUSD = true;
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Strategy 1: DarvasBoxXAUUSD |
|
||||
//+------------------------------------------------------------------+
|
||||
input group "=== DarvasBox Strategy ==="
|
||||
input string DB_Symbol = "XAUUSD";
|
||||
input int DB_BoxPeriod = 165;
|
||||
input double DB_BoxDeviation = 30000; // Increased to allow larger ranges (was 25140)
|
||||
input int DB_VolumeThreshold = 0; // Set to 0 to disable volume threshold check. Volume data from indicator used instead.
|
||||
input double DB_StopLoss = 1665;
|
||||
input double DB_TakeProfit = 3685;
|
||||
input bool DB_EnableLogging = false;
|
||||
input color DB_BoxColor = clrBlue;
|
||||
input int DB_BoxWidth = 1;
|
||||
input ENUM_TIMEFRAMES DB_TrendTimeframe = PERIOD_H2;
|
||||
input int DB_MA_Period = 125;
|
||||
input ENUM_MA_METHOD DB_MA_Method = MODE_EMA;
|
||||
input ENUM_APPLIED_PRICE DB_MA_Price = PRICE_WEIGHTED;
|
||||
input double DB_TrendThreshold = 4.94;
|
||||
input int DB_VolumeMA_Period = 110;
|
||||
input double DB_VolumeThresholdMultiplier = 1.5;
|
||||
input int DB_MagicNumber = 135790;
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Strategy 2: EMASlopeDistanceCocktailXAUUSD |
|
||||
//| PEPPERSTONE US: Gold symbol is typically "XAUUSD" or "GOLD" |
|
||||
//+------------------------------------------------------------------+
|
||||
input group "=== EMA Slope Distance Strategy ==="
|
||||
input string ES_Symbol = "XAUUSD";
|
||||
input int ES_EMA_Periode = 46;
|
||||
input double ES_PreisSchwelle = 600.0;
|
||||
input double ES_SteigungSchwelle = 80.0;
|
||||
input int ES_ÜberwachungTimeout = 800;
|
||||
input double ES_TrailingStop = 250.0;
|
||||
input double ES_LotGröße = 0.03;
|
||||
input int ES_MagicNumber = 12350;
|
||||
input bool ES_UseSpreadAdjustment = true;
|
||||
input ENUM_TIMEFRAMES ES_Timeframe = PERIOD_H1;
|
||||
input bool ES_UseBarData = true;
|
||||
input int ES_MaxTradesPerCrossover = 9;
|
||||
input int ES_ProfitCheckBars = 18;
|
||||
input bool ES_CloseUnprofitableTrades = true;
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Strategy 3: RSICrossOverReversalXAUUSD |
|
||||
//| PEPPERSTONE US: Gold symbol is typically "XAUUSD" or "GOLD" |
|
||||
//+------------------------------------------------------------------+
|
||||
input group "=== RSI CrossOver Reversal Strategy ==="
|
||||
input string RC_Symbol = "XAUUSD";
|
||||
input int RC_MagicNumber = 7;
|
||||
input int RC_rsiPeriod = 19;
|
||||
input int RC_overboughtLevel = 93;
|
||||
input int RC_oversoldLevel = 22;
|
||||
input double RC_entryRSIBuySpread = 0;
|
||||
input double RC_entryRSISellSpread = 0;
|
||||
input double RC_lotSize = 0.01;
|
||||
input int RC_slippage = 3;
|
||||
input int RC_cooldownSeconds = 209;
|
||||
input ENUM_TIMEFRAMES RC_TimeFrame1 = PERIOD_M1;
|
||||
input ENUM_TIMEFRAMES RC_TimeFrame2 = PERIOD_M1;
|
||||
input ENUM_TIMEFRAMES RC_BarTimeFrame = PERIOD_M12;
|
||||
input int RC_emaPeriod = 140;
|
||||
input double RC_emaSlopeThreshold = 105;
|
||||
input double RC_exitBuyRSI = 86;
|
||||
input double RC_exitSellRSI = 10;
|
||||
input double RC_TrailingStop = 295;
|
||||
input double RC_emaDistanceThreshold = 165;
|
||||
input int RC_tradingHourOneBegin = 24;
|
||||
input int RC_tradingHourOneEnd = 22;
|
||||
input int RC_tradingHourTwoBegin = 6;
|
||||
input int RC_tradingHourTwoEnd = 19;
|
||||
input bool RC_Sunday = false;
|
||||
input bool RC_Monday = false;
|
||||
input bool RC_Tuesday = true;
|
||||
input bool RC_Wednesday = true;
|
||||
input bool RC_Thursday = true;
|
||||
input bool RC_Friday = false;
|
||||
input bool RC_Saturday = false;
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Strategy 4: RSIMidPointHijackXAUUSD |
|
||||
//| PEPPERSTONE US: Gold symbol is typically "XAUUSD" or "GOLD" |
|
||||
//+------------------------------------------------------------------+
|
||||
input group "=== RSI MidPoint Hijack Strategy ==="
|
||||
input string RM_Symbol = "XAUUSD";
|
||||
input ENUM_TIMEFRAMES RM_InpTimeframe = PERIOD_H1;
|
||||
input double RM_InpLotSize = 0.02;
|
||||
input int RM_InpMagicNumberRSIFollow = 1001;
|
||||
input int RM_InpMagicNumberRSIReverse = 1002;
|
||||
input int RM_InpMagicNumberEMACross = 1003;
|
||||
input bool RM_InpEnableRSIFollow = true;
|
||||
input bool RM_InpEnableRSIReverse = true;
|
||||
input bool RM_InpEnableEMACross = true;
|
||||
input bool RM_InpEnableStrategyLock = false;
|
||||
input double RM_InpLockProfitThreshold = 0.0;
|
||||
input bool RM_InpCloseOppositeTrades = false;
|
||||
input int RM_InpRSIPeriod = 32;
|
||||
input int RM_InpRSIOverbought = 78;
|
||||
input int RM_InpRSIOversold = 46;
|
||||
input int RM_InpRSIExitLevel = 44;
|
||||
input int RM_InpRSIFollowStartHour = 23;
|
||||
input int RM_InpRSIFollowEndHour = 8;
|
||||
input bool RM_InpRSIFollowCloseOutsideHours = false;
|
||||
input int RM_InpRSIReversePeriod = 59;
|
||||
input int RM_InpRSIReverseOverbought = 51;
|
||||
input int RM_InpRSIReverseOversold = 49;
|
||||
input int RM_InpRSIReverseCrossLevel = 53;
|
||||
input int RM_InpRSIReverseExitLevel = 48;
|
||||
input int RM_InpRSIReverseStartHour = 7;
|
||||
input int RM_InpRSIReverseEndHour = 13;
|
||||
input bool RM_InpRSIReverseCloseOutsideHours = false;
|
||||
input int RM_InpRSIReverseCooldownBars = 15;
|
||||
input bool RM_InpRSIReverseCooldownOnLoss = true;
|
||||
input int RM_InpEMAPeriod = 120;
|
||||
input int RM_InpEMACrossStartHour = 8;
|
||||
input int RM_InpEMACrossEndHour = 14;
|
||||
input bool RM_InpEMACrossCloseOutsideHours = true;
|
||||
input bool RM_InpUseEMADistanceEntry = true;
|
||||
input double RM_InpEMADistancePips = 160.0;
|
||||
input int RM_InpEMADistancePeriod = 26;
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Strategy 5-10: RSI Scalping Strategies |
|
||||
//| Each RSI Scalping strategy trades on its own symbol: |
|
||||
//| - APPL: Apple stock (AAPL) |
|
||||
//| - BTCUSD: Bitcoin/USD |
|
||||
//| - MSFT: Microsoft stock |
|
||||
//| - NVDA: NVIDIA stock |
|
||||
//| - TSLA: Tesla stock |
|
||||
//| - XAUUSD: Gold/USD |
|
||||
//| |
|
||||
//| PEPPERSTONE US SYMBOL FORMATS: |
|
||||
//| - Stocks may use: "AAPL.US", "NASDAQ:AAPL", or just "AAPL" |
|
||||
//| - To find correct symbols: |
|
||||
//| 1. Open Market Watch (Ctrl+M) |
|
||||
//| 2. Right-click > Show All |
|
||||
//| 3. Search for the stock name |
|
||||
//| 4. Use the exact symbol name shown |
|
||||
//+------------------------------------------------------------------+
|
||||
input group "=== RSI Scalping APPL (AAPL) - Pepperstone US ==="
|
||||
input string RS_APPL_Symbol = "AAPL.US"; // Try: "AAPL.US", "NASDAQ:AAPL", or "AAPL"
|
||||
input ENUM_TIMEFRAMES RS_APPL_TimeFrame = PERIOD_M10;
|
||||
input int RS_APPL_RSI_Period = 14;
|
||||
input ENUM_APPLIED_PRICE RS_APPL_RSI_Applied_Price = PRICE_CLOSE;
|
||||
input double RS_APPL_RSI_Overbought = 80;
|
||||
input double RS_APPL_RSI_Oversold = 78;
|
||||
input double RS_APPL_RSI_Target_Buy = 94;
|
||||
input double RS_APPL_RSI_Target_Sell = 44;
|
||||
input int RS_APPL_BarsToWait = 7;
|
||||
input double RS_APPL_LotSize = 25;
|
||||
input int RS_APPL_MagicNumber = 20001;
|
||||
input int RS_APPL_Slippage = 3;
|
||||
|
||||
input group "=== RSI Scalping BTCUSD ==="
|
||||
input string RS_BTCUSD_Symbol = "BTCUSD"; // Pepperstone may use: "BTCUSD", "BTC/USD", or "BTCUSD.c"
|
||||
input ENUM_TIMEFRAMES RS_BTCUSD_TimeFrame = PERIOD_H1;
|
||||
input int RS_BTCUSD_RSI_Period = 14;
|
||||
input ENUM_APPLIED_PRICE RS_BTCUSD_RSI_Applied_Price = PRICE_CLOSE;
|
||||
input double RS_BTCUSD_RSI_Overbought = 90;
|
||||
input double RS_BTCUSD_RSI_Oversold = 73;
|
||||
input double RS_BTCUSD_RSI_Target_Buy = 88;
|
||||
input double RS_BTCUSD_RSI_Target_Sell = 48;
|
||||
input int RS_BTCUSD_BarsToWait = 6;
|
||||
input double RS_BTCUSD_LotSize = 0.1;
|
||||
input int RS_BTCUSD_MagicNumber = 123459123;
|
||||
input int RS_BTCUSD_Slippage = 3;
|
||||
|
||||
input group "=== RSI Scalping MSFT - Pepperstone US ==="
|
||||
input string RS_MSFT_Symbol = "MSFT.US"; // Try: "MSFT.US", "NASDAQ:MSFT", or "MSFT"
|
||||
input ENUM_TIMEFRAMES RS_MSFT_TimeFrame = PERIOD_H3;
|
||||
input int RS_MSFT_RSI_Period = 14;
|
||||
input ENUM_APPLIED_PRICE RS_MSFT_RSI_Applied_Price = PRICE_CLOSE;
|
||||
input double RS_MSFT_RSI_Overbought = 19;
|
||||
input double RS_MSFT_RSI_Oversold = 50;
|
||||
input double RS_MSFT_RSI_Target_Buy = 71;
|
||||
input double RS_MSFT_RSI_Target_Sell = 70;
|
||||
input int RS_MSFT_BarsToWait = 1;
|
||||
input double RS_MSFT_LotSize = 50;
|
||||
input int RS_MSFT_MagicNumber = 20002;
|
||||
input int RS_MSFT_Slippage = 3;
|
||||
|
||||
input group "=== RSI Scalping NVDA - Pepperstone US ==="
|
||||
input string RS_NVDA_Symbol = "NVDA.US"; // Try: "NVDA.US", "NASDAQ:NVDA", or "NVDA"
|
||||
input ENUM_TIMEFRAMES RS_NVDA_TimeFrame = PERIOD_M15;
|
||||
input int RS_NVDA_RSI_Period = 8;
|
||||
input ENUM_APPLIED_PRICE RS_NVDA_RSI_Applied_Price = PRICE_CLOSE;
|
||||
input double RS_NVDA_RSI_Overbought = 36;
|
||||
input double RS_NVDA_RSI_Oversold = 38;
|
||||
input double RS_NVDA_RSI_Target_Buy = 90;
|
||||
input double RS_NVDA_RSI_Target_Sell = 70;
|
||||
input int RS_NVDA_BarsToWait = 5;
|
||||
input double RS_NVDA_LotSize = 50;
|
||||
input int RS_NVDA_MagicNumber = 20003;
|
||||
input int RS_NVDA_Slippage = 3;
|
||||
|
||||
input group "=== RSI Scalping TSLA - Pepperstone US ==="
|
||||
input string RS_TSLA_Symbol = "TSLA.US"; // Try: "TSLA.US", "NASDAQ:TSLA", or "TSLA"
|
||||
input ENUM_TIMEFRAMES RS_TSLA_TimeFrame = PERIOD_H1;
|
||||
input int RS_TSLA_RSI_Period = 14;
|
||||
input ENUM_APPLIED_PRICE RS_TSLA_RSI_Applied_Price = PRICE_CLOSE;
|
||||
input double RS_TSLA_RSI_Overbought = 54;
|
||||
input double RS_TSLA_RSI_Oversold = 73;
|
||||
input double RS_TSLA_RSI_Target_Buy = 87;
|
||||
input double RS_TSLA_RSI_Target_Sell = 33;
|
||||
input int RS_TSLA_BarsToWait = 1;
|
||||
input double RS_TSLA_LotSize = 50;
|
||||
input int RS_TSLA_MagicNumber = 125421321;
|
||||
input int RS_TSLA_Slippage = 3;
|
||||
|
||||
input group "=== RSI Scalping XAUUSD ==="
|
||||
input string RS_XAUUSD_Symbol = "XAUUSD";
|
||||
input ENUM_TIMEFRAMES RS_XAUUSD_TimeFrame = PERIOD_H1;
|
||||
input int RS_XAUUSD_RSI_Period = 14;
|
||||
input ENUM_APPLIED_PRICE RS_XAUUSD_RSI_Applied_Price = PRICE_CLOSE;
|
||||
input double RS_XAUUSD_RSI_Overbought = 71;
|
||||
input double RS_XAUUSD_RSI_Oversold = 57;
|
||||
input double RS_XAUUSD_RSI_Target_Buy = 80;
|
||||
input double RS_XAUUSD_RSI_Target_Sell = 57;
|
||||
input int RS_XAUUSD_BarsToWait = 4;
|
||||
input double RS_XAUUSD_LotSize = 0.1;
|
||||
input int RS_XAUUSD_MagicNumber = 129102315;
|
||||
input int RS_XAUUSD_Slippage = 3;
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Global Variables - DarvasBox |
|
||||
//+------------------------------------------------------------------+
|
||||
struct DarvasBoxData {
|
||||
string symbol;
|
||||
bool isInitialized;
|
||||
double boxHigh;
|
||||
double boxLow;
|
||||
bool boxFormed;
|
||||
datetime lastBoxTime;
|
||||
string boxName;
|
||||
double minStopLevel;
|
||||
double point;
|
||||
CTrade trade;
|
||||
int maHandle;
|
||||
int volumeHandle;
|
||||
datetime lastBarTime;
|
||||
};
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Global Variables - EMA Slope Distance |
|
||||
//+------------------------------------------------------------------+
|
||||
struct EMASlopeData {
|
||||
string symbol;
|
||||
bool isInitialized;
|
||||
int ema_handle;
|
||||
double ema_array[];
|
||||
datetime letzte_überwachung_zeit;
|
||||
bool überwachung_aktiv;
|
||||
bool preis_trigger_aktiv;
|
||||
bool steigung_trigger_aktiv;
|
||||
int ticket;
|
||||
CTrade trade;
|
||||
int trades_in_current_crossover;
|
||||
bool crossover_detected;
|
||||
datetime trade_open_time;
|
||||
datetime last_bar_time;
|
||||
};
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Global Variables - RSI CrossOver Reversal |
|
||||
//+------------------------------------------------------------------+
|
||||
struct RSICrossOverData {
|
||||
string symbol;
|
||||
bool isInitialized;
|
||||
int rsiHandle;
|
||||
int emaHandle;
|
||||
double previousRSIDef;
|
||||
CTrade trade;
|
||||
datetime lastTradeTime;
|
||||
datetime bartime;
|
||||
bool WeekDays[7];
|
||||
datetime lastBarTime;
|
||||
};
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Global Variables - RSI MidPoint Hijack |
|
||||
//+------------------------------------------------------------------+
|
||||
struct RSIMidPointData {
|
||||
string symbol;
|
||||
bool isInitialized;
|
||||
int rsiHandle;
|
||||
int rsiReverseHandle;
|
||||
int emaHandle;
|
||||
bool rsiOverbought;
|
||||
bool rsiOversold;
|
||||
bool rsiReverseOverbought;
|
||||
bool rsiReverseOversold;
|
||||
CTrade trade;
|
||||
CPositionInfo positionInfo;
|
||||
bool emaCrossBuySignal;
|
||||
bool emaCrossSellSignal;
|
||||
int emaCrossSignalBar;
|
||||
datetime lastBarTime;
|
||||
datetime rsiReverseLastCloseTime;
|
||||
bool rsiReverseInCooldown;
|
||||
double lastBarRSI;
|
||||
double lastBarRSIReverse;
|
||||
double lastBarEMA;
|
||||
double lastBarClose;
|
||||
double lastBarEMAPrev;
|
||||
double lastBarClosePrev;
|
||||
};
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Global Variables - RSI Scalping |
|
||||
//+------------------------------------------------------------------+
|
||||
struct RSIScalpingData {
|
||||
string symbol;
|
||||
bool isInitialized;
|
||||
CTrade trade;
|
||||
int rsi_handle;
|
||||
double rsi_buffer[];
|
||||
double rsi_prev;
|
||||
double rsi_current;
|
||||
double rsi_two_bars_ago;
|
||||
bool position_open;
|
||||
ulong position_ticket;
|
||||
ENUM_POSITION_TYPE current_position_type;
|
||||
datetime last_bar_time;
|
||||
bool rsi_against_position;
|
||||
int bars_against_count;
|
||||
};
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Global Strategy Instances |
|
||||
//+------------------------------------------------------------------+
|
||||
DarvasBoxData dbData;
|
||||
EMASlopeData esData;
|
||||
RSICrossOverData rcData;
|
||||
RSIMidPointData rmData;
|
||||
RSIScalpingData rsAPPLData;
|
||||
RSIScalpingData rsBTCUSDData;
|
||||
RSIScalpingData rsMSFTData;
|
||||
RSIScalpingData rsNVDAData;
|
||||
RSIScalpingData rsTSLAData;
|
||||
RSIScalpingData rsXAUUSDData;
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Global Variables for Dynamic Lot Sizes |
|
||||
//+------------------------------------------------------------------+
|
||||
// All strategies start with minimum lot size for safety (will be adjusted by performance evaluator)
|
||||
double g_DB_LotSize = 0.01; // DarvasBox uses fixed lot size
|
||||
double g_ES_LotSize = 0.01; // EMA Slope Distance - start with minimum
|
||||
double g_RC_LotSize = 0.01; // RSI CrossOver Reversal - start with minimum
|
||||
double g_RM_LotSize = 0.01; // RSI MidPoint Hijack - start with minimum
|
||||
double g_RS_APPL_LotSize = 5.0; // Stock - start with stock minimum (5.0)
|
||||
double g_RS_BTCUSD_LotSize = 0.01; // Crypto - start with forex minimum (0.01)
|
||||
double g_RS_MSFT_LotSize = 5.0; // Stock - start with stock minimum (5.0)
|
||||
double g_RS_NVDA_LotSize = 5.0; // Stock - start with stock minimum (5.0)
|
||||
double g_RS_TSLA_LotSize = 5.0; // Stock - start with stock minimum (5.0)
|
||||
double g_RS_XAUUSD_LotSize = 0.01; // Forex - start with forex minimum (0.01)
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Expert initialization function |
|
||||
//+------------------------------------------------------------------+
|
||||
int OnInit()
|
||||
{
|
||||
int initResult = INIT_SUCCEEDED;
|
||||
|
||||
// Initialize Performance Evaluator
|
||||
InitPerformanceTracking();
|
||||
|
||||
// Initialize strategies - log warnings but don't fail entire EA if symbol unavailable
|
||||
if(EnableDarvasBox)
|
||||
{
|
||||
if(!InitDarvasBox(DB_Symbol))
|
||||
Print("Warning: DarvasBox strategy failed to initialize for symbol '", DB_Symbol, "'");
|
||||
else
|
||||
RegisterStrategy("DarvasBox", DB_MagicNumber, 0.01, DB_Symbol); // Fixed lot size
|
||||
}
|
||||
|
||||
if(EnableEMASlopeDistance)
|
||||
{
|
||||
if(!InitEMASlopeDistance(ES_Symbol))
|
||||
Print("Warning: EMASlopeDistance strategy failed to initialize for symbol '", ES_Symbol, "'");
|
||||
else
|
||||
{
|
||||
RegisterStrategy("EMASlopeDistance", ES_MagicNumber, ES_LotGröße, ES_Symbol);
|
||||
// Start with minimum lot size (will be adjusted by performance evaluator)
|
||||
double minLot = GetMinLotSizeForSymbol(ES_Symbol);
|
||||
g_ES_LotSize = minLot;
|
||||
}
|
||||
}
|
||||
|
||||
if(EnableRSICrossOverReversal)
|
||||
{
|
||||
if(!InitRSICrossOverReversal(RC_Symbol))
|
||||
Print("Warning: RSICrossOverReversal strategy failed to initialize for symbol '", RC_Symbol, "'");
|
||||
else
|
||||
{
|
||||
RegisterStrategy("RSICrossOverReversal", RC_MagicNumber, RC_lotSize, RC_Symbol);
|
||||
// Start with minimum lot size (will be adjusted by performance evaluator)
|
||||
double minLot = GetMinLotSizeForSymbol(RC_Symbol);
|
||||
g_RC_LotSize = minLot;
|
||||
}
|
||||
}
|
||||
|
||||
if(EnableRSIMidPointHijack)
|
||||
{
|
||||
if(!InitRSIMidPointHijack(RM_Symbol))
|
||||
Print("Warning: RSIMidPointHijack strategy failed to initialize for symbol '", RM_Symbol, "'");
|
||||
else
|
||||
{
|
||||
RegisterStrategy("RSIMidPointHijack", RM_InpMagicNumberRSIFollow, RM_InpLotSize, RM_Symbol);
|
||||
RegisterStrategy("RSIMidPointHijack_Reverse", RM_InpMagicNumberRSIReverse, RM_InpLotSize, RM_Symbol);
|
||||
RegisterStrategy("RSIMidPointHijack_EMACross", RM_InpMagicNumberEMACross, RM_InpLotSize, RM_Symbol);
|
||||
// Start with minimum lot size (will be adjusted by performance evaluator)
|
||||
double minLot = GetMinLotSizeForSymbol(RM_Symbol);
|
||||
g_RM_LotSize = minLot;
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize RSI Scalping strategies - don't fail entire EA if symbol unavailable
|
||||
if(EnableRSIScalpingAPPL)
|
||||
{
|
||||
InitRSIScalping(rsAPPLData, RS_APPL_Symbol, RS_APPL_TimeFrame, RS_APPL_RSI_Period, RS_APPL_RSI_Applied_Price, RS_APPL_MagicNumber, RS_APPL_Slippage);
|
||||
RegisterStrategy("RSIScalpingAPPL", RS_APPL_MagicNumber, RS_APPL_LotSize, RS_APPL_Symbol);
|
||||
// Start with minimum lot size (will be adjusted by performance evaluator)
|
||||
double minLot = GetMinLotSizeForSymbol(RS_APPL_Symbol);
|
||||
g_RS_APPL_LotSize = minLot;
|
||||
}
|
||||
|
||||
if(EnableRSIScalpingBTCUSD)
|
||||
{
|
||||
InitRSIScalping(rsBTCUSDData, RS_BTCUSD_Symbol, RS_BTCUSD_TimeFrame, RS_BTCUSD_RSI_Period, RS_BTCUSD_RSI_Applied_Price, RS_BTCUSD_MagicNumber, RS_BTCUSD_Slippage);
|
||||
RegisterStrategy("RSIScalpingBTCUSD", RS_BTCUSD_MagicNumber, RS_BTCUSD_LotSize, RS_BTCUSD_Symbol);
|
||||
// Start with minimum lot size (will be adjusted by performance evaluator)
|
||||
double minLot = GetMinLotSizeForSymbol(RS_BTCUSD_Symbol);
|
||||
g_RS_BTCUSD_LotSize = minLot;
|
||||
}
|
||||
|
||||
if(EnableRSIScalpingMSFT)
|
||||
{
|
||||
InitRSIScalping(rsMSFTData, RS_MSFT_Symbol, RS_MSFT_TimeFrame, RS_MSFT_RSI_Period, RS_MSFT_RSI_Applied_Price, RS_MSFT_MagicNumber, RS_MSFT_Slippage);
|
||||
RegisterStrategy("RSIScalpingMSFT", RS_MSFT_MagicNumber, RS_MSFT_LotSize, RS_MSFT_Symbol);
|
||||
// Start with minimum lot size (will be adjusted by performance evaluator)
|
||||
double minLot = GetMinLotSizeForSymbol(RS_MSFT_Symbol);
|
||||
g_RS_MSFT_LotSize = minLot;
|
||||
}
|
||||
|
||||
if(EnableRSIScalpingNVDA)
|
||||
{
|
||||
InitRSIScalping(rsNVDAData, RS_NVDA_Symbol, RS_NVDA_TimeFrame, RS_NVDA_RSI_Period, RS_NVDA_RSI_Applied_Price, RS_NVDA_MagicNumber, RS_NVDA_Slippage);
|
||||
RegisterStrategy("RSIScalpingNVDA", RS_NVDA_MagicNumber, RS_NVDA_LotSize, RS_NVDA_Symbol);
|
||||
// Start with minimum lot size (will be adjusted by performance evaluator)
|
||||
double minLot = GetMinLotSizeForSymbol(RS_NVDA_Symbol);
|
||||
g_RS_NVDA_LotSize = minLot;
|
||||
}
|
||||
|
||||
if(EnableRSIScalpingTSLA)
|
||||
{
|
||||
InitRSIScalping(rsTSLAData, RS_TSLA_Symbol, RS_TSLA_TimeFrame, RS_TSLA_RSI_Period, RS_TSLA_RSI_Applied_Price, RS_TSLA_MagicNumber, RS_TSLA_Slippage);
|
||||
RegisterStrategy("RSIScalpingTSLA", RS_TSLA_MagicNumber, RS_TSLA_LotSize, RS_TSLA_Symbol);
|
||||
// Start with minimum lot size (will be adjusted by performance evaluator)
|
||||
double minLot = GetMinLotSizeForSymbol(RS_TSLA_Symbol);
|
||||
g_RS_TSLA_LotSize = minLot;
|
||||
}
|
||||
|
||||
if(EnableRSIScalpingXAUUSD)
|
||||
{
|
||||
InitRSIScalping(rsXAUUSDData, RS_XAUUSD_Symbol, RS_XAUUSD_TimeFrame, RS_XAUUSD_RSI_Period, RS_XAUUSD_RSI_Applied_Price, RS_XAUUSD_MagicNumber, RS_XAUUSD_Slippage);
|
||||
RegisterStrategy("RSIScalpingXAUUSD", RS_XAUUSD_MagicNumber, RS_XAUUSD_LotSize, RS_XAUUSD_Symbol);
|
||||
// Start with minimum lot size (will be adjusted by performance evaluator)
|
||||
double minLot = GetMinLotSizeForSymbol(RS_XAUUSD_Symbol);
|
||||
g_RS_XAUUSD_LotSize = minLot;
|
||||
}
|
||||
|
||||
// Load adjusted lot sizes from performance evaluator
|
||||
if(PE_EnableAutoAdjustment)
|
||||
{
|
||||
double adjustedLot;
|
||||
adjustedLot = GetStrategyLotSize("EMASlopeDistance", ES_MagicNumber);
|
||||
if(adjustedLot > 0) g_ES_LotSize = adjustedLot;
|
||||
|
||||
adjustedLot = GetStrategyLotSize("RSICrossOverReversal", RC_MagicNumber);
|
||||
if(adjustedLot > 0) g_RC_LotSize = adjustedLot;
|
||||
|
||||
adjustedLot = GetStrategyLotSize("RSIMidPointHijack", RM_InpMagicNumberRSIFollow);
|
||||
if(adjustedLot > 0) g_RM_LotSize = adjustedLot;
|
||||
|
||||
adjustedLot = GetStrategyLotSize("RSIScalpingAPPL", RS_APPL_MagicNumber);
|
||||
if(adjustedLot > 0) g_RS_APPL_LotSize = adjustedLot;
|
||||
|
||||
adjustedLot = GetStrategyLotSize("RSIScalpingBTCUSD", RS_BTCUSD_MagicNumber);
|
||||
if(adjustedLot > 0) g_RS_BTCUSD_LotSize = adjustedLot;
|
||||
|
||||
adjustedLot = GetStrategyLotSize("RSIScalpingMSFT", RS_MSFT_MagicNumber);
|
||||
if(adjustedLot > 0) g_RS_MSFT_LotSize = adjustedLot;
|
||||
|
||||
adjustedLot = GetStrategyLotSize("RSIScalpingNVDA", RS_NVDA_MagicNumber);
|
||||
if(adjustedLot > 0) g_RS_NVDA_LotSize = adjustedLot;
|
||||
|
||||
adjustedLot = GetStrategyLotSize("RSIScalpingTSLA", RS_TSLA_MagicNumber);
|
||||
if(adjustedLot > 0) g_RS_TSLA_LotSize = adjustedLot;
|
||||
|
||||
adjustedLot = GetStrategyLotSize("RSIScalpingXAUUSD", RS_XAUUSD_MagicNumber);
|
||||
if(adjustedLot > 0) g_RS_XAUUSD_LotSize = adjustedLot;
|
||||
}
|
||||
|
||||
Print("United EA initialized. Active strategies: ",
|
||||
(EnableDarvasBox ? "DarvasBox " : ""),
|
||||
(EnableEMASlopeDistance ? "EMASlope " : ""),
|
||||
(EnableRSICrossOverReversal ? "RSICrossOver " : ""),
|
||||
(EnableRSIMidPointHijack ? "RSIMidPoint " : ""),
|
||||
(EnableRSIScalpingAPPL ? "RSIScalpingAPPL " : ""),
|
||||
(EnableRSIScalpingBTCUSD ? "RSIScalpingBTCUSD " : ""),
|
||||
(EnableRSIScalpingMSFT ? "RSIScalpingMSFT " : ""),
|
||||
(EnableRSIScalpingNVDA ? "RSIScalpingNVDA " : ""),
|
||||
(EnableRSIScalpingTSLA ? "RSIScalpingTSLA " : ""),
|
||||
(EnableRSIScalpingXAUUSD ? "RSIScalpingXAUUSD " : ""));
|
||||
|
||||
if(PE_EnableLogging)
|
||||
Print(GetPerformanceSummary());
|
||||
|
||||
return initResult;
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Expert deinitialization function |
|
||||
//+------------------------------------------------------------------+
|
||||
void OnDeinit(const int reason)
|
||||
{
|
||||
if(EnableDarvasBox)
|
||||
DeinitDarvasBox();
|
||||
|
||||
if(EnableEMASlopeDistance)
|
||||
DeinitEMASlopeDistance();
|
||||
|
||||
if(EnableRSICrossOverReversal)
|
||||
DeinitRSICrossOverReversal();
|
||||
|
||||
if(EnableRSIMidPointHijack)
|
||||
DeinitRSIMidPointHijack();
|
||||
|
||||
if(EnableRSIScalpingAPPL)
|
||||
DeinitRSIScalping(rsAPPLData);
|
||||
|
||||
if(EnableRSIScalpingBTCUSD)
|
||||
DeinitRSIScalping(rsBTCUSDData);
|
||||
|
||||
if(EnableRSIScalpingMSFT)
|
||||
DeinitRSIScalping(rsMSFTData);
|
||||
|
||||
if(EnableRSIScalpingNVDA)
|
||||
DeinitRSIScalping(rsNVDAData);
|
||||
|
||||
if(EnableRSIScalpingTSLA)
|
||||
DeinitRSIScalping(rsTSLAData);
|
||||
|
||||
if(EnableRSIScalpingXAUUSD)
|
||||
DeinitRSIScalping(rsXAUUSDData);
|
||||
|
||||
Print("United EA deinitialized. Reason: ", reason);
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Expert tick function |
|
||||
//+------------------------------------------------------------------+
|
||||
void OnTick()
|
||||
{
|
||||
// Process performance evaluation (checks for quarter end and adjusts lot sizes)
|
||||
ProcessPerformanceEvaluation();
|
||||
|
||||
// Update lot sizes from performance evaluator if auto-adjustment is enabled
|
||||
if(PE_EnableAutoAdjustment)
|
||||
{
|
||||
double adjustedLot;
|
||||
adjustedLot = GetStrategyLotSize("EMASlopeDistance", ES_MagicNumber);
|
||||
if(adjustedLot > 0) g_ES_LotSize = adjustedLot;
|
||||
|
||||
adjustedLot = GetStrategyLotSize("RSICrossOverReversal", RC_MagicNumber);
|
||||
if(adjustedLot > 0) g_RC_LotSize = adjustedLot;
|
||||
|
||||
adjustedLot = GetStrategyLotSize("RSIMidPointHijack", RM_InpMagicNumberRSIFollow);
|
||||
if(adjustedLot > 0) g_RM_LotSize = adjustedLot;
|
||||
|
||||
adjustedLot = GetStrategyLotSize("RSIScalpingAPPL", RS_APPL_MagicNumber);
|
||||
if(adjustedLot > 0) g_RS_APPL_LotSize = adjustedLot;
|
||||
|
||||
adjustedLot = GetStrategyLotSize("RSIScalpingBTCUSD", RS_BTCUSD_MagicNumber);
|
||||
if(adjustedLot > 0) g_RS_BTCUSD_LotSize = adjustedLot;
|
||||
|
||||
adjustedLot = GetStrategyLotSize("RSIScalpingMSFT", RS_MSFT_MagicNumber);
|
||||
if(adjustedLot > 0) g_RS_MSFT_LotSize = adjustedLot;
|
||||
|
||||
adjustedLot = GetStrategyLotSize("RSIScalpingNVDA", RS_NVDA_MagicNumber);
|
||||
if(adjustedLot > 0) g_RS_NVDA_LotSize = adjustedLot;
|
||||
|
||||
adjustedLot = GetStrategyLotSize("RSIScalpingTSLA", RS_TSLA_MagicNumber);
|
||||
if(adjustedLot > 0) g_RS_TSLA_LotSize = adjustedLot;
|
||||
|
||||
adjustedLot = GetStrategyLotSize("RSIScalpingXAUUSD", RS_XAUUSD_MagicNumber);
|
||||
if(adjustedLot > 0) g_RS_XAUUSD_LotSize = adjustedLot;
|
||||
}
|
||||
|
||||
if(EnableDarvasBox)
|
||||
ProcessDarvasBox(DB_Symbol);
|
||||
|
||||
if(EnableEMASlopeDistance)
|
||||
ProcessEMASlopeDistance(ES_Symbol);
|
||||
|
||||
if(EnableRSICrossOverReversal)
|
||||
ProcessRSICrossOverReversal(RC_Symbol);
|
||||
|
||||
if(EnableRSIMidPointHijack)
|
||||
ProcessRSIMidPointHijack(RM_Symbol);
|
||||
|
||||
if(EnableRSIScalpingAPPL)
|
||||
ProcessRSIScalping(rsAPPLData, RS_APPL_Symbol, RS_APPL_TimeFrame, RS_APPL_RSI_Period, RS_APPL_RSI_Applied_Price,
|
||||
RS_APPL_RSI_Overbought, RS_APPL_RSI_Oversold, RS_APPL_RSI_Target_Buy, RS_APPL_RSI_Target_Sell,
|
||||
RS_APPL_BarsToWait, g_RS_APPL_LotSize, RS_APPL_MagicNumber);
|
||||
|
||||
if(EnableRSIScalpingBTCUSD)
|
||||
ProcessRSIScalping(rsBTCUSDData, RS_BTCUSD_Symbol, RS_BTCUSD_TimeFrame, RS_BTCUSD_RSI_Period, RS_BTCUSD_RSI_Applied_Price,
|
||||
RS_BTCUSD_RSI_Overbought, RS_BTCUSD_RSI_Oversold, RS_BTCUSD_RSI_Target_Buy, RS_BTCUSD_RSI_Target_Sell,
|
||||
RS_BTCUSD_BarsToWait, g_RS_BTCUSD_LotSize, RS_BTCUSD_MagicNumber);
|
||||
|
||||
if(EnableRSIScalpingMSFT)
|
||||
ProcessRSIScalping(rsMSFTData, RS_MSFT_Symbol, RS_MSFT_TimeFrame, RS_MSFT_RSI_Period, RS_MSFT_RSI_Applied_Price,
|
||||
RS_MSFT_RSI_Overbought, RS_MSFT_RSI_Oversold, RS_MSFT_RSI_Target_Buy, RS_MSFT_RSI_Target_Sell,
|
||||
RS_MSFT_BarsToWait, g_RS_MSFT_LotSize, RS_MSFT_MagicNumber);
|
||||
|
||||
if(EnableRSIScalpingNVDA)
|
||||
ProcessRSIScalping(rsNVDAData, RS_NVDA_Symbol, RS_NVDA_TimeFrame, RS_NVDA_RSI_Period, RS_NVDA_RSI_Applied_Price,
|
||||
RS_NVDA_RSI_Overbought, RS_NVDA_RSI_Oversold, RS_NVDA_RSI_Target_Buy, RS_NVDA_RSI_Target_Sell,
|
||||
RS_NVDA_BarsToWait, g_RS_NVDA_LotSize, RS_NVDA_MagicNumber);
|
||||
|
||||
if(EnableRSIScalpingTSLA)
|
||||
ProcessRSIScalping(rsTSLAData, RS_TSLA_Symbol, RS_TSLA_TimeFrame, RS_TSLA_RSI_Period, RS_TSLA_RSI_Applied_Price,
|
||||
RS_TSLA_RSI_Overbought, RS_TSLA_RSI_Oversold, RS_TSLA_RSI_Target_Buy, RS_TSLA_RSI_Target_Sell,
|
||||
RS_TSLA_BarsToWait, g_RS_TSLA_LotSize, RS_TSLA_MagicNumber);
|
||||
|
||||
if(EnableRSIScalpingXAUUSD)
|
||||
ProcessRSIScalping(rsXAUUSDData, RS_XAUUSD_Symbol, RS_XAUUSD_TimeFrame, RS_XAUUSD_RSI_Period, RS_XAUUSD_RSI_Applied_Price,
|
||||
RS_XAUUSD_RSI_Overbought, RS_XAUUSD_RSI_Oversold, RS_XAUUSD_RSI_Target_Buy, RS_XAUUSD_RSI_Target_Sell,
|
||||
RS_XAUUSD_BarsToWait, g_RS_XAUUSD_LotSize, RS_XAUUSD_MagicNumber);
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Include strategy implementations |
|
||||
//+------------------------------------------------------------------+
|
||||
#include "Strategies/DarvasBoxStrategy.mqh"
|
||||
#include "Strategies/EMASlopeDistanceStrategy.mqh"
|
||||
#include "Strategies/RSICrossOverReversalStrategy.mqh"
|
||||
#include "Strategies/RSIMidPointHijackStrategy.mqh"
|
||||
#include "Strategies/RSIScalpingStrategy.mqh"
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
Reference in New Issue
Block a user