In quantitative trading, the traditional K-line chart is one of the most commonly used data presentation forms, but it also has certain limitations, such as insensitivity to fluctuations or excessive noise. In order to observe price trends more clearly, traders often use some improved charts, such as:
This article will introduce how to calculate the Renko and Heikin Ashi data based on ordinary K-lines on the FMZ Quant Trading Platform, and show the drawing effect, to help strategy developers analyze market trends more intuitively.
The Renko is based on “bricks”, and a new brick is drawn only when the price fluctuation exceeds a fixed range (such as $100).
Trading signal interpretation
Core calculation logic:
Calculate the Renko, plot and implementation code:
/*backtest
start: 2025-05-01 00:00:00
end: 2025-06-06 00:00:00
period: 1h
basePeriod: 1m
exchanges: [{"eid":"Binance","currency":"ETH_USDT","balance":1000,"stocks":0.5}]
*/
let globalbricks = []
let lastBarTime = 0
function getBricks(r, brickSize, sourceAttribute, lastPrice) {
for (let i = 1; i < r.length; i++) {
let bar = r[i]
let price = bar[sourceAttribute]
let time = bar.Time
if (time < lastBarTime) {
continue
}
// Traversing the original K-line data
while (Math.abs(price - lastPrice) >= brickSize) {
if (globalbricks.length > 0 && time == globalbricks[globalbricks.length - 1].Time) {
time = globalbricks[globalbricks.length - 1].Time + 1000
}
// Construction bricks
let brick = {
Time: time,
Open: lastPrice,
Close: 0,
High: 0,
Low: 0
}
if (price > lastPrice) {
// Rising bricks
lastPrice += brickSize
brick.Close = lastPrice
brick.High = lastPrice
brick.Low = brick.Open
} else {
// Falling bricks
lastPrice -= brickSize
brick.Close = lastPrice
brick.High = brick.Open
brick.Low = lastPrice
}
// Put into array
globalbricks.push(brick)
// time is accumulated by 1 second to prevent a BAR from being disconnected when it is divided into multiple bricks
time += 1000
}
lastBarTime = bar.Time
}
return globalbricks
}
function getRenko(r, brickSize, sourceAttribute) {
// If the original K-line data does not meet the calculation requirements, it will be returned directly.
if (!r || r.length <= 0) {
return null
}
if (globalbricks.length == 0) {
return getBricks(r, brickSize, sourceAttribute, r[0][sourceAttribute])
} else {
return getBricks(r, brickSize, sourceAttribute, globalbricks[globalbricks.length - 1].Close)
}
}
function main() {
let c = KLineChart({
overlay: true
})
while (true) {
let r = _C(exchange.GetRecords)
let bricks = getRenko(r, 100, "Close")
bricks.forEach(function (brick, index) {
c.begin(brick)
c.close()
})
Sleep(1000)
}
}
Backtesting
Heikin Ashi is a smoothing of traditional K-line
The calculation method is as follows:
HA_Close = (Open + High + Low + Close) / 4
HA_Open = (Previous HA_Open + Previous HA_Close) / 2
HA_High = max(High, HA_Open, HA_Close)
HA_Low = min(Low, HA_Open, HA_Close)
Heikin Ashi is essentially a moving average filtered K-line with stronger trend persistence.
Trend judgment and signal recognition
Implementation code and plot:
/*backtest
start: 2025-05-01 00:00:00
end: 2025-06-06 00:00:00
period: 1h
basePeriod: 1h
exchanges: [{"eid":"Binance","currency":"ETH_USDT","balance":1000,"stocks":0.5}]
*/
function toHeikinAshi(records) {
if (!records || records.length == 0) {
return null
}
let haRecords = []
for (let i = 0; i < records.length; i++) {
let r = records[i]
let ha = {}
ha.Time = r.Time
ha.Close = (r.Open + r.High + r.Low + r.Close) / 4
if (i === 0) {
// The opening price of the first Heikin Ashi is the average of the opening and closing prices of the ordinary K-line.
ha.Open = (r.Open + r.Close) / 2
} else {
// The opening price of each subsequent candlestick = the average of the previous Heikin Ashi opening and closing prices
ha.Open = (haRecords[i - 1].Open + haRecords[i - 1].Close) / 2
}
ha.High = Math.max(r.High, ha.Open, ha.Close)
ha.Low = Math.min(r.Low, ha.Open, ha.Close)
haRecords.push(ha)
}
return haRecords
}
function main() {
let c = KLineChart({
overlay: true
})
while (true) {
let r = _C(exchange.GetRecords)
let heikinAshiRecords = toHeikinAshi(r)
heikinAshiRecords.forEach(function (bar, index) {
c.begin(bar)
c.close()
})
Sleep(1000)
}
}
Backtesting
The Renko and Heikin Ashi are powerful tools for trend traders:
It is recommended to combine backtesting and live trading verification, choose a chart solution suitable for your own trading products and periods, and create a personalized quantitative trading system.