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:
zhutoutoutousan
2026-07-02 15:03:43 +02:00
co-authored by Cursor
parent 3f75a08848
commit 605faf5310
1014 changed files with 83437 additions and 10413 deletions
@@ -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