Files
EA/OI EA/OI_MeanReversion_Pro_XAUUSD.mq5
Kunthawat Greethong 39ce46877e Add files
2026-01-12 09:14:10 +07:00

2290 lines
80 KiB
Plaintext

//+------------------------------------------------------------------+
//| OI_MeanReversion_Pro_XAUUSD_V2.mq5 |
//| Professional OI Mean Reversion System |
//| Version 2.0 |
//+------------------------------------------------------------------+
#property copyright "Professional OI Mean Reversion System"
#property link ""
#property version "2.00"
#property description "Advanced Mean Reversion with OI Levels & Multi-Timeframe Filtering"
#property strict
//--- Includes
#include <Trade\Trade.mqh>
#include <Trade\AccountInfo.mqh>
#include <Trade\SymbolInfo.mqh>
#include <Trade\PositionInfo.mqh>
#include <Trade\OrderInfo.mqh>
#include <Trade\HistoryOrderInfo.mqh>
#include <Arrays\ArrayObj.mqh>
#include <Arrays\ArrayDouble.mqh>
//--- Market Phase Enum (Moved to global scope)
enum ENUM_MARKET_PHASE
{
PHASE_BULLISH,
PHASE_BEARISH,
PHASE_SIDEWAYS,
PHASE_NEUTRAL
};
//--- Input Parameters (จัดกลุ่มตามสเปก)
// Group A: OI & Delta Configuration
input group "=== OI & DELTA SETTINGS ==="
enum ENUM_OI_SOURCE {
OI_SOURCE_MANUAL, // Manual Input
OI_SOURCE_CSV_FILE, // CSV File
OI_SOURCE_AUTO_SYNC // Auto Sync (Future)
};
input ENUM_OI_SOURCE InpOISource = OI_SOURCE_CSV_FILE;
input string InpOICsvPath = "oi_data.csv"; // Path to CSV file
input int InpCSVReloadInterval = 60; // CSV reload interval (minutes, 0=disabled)
input double InpManualFuturePrice = 0.0; // Manual future price input
// OI Levels (Manual Input - สามารถใส่ได้ถึง 3 ระดับ)
input double InpCallStrike1 = 0.0;
input double InpCallStrike2 = 0.0;
input double InpCallStrike3 = 0.0;
input double InpPutStrike1 = 0.0;
input double InpPutStrike2 = 0.0;
input double InpPutStrike3 = 0.0;
// Delta Calculation
input int InpDeltaEmaPeriod = 20; // EMA period for Delta average
input double InpDeviationThreshold = 20.0; // Deviation threshold in points
input double InpDeviationMultiplier = 1.5; // Deviation multiplier for entry
// Group B: Trading Configuration
input group "=== TRADING SETTINGS ==="
input double InpLotSize = 0.1; // Fixed lot size
input bool InpUseMoneyManagement = true; // Use money management
input double InpRiskPercent = 1.0; // Risk per trade (%)
input bool InpUseStopLoss = true; // Use stop loss
input bool InpUseTakeProfit = true; // Use take profit
input int InpStopLossPoints = 300; // SL in points
input int InpTakeProfitPoints = 500; // TP in points
input int InpMaxSpread = 200; // Max spread in points
input int InpMaxSlippage = 10; // Max slippage in points
input int InpMagicNumber = 202412; // Magic number
input bool InpCloseOnZeroDeviation = true; // Close when deviation crosses zero
// Group C: Market Filters
input group "=== MARKET FILTERS ==="
input bool InpUseMarketPhaseFilter = true; // Filter by market phase
input ENUM_TIMEFRAMES InpTrendTF = PERIOD_H4; // Trend timeframe
input int InpTrendMAPeriod1 = 50; // Fast MA period
input int InpTrendMAPeriod2 = 200; // Slow MA period
input bool InpUseATRFilter = true; // Use ATR volatility filter
input double InpMaxATRPercent = 2.0; // Max ATR% for trading
input bool InpUseSessionFilter = true; // Filter by trading session
input int InpSessionStartHour = 8; // Session start (GMT)
input int InpSessionEndHour = 22; // Session end (GMT)
input bool InpAvoidHighImpactNews = true; // Avoid high impact news
// Group D: Risk Management
input group "=== RISK MANAGEMENT ==="
input double InpMaxDailyLossPercent = 3.0; // Max daily loss %
input double InpMaxDailyProfitPercent = 5.0; // Max daily profit %
input int InpMaxConsecutiveLosses = 3; // Max consecutive losses
input bool InpDisableAfterMaxLoss = true; // Disable after max loss
input double InpEquityProtectionPercent = 10.0; // Equity protection %
input bool InpCloseAllOnReverse = false; // Close all on market reversal
input int InpMaxDailyTrades = 10; // Maximum trades per day
// Group E: Advanced Features
input group "=== ADVANCED FEATURES ==="
input bool InpUseTrailingStop = false; // Use trailing stop
input int InpTrailingStartPoints = 150; // Trailing start in points
input int InpTrailingStepPoints = 50; // Trailing step in points
input bool InpUseSoftStopLoss = true; // Use soft stop loss (close manually)
input bool InpUseAutoRecovery = true; // Auto recover after restart
input bool InpEnableDashboard = true; // Enable dashboard display
//--- Global Objects
CTrade Trade;
CSymbolInfo SymbolInfo;
CAccountInfo AccountInfo;
CPositionInfo PositionInfo;
COrderInfo OrderInfo;
CHistoryOrderInfo HistoryOrderInfo;
//--- Global Variables
double DeltaPrice = 0.0;
double DeltaEMA = 0.0;
double DeltaDeviation = 0.0;
double FuturePrice = 0.0;
double SpotPrice = 0.0;
// OI Levels Arrays
double CallLevels[3];
double PutLevels[3];
int CallOI[3];
int PutOI[3];
// Dynamic OI Data Variables (modifiable)
double DynamicFuturePrice = 0.0;
double DynamicCallStrike1 = 0.0;
double DynamicCallStrike2 = 0.0;
double DynamicCallStrike3 = 0.0;
double DynamicPutStrike1 = 0.0;
double DynamicPutStrike2 = 0.0;
double DynamicPutStrike3 = 0.0;
// Key Levels from Dashboard
double LevelUpper1 = 0.0;
double LevelUpper2 = 0.0;
double LevelMid = 0.0;
double LevelLower1 = 0.0;
double LevelLower2 = 0.0;
// Trading Statistics
int DailyTradeCount = 0;
double DailyPnL = 0.0;
double DailyProfit = 0.0;
double DailyLoss = 0.0;
int ConsecutiveLosses = 0;
datetime LastTradeTime = 0;
datetime LastResetDate = 0;
// Risk Management
bool TradingEnabled = true;
double EquityHigh = 0.0;
double EquityLow = 0.0;
// Indicator Handles
int ATRHandle = INVALID_HANDLE;
int MAFastHandle = INVALID_HANDLE;
int MASlowHandle = INVALID_HANDLE;
int RSIMainHandle = INVALID_HANDLE;
// Dashboard
long chart_id = 0; // Chart window ID
int DashboardSubWindow = -1;
color PanelColor = C'30,30,30';
color TextColor = clrWhite;
color ProfitColor = clrLime;
color LossColor = clrRed;
color WarningColor = clrOrange;
// News Filter
bool NewsBlockActive = false;
datetime NewsBlockStart = 0;
datetime NewsBlockEnd = 0;
// CSV Cache Variables
double CachedFuturePrice = -1;
string LoadedCSVPath = "";
bool CSVLoadLogged = false;
datetime LastCSVReloadTime = 0;
//=== NEW: Control Panel Variables ===
// Control Panel Position - Moved below dashboard
int ControlPanelX = 10;
int ControlPanelY = 210;
// Input Values for Control Panel
double PendingPriceValue = 0.0;
double ManualLotSize = 0.5;
int ManualSLPoints = 0;
int ManualTPPoints = 300;
// OI Data Input Values
double ManualFuturePriceValue = 0.0;
double CallStrike1Value = 0.0;
double CallStrike2Value = 0.0;
double CallStrike3Value = 0.0;
double PutStrike1Value = 0.0;
double PutStrike2Value = 0.0;
double PutStrike3Value = 0.0;
// Control Panel Object Names
string ControlPanelObjects[] = {
// Top Panel Objects
"CP_TopPanel",
"CP_CloseAll",
// OI Data Panel Objects
"CP_OIDataPanel",
"CP_FuturePrice",
"CP_CallStrike1",
"CP_CallStrike2",
"CP_CallStrike3",
"CP_PutStrike1",
"CP_PutStrike2",
"CP_PutStrike3",
"CP_UpdateOI",
// Trading Panel Objects
"CP_TradingPanel",
"CP_PendingPrice",
"CP_LotSize",
"CP_SLPoints",
"CP_TPPoints",
"CP_Sell",
"CP_Buy",
"CP_PendingSell",
"CP_PendingBuy",
"CP_CloseAllPending",
"CP_CloseSell",
"CP_CloseBuy"
};
//--- Global Variables for Line Management
string DrawnLines[]; // Array to store drawn line names
int MaxLines = 10;
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
//--- Initialize trading objects
Trade.SetExpertMagicNumber(InpMagicNumber);
Trade.SetDeviationInPoints(InpMaxSlippage);
Trade.SetTypeFilling(ORDER_FILLING_IOC);
//--- Initialize symbol info
SymbolInfo.Name(_Symbol);
SymbolInfo.RefreshRates();
//--- Initialize Dynamic OI Variables with input parameters
DynamicFuturePrice = InpManualFuturePrice;
DynamicCallStrike1 = InpCallStrike1;
DynamicCallStrike2 = InpCallStrike2;
DynamicCallStrike3 = InpCallStrike3;
DynamicPutStrike1 = InpPutStrike1;
DynamicPutStrike2 = InpPutStrike2;
DynamicPutStrike3 = InpPutStrike3;
//--- Initialize OI Levels
InitializeOILevels();
//--- Initialize Key Levels
InitializeKeyLevels();
//--- Initialize indicators
if(!InitializeIndicators())
{
Print("Error initializing indicators");
return INIT_FAILED;
}
//--- Initialize risk management
EquityHigh = AccountInfo.Equity();
EquityLow = AccountInfo.Equity();
//--- Initialize dashboard
if(InpEnableDashboard)
{
chart_id = ChartID(); // Get current chart ID
CreateDashboard();
CreateControlPanel(); // Create new control panel
}
//--- Auto-recovery: Check for existing positions
if(InpUseAutoRecovery)
{
CheckExistingPositions();
}
//--- Set timer for updates (every 1 second)
EventSetTimer(1);
//--- Initialize lines array
ArrayResize(DrawnLines, MaxLines);
for(int i = 0; i < MaxLines; i++)
{
DrawnLines[i] = "";
}
Print("EA Initialized Successfully");
Print("Symbol: ", _Symbol);
Print("Account Balance: ", AccountInfo.Balance());
Print("Trading Enabled: ", TradingEnabled);
return INIT_SUCCEEDED;
}
//+------------------------------------------------------------------+
//| Expert deinitialization function |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
//--- Clean up dashboard and control panel
if(InpEnableDashboard)
{
ObjectsDeleteAll(chart_id, 0, -1);
}
//--- Release indicator handles
if(ATRHandle != INVALID_HANDLE) IndicatorRelease(ATRHandle);
if(MAFastHandle != INVALID_HANDLE) IndicatorRelease(MAFastHandle);
if(MASlowHandle != INVALID_HANDLE) IndicatorRelease(MASlowHandle);
if(RSIMainHandle != INVALID_HANDLE) IndicatorRelease(RSIMainHandle);
//--- Kill timer
EventKillTimer();
Print("EA Deinitialized");
}
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick()
{
//--- Skip if not enough bars
if(Bars(_Symbol, _Period) < 100)
return;
//--- Update market data
if(!UpdateMarketData())
return;
//--- Check global conditions
if(!CheckGlobalConditions())
return;
//--- Check for trade signals
CheckTradingSignals();
//--- Manage existing positions
ManagePositions();
//--- Update dashboard and control panel
if(InpEnableDashboard)
{
UpdateDashboard();
UpdateControlPanel();
}
}
//+------------------------------------------------------------------+
//| Timer function |
//+------------------------------------------------------------------+
void OnTimer()
{
//--- Update dashboard periodically
if(InpEnableDashboard)
{
UpdateDashboard();
UpdateControlPanel();
}
//--- Check news events
if(InpAvoidHighImpactNews)
{
CheckNewsEvents();
}
//--- Reset daily statistics if new day
CheckDailyReset();
//--- CSV reload check
if(InpOISource == OI_SOURCE_CSV_FILE && InpCSVReloadInterval > 0) {
if(TimeCurrent() - LastCSVReloadTime >= InpCSVReloadInterval * 60) {
Print("CSV Reload: Scheduled reload triggered");
LastCSVReloadTime = TimeCurrent();
CachedFuturePrice = -1;
LoadOIFromCSV();
}
}
}
//+------------------------------------------------------------------+
//| Chart Event Handler |
//+------------------------------------------------------------------+
void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam)
{
//--- Handle control panel button clicks
if(id == CHARTEVENT_OBJECT_CLICK)
{
HandleControlPanelClick(sparam);
}
//--- Handle edit field changes (สำหรับรับค่าจาก Input Fields)
if(id == CHARTEVENT_OBJECT_ENDEDIT)
{
// อัพเดทค่าทันทีเมื่อมีการแก้ไขข้อมูลใน Edit Fields
UpdateInputValues();
Print("Edit field updated: ", sparam, " Value: ", ObjectGetString(chart_id, sparam, OBJPROP_TEXT));
}
}
//+------------------------------------------------------------------+
//| Create Control Panel |
//+------------------------------------------------------------------+
void CreateControlPanel()
{
//--- Create top control panel
CreateControlPanelUI();
//--- Set initial values
UpdateControlPanelValues();
}
//+------------------------------------------------------------------+
//| Create Control Panel UI |
//+------------------------------------------------------------------+
void CreateControlPanelUI()
{
int panelWidth = 850; // Match dashboard width
int topPanelHeight = 50;
int oiPanelHeight = 120;
int tradingPanelHeight = 180;
//--- Top Panel (Quick Tools)
CreatePanel("CP_TopPanel", ControlPanelX, ControlPanelY, panelWidth, topPanelHeight, C'45,45,45', BORDER_FLAT);
//--- Close All Button
CreateButton("CP_CloseAll", ControlPanelX + 10, ControlPanelY + 10, 830, 30, "Close All Positions", clrRed, clrWhite);
//--- OI Data Panel (New Section)
CreatePanel("CP_OIDataPanel", ControlPanelX, ControlPanelY + topPanelHeight + 10, panelWidth, oiPanelHeight, C'45,45,45', BORDER_FLAT);
//--- OI Data Labels Row 1 - ปรับจัดเรียงให้เป็น Grid Layout
CreateLabel("CP_FuturePriceLabel", ControlPanelX + 10, ControlPanelY + topPanelHeight + 20, "Future Price:", clrYellow, 8);
CreateLabel("CP_CallStrikesLabel", ControlPanelX + 200, ControlPanelY + topPanelHeight + 20, "Call Strikes:", clrYellow, 8);
CreateLabel("CP_PutStrikesLabel", ControlPanelX + 200, ControlPanelY + topPanelHeight + 50, "Put Strikes:", clrYellow, 8);
//--- OI Data Fields Row 1 - จัดเรียงแบบ Grid
CreateEditField("CP_FuturePrice", ControlPanelX + 90, ControlPanelY + topPanelHeight + 15, 80, 20, "0", clrWhite, clrBlack);
CreateEditField("CP_CallStrike1", ControlPanelX + 280, ControlPanelY + topPanelHeight + 15, 80, 20, "0", clrWhite, clrBlack);
CreateEditField("CP_CallStrike2", ControlPanelX + 370, ControlPanelY + topPanelHeight + 15, 80, 20, "0", clrWhite, clrBlack);
CreateEditField("CP_CallStrike3", ControlPanelX + 460, ControlPanelY + topPanelHeight + 15, 80, 20, "0", clrWhite, clrBlack);
//--- OI Data Fields Row 2 - จัดเรียงให้เสมอกันกับ Call Strikes
CreateEditField("CP_PutStrike1", ControlPanelX + 280, ControlPanelY + topPanelHeight + 45, 80, 20, "0", clrWhite, clrBlack);
CreateEditField("CP_PutStrike2", ControlPanelX + 370, ControlPanelY + topPanelHeight + 45, 80, 20, "0", clrWhite, clrBlack);
CreateEditField("CP_PutStrike3", ControlPanelX + 460, ControlPanelY + topPanelHeight + 45, 80, 20, "0", clrWhite, clrBlack);
//--- Update OI Button
CreateButton("CP_UpdateOI", ControlPanelX + 750, ControlPanelY + topPanelHeight + 25, 90, 35, "Update OI Data", clrCyan, clrBlack);
//--- Trading Panel (Main Trading Controls)
CreatePanel("CP_TradingPanel", ControlPanelX, ControlPanelY + topPanelHeight + oiPanelHeight + 20, panelWidth, tradingPanelHeight, C'45,45,45', BORDER_FLAT);
//--- Trading Input Fields Labels
CreateLabel("CP_PendingPriceLabel", ControlPanelX + 10, ControlPanelY + topPanelHeight + oiPanelHeight + 35, "Price:", clrYellow, 8);
CreateLabel("CP_LotSizeLabel", ControlPanelX + 10, ControlPanelY + topPanelHeight + oiPanelHeight + 60, "Lot Size:", clrYellow, 8);
CreateLabel("CP_SLPointsLabel", ControlPanelX + 10, ControlPanelY + topPanelHeight + oiPanelHeight + 85, "SL (Point):", clrYellow, 8);
CreateLabel("CP_TPPointsLabel", ControlPanelX + 10, ControlPanelY + topPanelHeight + oiPanelHeight + 110, "TP (Point):", clrYellow, 8);
//--- Trading Input Fields
CreateEditField("CP_PendingPrice", ControlPanelX + 80, ControlPanelY + topPanelHeight + oiPanelHeight + 30, 80, 20, "0", clrWhite, clrBlack);
CreateEditField("CP_LotSize", ControlPanelX + 80, ControlPanelY + topPanelHeight + oiPanelHeight + 55, 80, 20, "0.5", clrWhite, clrBlack);
CreateEditField("CP_SLPoints", ControlPanelX + 80, ControlPanelY + topPanelHeight + oiPanelHeight + 80, 80, 20, "0", clrWhite, clrBlack);
CreateEditField("CP_TPPoints", ControlPanelX + 80, ControlPanelY + topPanelHeight + oiPanelHeight + 105, 80, 20, "300", clrWhite, clrBlack);
//--- Immediate Action Buttons Row 1
CreateButton("CP_Sell", ControlPanelX + 180, ControlPanelY + topPanelHeight + oiPanelHeight + 30, 100, 25, "Sell Now", clrRed, clrWhite);
CreateButton("CP_Buy", ControlPanelX + 290, ControlPanelY + topPanelHeight + oiPanelHeight + 30, 100, 25, "Buy Now", clrGreen, clrWhite);
//--- Pending Action Buttons Row 2
CreateButton("CP_PendingSell", ControlPanelX + 180, ControlPanelY + topPanelHeight + oiPanelHeight + 65, 100, 25, "Pending Sell", clrOrange, clrBlack);
CreateButton("CP_PendingBuy", ControlPanelX + 290, ControlPanelY + topPanelHeight + oiPanelHeight + 65, 100, 25, "Pending Buy", clrDarkGreen, clrWhite);
//--- Management Buttons Row 3
CreateButton("CP_CloseAllPending", ControlPanelX + 180, ControlPanelY + topPanelHeight + oiPanelHeight + 100, 210, 25, "Close All Pending Orders", clrPurple, clrWhite);
//--- Management Buttons Row 4
CreateButton("CP_CloseSell", ControlPanelX + 180, ControlPanelY + topPanelHeight + oiPanelHeight + 135, 100, 25, "Close All Sell", clrPurple, clrWhite);
CreateButton("CP_CloseBuy", ControlPanelX + 290, ControlPanelY + topPanelHeight + oiPanelHeight + 135, 100, 25, "Close All Buy", clrPurple, clrWhite);
}
//+------------------------------------------------------------------+
//| Create Panel |
//+------------------------------------------------------------------+
void CreatePanel(string name, int x, int y, int width, int height, color bgColor, ENUM_BORDER_TYPE border)
{
if(ObjectFind(chart_id, name) < 0)
{
ObjectCreate(chart_id, name, OBJ_RECTANGLE_LABEL, 0, 0, 0);
ObjectSetInteger(chart_id, name, OBJPROP_XDISTANCE, x);
ObjectSetInteger(chart_id, name, OBJPROP_YDISTANCE, y);
ObjectSetInteger(chart_id, name, OBJPROP_XSIZE, width);
ObjectSetInteger(chart_id, name, OBJPROP_YSIZE, height);
ObjectSetInteger(chart_id, name, OBJPROP_BGCOLOR, bgColor);
ObjectSetInteger(chart_id, name, OBJPROP_BORDER_TYPE, border);
ObjectSetInteger(chart_id, name, OBJPROP_BORDER_COLOR, clrGray);
ObjectSetInteger(chart_id, name, OBJPROP_BACK, false); // ปรับจาก true เป็น false เพื่อให้อยู่หน้ากราฟ
ObjectSetInteger(chart_id, name, OBJPROP_SELECTABLE, false);
ObjectSetInteger(chart_id, name, OBJPROP_HIDDEN, true);
// ตั้งค่า Z-Order ให้สูงเพื่อให้อยู่เหนือเส้นกราฟ
ObjectSetInteger(chart_id, name, OBJPROP_ZORDER, 1000);
}
}
//+------------------------------------------------------------------+
//| Create Button |
//+------------------------------------------------------------------+
void CreateButton(string name, int x, int y, int width, int height, string text, color bgColor, color textColor)
{
if(ObjectFind(chart_id, name) < 0)
{
ObjectCreate(chart_id, name, OBJ_BUTTON, 0, 0, 0);
ObjectSetInteger(chart_id, name, OBJPROP_XDISTANCE, x);
ObjectSetInteger(chart_id, name, OBJPROP_YDISTANCE, y);
ObjectSetInteger(chart_id, name, OBJPROP_XSIZE, width);
ObjectSetInteger(chart_id, name, OBJPROP_YSIZE, height);
ObjectSetString(chart_id, name, OBJPROP_TEXT, text);
ObjectSetInteger(chart_id, name, OBJPROP_BGCOLOR, bgColor);
ObjectSetInteger(chart_id, name, OBJPROP_COLOR, textColor);
ObjectSetInteger(chart_id, name, OBJPROP_FONTSIZE, 8);
ObjectSetString(chart_id, name, OBJPROP_FONT, "Arial");
ObjectSetInteger(chart_id, name, OBJPROP_CORNER, CORNER_LEFT_UPPER);
ObjectSetInteger(chart_id, name, OBJPROP_ANCHOR, ANCHOR_LEFT_UPPER);
ObjectSetInteger(chart_id, name, OBJPROP_SELECTABLE, false);
ObjectSetInteger(chart_id, name, OBJPROP_HIDDEN, true);
ObjectSetInteger(chart_id, name, OBJPROP_ZORDER, 1001);
}
}
//+------------------------------------------------------------------+
//| Create Edit Field |
//+------------------------------------------------------------------+
void CreateEditField(string name, int x, int y, int width, int height, string defaultText, color textColor, color bgColor)
{
if(ObjectFind(chart_id, name) < 0)
{
ObjectCreate(chart_id, name, OBJ_EDIT, 0, 0, 0);
ObjectSetInteger(chart_id, name, OBJPROP_XDISTANCE, x);
ObjectSetInteger(chart_id, name, OBJPROP_YDISTANCE, y);
ObjectSetInteger(chart_id, name, OBJPROP_XSIZE, width);
ObjectSetInteger(chart_id, name, OBJPROP_YSIZE, height);
ObjectSetString(chart_id, name, OBJPROP_TEXT, defaultText);
ObjectSetInteger(chart_id, name, OBJPROP_BGCOLOR, bgColor);
ObjectSetInteger(chart_id, name, OBJPROP_COLOR, textColor);
ObjectSetInteger(chart_id, name, OBJPROP_FONTSIZE, 8);
ObjectSetString(chart_id, name, OBJPROP_FONT, "Arial");
ObjectSetInteger(chart_id, name, OBJPROP_CORNER, CORNER_LEFT_UPPER);
ObjectSetInteger(chart_id, name, OBJPROP_ANCHOR, ANCHOR_LEFT_UPPER);
ObjectSetInteger(chart_id, name, OBJPROP_SELECTABLE, false);
ObjectSetInteger(chart_id, name, OBJPROP_HIDDEN, true);
ObjectSetInteger(chart_id, name, OBJPROP_ZORDER, 1001);
}
}
//+------------------------------------------------------------------+
//| Create Label |
//+------------------------------------------------------------------+
void CreateLabel(string name, int x, int y, string text, color clr, int fontSize = 8)
{
if(ObjectFind(chart_id, name) < 0)
{
ObjectCreate(chart_id, name, OBJ_LABEL, 0, 0, 0);
ObjectSetInteger(chart_id, name, OBJPROP_XDISTANCE, x);
ObjectSetInteger(chart_id, name, OBJPROP_YDISTANCE, y);
ObjectSetString(chart_id, name, OBJPROP_TEXT, text);
ObjectSetInteger(chart_id, name, OBJPROP_COLOR, clr);
ObjectSetInteger(chart_id, name, OBJPROP_FONTSIZE, fontSize);
ObjectSetString(chart_id, name, OBJPROP_FONT, "Arial");
ObjectSetInteger(chart_id, name, OBJPROP_CORNER, CORNER_LEFT_UPPER);
ObjectSetInteger(chart_id, name, OBJPROP_ANCHOR, ANCHOR_LEFT_UPPER);
ObjectSetInteger(chart_id, name, OBJPROP_SELECTABLE, false);
ObjectSetInteger(chart_id, name, OBJPROP_HIDDEN, true);
ObjectSetInteger(chart_id, name, OBJPROP_ZORDER, 1002);
}
}
//+------------------------------------------------------------------+
//| Handle Control Panel Click |
//+------------------------------------------------------------------+
void HandleControlPanelClick(string objectName)
{
//--- Get current values from input fields
UpdateInputValues();
if(objectName == "CP_CloseAll")
{
CloseAllPositions();
}
else if(objectName == "CP_UpdateOI") // New OI Data Update Handler
{
UpdateOIData();
}
else if(objectName == "CP_Sell")
{
ExecuteManualSell();
}
else if(objectName == "CP_Buy")
{
ExecuteManualBuy();
}
else if(objectName == "CP_PendingSell")
{
ExecutePendingSell();
}
else if(objectName == "CP_PendingBuy")
{
ExecutePendingBuy();
}
else if(objectName == "CP_CloseAllPending")
{
CancelAllPendingOrders();
}
else if(objectName == "CP_CloseSell")
{
CloseAllSellPositions();
}
else if(objectName == "CP_CloseBuy")
{
CloseAllBuyPositions();
}
}
//+------------------------------------------------------------------+
//| Update Input Values from Control Panel |
//+------------------------------------------------------------------+
void UpdateInputValues()
{
// Update trading input values
PendingPriceValue = StringToDouble(ObjectGetString(chart_id, "CP_PendingPrice", OBJPROP_TEXT));
ManualLotSize = StringToDouble(ObjectGetString(chart_id, "CP_LotSize", OBJPROP_TEXT));
ManualSLPoints = (int)StringToInteger(ObjectGetString(chart_id, "CP_SLPoints", OBJPROP_TEXT));
ManualTPPoints = (int)StringToInteger(ObjectGetString(chart_id, "CP_TPPoints", OBJPROP_TEXT));
// Update OI data input values
ManualFuturePriceValue = StringToDouble(ObjectGetString(chart_id, "CP_FuturePrice", OBJPROP_TEXT));
CallStrike1Value = StringToDouble(ObjectGetString(chart_id, "CP_CallStrike1", OBJPROP_TEXT));
CallStrike2Value = StringToDouble(ObjectGetString(chart_id, "CP_CallStrike2", OBJPROP_TEXT));
CallStrike3Value = StringToDouble(ObjectGetString(chart_id, "CP_CallStrike3", OBJPROP_TEXT));
PutStrike1Value = StringToDouble(ObjectGetString(chart_id, "CP_PutStrike1", OBJPROP_TEXT));
PutStrike2Value = StringToDouble(ObjectGetString(chart_id, "CP_PutStrike2", OBJPROP_TEXT));
PutStrike3Value = StringToDouble(ObjectGetString(chart_id, "CP_PutStrike3", OBJPROP_TEXT));
Print("Pending Price: ", PendingPriceValue);
Print("Lot Size: ", ManualLotSize);
Print("SL Points: ", ManualSLPoints);
Print("TP Points: ", ManualTPPoints);
Print("Manual Future Price: ", ManualFuturePriceValue);
Print("Call Strikes: ", CallStrike1Value, ", ", CallStrike2Value, ", ", CallStrike3Value);
Print("Put Strikes: ", PutStrike1Value, ", ", PutStrike2Value, ", ", PutStrike3Value);
}
//+------------------------------------------------------------------+
//| Update Control Panel Values |
//+------------------------------------------------------------------+
void UpdateControlPanelValues()
{
// Update price display
double currentBid = SymbolInfo.Bid();
ObjectSetString(chart_id, "CP_PendingPrice", OBJPROP_TEXT, DoubleToString(currentBid, _Digits));
// Initialize OI data fields with current input values (dynamic first, then input)
ObjectSetString(chart_id, "CP_FuturePrice", OBJPROP_TEXT,
DoubleToString((DynamicFuturePrice > 0) ? DynamicFuturePrice : InpManualFuturePrice, _Digits));
ObjectSetString(chart_id, "CP_CallStrike1", OBJPROP_TEXT,
DoubleToString((DynamicCallStrike1 > 0) ? DynamicCallStrike1 : InpCallStrike1, _Digits));
ObjectSetString(chart_id, "CP_CallStrike2", OBJPROP_TEXT,
DoubleToString((DynamicCallStrike2 > 0) ? DynamicCallStrike2 : InpCallStrike2, _Digits));
ObjectSetString(chart_id, "CP_CallStrike3", OBJPROP_TEXT,
DoubleToString((DynamicCallStrike3 > 0) ? DynamicCallStrike3 : InpCallStrike3, _Digits));
ObjectSetString(chart_id, "CP_PutStrike1", OBJPROP_TEXT,
DoubleToString((DynamicPutStrike1 > 0) ? DynamicPutStrike1 : InpPutStrike1, _Digits));
ObjectSetString(chart_id, "CP_PutStrike2", OBJPROP_TEXT,
DoubleToString((DynamicPutStrike2 > 0) ? DynamicPutStrike2 : InpPutStrike2, _Digits));
ObjectSetString(chart_id, "CP_PutStrike3", OBJPROP_TEXT,
DoubleToString((DynamicPutStrike3 > 0) ? DynamicPutStrike3 : InpPutStrike3, _Digits));
}
//+------------------------------------------------------------------+
//| Update Control Panel |
//+------------------------------------------------------------------+
void UpdateControlPanel()
{
// Update pending price with current market price periodically
static datetime lastUpdate = 0;
if(TimeCurrent() - lastUpdate > 5) // Update every 5 seconds
{
UpdateControlPanelValues();
lastUpdate = TimeCurrent();
}
}
//+------------------------------------------------------------------+
//| Execute Manual SELL |
//+------------------------------------------------------------------+
void ExecuteManualSell()
{
double lotSize = NormalizeLot(ManualLotSize);
if(lotSize <= 0) return;
double sl = (ManualSLPoints > 0) ? SymbolInfo.Bid() + ManualSLPoints * _Point : 0.0;
double tp = (ManualTPPoints > 0) ? SymbolInfo.Bid() - ManualTPPoints * _Point : 0.0;
if(Trade.Sell(lotSize, _Symbol, SymbolInfo.Bid(), sl, tp, "Manual SELL"))
{
Print("Manual SELL executed. Lot: ", lotSize, " Price: ", SymbolInfo.Bid());
DailyTradeCount++;
}
else
{
Print("Manual SELL failed. Error: ", Trade.ResultRetcodeDescription());
}
}
//+------------------------------------------------------------------+
//| Execute Manual BUY |
//+------------------------------------------------------------------+
void ExecuteManualBuy()
{
double lotSize = NormalizeLot(ManualLotSize);
if(lotSize <= 0) return;
double sl = (ManualSLPoints > 0) ? SymbolInfo.Ask() - ManualSLPoints * _Point : 0.0;
double tp = (ManualTPPoints > 0) ? SymbolInfo.Ask() + ManualTPPoints * _Point : 0.0;
if(Trade.Buy(lotSize, _Symbol, SymbolInfo.Ask(), sl, tp, "Manual BUY"))
{
Print("Manual BUY executed. Lot: ", lotSize, " Price: ", SymbolInfo.Ask());
DailyTradeCount++;
}
else
{
Print("Manual BUY failed. Error: ", Trade.ResultRetcodeDescription());
}
}
//+------------------------------------------------------------------+
//| Execute Pending SELL |
//+------------------------------------------------------------------+
void ExecutePendingSell()
{
// 1. อัพเดทค่าจาก Control Panel
UpdateInputValues();
// 2. Refresh rates ก่อนใช้งาน
SymbolInfo.RefreshRates();
// 3. ตรวจสอบค่าที่ได้
if(PendingPriceValue <= 0)
{
Print("Invalid pending price for SELL: ", PendingPriceValue);
Alert("กรุณากรอกราคาที่ต้องการสำหรับ Pending SELL");
return;
}
double lotSize = NormalizeLot(ManualLotSize);
if(lotSize <= 0)
{
Print("Invalid lot size for Pending SELL: ", ManualLotSize);
Alert("กรุณากรอกขนาด Lot ที่ถูกต้อง");
return;
}
// 4. คำนวณ SL และ TP สำหรับ SELL orders
// SL ต้องต่ำกว่าราคา entry สำหรับ SELL orders
double sl = (ManualSLPoints > 0) ? PendingPriceValue - ManualSLPoints * _Point : 0.0;
double tp = (ManualTPPoints > 0) ? PendingPriceValue - ManualTPPoints * _Point : 0.0;
Print("SELL Order - Entry: ", PendingPriceValue, " | SL: ", sl, " | TP: ", tp);
// 5. กำหนดประเภท Order - SELL logic ต้องถูกต้อง
ENUM_ORDER_TYPE orderType;
double currentBid = SymbolInfo.Bid(); // ใช้ Bid สำหรับ SELL orders
Print("Current Bid: ", currentBid, " | Pending Price: ", PendingPriceValue);
// SELL_LIMIT: ขายที่ราคาสูงกว่าตลาดปัจจุบัน (รอราคาขึ้นมาแล้วขาย)
// SELL_STOP: ขายเมื่อราคาลดลงถึงระดับที่กำหนด (Stop loss)
if(PendingPriceValue > currentBid)
{
orderType = ORDER_TYPE_SELL_LIMIT; // Sell limit if price is above current Bid
Print("Using SELL_LIMIT order type (sell at higher price)");
}
else
{
orderType = ORDER_TYPE_SELL_STOP; // Sell stop if price is below current Bid
Print("Using SELL_STOP order type (sell when price drops)");
}
// 6. ใช้ OrderSend() ตรงๆ แทน Trade.OrderSend()
MqlTradeRequest request = {};
MqlTradeResult result = {};
request.action = TRADE_ACTION_PENDING;
request.symbol = _Symbol;
request.type = orderType;
request.volume = lotSize;
request.price = NormalizeDouble(PendingPriceValue, _Digits);
request.sl = (sl > 0) ? NormalizeDouble(sl, _Digits) : 0;
request.tp = (tp > 0) ? NormalizeDouble(tp, _Digits) : 0;
request.comment = "Pending SELL";
request.type_filling = ORDER_FILLING_IOC;
request.magic = InpMagicNumber;
// 7. ใช้ Trade.OrderSend() สำหรับการจัดการที่ดีกว่า
if(Trade.OrderSend(request, result))
{
Print("Pending SELL order placed successfully!");
Print("Ticket: ", result.order, " | Price: ", result.price);
Alert("Pending SELL order placed successfully!\nTicket: " + IntegerToString(result.order) + "\nPrice: " + DoubleToString(result.price, _Digits));
}
else
{
Print("Pending SELL failed! Error: ", Trade.ResultRetcodeDescription());
Alert("Pending SELL failed! Error: " + Trade.ResultRetcodeDescription());
}
}
//+------------------------------------------------------------------+
//| Execute Pending BUY |
//+------------------------------------------------------------------+
void ExecutePendingBuy()
{
// 1. อัพเดทค่าจาก Control Panel
UpdateInputValues();
// 2. Refresh rates ก่อนใช้งาน
SymbolInfo.RefreshRates();
// 3. ตรวจสอบค่าที่ได้
if(PendingPriceValue <= 0)
{
Print("Invalid pending price for BUY: ", PendingPriceValue);
Alert("กรุณากรอกราคาที่ต้องการสำหรับ Pending BUY");
return;
}
double lotSize = NormalizeLot(ManualLotSize);
if(lotSize <= 0)
{
Print("Invalid lot size for Pending BUY: ", ManualLotSize);
Alert("กรุณากรอกขนาด Lot ที่ถูกต้อง");
return;
}
// 4. คำนวณ SL และ TP สำหรับ BUY orders
// SL ต้องต่ำกว่าราคา entry สำหรับ BUY orders
double sl = (ManualSLPoints > 0) ? PendingPriceValue - ManualSLPoints * _Point : 0.0;
double tp = (ManualTPPoints > 0) ? PendingPriceValue + ManualTPPoints * _Point : 0.0;
Print("BUY Order - Entry: ", PendingPriceValue, " | SL: ", sl, " | TP: ", tp);
// 5. กำหนดประเภท Order - BUY logic
ENUM_ORDER_TYPE orderType;
double currentAsk = SymbolInfo.Ask(); // ใช้ Ask สำหรับ BUY orders
Print("Current Ask: ", currentAsk, " | Pending Price: ", PendingPriceValue);
// BUY_LIMIT: ซื้อที่ราคาต่ำกว่าตลาดปัจจุบัน (รอราคาลงมาแล้วซื้อ)
// BUY_STOP: ซื้อเมื่อราคาขึ้นไปถึงระดับที่กำหนด (Breakout)
if(PendingPriceValue < currentAsk)
{
orderType = ORDER_TYPE_BUY_LIMIT; // Buy limit if price is below current Ask
Print("Using BUY_LIMIT order type (buy at lower price)");
}
else
{
orderType = ORDER_TYPE_BUY_STOP; // Buy stop if price is above current Ask
Print("Using BUY_STOP order type (buy when price breaks higher)");
}
// 6. เตรียม Trade Request
MqlTradeRequest request = {};
MqlTradeResult result = {};
request.action = TRADE_ACTION_PENDING;
request.symbol = _Symbol;
request.type = orderType;
request.volume = lotSize;
request.price = NormalizeDouble(PendingPriceValue, _Digits);
request.sl = (sl > 0) ? NormalizeDouble(sl, _Digits) : 0;
request.tp = (tp > 0) ? NormalizeDouble(tp, _Digits) : 0;
request.comment = "Pending BUY";
request.type_filling = ORDER_FILLING_IOC;
request.magic = InpMagicNumber;
// 7. ส่ง Order
if(Trade.OrderSend(request, result))
{
Print("Pending BUY order placed successfully!");
Print("Ticket: ", result.order, " | Price: ", result.price);
Alert("Pending BUY order placed successfully!\nTicket: " + IntegerToString(result.order) + "\nPrice: " + DoubleToString(result.price, _Digits));
}
else
{
Print("Pending BUY failed! Error: ", Trade.ResultRetcodeDescription());
Alert("Pending BUY failed! Error: " + Trade.ResultRetcodeDescription());
}
}
//+------------------------------------------------------------------+
//| Cancel All Pending Orders |
//+------------------------------------------------------------------+
void CancelAllPendingOrders()
{
int totalOrders = OrdersTotal();
int canceledCount = 0;
for(int i = totalOrders - 1; i >= 0; i--)
{
if(OrderInfo.SelectByIndex(i))
{
if(OrderInfo.Symbol() == _Symbol && OrderInfo.Magic() == InpMagicNumber)
{
ENUM_ORDER_TYPE orderType = OrderInfo.OrderType();
// Check if it's a pending order
if(orderType == ORDER_TYPE_BUY_LIMIT || orderType == ORDER_TYPE_BUY_STOP ||
orderType == ORDER_TYPE_SELL_LIMIT || orderType == ORDER_TYPE_SELL_STOP)
{
if(Trade.OrderDelete(OrderInfo.Ticket()))
{
Print("Pending order deleted: ", OrderInfo.Ticket());
canceledCount++;
}
}
}
}
}
if(canceledCount > 0)
{
Print("Total pending orders canceled: ", canceledCount);
}
else
{
Print("No pending orders found to cancel");
}
}
//+------------------------------------------------------------------+
//| Close All Sell Positions |
//+------------------------------------------------------------------+
void CloseAllSellPositions()
{
for(int i = PositionsTotal() - 1; i >= 0; i--)
{
if(PositionInfo.SelectByIndex(i))
{
if(PositionInfo.Symbol() == _Symbol &&
PositionInfo.Magic() == InpMagicNumber &&
PositionInfo.PositionType() == POSITION_TYPE_SELL)
{
Trade.PositionClose(PositionInfo.Ticket());
Print("SELL position closed: ", PositionInfo.Ticket());
}
}
}
}
//+------------------------------------------------------------------+
//| Close All Buy Positions |
//+------------------------------------------------------------------+
void CloseAllBuyPositions()
{
for(int i = PositionsTotal() - 1; i >= 0; i--)
{
if(PositionInfo.SelectByIndex(i))
{
if(PositionInfo.Symbol() == _Symbol &&
PositionInfo.Magic() == InpMagicNumber &&
PositionInfo.PositionType() == POSITION_TYPE_BUY)
{
Trade.PositionClose(PositionInfo.Ticket());
Print("BUY position closed: ", PositionInfo.Ticket());
}
}
}
}
//+------------------------------------------------------------------+
//| Normalize Lot Size |
//+------------------------------------------------------------------+
double NormalizeLot(double lot)
{
double minLot = SymbolInfo.LotsMin();
double maxLot = SymbolInfo.LotsMax();
double lotStep = SymbolInfo.LotsStep();
lot = MathMax(lot, minLot);
lot = MathMin(lot, maxLot);
if(lotStep > 0)
lot = MathRound(lot / lotStep) * lotStep;
return NormalizeDouble(lot, 2);
}
//+------------------------------------------------------------------+
//| Update OI Data from Control Panel |
//+------------------------------------------------------------------+
void UpdateOIData()
{
// Get current values from control panel
UpdateInputValues();
// แสดงข้อมูลที่ได้รับจาก Control Panel
Print("=== OI Data Update Process ===");
Print("Manual Future Price Value: ", ManualFuturePriceValue);
Print("Call Strike Values: ", CallStrike1Value, ", ", CallStrike2Value, ", ", CallStrike3Value);
Print("Put Strike Values: ", PutStrike1Value, ", ", PutStrike2Value, ", ", PutStrike3Value);
// Validate and update dynamic variables
if(ManualFuturePriceValue > 0)
{
DynamicFuturePrice = ManualFuturePriceValue;
Print("Updated Dynamic Future Price: ", DynamicFuturePrice);
}
else
{
Print("Warning: Manual Future Price is 0 or invalid, using previous value: ", DynamicFuturePrice);
}
// Update OI Strike levels (dynamic variables)
if(CallStrike1Value >= 0) DynamicCallStrike1 = CallStrike1Value;
if(CallStrike2Value >= 0) DynamicCallStrike2 = CallStrike2Value;
if(CallStrike3Value >= 0) DynamicCallStrike3 = CallStrike3Value;
if(PutStrike1Value >= 0) DynamicPutStrike1 = PutStrike1Value;
if(PutStrike2Value >= 0) DynamicPutStrike2 = PutStrike2Value;
if(PutStrike3Value >= 0) DynamicPutStrike3 = PutStrike3Value;
Print("Dynamic Call Strikes: ", DynamicCallStrike1, ", ", DynamicCallStrike2, ", ", DynamicCallStrike3);
Print("Dynamic Put Strikes: ", DynamicPutStrike1, ", ", DynamicPutStrike2, ", ", DynamicPutStrike3);
// Reinitialize OI levels with new values
InitializeOILevels();
InitializeKeyLevels();
Print("OI Data Updated Successfully!");
// Show confirmation
string message = "OI Data Updated Successfully!\n" +
"Future Price: " + DoubleToString(DynamicFuturePrice, _Digits) + "\n" +
"Call Strikes: " + DoubleToString(DynamicCallStrike1, _Digits) + ", " +
DoubleToString(DynamicCallStrike2, _Digits) + ", " + DoubleToString(DynamicCallStrike3, _Digits) + "\n" +
"Put Strikes: " + DoubleToString(DynamicPutStrike1, _Digits) + ", " +
DoubleToString(DynamicPutStrike2, _Digits) + ", " + DoubleToString(DynamicPutStrike3, _Digits);
Alert(message);
}
//+------------------------------------------------------------------+
//| Initialize OI Levels |
//+------------------------------------------------------------------+
void InitializeOILevels()
{
//--- Load OI data based on source
switch(InpOISource)
{
case OI_SOURCE_MANUAL:
// Use dynamic variables first, fall back to input parameters
CallLevels[0] = (DynamicCallStrike1 > 0) ? DynamicCallStrike1 : InpCallStrike1;
CallLevels[1] = (DynamicCallStrike2 > 0) ? DynamicCallStrike2 : InpCallStrike2;
CallLevels[2] = (DynamicCallStrike3 > 0) ? DynamicCallStrike3 : InpCallStrike3;
PutLevels[0] = (DynamicPutStrike1 > 0) ? DynamicPutStrike1 : InpPutStrike1;
PutLevels[1] = (DynamicPutStrike2 > 0) ? DynamicPutStrike2 : InpPutStrike2;
PutLevels[2] = (DynamicPutStrike3 > 0) ? DynamicPutStrike3 : InpPutStrike3;
// Default OI values
CallOI[0] = 1000;
CallOI[1] = 800;
CallOI[2] = 600;
PutOI[0] = 1000;
PutOI[1] = 800;
PutOI[2] = 600;
break;
case OI_SOURCE_CSV_FILE:
LoadOIFromCSV();
break;
case OI_SOURCE_AUTO_SYNC:
// Future implementation for auto-sync
break;
}
//--- Sort levels in ascending order
ArraySort(CallLevels);
ArraySort(PutLevels);
Print("OI Levels Initialized:");
Print("Call Levels: ", CallLevels[0], ", ", CallLevels[1], ", ", CallLevels[2]);
Print("Put Levels: ", PutLevels[0], ", ", PutLevels[1], ", ", PutLevels[2]);
}
//+------------------------------------------------------------------+
//| Load OI data from CSV file |
//+------------------------------------------------------------------+
void LoadOIFromCSV()
{
Print("=== CSV Loading Debug ===");
Print("Terminal Files dir: ", TerminalInfoString(TERMINAL_DATA_PATH) + "\\MQL5\\Files\\");
Print("Attempting to open: ", InpOICsvPath);
if(!FileIsExist(InpOICsvPath)) {
Print("CSV FILE NOT FOUND - check path or if scraper output exists");
return;
}
string filename = InpOICsvPath;
int filehandle = FileOpen(filename, FILE_READ | FILE_ANSI);
if(filehandle == INVALID_HANDLE)
{
int err = GetLastError();
Print("CSV OPEN FAILED [Error ", err, "]: ", err);
Print("File exists: ", FileIsExist(InpOICsvPath) ? "YES" : "NO");
InitializeOILevels();
return;
}
long fileSize = FileSize(filehandle);
Print("CSV opened successfully. Size: ", fileSize, " bytes");
int callIndex = 0;
int putIndex = 0;
double futurePrice = 0.0;
bool isFirstLine = true;
while(!FileIsEnding(filehandle))
{
string row = FileReadString(filehandle);
Print("DEBUG ROW: [", row, "]");
if(isFirstLine) {
isFirstLine = false;
if(StringFind(row, "Type") >= 0 || StringFind(row, "Strike") >= 0 || StringFind(row, "OI") >= 0) {
continue;
}
}
string data[];
int count = StringSplit(row, ',', data);
if(count >= 3)
{
string type = data[0];
double strike = StringToDouble(data[1]);
int oi = (int)StringToInteger(data[2]);
if(StringFind(type, "Future") >= 0)
{
futurePrice = strike;
if(!CSVLoadLogged) {
Print("DEBUG: Parsed Future price: ", futurePrice);
}
}
else if(type == "CALL" && callIndex < 3)
{
CallLevels[callIndex] = strike;
CallOI[callIndex] = oi;
callIndex++;
if(!CSVLoadLogged) {
Print("DEBUG: Found CALL row, strike=", strike, " oi=", oi);
}
}
else if(type == "PUT" && putIndex < 3)
{
PutLevels[putIndex] = strike;
PutOI[putIndex] = oi;
putIndex++;
if(!CSVLoadLogged) {
Print("DEBUG: Found PUT row, strike=", strike, " oi=", oi);
}
}
}
}
FileClose(filehandle);
for(int i = callIndex; i < 3; i++)
{
CallLevels[i] = 0;
CallOI[i] = 0;
}
for(int i = putIndex; i < 3; i++)
{
PutLevels[i] = 0;
PutOI[i] = 0;
}
if(futurePrice > 0) {
CachedFuturePrice = futurePrice;
DynamicFuturePrice = futurePrice;
FuturePrice = futurePrice;
LoadedCSVPath = filename;
CSVLoadLogged = true;
Print("CSV SUCCESS: FuturePrice=", futurePrice, ", CALL=[", CallLevels[0], ",", CallLevels[1], ",", CallLevels[2], "], PUT=[", PutLevels[0], ",", PutLevels[1], ",", PutLevels[2], "] loaded from ", filename);
} else {
if(!CSVLoadLogged) {
Print("CSV ERROR: No valid price found in ", filename);
CSVLoadLogged = true;
}
CachedFuturePrice = 0;
}
}
//+------------------------------------------------------------------+
//| Initialize Key Levels |
//+------------------------------------------------------------------+
void InitializeKeyLevels()
{
// Calculate key levels based on OI levels
if(PutLevels[2] > 0 && CallLevels[2] > 0)
{
LevelLower2 = PutLevels[2]; // Lowest put strike
LevelLower1 = PutLevels[1]; // Middle put strike
LevelMid = (PutLevels[0] + CallLevels[0]) / 2; // Mid point
LevelUpper1 = CallLevels[1]; // Middle call strike
LevelUpper2 = CallLevels[2]; // Highest call strike
}
else
{
// Use current price as reference
double currentPrice = SymbolInfo.Bid();
LevelLower2 = currentPrice - 500 * _Point;
LevelLower1 = currentPrice - 250 * _Point;
LevelMid = currentPrice;
LevelUpper1 = currentPrice + 250 * _Point;
LevelUpper2 = currentPrice + 500 * _Point;
}
}
//+------------------------------------------------------------------+
//| Initialize Indicators |
//+------------------------------------------------------------------+
bool InitializeIndicators()
{
// ATR for volatility
ATRHandle = iATR(_Symbol, PERIOD_H1, 14);
if(ATRHandle == INVALID_HANDLE)
{
Print("Error creating ATR indicator");
return false;
}
// Moving Averages for trend
MAFastHandle = iMA(_Symbol, InpTrendTF, InpTrendMAPeriod1, 0, MODE_EMA, PRICE_CLOSE);
MASlowHandle = iMA(_Symbol, InpTrendTF, InpTrendMAPeriod2, 0, MODE_SMA, PRICE_CLOSE);
if(MAFastHandle == INVALID_HANDLE || MASlowHandle == INVALID_HANDLE)
{
Print("Error creating MA indicators");
return false;
}
// RSI for momentum (optional)
RSIMainHandle = iRSI(_Symbol, PERIOD_H1, 14, PRICE_CLOSE);
return true;
}
//+------------------------------------------------------------------+
//| Update Market Data |
//+------------------------------------------------------------------+
bool UpdateMarketData()
{
// Get current prices
SpotPrice = SymbolInfo.Bid();
SymbolInfo.RefreshRates();
// Get future price (CSV cache, manual or from symbol)
if(CachedFuturePrice > 0)
{
FuturePrice = CachedFuturePrice;
}
else if(DynamicFuturePrice > 0)
{
FuturePrice = DynamicFuturePrice;
}
else if(InpManualFuturePrice > 0)
{
FuturePrice = InpManualFuturePrice;
}
else
{
// In real implementation, you might get this from a different symbol
// For now, use spot price with a small offset
FuturePrice = SpotPrice;
}
// Calculate Delta
double previousDelta = DeltaPrice;
DeltaPrice = FuturePrice - SpotPrice;
// Update Delta EMA
UpdateDeltaEMA();
// Calculate Deviation
DeltaDeviation = DeltaPrice - DeltaEMA;
// Check for zero cross
if(InpCloseOnZeroDeviation && previousDelta * DeltaPrice < 0)
{
CloseAllPositions();
}
return true;
}
//+------------------------------------------------------------------+
//| Update Delta EMA |
//+------------------------------------------------------------------+
void UpdateDeltaEMA()
{
static double ema = 0;
static bool firstRun = true;
if(firstRun)
{
ema = DeltaPrice;
firstRun = false;
}
else
{
double alpha = 2.0 / (InpDeltaEmaPeriod + 1.0);
ema = alpha * DeltaPrice + (1 - alpha) * ema;
}
DeltaEMA = ema;
}
//+------------------------------------------------------------------+
//| Check Global Trading Conditions |
//+------------------------------------------------------------------+
bool CheckGlobalConditions()
{
//--- Check if trading is enabled
if(!TradingEnabled)
{
return false;
}
//--- Check terminal connection
if(!TerminalInfoInteger(TERMINAL_CONNECTED))
{
Print("Terminal not connected");
return false;
}
//--- Check trading permission
if(!TerminalInfoInteger(TERMINAL_TRADE_ALLOWED) || !MQLInfoInteger(MQL_TRADE_ALLOWED))
{
Print("Trading not allowed");
return false;
}
//--- Check spread limit
long spread = SymbolInfo.Spread();
if(spread > InpMaxSpread)
{
return false;
}
//--- Check session time
if(InpUseSessionFilter && !IsTradingSession())
{
return false;
}
//--- Check news block
if(NewsBlockActive)
{
return false;
}
//--- Check volatility filter
if(InpUseATRFilter && !CheckVolatilityFilter())
{
return false;
}
//--- Check daily limits
if(!CheckDailyLimits())
{
TradingEnabled = false;
Print("Daily limit reached. Trading disabled.");
return false;
}
//--- Check equity protection
if(CheckEquityProtection())
{
TradingEnabled = false;
Print("Equity protection triggered. Trading disabled.");
return false;
}
return true;
}
//+------------------------------------------------------------------+
//| Check Trading Session |
//+------------------------------------------------------------------+
bool IsTradingSession()
{
MqlDateTime timeNow;
TimeCurrent(timeNow);
int hour = timeNow.hour;
// Check if current hour is within trading session
if(hour >= InpSessionStartHour && hour < InpSessionEndHour)
{
return true;
}
return false;
}
//+------------------------------------------------------------------+
//| Check Volatility Filter |
//+------------------------------------------------------------------+
bool CheckVolatilityFilter()
{
double atrValues[];
ArraySetAsSeries(atrValues, true);
if(CopyBuffer(ATRHandle, 0, 0, 1, atrValues) < 1)
return false;
double atr = atrValues[0];
double atrPercent = (atr / SpotPrice) * 100;
return (atrPercent <= InpMaxATRPercent);
}
//+------------------------------------------------------------------+
//| Check Daily Limits |
//+------------------------------------------------------------------+
bool CheckDailyLimits()
{
double balance = AccountInfo.Balance();
double equity = AccountInfo.Equity();
// Check daily loss limit
if(DailyLoss > 0)
{
double lossPercent = (DailyLoss / balance) * 100;
if(lossPercent >= InpMaxDailyLossPercent)
{
Print("Daily loss limit reached: ", lossPercent, "%");
return false;
}
}
// Check daily profit limit
if(DailyProfit > 0)
{
double profitPercent = (DailyProfit / balance) * 100;
if(profitPercent >= InpMaxDailyProfitPercent)
{
Print("Daily profit limit reached: ", profitPercent, "%");
return false;
}
}
// Check consecutive losses
if(ConsecutiveLosses >= InpMaxConsecutiveLosses && InpDisableAfterMaxLoss)
{
Print("Max consecutive losses reached: ", ConsecutiveLosses);
return false;
}
// Check daily trade count
if(DailyTradeCount >= InpMaxDailyTrades)
{
Print("Max daily trades reached: ", DailyTradeCount);
return false;
}
return true;
}
//+------------------------------------------------------------------+
//| Check Equity Protection |
//+------------------------------------------------------------------+
bool CheckEquityProtection()
{
double balance = AccountInfo.Balance();
double equity = AccountInfo.Equity();
if(balance <= 0) return false;
double drawdownPercent = ((balance - equity) / balance) * 100;
if(drawdownPercent >= InpEquityProtectionPercent)
{
Print("Equity protection triggered: ", drawdownPercent, "% drawdown");
CloseAllPositions();
return true;
}
return false;
}
//+------------------------------------------------------------------+
//| Check News Events |
//+------------------------------------------------------------------+
void CheckNewsEvents()
{
// Simplified news check - in real implementation, you would use a news API
// or economic calendar data
datetime timeNow = TimeCurrent();
// For now, this is a placeholder function
// In production, you would implement actual news checking logic here
}
//+------------------------------------------------------------------+
//| Check Trading Signals |
//+------------------------------------------------------------------+
void CheckTradingSignals()
{
// Don't open new trades if already have position
if(PositionsTotal() > 0)
{
// Check if we should add to position or close
return;
}
// Get market phase
ENUM_MARKET_PHASE marketPhase = GetMarketPhase();
// Check SELL conditions
if(CheckSellConditions(marketPhase))
{
ExecuteSellTrade();
}
// Check BUY conditions
else if(CheckBuyConditions(marketPhase))
{
ExecuteBuyTrade();
}
}
//+------------------------------------------------------------------+
//| Get Market Phase |
//+------------------------------------------------------------------+
ENUM_MARKET_PHASE GetMarketPhase()
{
if(!InpUseMarketPhaseFilter)
return PHASE_NEUTRAL;
double maFast[], maSlow[];
ArraySetAsSeries(maFast, true);
ArraySetAsSeries(maSlow, true);
if(CopyBuffer(MAFastHandle, 0, 0, 2, maFast) < 2) return PHASE_NEUTRAL;
if(CopyBuffer(MASlowHandle, 0, 0, 1, maSlow) < 1) return PHASE_NEUTRAL;
double maFastCurrent = maFast[0];
double maFastPrevious = maFast[1];
double maSlowCurrent = maSlow[0];
// Calculate slope
double slope = maFastCurrent - maFastPrevious;
if(maFastCurrent > maSlowCurrent && slope > 0)
return PHASE_BULLISH;
else if(maFastCurrent < maSlowCurrent && slope < 0)
return PHASE_BEARISH;
else if(MathAbs(slope) < 0.0001)
return PHASE_SIDEWAYS;
else
return PHASE_NEUTRAL;
}
//+------------------------------------------------------------------+
//| Check SELL Conditions |
//+------------------------------------------------------------------+
bool CheckSellConditions(ENUM_MARKET_PHASE marketPhase)
{
// 1. Check Delta Deviation
if(DeltaDeviation <= InpDeviationThreshold * _Point)
return false;
// 2. Check price near upper OI level
if(!IsPriceNearLevel(SpotPrice, CallLevels, true))
return false;
// 3. Check market phase filter
if(marketPhase == PHASE_BULLISH && InpUseMarketPhaseFilter)
{
// Need stronger signal in bullish phase
if(DeltaDeviation < InpDeviationThreshold * _Point * InpDeviationMultiplier)
return false;
}
// 4. Check overbought condition (optional)
if(!CheckOverbought())
return false;
// 5. Check if price is at key resistance
if(!IsAtResistance())
return false;
return true;
}
//+------------------------------------------------------------------+
//| Check BUY Conditions |
//+------------------------------------------------------------------+
bool CheckBuyConditions(ENUM_MARKET_PHASE marketPhase)
{
// 1. Check Delta Deviation
if(DeltaDeviation >= -InpDeviationThreshold * _Point)
return false;
// 2. Check price near lower OI level
if(!IsPriceNearLevel(SpotPrice, PutLevels, false))
return false;
// 3. Check market phase filter
if(marketPhase == PHASE_BEARISH && InpUseMarketPhaseFilter)
{
// Need stronger signal in bearish phase
if(DeltaDeviation > -InpDeviationThreshold * _Point * InpDeviationMultiplier)
return false;
}
// 4. Check oversold condition (optional)
if(!CheckOversold())
return false;
// 5. Check if price is at key support
if(!IsAtSupport())
return false;
return true;
}
//+------------------------------------------------------------------+
//| Check if price is near OI level |
//+------------------------------------------------------------------+
bool IsPriceNearLevel(double price, double &levels[], bool isUpper)
{
double tolerance = 50 * _Point; // 50 points tolerance
for(int i = 0; i < ArraySize(levels); i++)
{
if(levels[i] <= 0) continue;
if(isUpper)
{
// For upper levels, price should be at or above the level
if(price >= levels[i] - tolerance && price <= levels[i] + tolerance)
return true;
}
else
{
// For lower levels, price should be at or below the level
if(price >= levels[i] - tolerance && price <= levels[i] + tolerance)
return true;
}
}
return false;
}
//+------------------------------------------------------------------+
//| Check overbought condition |
//+------------------------------------------------------------------+
bool CheckOverbought()
{
// Simple RSI check
if(RSIMainHandle != INVALID_HANDLE)
{
double rsiValues[];
ArraySetAsSeries(rsiValues, true);
if(CopyBuffer(RSIMainHandle, 0, 0, 1, rsiValues) >= 1)
{
if(rsiValues[0] < 70) // Not overbought
return false;
}
}
return true;
}
//+------------------------------------------------------------------+
//| Check oversold condition |
//+------------------------------------------------------------------+
bool CheckOversold()
{
// Simple RSI check
if(RSIMainHandle != INVALID_HANDLE)
{
double rsiValues[];
ArraySetAsSeries(rsiValues, true);
if(CopyBuffer(RSIMainHandle, 0, 0, 1, rsiValues) >= 1)
{
if(rsiValues[0] > 30) // Not oversold
return false;
}
}
return true;
}
//+------------------------------------------------------------------+
//| Check if price is at resistance |
//+------------------------------------------------------------------+
bool IsAtResistance()
{
// Check if price is near upper key levels
double tolerance = 100 * _Point;
if(MathAbs(SpotPrice - LevelUpper1) <= tolerance ||
MathAbs(SpotPrice - LevelUpper2) <= tolerance)
{
return true;
}
return false;
}
//+------------------------------------------------------------------+
//| Check if price is at support |
//+------------------------------------------------------------------+
bool IsAtSupport()
{
// Check if price is near lower key levels
double tolerance = 100 * _Point;
if(MathAbs(SpotPrice - LevelLower1) <= tolerance ||
MathAbs(SpotPrice - LevelLower2) <= tolerance)
{
return true;
}
return false;
}
//+------------------------------------------------------------------+
//| Execute SELL Trade |
//+------------------------------------------------------------------+
void ExecuteSellTrade()
{
double lotSize = CalculateLotSize(POSITION_TYPE_SELL);
if(lotSize <= 0)
return;
double sl = CalculateStopLoss(POSITION_TYPE_SELL, SpotPrice);
double tp = CalculateTakeProfit(POSITION_TYPE_SELL, SpotPrice);
// Send sell order
if(Trade.Sell(lotSize, _Symbol, SpotPrice, sl, tp, "OI Mean Reversion SELL"))
{
DailyTradeCount++;
LastTradeTime = TimeCurrent();
Print("SELL order executed. Lot: ", lotSize, " Price: ", SpotPrice);
}
else
{
Print("SELL order failed. Error: ", Trade.ResultRetcodeDescription());
}
}
//+------------------------------------------------------------------+
//| Execute BUY Trade |
//+------------------------------------------------------------------+
void ExecuteBuyTrade()
{
double lotSize = CalculateLotSize(POSITION_TYPE_BUY);
if(lotSize <= 0)
return;
double sl = CalculateStopLoss(POSITION_TYPE_BUY, SpotPrice);
double tp = CalculateTakeProfit(POSITION_TYPE_BUY, SpotPrice);
// Send buy order
if(Trade.Buy(lotSize, _Symbol, SpotPrice, sl, tp, "OI Mean Reversion BUY"))
{
DailyTradeCount++;
LastTradeTime = TimeCurrent();
Print("BUY order executed. Lot: ", lotSize, " Price: ", SpotPrice);
}
else
{
Print("BUY order failed. Error: ", Trade.ResultRetcodeDescription());
}
}
//+------------------------------------------------------------------+
//| Calculate Lot Size |
//+------------------------------------------------------------------+
double CalculateLotSize(ENUM_POSITION_TYPE tradeType)
{
if(!InpUseMoneyManagement)
return NormalizeLot(InpLotSize);
double balance = AccountInfo.Balance();
double riskAmount = balance * (InpRiskPercent / 100.0);
double stopLossPrice = CalculateStopLoss(tradeType, SpotPrice);
double stopLossPoints = MathAbs(SpotPrice - stopLossPrice) / _Point;
double tickValue = SymbolInfo.TickValue();
double lotSize = riskAmount / (stopLossPoints * tickValue);
return NormalizeLot(lotSize);
}
//+------------------------------------------------------------------+
//| Calculate Stop Loss |
//+------------------------------------------------------------------+
double CalculateStopLoss(ENUM_POSITION_TYPE tradeType, double entryPrice)
{
if(!InpUseStopLoss)
return 0.0;
double slPoints = InpStopLossPoints * _Point;
if(tradeType == POSITION_TYPE_BUY)
return entryPrice - slPoints;
else
return entryPrice + slPoints;
}
//+------------------------------------------------------------------+
//| Calculate Take Profit |
//+------------------------------------------------------------------+
double CalculateTakeProfit(ENUM_POSITION_TYPE tradeType, double entryPrice)
{
if(!InpUseTakeProfit)
return 0.0;
double tpPoints = InpTakeProfitPoints * _Point;
if(tradeType == POSITION_TYPE_BUY)
return entryPrice + tpPoints;
else
return entryPrice - tpPoints;
}
//+------------------------------------------------------------------+
//| Manage Positions |
//+------------------------------------------------------------------+
void ManagePositions()
{
for(int i = PositionsTotal() - 1; i >= 0; i--)
{
if(PositionInfo.SelectByIndex(i))
{
if(PositionInfo.Symbol() == _Symbol && PositionInfo.Magic() == InpMagicNumber)
{
// Check for trailing stop
if(InpUseTrailingStop)
{
ApplyTrailingStop(i);
}
// Check for soft stop loss
if(InpUseSoftStopLoss)
{
CheckSoftStopLoss(i);
}
// Check for take profit at mid level
CheckMidLevelExit(i);
}
}
}
}
//+------------------------------------------------------------------+
//| Apply Trailing Stop |
//+------------------------------------------------------------------+
void ApplyTrailingStop(int positionIndex)
{
if(!PositionInfo.SelectByIndex(positionIndex))
return;
double currentPrice = PositionInfo.PositionType() == POSITION_TYPE_BUY ?
SymbolInfo.Bid() : SymbolInfo.Ask();
double openPrice = PositionInfo.PriceOpen();
double currentSL = PositionInfo.StopLoss();
double pointsProfit = MathAbs(currentPrice - openPrice) / _Point;
if(pointsProfit > InpTrailingStartPoints)
{
double newSL = 0;
double trailPoints = InpTrailingStepPoints * _Point;
if(PositionInfo.PositionType() == POSITION_TYPE_BUY)
{
newSL = currentPrice - trailPoints;
if(newSL > currentSL && newSL > openPrice)
{
Trade.PositionModify(_Symbol, newSL, PositionInfo.TakeProfit());
}
}
else
{
newSL = currentPrice + trailPoints;
if(newSL < currentSL && newSL < openPrice)
{
Trade.PositionModify(_Symbol, newSL, PositionInfo.TakeProfit());
}
}
}
}
//+------------------------------------------------------------------+
//| Check Soft Stop Loss |
//+------------------------------------------------------------------+
void CheckSoftStopLoss(int positionIndex)
{
if(!PositionInfo.SelectByIndex(positionIndex))
return;
double currentPrice = PositionInfo.PositionType() == POSITION_TYPE_BUY ?
SymbolInfo.Bid() : SymbolInfo.Ask();
double stopLossPrice = CalculateStopLoss(PositionInfo.PositionType(),
PositionInfo.PriceOpen());
if((PositionInfo.PositionType() == POSITION_TYPE_BUY && currentPrice <= stopLossPrice) ||
(PositionInfo.PositionType() == POSITION_TYPE_SELL && currentPrice >= stopLossPrice))
{
Trade.PositionClose(_Symbol);
ConsecutiveLosses++;
DailyLoss += PositionInfo.Profit();
}
}
//+------------------------------------------------------------------+
//| Check Mid Level Exit |
//+------------------------------------------------------------------+
void CheckMidLevelExit(int positionIndex)
{
if(!PositionInfo.SelectByIndex(positionIndex))
return;
double currentPrice = PositionInfo.PositionType() == POSITION_TYPE_BUY ?
SymbolInfo.Bid() : SymbolInfo.Ask();
// Close if price reaches mid level
if(MathAbs(currentPrice - LevelMid) <= 10 * _Point)
{
Trade.PositionClosePartial(_Symbol, PositionInfo.Volume() * 0.5); // Close half
}
}
//+------------------------------------------------------------------+
//| Close All Positions |
//+------------------------------------------------------------------+
void CloseAllPositions()
{
for(int i = PositionsTotal() - 1; i >= 0; i--)
{
if(PositionInfo.SelectByIndex(i))
{
if(PositionInfo.Symbol() == _Symbol && PositionInfo.Magic() == InpMagicNumber)
{
Trade.PositionClose(_Symbol);
}
}
}
}
//+------------------------------------------------------------------+
//| Check Existing Positions (Auto Recovery) |
//+------------------------------------------------------------------+
void CheckExistingPositions()
{
int count = 0;
for(int i = 0; i < PositionsTotal(); i++)
{
if(PositionInfo.SelectByIndex(i))
{
if(PositionInfo.Symbol() == _Symbol && PositionInfo.Magic() == InpMagicNumber)
{
count++;
Print("Found existing position #", i+1,
" Type: ", EnumToString(PositionInfo.PositionType()),
" Volume: ", PositionInfo.Volume(),
" Profit: ", PositionInfo.Profit());
}
}
}
if(count > 0)
{
Print("Auto-recovery: ", count, " positions restored");
}
}
//+------------------------------------------------------------------+
//| Check Daily Reset |
//+------------------------------------------------------------------+
void CheckDailyReset()
{
MqlDateTime timeNow, lastReset;
TimeCurrent(timeNow);
TimeToStruct(LastResetDate, lastReset);
if(timeNow.day != lastReset.day ||
timeNow.mon != lastReset.mon ||
timeNow.year != lastReset.year)
{
// New day, reset statistics
DailyTradeCount = 0;
DailyPnL = 0.0;
DailyProfit = 0.0;
DailyLoss = 0.0;
ConsecutiveLosses = 0;
LastResetDate = TimeCurrent();
TradingEnabled = true;
Print("Daily statistics reset");
}
}
//+------------------------------------------------------------------+
//| Create Dashboard |
//+------------------------------------------------------------------+
void CreateDashboard()
{
// Create main panel - ตั้งค่า Z-Order ให้สูงขึ้น
CreatePanel("MainPanel", 10, 20, 850, 180, PanelColor, BORDER_SUNKEN);
// Create section panels - ตั้งค่า Z-Order ให้สูงขึ้น และ BACK = false
CreatePanel("PricePanel", 20, 30, 260, 70, C'40,40,40', BORDER_FLAT);
CreatePanel("DeltaPanel", 290, 30, 260, 70, C'40,40,40', BORDER_FLAT);
CreatePanel("LevelsPanel", 560, 30, 290, 70, C'40,40,40', BORDER_FLAT);
CreatePanel("StatsPanel", 20, 110, 410, 80, C'40,40,40', BORDER_FLAT);
CreatePanel("TradingPanel", 440, 110, 410, 80, C'40,40,40', BORDER_FLAT);
// Initial labels
UpdateDashboard();
}
//+------------------------------------------------------------------+
//| Update Dashboard |
//+------------------------------------------------------------------+
void UpdateDashboard()
{
// Calculate metrics
double balance = AccountInfo.Balance();
double equity = AccountInfo.Equity();
double dailyGainPercent = balance > 0 ? ((equity - balance) / balance) * 100 : 0;
double maxDD = balance > 0 ? ((balance - equity) / balance) * 100 : 0;
// Get ATR
double atrValues[];
ArraySetAsSeries(atrValues, true);
double atr = 0;
double atrPercent = 0;
if(CopyBuffer(ATRHandle, 0, 0, 1, atrValues) >= 1)
{
atr = atrValues[0];
atrPercent = (atr / SpotPrice) * 100;
}
// Get market phase
string marketPhase = GetMarketPhaseString();
color phaseColor = GetMarketPhaseColor();
// Calculate distances to key levels
double distToUpper = LevelUpper2 > 0 ? ((LevelUpper2 - SpotPrice) / SpotPrice) * 100 : 0;
double distToLower = LevelLower2 > 0 ? ((SpotPrice - LevelLower2) / SpotPrice) * 100 : 0;
// Find nearest OI levels
double nearestCall = FindNearestLevel(SpotPrice, CallLevels, true);
double nearestPut = FindNearestLevel(SpotPrice, PutLevels, false);
// Price Section
UpdateLabel("PriceTitle", 30, 35, "PRICE INFORMATION", clrYellow, 10);
UpdateLabel("SpotPrice", 30, 55, "Spot: " + DoubleToString(SpotPrice, _Digits), TextColor, 9);
UpdateLabel("FuturePrice", 30, 70, "Future: " + DoubleToString(FuturePrice, _Digits), TextColor, 9);
UpdateLabel("Spread", 150, 55, "Spread: " + IntegerToString((int)SymbolInfo.Spread()), TextColor, 9);
// Delta Section
UpdateLabel("DeltaTitle", 300, 35, "DELTA & DEVIATION", clrYellow, 10);
UpdateLabel("DeltaValue", 300, 55, "ΔPrice: " + DoubleToString(DeltaPrice, 4),
DeltaPrice > 0 ? clrLime : clrRed, 9);
UpdateLabel("DeltaEMA", 300, 70, "ΔEMA: " + DoubleToString(DeltaEMA, 4), TextColor, 9);
UpdateLabel("Deviation", 420, 55, "Deviation: " + DoubleToString(DeltaDeviation/_Point, 1) + " pts",
MathAbs(DeltaDeviation) > InpDeviationThreshold * _Point ? WarningColor : TextColor, 9);
// Levels Section
UpdateLabel("LevelsTitle", 570, 35, "OI & KEY LEVELS", clrYellow, 10);
UpdateLabel("NearestCALL", 570, 55, "Nearest CALL: " + (nearestCall>0?DoubleToString(nearestCall, _Digits):"N/A"), clrCyan, 9);
UpdateLabel("NearestPUT", 570, 70, "Nearest PUT: " + (nearestPut>0?DoubleToString(nearestPut, _Digits):"N/A"), clrCyan, 9);
UpdateLabel("DistUpper", 725, 55, "%Far Upper: " + DoubleToString(distToUpper, 2), TextColor, 9);
UpdateLabel("DistLower", 725, 70, "%Far Lower: " + DoubleToString(distToLower, 2), TextColor, 9);
// Statistics Section
UpdateLabel("StatsTitle", 30, 115, "STATISTICS", clrYellow, 10);
UpdateLabel("DailyTrades", 30, 135, "Trades Today: " + IntegerToString(DailyTradeCount), TextColor, 9);
UpdateLabel("DailyGain", 30, 150, "%Gain: " + DoubleToString(dailyGainPercent, 2),
dailyGainPercent >= 0 ? ProfitColor : LossColor, 9);
UpdateLabel("MaxDD", 30, 165, "%Max DD: " + DoubleToString(maxDD, 2),
maxDD > 5 ? WarningColor : TextColor, 9);
UpdateLabel("ConsecLosses", 180, 135, "Consec. Losses: " + IntegerToString(ConsecutiveLosses),
ConsecutiveLosses > 0 ? WarningColor : TextColor, 9);
UpdateLabel("DailyProfit", 180, 150, "Daily P/L: " + DoubleToString(DailyProfit + DailyLoss, 2),
(DailyProfit + DailyLoss) >= 0 ? ProfitColor : LossColor, 9);
// Trading Section
UpdateLabel("TradingTitle", 450, 115, "TRADING STATUS", clrYellow, 10);
UpdateLabel("MarketPhase", 450, 135, "Market: " + marketPhase, phaseColor, 9);
UpdateLabel("TradingStatus", 450, 150, "Status: " + (TradingEnabled ? "ACTIVE" : "DISABLED"),
TradingEnabled ? clrLime : clrRed, 9);
UpdateLabel("ATRPercent", 450, 165, "ATR%: " + DoubleToString(atrPercent, 2),
atrPercent > InpMaxATRPercent ? WarningColor : TextColor, 9);
// Active Position
string posInfo = "No Active Position";
color posColor = clrGray;
double posProfit = 0;
if(PositionsTotal() > 0)
{
for(int i = 0; i < PositionsTotal(); i++)
{
if(PositionInfo.SelectByIndex(i))
{
if(PositionInfo.Symbol() == _Symbol && PositionInfo.Magic() == InpMagicNumber)
{
posInfo = PositionInfo.PositionType() == POSITION_TYPE_BUY ?
"LONG (" + DoubleToString(PositionInfo.Volume(), 2) + ")" :
"SHORT (" + DoubleToString(PositionInfo.Volume(), 2) + ")";
posColor = PositionInfo.PositionType() == POSITION_TYPE_BUY ? clrLime : clrRed;
posProfit = PositionInfo.Profit();
break;
}
}
}
}
UpdateLabel("PositionInfo", 600, 135, "Position: " + posInfo, posColor, 9);
UpdateLabel("PositionProfit", 600, 150, "P/L: " + DoubleToString(posProfit, 2),
posProfit >= 0 ? ProfitColor : LossColor, 9);
// News Block Warning
if(NewsBlockActive)
{
UpdateLabel("NewsWarning", 600, 165, "NEWS BLOCK ACTIVE", clrRed, 9);
}
else
{
ObjectDelete(chart_id, "NewsWarning");
}
}
//+------------------------------------------------------------------+
//| Update Label |
//+------------------------------------------------------------------+
void UpdateLabel(string name, int x, int y, string text, color clr, int fontSize = 9)
{
if(ObjectFind(chart_id, name) < 0)
{
ObjectCreate(chart_id, name, OBJ_LABEL, 0, 0, 0);
ObjectSetInteger(chart_id, name, OBJPROP_XDISTANCE, x);
ObjectSetInteger(chart_id, name, OBJPROP_YDISTANCE, y);
ObjectSetInteger(chart_id, name, OBJPROP_COLOR, clr);
ObjectSetInteger(chart_id, name, OBJPROP_FONTSIZE, fontSize);
ObjectSetString(chart_id, name, OBJPROP_FONT, "Consolas");
ObjectSetInteger(chart_id, name, OBJPROP_BACK, false);
ObjectSetInteger(chart_id, name, OBJPROP_SELECTABLE, false);
ObjectSetInteger(chart_id, name, OBJPROP_HIDDEN, true);
// ตั้งค่า Z-Order ให้สูง
ObjectSetInteger(chart_id, name, OBJPROP_ZORDER, 1002);
}
ObjectSetString(chart_id, name, OBJPROP_TEXT, text);
ObjectSetInteger(chart_id, name, OBJPROP_COLOR, clr);
}
//+------------------------------------------------------------------+
//| Find Nearest Level |
//+------------------------------------------------------------------+
double FindNearestLevel(double price, double &levels[], bool findAbove)
{
double nearest = 0;
double minDist = DBL_MAX;
for(int i = 0; i < ArraySize(levels); i++)
{
if(levels[i] <= 0) continue;
double dist = MathAbs(price - levels[i]);
if(findAbove)
{
if(levels[i] >= price && dist < minDist)
{
minDist = dist;
nearest = levels[i];
}
}
else
{
if(levels[i] <= price && dist < minDist)
{
minDist = dist;
nearest = levels[i];
}
}
}
return nearest;
}
//+------------------------------------------------------------------+
//| Get Market Phase String |
//+------------------------------------------------------------------+
string GetMarketPhaseString()
{
ENUM_MARKET_PHASE phase = GetMarketPhase();
switch(phase)
{
case PHASE_BULLISH: return "Bullish";
case PHASE_BEARISH: return "Bearish";
case PHASE_SIDEWAYS: return "Sideways";
default: return "Neutral";
}
}
//+------------------------------------------------------------------+
//| Get Market Phase Color |
//+------------------------------------------------------------------+
color GetMarketPhaseColor()
{
ENUM_MARKET_PHASE phase = GetMarketPhase();
switch(phase)
{
case PHASE_BULLISH: return clrLime;
case PHASE_BEARISH: return clrRed;
case PHASE_SIDEWAYS: return clrYellow;
default: return clrGray;
}
}
//+------------------------------------------------------------------+
//| String Split Function |
//+------------------------------------------------------------------+
int StringSplit(string text, string delimiter, string &result[])
{
int count = 0;
int pos = 0;
int len = StringLen(delimiter);
while(pos < StringLen(text))
{
int nextPos = StringFind(text, delimiter, pos);
if(nextPos == -1) nextPos = StringLen(text);
string substr = StringSubstr(text, pos, nextPos - pos);
ArrayResize(result, count + 1);
result[count] = substr;
count++;
pos = nextPos + len;
}
return count;
}
//+------------------------------------------------------------------+