@purpledawn

I know this is an old thread but wondering if you've been able to update/use the code you posted for zorro custom bars. I'm interested in experimenting with portfolios using custom bars (such as tick, renko & kase bars).

Include File:
Code:
#ifndef CUSTOMBARS
/// GENERAL CUSTOM BAR CODE - can be put in a separate include
typedef struct {
int LastBarIdx;
int LastBarNum;
int* OpenBar;
vars OpenDate;
vars Open;
vars High;
vars Low;
vars Close;
vars Price;
vars Volume;
} CustomBars;


function initCustomBars(CustomBars* customBars){
if (is(INITRUN)) {
} else {
if (customBars->Open == NULL) { //allocate bars when NumBars is available
customBars->OpenBar = malloc(NumBars * sizeof(int)); if(customBars->OpenBar == NULL)msg("Error could not allocate %i OpenBar",NumBars);memset(customBars->OpenBar, 0, NumBars * sizeof(int));
customBars->OpenDate = malloc(NumBars * sizeof(var)); if(customBars->OpenDate == NULL)msg("Error could not allocate %i OpenDate",NumBars);memset(customBars->OpenDate, 0, NumBars * sizeof(var));
customBars->Open = malloc(NumBars * sizeof(var)); if(customBars->Open == NULL)msg("Error could not allocate %i Open",NumBars);memset(customBars->Open, 0, NumBars * sizeof(var));
customBars->High = malloc(NumBars * sizeof(var)); if(customBars->High == NULL)msg("Error could not allocate %i High",NumBars);memset(customBars->High, 0, NumBars * sizeof(var));
customBars->Low = malloc(NumBars * sizeof(var)); if(customBars->Low == NULL)msg("Error could not allocate %i Low",NumBars);memset(customBars->Low, 0, NumBars * sizeof(var));
customBars->Close = malloc(NumBars * sizeof(var)); if(customBars->Close == NULL)msg("Error could not allocate %i Close",NumBars);memset(customBars->Close, 0, NumBars * sizeof(var));
customBars->Price = malloc(NumBars * sizeof(var)); if(customBars->Price == NULL)msg("Error could not allocate %i Price",NumBars);memset(customBars->Price, 0, NumBars * sizeof(var));
customBars->Volume = malloc(NumBars * sizeof(var)); if(customBars->Volume == NULL)msg("Error could not allocate %i Volume",NumBars);memset(customBars->Volume, 0, NumBars * sizeof(var));
customBars->LastBarIdx = NumBars;
customBars->LastBarNum=0;
}
}
}
function freeCustomBars(CustomBars* customBars){
//print(TO_CSV,"Bar:%i freeing OpenBar");
if (customBars->OpenBar != 0) free(customBars->OpenBar);customBars->OpenBar=0;
//print(TO_CSV,"Bar:%i freeing OpenDate");
if (customBars->OpenDate != NULL) free(customBars->OpenDate);customBars->OpenDate=0;
//print(TO_CSV,"Bar:%i freeing OpenBars");
if (customBars->Open != NULL) free(customBars->Open);customBars->Open=0;
//print(TO_CSV,"Bar:%i freeing High");
if (customBars->High != NULL) free(customBars->High);customBars->High=0;
//print(TO_CSV,"Bar:%i freeing Low");
if (customBars->Low != NULL) free(customBars->Low);customBars->Low=0;
//print(TO_CSV,"Bar:%i freeing Close");
if (customBars->Close != NULL) free(customBars->Close);customBars->Close=0;
//print(TO_CSV,"Bar:%i freeing Price");
if (customBars->Price != NULL) free(customBars->Price);customBars->Price=0;
//print(TO_CSV,"Bar:%i freeing Volume %A",customBars->Volume);
if (customBars->Volume != NULL) free(customBars->Volume);customBars->Volume=0;
//print(TO_CSV,"Bar:%i finished freeing bars n");
}
function enlarge(CustomBars* customBars){
//use if need to add more bars than originally allocated
int lastNumBars= customBars->LastBarNum;
int numCBars = ceil(lastNumBars*1.5); //expand by 50%
msg("in enlarge, lastNumBars:%i newNumBars:%i",lastNumBars,numCBars);

int* OpenBar = malloc(numCBars * sizeof(int)); if(OpenBar == NULL)msg("Error could not allocate %i OpenBar",numCBars); memset(OpenBar, 0, numCBars * sizeof(int));
vars OpenDate = malloc(numCBars * sizeof(var)); if(OpenDate == NULL)msg("Error could not allocate %i OpenDate",numCBars);memset(OpenDate, 0, numCBars * sizeof(var));
vars Open = malloc(numCBars * sizeof(var)); if(Open == NULL)msg("Error could not allocate %i Open",numCBars);memset(Open, 0, numCBars * sizeof(var));
vars High = malloc(numCBars * sizeof(var)); if(High == NULL)msg("Error could not allocate %i High",numCBars);memset(High, 0, numCBars * sizeof(var));
vars Low = malloc(numCBars * sizeof(var)); if(Low == NULL)msg("Error could not allocate %i Low",numCBars);memset(Low, 0, numCBars * sizeof(var));
vars Close = malloc(numCBars * sizeof(var)); if(Close == NULL)msg("Error could not allocate %i Close",numCBars);memset(Close, 0, numCBars * sizeof(var));
vars Price = malloc(numCBars * sizeof(var)); if(Price == NULL)msg("Error could not allocate %i Price",numCBars);memset(Price, 0, numCBars * sizeof(var));
vars Volume = malloc(numCBars * sizeof(var));if(Volume == NULL)msg("Error could not allocate %i Volume",numCBars); memset(Volume, 0, numCBars * sizeof(var));


memcpy(&OpenBar[numCBars- lastNumBars], customBars->OpenBar, lastNumBars*sizeof(int));
memcpy(&OpenDate[numCBars- lastNumBars], customBars->OpenDate, lastNumBars*sizeof(var));
memcpy(&Open[numCBars- lastNumBars], customBars->Open, lastNumBars*sizeof(var));
memcpy(&High[numCBars- lastNumBars], customBars->High, lastNumBars*sizeof(var));
memcpy(&Low[numCBars- lastNumBars], customBars->Low, lastNumBars*sizeof(var));
memcpy(&Close[numCBars- lastNumBars], customBars->Close, lastNumBars*sizeof(var));
memcpy(&Price[numCBars- lastNumBars], customBars->Price, lastNumBars*sizeof(var));
memcpy(&Volume[numCBars- lastNumBars], customBars->Volume, lastNumBars*sizeof(var));

//msg("freeing custom barS");
freeCustomBars(customBars); //for unknown reasons can get script crash freeing allocated mem
//msg("custom bars freed");


customBars->OpenBar = OpenBar;
customBars->OpenDate = OpenDate;
customBars->Open = Open;
customBars->High = High;
customBars->Low = Low;
customBars->Close = Close;
customBars->Price = Price;
customBars->Volume = Volume;

customBars->LastBarIdx = customBars->LastBarIdx + numCBars-lastNumBars;

}
function addCustomBar(CustomBars* customBars, var op, var hi, var lo, var cl, var vol){
//msg("in add custom1");
int ridx = customBars->LastBarIdx;
//print(TO_CSV,"Bar:%i closed custom bar %i op:%f hi:%f lo:%f cl:%f new bar(%f, %f, %f, %f)n",Bar,customBars->LastBarIdx,(customBars->Open)[ridx],(customBars->High)[ridx],(customBars->Low)[ridx],(customBars->Close)[ridx], op, hi, lo, cl);
ridx = customBars->LastBarIdx-1;
if (ridx < 0){
enlarge(customBars);
ridx = customBars->LastBarIdx-1;
//msg("enlarge custom bars, ridx now: %i",ridx);
}
(customBars->Open)[ridx]=op;
//msg("in add custom op: %f", op);
(customBars->High)[ridx]=hi;
(customBars->Low)[ridx]=lo;
(customBars->Close)[ridx]=cl;
(customBars->Price)[ridx]=(hi+lo+cl)/3.0;
(customBars->Volume)[ridx]=vol;

(customBars->OpenBar)[ridx]=Bar;
(customBars->OpenDate)[ridx]=wdate(0);
customBars->LastBarNum = customBars->LastBarNum+1;
customBars->LastBarIdx = ridx;
}
function updateLastCustomBar(CustomBars* customBars, var hi, var lo, var cl, var vol){
int ridx = customBars->LastBarIdx;
(customBars->High)[ridx]=max((customBars->High)[ridx],hi);
(customBars->Low)[ridx]=min((customBars->Low)[ridx],lo);
(customBars->Close)[ridx]=cl;
(customBars->Price)[ridx]=(hi+lo+cl)/3.0;
(customBars->Volume)[ridx]=(customBars->Volume)[ridx]+vol;
}

bool hasBars(CustomBars* customBars){
return (customBars->LastBarIdx) != NumBars;
}
var last(CustomBars* customBars, vars customIndexedSeries){
int idx = customBars->LastBarIdx ;
return customIndexedSeries[idx];
}
var price(CustomBars* customBars, int offset){
return last(customBars, customBars->Price);
}
vars priceSeries(CustomBars* customBars){
int idx = customBars->LastBarIdx ;
return &(customBars->Price)[idx];
}

var priceHigh(CustomBars* customBars, int offset){
return last(customBars, customBars->High);
}
vars priceHighSeries(CustomBars* customBars){
int idx = customBars->LastBarIdx ;
return &(customBars->High)[idx];
}
var priceLow(CustomBars* customBars, int offset){
return last(customBars, customBars->Low);
}
vars priceLowSeries(CustomBars* customBars){
int idx = customBars->LastBarIdx ;
return &(customBars->Low)[idx];
}

var priceOpen(CustomBars* customBars, int offset){
return last(customBars, customBars->Open);
}
vars priceOpenSeries(CustomBars* customBars){
int idx = customBars->LastBarIdx ;
return &(customBars->Open)[idx];
}

var priceClose(CustomBars* customBars, int offset){
return last(customBars, customBars->Close);
}
vars priceCloseSeries(CustomBars* customBars){
int idx = customBars->LastBarIdx ;
return &(customBars->Close)[idx];
}

var marketVol(CustomBars* customBars, int offset){
return last(customBars, customBars->Volume);
}
vars marketVolSeries(CustomBars* customBars){
int idx = customBars->LastBarIdx ;
return &(customBars->Volume)[idx];
}



function plot1(CustomBars* customBars, int barNum, string name, int colorup, int colordn){
int i = NumBars - barNum;
int startIdx = (customBars->OpenBar)[i];
int endIdx =NumBars-1; if (i > customBars->LastBarIdx) endIdx = (customBars->OpenBar)[i-1]-1;
if (startIdx == endIdx && endIdx < NumBars)
endIdx = endIdx+1;
if (PlotBars != 0){
//avoid too many bars error by not plotting outside plot zone
if(PlotBars > 0 && startIdx > PlotBars){
return;
}
if(PlotBars < 0 && endIdx < abs(PlotBars)){
return;
}
}

startIdx = NumBars - startIdx-1; endIdx = NumBars-endIdx-1;



if (colorup == 0)
colorup = BLUE;
if (colordn == 0)
colordn = RED;

int plotcolor = colorup;
bool showMsg = true;
bool isdecreasing = false;
if (i < (customBars->LastBarNum-1))
isdecreasing = (customBars->Close)[i] < (customBars->Close)[i+1]; //less than previous close
else
isdecreasing = (customBars->Close)[i] < (customBars->Open)[i];
if ( isdecreasing ){
plotcolor = colordn;
}

var lo = (customBars->Low)[i];
var hi = (customBars->High)[i];

string upName = strf("%s-Up",name);
string dnName = strf("%s-Dn",name);

if (!isdecreasing){
plotGraph(upName,startIdx,lo,LINE,plotcolor); // start point
plotGraph(upName,startIdx,hi,LINE,plotcolor); // 1st corner
plotGraph(upName,endIdx,hi,LINE,plotcolor); // 2nd corner
plotGraph(upName,endIdx,lo,LINE,plotcolor); // 3rd corner
plotGraph(upName,startIdx,lo,LINE|END,plotcolor); // 4th corner and end point
}
else {
plotGraph(dnName,startIdx,lo,LINE,plotcolor); // start point
plotGraph(dnName,startIdx,hi,LINE,plotcolor); // 1st corner
plotGraph(dnName,endIdx,hi,LINE,plotcolor); // 2nd corner
plotGraph(dnName,endIdx,lo,LINE,plotcolor); // 3rd corner
plotGraph(dnName,startIdx,lo,LINE|END,plotcolor); // 4th corner and end point
}

}
function plot(CustomBars* customBars, string name, int colorup, int colordn){
if (Bar != NumBars-1) return;

int i;
for (i = 1; i <= customBars->LastBarNum; i++){
//msg("plot bar");
plot1(customBars, i, name, colorup, colordn);
}
}


function plotLine(CustomBars* customBars, string name, vars customBarSeries, int type, int color){
int barNum; int endIdx = NumBars-1;
for (barNum = 1; barNum <= customBars->LastBarNum; barNum++){
int i = NumBars - barNum;
endIdx =NumBars-1; if (i > customBars->LastBarIdx) endIdx = (customBars->OpenBar)[i-1]-1;
endIdx = NumBars-endIdx-1;
plotGraph(name, endIdx,customBarSeries[i],LINE, color);
}
plotGraph(name, endIdx,customBarSeries[NumBars-1],LINE | END, color);
}
//plot a series indexed by customBars, ie have same number of values as customBars
function plot(CustomBars* customBars, string name, vars customBarSeries, int type, int color){
if (Bar != NumBars-1) return;
if (type == 0 or type & LINE){
//draw line graph
plotLine(customBars, name, customBarSeries, type, color);
}
else {
//...todo, handle other graph types for indexed series
}

}
/// END GENERAL CUSTOM BAR CODE - can be put in a separate include


//code to customize for each type of custom bar
function makeRandomBars(CustomBars* customBars, var probability){
if (is(INITRUN) or is(EXITRUN))
return;
initCustomBars(customBars);

static bool newBar = true;
var op = priceOpen(0);
var hi=priceHigh(0); var lo=priceLow(0); var cl=priceClose(0); var vol=marketVol(0);

if (newBar){
addCustomBar(customBars, op, hi, lo, cl, vol);
newBar = false;
}
else {
updateLastCustomBar(customBars, hi, lo, cl, vol);
}

//logic to decide when to stop bar
if (random() > (1-probability)){ //eg: close rand bar approx every probabilty base bars
newBar = true;
}
}

//renko bars
var upround(var num, var mintick){
var z = mintick*ceil(num/mintick);
return z;
}
var dnround(var num, var mintick){
var z =mintick*floor(num/mintick);
return z;
}
function addUpRenkoBoxes(CustomBars* customBars, int* rdir,var* ropen, var* rhi, var* rlo, var* rcl, var* upbox, var* dnbox, var fwdPips, var revPips, var hi, var vol, var mintick){
while (hi >= upround(*ropen + *upbox, mintick)){
*rhi = max(*rhi, upround(*ropen + *upbox,mintick));
updateLastCustomBar(customBars, *rhi, *rlo, upround(*ropen + *upbox,mintick), vol);
*ropen = *rlo = upround(*ropen + *upbox,mintick); *rdir = 1;
*upbox = fwdPips; *dnbox = revPips;
addCustomBar(customBars, *ropen, *rhi, *rlo, *ropen, 0);
}
*rhi = max(*rhi,hi);
}
function addDnRenkoBoxes(CustomBars* customBars, int* rdir,var* ropen, var* rhi, var* rlo, var* rcl, var* upbox, var* dnbox, var fwdPips, var revPips, var lo, var vol, var mintick){
while (lo <= dnround(*ropen - *dnbox, mintick)){
*rlo = min(*rlo, dnround(*ropen - *dnbox,mintick));
updateLastCustomBar(customBars, *rhi, *rlo, dnround(*ropen - *dnbox,mintick), vol);

*ropen = *rhi = dnround(*ropen - *dnbox,mintick); *rdir = -1;
*upbox = revPips; *dnbox = fwdPips;
addCustomBar(customBars, *ropen, *rhi, *rlo, *ropen, 0);
}
*rlo = min(*rlo,lo);
}
function makeRenkoBars(CustomBars* customBars, var numFwdPips, var numRevPips, var mintick, var* tmprdir, vars tmpohlcv){
static bool firstBarCreated = false;
if (is(INITRUN))
firstBarCreated = false;
if (is(INITRUN) or is(EXITRUN))
return;
initCustomBars(customBars);

static int rdir;
static var rop,rhi,rlo,rcl,rvol; //use static vars so can pass by reference
rop = tmpohlcv[0]; //initalize and store into passed in array so makeRenko can be called multiple times
rhi = tmpohlcv[1];
rlo = tmpohlcv[2];
rcl = tmpohlcv[3];
rvol = tmpohlcv[4];
rdir = *tmprdir;

if (mintick == 0)
mintick =PIP;

var op=priceOpen(0); var hi=priceHigh(0); var lo=priceLow(0); var cl=priceClose(0); var vol=marketVol(0);

var fwdPips = numFwdPips*PIP; var revPips = numRevPips*PIP;
if (rdir == 0 && rop == 0 && rcl == 0){
rop = op; rhi=rop; rlo=rop; rcl=rop;
addCustomBar(customBars, rop, rhi, rlo, rcl, 0); //open first bar
firstBarCreated = true;
}
if (rdir == 0){

if (rcl>rop && (rhi - rop) > fwdPips){
rdir = 1;
}
else if (rcl< rop && (rop - rlo) > fwdPips){
rdir = -1;
}
else if ((rhi - rop) > fwdPips){
rdir = 1;
}
else if ((rop - rlo) > fwdPips){
rdir = -1;
}
}

var upbox = fwdPips; var dnbox = revPips;
if (rdir == -1){
upbox = revPips; dnbox = fwdPips;
}
if ((rdir > 0 && cl >= op) || (rdir < 0 && cl >= op)){
//assume open lo hi cl
addDnRenkoBoxes(customBars, &rdir,&rop, &rhi, &rlo, &rcl, &upbox, &dnbox, fwdPips, revPips, lo, vol, mintick);
addUpRenkoBoxes(customBars, &rdir,&rop, &rhi, &rlo, &rcl, &upbox, &dnbox, fwdPips, revPips, hi, vol, mintick);
}
else if ((rdir < 0 && cl <= op) || (rdir > 0 && cl <= op)){
//assume open hi lo cl
addUpRenkoBoxes(customBars, &rdir,&rop, &rhi, &rlo, &rcl, &upbox, &dnbox, fwdPips, revPips, lo, vol, mintick);
addDnRenkoBoxes(customBars, &rdir,&rop, &rhi, &rlo, &rcl, &upbox, &dnbox, fwdPips, revPips, hi, vol, mintick);
}
else {
//assume open lo hi cl
addDnRenkoBoxes(customBars, &rdir,&rop, &rhi, &rlo, &rcl, &upbox, &dnbox, fwdPips, revPips, lo, vol, mintick);
addUpRenkoBoxes(customBars, &rdir,&rop, &rhi, &rlo, &rcl, &upbox, &dnbox, fwdPips, revPips, hi, vol, mintick);
}

tmpohlcv[0] = rop;
tmpohlcv[1] = rhi;
tmpohlcv[2] = rlo;
tmpohlcv[3] = rcl;
tmpohlcv[4]= rvol;
*tmprdir= rdir;

}
#define CUSTOMBARS
#endif



Test code:
Code:
#include<CustomBars.c>

//testing custom bars
function run() {
//msg("create mybars");
PlotBars = 10000;
BarPeriod = 1; //if changing barperiod to higher number, depending on the boxsize, makeRenko may need to enlarge its bar array multiple times if there are many more renko bars than NumBars. This may fail

static CustomBars myBars;
//makeRandomBars(&myBars, 0.01);

static int rdir;
static var rohlcv[5] = {0,0,0,0,0};
makeRenkoBars(&myBars, 10, 3*10, PIP/10.0, &rdir, rohlcv); //10:fwdBox 3*10:reversal box PIP/10.0: mintick rounding

static CustomBars myBars2;
static int rdir2;
static var rohlcv2[5] = {0,0,0,0,0};
makeRenkoBars(&myBars2, 4*10, 4*3*10, PIP/10.0, &rdir2, rohlcv2);



plot(&myBars,"renko1",BLUE, RED);
plot(&myBars2,"renko2",0x0000AA, 0xAA0000);


if (hasBars(&myBars) && myBars.LastBarNum >= 21){
vars offsetRandClose = priceCloseSeries(&myBars);
var rsma21 = SMA(offsetRandClose, 21); //real time calculation of sma of past 21 renko bars

plot("rk1_sma21",rsma21,0,BLUE);
}
if (hasBars(&myBars2) && myBars2.LastBarNum >= 21){
vars offsetRandClose2 = priceCloseSeries(&myBars2);
var rsma212 = SMA(offsetRandClose2, 21); //real time calculation of sma of past 21 renko bars

plot("rk2_sma21",rsma212,0,0x0000CC);
}


if (is(EXITRUN)) {
msg("is Exit Run!");
freeCustomBars(&myBars);
freeCustomBars(&myBars2);
}
}




However when I test the above code (Zorro S 1.96.4) I receive this error:

Z Client S 1.96.4
(c) oP group Germany 2018
Registered to:
CustomBars_TEST -stay

CustomBars_TEST compiling..
Error in 'custombars.c' line 8:
syntax error
< vars OpenDate;
>.



I also gather from the syntax highlighting that some of the functions in the include file may clash with predefined Zorro functions.

Again just wondering if you (or anyone) has updated and/or still uses this code.