277 lines
8.4 KiB
MQL5
277 lines
8.4 KiB
MQL5
//+------------------------------------------------------------------+
|
|
//| EAState.mqh |
|
|
//| Copyright 2025, Your Company Name |
|
|
//| https://www.yoursite.com |
|
|
//+------------------------------------------------------------------+
|
|
#property copyright "Copyright 2025, Your Company Name"
|
|
#property link "https://www.yoursite.com"
|
|
#property version "1.00"
|
|
#property strict
|
|
|
|
#include "EALogger.mqh"
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Market data state |
|
|
//+------------------------------------------------------------------+
|
|
struct SMarketData
|
|
{
|
|
MqlTick lastTick; // Last tick data
|
|
datetime lastUpdate; // Last update time
|
|
double bid, ask; // Current prices
|
|
double spread; // Current spread
|
|
|
|
// Initialize structure
|
|
void Init()
|
|
{
|
|
ZeroMemory(lastTick);
|
|
lastUpdate = 0;
|
|
bid = ask = spread = 0.0;
|
|
}
|
|
};
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Trade state |
|
|
//+------------------------------------------------------------------+
|
|
struct STradeState
|
|
{
|
|
int totalPositions; // Total open positions
|
|
double totalProfit; // Total profit/loss
|
|
double maxDrawdown; // Maximum drawdown
|
|
datetime lastTradeTime; // Time of last trade
|
|
|
|
// Initialize structure
|
|
void Init()
|
|
{
|
|
totalPositions = 0;
|
|
totalProfit = 0.0;
|
|
maxDrawdown = 0.0;
|
|
lastTradeTime = 0;
|
|
}
|
|
};
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| EA State Manager |
|
|
//+------------------------------------------------------------------+
|
|
class CEAState
|
|
{
|
|
private:
|
|
CEALogger* m_logger; // Logger instance
|
|
SMarketData m_marketData; // Market data state
|
|
STradeState m_tradeState; // Trade state
|
|
|
|
// Indicators
|
|
int m_maHandle; // Moving average handle
|
|
double m_maBuffer[]; // MA buffer
|
|
|
|
// Locks
|
|
bool m_isUpdating; // Update flag
|
|
|
|
// Internal methods
|
|
void UpdateIndicators();
|
|
|
|
public:
|
|
CEAState() : m_logger(NULL), m_maHandle(INVALID_HANDLE), m_isUpdating(false)
|
|
{
|
|
m_marketData.Init();
|
|
m_tradeState.Init();
|
|
}
|
|
|
|
~CEAState() { Deinitialize(); }
|
|
|
|
// Initialization
|
|
bool Initialize(CEALogger* logger);
|
|
void Deinitialize();
|
|
|
|
// State updates
|
|
void UpdateMarketData(const string symbol, ENUM_TIMEFRAMES timeframe);
|
|
void UpdateLastTick(const CTickEvent* tick);
|
|
void UpdateTradeState();
|
|
|
|
// Getters
|
|
const SMarketData& GetMarketData() const { return m_marketData; }
|
|
const STradeState& GetTradeState() const { return m_tradeState; }
|
|
|
|
// Indicator access
|
|
double GetMA(int shift = 0) const;
|
|
|
|
// State validation
|
|
bool IsMarketOpen() const;
|
|
bool IsTradingAllowed() const;
|
|
};
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Initialize state manager |
|
|
//+------------------------------------------------------------------+
|
|
bool CEAState::Initialize(CEALogger* logger)
|
|
{
|
|
if (logger == NULL)
|
|
return false;
|
|
|
|
m_logger = logger;
|
|
|
|
// Initialize indicators
|
|
m_maHandle = iMA(NULL, 0, 14, 0, MODE_SMA, PRICE_CLOSE);
|
|
if (m_maHandle == INVALID_HANDLE)
|
|
{
|
|
m_logger.LogError("Failed to initialize MA indicator");
|
|
return false;
|
|
}
|
|
|
|
// Set indicator buffers
|
|
ArraySetAsSeries(m_maBuffer, true);
|
|
|
|
m_logger.LogInfo("State manager initialized");
|
|
return true;
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Deinitialize state manager |
|
|
//+------------------------------------------------------------------+
|
|
void CEAState::Deinitialize()
|
|
{
|
|
// Release indicators
|
|
if (m_maHandle != INVALID_HANDLE)
|
|
{
|
|
IndicatorRelease(m_maHandle);
|
|
m_maHandle = INVALID_HANDLE;
|
|
}
|
|
|
|
// Clear buffers
|
|
ArrayFree(m_maBuffer);
|
|
|
|
m_logger = NULL;
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Update market data |
|
|
//+------------------------------------------------------------------+
|
|
void CEAState::UpdateMarketData(const string symbol, ENUM_TIMEFRAMES timeframe)
|
|
{
|
|
if (m_isUpdating)
|
|
return;
|
|
|
|
m_isUpdating = true;
|
|
|
|
// Update tick data
|
|
MqlTick lastTick;
|
|
if (SymbolInfoTick(symbol, lastTick))
|
|
{
|
|
m_marketData.lastTick = lastTick;
|
|
m_marketData.bid = lastTick.bid;
|
|
m_marketData.ask = lastTick.ask;
|
|
m_marketData.spread = lastTick.ask - lastTick.bid;
|
|
m_marketData.lastUpdate = TimeCurrent();
|
|
}
|
|
|
|
// Update indicators
|
|
UpdateIndicators();
|
|
|
|
m_isUpdating = false;
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Update last tick |
|
|
//+------------------------------------------------------------------+
|
|
void CEAState::UpdateLastTick(const CTickEvent* tick)
|
|
{
|
|
if (tick == NULL)
|
|
return;
|
|
|
|
// Update tick data from event
|
|
// Implementation depends on CTickEvent structure
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Update trade state |
|
|
//+------------------------------------------------------------------+
|
|
void CEAState::UpdateTradeState()
|
|
{
|
|
// Update positions count
|
|
m_tradeState.totalPositions = PositionsTotal();
|
|
|
|
// Update total profit
|
|
double totalProfit = 0;
|
|
for (int i = 0; i < m_tradeState.totalPositions; i++)
|
|
{
|
|
if (m_position.SelectByIndex(i))
|
|
totalProfit += m_position.Profit() + m_position.Swap() + m_position.Commission();
|
|
}
|
|
m_tradeState.totalProfit = totalProfit;
|
|
|
|
// Update max drawdown
|
|
if (totalProfit < m_tradeState.maxDrawdown)
|
|
m_tradeState.maxDrawdown = totalProfit;
|
|
|
|
// Update last trade time
|
|
if (m_tradeState.totalPositions > 0)
|
|
m_tradeState.lastTradeTime = TimeCurrent();
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Update indicators |
|
|
//+------------------------------------------------------------------+
|
|
void CEAState::UpdateIndicators()
|
|
{
|
|
if (m_maHandle == INVALID_HANDLE)
|
|
return;
|
|
|
|
// Copy MA values
|
|
if (CopyBuffer(m_maHandle, 0, 0, 1, m_maBuffer) != 1)
|
|
{
|
|
if (m_logger != NULL)
|
|
m_logger.LogError("Failed to copy MA buffer");
|
|
return;
|
|
}
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Get moving average value |
|
|
//+------------------------------------------------------------------+
|
|
double CEAState::GetMA(int shift = 0) const
|
|
{
|
|
if (shift < 0 || shift >= ArraySize(m_maBuffer))
|
|
return 0.0;
|
|
|
|
return m_maBuffer[shift];
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Check if market is open |
|
|
//+------------------------------------------------------------------+
|
|
bool CEAState::IsMarketOpen() const
|
|
{
|
|
// Check if current time is within trading hours
|
|
MqlDateTime dt;
|
|
TimeToStruct(TimeCurrent(), dt);
|
|
|
|
// Example: Check if it's a weekday and within trading hours
|
|
if (dt.day_of_week == 0 || dt.day_of_week == 6) // Weekend
|
|
return false;
|
|
|
|
// Example: Check trading hours (9:30 AM - 4:00 PM)
|
|
int currentMinute = dt.hour * 60 + dt.min;
|
|
if (currentMinute < 570 || currentMinute >= 960) // Before 9:30 AM or after 4:00 PM
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Check if trading is allowed |
|
|
//+------------------------------------------------------------------+
|
|
bool CEAState::IsTradingAllowed() const
|
|
{
|
|
// Check if market is open
|
|
if (!IsMarketOpen())
|
|
return false;
|
|
|
|
// Check if max positions reached
|
|
if (m_tradeState.totalPositions >= 10) // Example limit
|
|
return false;
|
|
|
|
// Check if max drawdown reached
|
|
if (m_tradeState.maxDrawdown <= -1000.0) // Example limit
|
|
return false;
|
|
|
|
return true;
|
|
}
|