Renko Builder in Javascript

Algo Forex Lab By · · 7 min read

As I mentioned in that article “I Built the Best Renko Builder in Python 3 Years Ago“, after realizing that Python couldn’t handle my speed requirements, I started using Python only as a bridge and used JavaScript to build the Renko candles.

It’s more efficient and faster, but it requires more coding for the chart (though only once!).

you need to pass historical data to renko_builder function then stream tick data and send to update_renko function

Historical Renko Candle From Tick Data

function renko_builder(data) {
  // renkosize = parseFloat(document.getElementById('renkosize_input').value)
  let oo = [data.bid[0]];
  let  hh = [data.bid[0] + renkosize];
  let ll = [data.bid[0]];
  let cc = [data.bid[0] + renkosize];
  let dd = [1];
  for (let i = 0; i < data.bid.length; i++) {
    if (data.bid[i] !== null) {
      let lst = data.bid[i];
      len = cc.length - 1;

      if (cc.at(-1) > oo.at(-1)) {
        if (lst >= (cc.at(-1) + renkosize)) {
          calc = Math.round((lst - cc.at(-1)) / renkosize);
          if (calc >= 2) {
            for (let j = 0; j < Math.floor(calc); j++) {
              dd.push(dd.at(-1) + 1);
              oo.push(cc.at(-1));
              hh.push(cc.at(-1) + renkosize);
              ll.push(cc.at(-1));
              cc.push(cc.at(-1) + renkosize);
            }
          } else {
            dd.push(dd.at(-1) + 1);
            oo.push(cc.at(-1));
            hh.push(cc.at(-1) + renkosize);
            ll.push(cc.at(-1));
            cc.push(cc.at(-1) + renkosize);
          }
        } else if (lst <= (oo.at(-1) - renkosize)) {
          calc = Math.round((oo.at(-1) - lst) / renkosize);
          if (calc >= 2) {
            for (let m = 0; m < Math.floor(calc); m++) {
              if (m === 0) {
                dd.push(dd.at(-1) + 1);
                hh.push(oo.at(-1));
                ll.push(oo.at(-1) - renkosize);
                cc.push(oo.at(-1) - renkosize);
                oo.push(oo.at(-1));
              } else {
                dd.push(dd.at(-1) + 1);
                oo.push(cc.at(-1));
                hh.push(cc.at(-1));
                ll.push(cc.at(-1) - renkosize);
                cc.push(cc.at(-1) - renkosize);
              }
            }
          } else {
            dd.push(dd.at(-1) + 1);
            hh.push(oo.at(-1));
            ll.push(oo.at(-1) - renkosize);
            cc.push(oo.at(-1) - renkosize);
            oo.push(oo.at(-1));
          }


        }
      } else if (cc.at(-1) < oo.at(-1)) {
        if (lst >= (oo.at(-1) + renkosize)) {
          calc = Math.round((lst - oo.at(-1)) / renkosize);
          if (calc >= 2) {
            for (let bv = 0; bv < Math.floor(calc); bv++) {
              if (bv === 0) {
                dd.push(dd.at(-1) + 1);
                hh.push(oo.at(-1) + renkosize);
                ll.push(oo.at(-1));
                cc.push(oo.at(-1) + renkosize);
                oo.push(oo.at(-1));
              } else {
                dd.push(dd.at(-1) + 1);
                oo.push(cc.at(-1));
                hh.push(cc.at(-1) + renkosize);
                ll.push(cc.at(-1));
                cc.push(cc.at(-1) + renkosize);
              }
            }
          } else {
            dd.push(dd.at(-1) + 1);
            hh.push(oo.at(-1) + renkosize);
            ll.push(oo.at(-1));
            cc.push(oo.at(-1) + renkosize);
            oo.push(oo.at(-1));
          }
        } else if (lst <= (cc.at(-1) - renkosize)) {
          calc = Math.round((cc.at(-1) - lst) / renkosize);
          if (calc >= 2) {
            for (let lm = 0; lm < Math.floor(calc); lm++) {
              dd.push(dd.at(-1) + 1);
              oo.push(cc.at(-1));
              hh.push(cc.at(-1));
              ll.push(cc.at(-1) - renkosize);
              cc.push(cc.at(-1) - renkosize);
            }
          } else {
            dd.push(dd.at(-1) + 1);
            oo.push(cc.at(-1));
            hh.push(cc.at(-1));
            ll.push(cc.at(-1) - renkosize);
            cc.push(cc.at(-1) - renkosize);
          }


        }
      }
    if (data.bid[i] > hh[hh.length - 1]){
        hh[hh.length - 1] = data.bid[i]
      }
      if (data.bid[i] < ll[ll.length -1]){
        ll[ll.length - 1] = data.bid[i]
      }
    }
  }
  t_candle = {
    time:dd,
    open:oo,
    high:hh,
    low:ll,
    close:cc,
  }
}
JavaScript
Expand

Live Renko Candle From Tick Data

function update_renko(data) {
  lst = data.bid;
  if (t_candle.close.at(-1) > t_candle.open.at(-1)) {
    if (lst >= (t_candle.close.at(-1) + renkosize)) {

      calc = Math.round((lst - t_candle.close.at(-1)) / renkosize);
      if (calc >= 2) {
        for (let j = 0; j < Math.floor(calc); j++) {
          t_candle.time.push(t_candle.time.at(-1) + 1);
          t_candle.open.push(t_candle.close.at(-1));
          t_candle.high.push(t_candle.close.at(-1) + renkosize);
          t_candle.low.push(t_candle.close.at(-1));
          t_candle.close.push(t_candle.close.at(-1) + renkosize);
        }
      } else {
        t_candle.time.push(t_candle.time.at(-1) + 1);
        t_candle.open.push(t_candle.close.at(-1));
        t_candle.high.push(t_candle.close.at(-1) + renkosize);
        t_candle.low.push(t_candle.close.at(-1));
        t_candle.close.push(t_candle.close.at(-1) + renkosize);
      }
    } else if (lst <= (t_candle.open.at(-1) - renkosize)) {
      calc = Math.round((t_candle.open.at(-1) - lst) / renkosize);
      if (calc >= 2) {
        for (let m = 0; m < Math.floor(calc); m++) {
          if (m === 0) {
            t_candle.time.push(t_candle.time.at(-1) + 1);
            t_candle.high.push(t_candle.open.at(-1));
            t_candle.low.push(t_candle.open.at(-1) - renkosize);
            t_candle.close.push(t_candle.open.at(-1) - renkosize);
            t_candle.open.push(t_candle.open.at(-1));
          } else {
            t_candle.time.push(t_candle.time.at(-1) + 1);
            t_candle.open.push(t_candle.close.at(-1));
            t_candle.high.push(t_candle.close.at(-1));
            t_candle.low.push(t_candle.close.at(-1) - renkosize);
            t_candle.close.push(t_candle.close.at(-1) - renkosize);
          }
        }
      } else {
        t_candle.time.push(t_candle.time.at(-1) + 1);
        t_candle.high.push(t_candle.open.at(-1));
        t_candle.low.push(t_candle.open.at(-1) - renkosize);
        t_candle.close.push(t_candle.open.at(-1) - renkosize);
        t_candle.open.push(t_candle.open.at(-1));
      }


    }
  } else if (t_candle.close.at(-1) < t_candle.open.at(-1)) {
    if (lst >= (t_candle.open.at(-1) + renkosize)) {
      calc = Math.round((lst - t_candle.open.at(-1)) / renkosize);
      if (calc >= 2) {
        for (let bv = 0; bv < Math.floor(calc); bv++) {
          if (bv === 0) {
            t_candle.time.push(t_candle.time.at(-1) + 1);
            t_candle.high.push(t_candle.open.at(-1) + renkosize);
            t_candle.low.push(t_candle.open.at(-1));
            t_candle.close.push(t_candle.open.at(-1) + renkosize);
            t_candle.open.push(t_candle.open.at(-1));
          } else {
            t_candle.time.push(t_candle.time.at(-1) + 1);
            t_candle.open.push(t_candle.close.at(-1));
            t_candle.high.push(t_candle.close.at(-1) + renkosize);
            t_candle.low.push(t_candle.close.at(-1));
            t_candle.close.push(t_candle.close.at(-1) + renkosize);
          }
        }
      } else {
        t_candle.time.push(t_candle.time.at(-1) + 1);
        t_candle.high.push(t_candle.open.at(-1) + renkosize);
        t_candle.low.push(t_candle.open.at(-1));
        t_candle.close.push(t_candle.open.at(-1) + renkosize);
        t_candle.open.push(t_candle.open.at(-1));
      }
    } else if (lst <= (t_candle.close.at(-1) - renkosize)) {
      calc = Math.round((t_candle.close.at(-1) - lst) / renkosize);
      if (calc >= 2) {
        for (let lm = 0; lm < Math.floor(calc); lm++) {
          t_candle.time.push(t_candle.time.at(-1) + 1);
          t_candle.open.push(t_candle.close.at(-1));
          t_candle.high.push(t_candle.close.at(-1));
          t_candle.low.push(t_candle.close.at(-1) - renkosize);
          t_candle.close.push(t_candle.close.at(-1) - renkosize);
        }
      } else {
        t_candle.time.push(t_candle.time.at(-1) + 1);
        t_candle.open.push(t_candle.close.at(-1));
        t_candle.high.push(t_candle.close.at(-1));
        t_candle.low.push(t_candle.close.at(-1) - renkosize);
        t_candle.close.push(t_candle.close.at(-1) - renkosize);
      }


    }
  }
}
JavaScript
Expand
Hassan Safari Hassan Safari
Hassan Safari is a Forex trader, financial risk manager, and full-stack trading systems developer specializing in brokerage infrastructure and algorithmic trading. With hands-on experience in Forex brokerage operations, he works on risk management, liquidity monitoring, and MetaTrader 5 (MT5) server administration. Hassan develops automated trading tools and investment platforms using Python, JavaScript, and PHP, combining financial market expertise with advanced technical execution. His work focuses on building secure, scalable, and risk-optimized trading environments for brokers and investors.