185 行
5.2 KiB
MQL5
185 行
5.2 KiB
MQL5
#ifndef TRADE_EXECUTION_MQH
|
|
#define TRADE_EXECUTION_MQH
|
|
|
|
#include "AISignalConfirmation.mqh"
|
|
#include "NNDataLogger.mqh"
|
|
|
|
void UpdateLastTradeInfo(const string direction);
|
|
|
|
bool IsInCooldown()
|
|
{
|
|
datetime now = TimeCurrent();
|
|
return (now - Last_Trade_Time < Trade_Cooldown_Seconds);
|
|
}
|
|
|
|
int CountOpenTradesForSymbol()
|
|
{
|
|
int count = 0;
|
|
for(int i = PositionsTotal() - 1; i >= 0; --i)
|
|
{
|
|
ulong ticket = PositionGetTicket(i);
|
|
if(ticket == 0 || !PositionSelectByTicket(ticket))
|
|
continue;
|
|
|
|
if(PositionGetString(POSITION_SYMBOL) == _Symbol && PositionGetInteger(POSITION_MAGIC) == MagicNumber)
|
|
count++;
|
|
}
|
|
return count;
|
|
}
|
|
|
|
// ── Base gate: cooldown + position cap ──────────────────────────────────────
|
|
// News direction checks live in OpenBuy / OpenSell so each side can be gated
|
|
// independently (e.g., news is bullish → OpenBuy passes, OpenSell blocked).
|
|
bool CanOpenNewTrade()
|
|
{
|
|
if(IsInCooldown())
|
|
return false;
|
|
|
|
if(CountOpenTradesForSymbol() >= Max_Open_Trades)
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
int GetSLPoints(const bool continuation)
|
|
{
|
|
if(Symbol_Profile_Initialized)
|
|
{
|
|
if(continuation) return Symbol_SL_Points;
|
|
return MathMax(20, Symbol_SL_Points / 2);
|
|
}
|
|
return continuation ? Continuation_SL_Points : Counter_SL_Points;
|
|
}
|
|
|
|
int GetTPPoints(const bool continuation)
|
|
{
|
|
if(Symbol_Profile_Initialized)
|
|
{
|
|
if(continuation) return Symbol_TP_Points;
|
|
return MathMax(80, (int)((double)Symbol_TP_Points * 0.85));
|
|
}
|
|
return continuation ? Continuation_TP_Points : Counter_TP_Points;
|
|
}
|
|
|
|
double BuildLotMultiplier()
|
|
{
|
|
double mult = 1.0;
|
|
|
|
if(Active_Praise_Signals >= 4)
|
|
mult *= 2.0;
|
|
else if(Active_Praise_Signals == 3)
|
|
mult *= 1.5;
|
|
|
|
if(Active_Warnings >= 3)
|
|
mult *= 0.5;
|
|
|
|
if(Current_State == STATE_CONTINUATION)
|
|
mult *= War_Survivor_Lot_Multiplier;
|
|
|
|
if(Use_Signal_Coordinator)
|
|
mult *= Coordinator_Lot_Multiplier;
|
|
|
|
return mult;
|
|
}
|
|
|
|
bool OpenBuy(const string reason, double lot_multiplier = 1.0)
|
|
{
|
|
if(!CanOpenNewTrade())
|
|
return false;
|
|
|
|
// Hard news block (no clear directional bias)
|
|
if(News_Trade_Block_Active)
|
|
return false;
|
|
|
|
// News directional gate — only sell-only sessions block buys
|
|
if(News_Trade_Allowed_Direction == -1)
|
|
return false;
|
|
|
|
double ai_mult = 1.0;
|
|
if(!AIApproveTrade(true, reason, ai_mult))
|
|
return false;
|
|
|
|
bool continuation = (Current_Mode == MODE_TRENDING && Current_State == STATE_CONTINUATION);
|
|
double entry = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
|
|
int sl_pts = GetSLPoints(continuation);
|
|
int tp_pts = GetTPPoints(continuation);
|
|
|
|
double lots = NormalizeLots(BaseLotSize * lot_multiplier * BuildLotMultiplier() * ai_mult);
|
|
double sl = NormalizePrice(entry - (sl_pts * _Point));
|
|
double tp = NormalizePrice(entry + (tp_pts * _Point));
|
|
|
|
bool ok = Trade.Buy(lots, _Symbol, 0.0, sl, tp, reason);
|
|
if(ok)
|
|
{
|
|
Last_Trade_Time = TimeCurrent();
|
|
UpdateLastTradeInfo("bullish");
|
|
TodayTrades++;
|
|
BuyTrades++;
|
|
|
|
// Capture feature snapshot for NN training (labeled when trade closes via NN_LabelFromDeal)
|
|
if(NN_LogData)
|
|
{
|
|
ulong d = Trade.ResultDeal();
|
|
if(d > 0 && HistoryDealSelect(d))
|
|
{
|
|
ulong pos_id = (ulong)HistoryDealGetInteger(d, DEAL_POSITION_ID);
|
|
int cat = (Current_State == STATE_CONTINUATION) ? 0 : 1;
|
|
NN_CaptureEntry(pos_id, true, reason,
|
|
Coordinator_Cluster_Strength, Coordinator_Conflict_Score, cat);
|
|
}
|
|
}
|
|
}
|
|
return ok;
|
|
}
|
|
|
|
bool OpenSell(const string reason, double lot_multiplier = 1.0)
|
|
{
|
|
if(!CanOpenNewTrade())
|
|
return false;
|
|
|
|
// Hard news block (no clear directional bias)
|
|
if(News_Trade_Block_Active)
|
|
return false;
|
|
|
|
// News directional gate — only buy-only sessions block sells
|
|
if(News_Trade_Allowed_Direction == 1)
|
|
return false;
|
|
|
|
double ai_mult = 1.0;
|
|
if(!AIApproveTrade(false, reason, ai_mult))
|
|
return false;
|
|
|
|
bool continuation = (Current_Mode == MODE_TRENDING && Current_State == STATE_CONTINUATION);
|
|
double entry = SymbolInfoDouble(_Symbol, SYMBOL_BID);
|
|
int sl_pts = GetSLPoints(continuation);
|
|
int tp_pts = GetTPPoints(continuation);
|
|
|
|
double lots = NormalizeLots(BaseLotSize * lot_multiplier * BuildLotMultiplier() * ai_mult);
|
|
double sl = NormalizePrice(entry + (sl_pts * _Point));
|
|
double tp = NormalizePrice(entry - (tp_pts * _Point));
|
|
|
|
bool ok = Trade.Sell(lots, _Symbol, 0.0, sl, tp, reason);
|
|
if(ok)
|
|
{
|
|
Last_Trade_Time = TimeCurrent();
|
|
UpdateLastTradeInfo("bearish");
|
|
TodayTrades++;
|
|
SellTrades++;
|
|
|
|
// Capture feature snapshot for NN training (labeled when trade closes via NN_LabelFromDeal)
|
|
if(NN_LogData)
|
|
{
|
|
ulong d = Trade.ResultDeal();
|
|
if(d > 0 && HistoryDealSelect(d))
|
|
{
|
|
ulong pos_id = (ulong)HistoryDealGetInteger(d, DEAL_POSITION_ID);
|
|
int cat = (Current_State == STATE_CONTINUATION) ? 0 : 1;
|
|
NN_CaptureEntry(pos_id, false, reason,
|
|
Coordinator_Cluster_Strength, Coordinator_Conflict_Score, cat);
|
|
}
|
|
}
|
|
}
|
|
return ok;
|
|
}
|
|
|
|
#endif
|