2268 lines
80 KiB
Plaintext
2268 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_MANUAL;
|
|
input string InpOICsvPath = "\\Files\\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()
|
|
{
|
|
string filename = InpOICsvPath;
|
|
int filehandle = FileOpen(filename, FILE_READ|FILE_CSV|FILE_ANSI, ',');
|
|
|
|
if(filehandle == INVALID_HANDLE)
|
|
{
|
|
Print("Error opening CSV file: ", filename);
|
|
InitializeOILevels();
|
|
return;
|
|
}
|
|
|
|
int callIndex = 0;
|
|
int putIndex = 0;
|
|
double futurePrice = 0.0;
|
|
bool isFirstLine = true;
|
|
|
|
while(!FileIsEnding(filehandle) && (callIndex < 3 || putIndex < 3))
|
|
{
|
|
string row = FileReadString(filehandle);
|
|
|
|
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++;
|
|
}
|
|
else if(type == "PUT" && putIndex < 3)
|
|
{
|
|
PutLevels[putIndex] = strike;
|
|
PutOI[putIndex] = oi;
|
|
putIndex++;
|
|
}
|
|
}
|
|
}
|
|
|
|
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;
|
|
}
|
|
//+------------------------------------------------------------------+ |