mirror of
https://github.com/dinethlive/dbasket-EA.git
synced 2026-08-13 18:58:11 +00:00
525 lines
18 KiB
Plaintext
525 lines
18 KiB
Plaintext
//+------------------------------------------------------------------+
|
|
//| DBasket_Structures.mqh |
|
|
//| D-Basket Correlation Hedging EA |
|
|
//| Core Data Structures |
|
|
//+------------------------------------------------------------------+
|
|
#property copyright "D-Basket EA"
|
|
#property version "1.00"
|
|
#property strict
|
|
|
|
#ifndef DBASKET_STRUCTURES_MQH
|
|
#define DBASKET_STRUCTURES_MQH
|
|
|
|
#include "DBasket_Defines.mqh"
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Correlation Data Structure |
|
|
//| Encapsulates all correlation engine outputs |
|
|
//+------------------------------------------------------------------+
|
|
struct CorrelationData
|
|
{
|
|
// Primary correlation coefficients
|
|
double corrAUDCAD_NZDCAD; // Main correlation: AUDCAD vs NZDCAD
|
|
double corrAUDCAD_AUDNZD; // Validation: AUDCAD vs AUDNZD
|
|
double corrNZDCAD_AUDNZD; // Validation: NZDCAD vs AUDNZD
|
|
|
|
// Spread and divergence metrics
|
|
double syntheticRatio; // AUDCAD / NZDCAD
|
|
double actualAUDNZD; // Current AUDNZD close price
|
|
double spreadValue; // syntheticRatio - actualAUDNZD
|
|
double spreadZScore; // Z-score of current spread
|
|
|
|
// Statistical parameters
|
|
double spreadMean; // Historical mean of spread
|
|
double spreadStdDev; // Historical standard deviation
|
|
|
|
// Metadata
|
|
datetime calculationTime; // Timestamp of last calculation
|
|
bool isValid; // False if insufficient data or error
|
|
int lookbackPeriod; // Number of bars used
|
|
string invalidReason; // Description if isValid == false
|
|
|
|
// Constructor
|
|
void CorrelationData()
|
|
{
|
|
Reset();
|
|
}
|
|
|
|
// Reset to default values
|
|
void Reset()
|
|
{
|
|
corrAUDCAD_NZDCAD = 0;
|
|
corrAUDCAD_AUDNZD = 0;
|
|
corrNZDCAD_AUDNZD = 0;
|
|
syntheticRatio = 0;
|
|
actualAUDNZD = 0;
|
|
spreadValue = 0;
|
|
spreadZScore = 0;
|
|
spreadMean = 0;
|
|
spreadStdDev = 0;
|
|
calculationTime = 0;
|
|
isValid = false;
|
|
lookbackPeriod = 0;
|
|
invalidReason = "";
|
|
}
|
|
};
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Position State Structure |
|
|
//| Track individual position within a basket |
|
|
//+------------------------------------------------------------------+
|
|
struct PositionState
|
|
{
|
|
// Position identification
|
|
ulong ticket; // MT5 position ticket
|
|
string symbol; // Symbol name
|
|
int symbolIndex; // 0=AUDCAD, 1=NZDCAD, 2=AUDNZD
|
|
|
|
// Position parameters
|
|
ENUM_POSITION_TYPE type; // POSITION_TYPE_BUY or SELL
|
|
double lots; // Position volume
|
|
double openPrice; // Entry price
|
|
datetime openTime; // Position open timestamp
|
|
|
|
// Risk management
|
|
double stopLoss; // SL price (0 if none)
|
|
double takeProfit; // TP price (0 if none)
|
|
|
|
// P&L tracking
|
|
double currentPrice; // Last known price
|
|
double unrealizedPL; // Floating profit/loss
|
|
double swap; // Accumulated swap
|
|
double commission; // Commission paid
|
|
|
|
// State flags
|
|
bool isOpen; // True if position exists
|
|
string comment; // Position comment
|
|
|
|
// Constructor
|
|
void PositionState()
|
|
{
|
|
Reset();
|
|
}
|
|
|
|
// Reset to default values
|
|
void Reset()
|
|
{
|
|
ticket = 0;
|
|
symbol = "";
|
|
symbolIndex = -1;
|
|
type = POSITION_TYPE_BUY;
|
|
lots = 0;
|
|
openPrice = 0;
|
|
openTime = 0;
|
|
stopLoss = 0;
|
|
takeProfit = 0;
|
|
currentPrice = 0;
|
|
unrealizedPL = 0;
|
|
swap = 0;
|
|
commission = 0;
|
|
isOpen = false;
|
|
comment = "";
|
|
}
|
|
};
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Basket State Structure |
|
|
//| Tracks a complete 3-leg basket |
|
|
//+------------------------------------------------------------------+
|
|
struct BasketState
|
|
{
|
|
// Basket identification
|
|
int basketID; // Unique basket identifier
|
|
ENUM_BASKET_STATE state; // Current basket state
|
|
ENUM_BASKET_SIGNAL direction; // LONG or SHORT basket
|
|
|
|
// Timing
|
|
datetime openTime; // Basket creation timestamp
|
|
datetime lastUpdateTime; // Last state update
|
|
int barsHeld; // Number of bars position held
|
|
|
|
// Position tracking for each leg
|
|
PositionState positions[NUM_SYMBOLS]; // All three legs
|
|
|
|
// Entry conditions snapshot
|
|
double entryZScore; // Z-score at entry
|
|
double entryCorrelation; // Primary correlation at entry
|
|
double entrySpread; // Spread value at entry
|
|
|
|
// P&L tracking
|
|
double unrealizedPL; // Total floating P&L
|
|
double realizedPL; // Realized P&L (if partially closed)
|
|
|
|
// Exit tracking
|
|
ENUM_EXIT_REASON exitReason; // Reason for exit (when closed)
|
|
|
|
// Constructor
|
|
void BasketState()
|
|
{
|
|
Reset();
|
|
}
|
|
|
|
// Reset to default values
|
|
void Reset()
|
|
{
|
|
basketID = 0;
|
|
state = BASKET_NONE;
|
|
direction = SIGNAL_NONE;
|
|
openTime = 0;
|
|
lastUpdateTime = 0;
|
|
barsHeld = 0;
|
|
entryZScore = 0;
|
|
entryCorrelation = 0;
|
|
entrySpread = 0;
|
|
unrealizedPL = 0;
|
|
realizedPL = 0;
|
|
exitReason = EXIT_MANUAL;
|
|
|
|
for(int i = 0; i < NUM_SYMBOLS; i++)
|
|
positions[i].Reset();
|
|
}
|
|
|
|
// Check if basket is active (has open positions)
|
|
bool IsActive() const
|
|
{
|
|
return (state == BASKET_OPEN || state == BASKET_PARTIAL);
|
|
}
|
|
|
|
// Get total lots across all legs
|
|
double GetTotalLots() const
|
|
{
|
|
double total = 0;
|
|
for(int i = 0; i < NUM_SYMBOLS; i++)
|
|
if(positions[i].isOpen)
|
|
total += positions[i].lots;
|
|
return total;
|
|
}
|
|
|
|
// Count open legs
|
|
int CountOpenLegs() const
|
|
{
|
|
int count = 0;
|
|
for(int i = 0; i < NUM_SYMBOLS; i++)
|
|
if(positions[i].isOpen)
|
|
count++;
|
|
return count;
|
|
}
|
|
};
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Performance Metrics Structure |
|
|
//| Track EA performance in real-time |
|
|
//+------------------------------------------------------------------+
|
|
struct PerformanceMetrics
|
|
{
|
|
// Account metrics
|
|
double startingBalance; // Initial balance at EA start
|
|
double currentBalance; // Current balance
|
|
double currentEquity; // Current equity
|
|
double peakEquity; // Highest equity reached
|
|
|
|
// P&L tracking
|
|
double realizedPL; // Total closed P&L
|
|
double unrealizedPL; // Total floating P&L
|
|
double netPL; // realizedPL + unrealizedPL
|
|
|
|
// Trade statistics
|
|
int totalBaskets; // Total baskets opened
|
|
int closedBaskets; // Total baskets closed
|
|
int winningBaskets; // Profitable closes
|
|
int losingBaskets; // Loss closes
|
|
double winRate; // winningBaskets / closedBaskets
|
|
double avgWin; // Average winning basket P&L
|
|
double avgLoss; // Average losing basket P&L
|
|
double profitFactor; // Sum(wins) / abs(Sum(losses))
|
|
|
|
// Risk metrics
|
|
double currentDrawdownPercent; // Current drawdown from peak
|
|
double maxDrawdownPercent; // Maximum drawdown
|
|
double maxDrawdownValue; // Max drawdown in currency
|
|
|
|
// Daily tracking
|
|
double dailyPnL; // Today's P&L
|
|
double dailyStartEquity; // Equity at day start
|
|
datetime dailyResetTime; // Last daily reset timestamp
|
|
int consecutiveLosses; // Current losing streak
|
|
int maxConsecutiveLosses; // Worst losing streak
|
|
|
|
// Operational metrics
|
|
int totalSignals; // Signals generated
|
|
int executedSignals; // Signals that became trades
|
|
int filteredSignals; // Signals blocked by filters
|
|
int erroredTrades; // Trade execution errors
|
|
datetime lastTradeTime; // Last basket open/close
|
|
|
|
// Timing
|
|
datetime metricsStartTime; // When tracking started
|
|
int uptimeSeconds; // Seconds since start
|
|
|
|
// Constructor
|
|
void PerformanceMetrics()
|
|
{
|
|
Reset();
|
|
}
|
|
|
|
// Reset to default values
|
|
void Reset()
|
|
{
|
|
startingBalance = 0;
|
|
currentBalance = 0;
|
|
currentEquity = 0;
|
|
peakEquity = 0;
|
|
realizedPL = 0;
|
|
unrealizedPL = 0;
|
|
netPL = 0;
|
|
totalBaskets = 0;
|
|
closedBaskets = 0;
|
|
winningBaskets = 0;
|
|
losingBaskets = 0;
|
|
winRate = 0;
|
|
avgWin = 0;
|
|
avgLoss = 0;
|
|
profitFactor = 0;
|
|
currentDrawdownPercent = 0;
|
|
maxDrawdownPercent = 0;
|
|
maxDrawdownValue = 0;
|
|
dailyPnL = 0;
|
|
dailyStartEquity = 0;
|
|
dailyResetTime = 0;
|
|
consecutiveLosses = 0;
|
|
maxConsecutiveLosses = 0;
|
|
totalSignals = 0;
|
|
executedSignals = 0;
|
|
filteredSignals = 0;
|
|
erroredTrades = 0;
|
|
lastTradeTime = 0;
|
|
metricsStartTime = 0;
|
|
uptimeSeconds = 0;
|
|
}
|
|
};
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Trade Log Entry Structure |
|
|
//| Record of trade operations for audit |
|
|
//+------------------------------------------------------------------+
|
|
struct TradeLogEntry
|
|
{
|
|
// Trade identification
|
|
int entryID; // Sequential log entry number
|
|
datetime timestamp; // Operation timestamp
|
|
string operation; // Operation type description
|
|
|
|
// Trade details
|
|
int basketID; // Basket identifier (-1 if N/A)
|
|
string symbol; // Symbol traded
|
|
ulong ticket; // Position ticket
|
|
ENUM_ORDER_TYPE orderType; // Buy/sell
|
|
double lots; // Volume
|
|
double price; // Execution price
|
|
|
|
// Outcome
|
|
bool success; // Operation succeeded
|
|
int errorCode; // MT5 error code
|
|
string errorDescription; // Error message
|
|
double pl; // P&L (for closes)
|
|
|
|
// Context
|
|
double accountBalance; // Balance at operation
|
|
double accountEquity; // Equity at operation
|
|
double zScore; // Z-score at operation
|
|
double correlation; // Correlation at operation
|
|
|
|
// Constructor
|
|
void TradeLogEntry()
|
|
{
|
|
Reset();
|
|
}
|
|
|
|
// Reset
|
|
void Reset()
|
|
{
|
|
entryID = 0;
|
|
timestamp = 0;
|
|
operation = "";
|
|
basketID = -1;
|
|
symbol = "";
|
|
ticket = 0;
|
|
orderType = ORDER_TYPE_BUY;
|
|
lots = 0;
|
|
price = 0;
|
|
success = false;
|
|
errorCode = 0;
|
|
errorDescription = "";
|
|
pl = 0;
|
|
accountBalance = 0;
|
|
accountEquity = 0;
|
|
zScore = 0;
|
|
correlation = 0;
|
|
}
|
|
};
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Price History Buffer Structure |
|
|
//| Maintains rolling window for correlation calculations |
|
|
//+------------------------------------------------------------------+
|
|
struct PriceHistoryBuffer
|
|
{
|
|
double prices[]; // Price data array
|
|
int size; // Current buffer size
|
|
int head; // Current write position (newest)
|
|
datetime lastUpdateTime; // Last update timestamp
|
|
bool isWarmedUp; // True when fully populated
|
|
|
|
// Constructor
|
|
void PriceHistoryBuffer()
|
|
{
|
|
size = 0;
|
|
head = 0;
|
|
lastUpdateTime = 0;
|
|
isWarmedUp = false;
|
|
}
|
|
|
|
// Initialize buffer with specific size
|
|
bool Initialize(int bufferSize)
|
|
{
|
|
if(bufferSize <= 0 || bufferSize > MAX_LOOKBACK_PERIOD)
|
|
return false;
|
|
|
|
if(ArrayResize(prices, bufferSize) != bufferSize)
|
|
return false;
|
|
|
|
ArrayInitialize(prices, 0);
|
|
size = bufferSize;
|
|
head = 0;
|
|
lastUpdateTime = 0;
|
|
isWarmedUp = false;
|
|
return true;
|
|
}
|
|
|
|
// Add new price (circular buffer pattern)
|
|
void AddPrice(double price, datetime time)
|
|
{
|
|
if(size <= 0)
|
|
return;
|
|
|
|
head = (head + 1) % size;
|
|
prices[head] = price;
|
|
lastUpdateTime = time;
|
|
|
|
// Check if warmed up (simple check - all positions written at least once)
|
|
if(!isWarmedUp && head == size - 1)
|
|
isWarmedUp = true;
|
|
}
|
|
|
|
// Get price at offset from newest (0 = newest, 1 = second newest, etc.)
|
|
double GetPrice(int offset) const
|
|
{
|
|
if(offset < 0 || offset >= size)
|
|
return 0;
|
|
|
|
int realIndex = (head - offset + size) % size;
|
|
return prices[realIndex];
|
|
}
|
|
|
|
// Get all prices in chronological order (oldest first)
|
|
bool GetPricesOrdered(double &output[]) const
|
|
{
|
|
if(ArrayResize(output, size) != size)
|
|
return false;
|
|
|
|
for(int i = 0; i < size; i++)
|
|
{
|
|
int srcIndex = (head - size + 1 + i + size) % size;
|
|
output[i] = prices[srcIndex];
|
|
}
|
|
return true;
|
|
}
|
|
};
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| EA Configuration Structure |
|
|
//| Groups all user-configurable settings |
|
|
//+------------------------------------------------------------------+
|
|
struct EAConfig
|
|
{
|
|
// Symbol configuration
|
|
string symbols[NUM_SYMBOLS]; // Full symbol names with suffix
|
|
ENUM_TIMEFRAMES timeframe; // Timeframe for calculations
|
|
|
|
// Correlation engine parameters
|
|
int lookbackPeriod; // Rolling window size
|
|
int updateIntervalSeconds; // Cache update frequency
|
|
|
|
// Signal generation parameters
|
|
double zScoreEntryThreshold; // Minimum |z-score| for entry
|
|
double zScoreExitThreshold; // Maximum |z-score| for exit
|
|
double minCorrelation; // Minimum acceptable correlation
|
|
double maxSpreadPips; // Maximum spread per symbol
|
|
|
|
// Risk management parameters
|
|
double baseLotSize; // Base lot size per leg
|
|
double riskPercentPerBasket; // Risk % per basket
|
|
double maxDrawdownPercent; // Circuit breaker threshold
|
|
double maxDailyLossPercent; // Daily loss limit %
|
|
double maxDailyLossAmount; // Daily loss limit amount
|
|
int maxOpenBaskets; // Maximum concurrent baskets
|
|
int maxHoldingHours; // Maximum basket hold time
|
|
|
|
// Trading hours
|
|
int tradingStartHour; // Start hour (broker time)
|
|
int tradingStartMinute; // Start minute
|
|
int tradingEndHour; // End hour (broker time)
|
|
int tradingEndMinute; // End minute
|
|
bool avoidRollover; // Skip rollover period
|
|
|
|
// Technical settings
|
|
int magicNumber; // EA magic number
|
|
int slippagePoints; // Maximum slippage
|
|
int maxRetries; // Trade retry limit
|
|
ENUM_LOG_LEVEL logLevel; // Logging verbosity
|
|
bool logToFile; // Enable file logging
|
|
ENUM_SIZING_MODE sizingMode; // Position sizing mode
|
|
|
|
// Constructor
|
|
void EAConfig()
|
|
{
|
|
SetDefaults();
|
|
}
|
|
|
|
// Set default values
|
|
void SetDefaults()
|
|
{
|
|
symbols[0] = DEFAULT_SYMBOL_AUDCAD;
|
|
symbols[1] = DEFAULT_SYMBOL_NZDCAD;
|
|
symbols[2] = DEFAULT_SYMBOL_AUDNZD;
|
|
timeframe = PERIOD_M15;
|
|
lookbackPeriod = 250;
|
|
updateIntervalSeconds = DEFAULT_CACHE_UPDATE_INTERVAL;
|
|
zScoreEntryThreshold = 2.5;
|
|
zScoreExitThreshold = 0.5;
|
|
minCorrelation = 0.75;
|
|
maxSpreadPips = 3.0;
|
|
baseLotSize = 0.01;
|
|
riskPercentPerBasket = 1.0;
|
|
maxDrawdownPercent = DEFAULT_MAX_DRAWDOWN_PERCENT;
|
|
maxDailyLossPercent = 5.0;
|
|
maxDailyLossAmount = DEFAULT_DAILY_LOSS_LIMIT;
|
|
maxOpenBaskets = 1;
|
|
maxHoldingHours = DEFAULT_MAX_HOLDING_HOURS;
|
|
tradingStartHour = 0;
|
|
tradingStartMinute = 0;
|
|
tradingEndHour = 23;
|
|
tradingEndMinute = 59;
|
|
avoidRollover = true;
|
|
magicNumber = 100000;
|
|
slippagePoints = DEFAULT_SLIPPAGE_POINTS;
|
|
maxRetries = MAX_RETRY_ATTEMPTS;
|
|
logLevel = LOG_LEVEL_INFO;
|
|
logToFile = false;
|
|
sizingMode = SIZING_FIXED;
|
|
}
|
|
};
|
|
|
|
#endif // DBASKET_STRUCTURES_MQH
|
|
//+------------------------------------------------------------------+
|