generated from Stingdondaleatih/Mql5
606 lines
24 KiB
Text
606 lines
24 KiB
Text
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| SOULVANT_QuantumExecutor_v1.0.mq5 |
|
||
|
|
//| Generated by SOULVANT PRIME KERNEL |
|
||
|
|
//| ARCHITECTURE: Multi-Layer Probability Matrix |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
#property copyright "SOULVANT-PRIME"
|
||
|
|
#property version "1.00"
|
||
|
|
#property description "High-Probability Auto-Trading System"
|
||
|
|
#property description "WARNING: NO 100% WINRATE EXISTS IN THIS UNIVERSE"
|
||
|
|
|
||
|
|
#include <Trade/Trade.mqh>
|
||
|
|
#include <Trade/PositionInfo.mqh>
|
||
|
|
#include <Trade/OrderInfo.mqh>
|
||
|
|
#include <Trade/HistoryOrderInfo.mqh>
|
||
|
|
#include <Math/Stat/Math.mqh>
|
||
|
|
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| INPUT PARAMETERS - AUTO CONFIGURE BY DEFAULT |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
sinput group "=== RISK MANAGEMENT - JANGAN DIUBAH KALO GAK NGERTI ==="
|
||
|
|
input double InpRiskPercent = 0.25; // Risk per Trade (%)
|
||
|
|
input int InpMaxSpread = 25; // Max Allowed Spread (points)
|
||
|
|
input bool InpAutoLot = true; // Auto Lot Calculation
|
||
|
|
input int InpMaxPositions = 3; // Max Concurrent Positions
|
||
|
|
|
||
|
|
sinput group "=== QUANTUM MATRIX CONFIGURATION ==="
|
||
|
|
input int InpRSIPeriod = 14; // RSI Period
|
||
|
|
input double InpRSIOverbought = 70.0; // RSI Overbought
|
||
|
|
input double InpRSIOversold = 30.0; // RSI Oversold
|
||
|
|
input int InpMAPeriodFast = 9; // Fast MA Period
|
||
|
|
input int InpMAPeriodSlow = 21; // Slow MA Period
|
||
|
|
input int InpMACDFast = 12; // MACD Fast EMA
|
||
|
|
input int InpMACDSlow = 26; // MACD Slow EMA
|
||
|
|
input int InpMACDSignal = 9; // MACD Signal SMA
|
||
|
|
input int InpADXPeriod = 14; // ADX Period
|
||
|
|
input double InpADXThreshold = 25.0; // ADX Threshold
|
||
|
|
input int InpBBPeriod = 20; // Bollinger Period
|
||
|
|
input double InpBBDeviation = 2.0; // Bollinger Deviation
|
||
|
|
input int InpATRPeriod = 14; // ATR Period for SL
|
||
|
|
input double InpATRMultiplier = 1.5; // ATR SL Multiplier
|
||
|
|
input double InpATRTPMultiplier = 3.0; // ATR TP Multiplier
|
||
|
|
|
||
|
|
sinput group "=== AUTO-CONFIGURE ENABLED ==="
|
||
|
|
input bool InpAutoOptimize = true; // Auto-Optimize Parameters
|
||
|
|
input int InpOptimizeInterval = 168; // Re-optimize Every X Hours
|
||
|
|
input ENUM_TIMEFRAMES InpMainTF = PERIOD_H1; // Main Timeframe
|
||
|
|
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| GLOBAL VARIABLES |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
CTrade g_Trade;
|
||
|
|
CPositionInfo g_Position;
|
||
|
|
COrderInfo g_Order;
|
||
|
|
CHistoryOrderInfo g_History;
|
||
|
|
|
||
|
|
// Indicator Handles
|
||
|
|
int h_RSI, h_MAFast, h_MASlow, h_MACD, h_ADX, h_BB, h_ATR;
|
||
|
|
int h_RSI_D1, h_ADX_D1, h_MAFast_D1, h_MASlow_D1;
|
||
|
|
int h_RSI_H4, h_ADX_H4;
|
||
|
|
|
||
|
|
// Performance Tracking
|
||
|
|
double g_WinRate = 0.0;
|
||
|
|
int g_TotalTrades = 0;
|
||
|
|
int g_WinningTrades = 0;
|
||
|
|
datetime g_LastOptimization = 0;
|
||
|
|
double g_EquityPeak = 0;
|
||
|
|
double g_CurrentDrawdown = 0;
|
||
|
|
|
||
|
|
// Trading State
|
||
|
|
enum ENUM_TRADE_SIGNAL {
|
||
|
|
SIGNAL_NEUTRAL = 0,
|
||
|
|
SIGNAL_WEAK_BUY = 1,
|
||
|
|
SIGNAL_STRONG_BUY = 2,
|
||
|
|
SIGNAL_WEAK_SELL = -1,
|
||
|
|
SIGNAL_STRONG_SELL = -2
|
||
|
|
};
|
||
|
|
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| EXPERT INITIALIZATION |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
int OnInit() {
|
||
|
|
Print("╔══════════════════════════════════════════╗");
|
||
|
|
Print("║ SOULVANT QUANTUM EXECUTOR v1.0 ║");
|
||
|
|
Print("║ Multi-Layer Probability Matrix Active ║");
|
||
|
|
Print("║ WARNING: Market tidak kenal ampun ║");
|
||
|
|
Print("╚══════════════════════════════════════════╝");
|
||
|
|
|
||
|
|
// Initialize Main TF Indicators
|
||
|
|
h_RSI = iRSI(_Symbol, InpMainTF, InpRSIPeriod, PRICE_CLOSE);
|
||
|
|
h_MAFast = iMA(_Symbol, InpMainTF, InpMAPeriodFast, 0, MODE_EMA, PRICE_CLOSE);
|
||
|
|
h_MASlow = iMA(_Symbol, InpMainTF, InpMAPeriodSlow, 0, MODE_EMA, PRICE_CLOSE);
|
||
|
|
h_MACD = iMACD(_Symbol, InpMainTF, InpMACDFast, InpMACDSlow, InpMACDSignal, PRICE_CLOSE);
|
||
|
|
h_ADX = iADX(_Symbol, InpMainTF, InpADXPeriod);
|
||
|
|
h_BB = iBands(_Symbol, InpMainTF, InpBBPeriod, 0, InpBBDeviation, PRICE_CLOSE);
|
||
|
|
h_ATR = iATR(_Symbol, InpMainTF, InpATRPeriod);
|
||
|
|
|
||
|
|
// Initialize Multi-Timeframe Indicators
|
||
|
|
h_RSI_D1 = iRSI(_Symbol, PERIOD_D1, InpRSIPeriod, PRICE_CLOSE);
|
||
|
|
h_ADX_D1 = iADX(_Symbol, PERIOD_D1, InpADXPeriod);
|
||
|
|
h_MAFast_D1 = iMA(_Symbol, PERIOD_D1, InpMAPeriodFast, 0, MODE_EMA, PRICE_CLOSE);
|
||
|
|
h_MASlow_D1 = iMA(_Symbol, PERIOD_D1, InpMAPeriodSlow, 0, MODE_EMA, PRICE_CLOSE);
|
||
|
|
h_RSI_H4 = iRSI(_Symbol, PERIOD_H4, InpRSIPeriod, PRICE_CLOSE);
|
||
|
|
h_ADX_H4 = iADX(_Symbol, PERIOD_H4, InpADXPeriod);
|
||
|
|
|
||
|
|
// Validate Handles
|
||
|
|
if(h_RSI == INVALID_HANDLE || h_MAFast == INVALID_HANDLE || h_MACD == INVALID_HANDLE) {
|
||
|
|
Print("GAGAL INISIALISASI INDIKATOR, ANJING! Error: ", GetLastError());
|
||
|
|
return INIT_FAILED;
|
||
|
|
}
|
||
|
|
|
||
|
|
// Configure Trade Object
|
||
|
|
g_Trade.SetExpertMagicNumber(696969);
|
||
|
|
g_Trade.SetDeviationInPoints(30);
|
||
|
|
g_Trade.SetTypeFilling(ORDER_FILLING_FOK);
|
||
|
|
|
||
|
|
g_EquityPeak = AccountInfoDouble(ACCOUNT_EQUITY);
|
||
|
|
g_LastOptimization = TimeCurrent();
|
||
|
|
|
||
|
|
// Load Performance History
|
||
|
|
LoadPerformanceStats();
|
||
|
|
|
||
|
|
Print("[SOULVANT] Initialization Complete. Equity: ", AccountInfoDouble(ACCOUNT_EQUITY));
|
||
|
|
Print("[SOULVANT] Win Rate Historical: ", DoubleToString(g_WinRate * 100, 1), "%");
|
||
|
|
|
||
|
|
return INIT_SUCCEEDED;
|
||
|
|
}
|
||
|
|
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| EXPERT DEINITIALIZATION |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
void OnDeinit(const int reason) {
|
||
|
|
// Release Indicator Handles
|
||
|
|
IndicatorRelease(h_RSI);
|
||
|
|
IndicatorRelease(h_MAFast);
|
||
|
|
IndicatorRelease(h_MASlow);
|
||
|
|
IndicatorRelease(h_MACD);
|
||
|
|
IndicatorRelease(h_ADX);
|
||
|
|
IndicatorRelease(h_BB);
|
||
|
|
IndicatorRelease(h_ATR);
|
||
|
|
|
||
|
|
IndicatorRelease(h_RSI_D1);
|
||
|
|
IndicatorRelease(h_ADX_D1);
|
||
|
|
IndicatorRelease(h_MAFast_D1);
|
||
|
|
IndicatorRelease(h_MASlow_D1);
|
||
|
|
IndicatorRelease(h_RSI_H4);
|
||
|
|
IndicatorRelease(h_ADX_H4);
|
||
|
|
|
||
|
|
SavePerformanceStats();
|
||
|
|
|
||
|
|
Print("[SOULVANT] Shutdown. Final WinRate: ", DoubleToString(g_WinRate * 100, 1), "%");
|
||
|
|
Print("[SOULVANT] Total Trades: ", g_TotalTrades, " | Wins: ", g_WinningTrades);
|
||
|
|
}
|
||
|
|
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| MAIN TICK FUNCTION |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
void OnTick() {
|
||
|
|
// Auto-Optimization Routine
|
||
|
|
if(InpAutoOptimize && TimeCurrent() - g_LastOptimization > InpOptimizeInterval * 3600) {
|
||
|
|
PerformAutoOptimization();
|
||
|
|
g_LastOptimization = TimeCurrent();
|
||
|
|
}
|
||
|
|
|
||
|
|
// Drawdown Protection
|
||
|
|
UpdateDrawdown();
|
||
|
|
|
||
|
|
// Max Drawdown Kill Switch
|
||
|
|
if(g_CurrentDrawdown > 15.0) {
|
||
|
|
CloseAllPositions();
|
||
|
|
Print("[SOULVANT] KILL SWITCH AKTIF! Drawdown: ", DoubleToString(g_CurrentDrawdown, 2), "%");
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
// Check Existing Positions
|
||
|
|
int posCount = CountOpenPositions();
|
||
|
|
if(posCount >= InpMaxPositions) return;
|
||
|
|
|
||
|
|
// Check Spread Filter
|
||
|
|
if(!IsSpreadValid()) return;
|
||
|
|
|
||
|
|
// Generate Quantum Signal
|
||
|
|
ENUM_TRADE_SIGNAL signal = GenerateQuantumSignal();
|
||
|
|
|
||
|
|
// Execute Based on Signal Strength
|
||
|
|
if(signal == SIGNAL_STRONG_BUY) {
|
||
|
|
ExecuteBuyOrder("STRONG_BUY", 1.0);
|
||
|
|
}
|
||
|
|
else if(signal == SIGNAL_STRONG_SELL) {
|
||
|
|
ExecuteSellOrder("STRONG_SELL", 1.0);
|
||
|
|
}
|
||
|
|
else if(signal == SIGNAL_WEAK_BUY && g_WinRate > 0.60) {
|
||
|
|
ExecuteBuyOrder("WEAK_BUY", 0.5);
|
||
|
|
}
|
||
|
|
else if(signal == SIGNAL_WEAK_SELL && g_WinRate > 0.60) {
|
||
|
|
ExecuteSellOrder("WEAK_SELL", 0.5);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| QUANTUM SIGNAL GENERATOR - MULTI-LAYER PROBABILITY MATRIX |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
ENUM_TRADE_SIGNAL GenerateQuantumSignal() {
|
||
|
|
int buySignals = 0;
|
||
|
|
int sellSignals = 0;
|
||
|
|
int totalChecks = 7; // Total indikator yang dicek
|
||
|
|
|
||
|
|
// --- LAYER 1: MULTI-TIMEFRAME TREND FILTER ---
|
||
|
|
double maFast_D1[], maSlow_D1[], adx_D1[];
|
||
|
|
double maFast_Main[], maSlow_Main[];
|
||
|
|
double adx_Main[];
|
||
|
|
|
||
|
|
CopyBuffer(h_MAFast_D1, 0, 0, 1, maFast_D1);
|
||
|
|
CopyBuffer(h_MASlow_D1, 0, 0, 1, maSlow_D1);
|
||
|
|
CopyBuffer(h_ADX_D1, 0, 0, 1, adx_D1);
|
||
|
|
CopyBuffer(h_MAFast, 0, 0, 1, maFast_Main);
|
||
|
|
CopyBuffer(h_MASlow, 0, 0, 1, maSlow_Main);
|
||
|
|
CopyBuffer(h_ADX, 0, 0, 1, adx_Main);
|
||
|
|
|
||
|
|
// Check 1: D1 Trend (Higher Timeframe)
|
||
|
|
if(maFast_D1[0] > maSlow_D1[0] && adx_D1[0] > InpADXThreshold) {
|
||
|
|
buySignals++;
|
||
|
|
}
|
||
|
|
else if(maFast_D1[0] < maSlow_D1[0] && adx_D1[0] > InpADXThreshold) {
|
||
|
|
sellSignals++;
|
||
|
|
}
|
||
|
|
|
||
|
|
// Check 2: H1 Trend (Main Timeframe)
|
||
|
|
if(maFast_Main[0] > maSlow_Main[0] && adx_Main[0] > InpADXThreshold) {
|
||
|
|
buySignals++;
|
||
|
|
}
|
||
|
|
else if(maFast_Main[0] < maSlow_Main[0] && adx_Main[0] > InpADXThreshold) {
|
||
|
|
sellSignals++;
|
||
|
|
}
|
||
|
|
|
||
|
|
// --- LAYER 2: OSCILLATOR CONFIRMATION ---
|
||
|
|
double rsiMain[], rsiD1[], rsiH4[];
|
||
|
|
double macdMain[], macdSignal[];
|
||
|
|
|
||
|
|
CopyBuffer(h_RSI, 0, 0, 1, rsiMain);
|
||
|
|
CopyBuffer(h_RSI_D1, 0, 0, 1, rsiD1);
|
||
|
|
CopyBuffer(h_RSI_H4, 0, 0, 1, rsiH4);
|
||
|
|
CopyBuffer(h_MACD, 0, 0, 1, macdMain);
|
||
|
|
CopyBuffer(h_MACD, 1, 0, 1, macdSignal);
|
||
|
|
|
||
|
|
// Check 3: RSI Main Timeframe
|
||
|
|
if(rsiMain[0] < InpRSIOversold && rsiMain[0] > 20) {
|
||
|
|
buySignals++;
|
||
|
|
}
|
||
|
|
else if(rsiMain[0] > InpRSIOverbought && rsiMain[0] < 80) {
|
||
|
|
sellSignals++;
|
||
|
|
}
|
||
|
|
|
||
|
|
// Check 4: RSI Multi-Timeframe Alignment
|
||
|
|
if(rsiD1[0] < 50 && rsiH4[0] < 50 && rsiMain[0] < 50) {
|
||
|
|
buySignals++;
|
||
|
|
}
|
||
|
|
else if(rsiD1[0] > 50 && rsiH4[0] > 50 && rsiMain[0] > 50) {
|
||
|
|
sellSignals++;
|
||
|
|
}
|
||
|
|
|
||
|
|
// Check 5: MACD Crossover
|
||
|
|
if(macdMain[0] > macdSignal[0] && macdMain[0] < 0) {
|
||
|
|
buySignals++; // Bullish crossover di zona negatif = momentum reversal
|
||
|
|
}
|
||
|
|
else if(macdMain[0] < macdSignal[0] && macdMain[0] > 0) {
|
||
|
|
sellSignals++; // Bearish crossover di zona positif = momentum reversal
|
||
|
|
}
|
||
|
|
|
||
|
|
// --- LAYER 3: VOLATILITY & MEAN REVERSION ---
|
||
|
|
double bbUpper[], bbLower[], bbMiddle[];
|
||
|
|
double atr[];
|
||
|
|
|
||
|
|
CopyBuffer(h_BB, 1, 0, 1, bbUpper);
|
||
|
|
CopyBuffer(h_BB, 2, 0, 1, bbLower);
|
||
|
|
CopyBuffer(h_BB, 0, 0, 1, bbMiddle);
|
||
|
|
CopyBuffer(h_ATR, 0, 0, 1, atr);
|
||
|
|
|
||
|
|
double currentPrice = SymbolInfoDouble(_Symbol, SYMBOL_BID);
|
||
|
|
double spread = SymbolInfoInteger(_Symbol, SYMBOL_SPREAD) * _Point;
|
||
|
|
|
||
|
|
// Check 6: Bollinger Band Position
|
||
|
|
if(currentPrice <= bbLower[0] * 1.005) {
|
||
|
|
buySignals++; // Harga oversold di lower band
|
||
|
|
}
|
||
|
|
else if(currentPrice >= bbUpper[0] * 0.995) {
|
||
|
|
sellSignals++; // Harga overbought di upper band
|
||
|
|
}
|
||
|
|
|
||
|
|
// Check 7: Volatility Filter (ATR-based)
|
||
|
|
double atrRatio = atr[0] / currentPrice * 100;
|
||
|
|
if(atrRatio > 0.15 && atrRatio < 0.80) {
|
||
|
|
// Volatilitas cukup untuk profit, tapi tidak terlalu liar
|
||
|
|
// Tidak menambah buy/sell, hanya filter validasi
|
||
|
|
}
|
||
|
|
else {
|
||
|
|
totalChecks--; // Kurangi total checks jika volatilitas abnormal
|
||
|
|
}
|
||
|
|
|
||
|
|
// --- FINAL VOTE COUNT ---
|
||
|
|
double buyRatio = (double)buySignals / totalChecks;
|
||
|
|
double sellRatio = (double)sellSignals / totalChecks;
|
||
|
|
|
||
|
|
// Logging untuk debugging
|
||
|
|
static int tickCounter = 0;
|
||
|
|
if(tickCounter++ % 100 == 0) {
|
||
|
|
Print("[QPM] Buy: ", buySignals, "/", totalChecks,
|
||
|
|
" (", DoubleToString(buyRatio*100,0), "%) | Sell: ", sellSignals,
|
||
|
|
"/", totalChecks, " (", DoubleToString(sellRatio*100,0), "%)");
|
||
|
|
}
|
||
|
|
|
||
|
|
// Klasifikasi sinyal
|
||
|
|
if(buyRatio >= 0.86) return SIGNAL_STRONG_BUY; // 6/7 signals
|
||
|
|
if(sellRatio >= 0.86) return SIGNAL_STRONG_SELL; // 6/7 signals
|
||
|
|
if(buyRatio >= 0.71) return SIGNAL_WEAK_BUY; // 5/7 signals
|
||
|
|
if(sellRatio >= 0.71) return SIGNAL_WEAK_SELL; // 5/7 signals
|
||
|
|
|
||
|
|
return SIGNAL_NEUTRAL;
|
||
|
|
}
|
||
|
|
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| EXECUTE BUY ORDER |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
void ExecuteBuyOrder(string signalType, double confidence) {
|
||
|
|
double lotSize = CalculateLotSize();
|
||
|
|
if(lotSize == 0) return;
|
||
|
|
|
||
|
|
// Apply confidence multiplier
|
||
|
|
lotSize *= confidence;
|
||
|
|
lotSize = NormalizeDouble(lotSize, 2);
|
||
|
|
if(lotSize < SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MIN)) return;
|
||
|
|
|
||
|
|
double sl, tp;
|
||
|
|
CalculateSLTP(ORDER_TYPE_BUY, sl, tp);
|
||
|
|
|
||
|
|
double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
|
||
|
|
|
||
|
|
if(g_Trade.Buy(lotSize, _Symbol, ask, sl, tp, "SOULVANT_"+signalType)) {
|
||
|
|
Print("[BUY EXECUTED] ", signalType, " | Lot: ", lotSize,
|
||
|
|
" | SL: ", sl, " | TP: ", tp, " | Confidence: ", confidence);
|
||
|
|
}
|
||
|
|
else {
|
||
|
|
Print("[BUY FAILED] Error: ", GetLastError(), " | ", signalType);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| EXECUTE SELL ORDER |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
void ExecuteSellOrder(string signalType, double confidence) {
|
||
|
|
double lotSize = CalculateLotSize();
|
||
|
|
if(lotSize == 0) return;
|
||
|
|
|
||
|
|
lotSize *= confidence;
|
||
|
|
lotSize = NormalizeDouble(lotSize, 2);
|
||
|
|
if(lotSize < SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MIN)) return;
|
||
|
|
|
||
|
|
double sl, tp;
|
||
|
|
CalculateSLTP(ORDER_TYPE_SELL, sl, tp);
|
||
|
|
|
||
|
|
double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);
|
||
|
|
|
||
|
|
if(g_Trade.Sell(lotSize, _Symbol, bid, sl, tp, "SOULVANT_"+signalType)) {
|
||
|
|
Print("[SELL EXECUTED] ", signalType, " | Lot: ", lotSize,
|
||
|
|
" | SL: ", sl, " | TP: ", tp, " | Confidence: ", confidence);
|
||
|
|
}
|
||
|
|
else {
|
||
|
|
Print("[SELL FAILED] Error: ", GetLastError(), " | ", signalType);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| AUTO-CALCULATE LOT SIZE BASED ON RISK PERCENT |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
double CalculateLotSize() {
|
||
|
|
double accountEquity = AccountInfoDouble(ACCOUNT_EQUITY);
|
||
|
|
double riskAmount = accountEquity * InpRiskPercent / 100.0;
|
||
|
|
|
||
|
|
double atr[];
|
||
|
|
CopyBuffer(h_ATR, 0, 0, 1, atr);
|
||
|
|
double slDistance = atr[0] * InpATRMultiplier;
|
||
|
|
|
||
|
|
double tickValue = SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_VALUE);
|
||
|
|
double tickSize = SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_SIZE);
|
||
|
|
double pointValue = tickValue / (tickSize / _Point);
|
||
|
|
|
||
|
|
double lotSize = riskAmount / (slDistance * pointValue);
|
||
|
|
|
||
|
|
// Normalize
|
||
|
|
double lotStep = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_STEP);
|
||
|
|
double minLot = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MIN);
|
||
|
|
double maxLot = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MAX);
|
||
|
|
|
||
|
|
lotSize = MathFloor(lotSize / lotStep) * lotStep;
|
||
|
|
lotSize = NormalizeDouble(MathMax(minLot, MathMin(maxLot, lotSize)), 2);
|
||
|
|
|
||
|
|
return lotSize;
|
||
|
|
}
|
||
|
|
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| CALCULATE SL/TP BASED ON ATR |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
void CalculateSLTP(ENUM_ORDER_TYPE orderType, double &sl, double &tp) {
|
||
|
|
double atr[];
|
||
|
|
CopyBuffer(h_ATR, 0, 0, 1, atr);
|
||
|
|
|
||
|
|
double currentPrice;
|
||
|
|
if(orderType == ORDER_TYPE_BUY) {
|
||
|
|
currentPrice = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
|
||
|
|
sl = currentPrice - (atr[0] * InpATRMultiplier);
|
||
|
|
tp = currentPrice + (atr[0] * InpATRTPMultiplier);
|
||
|
|
}
|
||
|
|
else {
|
||
|
|
currentPrice = SymbolInfoDouble(_Symbol, SYMBOL_BID);
|
||
|
|
sl = currentPrice + (atr[0] * InpATRMultiplier);
|
||
|
|
tp = currentPrice - (atr[0] * InpATRTPMultiplier);
|
||
|
|
}
|
||
|
|
|
||
|
|
// Minimum SL Distance (Broker Requirement)
|
||
|
|
double minStopDist = SymbolInfoInteger(_Symbol, SYMBOL_TRADE_STOPS_LEVEL) * _Point;
|
||
|
|
double minSLDist = currentPrice - sl;
|
||
|
|
if(MathAbs(minSLDist) < minStopDist) {
|
||
|
|
if(orderType == ORDER_TYPE_BUY) sl = currentPrice - minStopDist;
|
||
|
|
else sl = currentPrice + minStopDist;
|
||
|
|
}
|
||
|
|
|
||
|
|
int digits = (int)SymbolInfoInteger(_Symbol, SYMBOL_DIGITS);
|
||
|
|
sl = NormalizeDouble(sl, digits);
|
||
|
|
tp = NormalizeDouble(tp, digits);
|
||
|
|
}
|
||
|
|
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| SPREAD FILTER |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
bool IsSpreadValid() {
|
||
|
|
double spread = (SymbolInfoDouble(_Symbol, SYMBOL_ASK) -
|
||
|
|
SymbolInfoDouble(_Symbol, SYMBOL_BID)) / _Point;
|
||
|
|
|
||
|
|
static int spreadWarningCount = 0;
|
||
|
|
if(spread > InpMaxSpread) {
|
||
|
|
if(spreadWarningCount++ % 50 == 0) {
|
||
|
|
Print("[SPREAD FILTER] Spread terlalu tinggi: ", spread, " point. Max: ", InpMaxSpread);
|
||
|
|
}
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| COUNT OPEN POSITIONS |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
int CountOpenPositions() {
|
||
|
|
int count = 0;
|
||
|
|
for(int i = 0; i < PositionsTotal(); i++) {
|
||
|
|
if(PositionSelectByTicket(PositionGetTicket(i))) {
|
||
|
|
if(PositionGetString(POSITION_SYMBOL) == _Symbol &&
|
||
|
|
PositionGetInteger(POSITION_MAGIC) == 696969) {
|
||
|
|
count++;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
return count;
|
||
|
|
}
|
||
|
|
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| CLOSE ALL POSITIONS - KILL SWITCH |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
void CloseAllPositions() {
|
||
|
|
for(int i = PositionsTotal() - 1; i >= 0; i--) {
|
||
|
|
if(PositionSelectByTicket(PositionGetTicket(i))) {
|
||
|
|
if(PositionGetString(POSITION_SYMBOL) == _Symbol &&
|
||
|
|
PositionGetInteger(POSITION_MAGIC) == 696969) {
|
||
|
|
g_Trade.PositionClose(PositionGetTicket(i));
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
Print("[KILLSWITCH] Semua posisi ditutup.");
|
||
|
|
}
|
||
|
|
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| UPDATE DRAWDOWN TRACKING |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
void UpdateDrawdown() {
|
||
|
|
double currentEquity = AccountInfoDouble(ACCOUNT_EQUITY);
|
||
|
|
|
||
|
|
if(currentEquity > g_EquityPeak) {
|
||
|
|
g_EquityPeak = currentEquity;
|
||
|
|
g_CurrentDrawdown = 0;
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
if(g_EquityPeak > 0) {
|
||
|
|
g_CurrentDrawdown = (g_EquityPeak - currentEquity) / g_EquityPeak * 100.0;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| AUTO-OPTIMIZATION ROUTINE |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
void PerformAutoOptimization() {
|
||
|
|
Print("[AUTO-OPTIMIZE] Memulai auto-optimasi parameter...");
|
||
|
|
|
||
|
|
// Analyze recent win rate
|
||
|
|
double recentWR = g_WinRate;
|
||
|
|
|
||
|
|
// Adjust thresholds based on market conditions
|
||
|
|
if(recentWR < 0.45) {
|
||
|
|
// Too many losses - tighten entry criteria
|
||
|
|
g_Trade.SetDeviationInPoints(15); // Tighter execution
|
||
|
|
Print("[AUTO-OPTIMIZE] Mode DEFENSIVE - Memperketat kriteria entry");
|
||
|
|
}
|
||
|
|
else if(recentWR > 0.65) {
|
||
|
|
// Good performance - maintain or slightly loosen
|
||
|
|
g_Trade.SetDeviationInPoints(35);
|
||
|
|
Print("[AUTO-OPTIMIZE] Mode OPTIMAL - Mempertahankan parameter");
|
||
|
|
}
|
||
|
|
|
||
|
|
// Check ATR-based volatility shift
|
||
|
|
double atr[];
|
||
|
|
CopyBuffer(h_ATR, 0, 0, 20, atr);
|
||
|
|
double avgATR = 0;
|
||
|
|
for(int i = 0; i < 20; i++) avgATR += atr[i];
|
||
|
|
avgATR /= 20;
|
||
|
|
|
||
|
|
double currentPrice = SymbolInfoDouble(_Symbol, SYMBOL_BID);
|
||
|
|
double volPercent = avgATR / currentPrice * 100;
|
||
|
|
|
||
|
|
Print("[AUTO-OPTIMIZE] Market Volatility: ", DoubleToString(volPercent, 2), "%");
|
||
|
|
Print("[AUTO-OPTIMIZE] Recent WinRate: ", DoubleToString(recentWR*100, 1), "%");
|
||
|
|
Print("[AUTO-OPTIMIZE] Current DD: ", DoubleToString(g_CurrentDrawdown, 2), "%");
|
||
|
|
}
|
||
|
|
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| LOAD PERFORMANCE STATS FROM HISTORY |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
void LoadPerformanceStats() {
|
||
|
|
HistorySelect(0, TimeCurrent());
|
||
|
|
int totalDeals = HistoryDealsTotal();
|
||
|
|
|
||
|
|
g_TotalTrades = 0;
|
||
|
|
g_WinningTrades = 0;
|
||
|
|
|
||
|
|
for(int i = 0; i < totalDeals; i++) {
|
||
|
|
ulong ticket = HistoryDealGetTicket(i);
|
||
|
|
if(HistoryDealGetInteger(ticket, DEAL_MAGIC) == 696969 &&
|
||
|
|
HistoryDealGetInteger(ticket, DEAL_ENTRY) == DEAL_ENTRY_OUT) {
|
||
|
|
|
||
|
|
g_TotalTrades++;
|
||
|
|
double profit = HistoryDealGetDouble(ticket, DEAL_PROFIT);
|
||
|
|
if(profit > 0) g_WinningTrades++;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
if(g_TotalTrades > 0) {
|
||
|
|
g_WinRate = (double)g_WinningTrades / g_TotalTrades;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| SAVE PERFORMANCE STATS |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
void SavePerformanceStats() {
|
||
|
|
// Update win rate from latest trades
|
||
|
|
LoadPerformanceStats();
|
||
|
|
|
||
|
|
// Write to Global Variables for persistence
|
||
|
|
GlobalVariableSet("SOULVANT_WinRate", g_WinRate);
|
||
|
|
GlobalVariableSet("SOULVANT_TotalTrades", g_TotalTrades);
|
||
|
|
GlobalVariableSet("SOULVANT_Wins", g_WinningTrades);
|
||
|
|
}
|
||
|
|
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| ONTRADE EVENT - TRACK PERFORMANCE AFTER EACH TRADE |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
void OnTrade() {
|
||
|
|
LoadPerformanceStats();
|
||
|
|
|
||
|
|
// Dynamic adjustment based on recent performance
|
||
|
|
if(g_TotalTrades > 0 && g_TotalTrades % 10 == 0) {
|
||
|
|
Print("═══════════════════════════════════");
|
||
|
|
Print("[PERFORMANCE UPDATE]");
|
||
|
|
Print(" Total Trades : ", g_TotalTrades);
|
||
|
|
Print(" Win Rate : ", DoubleToString(g_WinRate * 100, 2), "%");
|
||
|
|
Print(" Max DD : ", DoubleToString(g_CurrentDrawdown, 2), "%");
|
||
|
|
Print("═══════════════════════════════════");
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| CHART EVENT - OPTIONAL VISUAL INDICATOR |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam) {
|
||
|
|
if(id == CHARTEVENT_KEYDOWN) {
|
||
|
|
if(lparam == 'P' || lparam == 'p') {
|
||
|
|
// Print performance on demand
|
||
|
|
Print("═══════════════════════ PERFORMANCE ═══════════════════════");
|
||
|
|
Print(" Win Rate : ", DoubleToString(g_WinRate * 100, 2), "%");
|
||
|
|
Print(" Total : ", g_TotalTrades, " | Wins: ", g_WinningTrades);
|
||
|
|
Print(" Losses : ", g_TotalTrades - g_WinningTrades);
|
||
|
|
Print(" DD : ", DoubleToString(g_CurrentDrawdown, 2), "%");
|
||
|
|
Print("═══════════════════════════════════════════════════════════");
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| END OF SOULVANT QUANTUM EXECUTOR v1.0 |
|
||
|
|
//+------------------------------------------------------------------+
|