#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();
    }
}