After a full set of days of AFL learning and programming, I have completed and debugged the Tom DeMark "TD Trendlines" indicator.
It implements the qualification of trendline breaks for both supply and demand.
It calculates 3 different price objectives for both long and short trades.
I have added some risk management calculations for me to start paper trading using IB plugin and real time quotes.
I am sure many sections could be much improved. If any of you have interest in Tom DeMark's methodologies you are welcome to use it.
@portfoliobuilder mentioned some interest in TD so here goes.
It includes lots of documentation as to the TD rules.
_SECTION_BEGIN ("TD Trendlines-true TD");
GraphXSpace = 20;
//SetChartOptions(0,chartShowArrows|chartShowDates);
_N(Title = StrFormat("{{NAME}} - {{INTERVAL}} {{DATE}} Open %.3f, Hi %.3f, Lo %.3f, Close %.3f (%.1f%%) {{VALUES}}", O, H, L, C, SelectedValue( ROC( C, 1 ) ) ));
Plot(C, "", IIf(O>=C, colorRed, colorGreen), styleBar, Null, Null, 0, 0, 3);
pointLevel = Param("Pivot Point Level.................", 1, 1,10,1,0);
pointAddCondition = ParamToggle("Additional TD Point Condition.....", "No|Yes", 0);
showPoints = ParamToggle("Show TD Points....................","No|Yes", 1);
showDblPoints = ParamToggle("Show Double TD Points.............", "No|Yes", 0);
C1cancel = ParamToggle("Use break Cancellation C1.........", "No|Yes", 1);
C2cancel = ParamToggle("Use break Cancellation C2.........", "No|Yes", 1);
C3cancel = ParamToggle("Use break Cancellation C3.........", "No|Yes", 0);
minPercent = Param("Minimum Percent gain to enter.....", 3, 1, 10, .1, .1);
lPriceObjRed = Param("Long Price Objective % reduction..", 0, 0, 25, 1,1);
sPriceObjRed = Param("Short Price Objective % reduction.", 0, 0, 25, 1,1);
//previousSTrendline = Param("Use Previous Supply Trendline.....", 0, 0, 2, 1, 1);
//previousDTrendline = Param("Use Previous Demand Trendline.......", 0, 0, 2, 1, 1);
showDisqualified = ParamToggle("Show Disqualified Breaks..........", "No|Yes", 1);
showQualified = ParamToggle("Show Qualified Breaks.............", "No|Yes", 1);
capital = Param ("Working Capital...................", 2000, 1000, 5000, 100, 100);
riskPercent = Param ("Percentage of capital to risk.....", .01, .01, .02, .001, .001);
SetBarsRequired(sbrAll, 0);
//****************************************variables declaration*****************************************
firstSupply = secondSupply = Null;
twoSupplyPointsFound = twoDemandPointsFound = 0;
firstDemand = secondDemand = Null;
supplyLine = demandLine = Null;
loopLimit = Null;
TDsPoints = Null;
sLineCancelled = dLineCancelled = Null;
sBreakCancelled = dBreakCancelled = Null;
//sLineQualified = Null;
//dLineQualified = Null;
shapePosAdj = 8;
textPosAdj = 18;
sStartPos = 23;
dStartPos = -32;
prev1SPos = sStartPos;
currSPos = sStartPos;
currDPos = dStartPos;
prev1DPos = dStartPos;
sLineROA = dLineROA = Null;
sendSAlert = sendDAlert = False;
disqualifiedSBreak = disqualifiedDBreak = False;
sx0 = sx1 = sy0 = sy1 = dx0 = dx1 = dy0 = dy1 = Null;
supplyBreakOutBar = demandBreakOutBar = Null;
slevel = dLevel = False;
sBreak = dBreak = Null;
sQ1 = sQ2 = sQ3 = dQ1 = dQ2 = dQ3 = sC1 = sC2 = sC3 = dC1 = dC2 = dC3 = Null;
lastBar = Barcount - 1;
supplyPriceObj1Value = Null;
supplyPriceObj2Value = Null;
demandPriceObj1Value = Null;
demandPriceObj2Value = Null;
//*************************************Functions Declarations******************************************
//****************************************** TD Price Projectors **********************************************
//TD Price Projector 1,
// the least precise and the easiest to calculate, is as follows:
// when price advances above a declining TD Line,
// usually price continues to advance to at least a price level
// equivalent to the distance tance between the lowest price value beneath the TD Line
// and the TD Line value directly above it,
// added to the TD Line value on the day of the breakout to the upside
// What may sound complex when described in words is very simple when viewed on the chart (see Figure 1.16).
//
//Thomas R. DeMark. The New Science of Technical Analysis (Kindle Locations 244-247). Kindle Edition.
function lowestObjective (obj1, obj2, obj3)
{
if (obj1 < obj2 AND NOT AlmostEqual(obj1, obj2, 5))
{
lowestObj = obj1;
} else if (obj2 < obj3 AND NOT AlmostEqual(obj2, obj3, 5))
{
lowestObj = obj2;
} else{
lowestObj = obj3;
}
return lowestObj;
}
function highestObjective (obj1, obj2, obj3)
{
if (obj1 > obj2 AND NOT AlmostEqual(obj1, obj2, 5))
{
highestObj = obj1;
} else if (obj2 > obj3 AND NOT AlmostEqual(obj2, obj3, 5))
{
highestObj = obj2;
} else{
highestObj = obj3;
}
return highestObj;
}
function unitsToBuy ( entryPrice, risk)
{
amountToRisk = capital * riskPercent;
units = floor(amountToRisk / risk);
capitalUnits = floor(capital / 5 / entryPrice);
if (units < capitalUnits)
{
maxUnits = units;
} else maxUnits = capitalUnits;
return maxUnits;
}
function breakSPriceObj3 (supplyline, trueLow, barID)
{
obj = supplyline[barID-1] - truelow[barID-1];
nextBarLineValue = supplyline[barID] - (supplyline[barID-1] - supplyline[barID]);
priceObj = supplyline[barID] + (obj * (1 - (lPriceObjRed/100)));
return priceObj;
}
function breakDPriceObj3 (demandline, trueHigh, barID)
{
obj = trueHigh[barID-1] - demandline[barID-1];
nextBarLineValue = demandline[barID] + (demandline[barID] - demandLine[barID-1]);
priceObj = demandline[barID] - (obj * (1 - (sPriceObjRed/100)));
return priceObj;
}
function LineCrossBar(dLine, sLine)
{
notFound = 1;
crossBar = Null;
TDCrossBar = Cross(dLine, sLine);
for (i=BarCount - 1; i > 0 AND notFound; i--)
{
if (TDCrossBar[i] == 1)
{
crossBar = i;
notFound = 0;
break;
}
}
shortLoop = IIf(IsNull(crossBar), BarCount - 1, crossBar);
return shortLoop;
}
function trendLineROA(tdLine, firstPoint, secondPoint)
{
//determine number of bars between points
//substract linevalue between second and first point
//divide change by number of bars
// return ROC
// negative values for supply line
// positive values for demand line
lineROA = (tdLine[secondPoint] - tdLine[firstPoint] ) / (firstPoint - secondPoint);
return lineROA;
}
//****************************************BUILD Arrays******************************************
//******************************* True Lows and True Highs**************************************
// a true High is the high of the current day or the previous day's Close if higher
// a true Low is the Low of the current day or the previous day's Close if lower
tL = Min(Ref(C,-1), L);
tH = Max(Ref(C,-1), H);
//********************* TD Points arrays (supply and demand) - level as per Parameter ***********
//ll = LLV(tL,pointLevel); // if tL == L no TD point is defined
//hh = HHV(tH,pointLevel); // if tH == H no TD point is defined
// when I become fully familiar in recognizing the Qualifies and Cancellations
// I will reinstate the true Highs(tH) and true Lows (tL)
ll = LLV(L,pointLevel);
hh = HHV(H,pointLevel);
// Consider adding an additional qualifier to identify TD Points:
// 2. Not only must the highs the day before and the day after be less than the highest high-the high in between
// but the pivot high must also be greater than the close two days before the high.
//
// Thomas R. DeMark. The New Science of Technical Analysis (Kindle Locations 200-201). Kindle Edition. Chapter 1 Figure 1.7
//
// pivot High > Ref(C, -2) with Parameter to turn On/Off
// pivot Low > Ref(C, -2)
if (pointAddCondition AND pointLevel == 1) // see paramToggle
{
TDdPoints = L < Ref(ll,-1) AND L < Ref(ll,pointLevel) AND L < Ref(C, -2);
TDsPoints = H > Ref(hh,-1) AND H > Ref(hh,pointLevel) AND H > Ref(C, -2);
} else
{
TDdPoints = L < Ref(ll,-1) AND L < Ref(ll,pointLevel);
TDsPoints = H > Ref(hh,-1) AND H > Ref(hh,pointLevel);
}
//*********************************** TD Double TD Points ******************************************
/*
If a level 1 TD Point low is defined,
and subsequently a second level 1 TD Point low is formed at a higher price level,
then this secondary test of the original low generally confirms that the price trend should be up.
On the other hand, if a level 1 TD Point high is defined,
and subsequently a second level 1 TD Point high is formed at a lower price level,
then this secondary test of the original high usually confirms that the trend should be down.
Research indicates that subsequent to the formation of the second TD Point low,
once the high of the second TD Point low day is exceeded upside,
then the trend should be up.
Conversely, subsequent to the formation of the second TD Point high,
once the low of the second TD Point high day is exceeded downside,
then the trend should be down.
page 230-231
Thomas R. DeMark. New Market Timing Techniques: Innovative Studies in Market Rhythm & Price Exhaustion (p. 230). Kindle Edition.
*/
//******************************** will use True Highs and True Lows to identify TD Double TD Points *************************************
firstSpoint = firstDPoint = True;
subsequentSPoint = subsequentDPoint = True;
TDdTDsPoints = TDdTDdPoints = Null;
for (i = 0; i < BarCount-1; i++)
{
if (TDsPoints[i])
{
if (firstSPoint)
{
firstSPoint = False;
previousSTDPoint = i;
}
else if (tH[i] < tH[previousSTDpoint])
{
firstSPoint = False;
TDdTDsPoints[i] = True;
TDdTDsPoints[previousSTDPoint] = True;
previousSTDPoint = i;
} else
{
TDdTDsPoints[i] = False;
previousSTDPoint = i;
//firstSPoint = True;
subsequentSPoint = True;
}
}
}
for (i = 0; i < BarCount-1; i++)
{
if (TDdPoints[i])
{
if (firstDPoint)
{
firstDPoint = False;
previousDTDPoint = i;
}else if(tL[i] > tL[previousDTDPoint])
{
firstDPoint = False;
TDdTDdPoints[i] = True;
TDdTDsdPoints[previousDTDPoint] = True;
previousDTDPoint = i;
} else
{
TDdTDdPoints[i] = False;
previousDTDPoint = i;
//firstSPoint = True;
subsequentDPoint = True;
}
}
}
//*********************************** Show all TD Points ***************************************
if (showPoints)
{
PlotShapes(IIf(TDsPoints, shapeSmallCircle, shapeNone),colorRed, 0, H, shapePosAdj, 0);
PlotShapes(IIf(TDdPoints, shapesmallCircle, shapeNone), colorGreen, 0, L, -shapePosAdj, 0);
}
if (showDblPoints)
{
PlotShapes(IIf(TDdTDsPoints, shapeHollowCircle, shapeNone),colorRed, 0, H, shapePosAdj, 0);
PlotShapes(IIf(TDdTDdPoints, shapeHollowCircle, shapeNone), colorGreen, 0, L, -shapePosAdj, 0);
}
//***************************** Supply and Demand Lines ****************************************
// For now only the last supply and demand lines are drawn as per level parameter
// TD Trendlines are drawn from Right to Left as per TD Demark
// Loop from right to left
for (i = BarCount-1; twoSupplyPointsFound < 2 AND i != 0; i--)
{
if (twoSupplyPointsFound == 0 AND TDsPoints[i])
{
firstSupply = i;
sx0 = firstSupply;
sy0 = H[firstSupply];
twoSupplyPointsFound++;
} else if (twoSupplyPointsFound == 1 AND TDsPoints[i] AND H[i] > H[firstSupply])
{
secondSupply = i;
sx1 = secondSupply;
sy1 = H[secondSupply];
twoSupplyPointsFound++;
}
}
for (i = BarCount-1; twoDemandPointsFound < 2 AND i != 0; i--)
{
if (twoDemandPointsFound == 0 AND TDdPoints[i])
{
firstDemand = i;
dx0 = firstDemand;
dy0 = L[firstDemand];
twoDemandPointsFound++;
} else if (twoDemandPointsFound == 1 AND TDdPoints[i] AND (L[i] < L[firstDemand]))
{
secondDemand = i;
dx1 = secondDemand;
dy1 = L[secondDemand];
twoDemandPointsFound++;
}
}
foundTwoSPoints = NOT IsNull(secondSupply) AND NOT IsNull(firstSupply);
foundTwoDpoints = (NOT IsNull(secondDemand)) AND (NOT IsNull(firstDemand));
if (foundTwoSPoints)
{
supplyLine = LineArray(sx1, sy1, sx0, sy0, 1, 0);
sLineROA = trendLineROA(supplyLine, firstSupply, secondSupply);
} else
{
printf("No second supply point found for level %g-No supply trendline\n", pointLevel);
}
if (foundTwoDpoints)
{
demandLine = LineArray(dx1, dy1, dx0, dy0, 1, 0);
dLineROA = trendLineROA(demandLine, firstDemand, secondDemand);
} else
{
printf("No second demand point found for level %g- No Demand Line\n", pointLevel);
}
// sQ2 *********************
// if the opening price is above the TD Line,
// then the dynamics of the marketplace have more than likely shifted so dramatically in favor of buyers
// and the upside since the previous day's close that the breakout is legitimized.
// However; two additional conditions, not included in my previous book, must also be present to confirm Qualifier 2
// 1.- First of all, the opening price must not only be above the TD Supply Line
// but also above the previous day's close since it is possible, if the TD Supply Line is very steep,
// that price can open above the line but below the previous day's close.
// 2.- Second, price must follow through upside by at least one or two price ticks above the opening price level
// since the opening could be a last gasp of demand in a price vacuum caused by the specialists or market makers,
// and this exhaustion would not present a buying opportunity; rather, it would coincide with a price peak.
//
// Thomas R. DeMark. New Market Timing Techniques: Innovative Studies in Market Rhythm & Price Exhaustion (pp. 167-168). Kindle Edition.
//
// sQ2 is valid if:
// O > trendline AND
// O > ref(C, -1)
// Follow through on Open by a few ticks to qualify (H > O)
// - supply trendline if qualified
// intraday entry is justified
// determine price objective and draw price objective line
//
// if price opens below supply trendline sQ1 needs to be validated
// sQ1 is valid if:
// The close on the trading day before an upside breakout must be a down close
//
// or sQ3 is valid if:
// Even if the close the previous trading day is up
// and the current day's opening price is below the TD Supply Line
// or fails to follow through after the open,
// if the current day's high is able to surpass a measure of the previous day's demand
// and then exceed the TD Supply Line, this demand should be sufficient to justify an intraday upside breakout,
// which will be confirmed for a conventional chartist by a closing price above the TD Supply Line.
// Calculate the previous day's expression of demand or buying
// by subtracting the difference between the previous day's closing price and that same day's true low
// (that same day's low or the previous trading day's close, whichever is less).
// Then add that value to the previous day's close to identify the level at which the buying pressure expressed that trading day
// will be replicated the current trading day.
// If this value is beneath the TD Supply Line and subsequent to price exceeding this measurement of demand
// and then exceeding the TD Supply Line, there is sufficient buying to justify intraday entry on the upside breakout.
// However, if the TD Supply Line breakout upside occurs prior to the measure of demand
// exceeding the previous day's level, Qualifier 3 is not fulfilled.
//
// Thomas R. DeMark. New Market Timing Techniques: Innovative Studies in Market Rhythm & Price Exhaustion (p. 168). Kindle Edition.
//
// 4. A potential new Qualifier that I am currently researching for inclusion to the Qualifier set
// relates the true price range the day before a breakout to the breakout level.
// Specifically, if that price range is doubled
// and the breakout level added to the previous trading day's close for an upside breakout
// (subtracted from the previous trading day's close for a downside breakout)
// exceeds these price levels, then the breakouts are disqualified.
// Otherwise they are qualified.
// Note that this is preliminary work, however.
//
// Thomas R. DeMark. New Market Timing Techniques: Innovative Studies in Market Rhythm & Price Exhaustion (p. 168). Kindle Edition.
// build arrays for qualification of bars within the supply and demand lines
// for Q1 and Q3 and C1, C2, C3 and C4
lowestSLowValue = 99999;
lowestSCloseValue = 99999;
if (foundTwoSPoints) // if a supply line exists
{
for (i = BarCount-1; i > secondSupply; i--) // find Lowest Low and lowest Close for upside price projections
{
if (L[i-1] < L[i] AND L[i-1] < lowestSLowValue AND L[i-1] < supplyLine[i-1])
{
lowestSLowBar = i - 1;
lowestSLowValue = L[i - 1];
supplyPriceObj1Value = supplyLine[i - 1] - L[i - 1];
} else
{
lowestSLowBar = i;
lowestSLowValue = L[i];
supplyPriceObj1Value = supplyLine[i] - L[i];
}
if (C[i-1] < C[i] AND C[i-1] < lowestSCloseValue AND C[i-1] < supplyLine[i-1])
{
lowestSCloseBar = i-1;
lowestSCloseValue = C[i-1];
supplyPriceObj2Value = supplyLine[i-1] - L[i-1];
}else
{
lowestSCloseBar = i;
lowestSCloseValue = C[i];
supplyPriceObj2Value = supplyLine[i] - L[i];
}
}
for (i = BarCount - 1; i > firstSupply + pointLevel; i--)
{
sBreak[i] = IIf(tH[i] > supplyLine[i] AND NOT AlmostEqual(tH[i], supplyLine[i], 4), True, False); // build supply break array
sQ2[i] = O[i] > supplyLine[i] AND H[i] > O[i]; // does bar i qualify for a sQ2 qualified break?
sendSAlert = IIf(sQ2[i] AND i == lastBar, True, False);
sQ1[i-1] = C[i-1] < C[i-2]; // now check for supply line Q1
sDiff = C[i-1] - tL[i-1]; // now check for supply line Q3
prevSDemandLevel = C[i-1] + sDiff; // yesterdays demand:
sQ3[i-1] = prevSDemandLevel < supplyLine[i]; // if previousDemandLevel < today's supplyLine
// Now does today's bar cancel yesterday's possible supply line Break
sC1[i] = iif (C1cancel AND O[i] < supplyLine[i], True, False);
sC2[i] = IIf (C2Cancel AND O[i] < C[i-1] AND C[i] < supplyLine[i-1], True, False);
sC3[i] = IIf (C3Cancel AND H[i] < tH[i -1], True, False );
// sC4 = see New Market timing Techniques pp 168
}
}
highestDHighValue = -99999;
highestDCloseValue = -99999;
if (foundTwoDPoints) // if a demand line exists
{
for (i = BarCount - 1; i >= secondDemand; i--) // find highest High for downside price projections
{
if (H[i-1] > H[i] AND H[i-1] > highestDHighValue AND H[i-1] > demandLine[i-1])
{
highestDHighBar = i-1;
highestDHighValue = L[i-1];
demandPriceObj1Value = H[i-1] - demandLine[i-1];
} else
{
highestDHighBar = i;
highestDHighValue = L[i];
demandPriceObj1Value = H[i] - demandLine[i];
}
if (C[i-1] > C[i] AND C[i-1] > highestDCloseValue AND C[i-1] > demandLine[i-1])
{
highestDCloseBar = i-1;
highestDCloseValue = C[i-1];
demandPriceObj2Value = H[i-1] - demandLine[i-1];
}
}
for (i = BarCount - 1; i > firstDemand + pointLevel; i--) // identify Qualifier and Cancellation bars
{
// build demand break array
dBreak[i] = IIf(tL[i] < demandLine[i] AND NOT AlmostEqual(tL[i], demandLine[i], 5), True, False);
dQ2[i] = O[i] < demandLine[i] AND NOT AlmostEqual(O[i], demandLine[i], 5) AND L[i] < O[i]; // initialize dQ2 as array of nulls
sendDAlert = IIf(dQ2[i] AND i == lastBar, True, False);
dQ1[i-1] = (C[i-1] > C[i-2]); // now check for demand line break Q1
dDiff = tH[i-1] - C[i-1] ; // now check for demand line break Q3
prevDdemandLevel = C[i-1] + dDiff; // determine yesterdays demand level
dQ3[i-1] = prevDdemandLevel > demandLine[i]; // if previous Demand Level > today's demand line
// now does today's bar cancel yesterdays possible demand line Break?
dC1[i] = IIf (C1cancel AND O[i] > demandLine[i], True, False);
dC2[i] = IIf (C2cancel AND O[i] > C[i-1] AND C[i] > demandLine[i-1], True, False);
dC3[i] = IIf(C3Cancel AND L[i] < tL[i -1], True, False );
//dC4 = see New Market timing Techniques pp 168
}
}
// Identify valid breaks according to parameter selections for Cancellation
qualifiedSBreak = Ref(sBreak, 0) AND (Ref(sQ3, -1) OR Ref(sQ1, -1) OR Ref(sQ2, 0));
qualifiedDBreak = Ref(dBreak, 0) AND (Ref(dQ3, -1) OR Ref(dQ1, -1) OR Ref(dQ2, 0));
disqualifiedDBreak[0] = False;
disqualifiedSBreak[0] = False;
if (C1Cancel AND NOT C2Cancel AND NOT C3Cancel)
{
disqualifiedSBreak = Ref(sBreak,0) AND (Ref(sQ3, -1) OR Ref(sQ1, -1) OR Ref(sQ2, 0))
AND (Ref(sC1, 1));
} else if (C1Cancel AND C2Cancel AND NOT C3Cancel)
{
disqualifiedSBreak = Ref(sBreak,0) AND (Ref(sQ3, -1) OR Ref(sQ1, -1) OR Ref(sQ2, 0))
AND (Ref(sC1, 1) OR Ref(sC2, 1));
} else if (C1Cancel AND C2Cancel AND C3Cancel)
{
disqualifiedSBreak = Ref(sBreak, 0) AND (Ref(sQ3, -1) OR Ref(sQ1, -1) OR Ref(sQ2, 0))
AND (Ref(sC1, 1) OR Ref(sC2, 1) OR Ref(sC3, 1));
} else if (NOT C1Cancel AND C2Cancel AND NOT C3Cancel)
{
disqualifiedSBreak = Ref(sBreak, 0) AND (Ref(sQ3, -1) OR Ref(sQ1, -1) OR Ref(sQ2, 0))
AND Ref(sC2, 1);
} else if (NOT C1Cancel AND C2Cancel AND C3Cancel)
{
disqualifiedSBreak = Ref(sBreak, 0) AND (Ref(sQ3, -1) OR Ref(sQ1, -1) OR Ref(sQ2, 0))
AND (Ref(sC2, 1) OR Ref(sC3, 1));
} else if (NOT C1Cancel AND NOT C2Cancel AND C3Cancel)
{
disqualifiedSBreak = Ref(sBreak, 0) AND (Ref(sQ3, -1) OR Ref(sQ1, -1) OR Ref(sQ2, 0))
AND Ref(sC3, 1);
}
if (C1Cancel AND NOT C2Cancel AND NOT C3Cancel)
{
disqualifiedDBreak = Ref(dBreak,0) AND (Ref(dQ3, -1) OR Ref(dQ1, -1) OR Ref(dQ2, 0))
AND (Ref(dC1, 1));
} else if (C1Cancel AND C2Cancel AND NOT C3Cancel)
{
disqualifiedDBreak = Ref(dBreak,0) AND (Ref(dQ3, -1) OR Ref(dQ1, -1) OR Ref(dQ2, 0))
AND (Ref(dC1, 1) OR Ref(dC2, 1));
} else if (C1Cancel AND C2Cancel AND C3Cancel)
{
disqualifiedDBreak = Ref(dBreak,0) AND (Ref(dQ3, -1) OR Ref(dQ1, -1) OR Ref(dQ2, 0))
AND (Ref(dC1, 1) OR Ref(dC2, 1) OR Ref(dC3, 1));
} else if (NOT C1Cancel AND C2Cancel AND NOT C3Cancel)
{
disqualifiedDBreak = Ref(dBreak,0) AND (Ref(dQ3, -1) OR Ref(dQ1, -1) OR Ref(dQ2, 0))
AND Ref(dC2, 1);
} else if (NOT C1Cancel AND C2Cancel AND C3Cancel)
{
disqualifiedDBreak = Ref(dBreak,0) AND (Ref(dQ3, -1) OR Ref(dQ1, -1) OR Ref(dQ2, 0))
AND (Ref(dC2, 1) OR Ref(dC3, 1));
} else if (NOT C1Cancel AND NOT C2Cancel AND C3Cancel)
{
disqualifiedDBreak = Ref(dBreak,0) AND (Ref(dQ3, -1) OR Ref(dQ1, -1) OR Ref(dQ2, 0))
AND Ref(dC3, 1);
}
//******************************************* Plotting Section analysis has been done *******************
posAdjust = 2; // used to properly align various Qualifiers and Cancellations
sLineType = 1; // Qualified Trendlines with be lines and Disqualified Trendlines will be dotted lines
spobjDrawn = False; // Supply price objective drawn
maxsPrice = Null; // maximum entry price to expect minimum percentage gain or risk/reward ratio
Buy = False;
buyPrice = Null;
for (i = firstSupply + pointLevel + 1; i <= BarCount-1; i++)
{
if (qualifiedSBreak[i])
{
if(sQ1[i-1])
{
PlotText("Q1", i-1.00, H[i-1], colorYellow, colorBlack, prev1SPos);
prev1SPos += textPosAdj;
}
if(sQ2[i])
{
PlotText("Q2", i, H[i], colorYellow, colorBlack, currSPos);
currSPos += textPosAdj;
}
if(sQ3[i-1])
{
PlotText("Q3", i-1.00, H[i-1], colorYellow, colorBlack, prev1SPos);
prev1SPos += textPosAdj;
}
/* ***********************************************************************************************************************
TBD - If previous break is disqualified today, cancel price objectives and recalculate them if today's break is qualified
**************************************************************************************************************************/
if(disqualifiedSBreak[i-1])
{
if(sC1[i])
{
PlotText("C1", i, H[i], colorBlack, colorYellow, currSPos);
currSPos -= textPosAdj;
}
if(sC2[i])
{
PlotText("C2", i, H[i], colorBlack, colorYellow, currSPos);
currSPos -= textPosAdj;
}
if(sC3[i])
{
PlotText("C3", i, H[i], colorBlack, colorYellow, currSPos);
currSPos -= textPosAdj;
}
}
if (NOT spobjDrawn)
{
PlotText("B", i+.02, H[i], colorDarkGreen, colorWhite, 2);
currSpos += textPosAdj;
//Draw Price Objective1 lines
ddt = Ref(DateTime(),i-1);
strdt = DateTimeToStr(ddt[i-1], 1);
brkPriceObj1 = supplyLine[i] + (supplyPriceObj1Value * ( 1.00 - (lPriceObjRed/100)));
brkPriceObj2 = supplyLine[i] + (supplyPriceObj2Value * ( 1.00 - (lPriceObjRed/100)));
brkPriceObj3 = breakSPriceObj3 (supplyLine, tL, i-1);
printf("(" + strdt +") intraday supply break, price obj 1: $%.3f \n", brkPriceObj1);
printf("(" + strdt +") intraday supply break, price obj 2: $%.3f \n", brkPriceObj2);
printf("(" + strdt +") intraday supply break, price obj 3: $%.3f \n", brkPriceObj3);
// When and how to enter trade as per my mgmt rules
safestObj = lowestObjective (brkPriceObj1, brkPriceObj2, brkPriceObj3);
entryPrice = supplyLine[i];
reward = safestObj - entryPrice;
riskAmt = supplyLine[i] - demandLine[firstDemand];
units2Buy = unitsToBuy(entryPrice, riskAmt);
riskReward = reward / riskAmt;
//Buy = riskReward > 1.25;
buyPrice = entryPrice;
SellPrice = safestObj;
printf("Units to buy: %.0f with Entry at $%.2f for a risk reward of %.2f\n", units2Buy, entryPrice, riskReward);
GfxSetCoordsMode(1);
GfxSetOverlayMode(0);
GfxSelectPen(colorGreen, 1, 0);
GfxMoveTo(i+0.1, brkPriceObj1);
GfxLineTo(BarCount + 1, brkPriceObj1);
pobjText = "a: " + NumToStr(brkPriceObj1, 1.3, True, False);
PlotTextSetFont(pobjText, "Times New Roman", 10, BarCount + 1.5, brkPriceObj1 * 1.000 , colorBlack, coloryellow, 0);
if (NOT AlmostEqual(brkPriceObj2, brkPriceObj1, 5))
{
GfxMoveTo(i+0.1, brkPriceObj2);
GfxLineTo(BarCount + 1, brkPriceObj2);
pobjText = "b: " + NumToStr(brkPriceObj2, 1.3, True, False);
PlotTextSetFont(pobjText, "Times New Roman", 10, BarCount + 1.5, brkPriceObj2 * 1.000 , colorBlack, coloryellow, 0);
posAdjust += posAdjust;
}
if (NOT AlmostEqual(brkPriceObj3, brkPriceObj2, 5))
{
GfxMoveTo(i+0.1, brkPriceObj3);
GfxLineTo(BarCount + 1, brkPriceObj3);
pobjText = "c: " + NumToStr(brkPriceObj3, 1.3, True, False);
PlotTextSetFont(pobjText, "Times New Roman", 8, BarCount + 1.5, brkPriceObj3 * 1.000 , colorBlack, colorYellow, 0);
}
spobjDrawn = True;
}
}
currSPos = sStartPos;
prev1SPos = currSPos;
}
dLineType = 1;
dpobjDrawn = False;
maxdPrice = Null;
dLineType = 1;
for (i = firstDemand + pointLevel + 1; i <= BarCount-1; i++)
{
if (qualifiedDBreak[i])
{
if(dQ1[i-1])
{
PlotText("Q1", i-1.00, L[i-1], colorYellow, colorBlack, prev1DPos);
prev1DPos -= textPosAdj;
}
if(dQ2[i])
{
PlotText("Q2", i, L[i], colorYellow, colorBlack, currDPos);
currDPos -= textPosAdj;
}
if(dQ3[i-1])
{
PlotText("Q3", i-1.00, L[i-1], colorYellow, colorBlack, prev1DPos);
prev1DPos -= textPosAdj;
}
if(disqualifiedDBreak[i-1])
{
if(dC1[i])
{
PlotText("C1", i, L[i], colorBlack, colorYellow, currDPos);
currDPos -= textPosAdj;
}
if(dC2[i])
{
PlotText("C2", i, L[i], colorBlack, colorYellow, currDPos);
currDPos -= textPosAdj;
}
if(dC3[i])
{
PlotText("C3", i, L[i], colorBlack, colorYellow, currDPos);
currDPos -= textPosAdj;
}
}
if (NOT dpobjDrawn)
{
PlotText("B", i+.02, L[i], colorDarkGreen, colorWhite, -15);
currDpos -= textPosAdj;
//plot price objectives
ddt = Ref(DateTime(),i-1);
strdt = DateTimeToStr(ddt[i-1], 1);
brkPriceObj1 = demandLine[i] - (demandPriceObj1Value * ( 1 - (sPriceObjRed/100)));
brkPriceObj2 = demandLine[i] - (demandPriceObj2Value * ( 1 - (sPriceObjRed/100)));
brkPriceObj3 = breakDPriceObj3 (demandLine, tH, i-1);
printf("(" + strdt +") intraday demand break, price obj 1: $%.3f \n", brkPriceObj1);
printf("(" + strdt +") intraday demand break, price obj 2: $%.3f \n", brkPriceObj2);
printf("(" + strdt +") intraday demand break, price obj 3: $%.3f \n", brkPriceObj3);
// When and how to enter trade as per my mgmt rules
safestObj = highestObjective (brkPriceObj1, brkPriceObj2, brkPriceObj3);
entryPrice = demandLine[i];
reward = entryPrice - safestObj;
riskAmt = demandLine[firstSupply] - demandLine[i];
units2Buy = unitsToBuy(entryPrice, riskAmt);
riskReward = reward / riskAmt;
//Buy = riskReward > 1.25;
buyPrice = entryPrice;
sellPrice = safestObj;
printf("Units to buy: %.0f with Entry at $%.2f for a risk reward of %.2f\n", units2Buy, entryPrice, riskReward);
GfxSetCoordsMode(1);
GfxSetOverlayMode(0);
GfxSelectPen(colorRed, 1, 0);
GfxMoveTo(i+0.1, brkPriceObj1);
GfxLineTo(BarCount + 1, brkPriceObj1);
pobjText = "a: " + NumToStr(brkPriceObj1, 1.3, True, False);
PlotTextSetFont(pobjText, "Times New Roman", 8, BarCount + 1.5, brkPriceObj1 * 1.00 , colorBlack, coloryellow, 0);
if (NOT AlmostEqual(brkPriceObj2, brkPriceObj1, 5))
{
GfxMoveTo(i+0.1, brkPriceObj2);
GfxLineTo(BarCount + 1, brkPriceObj2);
pobjText = "b: " + NumToStr(brkPriceObj2, 1.3, True, False);
PlotTextSetFont(pobjText, "Times New Roman", 10, BarCount + 1.5, brkPriceObj2 * 1.00 , colorBlack, coloryellow, 0);
}
if (NOT AlmostEqual(brkPriceObj3, brkPriceObj2, 5))
{
GfxMoveTo(i+0.1, brkPriceObj3);
GfxLineTo(BarCount + 1, brkPriceObj3);
pobjText = "c: " + NumToStr(brkPriceObj3, 1.3, True, False);
PlotTextSetFont(pobjText, "Times New Roman", 10, BarCount + 1.5, brkPriceObj3 * 1.00 , colorBlack, coloryellow, 0);
}
dpobjDrawn = True;
}
}
currDPos = dStartPos;
prev1DPos = currDPos;
}
// send Alert
Buy = sendSAlert OR sendDAlert; // a buy signal can also be derived from the disqualification (or cancellation) of a demand line break
Sell = False; // will implement later after I assess the precision of the Cancellation signals (sC1, sC2, sC3 and dC1, dC2, dC3)
AlertIf(Buy, "EMAIL", "Supply break Alert at " + NumToStr(buyPrice, 1.3, True)+" for: " +Name()+ "-"+FullName(), 1, 15, 1);
AlertIf(Sell, "EMAIL", "Yesterday's Supply break cancelled for: " + Name() + "-" + FullName(), 2, 15, 1);
Plot (supplyLine, "Supply Line", colorRed, slineType, Null, Null, 0, 0, 2);
Plot (demandLine, "Demand Line", colorGreen, dLineType, Null, Null, 0, 0, 2);
_SECTION_END();