Prepare source-only public release for develop.
Add cluster audit pipeline, united EA updates, brochure generators, and publication hygiene (gitignore, MT5 path desensitization, pre-upload scan). Remove tracked reports, models, and binary artifacts from the repo. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
co-authored by
Cursor
parent
3f75a08848
commit
605faf5310
@@ -157,3 +157,30 @@ int CountPositionsByMagic(string symbol, ulong magic_number)
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Align volume to SYMBOL_VOLUME_STEP / min / max (avoids Invalid volume) |
|
||||
//+------------------------------------------------------------------+
|
||||
double United_NormalizeVolume(const string symbol, double volume)
|
||||
{
|
||||
double minLot = SymbolInfoDouble(symbol, SYMBOL_VOLUME_MIN);
|
||||
double maxLot = SymbolInfoDouble(symbol, SYMBOL_VOLUME_MAX);
|
||||
double lotStep = SymbolInfoDouble(symbol, SYMBOL_VOLUME_STEP);
|
||||
if(lotStep <= 0.0)
|
||||
lotStep = 0.01;
|
||||
|
||||
double v = MathFloor(volume / lotStep) * lotStep;
|
||||
|
||||
if(v < minLot)
|
||||
v = minLot;
|
||||
if(v > maxLot)
|
||||
v = maxLot;
|
||||
|
||||
int digits = (int)MathCeil(-MathLog10(lotStep));
|
||||
if(digits < 0)
|
||||
digits = 0;
|
||||
if(digits > 8)
|
||||
digits = 8;
|
||||
|
||||
return NormalizeDouble(v, digits);
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
|
||||
@@ -1,12 +1,18 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| DarvasBoxStrategy.mqh |
|
||||
//+------------------------------------------------------------------+
|
||||
#if defined(CLUSTER0_ORCHESTRATOR) || defined(UNITED_V2_DYNAMIC_LOTS)
|
||||
// MQL5: no #if — use #ifdef only (no defined() / || in one #if)
|
||||
#ifdef UNITED_V2_DYNAMIC_LOTS
|
||||
extern double g_DB_LotSize;
|
||||
#define DARVAS_TRADE_LOT (g_DB_LotSize)
|
||||
#else
|
||||
#ifdef CLUSTER0_ORCHESTRATOR
|
||||
extern double g_DB_LotSize;
|
||||
#define DARVAS_TRADE_LOT (g_DB_LotSize)
|
||||
#else
|
||||
#define DARVAS_TRADE_LOT 0.01
|
||||
#endif
|
||||
#endif
|
||||
|
||||
bool InitDarvasBox(string symbol)
|
||||
{
|
||||
@@ -197,13 +203,19 @@ bool PlaceOrder(ENUM_ORDER_TYPE orderType, double price, double sl, double tp)
|
||||
}
|
||||
|
||||
bool result = false;
|
||||
const double lot = United_NormalizeVolume(dbData.symbol, DARVAS_TRADE_LOT);
|
||||
if(lot <= 0.0)
|
||||
{
|
||||
Print("DarvasBox: Order rejected - invalid lot after normalize (raw=", DARVAS_TRADE_LOT, ")");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Use market price (0) instead of explicit price - this ensures market order execution
|
||||
// In backtesting, explicit price might fail if price has moved
|
||||
if(orderType == ORDER_TYPE_BUY)
|
||||
result = dbData.trade.Buy(DARVAS_TRADE_LOT, dbData.symbol, 0, sl, tp, "Darvas Box Breakout");
|
||||
result = dbData.trade.Buy(lot, dbData.symbol, 0, sl, tp, "Darvas Box Breakout");
|
||||
else
|
||||
result = dbData.trade.Sell(DARVAS_TRADE_LOT, dbData.symbol, 0, sl, tp, "Darvas Box Breakdown");
|
||||
result = dbData.trade.Sell(lot, dbData.symbol, 0, sl, tp, "Darvas Box Breakdown");
|
||||
|
||||
// Always log errors, success only if logging enabled
|
||||
if(result)
|
||||
|
||||
@@ -45,6 +45,29 @@ int TimeHour(datetime when = 0)
|
||||
return dt.hour;
|
||||
}
|
||||
|
||||
double RC_NormalizeLot(const string sym, const double lots)
|
||||
{
|
||||
const double mn = SymbolInfoDouble(sym, SYMBOL_VOLUME_MIN);
|
||||
const double mx = SymbolInfoDouble(sym, SYMBOL_VOLUME_MAX);
|
||||
double step = SymbolInfoDouble(sym, SYMBOL_VOLUME_STEP);
|
||||
if(step <= 0.0)
|
||||
step = 0.01;
|
||||
double v = MathMax(lots, mn);
|
||||
v = MathMin(v, mx);
|
||||
return NormalizeDouble(MathFloor(v / step + 0.5) * step, 2);
|
||||
}
|
||||
|
||||
bool RC_IsTrendStrong(const double emaSlope, const double priceToEmaDistance)
|
||||
{
|
||||
if(!RC_UseTrendStrengthFilter)
|
||||
return false;
|
||||
const bool slopeStrong = (RC_emaSlopeThreshold > 0.0)
|
||||
&& (MathAbs(emaSlope) > RC_emaSlopeThreshold);
|
||||
const bool distanceStrong = (RC_emaDistanceThreshold > 0.0)
|
||||
&& (MathAbs(priceToEmaDistance) > RC_emaDistanceThreshold);
|
||||
return slopeStrong || distanceStrong;
|
||||
}
|
||||
|
||||
bool InitRSICrossOverReversal(string symbol)
|
||||
{
|
||||
WeekDays_Init();
|
||||
@@ -79,6 +102,8 @@ bool InitRSICrossOverReversal(string symbol)
|
||||
}
|
||||
|
||||
rcData.trade.SetExpertMagicNumber(RC_MagicNumber);
|
||||
rcData.trade.SetDeviationInPoints(RC_slippage);
|
||||
rcData.trade.SetTypeFillingBySymbol(symbol);
|
||||
rcData.isInitialized = true;
|
||||
Print("RSICrossOverReversal: Successfully initialized for symbol '", symbol, "'");
|
||||
return true;
|
||||
@@ -147,9 +172,12 @@ void ProcessRSICrossOverReversal(string symbol)
|
||||
return;
|
||||
|
||||
rcData.symbol = symbol; // Update symbol in case it changed
|
||||
if(rcData.bartime == iTime(rcData.symbol, RC_BarTimeFrame, 0))
|
||||
const datetime barTime = iTime(rcData.symbol, RC_BarTimeFrame, 0);
|
||||
if(barTime == 0)
|
||||
return;
|
||||
rcData.bartime = iTime(rcData.symbol, RC_BarTimeFrame, 0);
|
||||
if(rcData.bartime == barTime)
|
||||
return;
|
||||
rcData.bartime = barTime;
|
||||
|
||||
double rsi[];
|
||||
if(CopyBuffer(rcData.rsiHandle, 0, 0, 2, rsi) <= 0)
|
||||
@@ -209,7 +237,7 @@ void ProcessRSICrossOverReversal(string symbol)
|
||||
ApplyTrailingStop();
|
||||
|
||||
bool cooldownPassed = (currentTime - rcData.lastTradeTime) >= RC_cooldownSeconds;
|
||||
bool isTrendStrong = MathAbs(emaSlope) > RC_emaSlopeThreshold || MathAbs(priceToEmaDistance) > RC_emaDistanceThreshold;
|
||||
const bool isTrendStrong = RC_IsTrendStrong(emaSlope, priceToEmaDistance);
|
||||
|
||||
if(isBuyPosition && currentRSI > RC_exitBuyRSI)
|
||||
{
|
||||
@@ -229,25 +257,36 @@ void ProcessRSICrossOverReversal(string symbol)
|
||||
rcData.lastTradeTime = currentTime;
|
||||
}
|
||||
|
||||
if(!isTrendStrong &&
|
||||
currentRSI < RC_overboughtLevel - RC_entryRSISellSpread && rcData.previousRSIDef >= RC_overboughtLevel &&
|
||||
!isSellPosition && !hasPosition && cooldownPassed)
|
||||
hasPosition = PositionExistsByMagic(rcData.symbol, RC_MagicNumber);
|
||||
isBuyPosition = false;
|
||||
isSellPosition = false;
|
||||
if(hasPosition && PositionSelectByMagic(rcData.symbol, RC_MagicNumber))
|
||||
{
|
||||
rcData.trade.SetExpertMagicNumber(RC_MagicNumber);
|
||||
if(rcData.trade.Sell(g_RC_LotSize, rcData.symbol, 0.0, 0.0, 0.0, "Sell Order"))
|
||||
{
|
||||
rcData.lastTradeTime = currentTime;
|
||||
}
|
||||
const ENUM_POSITION_TYPE positionType = (ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);
|
||||
if(positionType == POSITION_TYPE_BUY)
|
||||
isBuyPosition = true;
|
||||
else if(positionType == POSITION_TYPE_SELL)
|
||||
isSellPosition = true;
|
||||
}
|
||||
|
||||
if(!isTrendStrong &&
|
||||
currentRSI > RC_oversoldLevel + RC_entryRSIBuySpread && rcData.previousRSIDef <= RC_oversoldLevel &&
|
||||
!isBuyPosition && !hasPosition && cooldownPassed)
|
||||
const double lots = RC_NormalizeLot(rcData.symbol, g_RC_LotSize);
|
||||
if(lots > 0.0 && !isTrendStrong && cooldownPassed && !hasPosition)
|
||||
{
|
||||
rcData.trade.SetExpertMagicNumber(RC_MagicNumber);
|
||||
if(rcData.trade.Buy(g_RC_LotSize, rcData.symbol, 0.0, 0.0, 0.0, "Buy Order"))
|
||||
if(currentRSI < RC_overboughtLevel - RC_entryRSISellSpread
|
||||
&& rcData.previousRSIDef >= RC_overboughtLevel
|
||||
&& !isSellPosition)
|
||||
{
|
||||
rcData.lastTradeTime = currentTime;
|
||||
rcData.trade.SetExpertMagicNumber(RC_MagicNumber);
|
||||
if(rcData.trade.Sell(lots, rcData.symbol, 0.0, 0.0, 0.0, "Sell Order"))
|
||||
rcData.lastTradeTime = currentTime;
|
||||
}
|
||||
else if(currentRSI > RC_oversoldLevel + RC_entryRSIBuySpread
|
||||
&& rcData.previousRSIDef <= RC_oversoldLevel
|
||||
&& !isBuyPosition)
|
||||
{
|
||||
rcData.trade.SetExpertMagicNumber(RC_MagicNumber);
|
||||
if(rcData.trade.Buy(lots, rcData.symbol, 0.0, 0.0, 0.0, "Buy Order"))
|
||||
rcData.lastTradeTime = currentTime;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -163,6 +163,7 @@ input double RC_exitBuyRSI = 86;
|
||||
input double RC_exitSellRSI = 10;
|
||||
input double RC_TrailingStop = 295;
|
||||
input double RC_emaDistanceThreshold = 165;
|
||||
input bool RC_UseTrendStrengthFilter = true;
|
||||
input int RC_tradingHourOneBegin = 24;
|
||||
input int RC_tradingHourOneEnd = 22;
|
||||
input int RC_tradingHourTwoBegin = 6;
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 29 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 29 KiB |
Reference in New Issue
Block a user