RSI_Divergence

Indicators Used
Moving average indicatorRelative strength indexIndicator of the average true range
Miscellaneous
Implements a curve of type %1It plays sound alerts
0 Views
0 Downloads
0 Favorites
RSI_Divergence

#property  copyright  "RSI Divergence"
#property  link       "RSI Divergence"

//---- defines
#define DodgerBlue2  0xaa6014
#define Crimson2     0x280d93

//---- indicator settings
#property  indicator_separate_window

#property indicator_minimum  0
#property indicator_maximum  100

#property  indicator_buffers  8

#property  indicator_color1  SlateBlue     // 0: Rsi line
#property  indicator_color2  MediumOrchid  // 1: Rsi smoothed line(T3)
#property  indicator_color3  Aqua          // 2: Long signal, cross
#property  indicator_color4  Magenta       // 3: Short signal, cross
#property  indicator_color5  DodgerBlue    // 4: Long signal, divergence
#property  indicator_color6  Crimson       // 5: Short signal, divergence
#property  indicator_color7  Crimson2      // 6: Top peak
#property  indicator_color8  DodgerBlue2   // 7: Bottom peak

#property  indicator_width1  1
#property  indicator_width2  1
#property  indicator_width3  1
#property  indicator_width4  1
#property  indicator_width5  1
#property  indicator_width6  1
#property  indicator_width7  1
#property  indicator_width8  1

#property  indicator_style1  STYLE_SOLID
#property  indicator_style2  STYLE_DOT
#property  indicator_style3  STYLE_SOLID
#property  indicator_style4  STYLE_SOLID
#property  indicator_style5  STYLE_SOLID
#property  indicator_style6  STYLE_SOLID
#property  indicator_style7  STYLE_SOLID
#property  indicator_style8  STYLE_SOLID

//---- indicator parameters
extern int    timeFrame     = 0;          // time frame
extern bool   bCheckDiv     = true;       // show divergence
extern bool   bShowAllDiv   = false;      // show all divergence or above/below level_hi/lo
extern bool   bCheckCross   = false;      // show cross signal
extern bool   bCheckLineMan = true;       // show LineMan
extern bool   bAlertCross   = false;      // PlaySound() on signal cross
extern bool   bAlertDiv     = false;      // PlaySound() on divergence
extern bool   bAlertLineMan = false;      // PlaySound() on divergence
extern bool   bDrawOnChart  = true;       // draw lines on chart/window
extern int    div_mode      = MODE_MAIN;  // 0/MODE_MAIN:RSI value 1/MODE_SIGNAL:smoothed value(T3)
extern int    nCheckBars    = 120;        // number of bars to check divergence
extern int    rsi_period    = 8;          // RSI period
extern int    t3_period     = 8;          // RSI period
extern double level_lo      = 30;         // when bShowAllDiv is true, show divergence only below this level
extern double level_hi      = 70;         // when bShowAllDiv is true, show divergence only above this level
extern double div_oscErr    = 4.0;        // allowable error along divergence line (oscilator)
extern double div_priceErr  = 0.4;        // allowable error along divergence line (PPS), iATR(nCheckBars)*err
extern int    window        = 0;          // specify indicator window explicitly, 0: auto
extern int    nMaxBars      = 2000;       // maximum number of bars to calculate, 0: no limit

//---- indicator buffers
double BufferMain[];     // 0: Rsi main line
double BufferSignal[];   // 1: Rsi smoothed line
double BufferLongCross[];   // 2: Long signal, cross
double BufferShortCross[];  // 3: Short signal, cross
double BufferLongDiv[];     // 4: Long signal, divergence
double BufferShortDiv[];    // 5: Short signal, divergence
double BufferTop[];         // 6: top peak
double BufferBottom[];      // 7: bottom peak

//---- vars
string sIndicatorName;
string sIndSelf = "00-RsiDiv_v104";
string sPrefix;
int    g_window;
int    markLong        = 233;
int    markShort       = 234;
int    markDot         = 167;
color  colRegularLong  = DodgerBlue;  // ( 30, 144, 255)= 0x1e90ff
color  colRegularShort = Crimson;     // (220,  20,  60)= 0xdc143c
color  colHiddenLong   = DodgerBlue2;
color  colHiddenShort  = Crimson2;
color  colLineManUpper = Aqua;
color  colLineManLower = Magenta;
int    wRegular        = 1;
int    wHidden         = 1;
double t3_curvature    = 0.6180;
double t3_e1, t3_e2, t3_e3, t3_e4, t3_e5, t3_e6;
double t3_c1, t3_c2, t3_c3, t3_c4;
double t3_w1, t3_w2, t3_b2, t3_b3;
datetime tAlertLast    = 0;

//----------------------------------------------------------------------
string TimeFrameToStr(int timeFrame)
{
    switch (timeFrame) {
    case 1:     return("M1");
    case 5:     return("M5");
    case 15:    return("M15");
    case 30:    return("M30");
    case 60:    return("H1");
    case 240:   return("H4");
    case 1440:  return("D1");
    case 10080: return("W1");
    case 43200: return("MN");
    }
    
    return("??");
}

//----------------------------------------------------------------------
void init()
{
    if (timeFrame == 0) {
	timeFrame = Period();
    }
    
    string tf = TimeFrameToStr(timeFrame);
    sIndicatorName = sIndSelf + "(" + tf + "," + div_mode + "," + rsi_period + "," + t3_period + ")";
    sPrefix = sIndicatorName;
    
    IndicatorShortName(sIndicatorName);
    
    SetIndexBuffer(0, BufferMain);
    SetIndexBuffer(1, BufferSignal);
    SetIndexBuffer(2, BufferLongCross);
    SetIndexBuffer(3, BufferShortCross);
    SetIndexBuffer(4, BufferLongDiv);
    SetIndexBuffer(5, BufferShortDiv);
    SetIndexBuffer(6, BufferTop);
    SetIndexBuffer(7, BufferBottom);
    
    SetIndexLabel(0, "Rsi main");
    SetIndexLabel(1, "Rsi signal");
    SetIndexLabel(2, "Long signal, cross");
    SetIndexLabel(3, "Short signal, cross");
    SetIndexLabel(4, "Long signal, divergence");
    SetIndexLabel(5, "Short signal, divergence");
    SetIndexLabel(6, "Top peak");
    SetIndexLabel(7, "Bottom peak");
    
    SetIndexStyle(0, DRAW_LINE);
    SetIndexStyle(1, DRAW_LINE);
    SetIndexStyle(2, DRAW_ARROW);
    SetIndexStyle(3, DRAW_ARROW);
    SetIndexStyle(4, DRAW_ARROW);
    SetIndexStyle(5, DRAW_ARROW);
    SetIndexStyle(6, DRAW_ARROW);
    SetIndexStyle(7, DRAW_ARROW);
    
    SetIndexArrow(2, markLong);
    SetIndexArrow(3, markShort);
    SetIndexArrow(4, markLong);
    SetIndexArrow(5, markShort);
    SetIndexArrow(6, markDot);
    SetIndexArrow(7, markDot);
    
    int n = rsi_period;
    
    SetIndexDrawBegin(0, n);
    SetIndexDrawBegin(1, n);
    SetIndexDrawBegin(2, n);
    SetIndexDrawBegin(3, n);
    SetIndexDrawBegin(4, n);
    SetIndexDrawBegin(5, n);
    SetIndexDrawBegin(6, n);
    SetIndexDrawBegin(7, n);
    
    SetLevelValue(0, level_lo);
    SetLevelValue(1, level_hi);
    
    // setup for T3
    t3_e1 = 0;
    t3_e2 = 0;
    t3_e3 = 0;
    t3_e4 = 0;
    t3_e5 = 0;
    t3_e6 = 0;
    
    t3_c1 = 0;
    t3_c2 = 0;
    t3_c3 = 0;
    t3_c4 = 0;
    
    t3_w1 = 0;
    t3_w2 = 0;
    
    t3_b2 = 0;
    t3_b3 = 0;

    t3_b2 = t3_curvature * t3_curvature;
    t3_b3 = t3_b2 * t3_curvature;
    
    t3_c1 = -t3_b3;
    t3_c2 = (3.0 * (t3_b2 + t3_b3));
    t3_c3 = -3.0 * (2.0 * t3_b2 + t3_curvature + t3_b3);
    t3_c4 = (1.0 + 3 * t3_curvature + t3_b3 + 3.0 * t3_b2);
    double x = MathMax(t3_period, 1);
    x = 1.0 + 0.5 * (x - 1.0);
    t3_w1 = 2.0 / (x + 1.0);
    t3_w2 = 1.0 - t3_w1;
}

//----------------------------------------------------------------------
void deinit()
{
    int n = ObjectsTotal();
    for (int i = n - 1; i >= 0; i--) {
	string sName = ObjectName(i);
	if (StringFind(sName, sPrefix) == 0) {
	    ObjectDelete(sName);
	}
    }
}

//----------------------------------------------------------------------
void objLine(string sName, int win, datetime ts, double ps, datetime te, double pe, color col,
	     int width = 1, int style = STYLE_SOLID, bool bBack = true, bool bRay = false)
{
    sName = sPrefix + sName + " w" + win;
    
    ObjectCreate(sName, OBJ_TREND, win, 0, 0);
    ObjectSet(sName, OBJPROP_TIME1,  ts);
    ObjectSet(sName, OBJPROP_PRICE1, ps);
    ObjectSet(sName, OBJPROP_TIME2,  te);
    ObjectSet(sName, OBJPROP_PRICE2, pe);
    ObjectSet(sName, OBJPROP_COLOR,  col);
    ObjectSet(sName, OBJPROP_WIDTH,  width);
    ObjectSet(sName, OBJPROP_STYLE,  style);
    ObjectSet(sName, OBJPROP_BACK,   bBack);
    ObjectSet(sName, OBJPROP_RAY,    bRay);
}	    

//----------------------------------------------------------------------
void objArrow(string sName, int win, datetime t, double p, int arrow, color col, int width = 1)
{
    sName = sPrefix + sName + " w" + win;
    
    ObjectCreate(sName, OBJ_ARROW, win, 0, 0);
    ObjectSet(sName, OBJPROP_TIME1,     t);
    ObjectSet(sName, OBJPROP_PRICE1,    p);
    ObjectSet(sName, OBJPROP_ARROWCODE, arrow);
    ObjectSet(sName, OBJPROP_COLOR,     col);
    ObjectSet(sName, OBJPROP_WIDTH,     width);
}

//----------------------------------------------------------------------
double getVal(int i)
{
    if (div_mode == MODE_MAIN) {
	return(BufferMain[i]);
    }
    
    return(BufferSignal[i]);
}

//----------------------------------------------------------------------
double getLowerPrice(int i)
{
    double hi, lo;
    
    if (div_mode == MODE_MAIN) {
	hi = High[i];
	lo = Low[i];
    } else {
	hi = iMA(NULL, 0, t3_period, 0, MODE_LWMA, PRICE_HIGH, i);
	lo = iMA(NULL, 0, t3_period, 0, MODE_LWMA, PRICE_LOW, i);
    }
    
    return(MathMin(hi, lo));
}

//----------------------------------------------------------------------
double getHigherPrice(int i)
{
    double hi, lo;
    
    if (div_mode == MODE_MAIN) {
	hi = High[i];
	lo = Low[i];
    } else {
	hi = iMA(NULL, 0, t3_period, 0, MODE_LWMA, PRICE_HIGH, i);
	lo = iMA(NULL, 0, t3_period, 0, MODE_LWMA, PRICE_LOW, i);
    }
    
    return(MathMax(hi, lo));
}

//----------------------------------------------------------------------
void intersect(double &x0, double &y0, double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4)
{
    x0 = 0;
    y0 = 0;
    
    double a1, a2, b1, b2;
    
    if (x1 == x2){
	if (x3 != x4) {
	    a1 = (y4 - y3) / (x4 - x3);
	    b1 = y3 - a1 * x3;
	    x0 = x2;
	    y0 = a1 * x0 + b1;
	} else {
	    if (x1 == x3) {
		x0 = x1;
		y0 = y1;
	    }
	}
	
	return;
    }
    
    if (x3 == x4){
	a1 = (y2 - y1) / (x2 - x1);
	b1 = y2 - a1 * x2;
	x0 = x3;
	y0 = a1 * x0 + b1;
	
	return;
    }
    
    a1 = 0;
    b1 = 0;
    a2 = 0;
    b2 = 0;
    
    a1 = (y2 - y1) / (x2 - x1);
    b1 = y2 - a1 * x2;
    
    a2 = (y4 - y3) / (x4 - x3);
    b2 = y3 - a2 * x3;
    
    if (a1 != a2) {
	x0 = (b1 - b2) / (a2 - a1);
	y0 = a1 * x0 + b1;
    } else {
	if (b1 == b2) {
	    x0 = x1;
	    y0 = y1;
	}
    }
}

//----------------------------------------------------------------------
bool checkAlert()
{
    bool bPlayed = false;
    
    if ((bCheckCross && bAlertCross) || (bCheckDiv && bAlertDiv) || (bCheckLineMan && bAlertLineMan)) {
	bool bFireCross = (BufferLongCross[0] != EMPTY_VALUE || BufferShortCross[0] != EMPTY_VALUE);
	bool bFireDiv   = (BufferLongDiv[0]   != EMPTY_VALUE || BufferShortDiv[0]   != EMPTY_VALUE);
	bool bFire = ((bAlertCross && bFireCross) || (bAlertDiv && bFireDiv));
	if (bFire && tAlertLast != Time[0]) {
	    PlaySound("alert.wav");
	    bPlayed = true;
	}
    }
    
    return(bPlayed);
}

//----------------------------------------------------------------------
void start()
{
    bool bRedraw = false;
    
    if (window > 0) {
	g_window = window;
    } else {
	g_window = WindowOnDropped();
	if (g_window <= 0) {
	    g_window = WindowFind(sIndicatorName);
	}
    }
    
    int limit = Bars;
    if (nMaxBars > 0) {
	limit = MathMin(limit, nMaxBars);
    }
    
    if (timeFrame != Period()) {
	// MTF
	limit = MathMax(limit, timeFrame / Period());
	for (int i = limit - 1; i >= 0; i--) {
	    int x = iBarShift(NULL, timeFrame, Time[i]);
	    BufferMain[i]       = iCustom(NULL, timeFrame, sIndSelf, 0, bCheckDiv, bShowAllDiv, bCheckCross, bCheckLineMan,
					  false, false, false, bDrawOnChart, div_mode, nCheckBars, rsi_period, t3_period,
					  level_lo, level_hi, div_oscErr, div_priceErr, window, nMaxBars, 0, x);
	    BufferSignal[i]     = iCustom(NULL, timeFrame, sIndSelf, 0,  bCheckDiv, bShowAllDiv, bCheckCross, bCheckLineMan,
					  false, false, false, false, div_mode, nCheckBars, rsi_period, t3_period,
					  level_lo, level_hi, div_oscErr, div_priceErr, window, nMaxBars, 1, x);
	    BufferLongCross[i]  = iCustom(NULL, timeFrame, sIndSelf, 0,  bCheckDiv, bShowAllDiv, bCheckCross, bCheckLineMan,
					  false, false, false, false, div_mode, nCheckBars, rsi_period, t3_period,
					  level_lo, level_hi, div_oscErr, div_priceErr, window, nMaxBars, 2, x);
	    BufferShortCross[i] = iCustom(NULL, timeFrame, sIndSelf, 0,  bCheckDiv, bShowAllDiv, bCheckCross, bCheckLineMan,
					  false, false, false, false, div_mode, nCheckBars, rsi_period, t3_period,
					  level_lo, level_hi, div_oscErr, div_priceErr, window, nMaxBars, 3, x);
	    BufferLongDiv[i]    = iCustom(NULL, timeFrame, sIndSelf, 0,  bCheckDiv, bShowAllDiv, bCheckCross, bCheckLineMan,
					  false, false, false, false, div_mode, nCheckBars, rsi_period, t3_period,
					  level_lo, level_hi, div_oscErr, div_priceErr, window, nMaxBars, 4, x);
	    BufferShortDiv[i]   = iCustom(NULL, timeFrame, sIndSelf, 0,  bCheckDiv, bShowAllDiv, bCheckCross, bCheckLineMan,
					  false, false, false, false, div_mode, nCheckBars, rsi_period, t3_period,
					  level_lo, level_hi, div_oscErr, div_priceErr, window, nMaxBars, 5, x);
	    BufferTop[i]        = iCustom(NULL, timeFrame, sIndSelf, 0,  bCheckDiv, bShowAllDiv, bCheckCross, bCheckLineMan,
					  false, false, false, false, div_mode, nCheckBars, rsi_period, t3_period,
					  level_lo, level_hi, div_oscErr, div_priceErr, window, nMaxBars, 6, x);
	    BufferBottom[i]     = iCustom(NULL, timeFrame, sIndSelf, 0, bCheckDiv, bShowAllDiv, bCheckCross, bCheckLineMan,
					  false, false, false, false, div_mode, nCheckBars, rsi_period, t3_period,
					  level_lo, level_hi, div_oscErr, div_priceErr, window, nMaxBars, 7, x);
	}
	
	// check alert
	if (checkAlert()) {
	    tAlertLast = Time[0];
	}
	
	return;
    }
    
    // timeFrame == Period()
    
    double val1, val2, val3, val4;
    for (i = limit - 1; i >= 0; i--) {
	double rsi = iRSI(NULL, 0, rsi_period, PRICE_CLOSE, i);
	
	t3_e1 = t3_w1 * rsi + t3_w2 * t3_e1;
	t3_e2 = t3_w1 * t3_e1 + t3_w2 * t3_e2;
	t3_e3 = t3_w1 * t3_e2 + t3_w2 * t3_e3;
	t3_e4 = t3_w1 * t3_e3 + t3_w2 * t3_e4;
	t3_e5 = t3_w1 * t3_e4 + t3_w2 * t3_e5;
	t3_e6 = t3_w1 * t3_e5 + t3_w2 * t3_e6;
	
	BufferMain[i]    = rsi;
	BufferSignal[i]  = t3_c1 * t3_e6 + t3_c2 * t3_e5 + t3_c3 * t3_e4 + t3_c4 * t3_e3;
	BufferLongCross[i]  = EMPTY_VALUE;
	BufferShortCross[i] = EMPTY_VALUE;
	BufferTop[i]        = EMPTY_VALUE;
	BufferBottom[i]     = EMPTY_VALUE;
	
	
	// check cross
	if (bCheckCross) {
	    double main2 = BufferMain[i + 2];
	    double main1 = BufferMain[i + 1];
	
	    double sig2  = BufferSignal[i + 2];
	    double sig1  = BufferSignal[i + 1];
	
	    datetime t2 = Time[i + 2];
	    datetime t1 = Time[i + 1];
	
	    double cx, cy;
	    intersect(cx, cy, t2, main2, t1, main1, t2, sig2, t1, sig1);
	    if (cx > t2 && cx <= t1) {
		if (cy <= level_lo) {
		    BufferLongCross[i] = cy;
		}
		if (cy >= level_hi) {
		    BufferShortCross[i] = cy;
		}
	    }
	}
	
	if (bCheckDiv || bCheckLineMan) {
	    val4 = getVal(i + 4);
	    val3 = getVal(i + 3);
	    val2 = getVal(i + 2);
	    val1 = getVal(i + 1);
	
	    // top peak
	    if (val4 <= val3 && val3 <= val2 && val2 > val1) {
		BufferTop[i + 2] = val2;
	    }
	
	    // bottom peak
	    if (val4 > val3 && val3 > val2 && val2 <= val1) {
		BufferBottom[i + 2] = val2;
	    }
	}
    }
    
    // search divergence on bottom
    if (bCheckDiv) {
	for (int i1 = limit - 1; i1 >= 0; i1--) {
	    if (BufferBottom[i1] == EMPTY_VALUE) {
		continue;
	    }
	    
	    for (int hidden = 0; hidden <= 1; hidden++) {
		val1 = getVal(i1);
		double p1 = Close[i1];
		int i2 = -1;
		for (int j = 1; j <= nCheckBars; j++) {
		    x = i1 + j;
		    if (BufferBottom[x] == EMPTY_VALUE) {
			continue;
		    }
		    val2 = getVal(x);
		    double p2 = Close[x];
		    if ((!hidden && (val2 > val1 || p2 < p1)) ||
			(hidden  && (val2 < val1 || p2 > p1))) {
			continue;
		    }
		    bool bExceed = false;
		    // check div_oscErr
		    for (int k = i1 + 1; k < x; k++) {
			double s = getVal(k);
			double pred = val1 + (val2 - val1) * (k - i1) / (x - i1);
			if (pred - s >= div_oscErr) {
			    bExceed = true;
			    break;
			}
		    }
		    // check div_priceErr
		    for (k = i1 + 1; k < x; k++) {
			s = getLowerPrice(k);
			pred = p1 + (p2 - p1) * (k - i1) / (x - i1);
			if (pred - s >= iATR(NULL, 0, nCheckBars, k) * div_priceErr) {
			    bExceed = true;
			    break;
			}
		    }
		    if (!bExceed) {
			i2 = x;
		    }
		}
		if (i2 >= 0) {
		    val1 = getVal(i1);
		    val2 = getVal(i2);
		    datetime ts = Time[i1];
		    datetime tsSig = Time[i1 - 2];
		    datetime te = Time[i2];
		    double os = getVal(i1);
		    double oe = getVal(i2);
		    double ps = Close[i1];
		    double psSig = Open[i1 - 2];
		    double pe = Close[i2];
		    color colLine, colArrow;
		    int w;
		    if (!hidden) {
			colLine = colRegularLong;
			colArrow = colRegularLong;
			w = wRegular;
		    } else {
			colLine = colHiddenLong;
			colArrow = colRegularLong;
			w = wHidden;
		    }
		    if (bShowAllDiv || (os <= level_lo || oe <= level_lo)) {
			objLine("line bo" + ts, g_window, ts, os, te, oe, colLine, w);
			if (bDrawOnChart) {
			    objLine("line bp" + ts, 0, ts, ps, te, pe, colLine, w);
			    objArrow("arrow bp" + tsSig, 0, tsSig, psSig - Point, markLong, colArrow);
			}
			BufferLongDiv[i1 - 2] = os;
			bRedraw = true;
		    }
		}
	    }
	}
	
	// search divergence on top
	for (i1 = limit - 1; i1 >= 0; i1--) {
	    if (BufferTop[i1] == EMPTY_VALUE) {
		continue;
	    }
	    
	    for (hidden = 0; hidden <= 1; hidden++) {
		val1 = getVal(i1);
		p1 = Close[i1];
		i2 = -1;
		for (j = 1; j <= nCheckBars; j++) {
		    x = i1 + j;
		    if (BufferTop[x] == EMPTY_VALUE) {
			continue;
		    }
		    val2 = getVal(x);
		    p2 = Close[x];
		    if ((!hidden && (val2 > val1 || p2 < p1)) ||
			(hidden  && (val2 < val1 || p2 > p1))) {
			continue;
		    }
		    bExceed = false;
		    // check div_oscErr
		    for (k = i1 + 1; k < x; k++) {
			s = getVal(k);
			pred = val1 + (val2 - val1) * (k - i1) / (x - i1);
			if (s - pred >= div_oscErr) {
			    bExceed = true;
			    break;
			}
		    }
		    // check div_priceErr
		    for (k = i1 + 1; k < x; k++) {
			s = getHigherPrice(k);
			pred = p1 + (p2 - p1) * (k - i1) / (x - i1);
			if (s - pred >= iATR(NULL, 0, nCheckBars, k) * div_priceErr) {
			    bExceed = true;
			    break;
			}
		    }
		    if (!bExceed) {
			i2 = x;
		    }
		}
		if (i2 >= 0) {
		    val1 = getVal(i1);
		    val2 = getVal(i2);
		    ts = Time[i1];
		    tsSig = Time[i1 - 2];
		    te = Time[i2];
		    os = getVal(i1);
		    oe = getVal(i2);
		    ps = Close[i1];
		    psSig = Open[i1 - 2];
		    pe = Close[i2];
		    if (!hidden) {
			colLine = colRegularShort;
			colArrow = colRegularShort;
			w = wRegular;
		    } else {
			colLine = colHiddenShort;
			colArrow = colRegularShort;
			w = wHidden;
		    }
		    if (bShowAllDiv || (os >= level_hi || oe >= level_hi)) {
			objLine("line to" + ts, g_window, ts, os, te, oe, colLine, w);
			if (bDrawOnChart) {
			    objLine("line tp" + ts, 0, ts, ps, te, pe, colLine, w);
			    objArrow("arrow tp" + tsSig, 0, tsSig, psSig + Point, markShort, colArrow);
			}
			BufferShortDiv[i1 - 2] = os;
			bRedraw = true;
		    }
		}
	    }
	}
    }
    
    // LineMan
    if (bCheckLineMan) {
	// lower line
	int b0 = -1;
	int b1 = -1;
	for (i = 0; i < limit; i++) {
	    bool bBottom = (BufferBottom[i] != EMPTY_VALUE);
	    if (bBottom) {
		if (b0 == -1) {
		    b0 = i;
		} else if (b1 == -1) {
		    b1 = i;
		    break;
		}
	    }
	}
	int style;
	if (b0 >= 0 && b1 >= 0) {
	    ts = Time[b1];
	    ps = BufferBottom[b1];
	    te = Time[b0];
	    pe = BufferBottom[b0];
	    if (pe > ps) {
		style = STYLE_SOLID;
	    } else {
		style = STYLE_DOT;
	    }
	    objLine("LineManUp", g_window, ts, ps, te, pe, colLineManLower, 1, style, true, true);
	    bRedraw = true;
	}
	
	// upper line
	int u0 = -1;
	int u1 = -1;
	for (i = 0; i < limit; i++) {
	    bool bTop = (BufferTop[i] != EMPTY_VALUE);
	    if (bTop) {
		if (u0 == -1) {
		    u0 = i;
		} else if (u1 == -1) {
		    u1 = i;
		    break;
		}
	    }
	}
	if (u0 >= 0 && u1 >= 0) {
	    ts = Time[u1];
	    ps = BufferTop[u1];
	    te = Time[u0];
	    pe = BufferTop[u0];
	    if (pe < ps) {
		style = STYLE_SOLID;
	    } else {
		style = STYLE_DOT;
	    }
	    objLine("LineManDown", g_window, ts, ps, te, pe, colLineManUpper, 1, style, true, true);
	    bRedraw = true;
	}
    }
    
    // check alert
    if (checkAlert()) {
	tAlertLast = Time[0];
    }
    
    if (bRedraw) {
	WindowRedraw();
    }
}

Comments

Markdown supported. Formatting help

Markdown Formatting Guide

Element Markdown Syntax
Heading # H1
## H2
### H3
Bold **bold text**
Italic *italicized text*
Link [title](https://www.example.com)
Image ![alt text](image.jpg)
Code `code`
Code Block ```
code block
```
Quote > blockquote
Unordered List - Item 1
- Item 2
Ordered List 1. First item
2. Second item
Horizontal Rule ---