MT5-分享交易程式碼

//+------------------------------------------------------------------+
//| V15_Variant_3.mq5 |
//| H1 trend + M1/M5 KD/BB pullback resonance for FIRST entry only |
//| Adds still use fixed grid step 0.001 * first price. |
//| Attach on M5 or M15 recommended. |
//+------------------------------------------------------------------+
#property copyright "EAM1 Training V15"
#property version "15.30"
#property description "V15-3 KD/BB pullback first-entry BUY grid"
#property strict
#include <Trade/Trade.mqh>
#define FIXED_LOTS 0.01
input group "=== Identity ==="
input long InpMagic = 715003;
input string InpComment = "V15_Var3";
input int InpMaxSpreadPoints = 400;
input group "=== Shared grid math ==="
input int InpMaxGridLayers = 20;
input double InpGridStepFrac = 0.001;
input double InpSlFrac = 0.976;
input int InpCooldownBars = 3;
input group "=== Variant3: HTF direction ==="
input ENUM_TIMEFRAMES InpHtf = PERIOD_H1;
input int InpHtfEmaFast = 50;
input int InpHtfEmaSlow = 200;
input bool InpExitOnHtfBear = true;
input bool InpBlockAddOnBear = true;
input group "=== Variant3: First-entry resonance (chart TF) ==="
input int InpKPeriod = 5;
input int InpDPeriod = 3;
input int InpSlowing = 3;
input double InpKdMax = 35.0; // KD below this + golden cross
input int InpBbPeriod = 20;
input double InpBbDev = 2.0;
input bool InpAllowKdOrBb = true; // OR logic: KD golden OR touch BB lower
//+------------------------------------------------------------------+
CTrade trade;
CPositionInfo pos;
int g_hEmaFast = INVALID_HANDLE;
int g_hEmaSlow = INVALID_HANDLE;
int g_hStoch = INVALID_HANDLE;
int g_hBb = INVALID_HANDLE;
datetime g_lastBar = 0;
double g_initPrice = 0.0;
double g_gridStep = 0.0;
//+------------------------------------------------------------------+
double TpMultByCount(const int count)
{
if(count <= 1) return 1.0020;
if(count == 2) return 1.0015;
if(count == 3) return 1.0012;
if(count == 4) return 1.0009;
if(count == 5) return 1.0006;
if(count == 6) return 1.0003;
return 1.0001;
}
//+------------------------------------------------------------------+
bool SpreadOk()
{
return ((int)SymbolInfoInteger(_Symbol, SYMBOL_SPREAD) <= InpMaxSpreadPoints);
}
//+------------------------------------------------------------------+
double NormLot(double lot)
{
double vmin = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MIN);
double vmax = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MAX);
double step = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_STEP);
if(step <= 0.0) step = 0.01;
if(lot < vmin) lot = vmin;
if(lot > vmax) lot = vmax;
lot = MathFloor(lot / step + 1e-8) * step;
return NormalizeDouble(lot, 2);
}
//+------------------------------------------------------------------+
int DigitsSym() { return (int)SymbolInfoInteger(_Symbol, SYMBOL_DIGITS); }
//+------------------------------------------------------------------+
bool HtfBull()
{
if(g_hEmaFast == INVALID_HANDLE || g_hEmaSlow == INVALID_HANDLE) return false;
double f[], s[];
ArraySetAsSeries(f, true);
ArraySetAsSeries(s, true);
if(CopyBuffer(g_hEmaFast, 0, 0, 3, f) < 3) return false;
if(CopyBuffer(g_hEmaSlow, 0, 0, 3, s) < 3) return false;
double c1 = iClose(_Symbol, InpHtf, 1);
return (c1 > f[1] && f[1] > s[1]);
}
//+------------------------------------------------------------------+
bool HtfBearBreak()
{
if(g_hEmaFast == INVALID_HANDLE || g_hEmaSlow == INVALID_HANDLE) return false;
double f[], s[];
ArraySetAsSeries(f, true);
ArraySetAsSeries(s, true);
if(CopyBuffer(g_hEmaFast, 0, 0, 3, f) < 3) return false;
if(CopyBuffer(g_hEmaSlow, 0, 0, 3, s) < 3) return false;
double c1 = iClose(_Symbol, InpHtf, 1);
bool death = (f[2] >= s[2] && f[1] < s[1]);
bool below = (c1 < s[1]);
return (death || below);
}
//+------------------------------------------------------------------+
bool FirstEntrySignal()
{
double k[], d[], bbLower[], bbMid[], bbUpper[];
ArraySetAsSeries(k, true);
ArraySetAsSeries(d, true);
ArraySetAsSeries(bbLower, true);
ArraySetAsSeries(bbMid, true);
ArraySetAsSeries(bbUpper, true);
if(CopyBuffer(g_hStoch, 0, 0, 3, k) < 3) return false;
if(CopyBuffer(g_hStoch, 1, 0, 3, d) < 3) return false;
// iBands: 0=BASE, 1=UPPER, 2=LOWER
if(CopyBuffer(g_hBb, 2, 0, 3, bbLower) < 3) return false;
double c1 = iClose(_Symbol, PERIOD_CURRENT, 1);
double l1 = iLow(_Symbol, PERIOD_CURRENT, 1);
bool kdGold = (k[2] <= d[2] && k[1] > d[1]);
bool kdOs = (k[1] <= InpKdMax || k[2] <= InpKdMax);
bool kdOk = (kdGold && kdOs);
bool touchBb = (l1 <= bbLower[1] || c1 <= bbLower[1]);
if(InpAllowKdOrBb)
return (kdOk || touchBb);
return (kdOk && touchBb);
}
//+------------------------------------------------------------------+
int CountBuys(double &avg, double &lowest, datetime &lastT, datetime &oldest)
{
int n = 0;
double cost = 0.0, vol = 0.0;
avg = 0.0;
lowest = 0.0;
lastT = 0;
oldest = 0;
bool have = false;
for(int i = PositionsTotal() - 1; i >= 0; --i)
{
if(!pos.SelectByIndex(i)) continue;
if(pos.Symbol() != _Symbol || pos.Magic() != InpMagic) continue;
if(pos.PositionType() != POSITION_TYPE_BUY) continue;
n++;
double p = pos.PriceOpen();
double v = pos.Volume();
cost += p * v;
vol += v;
if(!have || p < lowest) { lowest = p; have = true; }
if(pos.Time() > lastT) lastT = pos.Time();
if(oldest == 0 || pos.Time() < oldest) oldest = pos.Time();
}
avg = (vol > 0.0 ? cost / vol : 0.0);
return n;
}
//+------------------------------------------------------------------+
bool CloseAllBuys(const string reason)
{
bool ok = true;
for(int i = PositionsTotal() - 1; i >= 0; --i)
{
if(!pos.SelectByIndex(i)) continue;
if(pos.Symbol() != _Symbol || pos.Magic() != InpMagic) continue;
if(pos.PositionType() != POSITION_TYPE_BUY) continue;
if(!trade.PositionClose(pos.Ticket()))
{
ok = false;
Print(InpComment, " CLOSE FAIL ", reason, " ", trade.ResultRetcode());
}
}
if(ok)
{
Print(InpComment, " CLOSE_ALL ", reason);
g_initPrice = 0.0;
g_gridStep = 0.0;
}
return ok;
}
//+------------------------------------------------------------------+
void SyncSl(const double slPrice)
{
int digits = DigitsSym();
double sl = NormalizeDouble(slPrice, digits);
long stops = SymbolInfoInteger(_Symbol, SYMBOL_TRADE_STOPS_LEVEL);
double minD = (double)stops * _Point;
double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);
if(sl >= bid - minD)
sl = NormalizeDouble(bid - MathMax(minD, 10 * _Point), digits);
for(int i = PositionsTotal() - 1; i >= 0; --i)
{
if(!pos.SelectByIndex(i)) continue;
if(pos.Symbol() != _Symbol || pos.Magic() != InpMagic) continue;
if(pos.PositionType() != POSITION_TYPE_BUY) continue;
if(MathAbs(pos.StopLoss() - sl) > _Point)
trade.PositionModify(pos.Ticket(), sl, 0.0);
}
}
//+------------------------------------------------------------------+
bool OpenBuy(const bool isAdd)
{
if(!SpreadOk()) return false;
trade.SetExpertMagicNumber(InpMagic);
trade.SetDeviationInPoints(40);
trade.SetTypeFillingBySymbol(_Symbol);
double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
if(!isAdd)
{
g_initPrice = ask;
g_gridStep = g_initPrice * InpGridStepFrac;
if(g_gridStep <= 0.0) g_gridStep = 10 * _Point;
}
double sl = NormalizeDouble(g_initPrice * InpSlFrac, DigitsSym());
bool ok = trade.Buy(NormLot(FIXED_LOTS), _Symbol, ask, sl, 0.0,
isAdd ? InpComment + "_G" : InpComment + "_0");
if(ok)
{
Print(InpComment, isAdd ? " GRID" : " OPEN0",
" ask=", ask, " init=", g_initPrice, " step=", g_gridStep);
SyncSl(g_initPrice * InpSlFrac);
}
else
Print(InpComment, " BUY FAIL ", trade.ResultRetcode(), " ",
trade.ResultRetcodeDescription());
return ok;
}
//+------------------------------------------------------------------+
void RecoverInitFromPositions()
{
double hi = 0.0;
for(int i = PositionsTotal() - 1; i >= 0; --i)
{
if(!pos.SelectByIndex(i)) continue;
if(pos.Symbol() != _Symbol || pos.Magic() != InpMagic) continue;
if(pos.PositionType() != POSITION_TYPE_BUY) continue;
if(pos.PriceOpen() > hi) hi = pos.PriceOpen();
}
if(hi > 0.0)
{
g_initPrice = hi;
g_gridStep = g_initPrice * InpGridStepFrac;
}
}
//+------------------------------------------------------------------+
int OnInit()
{
trade.SetExpertMagicNumber(InpMagic);
g_hEmaFast = iMA(_Symbol, InpHtf, InpHtfEmaFast, 0, MODE_EMA, PRICE_CLOSE);
g_hEmaSlow = iMA(_Symbol, InpHtf, InpHtfEmaSlow, 0, MODE_EMA, PRICE_CLOSE);
g_hStoch = iStochastic(_Symbol, PERIOD_CURRENT, InpKPeriod, InpDPeriod, InpSlowing,
MODE_SMA, STO_LOWHIGH);
g_hBb = iBands(_Symbol, PERIOD_CURRENT, InpBbPeriod, 0, InpBbDev, PRICE_CLOSE);
if(g_hEmaFast == INVALID_HANDLE || g_hEmaSlow == INVALID_HANDLE ||
g_hStoch == INVALID_HANDLE || g_hBb == INVALID_HANDLE)
return INIT_FAILED;
Print(InpComment, " V15_Variant_3 H1 bull + KD<=", InpKdMax,
" OR BB lower | step=", InpGridStepFrac, " sl=", InpSlFrac);
return INIT_SUCCEEDED;
}
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
if(g_hEmaFast != INVALID_HANDLE) IndicatorRelease(g_hEmaFast);
if(g_hEmaSlow != INVALID_HANDLE) IndicatorRelease(g_hEmaSlow);
if(g_hStoch != INVALID_HANDLE) IndicatorRelease(g_hStoch);
if(g_hBb != INVALID_HANDLE) IndicatorRelease(g_hBb);
}
//+------------------------------------------------------------------+
void OnTick()
{
double avg = 0.0, lowest = 0.0;
datetime lastT = 0, oldest = 0;
int count = CountBuys(avg, lowest, lastT, oldest);
if(count == 0)
{
g_initPrice = 0.0;
g_gridStep = 0.0;
}
else if(g_initPrice <= 0.0)
RecoverInitFromPositions();
bool htfOk = HtfBull();
bool htfBreak = HtfBearBreak();
if(count > 0 && InpExitOnHtfBear && htfBreak)
{
CloseAllBuys("HTF_BEAR_BREAK");
return;
}
double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);
double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
if(count > 0 && avg > 0.0 && g_initPrice > 0.0)
{
double slPrice = g_initPrice * InpSlFrac;
double tpPrice = avg * TpMultByCount(count);
SyncSl(slPrice);
if(bid <= slPrice)
{
CloseAllBuys("SL_0.976");
return;
}
if(bid >= tpPrice)
{
Print(InpComment, " TP count=", count, " avg=", avg);
CloseAllBuys("BASKET_TP");
return;
}
// adds: fixed grid only; still require HTF bull if enabled
bool allowAdd = true;
if(InpBlockAddOnBear && !htfOk) allowAdd = false;
if(allowAdd && count < InpMaxGridLayers && g_gridStep > 0.0)
{
int barsPassed = (lastT > 0 ? iBarShift(_Symbol, PERIOD_CURRENT, lastT) : 0);
if(barsPassed < 0) barsPassed = 0;
if(barsPassed >= InpCooldownBars && ask <= lowest - g_gridStep)
OpenBuy(true);
}
}
datetime t = iTime(_Symbol, PERIOD_CURRENT, 0);
if(t == 0 || t == g_lastBar) return;
g_lastBar = t;
if(count != 0) return;
if(!htfOk) return;
if(!FirstEntrySignal()) return;
OpenBuy(false);
}
//+------------------------------------------------------------------+