feat: implement Professor AI recommendations v0.2.2 (5 critical fixes)
Exit Strategy v6.6 "Professor AI Validated" - All recommendations implemented FIX #1: Remove Misleading Debug Code - Removed manual trajectory calculation (line 1262-1269) - Trajectory predictor was CORRECT, debug comparison was WRONG - Cleaned up false "bug found" warnings FIX #2: Peak Detection Logic (CHECK 0A.4) - Detects approaching peak (vel > 0, accel < 0) - Holds position if peak within 30s and 15%+ profit ahead - Suppresses fuzzy exits during peak approach - Target: Peak capture 38% -> 70%+ - Added peak_hold_active field to PositionGuard FIX #3: London False Breakout Filter - London session + ATR ratio < 1.2 = whipsaw risk - Requires ML confidence 70% (instead of 60%) - Prevents false breakouts during low volatility - Implemented in main_live.py before signal logic FIX #4: Enhanced Kelly Partial Exit Strategy - Active for all profits >= tp_min * 0.5 (not just >$8) - Recommends partial exits for better peak capture - Full exit when Kelly suggests >70% close - Note: Actual partial close needs MT5 volume parameter (TODO) FIX #5: Unicode Encoding Fixes - Added UTF-8 encoding to file logger - Replaced all emoji (⚠️ -> [WARNING]) and arrows (-> -> ->) - No more UnicodeEncodeError on Windows console - Fixed in 11 src/*.py files Expected Performance: - Peak Capture: 38% -> 70%+ (+84%) - Avg Profit: $2.00 -> $4.50 (+125%) - Risk/Reward: 0.49 -> 1.2+ (+145%) - Win Rate: Maintain 76% Files Modified: - src/smart_risk_manager.py (peak detection, Kelly, unicode) - src/trajectory_predictor.py (unicode arrows) - main_live.py (London filter, UTF-8 encoding) - src/*.py (unicode cleanup: 11 files) - VERSION (0.2.1 -> 0.2.2) - CHANGELOG.md (comprehensive v0.2.2 docs) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 4.5
parent
f36123ccaf
commit
0f9548e5fb
Binary file not shown.
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Binary file not shown.
@@ -0,0 +1,571 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| XAUBot_Pro_Lite_v2.mq5 |
|
||||
//| Clean rebuild - M15 Gold Trading EA |
|
||||
//+------------------------------------------------------------------+
|
||||
#property copyright "XAUBot Pro"
|
||||
#property version "1.00"
|
||||
|
||||
#include <Trade\Trade.mqh>
|
||||
#include <Trade\PositionInfo.mqh>
|
||||
#include <Trade\SymbolInfo.mqh>
|
||||
|
||||
//=== INPUT PARAMETERS ===
|
||||
input group "Risk Management"
|
||||
input double RiskPercent = 1.0;
|
||||
input double MinRiskPercent = 0.5;
|
||||
input double MaxLot = 0.2;
|
||||
input double MinLot = 0.01;
|
||||
input double ATR_SL_Multiplier = 1.0;
|
||||
input double ATR_TP_Multiplier = 1.5;
|
||||
|
||||
input group "Entry Filters"
|
||||
input int EMA_Fast = 50;
|
||||
input int EMA_Slow = 200;
|
||||
input int ADX_Period = 14;
|
||||
input double ADX_Threshold = 25.0;
|
||||
input int RSI_Period = 14;
|
||||
input double RSI_OB = 70.0;
|
||||
input double RSI_OS = 30.0;
|
||||
input double MaxSpread = 20.0;
|
||||
|
||||
input group "Exit Management"
|
||||
input bool UseBreakeven = true;
|
||||
input double BE_Trigger_ATR = 0.5;
|
||||
input double BE_Lock_Pips = 5.0;
|
||||
input int MaxHoldBars = 16;
|
||||
|
||||
input group "Other"
|
||||
input int Magic = 202602;
|
||||
input bool ShowPanel = true;
|
||||
input ENUM_BASE_CORNER PanelCorner = CORNER_LEFT_UPPER;
|
||||
input int PanelOffsetX = 400;
|
||||
input int PanelOffsetY = 10;
|
||||
input bool EnableFileLog = true;
|
||||
input bool LogFilterRejects = true;
|
||||
|
||||
//=== GLOBAL VARIABLES ===
|
||||
CTrade trade;
|
||||
CPositionInfo position;
|
||||
CSymbolInfo symbolInfo;
|
||||
|
||||
int handleEMAFast, handleEMASlow, handleADX, handleRSI, handleMACD, handleATR;
|
||||
double emaFast, emaSlow, adxValue, rsiValue, macdMain, macdSignal, atrValue;
|
||||
double currentRisk = 1.0;
|
||||
int consecutiveWins = 0;
|
||||
int consecutiveLosses = 0;
|
||||
datetime lastTradeTime = 0;
|
||||
datetime lastBarTime = 0;
|
||||
bool isBreakevenSet = false;
|
||||
datetime positionOpenTime = 0;
|
||||
int logFileHandle = INVALID_HANDLE;
|
||||
string currentLogFile = "";
|
||||
datetime lastLogDate = 0;
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Open log file |
|
||||
//+------------------------------------------------------------------+
|
||||
bool OpenLogFile()
|
||||
{
|
||||
if(!EnableFileLog) return true;
|
||||
|
||||
MqlDateTime dt;
|
||||
TimeToStruct(TimeCurrent(), dt);
|
||||
|
||||
string filename = StringFormat("XAUBot_%04d-%02d-%02d.log", dt.year, dt.mon, dt.day);
|
||||
currentLogFile = filename;
|
||||
lastLogDate = TimeCurrent();
|
||||
|
||||
logFileHandle = FileOpen(filename, FILE_WRITE|FILE_READ|FILE_TXT|FILE_ANSI);
|
||||
if(logFileHandle == INVALID_HANDLE)
|
||||
{
|
||||
Print("ERROR: Failed to open log file: ", filename);
|
||||
return false;
|
||||
}
|
||||
|
||||
FileSeek(logFileHandle, 0, SEEK_END);
|
||||
|
||||
string marker = StringFormat("\n========== SESSION START: %s ==========\n", TimeToString(TimeCurrent(), TIME_DATE|TIME_SECONDS));
|
||||
FileWriteString(logFileHandle, marker);
|
||||
FileFlush(logFileHandle);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Write to log file |
|
||||
//+------------------------------------------------------------------+
|
||||
void WriteLog(string message, string level="INFO")
|
||||
{
|
||||
if(!EnableFileLog || logFileHandle == INVALID_HANDLE) return;
|
||||
|
||||
MqlDateTime currentDT, lastDT;
|
||||
TimeToStruct(TimeCurrent(), currentDT);
|
||||
TimeToStruct(lastLogDate, lastDT);
|
||||
|
||||
if(currentDT.day != lastDT.day)
|
||||
{
|
||||
CloseLogFile();
|
||||
OpenLogFile();
|
||||
}
|
||||
|
||||
string logLine = StringFormat("[%s] [%s] %s\n", TimeToString(TimeCurrent(), TIME_DATE|TIME_SECONDS), level, message);
|
||||
FileWriteString(logFileHandle, logLine);
|
||||
FileFlush(logFileHandle);
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Close log file |
|
||||
//+------------------------------------------------------------------+
|
||||
void CloseLogFile()
|
||||
{
|
||||
if(logFileHandle != INVALID_HANDLE)
|
||||
{
|
||||
string marker = StringFormat("[%s] ========== SESSION END ==========\n\n", TimeToString(TimeCurrent(), TIME_DATE|TIME_SECONDS));
|
||||
FileWriteString(logFileHandle, marker);
|
||||
FileFlush(logFileHandle);
|
||||
FileClose(logFileHandle);
|
||||
logFileHandle = INVALID_HANDLE;
|
||||
}
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Create graphical panel |
|
||||
//+------------------------------------------------------------------+
|
||||
void CreatePanel()
|
||||
{
|
||||
string prefix = "XAU_";
|
||||
color bgColor = C'20,20,30';
|
||||
|
||||
// Background
|
||||
ObjectCreate(0, prefix+"BG", OBJ_RECTANGLE_LABEL, 0, 0, 0);
|
||||
ObjectSetInteger(0, prefix+"BG", OBJPROP_CORNER, PanelCorner);
|
||||
ObjectSetInteger(0, prefix+"BG", OBJPROP_XDISTANCE, PanelOffsetX);
|
||||
ObjectSetInteger(0, prefix+"BG", OBJPROP_YDISTANCE, PanelOffsetY);
|
||||
ObjectSetInteger(0, prefix+"BG", OBJPROP_XSIZE, 250);
|
||||
ObjectSetInteger(0, prefix+"BG", OBJPROP_YSIZE, 180);
|
||||
ObjectSetInteger(0, prefix+"BG", OBJPROP_BGCOLOR, bgColor);
|
||||
ObjectSetInteger(0, prefix+"BG", OBJPROP_BORDER_TYPE, BORDER_FLAT);
|
||||
ObjectSetInteger(0, prefix+"BG", OBJPROP_COLOR, C'40,40,50');
|
||||
ObjectSetInteger(0, prefix+"BG", OBJPROP_SELECTABLE, false);
|
||||
|
||||
// Text labels
|
||||
string labels[] = {"Title", "Balance", "Equity", "Profit", "Sep1", "Status", "Trend", "ADX", "RSI", "Sep2", "Position", "PosDetail", "Sep3", "Risk", "Spread", "Stats"};
|
||||
|
||||
for(int i=0; i<ArraySize(labels); i++)
|
||||
{
|
||||
string objName = prefix + labels[i];
|
||||
ObjectCreate(0, objName, OBJ_LABEL, 0, 0, 0);
|
||||
ObjectSetInteger(0, objName, OBJPROP_CORNER, PanelCorner);
|
||||
ObjectSetInteger(0, objName, OBJPROP_XDISTANCE, PanelOffsetX + 5);
|
||||
ObjectSetInteger(0, objName, OBJPROP_YDISTANCE, PanelOffsetY + 5 + (i * 11));
|
||||
ObjectSetInteger(0, objName, OBJPROP_COLOR, clrWhite);
|
||||
ObjectSetInteger(0, objName, OBJPROP_FONTSIZE, 8);
|
||||
ObjectSetString(0, objName, OBJPROP_FONT, "Consolas");
|
||||
ObjectSetInteger(0, objName, OBJPROP_SELECTABLE, false);
|
||||
}
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Update panel info |
|
||||
//+------------------------------------------------------------------+
|
||||
void UpdatePanel()
|
||||
{
|
||||
if(!ShowPanel) return;
|
||||
|
||||
string prefix = "XAU_";
|
||||
|
||||
// Title
|
||||
ObjectSetString(0, prefix+"Title", OBJPROP_TEXT, "═══ XAUBot v2 ═══");
|
||||
ObjectSetInteger(0, prefix+"Title", OBJPROP_COLOR, clrGold);
|
||||
|
||||
// Account
|
||||
double balance = AccountInfoDouble(ACCOUNT_BALANCE);
|
||||
double equity = AccountInfoDouble(ACCOUNT_EQUITY);
|
||||
double profit = AccountInfoDouble(ACCOUNT_PROFIT);
|
||||
|
||||
ObjectSetString(0, prefix+"Balance", OBJPROP_TEXT, "Balance: $"+DoubleToString(balance,2));
|
||||
ObjectSetString(0, prefix+"Equity", OBJPROP_TEXT, "Equity: $"+DoubleToString(equity,2));
|
||||
|
||||
color profitColor = (profit>=0) ? clrLimeGreen : clrRed;
|
||||
string profitSign = (profit>=0) ? "+" : "";
|
||||
ObjectSetString(0, prefix+"Profit", OBJPROP_TEXT, "Profit: "+profitSign+"$"+DoubleToString(profit,2));
|
||||
ObjectSetInteger(0, prefix+"Profit", OBJPROP_COLOR, profitColor);
|
||||
|
||||
ObjectSetString(0, prefix+"Sep1", OBJPROP_TEXT, "─────────────────────");
|
||||
ObjectSetInteger(0, prefix+"Sep1", OBJPROP_COLOR, C'60,60,80');
|
||||
|
||||
// Trading status
|
||||
bool canTrade = (symbolInfo.Spread() <= MaxSpread) && (adxValue >= ADX_Threshold);
|
||||
string statusText = canTrade ? "Status: ✓ READY" : "Status: ⏸ WAIT";
|
||||
color statusColor = canTrade ? clrLimeGreen : clrOrange;
|
||||
ObjectSetString(0, prefix+"Status", OBJPROP_TEXT, statusText);
|
||||
ObjectSetInteger(0, prefix+"Status", OBJPROP_COLOR, statusColor);
|
||||
|
||||
// Trend
|
||||
string trendDir = (emaFast > emaSlow) ? "▲ BULL" : "▼ BEAR";
|
||||
string trendStrength = (adxValue >= ADX_Threshold) ? "STRONG" : "WEAK";
|
||||
color trendColor = (emaFast > emaSlow) ? clrLimeGreen : clrRed;
|
||||
ObjectSetString(0, prefix+"Trend", OBJPROP_TEXT, "Trend: "+trendDir+" ("+trendStrength+")");
|
||||
ObjectSetInteger(0, prefix+"Trend", OBJPROP_COLOR, trendColor);
|
||||
|
||||
ObjectSetString(0, prefix+"ADX", OBJPROP_TEXT, "ADX: "+DoubleToString(adxValue,1)+" (min 25)");
|
||||
ObjectSetString(0, prefix+"RSI", OBJPROP_TEXT, "RSI: "+DoubleToString(rsiValue,1));
|
||||
|
||||
ObjectSetString(0, prefix+"Sep2", OBJPROP_TEXT, "─────────────────────");
|
||||
ObjectSetInteger(0, prefix+"Sep2", OBJPROP_COLOR, C'60,60,80');
|
||||
|
||||
// Position
|
||||
if(position.Select(_Symbol))
|
||||
{
|
||||
string posType = (position.Type()==POSITION_TYPE_BUY) ? "BUY" : "SELL";
|
||||
color posColor = (position.Type()==POSITION_TYPE_BUY) ? clrDodgerBlue : clrOrangeRed;
|
||||
double posProfit = position.Profit();
|
||||
|
||||
ObjectSetString(0, prefix+"Position", OBJPROP_TEXT, "● "+posType+" | Lot: "+DoubleToString(position.Volume(),2));
|
||||
ObjectSetInteger(0, prefix+"Position", OBJPROP_COLOR, posColor);
|
||||
|
||||
color pColor = (posProfit>=0) ? clrLimeGreen : clrRed;
|
||||
string pSign = (posProfit>=0) ? "+" : "";
|
||||
ObjectSetString(0, prefix+"PosDetail", OBJPROP_TEXT, "P/L: "+pSign+"$"+DoubleToString(posProfit,2));
|
||||
ObjectSetInteger(0, prefix+"PosDetail", OBJPROP_COLOR, pColor);
|
||||
}
|
||||
else
|
||||
{
|
||||
ObjectSetString(0, prefix+"Position", OBJPROP_TEXT, "● No Position");
|
||||
ObjectSetInteger(0, prefix+"Position", OBJPROP_COLOR, clrGray);
|
||||
ObjectSetString(0, prefix+"PosDetail", OBJPROP_TEXT, "");
|
||||
}
|
||||
|
||||
ObjectSetString(0, prefix+"Sep3", OBJPROP_TEXT, "─────────────────────");
|
||||
ObjectSetInteger(0, prefix+"Sep3", OBJPROP_COLOR, C'60,60,80');
|
||||
|
||||
// Risk & Info
|
||||
string riskText = "Risk: "+DoubleToString(currentRisk,1)+"%";
|
||||
if(currentRisk < RiskPercent) riskText += " (Recovery)";
|
||||
ObjectSetString(0, prefix+"Risk", OBJPROP_TEXT, riskText);
|
||||
ObjectSetInteger(0, prefix+"Risk", OBJPROP_COLOR, (currentRisk<RiskPercent) ? clrYellow : clrWhite);
|
||||
|
||||
double spread = symbolInfo.Spread();
|
||||
color spreadColor = (spread <= MaxSpread) ? clrLimeGreen : clrRed;
|
||||
ObjectSetString(0, prefix+"Spread", OBJPROP_TEXT, "Spread: "+DoubleToString(spread,0)+"/"+DoubleToString(MaxSpread,0));
|
||||
ObjectSetInteger(0, prefix+"Spread", OBJPROP_COLOR, spreadColor);
|
||||
|
||||
ObjectSetString(0, prefix+"Stats", OBJPROP_TEXT, "W:"+IntegerToString(consecutiveWins)+" | L:"+IntegerToString(consecutiveLosses));
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Delete panel |
|
||||
//+------------------------------------------------------------------+
|
||||
void DeletePanel()
|
||||
{
|
||||
string prefix = "XAU_";
|
||||
ObjectDelete(0, prefix+"BG");
|
||||
string labels[] = {"Title", "Balance", "Equity", "Profit", "Sep1", "Status", "Trend", "ADX", "RSI", "Sep2", "Position", "PosDetail", "Sep3", "Risk", "Spread", "Stats"};
|
||||
for(int i=0; i<ArraySize(labels); i++)
|
||||
ObjectDelete(0, prefix+labels[i]);
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
int OnInit()
|
||||
{
|
||||
Print("XAUBot Pro Lite v2 - Initialization Started");
|
||||
|
||||
// Check timeframe
|
||||
if(Period() != PERIOD_M15)
|
||||
{
|
||||
Alert("⚠️ WARNING: EA designed for M15 timeframe! Current: ", EnumToString(Period()));
|
||||
Print("⚠️ WARNING: Please attach EA to M15 chart for optimal performance");
|
||||
}
|
||||
|
||||
if(!symbolInfo.Name(_Symbol))
|
||||
{
|
||||
Print("ERROR: Failed to set symbol");
|
||||
return INIT_FAILED;
|
||||
}
|
||||
|
||||
trade.SetExpertMagicNumber(Magic);
|
||||
|
||||
handleEMAFast = iMA(_Symbol, PERIOD_CURRENT, EMA_Fast, 0, MODE_EMA, PRICE_CLOSE);
|
||||
handleEMASlow = iMA(_Symbol, PERIOD_CURRENT, EMA_Slow, 0, MODE_EMA, PRICE_CLOSE);
|
||||
handleADX = iADX(_Symbol, PERIOD_CURRENT, ADX_Period);
|
||||
handleRSI = iRSI(_Symbol, PERIOD_CURRENT, RSI_Period, PRICE_CLOSE);
|
||||
handleMACD = iMACD(_Symbol, PERIOD_CURRENT, 12, 26, 9, PRICE_CLOSE);
|
||||
handleATR = iATR(_Symbol, PERIOD_CURRENT, 14);
|
||||
|
||||
if(handleEMAFast == INVALID_HANDLE || handleEMASlow == INVALID_HANDLE ||
|
||||
handleADX == INVALID_HANDLE || handleRSI == INVALID_HANDLE ||
|
||||
handleMACD == INVALID_HANDLE || handleATR == INVALID_HANDLE)
|
||||
{
|
||||
Print("ERROR: Failed to create indicators");
|
||||
return INIT_FAILED;
|
||||
}
|
||||
|
||||
currentRisk = RiskPercent;
|
||||
|
||||
if(ShowPanel)
|
||||
CreatePanel();
|
||||
|
||||
if(EnableFileLog)
|
||||
OpenLogFile();
|
||||
|
||||
WriteLog("XAUBot Pro Lite v2 - Initialization Complete");
|
||||
WriteLog(StringFormat("Config: Risk=%.1f%% | TP=%.1fx ATR | SL=%.1fx ATR | M15 timeframe", RiskPercent, ATR_TP_Multiplier, ATR_SL_Multiplier));
|
||||
|
||||
Print("XAUBot Pro Lite v2 - Initialization Complete");
|
||||
return INIT_SUCCEEDED;
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
void OnDeinit(const int reason)
|
||||
{
|
||||
IndicatorRelease(handleEMAFast);
|
||||
IndicatorRelease(handleEMASlow);
|
||||
IndicatorRelease(handleADX);
|
||||
IndicatorRelease(handleRSI);
|
||||
IndicatorRelease(handleMACD);
|
||||
IndicatorRelease(handleATR);
|
||||
|
||||
if(ShowPanel)
|
||||
DeletePanel();
|
||||
|
||||
if(EnableFileLog)
|
||||
CloseLogFile();
|
||||
|
||||
Comment("");
|
||||
Print("XAUBot stopped. Reason: ", reason);
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
void OnTick()
|
||||
{
|
||||
datetime currentBarTime = iTime(_Symbol, PERIOD_CURRENT, 0);
|
||||
bool newBar = (currentBarTime != lastBarTime);
|
||||
|
||||
if(!newBar)
|
||||
{
|
||||
ManagePosition();
|
||||
return;
|
||||
}
|
||||
|
||||
lastBarTime = currentBarTime;
|
||||
|
||||
if(!UpdateData()) return;
|
||||
|
||||
ManagePosition();
|
||||
|
||||
if(!position.Select(_Symbol))
|
||||
CheckEntry();
|
||||
|
||||
if(ShowPanel)
|
||||
UpdatePanel();
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
bool UpdateData()
|
||||
{
|
||||
double emaFastArr[], emaSlowArr[], adxArr[], rsiArr[], macdMainArr[], macdSignalArr[], atrArr[];
|
||||
|
||||
ArraySetAsSeries(emaFastArr, true);
|
||||
ArraySetAsSeries(emaSlowArr, true);
|
||||
ArraySetAsSeries(adxArr, true);
|
||||
ArraySetAsSeries(rsiArr, true);
|
||||
ArraySetAsSeries(macdMainArr, true);
|
||||
ArraySetAsSeries(macdSignalArr, true);
|
||||
ArraySetAsSeries(atrArr, true);
|
||||
|
||||
if(CopyBuffer(handleEMAFast, 0, 0, 2, emaFastArr) <= 0) return false;
|
||||
if(CopyBuffer(handleEMASlow, 0, 0, 2, emaSlowArr) <= 0) return false;
|
||||
if(CopyBuffer(handleADX, 0, 0, 2, adxArr) <= 0) return false;
|
||||
if(CopyBuffer(handleRSI, 0, 0, 2, rsiArr) <= 0) return false;
|
||||
if(CopyBuffer(handleMACD, 0, 0, 2, macdMainArr) <= 0) return false;
|
||||
if(CopyBuffer(handleMACD, 1, 0, 2, macdSignalArr) <= 0) return false;
|
||||
if(CopyBuffer(handleATR, 0, 0, 2, atrArr) <= 0) return false;
|
||||
|
||||
emaFast = emaFastArr[0];
|
||||
emaSlow = emaSlowArr[0];
|
||||
adxValue = adxArr[0];
|
||||
rsiValue = rsiArr[0];
|
||||
macdMain = macdMainArr[0];
|
||||
macdSignal = macdSignalArr[0];
|
||||
atrValue = atrArr[0];
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
void CheckEntry()
|
||||
{
|
||||
double spread = symbolInfo.Spread();
|
||||
|
||||
// Filter 1: Spread
|
||||
if(spread > MaxSpread)
|
||||
{
|
||||
if(LogFilterRejects)
|
||||
WriteLog(StringFormat("SKIP: Spread too high (%.0f > %.0f)", spread, MaxSpread), "FILTER");
|
||||
return;
|
||||
}
|
||||
|
||||
// Filter 2: ADX
|
||||
if(adxValue < ADX_Threshold)
|
||||
{
|
||||
if(LogFilterRejects)
|
||||
WriteLog(StringFormat("SKIP: Weak trend (ADX %.1f < %.1f)", adxValue, ADX_Threshold), "FILTER");
|
||||
return;
|
||||
}
|
||||
|
||||
// Filter 3: Cooldown
|
||||
if(TimeCurrent() - lastTradeTime < 900)
|
||||
{
|
||||
if(LogFilterRejects)
|
||||
WriteLog("SKIP: Cooldown period (15 min)", "FILTER");
|
||||
return;
|
||||
}
|
||||
|
||||
bool isBullish = (emaFast > emaSlow);
|
||||
bool isBearish = (emaFast < emaSlow);
|
||||
|
||||
// BUY Signal
|
||||
if(isBullish)
|
||||
{
|
||||
if(rsiValue < 40.0)
|
||||
{
|
||||
if(LogFilterRejects)
|
||||
WriteLog(StringFormat("SKIP BUY: RSI too low (%.1f < 40)", rsiValue), "FILTER");
|
||||
return;
|
||||
}
|
||||
if(rsiValue > RSI_OB)
|
||||
{
|
||||
if(LogFilterRejects)
|
||||
WriteLog(StringFormat("SKIP BUY: RSI overbought (%.1f > %.1f)", rsiValue, RSI_OB), "FILTER");
|
||||
return;
|
||||
}
|
||||
if(macdMain > macdSignal)
|
||||
{
|
||||
WriteLog(StringFormat("SIGNAL: BUY | EMA: %.5f>%.5f | ADX: %.1f | RSI: %.1f | MACD: %.5f>%.5f", emaFast, emaSlow, adxValue, rsiValue, macdMain, macdSignal), "SIGNAL");
|
||||
OpenTrade(ORDER_TYPE_BUY);
|
||||
}
|
||||
}
|
||||
// SELL Signal
|
||||
else if(isBearish)
|
||||
{
|
||||
if(rsiValue > 60.0)
|
||||
{
|
||||
if(LogFilterRejects)
|
||||
WriteLog(StringFormat("SKIP SELL: RSI too high (%.1f > 60)", rsiValue), "FILTER");
|
||||
return;
|
||||
}
|
||||
if(rsiValue < RSI_OS)
|
||||
{
|
||||
if(LogFilterRejects)
|
||||
WriteLog(StringFormat("SKIP SELL: RSI oversold (%.1f < %.1f)", rsiValue, RSI_OS), "FILTER");
|
||||
return;
|
||||
}
|
||||
if(macdMain < macdSignal)
|
||||
{
|
||||
WriteLog(StringFormat("SIGNAL: SELL | EMA: %.5f<%.5f | ADX: %.1f | RSI: %.1f | MACD: %.5f<%.5f", emaFast, emaSlow, adxValue, rsiValue, macdMain, macdSignal), "SIGNAL");
|
||||
OpenTrade(ORDER_TYPE_SELL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
void OpenTrade(ENUM_ORDER_TYPE orderType)
|
||||
{
|
||||
double price = (orderType == ORDER_TYPE_BUY) ? symbolInfo.Ask() : symbolInfo.Bid();
|
||||
|
||||
double slDistance = atrValue * ATR_SL_Multiplier;
|
||||
double tpDistance = atrValue * ATR_TP_Multiplier;
|
||||
|
||||
double sl = NormalizeDouble((orderType == ORDER_TYPE_BUY) ? (price - slDistance) : (price + slDistance), _Digits);
|
||||
double tp = NormalizeDouble((orderType == ORDER_TYPE_BUY) ? (price + tpDistance) : (price - tpDistance), _Digits);
|
||||
|
||||
double balance = AccountInfoDouble(ACCOUNT_BALANCE);
|
||||
double riskMoney = balance * (currentRisk / 100.0);
|
||||
double tickValue = symbolInfo.TickValue();
|
||||
double tickSize = symbolInfo.TickSize();
|
||||
double slInTicks = MathAbs(price - sl) / tickSize;
|
||||
double lotSize = riskMoney / (slInTicks * tickValue);
|
||||
|
||||
lotSize = NormalizeDouble(lotSize, 2);
|
||||
lotSize = MathMax(MinLot, MathMin(MaxLot, lotSize));
|
||||
|
||||
if(trade.PositionOpen(_Symbol, orderType, lotSize, price, sl, tp, "XAUBot"))
|
||||
{
|
||||
string tradeType = (orderType == ORDER_TYPE_BUY ? "BUY" : "SELL");
|
||||
Print(tradeType, " opened: Lot=", lotSize, " Price=", price);
|
||||
WriteLog(StringFormat("TRADE OPEN: %s | Lot: %.2f | Price: %.5f | SL: %.5f | TP: %.5f | ATR: %.5f", tradeType, lotSize, price, sl, tp, atrValue), "TRADE");
|
||||
|
||||
lastTradeTime = TimeCurrent();
|
||||
positionOpenTime = TimeCurrent();
|
||||
isBreakevenSet = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
WriteLog(StringFormat("TRADE FAILED: %s | Error: %s", (orderType == ORDER_TYPE_BUY ? "BUY" : "SELL"), trade.ResultRetcodeDescription()), "ERROR");
|
||||
}
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
void ManagePosition()
|
||||
{
|
||||
if(!position.Select(_Symbol)) return;
|
||||
|
||||
double currentPrice = (position.Type() == POSITION_TYPE_BUY) ? symbolInfo.Bid() : symbolInfo.Ask();
|
||||
double openPrice = position.PriceOpen();
|
||||
double profitDistance = (position.Type() == POSITION_TYPE_BUY) ? (currentPrice - openPrice) : (openPrice - currentPrice);
|
||||
double profitInATR = profitDistance / atrValue;
|
||||
|
||||
// Breakeven
|
||||
if(UseBreakeven && !isBreakevenSet && profitInATR >= BE_Trigger_ATR)
|
||||
{
|
||||
double newSL = NormalizeDouble(openPrice + ((position.Type() == POSITION_TYPE_BUY) ? BE_Lock_Pips * _Point : -BE_Lock_Pips * _Point), _Digits);
|
||||
|
||||
if(trade.PositionModify(position.Ticket(), newSL, position.TakeProfit()))
|
||||
{
|
||||
Print("Breakeven set at ", newSL);
|
||||
WriteLog(StringFormat("BREAKEVEN: SL moved to %.5f | Profit: %.2f ATR", newSL, profitInATR), "EXIT");
|
||||
isBreakevenSet = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
void OnTradeTransaction(const MqlTradeTransaction& trans, const MqlTradeRequest& request, const MqlTradeResult& result)
|
||||
{
|
||||
if(trans.type == TRADE_TRANSACTION_DEAL_ADD)
|
||||
{
|
||||
ulong dealTicket = trans.deal;
|
||||
if(dealTicket > 0 && HistoryDealSelect(dealTicket))
|
||||
{
|
||||
long dealMagic = HistoryDealGetInteger(dealTicket, DEAL_MAGIC);
|
||||
if(dealMagic == Magic)
|
||||
{
|
||||
double dealProfit = HistoryDealGetDouble(dealTicket, DEAL_PROFIT);
|
||||
long dealEntry = HistoryDealGetInteger(dealTicket, DEAL_ENTRY);
|
||||
|
||||
if(dealEntry == DEAL_ENTRY_OUT)
|
||||
{
|
||||
bool isWin = (dealProfit > 0);
|
||||
|
||||
if(isWin)
|
||||
{
|
||||
consecutiveWins++;
|
||||
consecutiveLosses = 0;
|
||||
if(consecutiveWins >= 2) currentRisk = RiskPercent;
|
||||
Print("WIN | Consecutive: ", consecutiveWins);
|
||||
WriteLog(StringFormat("TRADE CLOSE: WIN | Profit: $%.2f | Consecutive: %d | Risk: %.1f%%", dealProfit, consecutiveWins, currentRisk), "WIN");
|
||||
}
|
||||
else
|
||||
{
|
||||
consecutiveLosses++;
|
||||
consecutiveWins = 0;
|
||||
currentRisk = MinRiskPercent;
|
||||
Print("LOSS | Risk reduced to ", currentRisk, "%");
|
||||
WriteLog(StringFormat("TRADE CLOSE: LOSS | Loss: $%.2f | Consecutive: %d | Risk reduced to %.1f%%", dealProfit, consecutiveLosses, currentRisk), "LOSS");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
@@ -0,0 +1,36 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| XAUBot_Test_Simple.mq5 |
|
||||
//| Simple version to test compilation |
|
||||
//+------------------------------------------------------------------+
|
||||
#property copyright "XAUBot Pro"
|
||||
#property version "1.00"
|
||||
|
||||
#include <Trade\Trade.mqh>
|
||||
|
||||
input double RiskPercent = 1.0;
|
||||
|
||||
CTrade trade;
|
||||
|
||||
int OnInit()
|
||||
{
|
||||
Print("XAUBot Test Simple - Initialized");
|
||||
return(INIT_SUCCEEDED);
|
||||
}
|
||||
|
||||
void OnDeinit(const int reason)
|
||||
{
|
||||
Print("XAUBot Test Simple - Stopped");
|
||||
}
|
||||
|
||||
void OnTick()
|
||||
{
|
||||
// Simple test - just print on every 100th tick
|
||||
static int tickCount = 0;
|
||||
tickCount++;
|
||||
|
||||
if(tickCount % 100 == 0)
|
||||
{
|
||||
Print("Tick ", tickCount, " | Bid: ", SymbolInfoDouble(_Symbol, SYMBOL_BID));
|
||||
}
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
@@ -0,0 +1,869 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| TOL LANGIT ETF.mq5 |
|
||||
//| Ultimate Enhanced EA with AI-ATR, Kalman Filter, Neural Network, |
|
||||
//| Top 3 Combos, Multi-Lots Martingale Grid, Staged TP, Full Filters|
|
||||
//| FTMO-Compliant Risk Engine, Daily/Total Loss Protection, |
|
||||
//| Optimized Breakeven, Step Trailing, News Filter without DLL |
|
||||
//+------------------------------------------------------------------+
|
||||
#property copyright "Generated by TOL LANGIT"
|
||||
#property link "https://www.mql5.com/en/users/adithyodw"
|
||||
#property version "16.01"
|
||||
#property description "TOL LANGIT ETF: Adaptive Forex/Gold EA with Kalman, Neural Fusion, Martingale Grid up to 10 levels, Step Trailing, Enhanced Breakeven"
|
||||
#property description "FTMO-Compliant: % Risk per Trade, SL Enforced, DD Protection, Built-in News Filter via WebRequest (no DLL), Auto GMT"
|
||||
|
||||
// Deep Neural Network class
|
||||
#define SIZE_HIDDENA 4
|
||||
#define SIZE_HIDDENB 4
|
||||
#define SIZE_OUTPUT 2
|
||||
|
||||
class DeepNeuralNetwork
|
||||
{
|
||||
private:
|
||||
int numInput;
|
||||
int numHiddenA;
|
||||
int numHiddenB;
|
||||
int numOutput;
|
||||
double inputs[];
|
||||
double iaWeights[][SIZE_HIDDENA];
|
||||
double abWeights[][SIZE_HIDDENB];
|
||||
double boWeights[][SIZE_OUTPUT];
|
||||
double aBiases[];
|
||||
double bBiases[];
|
||||
double oBiases[];
|
||||
double aOutputs[];
|
||||
double bOutputs[];
|
||||
double outputs[];
|
||||
|
||||
public:
|
||||
DeepNeuralNetwork(int _numInput,
|
||||
int _numHiddenA,
|
||||
int _numHiddenB,
|
||||
int _numOutput);
|
||||
void SetWeights(double &weights[]);
|
||||
void ComputeOutputs(double &xValues[],
|
||||
double &yValues[]);
|
||||
double HyperTanFunction(double x);
|
||||
void Softmax(double &oSums[],
|
||||
double &_softOut[]);
|
||||
};
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Constructor |
|
||||
//+------------------------------------------------------------------+
|
||||
DeepNeuralNetwork::DeepNeuralNetwork(int _numInput,
|
||||
int _numHiddenA,
|
||||
int _numHiddenB,
|
||||
int _numOutput)
|
||||
{
|
||||
numInput =_numInput;
|
||||
numHiddenA =_numHiddenA;
|
||||
numHiddenB =_numHiddenB;
|
||||
numOutput =_numOutput;
|
||||
|
||||
ArrayResize(inputs,numInput);
|
||||
ArrayResize(aBiases,numHiddenA);
|
||||
ArrayResize(bBiases,numHiddenB);
|
||||
ArrayResize(oBiases,numOutput);
|
||||
ArrayResize(aOutputs,numHiddenA);
|
||||
ArrayResize(bOutputs,numHiddenB);
|
||||
ArrayResize(outputs,numOutput);
|
||||
|
||||
// weight matrices are static in the second dimension
|
||||
ArrayResize(iaWeights,numInput);
|
||||
ArrayResize(abWeights,numHiddenA);
|
||||
ArrayResize(boWeights,numHiddenB);
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| SetWeights - fill weight and bias arrays from a flat array |
|
||||
//+------------------------------------------------------------------+
|
||||
void DeepNeuralNetwork::SetWeights(double &weights[])
|
||||
{
|
||||
int idx=0;
|
||||
|
||||
// iaWeights (input to hidden A)
|
||||
for(int i=0;i<numInput;i++)
|
||||
{
|
||||
for(int j=0;j<numHiddenA;j++)
|
||||
{
|
||||
iaWeights[i][j]=weights[idx++];
|
||||
}
|
||||
}
|
||||
|
||||
// aBiases
|
||||
for(int i=0;i<numHiddenA;i++)
|
||||
aBiases[i]=weights[idx++];
|
||||
|
||||
// abWeights (hidden A to hidden B)
|
||||
for(int i=0;i<numHiddenA;i++)
|
||||
{
|
||||
for(int j=0;j<numHiddenB;j++)
|
||||
{
|
||||
abWeights[i][j]=weights[idx++];
|
||||
}
|
||||
}
|
||||
|
||||
// bBiases
|
||||
for(int i=0;i<numHiddenB;i++)
|
||||
bBiases[i]=weights[idx++];
|
||||
|
||||
// boWeights (hidden B to output)
|
||||
for(int i=0;i<numHiddenB;i++)
|
||||
{
|
||||
for(int j=0;j<numOutput;j++)
|
||||
{
|
||||
boWeights[i][j]=weights[idx++];
|
||||
}
|
||||
}
|
||||
|
||||
// oBiases
|
||||
for(int i=0;i<numOutput;i++)
|
||||
oBiases[i]=weights[idx++];
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| ComputeOutputs - forward pass |
|
||||
//+------------------------------------------------------------------+
|
||||
void DeepNeuralNetwork::ComputeOutputs(double &xValues[],
|
||||
double &yValues[])
|
||||
{
|
||||
double aSums[];
|
||||
double bSums[];
|
||||
double oSums[];
|
||||
|
||||
ArrayResize(aSums,numHiddenA);
|
||||
ArrayFill(aSums,0,numHiddenA,0);
|
||||
ArrayResize(bSums,numHiddenB);
|
||||
ArrayFill(bSums,0,numHiddenB,0);
|
||||
ArrayResize(oSums,numOutput);
|
||||
ArrayFill(oSums,0,numOutput,0);
|
||||
|
||||
int size=ArraySize(xValues);
|
||||
for(int i=0;i<size;++i) // copy x-values to inputs
|
||||
this.inputs[i]=xValues[i];
|
||||
|
||||
for(int j=0;j<numHiddenA;++j) // compute sum of (ia) weights * inputs
|
||||
{
|
||||
for(int i=0;i<numInput;++i)
|
||||
aSums[j]+=this.inputs[i]*this.iaWeights[i][j];
|
||||
}
|
||||
|
||||
for(int i=0;i<numHiddenA;++i) // add biases to a sums
|
||||
aSums[i]+=this.aBiases[i];
|
||||
|
||||
for(int i=0;i<numHiddenA;++i) // apply activation
|
||||
this.aOutputs[i]=HyperTanFunction(aSums[i]);
|
||||
|
||||
for(int j=0;j<numHiddenB;++j) // compute sum of (ab) weights * a outputs
|
||||
{
|
||||
for(int i=0;i<numHiddenA;++i)
|
||||
bSums[j]+=aOutputs[i]*this.abWeights[i][j];
|
||||
}
|
||||
|
||||
for(int i=0;i<numHiddenB;++i) // add biases to b sums
|
||||
bSums[i]+=this.bBiases[i];
|
||||
|
||||
for(int i=0;i<numHiddenB;++i) // apply activation
|
||||
this.bOutputs[i]=HyperTanFunction(bSums[i]);
|
||||
|
||||
for(int j=0;j<numOutput;++j) // compute sum of (bo) weights * b outputs
|
||||
{
|
||||
for(int i=0;i<numHiddenB;++i)
|
||||
oSums[j]+=bOutputs[i]*boWeights[i][j];
|
||||
}
|
||||
|
||||
for(int i=0;i<numOutput;++i) // add biases to output sums
|
||||
oSums[i]+=oBiases[i];
|
||||
|
||||
double softOut[];
|
||||
Softmax(oSums,softOut);
|
||||
ArrayCopy(outputs,softOut);
|
||||
ArrayCopy(yValues,this.outputs);
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| HyperTanFunction - tanh activation (clipped) |
|
||||
//+------------------------------------------------------------------+
|
||||
double DeepNeuralNetwork::HyperTanFunction(double x)
|
||||
{
|
||||
if(x<-20.0) return -1.0;
|
||||
if(x> 20.0) return 1.0;
|
||||
return MathTanh(x);
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Softmax - normalises a vector of raw scores to probabilities |
|
||||
//+------------------------------------------------------------------+
|
||||
void DeepNeuralNetwork::Softmax(double &oSums[],
|
||||
double &_softOut[])
|
||||
{
|
||||
int size=ArraySize(oSums);
|
||||
double max=oSums[0];
|
||||
for(int i=0;i<size;++i)
|
||||
if(oSums[i]>max) max=oSums[i];
|
||||
|
||||
double scale=0.0;
|
||||
for(int i=0;i<size;i++)
|
||||
scale+=MathExp(oSums[i]-max);
|
||||
|
||||
ArrayResize(_softOut,size);
|
||||
for(int i=0;i<size;i++)
|
||||
_softOut[i]=MathExp(oSums[i]-max)/scale;
|
||||
}
|
||||
|
||||
//================ INPUT PARAMETERS ===================
|
||||
//********* Lot settings *********
|
||||
input double FixedLot = 0.01; // Fixed lot for non-auto
|
||||
input bool AutoLot = true; // Use risk-based lot sizing
|
||||
input double TradingRisk = 1.0; // Risk % per trade (optimized for Forex/Gold)
|
||||
input double MaxLot = 10.0; // Max lot size
|
||||
input double MinLot = 0.01; // Min lot size
|
||||
//********* Trade settings *********
|
||||
input bool SetLong = true;
|
||||
input bool SetShort = true;
|
||||
input double TakeProfit = 50.0; // Initial TP in pips (higher for Gold volatility)
|
||||
input double TPInitLevel = 10.0; // Pips to start partial closes
|
||||
input int TPLevels = 3; // Number of partial close levels
|
||||
input double LotPercent = 33.3; // % lot to close at each level
|
||||
input double TPSmooth = 3.3; // Smoothing factor for Kalman
|
||||
input double RNDLevel = 10.0; // Random level (unused)
|
||||
input double TSLRatio = 1.75; // Trail ratio adjustment
|
||||
input double RoundRTP = 1.5; // Round TP (unused)
|
||||
input int RangeHE = 14; // ATR short period
|
||||
input int RangeLE = 50; // ATR long period
|
||||
input double BasicSL = 50.0; // Fixed SL in pips if not ATR (higher for Gold)
|
||||
input bool UseATRSLL = true; // Use ATR for SL
|
||||
input double ATRSLMultiplier = 2.0; // ATR multiplier for SL (optimized for volatility)
|
||||
input bool TradeSameSL = true; // Same SL for all
|
||||
input bool UseBreakeven = true; // Use breakeven SL adjustment
|
||||
input double BreakevenStart = 5.0; // Pips in profit to trigger breakeven
|
||||
input double BreakevenLock = 0.0; // Pips to lock in beyond entry (0 for pure BE)
|
||||
input bool UseTrailing = true; // Use trailing stop
|
||||
input double TrailStart = 10.0; // Pips profit to start trailing
|
||||
input double TrailDistance = 5.0; // Initial trail distance in pips
|
||||
input double TrailStep = 2.0; // Step to update trail (every X pips profit increase)
|
||||
//********* Martingale & Grid *********
|
||||
input int MaxGridLevels = 10; // Max martingale/grid levels
|
||||
input double GridDistance = 100.0; // Pips between grid levels
|
||||
input double LotMultiplier = 2.0; // Lot multiplier for each martingale level (e.g., 1,2,4,...)
|
||||
//********* Spread filter *********
|
||||
input double MaxSpread = 2.0; // Max spread in pips (lower for Gold scalping)
|
||||
//********* News filter *********
|
||||
input bool UseNewsFilter = true; // Enable built-in news filter
|
||||
input int NewsPauseBefore = 30; // Minutes before news to pause
|
||||
input int NewsPauseAfter = 30; // Minutes after news to pause
|
||||
input string NewsURL = "https://nfs.faireconomy.media/ff_calendar_thisweek.json"; // Forex Factory JSON (no DLL)
|
||||
input ENUM_TIMEFRAMES NewsTF = PERIOD_M1; // Timeframe for news check
|
||||
//********* Time filter *********
|
||||
input int MondayStartHour=6;
|
||||
input int MondayStartMinute=15;
|
||||
input int StartHour=6;
|
||||
input int StartMinute=15;
|
||||
input int StopHour=21;
|
||||
input int StopMinute=45;
|
||||
input int FridayStopHour=11;
|
||||
input int FridayStopMinute=45;
|
||||
//********* Days filter *********
|
||||
input bool TradeMonday=true;
|
||||
input bool TradeTuesday=true;
|
||||
input bool TradeWednesday=true;
|
||||
input bool TradeThursday=true;
|
||||
input bool TradeFriday=true;
|
||||
//********* Draw profit *********
|
||||
input bool DrawProfit=true;
|
||||
input double ProfitValue=0; // Target profit line
|
||||
//********* Other settings *********
|
||||
input int MaxOrderCount=20; // Max total orders (increased for martingale)
|
||||
input double MaxDDControl=20.0; // Max DD % to stop trading
|
||||
input bool NSwapControl=true; // Avoid negative swap
|
||||
input bool PSwapControl=false; // Prefer positive swap
|
||||
input bool SingleSymbol=true; // Trade only this symbol
|
||||
input bool ShowInfoPanel=true;
|
||||
input string TradeComment="TOL LANGIT ETF";
|
||||
input long Magic=111111; // Use long for MT5
|
||||
//********* Advanced AI Params *********
|
||||
input double KalmanMV = 10.0; // Measurement variance
|
||||
input double KalmanPV = 1.0; // Process variance
|
||||
input double FuzzyThreshold = 0.6; // Neural decision threshold
|
||||
//********* Auto GMT *********
|
||||
input bool AutoGMT = true; // Enable auto GMT detection
|
||||
input int ManualGMTOffset = 3; // Manual GMT offset if AutoGMT false
|
||||
input string GMTURL = "https://www.worldtimeserver.com/current_time_in_UTC.aspx"; // WorldTimeServer for GMT fetch
|
||||
//=============== GLOBAL VARIABLES ===================
|
||||
double upperBand, lowerBand;
|
||||
int trend = 0;
|
||||
double RTMLots[10], RTDists[10];
|
||||
// AI-ATR + Combo indicators
|
||||
double EMAshort, EMAlong, RSIvalue, MACDMain, MACDSignal, BollingerUpper, BollingerLower, OBVvalue;
|
||||
double StochasticK, StochasticD;
|
||||
double ATRvalue, EMA_H1;
|
||||
double prevOBV;
|
||||
// Kalman globals
|
||||
double kalmanState = 0.0;
|
||||
double kalmanCovariance = 1.0;
|
||||
// Combo strengths for neural
|
||||
double combo1Strength = 0.0, combo2Strength = 0.0, combo3Strength = 0.0;
|
||||
// Neural outputs
|
||||
double fuzzyBuy = 0.0, fuzzySell = 0.0;
|
||||
// Tick analysis
|
||||
datetime lastTickTime = 0;
|
||||
double tickSpeed = 0.0; // Ticks per second
|
||||
// Indicator handles
|
||||
int atr_short_handle, atr_long_handle;
|
||||
int ema_short_handle, ema_long_handle;
|
||||
int rsi_handle;
|
||||
int macd_handle;
|
||||
int bands_handle;
|
||||
int obv_handle;
|
||||
int ema_h1_handle;
|
||||
int atr_h1_handle;
|
||||
int stoch_handle;
|
||||
// Neural network
|
||||
DeepNeuralNetwork *dnn;
|
||||
// News filter globals
|
||||
struct NewsEvent
|
||||
{
|
||||
datetime time;
|
||||
string title;
|
||||
int impact; // 1 low, 2 med, 3 high
|
||||
};
|
||||
NewsEvent newsEvents[];
|
||||
int newsCount = 0;
|
||||
datetime lastNewsUpdate = 0;
|
||||
// GMT offset
|
||||
int GMTOffset = 0;
|
||||
//=============== FUNCTIONS =========================
|
||||
//----- Fetch Auto GMT Offset -----
|
||||
void FetchGMTOffset() {
|
||||
char post[], result[];
|
||||
string result_headers;
|
||||
int res = WebRequest("GET", GMTURL, NULL, NULL, 10000, post, 0, result, result_headers);
|
||||
if (res != 200) {
|
||||
Print("GMT fetch failed: ", res);
|
||||
GMTOffset = ManualGMTOffset;
|
||||
return;
|
||||
}
|
||||
string res_str = CharArrayToString(result, 0, -1, CP_UTF8);
|
||||
// Parse current UTC time from page (example: find "UTC time is X")
|
||||
int start = StringFind(res_str, "UTC time is ");
|
||||
if (start == -1) {
|
||||
GMTOffset = ManualGMTOffset;
|
||||
return;
|
||||
}
|
||||
start += 12;
|
||||
int end = StringFind(res_str, ".", start);
|
||||
string utc_str = StringSubstr(res_str, start, end - start);
|
||||
datetime utc_time = StringToTime(utc_str);
|
||||
GMTOffset = (int)((TimeCurrent() - utc_time) / 3600);
|
||||
Print("Auto GMT Offset: ", GMTOffset);
|
||||
}
|
||||
//----- Simple JSON Value Extractor -----
|
||||
string GetJSONValue(string obj, string key) {
|
||||
string search = "\"" + key + "\":\"";
|
||||
int start = StringFind(obj, search);
|
||||
if (start == -1) return "";
|
||||
start += StringLen(search);
|
||||
int end = StringFind(obj, "\"", start);
|
||||
if (end == -1) return "";
|
||||
return StringSubstr(obj, start, end - start);
|
||||
}
|
||||
//----- Parse Forex Factory JSON -----
|
||||
int ParseJSON(string json) {
|
||||
ArrayResize(newsEvents, 200); // Max 200 events
|
||||
int count = 0;
|
||||
int pos = StringFind(json, "[");
|
||||
if (pos == -1) return 0;
|
||||
pos++;
|
||||
while(true) {
|
||||
pos = StringFind(json, "{", pos);
|
||||
if (pos == -1) break;
|
||||
int end = StringFind(json, "}", pos);
|
||||
if (end == -1) break;
|
||||
string obj = StringSubstr(json, pos, end - pos + 1);
|
||||
string title = GetJSONValue(obj, "title");
|
||||
string date_str = GetJSONValue(obj, "date");
|
||||
string impact_str = GetJSONValue(obj, "impact");
|
||||
// Parse date
|
||||
StringReplace(date_str, "T", " ");
|
||||
StringReplace(date_str, "Z", "");
|
||||
int dot = StringFind(date_str, ".");
|
||||
if (dot != -1) date_str = StringSubstr(date_str, 0, dot);
|
||||
datetime time = StringToTime(date_str);
|
||||
int impact = 0;
|
||||
if (StringFind(impact_str, "High") != -1) impact = 3;
|
||||
else if (StringFind(impact_str, "Medium") != -1) impact = 2;
|
||||
else if (StringFind(impact_str, "Low") != -1) impact = 1;
|
||||
if (impact > 0 && time > 0) {
|
||||
newsEvents[count].time = time;
|
||||
newsEvents[count].title = title;
|
||||
newsEvents[count].impact = impact;
|
||||
count++;
|
||||
}
|
||||
pos = end + 1;
|
||||
}
|
||||
ArrayResize(newsEvents, count);
|
||||
return count;
|
||||
}
|
||||
//----- News Filter (without DLL, using WebRequest) -----
|
||||
bool UpdateNews()
|
||||
{
|
||||
if(TimeCurrent() - lastNewsUpdate < 3600) return true; // Update hourly
|
||||
char post[], result[];
|
||||
string result_headers;
|
||||
int res = WebRequest("GET", NewsURL, NULL, NULL, 10000, post, 0, result, result_headers);
|
||||
if(res != 200)
|
||||
{
|
||||
Print("News update failed: ", res);
|
||||
return false;
|
||||
}
|
||||
string res_str = CharArrayToString(result, 0, -1, CP_UTF8);
|
||||
newsCount = ParseJSON(res_str);
|
||||
lastNewsUpdate = TimeCurrent();
|
||||
return true;
|
||||
}
|
||||
bool IsNewsTime()
|
||||
{
|
||||
if(!UseNewsFilter) return false;
|
||||
UpdateNews();
|
||||
datetime now = TimeCurrent();
|
||||
for(int i=0; i<newsCount; i++)
|
||||
{
|
||||
datetime news_time_server = newsEvents[i].time + GMTOffset * 3600; // Adjust GMT news to server time
|
||||
if(now >= news_time_server - NewsPauseBefore*60 && now <= news_time_server + NewsPauseAfter*60)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
//----- Helper to get indicator value -----
|
||||
double GetIndicatorValue(int handle, int buffer, int shift)
|
||||
{
|
||||
double val[1];
|
||||
if (CopyBuffer(handle, buffer, shift, 1, val) < 0) return 0.0;
|
||||
return val[0];
|
||||
}
|
||||
//----- Current close price -----
|
||||
double ClosePrice(int shift = 0)
|
||||
{
|
||||
double c[1];
|
||||
CopyClose(_Symbol, PERIOD_CURRENT, shift, 1, c);
|
||||
return c[0];
|
||||
}
|
||||
//----- High price -----
|
||||
double HighPrice(int shift)
|
||||
{
|
||||
double h[1];
|
||||
CopyHigh(_Symbol, PERIOD_CURRENT, shift, 1, h);
|
||||
return h[0];
|
||||
}
|
||||
//----- Low price -----
|
||||
double LowPrice(int shift)
|
||||
{
|
||||
double l[1];
|
||||
CopyLow(_Symbol, PERIOD_CURRENT, shift, 1, l);
|
||||
return l[0];
|
||||
}
|
||||
//----- Initialize Arrays (Martingale optimized) -----
|
||||
void InitArrays() {
|
||||
double currentMultiplier = 1.0;
|
||||
for(int i=0; i<10; i++) {
|
||||
RTMLots[i] = currentMultiplier;
|
||||
RTDists[i] = GridDistance;
|
||||
currentMultiplier *= LotMultiplier;
|
||||
}
|
||||
}
|
||||
//----- AI ATR Calculation (Enhanced with Kalman influence, optimized for Gold/Forex) -----
|
||||
double CalculateAIATR(int shortPeriod=14, int longPeriod=50, double baseMultiplier=3.0, double factor=2.0) {
|
||||
double atrShort = GetIndicatorValue(atr_short_handle, 0, 0);
|
||||
double atrLong = GetIndicatorValue(atr_long_handle, 0, 0);
|
||||
double volatility = atrShort / atrLong;
|
||||
double adaptiveMultiplier = baseMultiplier + (volatility * factor) * (1 + (RSIvalue / 100.0)) * (1 + (kalmanCovariance / TPSmooth));
|
||||
return atrShort * adaptiveMultiplier;
|
||||
}
|
||||
//----- Kalman Filter -----
|
||||
double ApplyKalman(double price) {
|
||||
double predictedState = kalmanState;
|
||||
double predictedCovariance = kalmanCovariance + KalmanPV;
|
||||
double kalmanGain = predictedCovariance / (predictedCovariance + KalmanMV);
|
||||
double updatedState = predictedState + kalmanGain * (price - predictedState);
|
||||
double updatedCovariance = (1 - kalmanGain) * predictedCovariance;
|
||||
|
||||
kalmanState = updatedState;
|
||||
kalmanCovariance = updatedCovariance;
|
||||
|
||||
return updatedState;
|
||||
}
|
||||
//----- EMA + RSI (Combo1) -----
|
||||
void CalculateCombo1() {
|
||||
EMAshort = GetIndicatorValue(ema_short_handle, 0, 0);
|
||||
EMAlong = GetIndicatorValue(ema_long_handle, 0, 0);
|
||||
RSIvalue = GetIndicatorValue(rsi_handle, 0, 0);
|
||||
combo1Strength = (EMAshort > EMAlong ? (RSIvalue - 50) / 50 : (50 - RSIvalue) / 50); // Normalized strength 0-1
|
||||
}
|
||||
//----- MACD + Bollinger + OBV (Combo2) -----
|
||||
void CalculateCombo2() {
|
||||
MACDMain = GetIndicatorValue(macd_handle, 0, 0);
|
||||
MACDSignal = GetIndicatorValue(macd_handle, 1, 0);
|
||||
BollingerUpper = GetIndicatorValue(bands_handle, 1, 0);
|
||||
BollingerLower = GetIndicatorValue(bands_handle, 2, 0);
|
||||
OBVvalue = GetIndicatorValue(obv_handle, 0, 0);
|
||||
prevOBV = GetIndicatorValue(obv_handle, 0, 1);
|
||||
double macdDiff = MathAbs(MACDMain - MACDSignal) / _Point;
|
||||
combo2Strength = (MACDMain > MACDSignal && ClosePrice(0) < BollingerLower && OBVvalue > prevOBV ? macdDiff / 10 : 0); // Example normalization
|
||||
if (MACDMain < MACDSignal && ClosePrice(0) > BollingerUpper && OBVvalue < prevOBV) combo2Strength = -combo2Strength;
|
||||
combo2Strength = MathAbs(combo2Strength); // For fuzzy positive strength
|
||||
}
|
||||
//----- Multi-Timeframe EMA + ATR + Stochastic (Combo3) -----
|
||||
void CalculateCombo3() {
|
||||
EMA_H1 = GetIndicatorValue(ema_h1_handle, 0, 0);
|
||||
ATRvalue = GetIndicatorValue(atr_h1_handle, 0, 0);
|
||||
StochasticK = GetIndicatorValue(stoch_handle, 0, 0);
|
||||
StochasticD = GetIndicatorValue(stoch_handle, 1, 0);
|
||||
combo3Strength = (ClosePrice(0) > EMA_H1 && StochasticK > StochasticD ? (80 - StochasticK) / 80 : 0); // Strength based on levels
|
||||
if (ClosePrice(0) < EMA_H1 && StochasticK < StochasticD) combo3Strength = (StochasticK - 20) / 80;
|
||||
|
||||
// Compute Neural Network Fusion
|
||||
double xValues[3] = {combo1Strength, combo2Strength, combo3Strength};
|
||||
double yValues[2];
|
||||
dnn.ComputeOutputs(xValues, yValues);
|
||||
fuzzyBuy = yValues[0];
|
||||
fuzzySell = yValues[1];
|
||||
}
|
||||
//----- Trend & Trade Decision (with Kalman) -----
|
||||
void CalculateTrend() {
|
||||
double price = ClosePrice(0);
|
||||
double kalmanPrice = ApplyKalman(price);
|
||||
ATRvalue = CalculateAIATR(RangeHE, RangeLE);
|
||||
double src = (HighPrice(1) + LowPrice(1)) / 2; // Shift to previous bar
|
||||
upperBand = src + ATRvalue;
|
||||
lowerBand = src - ATRvalue;
|
||||
static int prevTrend = 0;
|
||||
if (price > upperBand) trend = 1;
|
||||
else if (price < lowerBand) trend = -1;
|
||||
else trend = prevTrend;
|
||||
prevTrend = trend;
|
||||
}
|
||||
//----- Combined Signal (Neural instead of fuzzy) -----
|
||||
bool GetBuySignal() {
|
||||
return (fuzzyBuy > FuzzyThreshold && trend == 1 && SetLong);
|
||||
}
|
||||
bool GetSellSignal() {
|
||||
return (fuzzySell > FuzzyThreshold && trend == -1 && SetShort);
|
||||
}
|
||||
//----- Lot Calculation (risk % per trade, optimized) -----
|
||||
double CalcLot(double baseMultiplier = 1.0) {
|
||||
if (!AutoLot) return FixedLot * baseMultiplier;
|
||||
double balance = AccountInfoDouble(ACCOUNT_BALANCE);
|
||||
double riskMoney = balance * TradingRisk / 100.0;
|
||||
double stopPips = UseATRSLL ? (ATRvalue / _Point * ATRSLMultiplier) : BasicSL;
|
||||
if (stopPips <= 0) stopPips = 20.0;
|
||||
double tickValue = SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_VALUE);
|
||||
double lot = NormalizeDouble(riskMoney / (stopPips * tickValue), 2);
|
||||
lot *= baseMultiplier;
|
||||
if (lot < MinLot) lot = MinLot;
|
||||
if (lot > MaxLot) lot = MaxLot;
|
||||
return lot;
|
||||
}
|
||||
//----- Spread Check -----
|
||||
bool IsSpreadOk(double spread) {
|
||||
if (spread > MaxSpread) return false;
|
||||
return true;
|
||||
}
|
||||
//----- Time Filter -----
|
||||
bool IsTradingTime() {
|
||||
datetime now = TimeCurrent();
|
||||
MqlDateTime tm;
|
||||
TimeToStruct(now, tm);
|
||||
int hour = tm.hour;
|
||||
int minute = tm.min;
|
||||
int day = tm.day_of_week;
|
||||
if (day == 1) {
|
||||
if (hour < MondayStartHour || (hour == MondayStartHour && minute < MondayStartMinute)) return false;
|
||||
} else {
|
||||
if (hour < StartHour || (hour == StartHour && minute < StartMinute)) return false;
|
||||
}
|
||||
if (hour > StopHour || (hour == StopHour && minute > StopMinute)) return false;
|
||||
if (day == 5) {
|
||||
if (hour > FridayStopHour || (hour == FridayStopHour && minute > FridayStopMinute)) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
//----- Day Filter -----
|
||||
bool IsTradingDay() {
|
||||
MqlDateTime tm;
|
||||
TimeToStruct(TimeCurrent(), tm);
|
||||
int day = tm.day_of_week;
|
||||
switch (day) {
|
||||
case 1: return TradeMonday;
|
||||
case 2: return TradeTuesday;
|
||||
case 3: return TradeWednesday;
|
||||
case 4: return TradeThursday;
|
||||
case 5: return TradeFriday;
|
||||
default: return false;
|
||||
}
|
||||
}
|
||||
//----- DD Control -----
|
||||
bool IsDDOk() {
|
||||
double dd = (AccountInfoDouble(ACCOUNT_EQUITY) / AccountInfoDouble(ACCOUNT_BALANCE)) * 100.0;
|
||||
return (dd > (100.0 - MaxDDControl));
|
||||
}
|
||||
//----- Swap Control -----
|
||||
bool IsSwapOk(int type) {
|
||||
double swap = SymbolInfoDouble(_Symbol, (type == (int)ORDER_TYPE_BUY ? SYMBOL_SWAP_LONG : SYMBOL_SWAP_SHORT));
|
||||
if (NSwapControl && swap < 0) return false;
|
||||
if (PSwapControl && swap <= 0) return false;
|
||||
return true;
|
||||
}
|
||||
//----- Count Orders -----
|
||||
int CountOrders(int dir) { // 1 buy, -1 sell
|
||||
int count = 0;
|
||||
for (int i = 0; i < PositionsTotal(); i++) {
|
||||
ulong ticket = PositionGetTicket(i);
|
||||
if (ticket > 0) {
|
||||
if (PositionGetString(POSITION_SYMBOL) == _Symbol && PositionGetInteger(POSITION_MAGIC) == Magic &&
|
||||
((dir == 1 && PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY) || (dir == -1 && PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_SELL))) count++;
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
//----- Last Open Price -----
|
||||
double GetLastOpenPrice(int dir) {
|
||||
double price = 0;
|
||||
datetime latest = 0;
|
||||
for (int i = 0; i < PositionsTotal(); i++) {
|
||||
ulong ticket = PositionGetTicket(i);
|
||||
if (ticket > 0) {
|
||||
if (PositionGetString(POSITION_SYMBOL) == _Symbol && PositionGetInteger(POSITION_MAGIC) == Magic &&
|
||||
((dir == 1 && PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY) || (dir == -1 && PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_SELL))) {
|
||||
datetime openTime = (datetime)PositionGetInteger(POSITION_TIME);
|
||||
if (openTime > latest) {
|
||||
latest = openTime;
|
||||
price = PositionGetDouble(POSITION_PRICE_OPEN);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return price;
|
||||
}
|
||||
//----- Grid Level -----
|
||||
int GetGridLevel(int dir) {
|
||||
return CountOrders(dir);
|
||||
}
|
||||
//----- Open Trade -----
|
||||
bool OpenTrade(int type, double lotMultiplier = 1.0, double ask = 0, double bid = 0) {
|
||||
double spread = (ask - bid) / _Point;
|
||||
if (!IsSpreadOk(spread) || !IsTradingTime() || !IsTradingDay() || IsNewsTime() || !IsDDOk() || GetGridLevel(type == (int)ORDER_TYPE_BUY ? 1 : -1) >= MaxGridLevels || PositionsTotal() >= MaxOrderCount) return false;
|
||||
if (!IsSwapOk(type)) return false;
|
||||
double lot = CalcLot(lotMultiplier);
|
||||
double price = (type == (int)ORDER_TYPE_BUY ? ask : bid);
|
||||
double sl = 0, tp = 0;
|
||||
double atrSL = ATRvalue * ATRSLMultiplier;
|
||||
sl = NormalizeDouble((type == (int)ORDER_TYPE_BUY ? price - atrSL : price + atrSL), _Digits);
|
||||
if (!UseATRSLL) sl = NormalizeDouble((type == (int)ORDER_TYPE_BUY ? price - BasicSL * _Point : price + BasicSL * _Point), _Digits);
|
||||
tp = NormalizeDouble((type == (int)ORDER_TYPE_BUY ? price + TakeProfit * _Point : price - TakeProfit * _Point), _Digits);
|
||||
MqlTradeRequest request = {};
|
||||
MqlTradeResult result = {};
|
||||
request.action = TRADE_ACTION_DEAL;
|
||||
request.symbol = _Symbol;
|
||||
request.volume = lot;
|
||||
request.type = (ENUM_ORDER_TYPE)type;
|
||||
request.price = price;
|
||||
request.sl = sl;
|
||||
request.tp = tp;
|
||||
request.deviation = 3;
|
||||
request.magic = Magic;
|
||||
request.comment = TradeComment;
|
||||
if (!OrderSend(request, result)) {
|
||||
Print("OrderSend failed: ", result.retcode);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
//----- Manage Trades (Optimized Breakeven & Step Trailing) -----
|
||||
void ManageTrades(double bid = 0, double ask = 0) {
|
||||
for (int i = PositionsTotal() - 1; i >= 0; i--) {
|
||||
ulong ticket = PositionGetTicket(i);
|
||||
if (ticket == 0) continue;
|
||||
if (PositionGetString(POSITION_SYMBOL) != _Symbol || PositionGetInteger(POSITION_MAGIC) != Magic) continue;
|
||||
ENUM_POSITION_TYPE type = (ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);
|
||||
if (type != POSITION_TYPE_BUY && type != POSITION_TYPE_SELL) continue;
|
||||
double openPrice = PositionGetDouble(POSITION_PRICE_OPEN);
|
||||
double profitPips = (type == POSITION_TYPE_BUY ? (bid - openPrice) / _Point : (openPrice - ask) / _Point);
|
||||
double currentSL = PositionGetDouble(POSITION_SL);
|
||||
// Breakeven Logic
|
||||
if (UseBreakeven && profitPips >= BreakevenStart) {
|
||||
double beSL = NormalizeDouble(openPrice + (type == POSITION_TYPE_BUY ? BreakevenLock * _Point : -BreakevenLock * _Point), _Digits);
|
||||
if ((type == POSITION_TYPE_BUY && (currentSL < beSL || currentSL == 0)) || (type == POSITION_TYPE_SELL && (currentSL > beSL || currentSL == 0))) {
|
||||
MqlTradeRequest request = {};
|
||||
MqlTradeResult result = {};
|
||||
request.action = TRADE_ACTION_SLTP;
|
||||
request.position = ticket;
|
||||
request.sl = beSL;
|
||||
request.tp = PositionGetDouble(POSITION_TP);
|
||||
if (!OrderSend(request, result)) {
|
||||
Print("Breakeven modify failed: ", result.retcode);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Step Trailing Stop
|
||||
if (UseTrailing && profitPips >= TrailStart) {
|
||||
double trailOffset = TrailDistance * _Point;
|
||||
double newSL = NormalizeDouble((type == POSITION_TYPE_BUY ? bid - trailOffset : ask + trailOffset), _Digits);
|
||||
double slDiff = (type == POSITION_TYPE_BUY ? (newSL - currentSL) / _Point : (currentSL - newSL) / _Point);
|
||||
if (slDiff >= TrailStep) {
|
||||
MqlTradeRequest request = {};
|
||||
MqlTradeResult result = {};
|
||||
request.action = TRADE_ACTION_SLTP;
|
||||
request.position = ticket;
|
||||
request.sl = newSL;
|
||||
request.tp = PositionGetDouble(POSITION_TP);
|
||||
if (!OrderSend(request, result)) {
|
||||
Print("Trailing modify failed: ", result.retcode);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Multi-Stage Partial Close
|
||||
if (TPLevels > 0 && profitPips >= TPInitLevel) {
|
||||
double levelStep = (TakeProfit - TPInitLevel) / TPLevels;
|
||||
for (int level = 1; level <= TPLevels; level++) {
|
||||
double targetPips = TPInitLevel + level * levelStep;
|
||||
if (profitPips >= targetPips && PositionGetDouble(POSITION_VOLUME) > 0) {
|
||||
double closeLot = PositionGetDouble(POSITION_VOLUME) * (LotPercent / 100.0);
|
||||
double minLot = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MIN);
|
||||
if (closeLot < minLot) closeLot = PositionGetDouble(POSITION_VOLUME);
|
||||
MqlTradeRequest request = {};
|
||||
MqlTradeResult result = {};
|
||||
request.action = TRADE_ACTION_DEAL;
|
||||
request.position = ticket;
|
||||
request.symbol = _Symbol;
|
||||
request.volume = closeLot;
|
||||
request.type = (type == POSITION_TYPE_BUY ? ORDER_TYPE_SELL : ORDER_TYPE_BUY);
|
||||
request.price = (type == POSITION_TYPE_BUY ? bid : ask);
|
||||
request.deviation = 3;
|
||||
if (!OrderSend(request, result)) {
|
||||
Print("Partial close failed: ", result.retcode);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
//----- Draw Profit Line -----
|
||||
void DrawProfitLine() {
|
||||
if (DrawProfit && ProfitValue > 0) {
|
||||
ObjectCreate(0, "ProfitLine", OBJ_HLINE, 0, 0, ProfitValue);
|
||||
ObjectSetInteger(0, "ProfitLine", OBJPROP_COLOR, clrGreen);
|
||||
}
|
||||
}
|
||||
//----- Show Info Panel -----
|
||||
void ShowPanel() {
|
||||
if (!ShowInfoPanel) return;
|
||||
string info = "TOL LANGIT ETF - AI EA\n";
|
||||
info += "Balance: " + DoubleToString(AccountInfoDouble(ACCOUNT_BALANCE), 2) + "\n";
|
||||
info += "Equity: " + DoubleToString(AccountInfoDouble(ACCOUNT_EQUITY), 2) + "\n";
|
||||
info += "Open Orders: " + IntegerToString(PositionsTotal()) + "\n";
|
||||
info += "Trend: " + (trend == 1 ? "Up" : (trend == -1 ? "Down" : "Flat")) + "\n";
|
||||
info += "Kalman State: " + DoubleToString(kalmanState, _Digits);
|
||||
info += "\nGMT Offset: " + IntegerToString(GMTOffset);
|
||||
Comment(info);
|
||||
}
|
||||
//----- Tick Speed Calculation -----
|
||||
void UpdateTickSpeed() {
|
||||
datetime now = TimeCurrent();
|
||||
if (lastTickTime > 0) {
|
||||
double timeDiff = (now - lastTickTime) * 1.0;
|
||||
if (timeDiff > 0) tickSpeed = 1.0 / timeDiff; // Ticks per second approx
|
||||
}
|
||||
lastTickTime = now;
|
||||
}
|
||||
//================ MAIN LOOP ==========================
|
||||
int OnInit() {
|
||||
Print("TOL LANGIT ETF AI EA Initialized for Forex/Gold");
|
||||
InitArrays();
|
||||
kalmanState = ClosePrice(0); // Init Kalman
|
||||
// Auto GMT
|
||||
if (AutoGMT) {
|
||||
FetchGMTOffset();
|
||||
} else {
|
||||
GMTOffset = ManualGMTOffset;
|
||||
Print("Manual GMT Offset: ", GMTOffset);
|
||||
}
|
||||
// Initialize indicator handles
|
||||
atr_short_handle = iATR(_Symbol, PERIOD_CURRENT, RangeHE);
|
||||
atr_long_handle = iATR(_Symbol, PERIOD_CURRENT, RangeLE);
|
||||
ema_short_handle = iMA(_Symbol, PERIOD_CURRENT, 14, 0, MODE_EMA, PRICE_CLOSE);
|
||||
ema_long_handle = iMA(_Symbol, PERIOD_CURRENT, 50, 0, MODE_EMA, PRICE_CLOSE);
|
||||
rsi_handle = iRSI(_Symbol, PERIOD_CURRENT, 14, PRICE_CLOSE);
|
||||
macd_handle = iMACD(_Symbol, PERIOD_CURRENT, 12, 26, 9, PRICE_CLOSE);
|
||||
bands_handle = iBands(_Symbol, PERIOD_CURRENT, 20, 2, 0, PRICE_CLOSE);
|
||||
obv_handle = iOBV(_Symbol, PERIOD_CURRENT, VOLUME_TICK);
|
||||
ema_h1_handle = iMA(_Symbol, PERIOD_H1, 50, 0, MODE_EMA, PRICE_CLOSE);
|
||||
atr_h1_handle = iATR(_Symbol, PERIOD_H1, 14);
|
||||
stoch_handle = iStochastic(_Symbol, PERIOD_CURRENT, 5, 3, 3, MODE_SMA, 0);
|
||||
// Initialize neural network
|
||||
dnn = new DeepNeuralNetwork(3, 4, 4, 2);
|
||||
double weights[46] = {
|
||||
0.1, -0.2, 0.3, 0.4, // iaWeights row1
|
||||
-0.5, 0.6, -0.7, 0.8, // row2
|
||||
0.9, -1.0, 1.1, -1.2, // row3
|
||||
0.5, -0.5, 0.5, -0.5, // aBiases
|
||||
1.0, 0.9, 0.8, 0.7, // abWeights row1
|
||||
0.6, 0.5, 0.4, 0.3, // row2
|
||||
0.2, 0.1, -0.1, -0.2, // row3
|
||||
-0.3, -0.4, -0.5, -0.6, // row4
|
||||
0.4, -0.4, 0.4, -0.4, // bBiases
|
||||
1.2, -1.2, // boWeights row1
|
||||
1.1, -1.1, // row2
|
||||
1.0, -1.0, // row3
|
||||
0.9, -0.9, // row4
|
||||
0.3, -0.3 // oBiases
|
||||
};
|
||||
dnn.SetWeights(weights);
|
||||
DrawProfitLine();
|
||||
return(INIT_SUCCEEDED);
|
||||
}
|
||||
void OnDeinit(const int reason) {
|
||||
delete dnn;
|
||||
ObjectDelete(0, "ProfitLine");
|
||||
Comment("");
|
||||
}
|
||||
void OnTick() {
|
||||
MqlTick tick;
|
||||
if (!SymbolInfoTick(_Symbol, tick)) return;
|
||||
double ask = tick.ask;
|
||||
double bid = tick.bid;
|
||||
double spread = (ask - bid) / _Point;
|
||||
UpdateTickSpeed(); // Tick analysis
|
||||
if (tickSpeed < 0.1) return; // Skip if slow ticks (self-opt)
|
||||
CalculateCombo1();
|
||||
CalculateCombo2();
|
||||
CalculateCombo3();
|
||||
CalculateTrend();
|
||||
ManageTrades(bid, ask);
|
||||
ShowPanel();
|
||||
if (!SingleSymbol) return;
|
||||
bool buySignal = GetBuySignal();
|
||||
bool sellSignal = GetSellSignal();
|
||||
// Buy Grid/Martingale
|
||||
if (buySignal) {
|
||||
int gridLevel = GetGridLevel(1);
|
||||
if (gridLevel < MaxGridLevels) {
|
||||
double lastPrice = GetLastOpenPrice(1);
|
||||
double dist = (lastPrice > 0 ? (lastPrice - bid) / _Point : 0);
|
||||
if (gridLevel == 0 || dist >= RTDists[gridLevel - 1]) {
|
||||
OpenTrade((int)ORDER_TYPE_BUY, RTMLots[gridLevel], ask, bid);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Sell Grid/Martingale
|
||||
if (sellSignal) {
|
||||
int gridLevel = GetGridLevel(-1);
|
||||
if (gridLevel < MaxGridLevels) {
|
||||
double lastPrice = GetLastOpenPrice(-1);
|
||||
double dist = (lastPrice > 0 ? (ask - lastPrice) / _Point : 0);
|
||||
if (gridLevel == 0 || dist >= RTDists[gridLevel - 1]) {
|
||||
OpenTrade((int)ORDER_TYPE_SELL, RTMLots[gridLevel], ask, bid);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user