Init nến m15
This commit is contained in:
@@ -0,0 +1,165 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| MotherBarBreakout.mq5 |
|
||||
//| M15: thân nến >= K × TB thân N nến liền trước |
|
||||
//+------------------------------------------------------------------+
|
||||
#property copyright "MotherBarBreakout"
|
||||
#property version "2.01"
|
||||
|
||||
#property description "M15 large body: body >= K × average of N prior bodies. Marks on chart."
|
||||
|
||||
input ENUM_TIMEFRAMES InpTf = PERIOD_M15;
|
||||
input int InpAvgPriorBodies = 10; // TB của 10 thân nến liền trước
|
||||
input double InpBodyVsAvgMult = 3.0; // thân hiện tại >= hệ số này × TB (vd 3 = gấp 3)
|
||||
input int InpScanBarsOnInit = 300;
|
||||
input bool InpClearMarksOnInit = true;
|
||||
|
||||
input color InpClrBullBar = clrDodgerBlue; // nến tăng (chỉ phân biệt hướng nến, không lọc trend)
|
||||
input color InpClrBearBar = clrDarkOrange;
|
||||
input int InpArrowSize = 2;
|
||||
input int InpArrowOffsetPts = 20;
|
||||
|
||||
const string OBJ_PFX = "MBB_";
|
||||
|
||||
datetime g_lastBarTime = 0;
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
double BodyAbs(const string sym, const ENUM_TIMEFRAMES tf, const int sh)
|
||||
{
|
||||
return MathAbs(iClose(sym, tf, sh) - iOpen(sym, tf, sh));
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Thân nến sh >= InpBodyVsAvgMult × TB thân sh+1 .. sh+n //
|
||||
//+------------------------------------------------------------------+
|
||||
bool IsBodyLargerThanPriorAverage(const string sym, const ENUM_TIMEFRAMES tf,
|
||||
const int sh, const int nAvg)
|
||||
{
|
||||
if(nAvg < 1)
|
||||
return false;
|
||||
|
||||
if(InpBodyVsAvgMult <= 0.0)
|
||||
return false;
|
||||
|
||||
const int need = sh + nAvg + 1;
|
||||
if(Bars(sym, tf) < need)
|
||||
return false;
|
||||
|
||||
double sum = 0.0;
|
||||
for(int k = 1; k <= nAvg; k++)
|
||||
sum += BodyAbs(sym, tf, sh + k);
|
||||
|
||||
const double avg = sum / (double)nAvg;
|
||||
const double body = BodyAbs(sym, tf, sh);
|
||||
const double threshold = InpBodyVsAvgMult * avg;
|
||||
|
||||
return (body >= threshold);
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
void DeleteMarkersByPrefix()
|
||||
{
|
||||
const long chart_id = ChartID();
|
||||
const int n = ObjectsTotal(chart_id, 0, -1);
|
||||
for(int i = n - 1; i >= 0; i--)
|
||||
{
|
||||
const string name = ObjectName(chart_id, i, 0, -1);
|
||||
if(StringFind(name, OBJ_PFX) == 0)
|
||||
ObjectDelete(chart_id, name);
|
||||
}
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
void PlaceMarker(const string sym, const ENUM_TIMEFRAMES tf, const int sh)
|
||||
{
|
||||
const datetime t = iTime(sym, tf, sh);
|
||||
const string name = OBJ_PFX + IntegerToString((long)t);
|
||||
const long chart_id = ChartID();
|
||||
|
||||
if(ObjectFind(chart_id, name) >= 0)
|
||||
return;
|
||||
|
||||
const bool bull = (iClose(sym, tf, sh) >= iOpen(sym, tf, sh));
|
||||
const int dig = (int)SymbolInfoInteger(sym, SYMBOL_DIGITS);
|
||||
const double pt = SymbolInfoDouble(sym, SYMBOL_POINT);
|
||||
|
||||
double price = 0.0;
|
||||
if(bull)
|
||||
price = iLow(sym, tf, sh) - InpArrowOffsetPts * pt;
|
||||
else
|
||||
price = iHigh(sym, tf, sh) + InpArrowOffsetPts * pt;
|
||||
price = NormalizeDouble(price, dig);
|
||||
|
||||
if(!ObjectCreate(chart_id, name, OBJ_ARROW, 0, t, price))
|
||||
return;
|
||||
|
||||
ObjectSetInteger(chart_id, name, OBJPROP_ARROWCODE, bull ? 233 : 234);
|
||||
ObjectSetInteger(chart_id, name, OBJPROP_COLOR, bull ? InpClrBullBar : InpClrBearBar);
|
||||
ObjectSetInteger(chart_id, name, OBJPROP_WIDTH, InpArrowSize);
|
||||
ObjectSetInteger(chart_id, name, OBJPROP_ANCHOR, bull ? ANCHOR_TOP : ANCHOR_BOTTOM);
|
||||
ObjectSetInteger(chart_id, name, OBJPROP_BACK, false);
|
||||
ObjectSetInteger(chart_id, name, OBJPROP_SELECTABLE, false);
|
||||
ObjectSetInteger(chart_id, name, OBJPROP_HIDDEN, false);
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
void TryMarkAtShift(const string sym, const ENUM_TIMEFRAMES tf, const int sh)
|
||||
{
|
||||
if(IsBodyLargerThanPriorAverage(sym, tf, sh, InpAvgPriorBodies))
|
||||
PlaceMarker(sym, tf, sh);
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
void ScanHistory(const string sym, const ENUM_TIMEFRAMES tf, const int maxBars)
|
||||
{
|
||||
if(maxBars <= 0)
|
||||
return;
|
||||
|
||||
const int n = MathMin(maxBars, Bars(sym, tf) - InpAvgPriorBodies - 2);
|
||||
for(int sh = 1; sh <= n; sh++)
|
||||
TryMarkAtShift(sym, tf, sh);
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
int OnInit()
|
||||
{
|
||||
if(InpAvgPriorBodies < 1)
|
||||
{
|
||||
Print("[MBB] InpAvgPriorBodies phải >= 1");
|
||||
return INIT_FAILED;
|
||||
}
|
||||
if(InpBodyVsAvgMult <= 0.0)
|
||||
{
|
||||
Print("[MBB] InpBodyVsAvgMult phải > 0");
|
||||
return INIT_FAILED;
|
||||
}
|
||||
|
||||
if(InpClearMarksOnInit)
|
||||
DeleteMarkersByPrefix();
|
||||
|
||||
ScanHistory(_Symbol, InpTf, InpScanBarsOnInit);
|
||||
|
||||
g_lastBarTime = iTime(_Symbol, InpTf, 0);
|
||||
ChartRedraw();
|
||||
return INIT_SUCCEEDED;
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
void OnDeinit(const int reason)
|
||||
{
|
||||
DeleteMarkersByPrefix();
|
||||
ChartRedraw();
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
void OnTick()
|
||||
{
|
||||
const datetime t0 = iTime(_Symbol, InpTf, 0);
|
||||
if(t0 == 0 || t0 == g_lastBarTime)
|
||||
return;
|
||||
g_lastBarTime = t0;
|
||||
|
||||
TryMarkAtShift(_Symbol, InpTf, 1);
|
||||
ChartRedraw();
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
Reference in New Issue
Block a user